ETH Price: $3,719.93 (+4.43%)

Token

ERC-20: Curta ^ Paradigm CTF 2023 Player NFTs (PCTF{CUR74_2023})
 

Overview

Max Total Supply

0 PCTF{CUR74_2023}

Holders

12

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
vicnaum.eth
Balance
1 PCTF{CUR74_2023}
0x79635b386b9bd6636cd701879c32e6dd181c853f
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:
CurtaPCTF2023

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
paris EvmVersion
File 1 of 10 : CurtaPCTF2023.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import {LibString} from "solady/utils/LibString.sol";
import {Owned} from "solmate/auth/Owned.sol";
import {ERC721} from "solmate/tokens/ERC721.sol";
import {ICurtaPCTF2023} from "./interfaces/ICurtaPCTF2023.sol";
import {Base64} from "./utils/Base64.sol";
import {CurtaPCTF2023Art} from "./utils/CurtaPCTF2023Art.sol";
import {CurtaPCTF2023Audio} from "./utils/CurtaPCTF2023Audio.sol";
import {CurtaPCTF2023Metadata} from "./utils/CurtaPCTF2023Metadata.sol";

/// @title Curta ^ Paradigm CTF 2023 commemorative NFTs
/// @author fiveoutofnine
/// @notice An NFT collection to commemorate players of the Curta team for their
/// participation and performance in the 2023 Paradigm CTF. In addition to
/// displaying the team's results, the metadata of each token contains a 100%
/// onchain-generated 1:38 minute long audio arrangement of "In the Hall of the
/// "Mountain King" by Edvard Grieg with 3 layered melody lines and a bass line
/// at 117.1875 BPM.
contract CurtaPCTF2023 is ICurtaPCTF2023, ERC721, Owned {
    using LibString for uint256;

    // -------------------------------------------------------------------------
    // Constants
    // -------------------------------------------------------------------------

    /// @notice Description of the collection.
    string constant COLLECTION_DESCRIPTION =
        "An NFT collection to commemorate players of the Curta team for their p"
        "articipation and performance in the 2023 Paradigm CTF. In addition to "
        "displaying the team's results, the metadata of each token contains a 1"
        '00% onchain-generated 1:38 minute long audio arrangement of \\"In the '
        'Hall of the Mountain King\\" by Edvard Grieg with 3 layered melody lin'
        "es and a bass line at 117.1875 BPM.";

    // -------------------------------------------------------------------------
    // Storage
    // -------------------------------------------------------------------------

    /// @inheritdoc ICurtaPCTF2023
    string public override baseURI;

    // -------------------------------------------------------------------------
    // Constructor + functions
    // -------------------------------------------------------------------------

    /// @param _owner Initial owner of the contract.
    constructor(
        address _owner
    )
        ERC721("Curta ^ Paradigm CTF 2023 Player NFTs", "PCTF{CUR74_2023}")
        Owned(_owner)
    {}

    /// @inheritdoc ICurtaPCTF2023
    function mint() external {
        // Get the token ID to mint for the player. The helper function will
        // revert if the player was not part of the team.
        uint256 tokenId = CurtaPCTF2023Metadata.getPlayerId(msg.sender);

        // Mint token.
        _mint(msg.sender, tokenId);
    }

    /// @inheritdoc ICurtaPCTF2023
    function setBaseURI(string calldata _baseURI) external override onlyOwner {
        // Set new base URI.
        baseURI = _baseURI;

        // Emit event.
        emit SetBaseURI(_baseURI);
    }

    // -------------------------------------------------------------------------
    // Onchain audio generation
    // -------------------------------------------------------------------------

    /// @inheritdoc ICurtaPCTF2023
    function getAudioWavFileHeader() external pure returns (bytes memory) {
        return CurtaPCTF2023Audio.getAudioWavFileHeader();
    }

    /// @inheritdoc ICurtaPCTF2023
    function getSoundValueAtSample(
        uint256 _tick
    ) external pure returns (uint8) {
        return CurtaPCTF2023Audio.getSoundValueAtSample(_tick);
    }

    // -------------------------------------------------------------------------
    // ERC721Metadata
    // -------------------------------------------------------------------------

    /// @notice Returns the adjusted URI for a given token ID.
    /// @dev Reverts if the token ID does not exist. Additionally, if `baseURI`
    /// is unset, `tokenURI` will directly return the URI generated onchain via
    /// {_tokenURI(uint256)}. Otherwise, it will return `baseURI + tokenId`.
    /// @param _id The token ID.
    /// @return The adjusted URI for the given token ID.
    function tokenURI(
        uint256 _id
    ) public view override returns (string memory) {
        // Revert if the token hasn't been minted.
        if (_ownerOf[_id] == address(0)) revert TokenUnminted();

        return
            bytes(baseURI).length == 0
                ? _tokenURI(_id)
                : string.concat(baseURI, _id.toString());
    }

    /// @notice Returns the URI for a given token ID, as generated onchain.
    /// @param _id The token ID.
    /// @return The URI for the given token ID.
    function _tokenURI(uint256 _id) internal pure returns (string memory) {
        // Get name of the player the token is attributed to.
        string memory name = CurtaPCTF2023Metadata.getPlayerNameFromID(_id);

        return
            string.concat(
                "data:application/json;base64,",
                Base64.encode(
                    abi.encodePacked(
                        '{"name":"',
                        name,
                        unicode' ∈ Curta ^ Paradigm CTF 2023","description":"',
                        COLLECTION_DESCRIPTION,
                        '","animation_url":"data:text/html;charset=utf-8;base64'
                        ",",
                        Base64.encode(
                            abi.encodePacked(CurtaPCTF2023Art.render(_id))
                        ),
                        '","attributes":[{"trait_type":"Player","value":"',
                        name,
                        '"},{"trait_type":"Year","value":2023}]}'
                    )
                )
            );
    }

    // -------------------------------------------------------------------------
    // Contract metadata
    // -------------------------------------------------------------------------

    /// @inheritdoc ICurtaPCTF2023
    function contractURI() external pure override returns (string memory) {
        return
            string.concat(
                "data:application/json;base64,",
                Base64.encode(
                    abi.encodePacked(
                        '{"name":"Curta ^ Paradigm CTF 2023 Player NFTs","descr'
                        'iption":"',
                        COLLECTION_DESCRIPTION,
                        '"}'
                    )
                )
            );
    }
}

File 2 of 10 : LibString.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for converting numbers into strings and other string operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
library LibString {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The `length` of the output is too small to contain all the hex digits.
    error HexLengthInsufficient();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The constant returned when the `search` is not found in the string.
    uint256 internal constant NOT_FOUND = type(uint256).max;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     DECIMAL OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(uint256 value) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
            // We will need 1 word for the trailing zeros padding, 1 word for the length,
            // and 3 words for a maximum of 78 digits.
            str := add(mload(0x40), 0x80)
            // Update the free memory pointer to allocate.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end of the memory to calculate the length later.
            let end := str

            let w := not(0) // Tsk.
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for { let temp := value } 1 {} {
                str := add(str, w) // `sub(str, 1)`.
                // Write the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(str, add(48, mod(temp, 10)))
                // Keep dividing `temp` until zero.
                temp := div(temp, 10)
                if iszero(temp) { break }
            }

            let length := sub(end, str)
            // Move the pointer 32 bytes leftwards to make room for the length.
            str := sub(str, 0x20)
            // Store the length.
            mstore(str, length)
        }
    }

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(int256 value) internal pure returns (string memory str) {
        if (value >= 0) {
            return toString(uint256(value));
        }
        unchecked {
            str = toString(uint256(-value));
        }
        /// @solidity memory-safe-assembly
        assembly {
            // We still have some spare memory space on the left,
            // as we have allocated 3 words (96 bytes) for up to 78 digits.
            let length := mload(str) // Load the string length.
            mstore(str, 0x2d) // Store the '-' character.
            str := sub(str, 1) // Move back the string pointer by a byte.
            mstore(str, add(length, 1)) // Update the string length.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   HEXADECIMAL OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `length` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2 + 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value, length);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `length` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexStringNoPrefix(uint256 value, uint256 length)
        internal
        pure
        returns (string memory str)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes
            // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
            // We add 0x20 to the total and round down to a multiple of 0x20.
            // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
            str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
            // Allocate the memory.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let start := sub(str, add(length, length))
            let w := not(1) // Tsk.
            let temp := value
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for {} 1 {} {
                str := add(str, w) // `sub(str, 2)`.
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(xor(str, start)) { break }
            }

            if temp {
                // Store the function selector of `HexLengthInsufficient()`.
                mstore(0x00, 0x2194895a)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Compute the string's length.
            let strLength := sub(end, str)
            // Move the pointer and write the length.
            str := sub(str, 0x20)
            mstore(str, strLength)
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
    /// As address are 20 bytes long, the output will left-padded to have
    /// a length of `20 * 2 + 2` bytes.
    function toHexString(uint256 value) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x".
    /// The output excludes leading "0" from the `toHexString` output.
    /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.
    function toMinimalHexString(uint256 value) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero.
            str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.
            mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output excludes leading "0" from the `toHexStringNoPrefix` output.
    /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.
    function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
            let strLength := mload(str) // Get the length.
            str := add(str, o) // Move the pointer, accounting for leading zero.
            mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is encoded using 2 hexadecimal digits per byte.
    /// As address are 20 bytes long, the output will left-padded to have
    /// a length of `20 * 2` bytes.
    function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
            // 0x02 bytes for the prefix, and 0x40 bytes for the digits.
            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
            str := add(mload(0x40), 0x80)
            // Allocate the memory.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let w := not(1) // Tsk.
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for { let temp := value } 1 {} {
                str := add(str, w) // `sub(str, 2)`.
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(temp) { break }
            }

            // Compute the string's length.
            let strLength := sub(end, str)
            // Move the pointer and write the length.
            str := sub(str, 0x20)
            mstore(str, strLength)
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
    /// and the alphabets are capitalized conditionally according to
    /// https://eips.ethereum.org/EIPS/eip-55
    function toHexStringChecksummed(address value) internal pure returns (string memory str) {
        str = toHexString(value);
        /// @solidity memory-safe-assembly
        assembly {
            let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
            let o := add(str, 0x22)
            let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
            let t := shl(240, 136) // `0b10001000 << 240`
            for { let i := 0 } 1 {} {
                mstore(add(i, i), mul(t, byte(i, hashed)))
                i := add(i, 1)
                if eq(i, 20) { break }
            }
            mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
            o := add(o, 0x20)
            mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
    function toHexString(address value) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is encoded using 2 hexadecimal digits per byte.
    function toHexStringNoPrefix(address value) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            str := mload(0x40)

            // Allocate the memory.
            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
            // 0x02 bytes for the prefix, and 0x28 bytes for the digits.
            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
            mstore(0x40, add(str, 0x80))

            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            str := add(str, 2)
            mstore(str, 40)

            let o := add(str, 0x20)
            mstore(add(o, 40), 0)

            value := shl(96, value)

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for { let i := 0 } 1 {} {
                let p := add(o, add(i, i))
                let temp := byte(i, value)
                mstore8(add(p, 1), mload(and(temp, 15)))
                mstore8(p, mload(shr(4, temp)))
                i := add(i, 1)
                if eq(i, 20) { break }
            }
        }
    }

    /// @dev Returns the hex encoded string from the raw bytes.
    /// The output is encoded using 2 hexadecimal digits per byte.
    function toHexString(bytes memory raw) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(raw);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hex encoded string from the raw bytes.
    /// The output is encoded using 2 hexadecimal digits per byte.
    function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            let length := mload(raw)
            str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
            mstore(str, add(length, length)) // Store the length of the output.

            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let o := add(str, 0x20)
            let end := add(raw, length)

            for {} iszero(eq(raw, end)) {} {
                raw := add(raw, 1)
                mstore8(add(o, 1), mload(and(mload(raw), 15)))
                mstore8(o, mload(and(shr(4, mload(raw)), 15)))
                o := add(o, 2)
            }
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(0x40, add(o, 0x20)) // Allocate the memory.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   RUNE STRING OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the number of UTF characters in the string.
    function runeCount(string memory s) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            if mload(s) {
                mstore(0x00, div(not(0), 255))
                mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
                let o := add(s, 0x20)
                let end := add(o, mload(s))
                for { result := 1 } 1 { result := add(result, 1) } {
                    o := add(o, byte(0, mload(shr(250, mload(o)))))
                    if iszero(lt(o, end)) { break }
                }
            }
        }
    }

    /// @dev Returns if this string is a 7-bit ASCII string.
    /// (i.e. all characters codes are in [0..127])
    function is7BitASCII(string memory s) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let mask := shl(7, div(not(0), 255))
            result := 1
            let n := mload(s)
            if n {
                let o := add(s, 0x20)
                let end := add(o, n)
                let last := mload(end)
                mstore(end, 0)
                for {} 1 {} {
                    if and(mask, mload(o)) {
                        result := 0
                        break
                    }
                    o := add(o, 0x20)
                    if iszero(lt(o, end)) { break }
                }
                mstore(end, last)
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   BYTE STRING OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // For performance and bytecode compactness, all indices of the following operations
    // are byte (ASCII) offsets, not UTF character offsets.

    /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.
    function replace(string memory subject, string memory search, string memory replacement)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)
            let replacementLength := mload(replacement)

            subject := add(subject, 0x20)
            search := add(search, 0x20)
            replacement := add(replacement, 0x20)
            result := add(mload(0x40), 0x20)

            let subjectEnd := add(subject, subjectLength)
            if iszero(gt(searchLength, subjectLength)) {
                let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(search)
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                mstore(result, t)
                                result := add(result, 1)
                                subject := add(subject, 1)
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Copy the `replacement` one word at a time.
                        for { let o := 0 } 1 {} {
                            mstore(add(result, o), mload(add(replacement, o)))
                            o := add(o, 0x20)
                            if iszero(lt(o, replacementLength)) { break }
                        }
                        result := add(result, replacementLength)
                        subject := add(subject, searchLength)
                        if searchLength {
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    mstore(result, t)
                    result := add(result, 1)
                    subject := add(subject, 1)
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
            }

            let resultRemainder := result
            result := add(mload(0x40), 0x20)
            let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))
            // Copy the rest of the string one word at a time.
            for {} lt(subject, subjectEnd) {} {
                mstore(resultRemainder, mload(subject))
                resultRemainder := add(resultRemainder, 0x20)
                subject := add(subject, 0x20)
            }
            result := sub(result, 0x20)
            let last := add(add(result, 0x20), k) // Zeroize the slot after the string.
            mstore(last, 0)
            mstore(0x40, add(last, 0x20)) // Allocate the memory.
            mstore(result, k) // Store the length.
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from left to right, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(string memory subject, string memory search, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for { let subjectLength := mload(subject) } 1 {} {
                if iszero(mload(search)) {
                    if iszero(gt(from, subjectLength)) {
                        result := from
                        break
                    }
                    result := subjectLength
                    break
                }
                let searchLength := mload(search)
                let subjectStart := add(subject, 0x20)

                result := not(0) // Initialize to `NOT_FOUND`.

                subject := add(subjectStart, from)
                let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)

                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(add(search, 0x20))

                if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }

                if iszero(lt(searchLength, 0x20)) {
                    for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
                        if iszero(shr(m, xor(mload(subject), s))) {
                            if eq(keccak256(subject, searchLength), h) {
                                result := sub(subject, subjectStart)
                                break
                            }
                        }
                        subject := add(subject, 1)
                        if iszero(lt(subject, end)) { break }
                    }
                    break
                }
                for {} 1 {} {
                    if iszero(shr(m, xor(mload(subject), s))) {
                        result := sub(subject, subjectStart)
                        break
                    }
                    subject := add(subject, 1)
                    if iszero(lt(subject, end)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from left to right.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256 result)
    {
        result = indexOf(subject, search, 0);
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from right to left, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(string memory subject, string memory search, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                result := not(0) // Initialize to `NOT_FOUND`.
                let searchLength := mload(search)
                if gt(searchLength, mload(subject)) { break }
                let w := result

                let fromMax := sub(mload(subject), searchLength)
                if iszero(gt(fromMax, from)) { from := fromMax }

                let end := add(add(subject, 0x20), w)
                subject := add(add(subject, 0x20), from)
                if iszero(gt(subject, end)) { break }
                // As this function is not too often used,
                // we shall simply use keccak256 for smaller bytecode size.
                for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
                    if eq(keccak256(subject, searchLength), h) {
                        result := sub(subject, add(end, 1))
                        break
                    }
                    subject := add(subject, w) // `sub(subject, 1)`.
                    if iszero(gt(subject, end)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from right to left.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256 result)
    {
        result = lastIndexOf(subject, search, uint256(int256(-1)));
    }

    /// @dev Returns whether `subject` starts with `search`.
    function startsWith(string memory subject, string memory search)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLength := mload(search)
            // Just using keccak256 directly is actually cheaper.
            // forgefmt: disable-next-item
            result := and(
                iszero(gt(searchLength, mload(subject))),
                eq(
                    keccak256(add(subject, 0x20), searchLength),
                    keccak256(add(search, 0x20), searchLength)
                )
            )
        }
    }

    /// @dev Returns whether `subject` ends with `search`.
    function endsWith(string memory subject, string memory search)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLength := mload(search)
            let subjectLength := mload(subject)
            // Whether `search` is not longer than `subject`.
            let withinRange := iszero(gt(searchLength, subjectLength))
            // Just using keccak256 directly is actually cheaper.
            // forgefmt: disable-next-item
            result := and(
                withinRange,
                eq(
                    keccak256(
                        // `subject + 0x20 + max(subjectLength - searchLength, 0)`.
                        add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),
                        searchLength
                    ),
                    keccak256(add(search, 0x20), searchLength)
                )
            )
        }
    }

    /// @dev Returns `subject` repeated `times`.
    function repeat(string memory subject, uint256 times)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            if iszero(or(iszero(times), iszero(subjectLength))) {
                subject := add(subject, 0x20)
                result := mload(0x40)
                let output := add(result, 0x20)
                for {} 1 {} {
                    // Copy the `subject` one word at a time.
                    for { let o := 0 } 1 {} {
                        mstore(add(output, o), mload(add(subject, o)))
                        o := add(o, 0x20)
                        if iszero(lt(o, subjectLength)) { break }
                    }
                    output := add(output, subjectLength)
                    times := sub(times, 1)
                    if iszero(times) { break }
                }
                mstore(output, 0) // Zeroize the slot after the string.
                let resultLength := sub(output, add(result, 0x20))
                mstore(result, resultLength) // Store the length.
                // Allocate the memory.
                mstore(0x40, add(result, add(resultLength, 0x20)))
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function slice(string memory subject, uint256 start, uint256 end)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            if iszero(gt(subjectLength, end)) { end := subjectLength }
            if iszero(gt(subjectLength, start)) { start := subjectLength }
            if lt(start, end) {
                result := mload(0x40)
                let resultLength := sub(end, start)
                mstore(result, resultLength)
                subject := add(subject, start)
                let w := not(0x1f)
                // Copy the `subject` one word at a time, backwards.
                for { let o := and(add(resultLength, 0x1f), w) } 1 {} {
                    mstore(add(result, o), mload(add(subject, o)))
                    o := add(o, w) // `sub(o, 0x20)`.
                    if iszero(o) { break }
                }
                // Zeroize the slot after the string.
                mstore(add(add(result, 0x20), resultLength), 0)
                // Allocate memory for the length and the bytes,
                // rounded up to a multiple of 32.
                mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
    /// `start` is a byte offset.
    function slice(string memory subject, uint256 start)
        internal
        pure
        returns (string memory result)
    {
        result = slice(subject, start, uint256(int256(-1)));
    }

    /// @dev Returns all the indices of `search` in `subject`.
    /// The indices are byte offsets.
    function indicesOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256[] memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)

            if iszero(gt(searchLength, subjectLength)) {
                subject := add(subject, 0x20)
                search := add(search, 0x20)
                result := add(mload(0x40), 0x20)

                let subjectStart := subject
                let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(search)
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                subject := add(subject, 1)
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Append to `result`.
                        mstore(result, sub(subject, subjectStart))
                        result := add(result, 0x20)
                        // Advance `subject` by `searchLength`.
                        subject := add(subject, searchLength)
                        if searchLength {
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    subject := add(subject, 1)
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
                let resultEnd := result
                // Assign `result` to the free memory pointer.
                result := mload(0x40)
                // Store the length of `result`.
                mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
                // Allocate memory for result.
                // We allocate one more word, so this array can be recycled for {split}.
                mstore(0x40, add(resultEnd, 0x20))
            }
        }
    }

    /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
    function split(string memory subject, string memory delimiter)
        internal
        pure
        returns (string[] memory result)
    {
        uint256[] memory indices = indicesOf(subject, delimiter);
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(0x1f)
            let indexPtr := add(indices, 0x20)
            let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
            mstore(add(indicesEnd, w), mload(subject))
            mstore(indices, add(mload(indices), 1))
            let prevIndex := 0
            for {} 1 {} {
                let index := mload(indexPtr)
                mstore(indexPtr, 0x60)
                if iszero(eq(index, prevIndex)) {
                    let element := mload(0x40)
                    let elementLength := sub(index, prevIndex)
                    mstore(element, elementLength)
                    // Copy the `subject` one word at a time, backwards.
                    for { let o := and(add(elementLength, 0x1f), w) } 1 {} {
                        mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
                        o := add(o, w) // `sub(o, 0x20)`.
                        if iszero(o) { break }
                    }
                    // Zeroize the slot after the string.
                    mstore(add(add(element, 0x20), elementLength), 0)
                    // Allocate memory for the length and the bytes,
                    // rounded up to a multiple of 32.
                    mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))
                    // Store the `element` into the array.
                    mstore(indexPtr, element)
                }
                prevIndex := add(index, mload(delimiter))
                indexPtr := add(indexPtr, 0x20)
                if iszero(lt(indexPtr, indicesEnd)) { break }
            }
            result := indices
            if iszero(mload(delimiter)) {
                result := add(indices, 0x20)
                mstore(result, sub(mload(indices), 2))
            }
        }
    }

    /// @dev Returns a concatenated string of `a` and `b`.
    /// Cheaper than `string.concat()` and does not de-align the free memory pointer.
    function concat(string memory a, string memory b)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(0x1f)
            result := mload(0x40)
            let aLength := mload(a)
            // Copy `a` one word at a time, backwards.
            for { let o := and(add(aLength, 0x20), w) } 1 {} {
                mstore(add(result, o), mload(add(a, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let bLength := mload(b)
            let output := add(result, aLength)
            // Copy `b` one word at a time, backwards.
            for { let o := and(add(bLength, 0x20), w) } 1 {} {
                mstore(add(output, o), mload(add(b, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let totalLength := add(aLength, bLength)
            let last := add(add(result, 0x20), totalLength)
            // Zeroize the slot after the string.
            mstore(last, 0)
            // Stores the length.
            mstore(result, totalLength)
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 0x1f), w))
        }
    }

    /// @dev Returns a copy of the string in either lowercase or UPPERCASE.
    /// WARNING! This function is only compatible with 7-bit ASCII strings.
    function toCase(string memory subject, bool toUpper)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let length := mload(subject)
            if length {
                result := add(mload(0x40), 0x20)
                subject := add(subject, 1)
                let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
                let w := not(0)
                for { let o := length } 1 {} {
                    o := add(o, w)
                    let b := and(0xff, mload(add(subject, o)))
                    mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
                    if iszero(o) { break }
                }
                result := mload(0x40)
                mstore(result, length) // Store the length.
                let last := add(add(result, 0x20), length)
                mstore(last, 0) // Zeroize the slot after the string.
                mstore(0x40, add(last, 0x20)) // Allocate the memory.
            }
        }
    }

    /// @dev Returns a string from a small bytes32 string.
    /// `smallString` must be null terminated, or behavior will be undefined.
    function fromSmallString(bytes32 smallString) internal pure returns (string memory result) {
        if (smallString == bytes32(0)) return result;
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let n := 0
            for {} 1 {} {
                n := add(n, 1)
                if iszero(byte(n, smallString)) { break } // Scan for '\0'.
            }
            mstore(result, n)
            let o := add(result, 0x20)
            mstore(o, smallString)
            mstore(add(o, n), 0)
            mstore(0x40, add(result, 0x40))
        }
    }

    /// @dev Returns a lowercased copy of the string.
    /// WARNING! This function is only compatible with 7-bit ASCII strings.
    function lower(string memory subject) internal pure returns (string memory result) {
        result = toCase(subject, false);
    }

    /// @dev Returns an UPPERCASED copy of the string.
    /// WARNING! This function is only compatible with 7-bit ASCII strings.
    function upper(string memory subject) internal pure returns (string memory result) {
        result = toCase(subject, true);
    }

    /// @dev Escapes the string to be used within HTML tags.
    function escapeHTML(string memory s) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let end := add(s, mload(s))
            result := add(mload(0x40), 0x20)
            // Store the bytes of the packed offsets and strides into the scratch space.
            // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
            mstore(0x1f, 0x900094)
            mstore(0x08, 0xc0000000a6ab)
            // Store "&quot;&amp;&#39;&lt;&gt;" into the scratch space.
            mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
            for {} iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                // Not in `["\"","'","&","<",">"]`.
                if iszero(and(shl(c, 1), 0x500000c400000000)) {
                    mstore8(result, c)
                    result := add(result, 1)
                    continue
                }
                let t := shr(248, mload(c))
                mstore(result, mload(and(t, 0x1f)))
                result := add(result, shr(5, t))
            }
            let last := result
            mstore(last, 0) // Zeroize the slot after the string.
            result := mload(0x40)
            mstore(result, sub(last, add(result, 0x20))) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate the memory.
        }
    }

    /// @dev Escapes the string to be used within double-quotes in a JSON.
    /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.
    function escapeJSON(string memory s, bool addDoubleQuotes)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let end := add(s, mload(s))
            result := add(mload(0x40), 0x20)
            if addDoubleQuotes {
                mstore8(result, 34)
                result := add(1, result)
            }
            // Store "\\u0000" in scratch space.
            // Store "0123456789abcdef" in scratch space.
            // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
            // into the scratch space.
            mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
            // Bitmask for detecting `["\"","\\"]`.
            let e := or(shl(0x22, 1), shl(0x5c, 1))
            for {} iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                if iszero(lt(c, 0x20)) {
                    if iszero(and(shl(c, 1), e)) {
                        // Not in `["\"","\\"]`.
                        mstore8(result, c)
                        result := add(result, 1)
                        continue
                    }
                    mstore8(result, 0x5c) // "\\".
                    mstore8(add(result, 1), c)
                    result := add(result, 2)
                    continue
                }
                if iszero(and(shl(c, 1), 0x3700)) {
                    // Not in `["\b","\t","\n","\f","\d"]`.
                    mstore8(0x1d, mload(shr(4, c))) // Hex value.
                    mstore8(0x1e, mload(and(c, 15))) // Hex value.
                    mstore(result, mload(0x19)) // "\\u00XX".
                    result := add(result, 6)
                    continue
                }
                mstore8(result, 0x5c) // "\\".
                mstore8(add(result, 1), mload(add(c, 8)))
                result := add(result, 2)
            }
            if addDoubleQuotes {
                mstore8(result, 34)
                result := add(1, result)
            }
            let last := result
            mstore(last, 0) // Zeroize the slot after the string.
            result := mload(0x40)
            mstore(result, sub(last, add(result, 0x20))) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate the memory.
        }
    }

    /// @dev Escapes the string to be used within double-quotes in a JSON.
    function escapeJSON(string memory s) internal pure returns (string memory result) {
        result = escapeJSON(s, false);
    }

    /// @dev Returns whether `a` equals `b`.
    function eq(string memory a, string memory b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
        }
    }

    /// @dev Returns whether `a` equals `b`. For small strings up to 32 bytes.
    /// `b` must be null terminated, or behavior will be undefined.
    function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            // These should be evaluated on compile time, as far as possible.
            let x := and(b, add(not(b), 1))
            let r := or(shl(8, iszero(b)), shl(7, iszero(iszero(shr(128, x)))))
            r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            result := gt(eq(mload(a), sub(32, shr(3, r))), shr(r, xor(b, mload(add(a, 0x20)))))
        }
    }

    /// @dev Packs a single string with its length into a single word.
    /// Returns `bytes32(0)` if the length is zero or greater than 31.
    function packOne(string memory a) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // We don't need to zero right pad the string,
            // since this is our own custom non-standard packing scheme.
            result :=
                mul(
                    // Load the length and the bytes.
                    mload(add(a, 0x1f)),
                    // `length != 0 && length < 32`. Abuses underflow.
                    // Assumes that the length is valid and within the block gas limit.
                    lt(sub(mload(a), 1), 0x1f)
                )
        }
    }

    /// @dev Unpacks a string packed using {packOne}.
    /// Returns the empty string if `packed` is `bytes32(0)`.
    /// If `packed` is not an output of {packOne}, the output behavior is undefined.
    function unpackOne(bytes32 packed) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the free memory pointer.
            result := mload(0x40)
            // Allocate 2 words (1 for the length, 1 for the bytes).
            mstore(0x40, add(result, 0x40))
            // Zeroize the length slot.
            mstore(result, 0)
            // Store the length and bytes.
            mstore(add(result, 0x1f), packed)
            // Right pad with zeroes.
            mstore(add(add(result, 0x20), mload(result)), 0)
        }
    }

    /// @dev Packs two strings with their lengths into a single word.
    /// Returns `bytes32(0)` if combined length is zero or greater than 30.
    function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let aLength := mload(a)
            // We don't need to zero right pad the strings,
            // since this is our own custom non-standard packing scheme.
            result :=
                mul(
                    // Load the length and the bytes of `a` and `b`.
                    or(
                        shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),
                        mload(sub(add(b, 0x1e), aLength))
                    ),
                    // `totalLength != 0 && totalLength < 31`. Abuses underflow.
                    // Assumes that the lengths are valid and within the block gas limit.
                    lt(sub(add(aLength, mload(b)), 1), 0x1e)
                )
        }
    }

    /// @dev Unpacks strings packed using {packTwo}.
    /// Returns the empty strings if `packed` is `bytes32(0)`.
    /// If `packed` is not an output of {packTwo}, the output behavior is undefined.
    function unpackTwo(bytes32 packed)
        internal
        pure
        returns (string memory resultA, string memory resultB)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the free memory pointer.
            resultA := mload(0x40)
            resultB := add(resultA, 0x40)
            // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
            mstore(0x40, add(resultB, 0x40))
            // Zeroize the length slots.
            mstore(resultA, 0)
            mstore(resultB, 0)
            // Store the lengths and bytes.
            mstore(add(resultA, 0x1f), packed)
            mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
            // Right pad with zeroes.
            mstore(add(add(resultA, 0x20), mload(resultA)), 0)
            mstore(add(add(resultB, 0x20), mload(resultB)), 0)
        }
    }

    /// @dev Directly returns `a` without copying.
    function directReturn(string memory a) internal pure {
        assembly {
            // Assumes that the string does not start from the scratch space.
            let retStart := sub(a, 0x20)
            let retSize := add(mload(a), 0x40)
            // Right pad with zeroes. Just in case the string is produced
            // by a method that doesn't zero right pad.
            mstore(add(retStart, retSize), 0)
            // Store the return offset.
            mstore(retStart, 0x20)
            // End the transaction, returning the string.
            return(retStart, retSize)
        }
    }
}

File 3 of 10 : Owned.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

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

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

        emit OwnershipTransferred(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function transferOwnership(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnershipTransferred(msg.sender, newOwner);
    }
}

File 4 of 10 : ERC721.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    event Approval(address indexed owner, address indexed spender, uint256 indexed id);

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /*//////////////////////////////////////////////////////////////
                         METADATA STORAGE/LOGIC
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*//////////////////////////////////////////////////////////////
                      ERC721 BALANCE/OWNER STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) internal _ownerOf;

    mapping(address => uint256) internal _balanceOf;

    function ownerOf(uint256 id) public view virtual returns (address owner) {
        require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
    }

    function balanceOf(address owner) public view virtual returns (uint256) {
        require(owner != address(0), "ZERO_ADDRESS");

        return _balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                         ERC721 APPROVAL STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*//////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = _ownerOf[id];

        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(from == _ownerOf[id], "WRONG_FROM");

        require(to != address(0), "INVALID_RECIPIENT");

        require(
            msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
            "NOT_AUTHORIZED"
        );

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            _balanceOf[from]--;

            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes calldata data
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(_ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

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

    function _burn(uint256 id) internal virtual {
        address owner = _ownerOf[id];

        require(owner != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            _balanceOf[owner]--;
        }

        delete _ownerOf[id];

        delete getApproved[id];

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

    /*//////////////////////////////////////////////////////////////
                        INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }
}

/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC721TokenReceiver.onERC721Received.selector;
    }
}

File 5 of 10 : ICurtaPCTF2023.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

/// @title The interface for {CurtaPCTF2023}
interface ICurtaPCTF2023 {
    // -------------------------------------------------------------------------
    // Errors
    // -------------------------------------------------------------------------

    /// @notice Emitted when a token hasn't been minted.
    error TokenUnminted();

    // -------------------------------------------------------------------------
    // Events
    // -------------------------------------------------------------------------

    /// @notice Emitted when the base URI is set.
    /// @param baseURI The new base URI.
    event SetBaseURI(string baseURI);

    // -------------------------------------------------------------------------
    // Storage
    // -------------------------------------------------------------------------

    /// @dev If `baseURI` is unset, `tokenURI` will directly return the URI
    /// generated onchain via {CurtaPCTF2023._tokenURI(uint256)}. Otherwise, it
    /// will return `baseURI + tokenId`.
    /// @return The base URI for the token collection.
    function baseURI() external view returns (string memory);

    // -------------------------------------------------------------------------
    // Functions
    // -------------------------------------------------------------------------

    /// @notice Mints a token to the sender.
    /// @dev The sender must have been a player on the Curta ^ Paradigm CTF 2023
    /// team (it will revert otherwise).
    function mint() external;

    /// @notice Sets the base URI for the token collection.
    /// @dev This function can only be called by the contract owner.
    /// @param _baseURI The new base URI for the token collection.
    function setBaseURI(string calldata _baseURI) external;

    // -------------------------------------------------------------------------
    // Onchain audio generation
    // -------------------------------------------------------------------------

    /// @notice Returns the WAV file header for the audio file for 1 full cycle
    /// of the token's sound with the parameters the token's sound was generated
    /// with:
    ///     * Size: 196.61735kB (1572910 bytes) = 98.304s (1572864/8000/2)
    ///     * Number of channels: 1
    ///     * Sample rate: 8000Hz
    ///     * Bits/sample: 16 bits/sample
    function getAudioWavFileHeader() external pure returns (bytes memory);

    /// @notice Returns the sound value at a given time tick in the audio.
    /// @dev {CurtaPCTF2023}'s audio was generated at a sample rate of 8000Hz,
    /// which means that `_tick` increments by 1 every 1/8000 seconds.
    /// @param _tick The number of samples since the beginning of the audio at
    /// a frequency of 8000Hz to get the sound value at.
    /// @return The sound value at the given time tick, a value in the range
    /// `[0, 255]` (higher means louder).
    function getSoundValueAtSample(uint256 _tick) external pure returns (uint8);

    // -------------------------------------------------------------------------
    // Metadata
    // -------------------------------------------------------------------------

    /// @notice Returns the contract URI for this contract.
    /// @return The contract URI for this contract.
    function contractURI() external view returns (string memory);
}

File 6 of 10 : Base64.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

/// @title Base64
/// @author Brecht Devos - <[email protected]>
/// @notice Provides a function for encoding some bytes in base64
library Base64 {
    string internal constant TABLE =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678" "9+/";

    function encode(bytes memory data) internal pure returns (string memory) {
        if (data.length == 0) return "";
        string memory table = TABLE;
        uint256 encodedLength = ((data.length + 2) / 3) << 2;
        string memory result = new string(encodedLength + 0x20);

        assembly {
            mstore(result, encodedLength)
            let tablePtr := add(table, 1)
            let dataPtr := data
            let endPtr := add(dataPtr, mload(data))
            let resultPtr := add(result, 0x20)

            for { } lt(dataPtr, endPtr) { } {
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)
                mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(shr(0x12, input), 0x3F)))))
                resultPtr := add(resultPtr, 1)
                mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(shr(0xC, input), 0x3F)))))
                resultPtr := add(resultPtr, 1)
                mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(shr(6, input), 0x3F)))))
                resultPtr := add(resultPtr, 1)
                mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(input, 0x3F)))))
                resultPtr := add(resultPtr, 1)
            }
            switch mod(mload(data), 3)
            case 1 { mstore(sub(resultPtr, 2), shl(0xF0, 0x3D3D)) }
            case 2 { mstore(sub(resultPtr, 1), shl(0xF8, 0x3D)) }
        }

        return result;
    }
}

File 7 of 10 : CurtaPCTF2023Art.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

/// @title Curta ^ Paradigm CTF 2023 commemorative NFT visual art
/// @notice A library for generating HTML output for {CurtaPCTF2023}.
library CurtaPCTF2023Art {
    // -------------------------------------------------------------------------
    // Constants
    // -------------------------------------------------------------------------

    /// @notice Starting string for the HTML.
    string constant HTML_START =
        unicode"<style>button{height:20px;margin:0 auto;border:0;background:#00"
        unicode"E100;cursor:pointer;color:#000}button:hover{text-decoration:und"
        unicode"erline}.b{width:512px}.c{color:#00e100}.a{position:absolute;mar"
        unicode"gin:auto 0;border-radius:100%;top:6px;width:12px;height:12px}</"
        unicode"style><body style=width:640px;height:640px;margin:0><div class="
        unicode'b style="height:512px;background:#161616;padding:64px"><div sty'
        unicode'le="background:#000;border-radius:8px;height:464px;overflow:hid'
        unicode'den;border:1px solid #343434;margin:20px 0"><div style=position'
        unicode":relative;display:flex;width:500px;height:24px;background:#dada"
        unicode"da;padding-left:6px;padding-right:6px><code style=font-weight:6"
        unicode"00;margin:auto;color:#484848>Curta ^ Paradigm CTF 2023</code><d"
        unicode"iv style=background:#ed6a5e;left:6px class=a></div><div style=b"
        unicode"ackground:#f5bf4f;left:22px class=a></div><div style=background"
        unicode':#62c555;left:38px class=a></div></div><pre style="width:496px;'
        unicode'height:292px;display:flex;padding:0px 8px;color:#fff;margin:0">'
        unicode"<code style=margin:auto>┌<span class=c>MEMBERS</span>───┐┌<span"
        unicode" class=c>CHALLENGES COMPLETED</span>───────────┐\n│";

    /// @notice Ending string for the HTML.
    string constant HTML_END =
        unicode"     ││100%                     200.65│\n│          ││BLACK WOR"
        unicode"LD              182.80│\n│          ││HELLO WORLD              "
        unicode"133.22│\n└──────────┘└───────────────────────────────┘</code></"
        unicode"pre><div class=b style=display:flex><button id=b><code>[ Submit"
        unicode" PCTF{CUR74_2023} ]</code></button></div><audio id=a>Your brows"
        unicode"er does not support the audio element</audio><div class=b style"
        unicode"=position:relative;height:128px><canvas id=d style=position:abs"
        unicode'olute width=512 height=128></canvas><div id=c style="border:.5p'
        unicode'x solid #00e100;height:127px;position:absolute;left:0"></div></'
        unicode'div></div><script>document.getElementById("b").addEventListener'
        unicode'("click",()=>{g=0;j=0;for(s="",t=0;t<3*2**18;t++){c="charCodeAt'
        unicode'",u=(t>>18)%3,r=(t)=>t&256?t&255:256-(t&255),a=30*t*2**(("%\'(*'
        unicode",(,,+'++*&**%'(*,(,1/,(,////\"[c](t>>11&31)+[0,12,7,19][t>>16&3"
        unicode'])/12-6),x=30*t*2**(("%,%,%,%,%,%,(/(/,3,3(0,3"[c](8*(t>>17&1?2'
        unicode":t>>15&1)+(t>>12&7)))/12-7),y=a*2,z=y*2;s+=String.fromCharCode("
        unicode"(r(a)/(5-(u>1))+(u>0)/5*r(y)+(u>1)*(r(z)/5+r(x)/4))%256|0)}a=do"
        unicode'cument.getElementById("a");a.src="data:audio/wav;base64,UklGRi4'
        unicode'AGABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAGACA"+btoa(s);'
        unicode'a.play();setInterval(()=>{c=document.getElementById("c");c.styl'
        unicode'e.left=(Math.min(128*g+128,j++)*100/128)+"%";},32);h=()=>{d=doc'
        unicode'ument.getElementById("d").getContext("2d");d.clearRect(0,0,512,'
        unicode'128);d.fillStyle="#FFF";[...Array(4096)].map((_,i)=>{d.beginPat'
        unicode"h();d.arc(i/8,128-s.charCodeAt(32768*g+i*8)/2,1,0,2*Math.PI);d."
        unicode"fill();});g++;j=0;};h();setInterval(h,4096)})</script>";

    // -------------------------------------------------------------------------
    // `render` function
    // -------------------------------------------------------------------------

    /// @notice Renders a HTML commemorating a player's participation and
    /// performance on the Curta team for the 2023 Paradigm CTF.
    /// @param _id ID of the player.
    /// @return HTML string.
    function render(uint256 _id) internal pure returns (string memory) {
        string memory html;
        // Block-scoping to prevent stack too deep error.
        {
            html = string.concat(
                HTML_START,
                _getHighlightedSpan("sudolabel", _id == 0),
                unicode" ││SUSPICIOUS CHARITY       369.96│\n│",
                _getHighlightedSpan("Kalzak", _id == 1),
                unicode"    ││FREE REAL ESTATE           1.74│\n│",
                _getHighlightedSpan("seen", _id == 2),
                unicode"      ││GRAINS OF SAND           343.99│\n│",
                _getHighlightedSpan("igorline", _id == 3),
                unicode"  ││DROPPER                  233.22│\n│",
                _getHighlightedSpan("pogo", _id == 4),
                unicode"      ││COSMIC RADIATION          43.78│\n│",
                _getHighlightedSpan("popular", _id == 5),
                unicode"   ││DRAGON TYRANT            425.13│\n│",
                _getHighlightedSpan("orenyomtov", _id == 6),
                unicode"││HOPPING INTO PLACE       316.55│\n│"
            );
        }

        return
            string.concat(
                html,
                _getHighlightedSpan("0x796", _id == 7),
                unicode"     ││ENTERPRISE BLOCKCHAIN    271.22│\n│",
                _getHighlightedSpan("plotchy", _id == 8),
                unicode"   ││DAI++                    316.55│\n│",
                _getHighlightedSpan("forager", _id == 9),
                unicode"   ││DODONT <span class=c>[FIRST BLOOD]</span>     233."
                unicode"10│\n│",
                _getHighlightedSpan("horsefacts", _id == 10),
                unicode"││OVEN                     281.90│\n│",
                _getHighlightedSpan("datadanne", _id == 11),
                unicode" ││SKILL BASED GAME         214.03│\n│",
                _getHighlightedSpan("brock", _id == 12),
                HTML_END
            );
    }

    /// @notice Helper function that returns a "highlighted" `<span/>` element
    /// if the player is selected (i.e. the corresponding token is attributed to
    /// them).
    /// @param _name Name of the player.
    /// @param _selected Whether the player is selected.
    /// @return HTML string for the span.
    function _getHighlightedSpan(
        string memory _name,
        bool _selected
    ) internal pure returns (string memory) {
        return
            _selected
                ? string.concat(
                    "<span class=c style=font-weight:900;text-decoration:underl"
                    "ine>",
                    _name,
                    "</span>"
                )
                : _name;
    }
}

File 8 of 10 : CurtaPCTF2023Audio.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import {FixedPointMathLib as Math} from "solady/utils/FixedPointMathLib.sol";

/// @title Curta ^ Paradigm CTF 2023 commemorative NFT auditory art
/// @notice A library for generating onchain audio for {CurtaPCTF2023}, which is
/// a 1:38 minute long audio arrangement of "In the Hall of the Mountain King"
/// by Edvard Grieg with 3 layered melody lines and a bass line at 117.1875 BPM.
/// @dev The metadata returned by {CurtaPCTF2023} doesn't use this library for
/// practical reasons. However, the same result can be yielded by calling
/// {getSoundValueAtSample} for each sample in the range `[0, 786432]` and
/// concatenating the result, prefixed with the header returned by
/// {getAudioWavFileHeader}.
library CurtaPCTF2023Audio {
    using Math for int256;
    using Math for uint256;

    // -------------------------------------------------------------------------
    // Constants
    // -------------------------------------------------------------------------

    /// @notice A bitpacked `uint256` of 8 bitpacked segments of 8-bit words
    /// representing quarter note pitch values for the bass line, where the note
    /// C3 has avalue of 62, and 1 is a semitone.
    uint256 constant BASS_NOTES = 0x332C3028332C332C2F282F282C252C252C252C252C252C25;

    /// @notice A bitpacked `uint256` of 8-bit words representing eigth note
    /// pitch values, for the melody line, where the note C3 has a value of 50,
    /// and 1 is a semitone.
    uint256 constant MELODY_NOTES = 0x2F2F2F2F2C282C2F312C282C2A2827252A2A262A2B2B272B2C2C282C2A282725;

    /// @notice A bitpacked `uint256` of 8-bit words representing tranpositions,
    /// to perform on the melody line every 2**16 samples, where 1 is a
    /// semitone.
    uint256 constant MELODY_TRANSPOSITIONS = 0x13070C00;

    // -------------------------------------------------------------------------
    // Functions
    // -------------------------------------------------------------------------

    /// @notice Returns the WAV file header for the audio file for 1 full cycle
    /// of the token's sound with the parameters the token's sound was generated
    /// with:
    ///     * Size: 196.61735kB (1572910 bytes) = 98.304s (1572864/8000/2)
    ///     * Number of channels: 1
    ///     * Sample rate: 8000Hz
    ///     * Bits/sample: 16 bits/sample
    function getAudioWavFileHeader() internal pure returns (bytes memory) {
        // Note: base-64 encoding the following hex string yields:
        // "UklGRi4AGABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAGACA".
        return
        // "RIFF" chunk descriptor
        hex"52" hex"49" hex"46" hex"46" // "RIFF" in ASCII
        hex"2e" hex"00" hex"18" hex"00" // Size of the file (length of data chunk + 46 for the header) = 1572864 + 46 = 1572910
        hex"57" hex"41" hex"56" hex"45" // "WAVE" in ASCII
        // "fmt " sub-chunk
        hex"66" hex"6d" hex"74" hex"20" // "fmt " in ASCII
        hex"10" hex"00" hex"00" hex"00" // Length of sub-chunk 1 = 16
        hex"01" hex"00" hex"01" hex"00" // Audio format = 1 (PCM), Number of channels = 1
        hex"40" hex"1f" hex"00" hex"00" // Sample rate = 8000Hz
        hex"40" hex"1f" hex"00" hex"00" // Byte rate (sample rate * bits/sample * channels) = 8000 * 1 * 1 = 8000 bytes/sec
        hex"01" hex"00" hex"10" hex"00" // Block align = 1, bits/sample = 16
        // "data" sub-chunk
        hex"64" hex"61" hex"74" hex"61" // "data" in ASCII
        hex"00" hex"00" hex"18" hex"00" // Length of data chunk = (3 * 2 ** 18 * 16 / 8) = 1572864 bytes
        hex"80"; // Sample 1
    }

    /// @notice Returns the sound value at a given time tick in the audio.
    /// @dev {CurtaPCTF2023}'s audio was generated at a sample rate of 8000Hz,
    /// which means that `_tick` increments by 1 every 1/8000 seconds. A full
    /// cycle of the audio is 3*2**18 = 786432 samples long, so `_tick` wraps
    /// around every 786432 samples (i.e. same values for equivalent
    /// `_tick % 786432`).
    /// @param _tick The number of samples since the beginning of the audio at
    /// a frequency of 8000Hz to get the sound value at.
    /// @return The sound value at the given time tick, a value in the range
    /// `[0, 255]` (higher means louder).
    function getSoundValueAtSample(uint256 _tick) internal pure returns (uint8) {
        // This function is equivalent to the following JavaScript code:
        // ```js
        // const getSoundValueAtSample = (tick) => {
        //   const transformValue = (v) => v & 256 ? v & 255 : 256 - (v & 255);
        //   const iteration = (tick >> 18) % 3;
        //   const melodyLine1 = 30 * tick * 2 ** (
        //     (
        //       "%'(*,(,,+'++*&**%'(*,(,1/,(,////".charCodeAt(tick >> 11 & 31) // Theme
        //         + [0, 12, 7, 19][tick >> 16 & 3]) / 12 - 6 // Adjustment
        //   );
        //   const bassLine = 30 * tick * 2 ** (
        //     ("%,%,%,%,%,%,(/(/,3,3(0,3".charCodeAt(
        //       8 * (tick >> 17 & 1 ? 2 : tick >> 15 & 1) + (tick >> 12 & 7)
        //     )) / 12 - 7
        //   );
        //   const melodyLine2 = melodyLine1 * 2;
        //   const melodyLine3 = melodyLine2 * 2;
        //   return transformValue(melodyLine1) / (5 - (iteration > 1))
        //     + (iteration > 0) / 5 * transformValue(melodyLine2)
        //     + (iteration > 1) * (transformValue(melodyLine3) / 5
        //     + transformValue(bassLine) / 4);
        // }
        // ```

        // Calculate the pitch of the value of the melody line at `_tick` as an
        // 18 decimal fixed point value in the range `[0, 255e18]`.
        int256 melody1 = int256(30 * _tick) * int256(2e18).powWad(
            (1e18 * int256(
                // Each note is 2**11 samples long (an eighth note at 117.1875
                // BPM), so `_tick >> 11`. Then, we take `% 32` because the
                // melody line is 32 notes long.
                ((MELODY_NOTES >> (((_tick >> 11) & 31) << 3)) & 0xFF)
                    // We adjust the melody's theme by transposing the theme
                    // by the corresponding amount every 2**16 samples. By
                    // adding to the pitch fetched for the melody line, we
                    // effectively repeat the theme 4 times with different
                    // transpositions.
                    + ((MELODY_TRANSPOSITIONS >> (((_tick >> 16) & 3) << 3)) & 0xFF)
            )) / 12 - int256(6e18)
        );
        // Calculate the pitch of the value of the bass line at `_tick` as an 18
        // decimal fixed point value in the range `[0, 255e18]`.
        int256 bass = int256(30 * _tick) * int256(2e18).powWad(
            (1e18 * int256(
                (BASS_NOTES >> (
                    // Calculate the starting offset of the bass line segment to
                    // read from. We want to read the segments in the following
                    // order: 0, 1, 0, 1, 2, 2, 2, 2. Each segment is 8 quarter
                    // notes long, or 2**15 samples long, so we can achieve this
                    // sequence by returning 2 if `(_tick >> 17) & 1` is 1, or
                    // taking the last bit of `_tick >> 15` otherwise.
                    ((((_tick >> 17) & 1 == 1) ? 2 : (_tick >> 15) & 1) << 3)
                        // Each note is 2**12 samples long (a quarter note at
                        // 117.1875 BPM), so `_tick >> 12`. Then, we take
                        // `% 8` because each segment of the bass line we read
                        // from is 8 notes long.
                        + ((_tick >> 12) & 7)
                )) & 0xFF
            )) / 12 - int256(7e18)
        );
        // Same as the first melody line, except 1 octave higher.
        int256 melody2 = melody1 * 2;
        // Same as the first melody line, except 2 octaves higher.
        int256 melody3 = melody2 * 2;

        // Truncate and transform pitch values to integer triangle wave values
        // in the range `[0, 255]` for a more pleasant sound.
        uint256 transformedMelody1 = _toTruncatedTriangleWaveValue(melody1);
        uint256 transformedBass = _toTruncatedTriangleWaveValue(bass);
        uint256 transformedMelody2 = _toTruncatedTriangleWaveValue(melody2);
        uint256 transformedMelody3 = _toTruncatedTriangleWaveValue(melody3);

        // We want to vary the loudness of each line every 2**18 samples in the
        // following volume (loudness) progressions, where 0 is the quietest
        // and 1 is the loudest:
        //                .-------------------------------------.
        //                | Line     | Rep. 0 | Rep. 1 | Rep. 2 |
        //                |----------|--------|--------|--------|
        //                | Melody 1 | 0.20   | 0.20   | 0.25   |
        //                | Melody 2 | 0.00   | 0.20   | 0.20   |
        //                | Melody 3 | 0.00   | 0.00   | 0.20   |
        //                | Bass     | 0.00   | 0.00   | 0.25   |
        //                |----------|--------|--------|--------|
        //                | TOTAL    | 0.20   | 0.40   | 0.90   |
        //                '-------------------------------------'
        // We achieve this with the following expression, which the `assembly`
        // block below is equivalent to:
        /// ```solidity
        // (
        //     (4 + iteration > 1) * transformedMelody1           
        //         + 4 * (iteration > 0) * transformedMelody2
        //         + 4 * (iteration > 1) * transformedMelody3
        //         + 5 * (iteration > 1) * transformedBass
        // ) / 20
        // ```
        uint256 iteration = (_tick >> 18) % 3;
        uint8 soundValue;
        assembly {
            soundValue := and(
                div(
                    add(
                        add(
                            mul(add(4, gt(iteration, 1)), transformedMelody1),
                            mul(mul(4, gt(iteration, 0)), transformedMelody2)
                        ),
                        add(
                            mul(mul(4, gt(iteration, 1)), transformedMelody3),
                            mul(mul(5, gt(iteration, 1)), transformedBass)
                        )
                    ),
                    20
                ),
                0xFF
            )
        }

        return soundValue;
    }

    /// @notice Truncate an 18 decimal fixed point value `_value`'s decimal
    /// component, and transform it to be on a triangle wave in the range
    /// `[0, 255]`.
    /// @param _value The 18 decimal fixed point value to transform.
    /// @return The truncated and transformed value in the range `[0, 255]`.
    function _toTruncatedTriangleWaveValue(int256 _value) internal pure returns (uint256) {
        uint256 truncatedValue;
        assembly {
            // `_value` can never be negative, so we can safely assign it
            // to a `uint256` value.
            truncatedValue := div(_value, 1000000000000000000) // 1e18
        }

        unchecked {
            return truncatedValue & 0x100 > 0
                ? truncatedValue & 0xFF
                : 256 - (truncatedValue & 0xFF); // Will never underflow.
        }
    }
}

File 9 of 10 : CurtaPCTF2023Metadata.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

/// @title Curta ^ Paradigm CTF 2023 commemorative NFT metadata
/// @notice A library for returning the metadata associated with players of the
/// Curta ^ Paradigm CTF 2023 team.
/// @dev Players have predetermined IDs (equal to the ID of the token they can
/// mint), names, and addresses (the addresses they can claim from). If a player
/// is not part of the team (i.e. there's no associated ID/address associated),
/// the functions will revert.
library CurtaPCTF2023Metadata {
    // -------------------------------------------------------------------------
    // Constants
    // -------------------------------------------------------------------------

    /// @notice The address of sudolabel (sudolabel.eth).
    address constant SUDOLABEL = 0x655aF72e1500EB8A8d1c90856Ae3B8f148A78471;

    /// @notice The address of Kalzak (kalzak.eth).
    address constant KALZAK = 0xd4057e08B9d484d70C5977784fC1f6D82d45ff67;

    /// @notice The address of seen (eoa.sina.eth).
    address constant SEEN = 0x2de14DB256Db2597fe3c8Eed46eF5b20bA390823;

    /// @notice The address of igorline (igorline.eth).
    address constant IGORLINE = 0x14869c6bF40BBc73e45821F7c28FD792151b3f9A;

    /// @notice The address of pogo (minimooger.eth).
    address constant POGO = 0x6E82554d7C496baCcc8d0bCB104A50B772d22a1F;

    /// @notice The address of popular (p0pular.eth).
    address constant POPULAR = 0x0Fc363b52E49074a395B075a6814Cb8F37E8F8BE;

    /// @notice The address of orenyomtov (orenyomtov.eth).
    address constant ORENYOMTOV = 0xD04Dd74d0a905E857278ac3A8bDaFadcD8BF8e87;

    /// @notice The address of 0x796 (vicnaum.eth).
    address constant ZERO_X_796 = 0x79635b386B9bd6636Cd701879C32E6dd181C853F;

    /// @notice The address of plotchy (plotchy.eth).
    address constant PLOTCHY = 0x97735C60c5E3C2788b7EE570306775e687095D19;

    /// @notice The address of forager (forager.eth).
    address constant FORAGER = 0x286cD2FF7Ad1337BaA783C345080e5Af9bBa0b6e;

    /// @notice The address of horsefacts (horsefacts.eth).
    address constant HORSEFACTS = 0x79d31bFcA5Fda7A4F15b36763d2e44C99D811a6C;

    /// @notice The address of datadanne (datadanne.eth).
    address constant DATADANNE = 0xBDfeB5439f5daecb78A17Ff846645A8bDBbF5725;

    /// @notice The address of brocke (brocke.eth).
    address constant BROCKE = 0x230d31EEC85F4063a405B0F95bdE509C0d0A8b5D;

    // -------------------------------------------------------------------------
    // Errors
    // -------------------------------------------------------------------------

    /// @notice Emitted when a player wasn't part of the Curta ^ Paradigm CTF
    /// 2023 team.
    /// @param _player The nonexistant player.
    error NonexistantPlayer(address _player);

    /// @notice Emitted when ID doesn't map to a player.
    /// @param _id The nonexistant ID.
    error NonexistantPlayerID(uint256 _id);

    // -------------------------------------------------------------------------
    // Functions
    // -------------------------------------------------------------------------

    /// @notice Returns the address of the player the token is attributed to.
    /// @dev Reverts if the token ID does not exist.
    /// @param _id The token ID.
    /// @return The address of the player the token is attributed to.
    function getPlayerAddress(uint256 _id) internal pure returns (address) {
        if (_id == 0) return SUDOLABEL;
        else if (_id == 1) return KALZAK;
        else if (_id == 2) return SEEN;
        else if (_id == 3) return IGORLINE;
        else if (_id == 4) return POGO;
        else if (_id == 5) return POPULAR;
        else if (_id == 6) return ORENYOMTOV;
        else if (_id == 7) return ZERO_X_796;
        else if (_id == 8) return PLOTCHY;
        else if (_id == 9) return FORAGER;
        else if (_id == 10) return HORSEFACTS;
        else if (_id == 11) return DATADANNE;
        else if (_id == 12) return BROCKE;
        revert NonexistantPlayerID(_id);
    }

    /// @notice Returns the ID of the player the token is attributed to.
    /// @dev Reverts if the player was not part of the Curta ^ Paradigm CTF 2023
    /// team.
    /// @param _player The player's address.
    /// @return The ID of the player the token is attributed to.
    function getPlayerId(address _player) internal pure returns (uint256) {
        if (_player == SUDOLABEL) return 0;
        else if (_player == KALZAK) return 1;
        else if (_player == SEEN) return 2;
        else if (_player == IGORLINE) return 3;
        else if (_player == POGO) return 4;
        else if (_player == POPULAR) return 5;
        else if (_player == ORENYOMTOV) return 6;
        else if (_player == ZERO_X_796) return 7;
        else if (_player == PLOTCHY) return 8;
        else if (_player == FORAGER) return 9;
        else if (_player == HORSEFACTS) return 10;
        else if (_player == DATADANNE) return 11;
        else if (_player == BROCKE) return 12;
        revert NonexistantPlayer(_player);
    }

    /// @notice Returns the name of the player the token is attributed to.
    /// @dev Reverts if the token ID does not exist.
    /// @param _id The token ID.
    /// @return The name of the player the token is attributed to.
    function getPlayerNameFromID(
        uint256 _id
    ) internal pure returns (string memory) {
        if (_id == 0) return "sudolabel";
        else if (_id == 1) return "Kalzak";
        else if (_id == 2) return "seen";
        else if (_id == 3) return "igorline";
        else if (_id == 4) return "pogo";
        else if (_id == 5) return "popular";
        else if (_id == 6) return "orenyomtov";
        else if (_id == 7) return "0x796";
        else if (_id == 8) return "plotchy";
        else if (_id == 9) return "forager";
        else if (_id == 10) return "horsefacts";
        else if (_id == 11) return "datadanne";
        else if (_id == 12) return "brocke";
        revert NonexistantPlayerID(_id);
    }
}

File 10 of 10 : FixedPointMathLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The operation failed, as the output exceeds the maximum value of uint256.
    error ExpOverflow();

    /// @dev The operation failed, as the output exceeds the maximum value of uint256.
    error FactorialOverflow();

    /// @dev The operation failed, due to an overflow.
    error RPowOverflow();

    /// @dev The operation failed, due to an multiplication overflow.
    error MulWadFailed();

    /// @dev The operation failed, either due to a
    /// multiplication overflow, or a division by a zero.
    error DivWadFailed();

    /// @dev The multiply-divide operation failed, either due to a
    /// multiplication overflow, or a division by a zero.
    error MulDivFailed();

    /// @dev The division failed, as the denominator is zero.
    error DivFailed();

    /// @dev The full precision multiply-divide operation failed, either due
    /// to the result being larger than 256 bits, or a division by a zero.
    error FullMulDivFailed();

    /// @dev The output is undefined, as the input is less-than-or-equal to zero.
    error LnWadUndefined();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The scalar of ETH and most ERC20s.
    uint256 internal constant WAD = 1e18;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*              SIMPLIFIED FIXED POINT OPERATIONS             */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to `(x * y) / WAD` rounded down.
    function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            if mul(y, gt(x, div(not(0), y))) {
                mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded up.
    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            if mul(y, gt(x, div(not(0), y))) {
                mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down.
    function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
            if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
                mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded up.
    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
            if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
                mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
        }
    }

    /// @dev Equivalent to `x` to the power of `y`.
    /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
    function powWad(int256 x, int256 y) internal pure returns (int256) {
        // Using `ln(x)` means `x` must be greater than 0.
        return expWad((lnWad(x) * y) / int256(WAD));
    }

    /// @dev Returns `exp(x)`, denominated in `WAD`.
    function expWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            // When the result is < 0.5 we return zero. This happens when
            // x <= floor(log(0.5e18) * 1e18) ~ -42e18
            if (x <= -42139678854452767551) return r;

            /// @solidity memory-safe-assembly
            assembly {
                // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
                // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
                if iszero(slt(x, 135305999368893231589)) {
                    mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
                    revert(0x1c, 0x04)
                }
            }

            // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
            // for more intermediate precision and a binary basis. This base conversion
            // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
            x = (x << 78) / 5 ** 18;

            // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
            // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
            // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
            int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
            x = x - k * 54916777467707473351141471128;

            // k is in the range [-61, 195].

            // Evaluate using a (6, 7)-term rational approximation.
            // p is made monic, we'll multiply by a scale factor later.
            int256 y = x + 1346386616545796478920950773328;
            y = ((y * x) >> 96) + 57155421227552351082224309758442;
            int256 p = y + x - 94201549194550492254356042504812;
            p = ((p * y) >> 96) + 28719021644029726153956944680412240;
            p = p * x + (4385272521454847904659076985693276 << 96);

            // We leave p in 2**192 basis so we don't need to scale it back up for the division.
            int256 q = x - 2855989394907223263936484059900;
            q = ((q * x) >> 96) + 50020603652535783019961831881945;
            q = ((q * x) >> 96) - 533845033583426703283633433725380;
            q = ((q * x) >> 96) + 3604857256930695427073651918091429;
            q = ((q * x) >> 96) - 14423608567350463180887372962807573;
            q = ((q * x) >> 96) + 26449188498355588339934803723976023;

            /// @solidity memory-safe-assembly
            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial won't have zeros in the domain as all its roots are complex.
                // No scaling is necessary because p is already 2**96 too large.
                r := sdiv(p, q)
            }

            // r should be in the range (0.09, 0.25) * 2**96.

            // We now need to multiply r by:
            // * the scale factor s = ~6.031367120.
            // * the 2**k factor from the range reduction.
            // * the 1e18 / 2**96 factor for base conversion.
            // We do this all at once, with an intermediate result in 2**213
            // basis, so the final right shift is always by a positive amount.
            r = int256(
                (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
            );
        }
    }

    /// @dev Returns `ln(x)`, denominated in `WAD`.
    function lnWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            /// @solidity memory-safe-assembly
            assembly {
                if iszero(sgt(x, 0)) {
                    mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
                    revert(0x1c, 0x04)
                }
            }

            // We want to convert x from 10**18 fixed point to 2**96 fixed point.
            // We do this by multiplying by 2**96 / 10**18. But since
            // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
            // and add ln(2**96 / 10**18) at the end.

            // Compute k = log2(x) - 96, t = 159 - k = 255 - log2(x) = 255 ^ log2(x).
            int256 t;
            /// @solidity memory-safe-assembly
            assembly {
                t := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
                t := or(t, shl(6, lt(0xffffffffffffffff, shr(t, x))))
                t := or(t, shl(5, lt(0xffffffff, shr(t, x))))
                t := or(t, shl(4, lt(0xffff, shr(t, x))))
                t := or(t, shl(3, lt(0xff, shr(t, x))))
                // forgefmt: disable-next-item
                t := xor(t, byte(and(0x1f, shr(shr(t, x), 0x8421084210842108cc6318c6db6d54be)),
                    0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))
            }

            // Reduce range of x to (1, 2) * 2**96
            // ln(2^k * x) = k * ln(2) + ln(x)
            x = int256(uint256(x << uint256(t)) >> 159);

            // Evaluate using a (8, 8)-term rational approximation.
            // p is made monic, we will multiply by a scale factor later.
            int256 p = x + 3273285459638523848632254066296;
            p = ((p * x) >> 96) + 24828157081833163892658089445524;
            p = ((p * x) >> 96) + 43456485725739037958740375743393;
            p = ((p * x) >> 96) - 11111509109440967052023855526967;
            p = ((p * x) >> 96) - 45023709667254063763336534515857;
            p = ((p * x) >> 96) - 14706773417378608786704636184526;
            p = p * x - (795164235651350426258249787498 << 96);

            // We leave p in 2**192 basis so we don't need to scale it back up for the division.
            // q is monic by convention.
            int256 q = x + 5573035233440673466300451813936;
            q = ((q * x) >> 96) + 71694874799317883764090561454958;
            q = ((q * x) >> 96) + 283447036172924575727196451306956;
            q = ((q * x) >> 96) + 401686690394027663651624208769553;
            q = ((q * x) >> 96) + 204048457590392012362485061816622;
            q = ((q * x) >> 96) + 31853899698501571402653359427138;
            q = ((q * x) >> 96) + 909429971244387300277376558375;
            /// @solidity memory-safe-assembly
            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial is known not to have zeros in the domain.
                // No scaling required because p is already 2**96 too large.
                r := sdiv(p, q)
            }

            // r is in the range (0, 0.125) * 2**96

            // Finalization, we need to:
            // * multiply by the scale factor s = 5.549…
            // * add ln(2**96 / 10**18)
            // * add k * ln(2)
            // * multiply by 10**18 / 2**96 = 5**18 >> 78

            // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
            r *= 1677202110996718588342820967067443963516166;
            // add ln(2) * k * 5e18 * 2**192
            r += 16597577552685614221487285958193947469193820559219878177908093499208371 * (159 - t);
            // add ln(2**96 / 10**18) * 5e18 * 2**192
            r += 600920179829731861736702779321621459595472258049074101567377883020018308;
            // base conversion: mul 2**18 / 2**192
            r >>= 174;
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  GENERAL NUMBER UTILITIES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Calculates `floor(a * b / d)` with full precision.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
    function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                // 512-bit multiply `[p1 p0] = x * y`.
                // Compute the product mod `2**256` and mod `2**256 - 1`
                // then use the Chinese Remainder Theorem to reconstruct
                // the 512 bit result. The result is stored in two 256
                // variables such that `product = p1 * 2**256 + p0`.

                // Least significant 256 bits of the product.
                let p0 := mul(x, y)
                let mm := mulmod(x, y, not(0))
                // Most significant 256 bits of the product.
                let p1 := sub(mm, add(p0, lt(mm, p0)))

                // Handle non-overflow cases, 256 by 256 division.
                if iszero(p1) {
                    if iszero(d) {
                        mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                        revert(0x1c, 0x04)
                    }
                    result := div(p0, d)
                    break
                }

                // Make sure the result is less than `2**256`. Also prevents `d == 0`.
                if iszero(gt(d, p1)) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }

                /*------------------- 512 by 256 division --------------------*/

                // Make division exact by subtracting the remainder from `[p1 p0]`.
                // Compute remainder using mulmod.
                let r := mulmod(x, y, d)
                // `t` is the least significant bit of `d`.
                // Always greater or equal to 1.
                let t := and(d, sub(0, d))
                // Divide `d` by `t`, which is a power of two.
                d := div(d, t)
                // Invert `d mod 2**256`
                // Now that `d` is an odd number, it has an inverse
                // modulo `2**256` such that `d * inv = 1 mod 2**256`.
                // Compute the inverse by starting with a seed that is correct
                // correct for four bits. That is, `d * inv = 1 mod 2**4`.
                let inv := xor(mul(3, d), 2)
                // Now use Newton-Raphson iteration to improve the precision.
                // Thanks to Hensel's lifting lemma, this also works in modular
                // arithmetic, doubling the correct bits in each step.
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
                result :=
                    mul(
                        // Divide [p1 p0] by the factors of two.
                        // Shift in bits from `p1` into `p0`. For this we need
                        // to flip `t` such that it is `2**256 / t`.
                        or(mul(sub(p1, gt(r, p0)), add(div(sub(0, t), t), 1)), div(sub(p0, r), t)),
                        // inverse mod 2**256
                        mul(inv, sub(2, mul(d, inv)))
                    )
                break
            }
        }
    }

    /// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Uniswap-v3-core under MIT license:
    /// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol
    function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
        result = fullMulDiv(x, y, d);
        /// @solidity memory-safe-assembly
        assembly {
            if mulmod(x, y, d) {
                result := add(result, 1)
                if iszero(result) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Returns `floor(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, y), d)
        }
    }

    /// @dev Returns `ceil(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
        }
    }

    /// @dev Returns `ceil(x / d)`.
    /// Reverts if `d` is zero.
    function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(d) {
                mstore(0x00, 0x65244e4e) // `DivFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(x, d))), div(x, d))
        }
    }

    /// @dev Returns `max(0, x - y)`.
    function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(gt(x, y), sub(x, y))
        }
    }

    /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
    /// Reverts if the computation overflows.
    function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
            if x {
                z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
                let half := shr(1, b) // Divide `b` by 2.
                // Divide `y` by 2 every iteration.
                for { y := shr(1, y) } y { y := shr(1, y) } {
                    let xx := mul(x, x) // Store x squared.
                    let xxRound := add(xx, half) // Round to the nearest number.
                    // Revert if `xx + half` overflowed, or if `x ** 2` overflows.
                    if or(lt(xxRound, xx), shr(128, x)) {
                        mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
                        revert(0x1c, 0x04)
                    }
                    x := div(xxRound, b) // Set `x` to scaled `xxRound`.
                    // If `y` is odd:
                    if and(y, 1) {
                        let zx := mul(z, x) // Compute `z * x`.
                        let zxRound := add(zx, half) // Round to the nearest number.
                        // If `z * x` overflowed or `zx + half` overflowed:
                        if or(xor(div(zx, x), z), lt(zxRound, zx)) {
                            // Revert if `x` is non-zero.
                            if iszero(iszero(x)) {
                                mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
                                revert(0x1c, 0x04)
                            }
                        }
                        z := div(zxRound, b) // Return properly scaled `zxRound`.
                    }
                }
            }
        }
    }

    /// @dev Returns the square root of `x`.
    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
            // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffffff, shr(r, x))))
            z := shl(shr(1, r), z)

            // Goal was to get `z*z*y` within a small factor of `x`. More iterations could
            // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
            // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
            // That's not possible if `x < 256` but we can just verify those cases exhaustively.

            // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
            // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
            // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.

            // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
            // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
            // with largest error when `s = 1` and when `s = 256` or `1/256`.

            // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
            // Then we can estimate `sqrt(y)` using
            // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.

            // There is no overflow risk here since `y < 2**136` after the first branch above.
            z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If `x+1` is a perfect square, the Babylonian method cycles between
            // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            z := sub(z, lt(div(x, z), z))
        }
    }

    /// @dev Returns the cube root of `x`.
    /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
    /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy
    function cbrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))

            z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))

            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)

            z := sub(z, lt(div(x, mul(z, z)), z))
        }
    }

    /// @dev Returns the square root of `x`, denominated in `WAD`.
    function sqrtWad(uint256 x) internal pure returns (uint256 z) {
        unchecked {
            z = 10 ** 9;
            if (x <= type(uint256).max / 10 ** 36 - 1) {
                x *= 10 ** 18;
                z = 1;
            }
            z *= sqrt(x);
        }
    }

    /// @dev Returns the cube root of `x`, denominated in `WAD`.
    function cbrtWad(uint256 x) internal pure returns (uint256 z) {
        unchecked {
            z = 10 ** 12;
            if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) {
                if (x >= type(uint256).max / 10 ** 36) {
                    x *= 10 ** 18;
                    z = 10 ** 6;
                } else {
                    x *= 10 ** 36;
                    z = 1;
                }
            }
            z *= cbrt(x);
        }
    }

    /// @dev Returns the factorial of `x`.
    function factorial(uint256 x) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(lt(x, 58)) {
                mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
                revert(0x1c, 0x04)
            }
            for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) }
        }
    }

    /// @dev Returns the log2 of `x`.
    /// Equivalent to computing the index of the most significant bit (MSB) of `x`.
    /// Returns 0 if `x` is zero.
    function log2(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0x0706060506020504060203020504030106050205030304010505030400000000))
        }
    }

    /// @dev Returns the log2 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log2Up(uint256 x) internal pure returns (uint256 r) {
        r = log2(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(shl(r, 1), x))
        }
    }

    /// @dev Returns the log10 of `x`.
    /// Returns 0 if `x` is zero.
    function log10(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(lt(x, 100000000000000000000000000000000000000)) {
                x := div(x, 100000000000000000000000000000000000000)
                r := 38
            }
            if iszero(lt(x, 100000000000000000000)) {
                x := div(x, 100000000000000000000)
                r := add(r, 20)
            }
            if iszero(lt(x, 10000000000)) {
                x := div(x, 10000000000)
                r := add(r, 10)
            }
            if iszero(lt(x, 100000)) {
                x := div(x, 100000)
                r := add(r, 5)
            }
            r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
        }
    }

    /// @dev Returns the log10 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log10Up(uint256 x) internal pure returns (uint256 r) {
        r = log10(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(exp(10, r), x))
        }
    }

    /// @dev Returns the log256 of `x`.
    /// Returns 0 if `x` is zero.
    function log256(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(shr(3, r), lt(0xff, shr(r, x)))
        }
    }

    /// @dev Returns the log256 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log256Up(uint256 x) internal pure returns (uint256 r) {
        r = log256(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(shl(shl(3, r), 1), x))
        }
    }

    /// @dev Returns the average of `x` and `y`.
    function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = (x & y) + ((x ^ y) >> 1);
        }
    }

    /// @dev Returns the average of `x` and `y`.
    function avg(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = (x >> 1) + (y >> 1) + (((x & 1) + (y & 1)) >> 1);
        }
    }

    /// @dev Returns the absolute value of `x`.
    function abs(int256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(sub(0, shr(255, x)), add(sub(0, shr(255, x)), x))
        }
    }

    /// @dev Returns the absolute distance between `x` and `y`.
    function dist(int256 x, int256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x))
        }
    }

    /// @dev Returns the minimum of `x` and `y`.
    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), lt(y, x)))
        }
    }

    /// @dev Returns the minimum of `x` and `y`.
    function min(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), slt(y, x)))
        }
    }

    /// @dev Returns the maximum of `x` and `y`.
    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), gt(y, x)))
        }
    }

    /// @dev Returns the maximum of `x` and `y`.
    function max(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), sgt(y, x)))
        }
    }

    /// @dev Returns `x`, bounded to `minValue` and `maxValue`.
    function clamp(uint256 x, uint256 minValue, uint256 maxValue)
        internal
        pure
        returns (uint256 z)
    {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
            z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
        }
    }

    /// @dev Returns `x`, bounded to `minValue` and `maxValue`.
    function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
            z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
        }
    }

    /// @dev Returns greatest common divisor of `x` and `y`.
    function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            for { z := x } y {} {
                let t := y
                y := mod(z, y)
                z := t
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   RAW NUMBER OPERATIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `x + y`, without checking for overflow.
    function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x + y;
        }
    }

    /// @dev Returns `x + y`, without checking for overflow.
    function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x + y;
        }
    }

    /// @dev Returns `x - y`, without checking for underflow.
    function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x - y;
        }
    }

    /// @dev Returns `x - y`, without checking for underflow.
    function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x - y;
        }
    }

    /// @dev Returns `x * y`, without checking for overflow.
    function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x * y;
        }
    }

    /// @dev Returns `x * y`, without checking for overflow.
    function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x * y;
        }
    }

    /// @dev Returns `x / y`, returning 0 if `y` is zero.
    function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(x, y)
        }
    }

    /// @dev Returns `x / y`, returning 0 if `y` is zero.
    function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := sdiv(x, y)
        }
    }

    /// @dev Returns `x % y`, returning 0 if `y` is zero.
    function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mod(x, y)
        }
    }

    /// @dev Returns `x % y`, returning 0 if `y` is zero.
    function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := smod(x, y)
        }
    }

    /// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
    function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := addmod(x, y, d)
        }
    }

    /// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
    function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mulmod(x, y, d)
        }
    }
}

Settings
{
  "remappings": [
    "transmissions11/solmate/=lib/solmate/src/",
    "forge-std/=lib/forge-std/src/",
    "solady/=lib/solady/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "solmate/=lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"NonexistantPlayer","type":"error"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"NonexistantPlayerID","type":"error"},{"inputs":[],"name":"TokenUnminted","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","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":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"SetBaseURI","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":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAudioWavFileHeader","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tick","type":"uint256"}],"name":"getSoundValueAtSample","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","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":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b50604051620046ae380380620046ae8339810160408190526200003491620000e9565b80604051806060016040528060258152602001620046896025913960408051808201909152601081526f504354467b43555237345f323032337d60801b60208201526000620000848382620001c0565b506001620000938282620001c0565b5050600680546001600160a01b0319166001600160a01b0384169081179091556040519091506000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350506200028c565b600060208284031215620000fc57600080fd5b81516001600160a01b03811681146200011457600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200014657607f821691505b6020821081036200016757634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001bb57600081815260208120601f850160051c81016020861015620001965750805b601f850160051c820191505b81811015620001b757828155600101620001a2565b5050505b505050565b81516001600160401b03811115620001dc57620001dc6200011b565b620001f481620001ed845462000131565b846200016d565b602080601f8311600181146200022c5760008415620002135750858301515b600019600386901b1c1916600185901b178555620001b7565b600085815260208120601f198616915b828110156200025d578886015182559484019460019091019084016200023c565b50858210156200027c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6143ed806200029c6000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c80636c0360eb116100d8578063b88d4fde1161008c578063e8a3d48511610066578063e8a3d48514610334578063e985e9c51461033c578063f2fde38b1461036a57600080fd5b8063b88d4fde14610306578063bd59342414610319578063c87b56dd1461032157600080fd5b80638da5cb5b116100bd5780638da5cb5b146102cb57806395d89b41146102eb578063a22cb465146102f357600080fd5b80636c0360eb146102a257806370a08231146102aa57600080fd5b806323b872dd1161012f57806342842e0e1161011457806342842e0e1461026957806355f804b31461027c5780636352211e1461028f57600080fd5b806323b872dd14610231578063333a70041461024457600080fd5b8063081812fc11610160578063081812fc146101b9578063095ea7b3146102145780631249c58b1461022957600080fd5b806301ffc9a71461017c57806306fdde03146101a4575b600080fd5b61018f61018a366004612752565b61037d565b60405190151581526020015b60405180910390f35b6101ac610462565b60405161019b91906127dd565b6101ef6101c73660046127f0565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61022761022236600461282d565b6104f0565b005b61022761063f565b61022761023f366004612857565b610659565b6102576102523660046127f0565b610920565b60405160ff909116815260200161019b565b610227610277366004612857565b61092b565b61022761028a3660046128dc565b610a95565b6101ef61029d3660046127f0565b610b61565b6101ac610bf2565b6102bd6102b836600461291e565b610bff565b60405190815260200161019b565b6006546101ef9073ffffffffffffffffffffffffffffffffffffffff1681565b6101ac610ca7565b610227610301366004612939565b610cb4565b610227610314366004612975565b610d4b565b6101ac610ea5565b6101ac61032f3660046127f0565b610eb4565b6101ac610f5f565b61018f61034a3660046129e4565b600560209081526000928352604080842090915290825290205460ff1681565b61022761037836600461291e565b610fc8565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316148061041057507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b8061045c57507f5b5e139f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000805461046f90612a17565b80601f016020809104026020016040519081016040528092919081815260200182805461049b90612a17565b80156104e85780601f106104bd576101008083540402835291602001916104e8565b820191906000526020600020905b8154815290600101906020018083116104cb57829003601f168201915b505050505081565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1633811480610553575073ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152604080832033845290915290205460ff165b6105be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a454400000000000000000000000000000000000060448201526064015b60405180910390fd5b60008281526004602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600061064a336110ba565b90506106563382611487565b50565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff8481169116146106e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f57524f4e475f46524f4d0000000000000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216610766576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e5400000000000000000000000000000060448201526064016105b5565b3373ffffffffffffffffffffffffffffffffffffffff841614806107ba575073ffffffffffffffffffffffffffffffffffffffff8316600090815260056020908152604080832033845290915290205460ff165b806107e8575060008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1633145b61084e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a454400000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055938616808352848320805460010190558583526002825284832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600061045c82611620565b610936838383610659565b73ffffffffffffffffffffffffffffffffffffffff82163b1580610a2a57506040517f150b7a020000000000000000000000000000000000000000000000000000000080825233600483015273ffffffffffffffffffffffffffffffffffffffff858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156109e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a069190612a6a565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b610a90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e540000000000000000000000000000000060448201526064016105b5565b505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016105b5565b6007610b23828483612b04565b507f23c8c9488efebfd474e85a7956de6f39b17c7ab88502d42a623db2d8e382bbaa8282604051610b55929190612c67565b60405180910390a15050565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610bed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f545f4d494e5445440000000000000000000000000000000000000000000060448201526064016105b5565b919050565b6007805461046f90612a17565b600073ffffffffffffffffffffffffffffffffffffffff8216610c7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a45524f5f41444452455353000000000000000000000000000000000000000060448201526064016105b5565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b6001805461046f90612a17565b33600081815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b610d56858585610659565b73ffffffffffffffffffffffffffffffffffffffff84163b1580610e3857506040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063150b7a0290610dd19033908a90899089908990600401612c83565b6020604051808303816000875af1158015610df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e149190612a6a565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b610e9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e540000000000000000000000000000000060448201526064016105b5565b5050505050565b6060610eaf6117f4565b905090565b60008181526002602052604090205460609073ffffffffffffffffffffffffffffffffffffffff16610f12576040517f1589363800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60078054610f1f90612a17565b159050610f56576007610f3183611814565b604051602001610f42929190612cea565b60405160208183030381529060405261045c565b61045c82611876565b6060610fa4604051806101a0016040528061017f8152602001613baf61017f9139604051602001610f909190612d8f565b6040516020818303038152906040526118fc565b604051602001610fb49190612e21565b604051602081830303815290604052905090565b60065473ffffffffffffffffffffffffffffffffffffffff163314611049576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016105b5565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b60007fffffffffffffffffffffffff9aa508d1eaff147572e36f7a951c470eb7587b8f73ffffffffffffffffffffffffffffffffffffffff83160161110157506000919050565b7fffffffffffffffffffffffff2bfa81f7462b7b28f3a68887b03e0927d2ba009973ffffffffffffffffffffffffffffffffffffffff83160161114657506001919050565b7fffffffffffffffffffffffffd21eb24da924da6801c37112b910a4df45c6f7dd73ffffffffffffffffffffffffffffffffffffffff83160161118b57506002919050565b7fffffffffffffffffffffffffeb7963940bf4438c1ba7de083d70286deae4c06673ffffffffffffffffffffffffffffffffffffffff8316016111d057506003919050565b7fffffffffffffffffffffffff917daab283b694533372f434efb5af488d2dd5e173ffffffffffffffffffffffffffffffffffffffff83160161121557506004919050565b7ffffffffffffffffffffffffff03c9c4ad1b6f8b5c6a4f8a597eb3470c817074273ffffffffffffffffffffffffffffffffffffffff83160161125a57506005919050565b7fffffffffffffffffffffffff2fb228b2f56fa17a8d8753c5742505232740717973ffffffffffffffffffffffffffffffffffffffff83160161129f57506006919050565b7fffffffffffffffffffffffff869ca4c79464299c9328fe7863cd1922e7e37ac173ffffffffffffffffffffffffffffffffffffffff8316016112e457506007919050565b7fffffffffffffffffffffffff688ca39f3a1c3d8774811a8fcf988a1978f6a2e773ffffffffffffffffffffffffffffffffffffffff83160161132957506008919050565b7fffffffffffffffffffffffffd7932d00852ecc845587c3cbaf7f1a506445f49273ffffffffffffffffffffffffffffffffffffffff83160161136e57506009919050565b7fffffffffffffffffffffffff862ce4035a02585b0ea4c989c2d1bb36627ee59473ffffffffffffffffffffffffffffffffffffffff8316016113b35750600a919050565b7fffffffffffffffffffffffff42014abc60a25134875e8007b99ba5742440a8db73ffffffffffffffffffffffffffffffffffffffff8316016113f85750600b919050565b7fffffffffffffffffffffffffdcf2ce1137a0bf9c5bfa4f06a421af63f2f574a373ffffffffffffffffffffffffffffffffffffffff83160161143d5750600c919050565b6040517f0fccfad700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216611504576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e5400000000000000000000000000000060448201526064016105b5565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f414c52454144595f4d494e54454400000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260036020908152604080832080546001019055848352600290915280822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000806116ac6753444835ec580000600c61167760ff6313070c006018600d8a901c161c8116907f2f2f2f2f2c282c2f312c282c2a2827252a2a262a2b2b272b2c2c282c2a28272560f860088b901c161c16612e95565b61168990670de0b6b3a7640000612ea8565b6116939190612f23565b61169d9190612f8b565b671bc16d674ec8000090611acf565b6116b784601e612fb2565b6116c19190612ea8565b90506000611735676124fee993bc0000600c600787821c166003600160118a901c8116146116f657600f89901c6001166116f9565b60025b61170492911b612e95565b77332c3028332c332c2f282f282c252c252c252c252c252c25901c60ff16670de0b6b3a76400006116899190612ea8565b61174085601e612fb2565b61174a9190612ea8565b90506000611759836002612ea8565b90506000611768826002612ea8565b9050600061177585611b07565b9050600061178285611b07565b9050600061178f85611b07565b9050600061179c85611b07565b905060006117af600360128d901c612fc9565b9050600060ff601486600185116005020285600186116004020201866000861160040202896001871160040102010104169050809a5050505050505050505050919050565b60606040518060600160405280602d8152602001613b82602d9139905090565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a90048061182f5750508190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909101908152919050565b6060600061188383611b33565b90506118d581604051806101a0016040528061017f8152602001613baf61017f91396118c16118b187611eb7565b604051602001610f909190612fdd565b84604051602001610f909493929190612ff9565b6040516020016118e59190612e21565b604051602081830303815290604052915050919050565b6060815160000361191b57505060408051602081019091526000815290565b6000604051806060016040528060408152602001613d2e6040913990506000600260038551600261194c9190612e95565b61195691906131a8565b901b90506000611967826020612e95565b67ffffffffffffffff81111561197f5761197f612a87565b6040519080825280601f01601f1916602001820160405280156119a9576020820181803683370190505b509050818152600183018586518101602084015b81831015611a175760039283018051603f601282901c811687015160f890811b8552600c83901c8216880151811b6001860152600683901c8216880151811b60028601529116860151901b938201939093526004016119bd565b600389510660018114611a315760028114611a7b57611ac1565b7f3d3d0000000000000000000000000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe830152611ac1565b7f3d000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8301525b509398975050505050505050565b6000611b00670de0b6b3a764000083611ae7866122a4565b611af19190612ea8565b611afb9190612f23565b612507565b9392505050565b6000670de0b6b3a764000082046101008116611b2a578060ff1661010003611b00565b60ff1692915050565b606081600003611b7657505060408051808201909152600981527f7375646f6c6162656c0000000000000000000000000000000000000000000000602082015290565b81600103611bb757505060408051808201909152600681527f4b616c7a616b0000000000000000000000000000000000000000000000000000602082015290565b81600203611bf857505060408051808201909152600481527f7365656e00000000000000000000000000000000000000000000000000000000602082015290565b81600303611c3957505060408051808201909152600881527f69676f726c696e65000000000000000000000000000000000000000000000000602082015290565b81600403611c7a57505060408051808201909152600481527f706f676f00000000000000000000000000000000000000000000000000000000602082015290565b81600503611cbb57505060408051808201909152600781527f706f70756c617200000000000000000000000000000000000000000000000000602082015290565b81600603611cfc57505060408051808201909152600a81527f6f72656e796f6d746f7600000000000000000000000000000000000000000000602082015290565b81600703611d3d57505060408051808201909152600581527f3078373936000000000000000000000000000000000000000000000000000000602082015290565b81600803611d7e57505060408051808201909152600781527f706c6f7463687900000000000000000000000000000000000000000000000000602082015290565b81600903611dbf57505060408051808201909152600781527f666f726167657200000000000000000000000000000000000000000000000000602082015290565b81600a03611e0057505060408051808201909152600a81527f686f727365666163747300000000000000000000000000000000000000000000602082015290565b81600b03611e4157505060408051808201909152600981527f6461746164616e6e650000000000000000000000000000000000000000000000602082015290565b81600c03611e8257505060408051808201909152600681527f62726f636b650000000000000000000000000000000000000000000000000000602082015290565b6040517f7e082e57000000000000000000000000000000000000000000000000000000008152600481018390526024016105b5565b606080604051806104800160405280610448815260200161373a6104489139611f186040518060400160405280600981526020017f7375646f6c6162656c0000000000000000000000000000000000000000000000815250856000146126ef565b611f5a6040518060400160405280600681526020017f4b616c7a616b0000000000000000000000000000000000000000000000000000815250866001146126ef565b611f9c6040518060400160405280600481526020017f7365656e00000000000000000000000000000000000000000000000000000000815250876002146126ef565b611fde6040518060400160405280600881526020017f69676f726c696e65000000000000000000000000000000000000000000000000815250886003146126ef565b6120206040518060400160405280600481526020017f706f676f00000000000000000000000000000000000000000000000000000000815250896004146126ef565b6120626040518060400160405280600781526020017f706f70756c6172000000000000000000000000000000000000000000000000008152508a6005146126ef565b6120a46040518060400160405280600a81526020017f6f72656e796f6d746f76000000000000000000000000000000000000000000008152508b6006146126ef565b6040516020016120bb9897969594939291906131bc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600582527f307837393600000000000000000000000000000000000000000000000000000060208301529150819061212790600786146126ef565b6121696040518060400160405280600781526020017f706c6f7463687900000000000000000000000000000000000000000000000000815250866008146126ef565b6121ab6040518060400160405280600781526020017f666f726167657200000000000000000000000000000000000000000000000000815250876009146126ef565b6121ed6040518060400160405280600a81526020017f686f72736566616374730000000000000000000000000000000000000000000081525088600a146126ef565b61222f6040518060400160405280600981526020017f6461746164616e6e65000000000000000000000000000000000000000000000081525089600b146126ef565b6122716040518060400160405280600581526020017f62726f636b0000000000000000000000000000000000000000000000000000008152508a600c146126ef565b60405180610680016040528061064a8152602001613d6e61064a91396040516020016118e5989796959493929190613478565b60008082136122bb57631615e6386000526004601cfd5b507ff8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff6f8421084210842108cc6318c6db6d54be6fffffffffffffffffffffffffffffffff831160071b83811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1783811c61ffff1060041b1783811c60ff1060031b1783811c9190911c601f169190911a1890811b609f90811c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506029190037d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c1821361253557919050565b680755bf798b4a1bf1e582126125535763a37bfec96000526004601cfd5b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b6060816126fc5782611b00565b8260405160200161270d91906136a7565b604051602081830303815290604052905092915050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461065657600080fd5b60006020828403121561276457600080fd5b8135611b0081612724565b60005b8381101561278a578181015183820152602001612772565b50506000910152565b600081518084526127ab81602086016020860161276f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611b006020830184612793565b60006020828403121561280257600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610bed57600080fd5b6000806040838503121561284057600080fd5b61284983612809565b946020939093013593505050565b60008060006060848603121561286c57600080fd5b61287584612809565b925061288360208501612809565b9150604084013590509250925092565b60008083601f8401126128a557600080fd5b50813567ffffffffffffffff8111156128bd57600080fd5b6020830191508360208285010111156128d557600080fd5b9250929050565b600080602083850312156128ef57600080fd5b823567ffffffffffffffff81111561290657600080fd5b61291285828601612893565b90969095509350505050565b60006020828403121561293057600080fd5b611b0082612809565b6000806040838503121561294c57600080fd5b61295583612809565b91506020830135801515811461296a57600080fd5b809150509250929050565b60008060008060006080868803121561298d57600080fd5b61299686612809565b94506129a460208701612809565b935060408601359250606086013567ffffffffffffffff8111156129c757600080fd5b6129d388828901612893565b969995985093965092949392505050565b600080604083850312156129f757600080fd5b612a0083612809565b9150612a0e60208401612809565b90509250929050565b600181811c90821680612a2b57607f821691505b602082108103612a64577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600060208284031215612a7c57600080fd5b8151611b0081612724565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f821115610a9057600081815260208120601f850160051c81016020861015612add5750805b601f850160051c820191505b81811015612afc57828155600101612ae9565b505050505050565b67ffffffffffffffff831115612b1c57612b1c612a87565b612b3083612b2a8354612a17565b83612ab6565b6000601f841160018114612b825760008515612b4c5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355610e9e565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015612bd15786850135825560209485019460019092019101612bb1565b5086821015612c0c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000612c7b602083018486612c1e565b949350505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152612cc3608083018486612c1e565b979650505050505050565b60008151612ce081856020860161276f565b9290920192915050565b6000808454612cf881612a17565b60018281168015612d105760018114612d4357612d72565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450612d72565b8860005260208060002060005b85811015612d695781548a820152908401908201612d50565b50505082870194505b505050508351612d8681836020880161276f565b01949350505050565b7f7b226e616d65223a224375727461205e20506172616469676d2043544620323081527f323320506c61796572204e465473222c226465736372697074696f6e223a2200602082015260008251612ded81603f85016020870161276f565b7f227d000000000000000000000000000000000000000000000000000000000000603f939091019283015250604101919050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612e5981601d85016020870161276f565b91909101601d0192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561045c5761045c612e66565b808202600082127f800000000000000000000000000000000000000000000000000000000000000084141615612ee057612ee0612e66565b818105831482151761045c5761045c612e66565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082612f3257612f32612ef4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615612f8657612f86612e66565b500590565b8181036000831280158383131683831282161715612fab57612fab612e66565b5092915050565b808202811582820484141761045c5761045c612e66565b600082612fd857612fd8612ef4565b500690565b60008251612fef81846020870161276f565b9190910192915050565b7f7b226e616d65223a220000000000000000000000000000000000000000000000815260008551613031816009850160208a0161276f565b7f20e28888204375727461205e20506172616469676d204354462032303233222c6009918401918201527f226465736372697074696f6e223a22000000000000000000000000000000000060298201528551613094816038840160208a0161276f565b7f222c22616e696d6174696f6e5f75726c223a22646174613a746578742f68746d603892909101918201527f6c3b636861727365743d7574662d383b6261736536342c000000000000000000605882015284516130f881606f84016020890161276f565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a2250606f92909101918201527f6c61796572222c2276616c7565223a2200000000000000000000000000000000608f820152612cc3613159609f830186612cce565b7f227d2c7b2274726169745f74797065223a2259656172222c2276616c7565223a81527f323032337d5d7d00000000000000000000000000000000000000000000000000602082015260270190565b6000826131b7576131b7612ef4565b500490565b600089516131ce818460208e0161276f565b8951908301906131e2818360208e0161276f565b8082019150507f20e29482e29482535553504943494f555320434841524954592020202020202081527f3336392e3936e294820ae29482000000000000000000000000000000000000006020820152885161324481602d840160208d0161276f565b7f20202020e29482e2948246524545205245414c20455354415445202020202020602d92909101918201527f2020202020312e3734e294820ae2948200000000000000000000000000000000604d82015287516132a881605d840160208c0161276f565b7f202020202020e29482e29482475241494e53204f462053414e44202020202020605d92909101918201527f20202020203334332e3939e294820ae294820000000000000000000000000000607d82015261346961341a6134146133c56133bf61337061336a61331b608f89018f612cce565b7f2020e29482e2948244524f50504552202020202020202020202020202020202081527f203233332e3232e294820ae294820000000000000000000000000000000000006020820152602e0190565b8c612cce565b7f202020202020e29482e29482434f534d494320524144494154494f4e2020202081527f20202020202034332e3738e294820ae294820000000000000000000000000000602082015260320190565b89612cce565b7f202020e29482e29482445241474f4e20545952414e542020202020202020202081527f20203432352e3133e294820ae2948200000000000000000000000000000000006020820152602f0190565b86612cce565b7fe29482e29482484f5050494e4720494e544f20504c414345202020202020203381527f31362e3535e294820ae2948200000000000000000000000000000000000000006020820152602c0190565b9b9a5050505050505050505050565b6000895161348a818460208e0161276f565b89519083019061349e818360208e0161276f565b8082019150507f2020202020e29482e29482454e544552505249534520424c4f434b434841494e81527f202020203237312e3232e294820ae2948200000000000000000000000000000060208201528851613500816031840160208d0161276f565b7f202020e29482e294824441492b2b202020202020202020202020202020202020603192909101918201527f20203331362e3535e294820ae29482000000000000000000000000000000000060518201528751613564816060840160208c0161276f565b7f202020e29482e29482444f444f4e54203c7370616e20636c6173733d633e5b46606092909101918201527f4952535420424c4f4f445d3c2f7370616e3e20202020203233332e3130e2948260808201527f0ae294820000000000000000000000000000000000000000000000000000000060a08201526134696136a161369b61364c6136466135f760a487018d612cce565b7fe29482e294824f56454e2020202020202020202020202020202020202020203281527f38312e3930e294820ae2948200000000000000000000000000000000000000006020820152602c0190565b8a612cce565b7f20e29482e29482534b494c4c2042415345442047414d4520202020202020202081527f3231342e3033e294820ae29482000000000000000000000000000000000000006020820152602d0190565b87612cce565b85612cce565b7f3c7370616e20636c6173733d63207374796c653d666f6e742d7765696768743a81527f3930303b746578742d6465636f726174696f6e3a756e6465726c696e653e000060208201526000825161370581603e85016020870161276f565b7f3c2f7370616e3e00000000000000000000000000000000000000000000000000603e93909101928301525060450191905056fe3c7374796c653e627574746f6e7b6865696768743a323070783b6d617267696e3a30206175746f3b626f726465723a303b6261636b67726f756e643a233030453130303b637572736f723a706f696e7465723b636f6c6f723a233030307d627574746f6e3a686f7665727b746578742d6465636f726174696f6e3a756e6465726c696e657d2e627b77696474683a35313270787d2e637b636f6c6f723a233030653130307d2e617b706f736974696f6e3a6162736f6c7574653b6d617267696e3a6175746f20303b626f726465722d7261646975733a313030253b746f703a3670783b77696474683a313270783b6865696768743a313270787d3c2f7374796c653e3c626f6479207374796c653d77696474683a36343070783b6865696768743a36343070783b6d617267696e3a303e3c64697620636c6173733d62207374796c653d226865696768743a35313270783b6261636b67726f756e643a233136313631363b70616464696e673a36347078223e3c646976207374796c653d226261636b67726f756e643a233030303b626f726465722d7261646975733a3870783b6865696768743a34363470783b6f766572666c6f773a68696464656e3b626f726465723a31707820736f6c696420233334333433343b6d617267696e3a323070782030223e3c646976207374796c653d706f736974696f6e3a72656c61746976653b646973706c61793a666c65783b77696474683a35303070783b6865696768743a323470783b6261636b67726f756e643a236461646164613b70616464696e672d6c6566743a3670783b70616464696e672d72696768743a3670783e3c636f6465207374796c653d666f6e742d7765696768743a3630303b6d617267696e3a6175746f3b636f6c6f723a233438343834383e4375727461205e20506172616469676d2043544620323032333c2f636f64653e3c646976207374796c653d6261636b67726f756e643a236564366135653b6c6566743a36707820636c6173733d613e3c2f6469763e3c646976207374796c653d6261636b67726f756e643a236635626634663b6c6566743a3232707820636c6173733d613e3c2f6469763e3c646976207374796c653d6261636b67726f756e643a233632633535353b6c6566743a3338707820636c6173733d613e3c2f6469763e3c2f6469763e3c707265207374796c653d2277696474683a34393670783b6865696768743a32393270783b646973706c61793a666c65783b70616464696e673a307078203870783b636f6c6f723a236666663b6d617267696e3a30223e3c636f6465207374796c653d6d617267696e3a6175746f3ee2948c3c7370616e20636c6173733d633e4d454d424552533c2f7370616e3ee29480e29480e29480e29490e2948c3c7370616e20636c6173733d633e4348414c4c454e47455320434f4d504c455445443c2f7370616e3ee29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e294900ae29482524946462e00180057415645666d74201000000001000100401f0000401f000001001000646174610000180080416e204e465420636f6c6c656374696f6e20746f20636f6d6d656d6f7261746520706c6179657273206f6620746865204375727461207465616d20666f722074686569722070617274696369706174696f6e20616e6420706572666f726d616e636520696e20746865203230323320506172616469676d204354462e20496e206164646974696f6e20746f20646973706c6179696e6720746865207465616d277320726573756c74732c20746865206d65746164617461206f66206561636820746f6b656e20636f6e7461696e7320612031303025206f6e636861696e2d67656e65726174656420313a3338206d696e757465206c6f6e6720617564696f20617272616e67656d656e74206f66205c22496e207468652048616c6c206f6620746865204d6f756e7461696e204b696e675c222062792045647661726420477269656720776974682033206c617965726564206d656c6f6479206c696e657320616e6420612062617373206c696e65206174203131372e313837352042504d2e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f2020202020e29482e29482313030252020202020202020202020202020202020202020203230302e3635e294820ae2948220202020202020202020e29482e29482424c41434b20574f524c4420202020202020202020202020203138322e3830e294820ae2948220202020202020202020e29482e2948248454c4c4f20574f524c4420202020202020202020202020203133332e3232e294820ae29494e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29498e29494e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e294983c2f636f64653e3c2f7072653e3c64697620636c6173733d62207374796c653d646973706c61793a666c65783e3c627574746f6e2069643d623e3c636f64653e5b205375626d697420504354467b43555237345f323032337d205d3c2f636f64653e3c2f627574746f6e3e3c2f6469763e3c617564696f2069643d613e596f75722062726f7773657220646f6573206e6f7420737570706f72742074686520617564696f20656c656d656e743c2f617564696f3e3c64697620636c6173733d62207374796c653d706f736974696f6e3a72656c61746976653b6865696768743a31323870783e3c63616e7661732069643d64207374796c653d706f736974696f6e3a6162736f6c7574652077696474683d353132206865696768743d3132383e3c2f63616e7661733e3c6469762069643d63207374796c653d22626f726465723a2e35707820736f6c696420233030653130303b6865696768743a31323770783b706f736974696f6e3a6162736f6c7574653b6c6566743a30223e3c2f6469763e3c2f6469763e3c2f6469763e3c7363726970743e646f63756d656e742e676574456c656d656e744279496428226222292e6164644576656e744c697374656e65722822636c69636b222c28293d3e7b673d303b6a3d303b666f7228733d22222c743d303b743c332a322a2a31383b742b2b297b633d2263686172436f64654174222c753d28743e3e31382925332c723d2874293d3e74263235363f74263235353a3235362d287426323535292c613d33302a742a322a2a2828222527282a2c282c2c2b272b2b2a262a2a2527282a2c282c312f2c282c2f2f2f2f225b635d28743e3e3131263331292b5b302c31322c372c31395d5b743e3e313626335d292f31322d36292c783d33302a742a322a2a282822252c252c252c252c252c252c282f282f2c332c3328302c33225b635d28382a28743e3e313726313f323a743e3e31352631292b28743e3e313226372929292f31322d37292c793d612a322c7a3d792a323b732b3d537472696e672e66726f6d43686172436f64652828722861292f28352d28753e3129292b28753e30292f352a722879292b28753e31292a2872287a292f352b722878292f342929253235367c30297d613d646f63756d656e742e676574456c656d656e744279496428226122293b612e7372633d22646174613a617564696f2f7761763b6261736536342c556b6c47526934414741425851565a465a6d3130494241414141414241414541514238414145416641414142414167415a4746305951414147414341222b62746f612873293b612e706c617928293b736574496e74657276616c2828293d3e7b633d646f63756d656e742e676574456c656d656e744279496428226322293b632e7374796c652e6c6566743d284d6174682e6d696e283132382a672b3132382c6a2b2b292a3130302f313238292b2225223b7d2c3332293b683d28293d3e7b643d646f63756d656e742e676574456c656d656e744279496428226422292e676574436f6e746578742822326422293b642e636c6561725265637428302c302c3531322c313238293b642e66696c6c5374796c653d2223464646223b5b2e2e2e41727261792834303936295d2e6d617028285f2c69293d3e7b642e626567696e5061746828293b642e61726328692f382c3132382d732e63686172436f646541742833323736382a672b692a38292f322c312c302c322a4d6174682e5049293b642e66696c6c28293b7d293b672b2b3b6a3d303b7d3b6828293b736574496e74657276616c28682c34303936297d293c2f7363726970743ea2646970667358221220014028a5543be52c0f1d32e7068286c08c6bd65bd1b045bf34f55a45a8d5c19e64736f6c634300081500334375727461205e20506172616469676d20435446203230323320506c61796572204e4654730000000000000000000000005dd2083a0d68c4eb8fed93ef010d1b0d68b3880f

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101775760003560e01c80636c0360eb116100d8578063b88d4fde1161008c578063e8a3d48511610066578063e8a3d48514610334578063e985e9c51461033c578063f2fde38b1461036a57600080fd5b8063b88d4fde14610306578063bd59342414610319578063c87b56dd1461032157600080fd5b80638da5cb5b116100bd5780638da5cb5b146102cb57806395d89b41146102eb578063a22cb465146102f357600080fd5b80636c0360eb146102a257806370a08231146102aa57600080fd5b806323b872dd1161012f57806342842e0e1161011457806342842e0e1461026957806355f804b31461027c5780636352211e1461028f57600080fd5b806323b872dd14610231578063333a70041461024457600080fd5b8063081812fc11610160578063081812fc146101b9578063095ea7b3146102145780631249c58b1461022957600080fd5b806301ffc9a71461017c57806306fdde03146101a4575b600080fd5b61018f61018a366004612752565b61037d565b60405190151581526020015b60405180910390f35b6101ac610462565b60405161019b91906127dd565b6101ef6101c73660046127f0565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61022761022236600461282d565b6104f0565b005b61022761063f565b61022761023f366004612857565b610659565b6102576102523660046127f0565b610920565b60405160ff909116815260200161019b565b610227610277366004612857565b61092b565b61022761028a3660046128dc565b610a95565b6101ef61029d3660046127f0565b610b61565b6101ac610bf2565b6102bd6102b836600461291e565b610bff565b60405190815260200161019b565b6006546101ef9073ffffffffffffffffffffffffffffffffffffffff1681565b6101ac610ca7565b610227610301366004612939565b610cb4565b610227610314366004612975565b610d4b565b6101ac610ea5565b6101ac61032f3660046127f0565b610eb4565b6101ac610f5f565b61018f61034a3660046129e4565b600560209081526000928352604080842090915290825290205460ff1681565b61022761037836600461291e565b610fc8565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316148061041057507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b8061045c57507f5b5e139f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000805461046f90612a17565b80601f016020809104026020016040519081016040528092919081815260200182805461049b90612a17565b80156104e85780601f106104bd576101008083540402835291602001916104e8565b820191906000526020600020905b8154815290600101906020018083116104cb57829003601f168201915b505050505081565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1633811480610553575073ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152604080832033845290915290205460ff165b6105be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a454400000000000000000000000000000000000060448201526064015b60405180910390fd5b60008281526004602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600061064a336110ba565b90506106563382611487565b50565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff8481169116146106e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f57524f4e475f46524f4d0000000000000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216610766576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e5400000000000000000000000000000060448201526064016105b5565b3373ffffffffffffffffffffffffffffffffffffffff841614806107ba575073ffffffffffffffffffffffffffffffffffffffff8316600090815260056020908152604080832033845290915290205460ff165b806107e8575060008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1633145b61084e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a454400000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055938616808352848320805460010190558583526002825284832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600061045c82611620565b610936838383610659565b73ffffffffffffffffffffffffffffffffffffffff82163b1580610a2a57506040517f150b7a020000000000000000000000000000000000000000000000000000000080825233600483015273ffffffffffffffffffffffffffffffffffffffff858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156109e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a069190612a6a565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b610a90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e540000000000000000000000000000000060448201526064016105b5565b505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016105b5565b6007610b23828483612b04565b507f23c8c9488efebfd474e85a7956de6f39b17c7ab88502d42a623db2d8e382bbaa8282604051610b55929190612c67565b60405180910390a15050565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610bed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f545f4d494e5445440000000000000000000000000000000000000000000060448201526064016105b5565b919050565b6007805461046f90612a17565b600073ffffffffffffffffffffffffffffffffffffffff8216610c7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a45524f5f41444452455353000000000000000000000000000000000000000060448201526064016105b5565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b6001805461046f90612a17565b33600081815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b610d56858585610659565b73ffffffffffffffffffffffffffffffffffffffff84163b1580610e3857506040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063150b7a0290610dd19033908a90899089908990600401612c83565b6020604051808303816000875af1158015610df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e149190612a6a565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b610e9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e540000000000000000000000000000000060448201526064016105b5565b5050505050565b6060610eaf6117f4565b905090565b60008181526002602052604090205460609073ffffffffffffffffffffffffffffffffffffffff16610f12576040517f1589363800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60078054610f1f90612a17565b159050610f56576007610f3183611814565b604051602001610f42929190612cea565b60405160208183030381529060405261045c565b61045c82611876565b6060610fa4604051806101a0016040528061017f8152602001613baf61017f9139604051602001610f909190612d8f565b6040516020818303038152906040526118fc565b604051602001610fb49190612e21565b604051602081830303815290604052905090565b60065473ffffffffffffffffffffffffffffffffffffffff163314611049576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016105b5565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b60007fffffffffffffffffffffffff9aa508d1eaff147572e36f7a951c470eb7587b8f73ffffffffffffffffffffffffffffffffffffffff83160161110157506000919050565b7fffffffffffffffffffffffff2bfa81f7462b7b28f3a68887b03e0927d2ba009973ffffffffffffffffffffffffffffffffffffffff83160161114657506001919050565b7fffffffffffffffffffffffffd21eb24da924da6801c37112b910a4df45c6f7dd73ffffffffffffffffffffffffffffffffffffffff83160161118b57506002919050565b7fffffffffffffffffffffffffeb7963940bf4438c1ba7de083d70286deae4c06673ffffffffffffffffffffffffffffffffffffffff8316016111d057506003919050565b7fffffffffffffffffffffffff917daab283b694533372f434efb5af488d2dd5e173ffffffffffffffffffffffffffffffffffffffff83160161121557506004919050565b7ffffffffffffffffffffffffff03c9c4ad1b6f8b5c6a4f8a597eb3470c817074273ffffffffffffffffffffffffffffffffffffffff83160161125a57506005919050565b7fffffffffffffffffffffffff2fb228b2f56fa17a8d8753c5742505232740717973ffffffffffffffffffffffffffffffffffffffff83160161129f57506006919050565b7fffffffffffffffffffffffff869ca4c79464299c9328fe7863cd1922e7e37ac173ffffffffffffffffffffffffffffffffffffffff8316016112e457506007919050565b7fffffffffffffffffffffffff688ca39f3a1c3d8774811a8fcf988a1978f6a2e773ffffffffffffffffffffffffffffffffffffffff83160161132957506008919050565b7fffffffffffffffffffffffffd7932d00852ecc845587c3cbaf7f1a506445f49273ffffffffffffffffffffffffffffffffffffffff83160161136e57506009919050565b7fffffffffffffffffffffffff862ce4035a02585b0ea4c989c2d1bb36627ee59473ffffffffffffffffffffffffffffffffffffffff8316016113b35750600a919050565b7fffffffffffffffffffffffff42014abc60a25134875e8007b99ba5742440a8db73ffffffffffffffffffffffffffffffffffffffff8316016113f85750600b919050565b7fffffffffffffffffffffffffdcf2ce1137a0bf9c5bfa4f06a421af63f2f574a373ffffffffffffffffffffffffffffffffffffffff83160161143d5750600c919050565b6040517f0fccfad700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216611504576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e5400000000000000000000000000000060448201526064016105b5565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f414c52454144595f4d494e54454400000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260036020908152604080832080546001019055848352600290915280822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000806116ac6753444835ec580000600c61167760ff6313070c006018600d8a901c161c8116907f2f2f2f2f2c282c2f312c282c2a2827252a2a262a2b2b272b2c2c282c2a28272560f860088b901c161c16612e95565b61168990670de0b6b3a7640000612ea8565b6116939190612f23565b61169d9190612f8b565b671bc16d674ec8000090611acf565b6116b784601e612fb2565b6116c19190612ea8565b90506000611735676124fee993bc0000600c600787821c166003600160118a901c8116146116f657600f89901c6001166116f9565b60025b61170492911b612e95565b77332c3028332c332c2f282f282c252c252c252c252c252c25901c60ff16670de0b6b3a76400006116899190612ea8565b61174085601e612fb2565b61174a9190612ea8565b90506000611759836002612ea8565b90506000611768826002612ea8565b9050600061177585611b07565b9050600061178285611b07565b9050600061178f85611b07565b9050600061179c85611b07565b905060006117af600360128d901c612fc9565b9050600060ff601486600185116005020285600186116004020201866000861160040202896001871160040102010104169050809a5050505050505050505050919050565b60606040518060600160405280602d8152602001613b82602d9139905090565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a90048061182f5750508190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909101908152919050565b6060600061188383611b33565b90506118d581604051806101a0016040528061017f8152602001613baf61017f91396118c16118b187611eb7565b604051602001610f909190612fdd565b84604051602001610f909493929190612ff9565b6040516020016118e59190612e21565b604051602081830303815290604052915050919050565b6060815160000361191b57505060408051602081019091526000815290565b6000604051806060016040528060408152602001613d2e6040913990506000600260038551600261194c9190612e95565b61195691906131a8565b901b90506000611967826020612e95565b67ffffffffffffffff81111561197f5761197f612a87565b6040519080825280601f01601f1916602001820160405280156119a9576020820181803683370190505b509050818152600183018586518101602084015b81831015611a175760039283018051603f601282901c811687015160f890811b8552600c83901c8216880151811b6001860152600683901c8216880151811b60028601529116860151901b938201939093526004016119bd565b600389510660018114611a315760028114611a7b57611ac1565b7f3d3d0000000000000000000000000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe830152611ac1565b7f3d000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8301525b509398975050505050505050565b6000611b00670de0b6b3a764000083611ae7866122a4565b611af19190612ea8565b611afb9190612f23565b612507565b9392505050565b6000670de0b6b3a764000082046101008116611b2a578060ff1661010003611b00565b60ff1692915050565b606081600003611b7657505060408051808201909152600981527f7375646f6c6162656c0000000000000000000000000000000000000000000000602082015290565b81600103611bb757505060408051808201909152600681527f4b616c7a616b0000000000000000000000000000000000000000000000000000602082015290565b81600203611bf857505060408051808201909152600481527f7365656e00000000000000000000000000000000000000000000000000000000602082015290565b81600303611c3957505060408051808201909152600881527f69676f726c696e65000000000000000000000000000000000000000000000000602082015290565b81600403611c7a57505060408051808201909152600481527f706f676f00000000000000000000000000000000000000000000000000000000602082015290565b81600503611cbb57505060408051808201909152600781527f706f70756c617200000000000000000000000000000000000000000000000000602082015290565b81600603611cfc57505060408051808201909152600a81527f6f72656e796f6d746f7600000000000000000000000000000000000000000000602082015290565b81600703611d3d57505060408051808201909152600581527f3078373936000000000000000000000000000000000000000000000000000000602082015290565b81600803611d7e57505060408051808201909152600781527f706c6f7463687900000000000000000000000000000000000000000000000000602082015290565b81600903611dbf57505060408051808201909152600781527f666f726167657200000000000000000000000000000000000000000000000000602082015290565b81600a03611e0057505060408051808201909152600a81527f686f727365666163747300000000000000000000000000000000000000000000602082015290565b81600b03611e4157505060408051808201909152600981527f6461746164616e6e650000000000000000000000000000000000000000000000602082015290565b81600c03611e8257505060408051808201909152600681527f62726f636b650000000000000000000000000000000000000000000000000000602082015290565b6040517f7e082e57000000000000000000000000000000000000000000000000000000008152600481018390526024016105b5565b606080604051806104800160405280610448815260200161373a6104489139611f186040518060400160405280600981526020017f7375646f6c6162656c0000000000000000000000000000000000000000000000815250856000146126ef565b611f5a6040518060400160405280600681526020017f4b616c7a616b0000000000000000000000000000000000000000000000000000815250866001146126ef565b611f9c6040518060400160405280600481526020017f7365656e00000000000000000000000000000000000000000000000000000000815250876002146126ef565b611fde6040518060400160405280600881526020017f69676f726c696e65000000000000000000000000000000000000000000000000815250886003146126ef565b6120206040518060400160405280600481526020017f706f676f00000000000000000000000000000000000000000000000000000000815250896004146126ef565b6120626040518060400160405280600781526020017f706f70756c6172000000000000000000000000000000000000000000000000008152508a6005146126ef565b6120a46040518060400160405280600a81526020017f6f72656e796f6d746f76000000000000000000000000000000000000000000008152508b6006146126ef565b6040516020016120bb9897969594939291906131bc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600582527f307837393600000000000000000000000000000000000000000000000000000060208301529150819061212790600786146126ef565b6121696040518060400160405280600781526020017f706c6f7463687900000000000000000000000000000000000000000000000000815250866008146126ef565b6121ab6040518060400160405280600781526020017f666f726167657200000000000000000000000000000000000000000000000000815250876009146126ef565b6121ed6040518060400160405280600a81526020017f686f72736566616374730000000000000000000000000000000000000000000081525088600a146126ef565b61222f6040518060400160405280600981526020017f6461746164616e6e65000000000000000000000000000000000000000000000081525089600b146126ef565b6122716040518060400160405280600581526020017f62726f636b0000000000000000000000000000000000000000000000000000008152508a600c146126ef565b60405180610680016040528061064a8152602001613d6e61064a91396040516020016118e5989796959493929190613478565b60008082136122bb57631615e6386000526004601cfd5b507ff8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff6f8421084210842108cc6318c6db6d54be6fffffffffffffffffffffffffffffffff831160071b83811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1783811c61ffff1060041b1783811c60ff1060031b1783811c9190911c601f169190911a1890811b609f90811c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506029190037d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c1821361253557919050565b680755bf798b4a1bf1e582126125535763a37bfec96000526004601cfd5b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b6060816126fc5782611b00565b8260405160200161270d91906136a7565b604051602081830303815290604052905092915050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461065657600080fd5b60006020828403121561276457600080fd5b8135611b0081612724565b60005b8381101561278a578181015183820152602001612772565b50506000910152565b600081518084526127ab81602086016020860161276f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611b006020830184612793565b60006020828403121561280257600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610bed57600080fd5b6000806040838503121561284057600080fd5b61284983612809565b946020939093013593505050565b60008060006060848603121561286c57600080fd5b61287584612809565b925061288360208501612809565b9150604084013590509250925092565b60008083601f8401126128a557600080fd5b50813567ffffffffffffffff8111156128bd57600080fd5b6020830191508360208285010111156128d557600080fd5b9250929050565b600080602083850312156128ef57600080fd5b823567ffffffffffffffff81111561290657600080fd5b61291285828601612893565b90969095509350505050565b60006020828403121561293057600080fd5b611b0082612809565b6000806040838503121561294c57600080fd5b61295583612809565b91506020830135801515811461296a57600080fd5b809150509250929050565b60008060008060006080868803121561298d57600080fd5b61299686612809565b94506129a460208701612809565b935060408601359250606086013567ffffffffffffffff8111156129c757600080fd5b6129d388828901612893565b969995985093965092949392505050565b600080604083850312156129f757600080fd5b612a0083612809565b9150612a0e60208401612809565b90509250929050565b600181811c90821680612a2b57607f821691505b602082108103612a64577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600060208284031215612a7c57600080fd5b8151611b0081612724565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f821115610a9057600081815260208120601f850160051c81016020861015612add5750805b601f850160051c820191505b81811015612afc57828155600101612ae9565b505050505050565b67ffffffffffffffff831115612b1c57612b1c612a87565b612b3083612b2a8354612a17565b83612ab6565b6000601f841160018114612b825760008515612b4c5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355610e9e565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015612bd15786850135825560209485019460019092019101612bb1565b5086821015612c0c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000612c7b602083018486612c1e565b949350505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152612cc3608083018486612c1e565b979650505050505050565b60008151612ce081856020860161276f565b9290920192915050565b6000808454612cf881612a17565b60018281168015612d105760018114612d4357612d72565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450612d72565b8860005260208060002060005b85811015612d695781548a820152908401908201612d50565b50505082870194505b505050508351612d8681836020880161276f565b01949350505050565b7f7b226e616d65223a224375727461205e20506172616469676d2043544620323081527f323320506c61796572204e465473222c226465736372697074696f6e223a2200602082015260008251612ded81603f85016020870161276f565b7f227d000000000000000000000000000000000000000000000000000000000000603f939091019283015250604101919050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612e5981601d85016020870161276f565b91909101601d0192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561045c5761045c612e66565b808202600082127f800000000000000000000000000000000000000000000000000000000000000084141615612ee057612ee0612e66565b818105831482151761045c5761045c612e66565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082612f3257612f32612ef4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615612f8657612f86612e66565b500590565b8181036000831280158383131683831282161715612fab57612fab612e66565b5092915050565b808202811582820484141761045c5761045c612e66565b600082612fd857612fd8612ef4565b500690565b60008251612fef81846020870161276f565b9190910192915050565b7f7b226e616d65223a220000000000000000000000000000000000000000000000815260008551613031816009850160208a0161276f565b7f20e28888204375727461205e20506172616469676d204354462032303233222c6009918401918201527f226465736372697074696f6e223a22000000000000000000000000000000000060298201528551613094816038840160208a0161276f565b7f222c22616e696d6174696f6e5f75726c223a22646174613a746578742f68746d603892909101918201527f6c3b636861727365743d7574662d383b6261736536342c000000000000000000605882015284516130f881606f84016020890161276f565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a2250606f92909101918201527f6c61796572222c2276616c7565223a2200000000000000000000000000000000608f820152612cc3613159609f830186612cce565b7f227d2c7b2274726169745f74797065223a2259656172222c2276616c7565223a81527f323032337d5d7d00000000000000000000000000000000000000000000000000602082015260270190565b6000826131b7576131b7612ef4565b500490565b600089516131ce818460208e0161276f565b8951908301906131e2818360208e0161276f565b8082019150507f20e29482e29482535553504943494f555320434841524954592020202020202081527f3336392e3936e294820ae29482000000000000000000000000000000000000006020820152885161324481602d840160208d0161276f565b7f20202020e29482e2948246524545205245414c20455354415445202020202020602d92909101918201527f2020202020312e3734e294820ae2948200000000000000000000000000000000604d82015287516132a881605d840160208c0161276f565b7f202020202020e29482e29482475241494e53204f462053414e44202020202020605d92909101918201527f20202020203334332e3939e294820ae294820000000000000000000000000000607d82015261346961341a6134146133c56133bf61337061336a61331b608f89018f612cce565b7f2020e29482e2948244524f50504552202020202020202020202020202020202081527f203233332e3232e294820ae294820000000000000000000000000000000000006020820152602e0190565b8c612cce565b7f202020202020e29482e29482434f534d494320524144494154494f4e2020202081527f20202020202034332e3738e294820ae294820000000000000000000000000000602082015260320190565b89612cce565b7f202020e29482e29482445241474f4e20545952414e542020202020202020202081527f20203432352e3133e294820ae2948200000000000000000000000000000000006020820152602f0190565b86612cce565b7fe29482e29482484f5050494e4720494e544f20504c414345202020202020203381527f31362e3535e294820ae2948200000000000000000000000000000000000000006020820152602c0190565b9b9a5050505050505050505050565b6000895161348a818460208e0161276f565b89519083019061349e818360208e0161276f565b8082019150507f2020202020e29482e29482454e544552505249534520424c4f434b434841494e81527f202020203237312e3232e294820ae2948200000000000000000000000000000060208201528851613500816031840160208d0161276f565b7f202020e29482e294824441492b2b202020202020202020202020202020202020603192909101918201527f20203331362e3535e294820ae29482000000000000000000000000000000000060518201528751613564816060840160208c0161276f565b7f202020e29482e29482444f444f4e54203c7370616e20636c6173733d633e5b46606092909101918201527f4952535420424c4f4f445d3c2f7370616e3e20202020203233332e3130e2948260808201527f0ae294820000000000000000000000000000000000000000000000000000000060a08201526134696136a161369b61364c6136466135f760a487018d612cce565b7fe29482e294824f56454e2020202020202020202020202020202020202020203281527f38312e3930e294820ae2948200000000000000000000000000000000000000006020820152602c0190565b8a612cce565b7f20e29482e29482534b494c4c2042415345442047414d4520202020202020202081527f3231342e3033e294820ae29482000000000000000000000000000000000000006020820152602d0190565b87612cce565b85612cce565b7f3c7370616e20636c6173733d63207374796c653d666f6e742d7765696768743a81527f3930303b746578742d6465636f726174696f6e3a756e6465726c696e653e000060208201526000825161370581603e85016020870161276f565b7f3c2f7370616e3e00000000000000000000000000000000000000000000000000603e93909101928301525060450191905056fe3c7374796c653e627574746f6e7b6865696768743a323070783b6d617267696e3a30206175746f3b626f726465723a303b6261636b67726f756e643a233030453130303b637572736f723a706f696e7465723b636f6c6f723a233030307d627574746f6e3a686f7665727b746578742d6465636f726174696f6e3a756e6465726c696e657d2e627b77696474683a35313270787d2e637b636f6c6f723a233030653130307d2e617b706f736974696f6e3a6162736f6c7574653b6d617267696e3a6175746f20303b626f726465722d7261646975733a313030253b746f703a3670783b77696474683a313270783b6865696768743a313270787d3c2f7374796c653e3c626f6479207374796c653d77696474683a36343070783b6865696768743a36343070783b6d617267696e3a303e3c64697620636c6173733d62207374796c653d226865696768743a35313270783b6261636b67726f756e643a233136313631363b70616464696e673a36347078223e3c646976207374796c653d226261636b67726f756e643a233030303b626f726465722d7261646975733a3870783b6865696768743a34363470783b6f766572666c6f773a68696464656e3b626f726465723a31707820736f6c696420233334333433343b6d617267696e3a323070782030223e3c646976207374796c653d706f736974696f6e3a72656c61746976653b646973706c61793a666c65783b77696474683a35303070783b6865696768743a323470783b6261636b67726f756e643a236461646164613b70616464696e672d6c6566743a3670783b70616464696e672d72696768743a3670783e3c636f6465207374796c653d666f6e742d7765696768743a3630303b6d617267696e3a6175746f3b636f6c6f723a233438343834383e4375727461205e20506172616469676d2043544620323032333c2f636f64653e3c646976207374796c653d6261636b67726f756e643a236564366135653b6c6566743a36707820636c6173733d613e3c2f6469763e3c646976207374796c653d6261636b67726f756e643a236635626634663b6c6566743a3232707820636c6173733d613e3c2f6469763e3c646976207374796c653d6261636b67726f756e643a233632633535353b6c6566743a3338707820636c6173733d613e3c2f6469763e3c2f6469763e3c707265207374796c653d2277696474683a34393670783b6865696768743a32393270783b646973706c61793a666c65783b70616464696e673a307078203870783b636f6c6f723a236666663b6d617267696e3a30223e3c636f6465207374796c653d6d617267696e3a6175746f3ee2948c3c7370616e20636c6173733d633e4d454d424552533c2f7370616e3ee29480e29480e29480e29490e2948c3c7370616e20636c6173733d633e4348414c4c454e47455320434f4d504c455445443c2f7370616e3ee29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e294900ae29482524946462e00180057415645666d74201000000001000100401f0000401f000001001000646174610000180080416e204e465420636f6c6c656374696f6e20746f20636f6d6d656d6f7261746520706c6179657273206f6620746865204375727461207465616d20666f722074686569722070617274696369706174696f6e20616e6420706572666f726d616e636520696e20746865203230323320506172616469676d204354462e20496e206164646974696f6e20746f20646973706c6179696e6720746865207465616d277320726573756c74732c20746865206d65746164617461206f66206561636820746f6b656e20636f6e7461696e7320612031303025206f6e636861696e2d67656e65726174656420313a3338206d696e757465206c6f6e6720617564696f20617272616e67656d656e74206f66205c22496e207468652048616c6c206f6620746865204d6f756e7461696e204b696e675c222062792045647661726420477269656720776974682033206c617965726564206d656c6f6479206c696e657320616e6420612062617373206c696e65206174203131372e313837352042504d2e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f2020202020e29482e29482313030252020202020202020202020202020202020202020203230302e3635e294820ae2948220202020202020202020e29482e29482424c41434b20574f524c4420202020202020202020202020203138322e3830e294820ae2948220202020202020202020e29482e2948248454c4c4f20574f524c4420202020202020202020202020203133332e3232e294820ae29494e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29498e29494e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e294983c2f636f64653e3c2f7072653e3c64697620636c6173733d62207374796c653d646973706c61793a666c65783e3c627574746f6e2069643d623e3c636f64653e5b205375626d697420504354467b43555237345f323032337d205d3c2f636f64653e3c2f627574746f6e3e3c2f6469763e3c617564696f2069643d613e596f75722062726f7773657220646f6573206e6f7420737570706f72742074686520617564696f20656c656d656e743c2f617564696f3e3c64697620636c6173733d62207374796c653d706f736974696f6e3a72656c61746976653b6865696768743a31323870783e3c63616e7661732069643d64207374796c653d706f736974696f6e3a6162736f6c7574652077696474683d353132206865696768743d3132383e3c2f63616e7661733e3c6469762069643d63207374796c653d22626f726465723a2e35707820736f6c696420233030653130303b6865696768743a31323770783b706f736974696f6e3a6162736f6c7574653b6c6566743a30223e3c2f6469763e3c2f6469763e3c2f6469763e3c7363726970743e646f63756d656e742e676574456c656d656e744279496428226222292e6164644576656e744c697374656e65722822636c69636b222c28293d3e7b673d303b6a3d303b666f7228733d22222c743d303b743c332a322a2a31383b742b2b297b633d2263686172436f64654174222c753d28743e3e31382925332c723d2874293d3e74263235363f74263235353a3235362d287426323535292c613d33302a742a322a2a2828222527282a2c282c2c2b272b2b2a262a2a2527282a2c282c312f2c282c2f2f2f2f225b635d28743e3e3131263331292b5b302c31322c372c31395d5b743e3e313626335d292f31322d36292c783d33302a742a322a2a282822252c252c252c252c252c252c282f282f2c332c3328302c33225b635d28382a28743e3e313726313f323a743e3e31352631292b28743e3e313226372929292f31322d37292c793d612a322c7a3d792a323b732b3d537472696e672e66726f6d43686172436f64652828722861292f28352d28753e3129292b28753e30292f352a722879292b28753e31292a2872287a292f352b722878292f342929253235367c30297d613d646f63756d656e742e676574456c656d656e744279496428226122293b612e7372633d22646174613a617564696f2f7761763b6261736536342c556b6c47526934414741425851565a465a6d3130494241414141414241414541514238414145416641414142414167415a4746305951414147414341222b62746f612873293b612e706c617928293b736574496e74657276616c2828293d3e7b633d646f63756d656e742e676574456c656d656e744279496428226322293b632e7374796c652e6c6566743d284d6174682e6d696e283132382a672b3132382c6a2b2b292a3130302f313238292b2225223b7d2c3332293b683d28293d3e7b643d646f63756d656e742e676574456c656d656e744279496428226422292e676574436f6e746578742822326422293b642e636c6561725265637428302c302c3531322c313238293b642e66696c6c5374796c653d2223464646223b5b2e2e2e41727261792834303936295d2e6d617028285f2c69293d3e7b642e626567696e5061746828293b642e61726328692f382c3132382d732e63686172436f646541742833323736382a672b692a38292f322c312c302c322a4d6174682e5049293b642e66696c6c28293b7d293b672b2b3b6a3d303b7d3b6828293b736574496e74657276616c28682c34303936297d293c2f7363726970743ea2646970667358221220014028a5543be52c0f1d32e7068286c08c6bd65bd1b045bf34f55a45a8d5c19e64736f6c63430008150033

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

0000000000000000000000005dd2083a0d68c4eb8fed93ef010d1b0d68b3880f

-----Decoded View---------------
Arg [0] : _owner (address): 0x5dd2083A0D68C4EB8fEd93EF010D1b0D68B3880F

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000005dd2083a0d68c4eb8fed93ef010d1b0d68b3880f


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.