ETH Price: $2,916.58 (+2.65%)
Gas: 8.71 Gwei
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Swap Constellati...161462192022-12-09 9:20:59699 days ago1670577659IN
0xF6170612...961D166c4
0 ETH0.0010180820.41479486
Swap Constellati...161462152022-12-09 9:20:11699 days ago1670577611IN
0xF6170612...961D166c4
0 ETH0.0010225520.50435626
Swap Constellati...161462092022-12-09 9:18:59699 days ago1670577539IN
0xF6170612...961D166c4
0 ETH0.0009668919.38826828
Swap Constellati...161462032022-12-09 9:17:47699 days ago1670577467IN
0xF6170612...961D166c4
0 ETH0.0010263520.5805304
Swap Constellati...161461962022-12-09 9:16:23699 days ago1670577383IN
0xF6170612...961D166c4
0 ETH0.0010674921.40549459
Swap Constellati...161434222022-12-08 23:58:23700 days ago1670543903IN
0xF6170612...961D166c4
0 ETH0.0006898913.83723495
Swap Constellati...161417952022-12-08 18:30:59700 days ago1670524259IN
0xF6170612...961D166c4
0 ETH0.0011907816.70804941
Swap Constellati...161414672022-12-08 17:25:11700 days ago1670520311IN
0xF6170612...961D166c4
0 ETH0.0016959923.79678421
Swap Constellati...161353382022-12-07 20:53:11701 days ago1670446391IN
0xF6170612...961D166c4
0 ETH0.0010661214.50824935
Set Moon Address160315612022-11-23 8:40:11715 days ago1669192811IN
0xF6170612...961D166c4
0 ETH0.0006375513.76733155
0x60806040160315612022-11-23 8:40:11715 days ago1669192811IN
 Create: AlienArtConstellation
0 ETH0.0665429513.76733155

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AlienArtConstellation

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : AlienArtConstellation.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {DynamicNftRegistryInterface} from "../../interfaces/dynamicNftRegistry/DynamicNftRegistryInterface.sol";
import {AlienArtBase} from "../../interfaces/alienArt/AlienArtBase.sol";
import {MoonImageConfig, MoonImageColors} from "../../moon/MoonStructs.sol";
import {AlienArtConstellationEventsAndErrors} from "./AlienArtConstellationEventsAndErrors.sol";
import {ConstellationLib} from "./ConstellationLib.sol";
import {IERC165} from "../../interfaces/ext/IERC165.sol";
import {IERC721} from "../../interfaces/ext/IERC721.sol";
import {ERC1155} from "../../ext/ERC1155.sol";
import {Ownable} from "../../ext/Ownable.sol";
import {Utils} from "../../utils/Utils.sol";
import {Traits} from "../../utils/Traits.sol";
import {LibPRNG} from "../../utils/LibPRNG.sol";
import {svg} from "./SVG.sol";

/// @title AlienArtConstellation
/// @author Aspyn Palatnick (aspyn.eth, stuckinaboot.eth)
/// @notice On-chain constellation NFTs that conform to the Alien Art (AlienArtBase) on-chain NFT composability standard and support swapping constellations between Non-Fungible Moon NFTs.
contract AlienArtConstellation is
    ERC1155,
    AlienArtBase,
    AlienArtConstellationEventsAndErrors,
    Ownable
{
    using LibPRNG for LibPRNG.PRNG;

    struct ConstellationParams {
        Constellation constellationType;
        // In degrees
        uint16 rotation;
        bool fluxConstellation;
    }

    enum Constellation {
        LITTLE_DIPPER,
        BIG_DIPPER,
        // Zodiac
        ARIES,
        PISCES,
        AQUARIUS,
        CAPRICORNUS,
        SAGITTARIUS,
        OPHIUCHUS,
        SCORPIUS,
        LIBRA,
        VIRGO,
        LEO,
        CANCER,
        GEMINI,
        TAURUS,
        NONE
    }

    // These constants ensure that Etherscan/etc can read the name and symbol for this contract
    string public constant name = "Constellations";
    string public constant symbol = "CLN";

    uint16 internal constant DEFAULT_VIEW_SIZE = 200;
    uint16 internal constant DEFAULT_MOON_RADIUS = 32;

    address internal moonAddress;

    mapping(uint256 => uint256) public moonTokenIdToConstellationTokenId;
    uint16 internal constant RANDOMNESS_FACTOR = 1337;

    address dynamicNftRegistryAddress;
    uint64 internal constant COOLDOWN_PERIOD = 120;

    /// @notice set moon address.
    /// @param _moonAddress moon address.
    function setMoonAddress(address _moonAddress) external onlyOwner {
        if (moonAddress != address(0)) {
            revert MoonAddressAlreadySet();
        }
        moonAddress = _moonAddress;
    }

    /// @notice swap constellation associated moon 1 with the constellation associated with moon 2.
    /// Both moons must be owned by the same user.
    /// @param moon1 moon 1 token id.
    /// @param moon2 moon 2 token id.
    function swapConstellations(uint256 moon1, uint256 moon2) external {
        // Checks

        // Check both moons are owned by this account
        if (
            IERC721(moonAddress).ownerOf(moon1) != msg.sender ||
            IERC721(moonAddress).ownerOf(moon2) != msg.sender
        ) {
            revert SwapMoonsOwnerMustBeMsgSender();
        }

        // Effects

        // Perform swap
        uint256 originalMoon1Constellation = moonTokenIdToConstellationTokenId[
            moon1
        ];
        moonTokenIdToConstellationTokenId[
            moon1
        ] = moonTokenIdToConstellationTokenId[moon2];
        moonTokenIdToConstellationTokenId[moon2] = originalMoon1Constellation;

        // Emit event indicating swap occurred
        emit SwapConstellations(
            msg.sender,
            moon1,
            moon2,
            moonTokenIdToConstellationTokenId[moon1],
            moonTokenIdToConstellationTokenId[moon2]
        );

        // Interactions
        if (dynamicNftRegistryAddress != address(0)) {
            // Call update token on zone registry (if defined) for both moons
            // and do not invalidate collection orders.
            DynamicNftRegistryInterface(dynamicNftRegistryAddress).updateToken(
                moonAddress,
                moon1,
                COOLDOWN_PERIOD,
                false
            );
            DynamicNftRegistryInterface(dynamicNftRegistryAddress).updateToken(
                moonAddress,
                moon2,
                COOLDOWN_PERIOD,
                false
            );
        }
    }

    /// @notice get constellation type that corresponds to a particular moon token id when the constellation is to be minted
    /// @param moonTokenId moon token id
    /// @return Constellation
    function getConstellationTypeForMoonTokenIdAtMint(uint256 moonTokenId)
        public
        view
        returns (Constellation)
    {
        LibPRNG.PRNG memory prng;
        prng.seed(
            keccak256(
                abi.encodePacked(
                    moonTokenId,
                    block.difficulty,
                    RANDOMNESS_FACTOR
                )
            )
        );

        uint256 randomFrom0To99 = prng.uniform(100);
        if (randomFrom0To99 <= 1) {
            // 2% chance of returning little dipper
            return Constellation.LITTLE_DIPPER;
        }
        if (randomFrom0To99 == 2) {
            // 1% chance of returning big dipper
            return Constellation.BIG_DIPPER;
        }

        // Length of zodiac constellation values and None is the value of the last enum - first zodiac constellation + 1 for the none value
        uint256 totalZodiacConstellations = uint256(Constellation.NONE) -
            uint256(Constellation.ARIES) +
            1;
        // Return any value from the zodiac constellations or None.
        return
            Constellation(
                prng.uniform(totalZodiacConstellations) +
                    uint256(Constellation.ARIES)
            );
    }

    /// @notice get art name for this alien art contract.
    /// @return art name.
    function getArtName() external pure override returns (string memory) {
        return name;
    }

    /// @notice get on-chain Constellation art image, adhering to Alien Art abstract class.
    /// @param tokenId moon token id.
    /// @param moonSeed moon seed.
    /// @param moonImageConfig moon image config.
    /// @param rotationInDegrees rotation in degrees.
    /// @return on-chain Constellation SVG.
    function getArt(
        uint256 tokenId,
        bytes32 moonSeed,
        MoonImageConfig calldata moonImageConfig,
        uint256 rotationInDegrees
    ) external view override returns (string memory) {
        Constellation constellation = Constellation(
            moonTokenIdToConstellationTokenId[tokenId]
        );
        return
            getArtForConstellation(
                constellation,
                moonSeed,
                moonImageConfig,
                rotationInDegrees
            );
    }

    // For a given moon seed, returns bool indicating if flux constellation should be used, bool indicating if
    // moon color for star color should be used
    function getConstellationUseFluxAndUseMoonColor(bytes32 moonSeed)
        internal
        pure
        returns (bool, bool)
    {
        if (moonSeed == bytes32(0)) {
            // If moon seed is bytes32(0), return false for both use flux and use moon color for star color
            return (false, false);
        }
        LibPRNG.PRNG memory prng;
        prng.seed(moonSeed);
        return (prng.uniform(4) == 0, prng.uniform(20) == 0);
    }

    /// @notice get on-chain Constellation SVG.
    /// @param constellation constellation to get SVG for.
    /// @param moonSeed moon seed of moon mapping to constellation.
    /// @param moonImageConfig moon image config.
    /// @param rotationInDegrees rotation in degrees.
    /// @return Constellation SVG.
    function getArtForConstellation(
        Constellation constellation,
        bytes32 moonSeed,
        MoonImageConfig memory moonImageConfig,
        uint256 rotationInDegrees
    ) public pure returns (string memory) {
        (
            bool useFlux,
            bool useMoonColorForStarColor
        ) = getConstellationUseFluxAndUseMoonColor(moonSeed);
        return
            getConstellation(
                ConstellationParams({
                    constellationType: constellation,
                    rotation: uint16(rotationInDegrees),
                    fluxConstellation: useFlux
                }),
                moonImageConfig.viewWidth,
                moonImageConfig.viewHeight,
                useMoonColorForStarColor
                    ? moonImageConfig.colors.moon
                    : "#FDFD96",
                moonSeed
            );
    }

    /// @notice get traits for Constellation.
    /// @param tokenId token id.
    /// @param moonSeed moon seed.
    /// @return traits.
    function getTraits(
        uint256 tokenId,
        bytes32 moonSeed,
        MoonImageConfig calldata,
        uint256
    ) external view override returns (string memory) {
        (
            bool useFlux,
            bool useMoonColorForStarColor
        ) = getConstellationUseFluxAndUseMoonColor(moonSeed);
        return
            string.concat(
                Traits.getTrait(
                    "Star brightness",
                    useFlux ? "Flux" : "Fixed",
                    true
                ),
                Traits.getTrait(
                    "Star color",
                    useMoonColorForStarColor ? "Moon" : "Classic",
                    true
                ),
                _getTraitForConstellation(
                    Constellation(moonTokenIdToConstellationTokenId[tokenId])
                )
            );
    }

    function _getTraitForConstellation(Constellation constellation)
        internal
        pure
        returns (string memory)
    {
        return
            Traits.getTrait(
                "Constellation",
                getConstellationTypeString(constellation),
                false
            );
    }

    function getConstellationTypeString(Constellation constellation)
        internal
        pure
        returns (string memory)
    {
        if (constellation == Constellation.LITTLE_DIPPER) {
            return "Little dipper";
        }
        if (constellation == Constellation.BIG_DIPPER) {
            return "Big dipper";
        }
        if (constellation == Constellation.ARIES) {
            return "Aries";
        }
        if (constellation == Constellation.PISCES) {
            return "Pisces";
        }
        if (constellation == Constellation.AQUARIUS) {
            return "Aquarius";
        }
        if (constellation == Constellation.CAPRICORNUS) {
            return "Capricornus";
        }
        if (constellation == Constellation.SAGITTARIUS) {
            return "Sagittarius";
        }
        if (constellation == Constellation.OPHIUCHUS) {
            return "Ophiuchus";
        }
        if (constellation == Constellation.SCORPIUS) {
            return "Scorpius";
        }
        if (constellation == Constellation.LIBRA) {
            return "Libra";
        }
        if (constellation == Constellation.VIRGO) {
            return "Virgo";
        }
        if (constellation == Constellation.LEO) {
            return "Leo";
        }
        if (constellation == Constellation.CANCER) {
            return "Cancer";
        }
        if (constellation == Constellation.GEMINI) {
            return "Gemini";
        }
        if (constellation == Constellation.TAURUS) {
            return "Taurus";
        }
        return "None";
    }

    function getConstellation(
        ConstellationParams memory constellation,
        uint256 rectWidth,
        uint256 rectHeight,
        string memory starColor,
        bytes32 moonSeed
    ) internal pure returns (string memory) {
        if (constellation.constellationType == Constellation.NONE) {
            return "";
        }

        ConstellationLib.GenerateConstellationParams
            memory params = ConstellationLib.GenerateConstellationParams(
                0,
                0,
                constellation.rotation,
                uint16(rectWidth) / 2,
                uint16(rectHeight) / 2,
                starColor,
                constellation.fluxConstellation,
                moonSeed
            );

        if (constellation.constellationType == Constellation.LITTLE_DIPPER) {
            params.x = 60;
            params.y = 150;
            return ConstellationLib.getLittleDipper(params);
        }
        if (constellation.constellationType == Constellation.BIG_DIPPER) {
            params.x = 89;
            params.y = 13;
            return ConstellationLib.getBigDipper(params);
        }
        if (constellation.constellationType == Constellation.ARIES) {
            params.x = 75;
            params.y = 40;
            return ConstellationLib.getAries(params);
        }
        if (constellation.constellationType == Constellation.PISCES) {
            params.x = 25;
            params.y = 147;
            return ConstellationLib.getPisces(params);
        }
        if (constellation.constellationType == Constellation.AQUARIUS) {
            params.x = 35;
            params.y = 156;
            return ConstellationLib.getAquarius(params);
        }
        if (constellation.constellationType == Constellation.CAPRICORNUS) {
            params.x = 35;
            params.y = 145;
            return ConstellationLib.getCapricornus(params);
        }
        if (constellation.constellationType == Constellation.SAGITTARIUS) {
            params.x = 35;
            params.y = 160;
            return ConstellationLib.getSagittarius(params);
        }
        if (constellation.constellationType == Constellation.OPHIUCHUS) {
            params.x = 35;
            params.y = 160;
            return ConstellationLib.getOphiuchus(params);
        }
        if (constellation.constellationType == Constellation.SCORPIUS) {
            params.x = 35;
            params.y = 140;
            return ConstellationLib.getScorpius(params);
        }
        if (constellation.constellationType == Constellation.LIBRA) {
            params.x = 75;
            params.y = 167;
            return ConstellationLib.getLibra(params);
        }
        if (constellation.constellationType == Constellation.VIRGO) {
            params.x = 15;
            params.y = 120;
            return ConstellationLib.getVirgo(params);
        }
        if (constellation.constellationType == Constellation.LEO) {
            params.x = 55;
            params.y = 165;
            return ConstellationLib.getLeo(params);
        }
        if (constellation.constellationType == Constellation.CANCER) {
            params.x = 110;
            params.y = 185;
            return ConstellationLib.getCancer(params);
        }
        if (constellation.constellationType == Constellation.GEMINI) {
            params.x = 75;
            params.y = 152;
            return ConstellationLib.getGemini(params);
        }
        if (constellation.constellationType == Constellation.TAURUS) {
            params.x = 67;
            params.y = 155;
            return ConstellationLib.getTaurus(params);
        }

        return "";
    }

    /// @notice get standalone Constellation, which is
    /// an on-chain Constellation SVG that can properly be rendered standalone (without being embedded in another SVG).
    /// @param constellation constellation.
    /// @param moonSeed moon seed of moon mapping to constellation.
    /// @param config moon image config.
    /// @return standalone Constellation SVG.
    function getStandaloneConstellation(
        Constellation constellation,
        bytes32 moonSeed,
        MoonImageConfig memory config
    ) public pure returns (string memory) {
        return
            svg.svgTag(
                string.concat(
                    svg.prop("xmlns", "http://www.w3.org/2000/svg"),
                    svg.prop("width", "400"),
                    svg.prop("height", "400"),
                    svg.prop("viewBox", "0 0 200 200")
                ),
                string.concat(
                    svg.rect(
                        string.concat(
                            svg.prop("width", "200"),
                            svg.prop("height", "200"),
                            svg.prop("fill", "#0e1111")
                        )
                    ),
                    getArtForConstellation(constellation, moonSeed, config, 0)
                )
            );
    }

    /// @notice burn and mint constellation for particular moon. Only callable by moon contract.
    /// @param moonTokenId moon token id.
    function burnAndMint(uint256 moonTokenId) external {
        // Only moon contract can burn
        if (msg.sender != moonAddress) {
            revert MsgSenderNotMoonAddress();
        }

        // Burn existing Constellation token
        _burn(msg.sender, moonTokenIdToConstellationTokenId[moonTokenId], 1);
        // Mint new token
        mint(moonTokenId, 1);
    }

    /// @notice mint Constellation NFTs corresponding with moons.
    /// @param startMoonTokenId start moon token id.
    /// @param numMoonsMinted number of moons minted.
    function mint(uint256 startMoonTokenId, uint256 numMoonsMinted) public {
        // Only moon contract can mint
        if (msg.sender != moonAddress) {
            revert MsgSenderNotMoonAddress();
        }

        for (
            uint256 moonTokenId = startMoonTokenId;
            moonTokenId < startMoonTokenId + numMoonsMinted;
            ++moonTokenId
        ) {
            // Determine constellation to mint based on moon token
            uint256 constellationIdx = uint256(
                getConstellationTypeForMoonTokenIdAtMint(moonTokenId)
            );
            // Map moon token id to this constellation token id (index)
            moonTokenIdToConstellationTokenId[moonTokenId] = constellationIdx;
            // Mint to msg.sender, which is moon contract since we only
            // allow minting by moon contract
            _mint(msg.sender, constellationIdx, 1, "");
        }
    }

    /// @notice get fully on-chain uri for a particular token.
    /// @param tokenId token id, which is an index in Constellation enum.
    /// @return Constellation uri for tokenId.
    function uri(uint256 tokenId)
        public
        view
        virtual
        override(ERC1155)
        returns (string memory)
    {
        if (tokenId > uint256(Constellation.NONE)) {
            revert InvalidConstellationIndex();
        }

        // Only define fields relevant for generating image for uri
        MoonImageConfig memory moonImageConfig;
        moonImageConfig.viewWidth = DEFAULT_VIEW_SIZE;
        moonImageConfig.viewHeight = DEFAULT_VIEW_SIZE;
        moonImageConfig.moonRadius = DEFAULT_MOON_RADIUS;

        string memory constellationSvg = Utils.svgToImageURI(
            getStandaloneConstellation(
                Constellation(tokenId),
                bytes32(0),
                moonImageConfig
            )
        );
        return
            Utils.formatTokenURI(
                constellationSvg,
                constellationSvg,
                getConstellationTypeString(Constellation(tokenId)),
                "Constellations are on-chain constellation NFTs. Constellations are on-chain art owned by on-chain art; Constellations are all owned by Non-Fungible Moon NFTs.",
                string.concat(
                    "[",
                    _getTraitForConstellation(Constellation(tokenId)),
                    "]"
                )
            );
    }

    // Dynamic NFT registry setup

    /// @notice set up dynamic NFT registry.
    /// @param _dynamicNftRegistryAddress dynamic NFT registry address.
    function setupDynamicNftRegistry(address _dynamicNftRegistryAddress)
        external
        onlyOwner
    {
        dynamicNftRegistryAddress = _dynamicNftRegistryAddress;
    }

    // IERC165 functions

    /// @notice check if this contract supports a given interface.
    /// @param interfaceId interface id.
    /// @return true if contract supports interfaceId, false otherwise.
    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(IERC165, ERC1155)
        returns (bool)
    {
        return
            super.supportsInterface(interfaceId) ||
            // AlienArtBase interface id
            interfaceId == type(AlienArtBase).interfaceId;
    }
}

File 2 of 16 : DynamicNftRegistryInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {OwnerPermissionedTokenRegistryInterface} from "./OwnerPermissionedTokenRegistryInterface.sol";

/**
 * @title  DynamicNftRegistry
 * @author James Wenzel (emo.eth)
 * @notice Interface for an open registry for allowed updaters of token contracts to register that a (potentially
 *         off-chain) metadata update has occurred on-chain, inheriting from OwnerPermissionedTokenRegistryInterface.
 */
interface DynamicNftRegistryInterface is
    OwnerPermissionedTokenRegistryInterface
{
    /**
     * @notice update token's last modified timestamp to timestamp of current block
     * @param tokenAddress address of the token contract
     * @param tokenId that has been updated
     * @param cooldownPeriod in seconds
     */
    function updateToken(
        address tokenAddress,
        uint256 tokenId,
        uint64 cooldownPeriod,
        bool invalidateCollectionOrders
    ) external;

    /**
     * @notice update token's last modified timestamp to a timestamp in the past
     * @param tokenAddress address of the token contract
     * @param tokenId that has been updated
     * @param timestamp specific timestamp when token was last updated
     * @param cooldownPeriod in seconds
     */
    function updateToken(
        address tokenAddress,
        uint256 tokenId,
        uint64 timestamp,
        uint64 cooldownPeriod,
        bool invalidateCollectionOrders
    ) external;
}

File 3 of 16 : AlienArtBase.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {IERC165} from "../ext/IERC165.sol";
import {MoonImageConfig} from "../../moon/MoonStructs.sol";

/// @title AlienArtBase
/// @author Aspyn Palatnick (aspyn.eth, stuckinaboot.eth)
/// @notice Alien Art is an on-chain NFT composability standard for on-chain art and traits.
abstract contract AlienArtBase is IERC165 {
    // Define functions that alien art contracts can override. These intentionally
    // use function state mutability as view to allow for reading on-chain data.

    /// @notice get art name.
    /// @return art name.
    function getArtName() external view virtual returns (string memory);

    /// @notice get alien art image for a particular token.
    /// @param tokenId token id.
    /// @param moonSeed moon seed.
    /// @param moonImageConfig moon image config.
    /// @param rotationInDegrees rotation in degrees.
    /// @return alien art image.
    function getArt(
        uint256 tokenId,
        bytes32 moonSeed,
        MoonImageConfig calldata moonImageConfig,
        uint256 rotationInDegrees
    ) external view virtual returns (string memory);

    /// @notice get moon filter for a particular token.
    /// @param tokenId token id.
    /// @param moonSeed moon seed.
    /// @param moonImageConfig moon image config.
    /// @param rotationInDegrees rotation in degrees.
    /// @return moon filter.
    function getMoonFilter(
        uint256 tokenId,
        bytes32 moonSeed,
        MoonImageConfig calldata moonImageConfig,
        uint256 rotationInDegrees
    ) external view virtual returns (string memory) {
        return "";
    }

    /// @notice get alien art traits for a particular token.
    /// @param tokenId token id.
    /// @param moonSeed moon seed.
    /// @param moonImageConfig moon image config.
    /// @param rotationInDegrees rotation in degrees.
    /// @return alien art traits.
    function getTraits(
        uint256 tokenId,
        bytes32 moonSeed,
        MoonImageConfig calldata moonImageConfig,
        uint256 rotationInDegrees
    ) external view virtual returns (string memory) {
        return "";
    }
}

File 4 of 16 : MoonStructs.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Colors describing the moon image.
struct MoonImageColors {
    string moon;
    uint16 moonHue;
    string border;
    uint8 borderSaturation;
    string background;
    uint8 backgroundLightness;
    string backgroundGradientColor;
}

// Config describing the complete moon image, with colors, positioning, and sizing.
struct MoonImageConfig {
    MoonImageColors colors;
    uint16 moonRadius;
    uint16 xOffset;
    uint16 yOffset;
    uint16 viewWidth;
    uint16 viewHeight;
    uint16 borderRadius;
    uint16 borderWidth;
    string borderType;
}

File 5 of 16 : AlienArtConstellationEventsAndErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/// @title AlienArtConstellationEventsAndErrors
/// @author Aspyn Palatnick (aspyn.eth, stuckinaboot.eth)
contract AlienArtConstellationEventsAndErrors {
    // Event to be emitted when swap constellations occurs
    event SwapConstellations(
        address indexed owner,
        uint256 indexed moon1,
        uint256 indexed moon2,
        uint256 newConstellationForMoon1,
        uint256 newConstellationForMoon2
    );

    // Set moon address errors
    error MoonAddressAlreadySet();

    // Mint errors
    error MsgSenderNotMoonAddress();

    // Swap constellations errors
    error SwapMoonsOwnerMustBeMsgSender();

    // Uri errors
    error InvalidConstellationIndex();
}

File 6 of 16 : ConstellationLib.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./SVG.sol";
import {Utils} from "../../utils/Utils.sol";
import {LibPRNG} from "../../utils/LibPRNG.sol";

/// @title ConstellationLib
/// @author Aspyn Palatnick (aspyn.eth, stuckinaboot.eth)
library ConstellationLib {
    // Constellations
    using LibPRNG for LibPRNG.PRNG;

    struct GenerateConstellationParams {
        uint256 x;
        uint256 y;
        uint16 rotationInDegrees;
        uint16 rotationCenterX;
        uint16 rotationCenterY;
        string starColor;
        bool fluxConstellation;
        bytes32 moonSeed;
    }

    function getLittleDipper(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory handle = string.concat(
            getStar(params, x, y),
            getStar(params, x + 11, y + 9),
            getStar(params, x + 26, y + 15),
            getStar(params, x + 43, y + 14)
        );
        string memory cup = string.concat(
            getStar(params, x + 57, y + 5),
            getStar(params, x + 64, y + 14),
            getStar(params, x + 47, y + 23)
        );

        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                string.concat(cup, handle)
            );
    }

    function getBigDipper(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory cup = string.concat(
            getStar(params, x, y + 16),
            getStar(params, x + 11, y),
            getStar(params, x + 38, y + 13),
            getStar(params, x + 33, y + 30)
        );
        string memory handle = string.concat(
            getStar(params, x + 46, y + 45),
            getStar(params, x + 54, y + 58),
            getStar(params, x + 78, y + 66)
        );

        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                string.concat(cup, handle)
            );
    }

    function getAries(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory stars = string.concat(
            getStar(params, x, y),
            getStar(params, x + 35, y - 19),
            getStar(params, x + 50, y - 21),
            getStar(params, x + 55, y - 16)
        );

        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    function getPisces(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory upperLine = string.concat(
            getStar(params, x, y),
            getStar(params, x + 7, y - 8),
            getStar(params, x + 17, y - 20),
            getStar(params, x + 24, y - 32),
            getStar(params, x + 21, y - 41),
            getStar(params, x + 30, y - 47)
        );
        string memory lowerLine = string.concat(
            getStar(params, x + 9, y - 2),
            getStar(params, x + 28, y - 7),
            getStar(params, x + 36, y - 5),
            getStar(params, x + 52, y - 6)
        );
        string memory lowerCirclePart1 = string.concat(
            getStar(params, x + 60, y - 2),
            getStar(params, x + 65, y - 6),
            getStar(params, x + 70, y - 2),
            getStar(params, x + 71, y + 5)
        );
        string memory lowerCirclePart2 = string.concat(
            getStar(params, x + 66, y + 9),
            getStar(params, x + 58, y + 8),
            getStar(params, x + 57, y + 1)
        );

        string memory stars = string.concat(
            upperLine,
            lowerLine,
            lowerCirclePart1,
            lowerCirclePart2
        );
        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    function getAquarius(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory bottomDownLine = string.concat(
            getStar(params, x, y),
            getStar(params, x + 12, y - 3),
            getStar(params, x + 20, y + 5),
            getStar(params, x + 22, y + 21)
        );
        string memory topAcrossLine = string.concat(
            getStar(params, x + 8, y - 21),
            getStar(params, x + 14, y - 26),
            getStar(params, x + 18, y - 21),
            getStar(params, x + 26, y - 27),
            getStar(params, x + 68, y - 10)
        );
        string memory middleDownLine = string.concat(
            getStar(params, x + 29, y - 11),
            getStar(params, x + 39, y - 1)
        );

        string memory stars = string.concat(
            bottomDownLine,
            topAcrossLine,
            middleDownLine
        );
        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    function getCapricornus(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory top = string.concat(
            getStar(params, x, y),
            getStar(params, x + 8, y - 1),
            getStar(params, x + 30, y + 5)
        );
        string memory left = string.concat(
            getStar(params, x + 7, y + 7),
            getStar(params, x + 13, y + 16),
            getStar(params, x + 30, y + 29)
        );
        string memory right = string.concat(
            getStar(params, x + 34, y + 26),
            getStar(params, x + 59, y + 3),
            getStar(params, x + 65, y - 3)
        );
        string memory stars = string.concat(top, left, right);
        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    function getSagittarius(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        string memory stars = string.concat(
            getSagittariusLeft(params),
            getSagittariusMiddle(params),
            getSagittariusRight(params)
        );
        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    function getOphiuchus(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory stars = string.concat(
            getStar(params, x, y),
            getStar(params, x + 3, y - 22),
            getStar(params, x + 11, y - 32),
            getStar(params, x + 19, y - 24),
            getStar(params, x + 22, y + 5),
            getStar(params, x + 9, y + 4)
        );

        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                // Avoid stack too deep error by adding last star here
                string.concat(stars, getStar(params, x + 33, y + 12))
            );
    }

    function getScorpius(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory top = string.concat(
            getStar(params, x, y),
            getStar(params, x + 3, y - 10),
            getStar(params, x + 9, y - 15),
            getStar(params, x + 14, y - 1)
        );
        string memory middle = string.concat(
            getStar(params, x + 19, y + 2),
            getStar(params, x + 21, y + 6),
            getStar(params, x + 25, y + 16),
            getStar(params, x + 25, y + 32)
        );
        string memory bottom1 = string.concat(
            getStar(params, x + 32, y + 37),
            getStar(params, x + 42, y + 39),
            getStar(params, x + 50, y + 33)
        );
        string memory bottom2 = string.concat(
            getStar(params, x + 47, y + 30),
            getStar(params, x + 44, y + 23)
        );
        string memory stars = string.concat(top, middle, bottom1, bottom2);
        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    function getLibra(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory triangle = string.concat(
            getStar(params, x, y),
            getStar(params, x + 6, y - 17),
            getStar(params, x + 23, y - 19)
        );
        string memory left = string.concat(
            getStar(params, x + 9, y + 13),
            getStar(params, x + 7, y + 18)
        );
        string memory right = string.concat(
            getStar(params, x + 21, y - 6),
            getStar(params, x + 32, y + 5)
        );
        string memory stars = string.concat(triangle, left, right);
        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    function getVirgo(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory middle = string.concat(
            getStar(params, x + 8, y),
            getStar(params, x + 11, y - 11),
            getStar(params, x + 10, y - 26),
            getStar(params, x + 22, y - 28),
            getStar(params, x + 28, y - 10)
        );
        string memory top = string.concat(
            getStar(params, x + 4, y - 32),
            getStar(params, x, y - 46),
            getStar(params, x + 34, y - 34)
        );
        string memory bottomLeft = string.concat(
            getStar(params, x + 21, y + 12),
            getStar(params, x + 24, y + 10),
            getStar(params, x + 30, y + 18)
        );
        string memory bottomRight = string.concat(
            getStar(params, x + 33, y - 7),
            getStar(params, x + 37, y - 4),
            getStar(params, x + 48, y + 9)
        );
        string memory stars = string.concat(
            middle,
            top,
            bottomLeft,
            bottomRight
        );
        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    function getLeo(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory loop = string.concat(
            getStar(params, x, y),
            getStar(params, x + 4, y - 10),
            getStar(params, x + 14, y - 12),
            getStar(params, x + 35, y + 3),
            getStar(params, x + 45, y + 21),
            getStar(params, x + 30, y + 12)
        );
        string memory top = string.concat(
            getStar(params, x + 17, y - 19),
            getStar(params, x + 11, y - 30),
            getStar(params, x + 2, y - 29)
        );

        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                string.concat(loop, top)
            );
    }

    function getCancer(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory stars = string.concat(
            getStar(params, x, y),
            getStar(params, x + 14, y - 21),
            getStar(params, x + 28, y - 12),
            getStar(params, x + 12, y - 29),
            getStar(params, x + 11, y - 49)
        );

        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    function getGemini(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        string memory stars = string.concat(
            getGeminiLeftPerson(params),
            getGeminiRightPerson(params)
        );
        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    function getTaurus(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;

        string memory left = string.concat(
            getStar(params, x, y),
            getStar(params, x + 5, y - 13),
            getStar(params, x + 18, y - 2)
        );
        string memory middle1 = string.concat(
            getStar(params, x + 18, y + 11),
            getStar(params, x + 22, y + 5),
            getStar(params, x + 22, y + 9)
        );
        string memory middle2 = string.concat(
            getStar(params, x + 23, y + 13),
            getStar(params, x + 26, y + 9),
            getStar(params, x + 27, y + 13)
        );
        string memory bottom = string.concat(
            getStar(params, x + 34, y + 19),
            getStar(params, x + 49, y + 24),
            getStar(params, x + 51, y + 29)
        );
        string memory stars = string.concat(left, middle1, middle2, bottom);
        return
            makeConstellation(
                params.rotationInDegrees,
                params.rotationCenterX,
                params.rotationCenterY,
                stars
            );
    }

    // Helpers

    function getTransform(
        uint16 rotationInDegrees,
        uint16 rotationCenterX,
        uint16 rotationCenterY
    ) internal pure returns (string memory) {
        return
            svg.prop(
                "transform",
                string.concat(
                    "rotate(",
                    Utils.uint2str(rotationInDegrees),
                    " ",
                    Utils.uint2str(rotationCenterX),
                    " ",
                    Utils.uint2str(rotationCenterY),
                    ")"
                )
            );
    }

    function getStarTransform(uint256 x, uint256 y)
        internal
        pure
        returns (string memory)
    {
        return
            svg.prop(
                "transform",
                string.concat(
                    "translate(",
                    Utils.uint2str(x),
                    ",",
                    Utils.uint2str(y),
                    ") scale(0.03)"
                )
            );
    }

    function getStar(
        GenerateConstellationParams memory params,
        uint256 x,
        uint256 y
    ) internal pure returns (string memory) {
        string memory opacity;
        if (params.fluxConstellation) {
            LibPRNG.PRNG memory prng;
            prng.seed(
                keccak256(
                    abi.encodePacked(
                        params.rotationInDegrees,
                        params.moonSeed,
                        x,
                        y
                    )
                )
            );
            // Minimum 30, max 100
            opacity = Utils.uint2str(prng.uniform(71) + 30);
        } else {
            opacity = "100";
        }

        return
            svg.path(
                string.concat(
                    svg.prop(
                        "d",
                        "M 40 60 L 63.511 72.361 L 59.021 46.180 L 78.042 27.639 L 51.756 23.820 L 40 0 L 28.244 23.820 L 1.958 27.639 L 20.979 46.180 L 16.489 72.361 L 40 60"
                    ),
                    svg.prop("fill", params.starColor),
                    svg.prop("filter", "url(#glo)"),
                    svg.prop("opacity", string.concat(opacity, "%")),
                    getStarTransform(x, y)
                )
            );
    }

    function makeConstellation(
        uint16 rotationInDegrees,
        uint16 rotationCenterX,
        uint16 rotationCenterY,
        string memory starElt
    ) internal pure returns (string memory) {
        return
            svg.g(
                getTransform(
                    rotationInDegrees,
                    rotationCenterX,
                    rotationCenterY
                ),
                string.concat(
                    // Glow filter
                    svg.filter(
                        svg.prop("id", "glo"),
                        string.concat(
                            svg.feGaussianBlur(
                                string.concat(
                                    svg.prop("stdDeviation", "4"),
                                    svg.prop("result", "blur")
                                )
                            ),
                            svg.feMerge(
                                string.concat(
                                    svg.feMergeNode(svg.prop("in", "blur")),
                                    svg.feMergeNode(svg.prop("in", "blur")),
                                    svg.feMergeNode(svg.prop("in", "blur")),
                                    svg.feMergeNode(
                                        svg.prop("in", "SourceGraphic")
                                    )
                                )
                            )
                        )
                    ),
                    starElt
                )
            );
    }

    // Individual constellation helpers

    // Sagittarius helpers for groups of stars as we get stack too deep errors
    // including all stars in one function

    function getSagittariusLeft(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;
        return
            string.concat(
                getStar(params, x, y),
                getStar(params, x + 11, y + 5),
                getStar(params, x + 18, y + 2),
                getStar(params, x + 22, y + 7),
                getStar(params, x + 19, y + 13),
                getStar(params, x + 19, y - 7),
                getStar(params, x + 11, y - 17)
            );
    }

    function getSagittariusMiddle(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;
        return
            string.concat(
                getStar(params, x + 27, y - 6),
                getStar(params, x + 30, y - 10),
                getStar(params, x + 31, y - 20),
                getStar(params, x + 26, y - 21),
                getStar(params, x + 36, y - 20),
                getStar(params, x + 42, y - 28)
            );
    }

    function getSagittariusRight(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;
        return
            string.concat(
                getStar(params, x + 33, y - 3),
                getStar(params, x + 36, y - 9),
                getStar(params, x + 45, y - 15),
                getStar(params, x + 55, y - 11),
                getStar(params, x + 60, y - 7),
                getStar(params, x + 55, y + 6),
                getStar(params, x + 53, y + 14),
                getStar(params, x + 44, y + 12),
                getStar(params, x + 43, y + 23)
            );
    }

    // Gemini helpers for groups of stars as we get stack too deep errors
    // including all stars in one function

    function getGeminiLeftPerson(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;
        string memory leftPersonTop = string.concat(
            getStar(params, x, y),
            getStar(params, x + 10, y - 12),
            getStar(params, x + 13, y - 6),
            getStar(params, x + 20, y - 7)
        );
        string memory leftPersonBottom1 = string.concat(
            getStar(params, x + 13, y + 4),
            getStar(params, x + 13, y + 15),
            getStar(params, x + 11, y + 23)
        );
        string memory leftPersonBottom2 = string.concat(
            getStar(params, x + 13, y + 34),
            getStar(params, x + 1, y + 21),
            getStar(params, x + 3, y + 38)
        );
        return
            string.concat(leftPersonTop, leftPersonBottom1, leftPersonBottom2);
    }

    function getGeminiRightPerson(GenerateConstellationParams memory params)
        internal
        pure
        returns (string memory)
    {
        uint256 x = params.x;
        uint256 y = params.y;
        string memory rightPersonTop = string.concat(
            getStar(params, x + 28, y - 16),
            getStar(params, x + 29, y - 6),
            getStar(params, x + 38, y - 7)
        );
        string memory rightPersonBottom1 = string.concat(
            getStar(params, x + 28, y + 9),
            getStar(params, x + 30, y + 18),
            getStar(params, x + 30, y + 30)
        );
        string memory rightPersonBottom2 = string.concat(
            getStar(params, x + 25, y + 35),
            getStar(params, x + 40, y + 32)
        );
        return
            string.concat(
                rightPersonTop,
                rightPersonBottom1,
                rightPersonBottom2
            );
    }
}

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

pragma solidity 0.8.17;

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

File 8 of 16 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)

pragma solidity 0.8.17;

import "./IERC165.sol";

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

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

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

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

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

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

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

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

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

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

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

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

File 9 of 16 : ERC1155.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.17;

/// @notice Minimalist and gas efficient standard ERC1155 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 amount
    );

    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] amounts
    );

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

    event URI(string value, uint256 indexed id);

    /*//////////////////////////////////////////////////////////////
                             ERC1155 STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(address => mapping(uint256 => uint256)) public balanceOf;

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

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

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

    /*//////////////////////////////////////////////////////////////
                              ERC1155 LOGIC
    //////////////////////////////////////////////////////////////*/

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

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

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) public virtual {
        require(
            msg.sender == from || isApprovedForAll[from][msg.sender],
            "NOT_AUTHORIZED"
        );

        balanceOf[from][id] -= amount;
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, from, to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155Received(
                    msg.sender,
                    from,
                    id,
                    amount,
                    data
                ) == ERC1155TokenReceiver.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) public virtual {
        require(ids.length == amounts.length, "LENGTH_MISMATCH");

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

        // Storing these outside the loop saves ~15 gas per iteration.
        uint256 id;
        uint256 amount;

        for (uint256 i = 0; i < ids.length; ) {
            id = ids[i];
            amount = amounts[i];

            balanceOf[from][id] -= amount;
            balanceOf[to][id] += amount;

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, from, to, ids, amounts);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155BatchReceived(
                    msg.sender,
                    from,
                    ids,
                    amounts,
                    data
                ) == ERC1155TokenReceiver.onERC1155BatchReceived.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
        public
        view
        virtual
        returns (uint256[] memory balances)
    {
        require(owners.length == ids.length, "LENGTH_MISMATCH");

        balances = new uint256[](owners.length);

        // Unchecked because the only math done is incrementing
        // the array index counter which cannot possibly overflow.
        unchecked {
            for (uint256 i = 0; i < owners.length; ++i) {
                balances[i] = balanceOf[owners[i]][ids[i]];
            }
        }
    }

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

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        returns (bool)
    {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
            interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
    }

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

    function _mint(
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, address(0), to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155Received(
                    msg.sender,
                    address(0),
                    id,
                    amount,
                    data
                ) == ERC1155TokenReceiver.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _batchMint(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        for (uint256 i = 0; i < idsLength; ) {
            balanceOf[to][ids[i]] += amounts[i];

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, address(0), to, ids, amounts);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155BatchReceived(
                    msg.sender,
                    address(0),
                    ids,
                    amounts,
                    data
                ) == ERC1155TokenReceiver.onERC1155BatchReceived.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _batchBurn(
        address from,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal virtual {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        for (uint256 i = 0; i < idsLength; ) {
            balanceOf[from][ids[i]] -= amounts[i];

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, from, address(0), ids, amounts);
    }

    function _burn(
        address from,
        uint256 id,
        uint256 amount
    ) internal virtual {
        balanceOf[from][id] -= amount;

        emit TransferSingle(msg.sender, from, address(0), id, amount);
    }
}

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

    function onERC1155BatchReceived(
        address,
        address,
        uint256[] calldata,
        uint256[] calldata,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC1155TokenReceiver.onERC1155BatchReceived.selector;
    }
}

File 10 of 16 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity 0.8.17;

import "./Context.sol";

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

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

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

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

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

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

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

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

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

File 11 of 16 : Utils.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Core utils used extensively to format CSS and numbers.
library Utils {
    string internal constant BASE64_TABLE =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    // converts an unsigned integer to a string
    function uint2str(uint256 _i) internal pure returns (string memory) {
        if (_i == 0) {
            return "0";
        }
        uint256 j = _i;
        uint256 len;
        while (j != 0) {
            ++len;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len;
        while (_i != 0) {
            k = k - 1;
            uint8 temp = (48 + uint8(_i - (_i / 10) * 10));
            bytes1 b1 = bytes1(temp);
            bstr[k] = b1;
            _i /= 10;
        }
        return string(bstr);
    }

    function htmlToURI(string memory _source)
        internal
        pure
        returns (string memory)
    {
        return
            string.concat(
                "data:text/html;base64,",
                encodeBase64(bytes(_source))
            );
    }

    function svgToImageURI(string memory _source)
        internal
        pure
        returns (string memory)
    {
        return
            string.concat(
                "data:image/svg+xml;base64,",
                encodeBase64(bytes(_source))
            );
    }

    function formatTokenURI(
        string memory _imageURI,
        string memory _animationURI,
        string memory _name,
        string memory _description,
        string memory _properties
    ) internal pure returns (string memory) {
        return
            string.concat(
                "data:application/json;base64,",
                encodeBase64(
                    bytes(
                        string.concat(
                            '{"name":"',
                            _name,
                            '","description":"',
                            _description,
                            '","attributes":',
                            _properties,
                            ',"image":"',
                            _imageURI,
                            '","animation_url":"',
                            _animationURI,
                            '"}'
                        )
                    )
                )
            );
    }

    // Encode some bytes in base64
    // https://gist.github.com/mbvissers/8ba9ac1eca9ed0ef6973bd49b3c999ba
    function encodeBase64(bytes memory data)
        internal
        pure
        returns (string memory)
    {
        if (data.length == 0) return "";

        // load the table into memory
        string memory table = BASE64_TABLE;

        // multiply by 4/3 rounded up
        uint256 encodedLen = 4 * ((data.length + 2) / 3);

        // add some extra buffer at the end required for the writing
        string memory result = new string(encodedLen + 32);

        assembly {
            // set the actual output length
            mstore(result, encodedLen)

            // prepare the lookup table
            let tablePtr := add(table, 1)

            // input ptr
            let dataPtr := data
            let endPtr := add(dataPtr, mload(data))

            // result ptr, jump over length
            let resultPtr := add(result, 32)

            // run over the input, 3 bytes at a time
            for {

            } lt(dataPtr, endPtr) {

            } {
                dataPtr := add(dataPtr, 3)

                // read 3 bytes
                let input := mload(dataPtr)

                // write 4 characters
                mstore(
                    resultPtr,
                    shl(248, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                )
                resultPtr := add(resultPtr, 1)
                mstore(
                    resultPtr,
                    shl(248, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                )
                resultPtr := add(resultPtr, 1)
                mstore(
                    resultPtr,
                    shl(248, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                )
                resultPtr := add(resultPtr, 1)
                mstore(
                    resultPtr,
                    shl(248, mload(add(tablePtr, and(input, 0x3F))))
                )
                resultPtr := add(resultPtr, 1)
            }

            // padding with '='
            switch mod(mload(data), 3)
            case 1 {
                mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
            }
            case 2 {
                mstore(sub(resultPtr, 1), shl(248, 0x3d))
            }
        }

        return result;
    }
}

File 12 of 16 : Traits.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {Utils} from "./Utils.sol";

/// @title Traits
/// @author Aspyn Palatnick (aspyn.eth, stuckinaboot.eth)
library Traits {
    function _getTrait(
        string memory traitType,
        string memory value,
        bool includeTrailingComma,
        bool includeValueQuotes
    ) internal pure returns (string memory) {
        return
            string.concat(
                '{"trait_type":"',
                traitType,
                '","value":',
                includeValueQuotes ? string.concat('"', value, '"') : value,
                "}",
                includeTrailingComma ? "," : ""
            );
    }

    function getTrait(
        string memory traitType,
        string memory value,
        bool includeTrailingComma
    ) internal pure returns (string memory) {
        return _getTrait(traitType, value, includeTrailingComma, true);
    }

    function getTrait(
        string memory traitType,
        uint256 value,
        bool includeTrailingComma
    ) internal pure returns (string memory) {
        return
            _getTrait(
                traitType,
                Utils.uint2str(value),
                includeTrailingComma,
                false
            );
    }
}

File 13 of 16 : LibPRNG.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for generating psuedorandom numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibPRNG.sol)
library LibPRNG {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STRUCTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev A psuedorandom number state in memory.
    struct PRNG {
        uint256 state;
    }

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

    /// @dev Seeds the `prng` with `state`.
    function seed(PRNG memory prng, bytes32 state) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(prng, state)
        }
    }

    /// @dev Returns a psuedorandom uint256, uniformly distributed
    /// between 0 (inclusive) and `upper` (exclusive).
    /// If your modulus is big, this method is recommended
    /// for uniform sampling to avoid modulo bias.
    /// For uniform sampling across all uint256 values,
    /// or for small enough moduli such that the bias is neligible,
    /// use {next} instead.
    function uniform(PRNG memory prng, uint256 upper)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // prettier-ignore
            for {} 1 {} {
                result := keccak256(prng, 0x20)
                mstore(prng, result)
                // prettier-ignore
                if iszero(lt(result, mod(sub(0, upper), upper))) { break }
            }
            result := mod(result, upper)
        }
    }
}

File 14 of 16 : SVG.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Core SVG utility library which helps us construct
// onchain SVG's with a simple, web-like API.
// Props to w1nt3r.eth for creating the core of this SVG utility library.
library svg {
    string internal constant NULL = "";

    /* MAIN ELEMENTS */
    function svgTag(string memory _props, string memory _children)
        internal
        pure
        returns (string memory)
    {
        return el("svg", _props, _children);
    }

    function g(string memory _props, string memory _children)
        internal
        pure
        returns (string memory)
    {
        return el("g", _props, _children);
    }

    function rect(string memory _props) internal pure returns (string memory) {
        return el("rect", _props, NULL);
    }

    function path(string memory _props) internal pure returns (string memory) {
        return el("path", _props, NULL);
    }

    function filter(string memory _props, string memory _children)
        internal
        pure
        returns (string memory)
    {
        return el("filter", _props, _children);
    }

    function feGaussianBlur(string memory _props)
        internal
        pure
        returns (string memory)
    {
        return el("feGaussianBlur", _props, NULL);
    }

    function feMerge(string memory _children)
        internal
        pure
        returns (string memory)
    {
        return el("feMerge", NULL, _children);
    }

    function feMergeNode(string memory _props)
        internal
        pure
        returns (string memory)
    {
        return el("feMergeNode", _props, NULL);
    }

    /* COMMON */
    // A generic element, can be used to construct any SVG (or HTML) element
    function el(
        string memory _tag,
        string memory _props,
        string memory _children
    ) internal pure returns (string memory) {
        return
            string.concat(
                "<",
                _tag,
                " ",
                _props,
                ">",
                _children,
                "</",
                _tag,
                ">"
            );
    }

    // an SVG attribute
    function prop(string memory _key, string memory _val)
        internal
        pure
        returns (string memory)
    {
        return string.concat(_key, '="', _val, '" ');
    }
}

File 15 of 16 : OwnerPermissionedTokenRegistryInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @title  OwnerPermissionedTokenRegistry
 * @author James Wenzel (emo.eth)
 * @notice Interface for a generic registry of tokens, where the owner of a token contract (as specified by the Ownable
 *         interface) is allowed to register the token as part of the registry and configure addresses allowed to call
 *         into subclass methods, as permissioned by the onlyTokenOrAllowedUpdater modifier.
 *
 *         This base registry interface includes methods to see if a token is registered, and the allowedUpdaters,
 *         if any, for registered tokens.
 */
interface OwnerPermissionedTokenRegistryInterface {
    error TokenNotRegistered(address tokenAddress);
    error TokenAlreadyRegistered(address tokenAddress);
    error NotAllowedUpdater();
    error NotTokenOrOwner(address token, address actualOwner);

    event TokenRegistered(address indexed tokenAddress);

    function registerToken(address tokenAddress) external;

    function addAllowedUpdater(address tokenAddress, address newAllowedUpdater)
        external;

    function removeAllowedUpdater(
        address tokenAddress,
        address allowedUpdaterToRemove
    ) external;

    function getAllowedUpdaters(address tokenAddress)
        external
        returns (address[] memory);

    function isAllowedUpdater(address tokenAddress, address updater)
        external
        returns (bool);

    function isTokenRegistered(address tokenAddress)
        external
        returns (bool isRegistered);
}

File 16 of 16 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity 0.8.17;

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

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

Settings
{
  "remappings": [
    "@erc721a/=lib/erc721a/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@solmate/=lib/solmate/src/",
    "@std/=lib/forge-std/src/",
    "ds-test/=lib/ds-test/src/",
    "erc721a/=lib/erc721a/contracts/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solmate/=lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"InvalidConstellationIndex","type":"error"},{"inputs":[],"name":"MoonAddressAlreadySet","type":"error"},{"inputs":[],"name":"MsgSenderNotMoonAddress","type":"error"},{"inputs":[],"name":"SwapMoonsOwnerMustBeMsgSender","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"moon1","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"moon2","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newConstellationForMoon1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newConstellationForMoon2","type":"uint256"}],"name":"SwapConstellations","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moonTokenId","type":"uint256"}],"name":"burnAndMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes32","name":"moonSeed","type":"bytes32"},{"components":[{"components":[{"internalType":"string","name":"moon","type":"string"},{"internalType":"uint16","name":"moonHue","type":"uint16"},{"internalType":"string","name":"border","type":"string"},{"internalType":"uint8","name":"borderSaturation","type":"uint8"},{"internalType":"string","name":"background","type":"string"},{"internalType":"uint8","name":"backgroundLightness","type":"uint8"},{"internalType":"string","name":"backgroundGradientColor","type":"string"}],"internalType":"struct MoonImageColors","name":"colors","type":"tuple"},{"internalType":"uint16","name":"moonRadius","type":"uint16"},{"internalType":"uint16","name":"xOffset","type":"uint16"},{"internalType":"uint16","name":"yOffset","type":"uint16"},{"internalType":"uint16","name":"viewWidth","type":"uint16"},{"internalType":"uint16","name":"viewHeight","type":"uint16"},{"internalType":"uint16","name":"borderRadius","type":"uint16"},{"internalType":"uint16","name":"borderWidth","type":"uint16"},{"internalType":"string","name":"borderType","type":"string"}],"internalType":"struct MoonImageConfig","name":"moonImageConfig","type":"tuple"},{"internalType":"uint256","name":"rotationInDegrees","type":"uint256"}],"name":"getArt","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AlienArtConstellation.Constellation","name":"constellation","type":"uint8"},{"internalType":"bytes32","name":"moonSeed","type":"bytes32"},{"components":[{"components":[{"internalType":"string","name":"moon","type":"string"},{"internalType":"uint16","name":"moonHue","type":"uint16"},{"internalType":"string","name":"border","type":"string"},{"internalType":"uint8","name":"borderSaturation","type":"uint8"},{"internalType":"string","name":"background","type":"string"},{"internalType":"uint8","name":"backgroundLightness","type":"uint8"},{"internalType":"string","name":"backgroundGradientColor","type":"string"}],"internalType":"struct MoonImageColors","name":"colors","type":"tuple"},{"internalType":"uint16","name":"moonRadius","type":"uint16"},{"internalType":"uint16","name":"xOffset","type":"uint16"},{"internalType":"uint16","name":"yOffset","type":"uint16"},{"internalType":"uint16","name":"viewWidth","type":"uint16"},{"internalType":"uint16","name":"viewHeight","type":"uint16"},{"internalType":"uint16","name":"borderRadius","type":"uint16"},{"internalType":"uint16","name":"borderWidth","type":"uint16"},{"internalType":"string","name":"borderType","type":"string"}],"internalType":"struct MoonImageConfig","name":"moonImageConfig","type":"tuple"},{"internalType":"uint256","name":"rotationInDegrees","type":"uint256"}],"name":"getArtForConstellation","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getArtName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"moonTokenId","type":"uint256"}],"name":"getConstellationTypeForMoonTokenIdAtMint","outputs":[{"internalType":"enum AlienArtConstellation.Constellation","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes32","name":"moonSeed","type":"bytes32"},{"components":[{"components":[{"internalType":"string","name":"moon","type":"string"},{"internalType":"uint16","name":"moonHue","type":"uint16"},{"internalType":"string","name":"border","type":"string"},{"internalType":"uint8","name":"borderSaturation","type":"uint8"},{"internalType":"string","name":"background","type":"string"},{"internalType":"uint8","name":"backgroundLightness","type":"uint8"},{"internalType":"string","name":"backgroundGradientColor","type":"string"}],"internalType":"struct MoonImageColors","name":"colors","type":"tuple"},{"internalType":"uint16","name":"moonRadius","type":"uint16"},{"internalType":"uint16","name":"xOffset","type":"uint16"},{"internalType":"uint16","name":"yOffset","type":"uint16"},{"internalType":"uint16","name":"viewWidth","type":"uint16"},{"internalType":"uint16","name":"viewHeight","type":"uint16"},{"internalType":"uint16","name":"borderRadius","type":"uint16"},{"internalType":"uint16","name":"borderWidth","type":"uint16"},{"internalType":"string","name":"borderType","type":"string"}],"internalType":"struct MoonImageConfig","name":"moonImageConfig","type":"tuple"},{"internalType":"uint256","name":"rotationInDegrees","type":"uint256"}],"name":"getMoonFilter","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AlienArtConstellation.Constellation","name":"constellation","type":"uint8"},{"internalType":"bytes32","name":"moonSeed","type":"bytes32"},{"components":[{"components":[{"internalType":"string","name":"moon","type":"string"},{"internalType":"uint16","name":"moonHue","type":"uint16"},{"internalType":"string","name":"border","type":"string"},{"internalType":"uint8","name":"borderSaturation","type":"uint8"},{"internalType":"string","name":"background","type":"string"},{"internalType":"uint8","name":"backgroundLightness","type":"uint8"},{"internalType":"string","name":"backgroundGradientColor","type":"string"}],"internalType":"struct MoonImageColors","name":"colors","type":"tuple"},{"internalType":"uint16","name":"moonRadius","type":"uint16"},{"internalType":"uint16","name":"xOffset","type":"uint16"},{"internalType":"uint16","name":"yOffset","type":"uint16"},{"internalType":"uint16","name":"viewWidth","type":"uint16"},{"internalType":"uint16","name":"viewHeight","type":"uint16"},{"internalType":"uint16","name":"borderRadius","type":"uint16"},{"internalType":"uint16","name":"borderWidth","type":"uint16"},{"internalType":"string","name":"borderType","type":"string"}],"internalType":"struct MoonImageConfig","name":"config","type":"tuple"}],"name":"getStandaloneConstellation","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes32","name":"moonSeed","type":"bytes32"},{"components":[{"components":[{"internalType":"string","name":"moon","type":"string"},{"internalType":"uint16","name":"moonHue","type":"uint16"},{"internalType":"string","name":"border","type":"string"},{"internalType":"uint8","name":"borderSaturation","type":"uint8"},{"internalType":"string","name":"background","type":"string"},{"internalType":"uint8","name":"backgroundLightness","type":"uint8"},{"internalType":"string","name":"backgroundGradientColor","type":"string"}],"internalType":"struct MoonImageColors","name":"colors","type":"tuple"},{"internalType":"uint16","name":"moonRadius","type":"uint16"},{"internalType":"uint16","name":"xOffset","type":"uint16"},{"internalType":"uint16","name":"yOffset","type":"uint16"},{"internalType":"uint16","name":"viewWidth","type":"uint16"},{"internalType":"uint16","name":"viewHeight","type":"uint16"},{"internalType":"uint16","name":"borderRadius","type":"uint16"},{"internalType":"uint16","name":"borderWidth","type":"uint16"},{"internalType":"string","name":"borderType","type":"string"}],"internalType":"struct MoonImageConfig","name":"","type":"tuple"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getTraits","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","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":[{"internalType":"uint256","name":"startMoonTokenId","type":"uint256"},{"internalType":"uint256","name":"numMoonsMinted","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"moonTokenIdToConstellationTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","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":"uint256","name":"amount","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":"address","name":"_moonAddress","type":"address"}],"name":"setMoonAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_dynamicNftRegistryAddress","type":"address"}],"name":"setupDynamicNftRegistry","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":[{"internalType":"uint256","name":"moon1","type":"uint256"},{"internalType":"uint256","name":"moon2","type":"uint256"}],"name":"swapConstellations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b506200001d3362000023565b62000075565b600280546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6155f680620000856000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806375a9f107116100de578063a22cb46511610097578063e985e9c511610071578063e985e9c5146103f1578063f242432a1461041f578063f2fde38b14610432578063f5d0af361461044557600080fd5b8063a22cb46514610399578063abfeb631146103ac578063bdb135b0146103d157600080fd5b806375a9f107146102f95780638da5cb5b1461030c578063941cbad01461032757806395d89b41146103515780639d264488146103735780639fdfdcf51461038657600080fd5b80631b2ef1ca1161014b57806340f0dfc81161012557806340f0dfc81461029e5780634e1273f4146102be5780635ca2708f146102de578063715018a6146102f157600080fd5b80631b2ef1ca1461026557806324a11047146102785780632eb2c2d61461028b57600080fd5b8062fdd58e1461019257806301ffc9a7146101cd5780630430f835146101f057806306fdde03146102055780630e89341c1461023f57806311104e9414610252575b600080fd5b6101ba6101a03660046141f0565b600060208181529281526040808220909352908152205481565b6040519081526020015b60405180910390f35b6101e06101db366004614232565b610458565b60405190151581526020016101c4565b6102036101fe36600461424f565b610484565b005b6102326040518060400160405280600e81526020016d436f6e7374656c6c6174696f6e7360901b81525081565b6040516101c491906142c1565b61023261024d3660046142d4565b6106fa565b6102036102603660046142d4565b610842565b61020361027336600461424f565b610897565b6102326102863660046142ed565b610938565b6102036102993660046143d6565b610a87565b6101ba6102ac3660046142d4565b60046020526000908152604090205481565b6102d16102cc366004614494565b610d2f565b6040516101c491906144ff565b6102036102ec366004614543565b610e63565b610203610e8d565b610232610307366004614857565b610ea1565b6002546040516001600160a01b0390911681526020016101c4565b60408051808201909152600e81526d436f6e7374656c6c6174696f6e7360901b6020820152610232565b6102326040518060400160405280600381526020016221a62760e91b81525081565b6102326103813660046142ed565b61111a565b6102326103943660046148ad565b61115e565b6102036103a736600461490b565b6111f6565b6102326103ba3660046142ed565b604080516020810190915260008152949350505050565b6103e46103df3660046142d4565b611262565b6040516101c4919061495f565b6101e06103ff366004614987565b600160209081526000928352604080842090915290825290205460ff1681565b61020361042d3660046149b5565b611343565b610203610440366004614543565b61153d565b610203610453366004614543565b6115b3565b600061046382611607565b8061047e57506001600160e01b03198216634332ac1760e11b145b92915050565b6003546040516331a9108f60e11b81526004810184905233916001600160a01b031690636352211e90602401602060405180830381865afa1580156104cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f19190614a30565b6001600160a01b031614158061057b57506003546040516331a9108f60e11b81526004810183905233916001600160a01b031690636352211e90602401602060405180830381865afa15801561054b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056f9190614a30565b6001600160a01b031614155b1561059957604051631163eb1d60e11b815260040160405180910390fd5b6000828152600460209081526040808320805485855293829020805482558490555481519081529182018390528391859133917f1a5ef162048a3a1492035fa30ece6f9956ccb5cff5ac5e7a7ce9dc512bb6e425910160405180910390a46005546001600160a01b0316156106f5576005546003546040516348489b1960e11b81526001600160a01b039182166004820152602481018690526078604482015260006064820152911690639091363290608401600060405180830381600087803b15801561066657600080fd5b505af115801561067a573d6000803e3d6000fd5b50506005546003546040516348489b1960e11b81526001600160a01b0391821660048201526024810187905260786044820152600060648201529116925063909136329150608401600060405180830381600087803b1580156106dc57600080fd5b505af11580156106f0573d6000803e3d6000fd5b505050505b505050565b6060600f82111561071e57604051631a6f232160e01b815260040160405180910390fd5b60408051610200810182526060610120820181815260006101408401819052610160840183905261018084018190526101a084018390526101c084018190526101e0840183905290835292820183905280820183905260c0820183905260e0820183905261010082015260c86080820181905260a0820152602080820152906107c26107bd85600f8111156107b5576107b5614949565b600085610ea1565b611655565b905061083a81826107e387600f8111156107de576107de614949565b611686565b6040518060c00160405280609e815260200161544e609e913961081689600f81111561081157610811614949565b611a33565b6040516020016108269190614a4d565b604051602081830303815290604052611a6e565b949350505050565b6003546001600160a01b0316331461086d57604051631b9a240b60e21b815260040160405180910390fd5b6000818152600460205260409020546108899033906001611aca565b610894816001610897565b50565b6003546001600160a01b031633146108c257604051631b9a240b60e21b815260040160405180910390fd5b815b6108ce8284614a97565b8110156106f55760006108e082611262565b600f8111156108f1576108f1614949565b90508060046000848152602001908152602001600020819055506109273382600160405180602001604052806000815250611b4e565b5061093181614aaa565b90506108c4565b606060008061094686611c96565b915091506109c26040518060400160405280600f81526020016e53746172206272696768746e65737360881b8152508361099d5760405180604001604052806005815260200164119a5e195960da1b8152506109bb565b6040518060400160405280600481526020016308cd8eaf60e31b8152505b6001611cdb565b610a366040518060400160405280600a81526020016929ba30b91031b7b637b960b11b81525083610a125760405180604001604052806007815260200166436c617373696360c81b8152506109bb565b6040518060400160405280600481526020016326b7b7b760e11b8152506001611cdb565b600089815260046020526040902054610a5a90600f81111561081157610811614949565b604051602001610a6c93929190614ac3565b60405160208183030381529060405292505050949350505050565b848314610acd5760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b60448201526064015b60405180910390fd5b336001600160a01b0389161480610b0757506001600160a01b038816600090815260016020908152604080832033845290915290205460ff165b610b445760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ac4565b60008060005b87811015610bff57888882818110610b6457610b64614b06565b905060200201359250868682818110610b7f57610b7f614b06565b6001600160a01b038e1660009081526020818152604080832089845282528220805493909102949094013595508593925090610bbc908490614b1c565b90915550506001600160a01b038a1660009081526020818152604080832086845290915281208054849290610bf2908490614a97565b9091555050600101610b4a565b50886001600160a01b03168a6001600160a01b0316336001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8b8b8b8b604051610c539493929190614b61565b60405180910390a46001600160a01b0389163b15610cfa5760405163bc197c8160e01b808252906001600160a01b038b169063bc197c8190610ca79033908f908e908e908e908e908e908e90600401614bb1565b6020604051808303816000875af1158015610cc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cea9190614c15565b6001600160e01b03191614610d07565b6001600160a01b03891615155b610d235760405162461bcd60e51b8152600401610ac490614c32565b50505050505050505050565b6060838214610d725760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b6044820152606401610ac4565b836001600160401b03811115610d8a57610d8a614574565b604051908082528060200260200182016040528015610db3578160200160208202803683370190505b50905060005b84811015610e5a57600080878784818110610dd657610dd6614b06565b9050602002016020810190610deb9190614543565b6001600160a01b03166001600160a01b031681526020019081526020016000206000858584818110610e1f57610e1f614b06565b90506020020135815260200190815260200160002054828281518110610e4757610e47614b06565b6020908102919091010152600101610db9565b50949350505050565b610e6b611cea565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b610e95611cea565b610e9f6000611d44565b565b606061083a610f0260405180604001604052806005815260200164786d6c6e7360d81b8152506040518060400160405280601a81526020017f687474703a2f2f7777772e77332e6f72672f323030302f737667000000000000815250611d96565b610f44604051806040016040528060058152602001640eed2c8e8d60db1b8152506040518060400160405280600381526020016203430360ec1b815250611d96565b610f87604051806040016040528060068152602001651a195a59da1d60d21b8152506040518060400160405280600381526020016203430360ec1b815250611d96565b610fd3604051806040016040528060078152602001660ecd2caee84def60cb1b8152506040518060400160405280600b81526020016a030203020323030203230360ac1b815250611d96565b604051602001610fe69493929190614c5c565b6040516020818303038152906040526110e861103a604051806040016040528060058152602001640eed2c8e8d60db1b8152506040518060400160405280600381526020016203230360ec1b815250611d96565b61107d604051806040016040528060068152602001651a195a59da1d60d21b8152506040518060400160405280600381526020016203230360ec1b815250611d96565b6110c260405180604001604052806004815260200163199a5b1b60e21b815250604051806040016040528060078152602001662330653131313160c81b815250611d96565b6040516020016110d493929190614ac3565b604051602081830303815290604052611dc2565b6110f5878787600061115e565b604051602001611106929190614cb3565b604051602081830303815290604052611dfa565b60008481526004602052604081205460609190600f81111561113e5761113e614949565b9050611154818661114e87614ce2565b8661115e565b9695505050505050565b606060008061116c86611c96565b915091506111eb604051806060016040528089600f81111561119057611190614949565b81526020018661ffff168152602001841515815250866080015161ffff168760a0015161ffff16846111e1576040518060400160405280600781526020016611a32223221c9b60c91b8152506111e5565b8851515b8a611e29565b979650505050505050565b3360008181526001602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600061127a6040518060200160405280600081525090565b6040805160208101859052449181019190915261053960f01b60608201526112c5906062015b604051602081830303815290604052805190602001208261219a90919063ffffffff16565b60006112d282606461219e565b9050600181116112e6575060009392505050565b806002036112f8575060019392505050565b60006113066002600f614b1c565b611311906001614a97565b9050600261131f848361219e565b6113299190614a97565b600f81111561133a5761133a614949565b95945050505050565b336001600160a01b038716148061137d57506001600160a01b038616600090815260016020908152604080832033845290915290205460ff165b6113ba5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ac4565b6001600160a01b038616600090815260208181526040808320878452909152812080548592906113eb908490614b1c565b90915550506001600160a01b03851660009081526020818152604080832087845290915281208054859290611421908490614a97565b909155505060408051858152602081018590526001600160a01b03808816929089169133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46001600160a01b0385163b1561150c5760405163f23a6e6160e01b808252906001600160a01b0387169063f23a6e61906114b99033908b908a908a908a908a90600401614cee565b6020604051808303816000875af11580156114d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fc9190614c15565b6001600160e01b03191614611519565b6001600160a01b03851615155b6115355760405162461bcd60e51b8152600401610ac490614c32565b505050505050565b611545611cea565b6001600160a01b0381166115aa5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ac4565b61089481611d44565b6115bb611cea565b6003546001600160a01b0316156115e557604051638a0ecb3f60e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60006301ffc9a760e01b6001600160e01b0319831614806116385750636cdb3d1360e11b6001600160e01b03198316145b8061047e5750506001600160e01b0319166303a24d0760e21b1490565b6060611660826121bc565b6040516020016116709190614d29565b6040516020818303038152906040529050919050565b6060600082600f81111561169c5761169c614949565b036116ca57505060408051808201909152600d81526c2634ba3a3632903234b83832b960991b602082015290565b600182600f8111156116de576116de614949565b0361170957505060408051808201909152600a8152692134b3903234b83832b960b11b602082015290565b600282600f81111561171d5761171d614949565b03611743575050604080518082019091526005815264417269657360d81b602082015290565b600382600f81111561175757611757614949565b0361177e57505060408051808201909152600681526550697363657360d01b602082015290565b600482600f81111561179257611792614949565b036117bb575050604080518082019091526008815267417175617269757360c01b602082015290565b600582600f8111156117cf576117cf614949565b036117fb57505060408051808201909152600b81526a4361707269636f726e757360a81b602082015290565b600682600f81111561180f5761180f614949565b0361183b57505060408051808201909152600b81526a536167697474617269757360a81b602082015290565b600782600f81111561184f5761184f614949565b036118795750506040805180820190915260098152684f706869756368757360b81b602082015290565b600882600f81111561188d5761188d614949565b036118b657505060408051808201909152600881526753636f727069757360c01b602082015290565b600982600f8111156118ca576118ca614949565b036118f05750506040805180820190915260058152644c6962726160d81b602082015290565b600a82600f81111561190457611904614949565b0361192a575050604080518082019091526005815264566972676f60d81b602082015290565b600b82600f81111561193e5761193e614949565b036119625750506040805180820190915260038152624c656f60e81b602082015290565b600c82600f81111561197657611976614949565b0361199d57505060408051808201909152600681526521b0b731b2b960d11b602082015290565b600d82600f8111156119b1576119b1614949565b036119d857505060408051808201909152600681526547656d696e6960d01b602082015290565b600e82600f8111156119ec576119ec614949565b03611a1357505060408051808201909152600681526554617572757360d01b602082015290565b50506040805180820190915260048152634e6f6e6560e01b602082015290565b606061047e6040518060400160405280600d81526020016c21b7b739ba32b63630ba34b7b760991b815250611a6784611686565b6000611cdb565b6060611aa08484848989604051602001611a8c959493929190614d6e565b6040516020818303038152906040526121bc565b604051602001611ab09190614e73565b604051602081830303815290604052905095945050505050565b6001600160a01b03831660009081526020818152604080832085845290915281208054839290611afb908490614b1c565b909155505060408051838152602081018390526000916001600160a01b0386169133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4505050565b6001600160a01b03841660009081526020818152604080832086845290915281208054849290611b7f908490614a97565b909155505060408051848152602081018490526001600160a01b0386169160009133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46001600160a01b0384163b15611c675760405163f23a6e6160e01b808252906001600160a01b0386169063f23a6e6190611c14903390600090899089908990600401614eb8565b6020604051808303816000875af1158015611c33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c579190614c15565b6001600160e01b03191614611c74565b6001600160a01b03841615155b611c905760405162461bcd60e51b8152600401610ac490614c32565b50505050565b60008082611ca957506000928392509050565b6040805160208101909152838152611cc281600461219e565b15611cce82601461219e565b6000149250925050915091565b606061083a8484846001612322565b6002546001600160a01b03163314610e9f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ac4565b600280546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60608282604051602001611dab929190614ef2565b604051602081830303815290604052905092915050565b606061047e604051806040016040528060048152602001631c9958dd60e21b81525083604051806020016040528060008152506123b1565b6060611e226040518060400160405280600381526020016273766760e81b81525084846123b1565b9392505050565b6060600f8651600f811115611e4057611e40614949565b03611e5a575060408051602081019091526000815261133a565b60006040518061010001604052806000815260200160008152602001886020015161ffff168152602001600288611e919190614f54565b61ffff168152602001611ea5600288614f54565b61ffff16815260208101869052604089810151151590820152606001849052905060008751600f811115611edb57611edb614949565b03611efc57603c815260966020820152611ef4816123e2565b91505061133a565b60018751600f811115611f1157611f11614949565b03611f2a5760598152600d6020820152611ef48161251e565b60028751600f811115611f3f57611f3f614949565b03611f5857604b815260286020820152611ef481612641565b60038751600f811115611f6d57611f6d614949565b03611f86576019815260936020820152611ef4816126e3565b60048751600f811115611f9b57611f9b614949565b03611fb45760238152609c6020820152611ef481612984565b60058751600f811115611fc957611fc9614949565b03611fe2576023815260916020820152611ef481612b5d565b60068751600f811115611ff757611ff7614949565b03612010576023815260a06020820152611ef481612c98565b60078751600f81111561202557612025614949565b0361203e576023815260a06020820152611ef481612cf2565b60088751600f81111561205357612053614949565b0361206c5760238152608c6020820152611ef481612df2565b60098751600f81111561208157612081614949565b0361209a57604b815260a76020820152611ef481612fb1565b600a8751600f8111156120af576120af614949565b036120c857600f815260786020820152611ef4816130b0565b600b8751600f8111156120dd576120dd614949565b036120f6576037815260a56020820152611ef481613283565b600c8751600f81111561210b5761210b614949565b0361212457606e815260b96020820152611ef481613368565b600d8751600f81111561213957612139614949565b0361215257604b815260986020820152611ef4816133db565b600e8751600f81111561216757612167614949565b036121805760438152609b6020820152611ef481613402565b505060408051602081019091526000815295945050505050565b9052565b60005b60208320905080835281826000030681106121a15706919050565b606081516000036121db57505060408051602081019091526000815290565b60006040518060600160405280604081526020016154ec604091399050600060038451600261220a9190614a97565b6122149190614f75565b61221f906004614f89565b9050600061222e826020614a97565b6001600160401b0381111561224557612245614574565b6040519080825280601f01601f19166020018201604052801561226f576020820181803683370190505b509050818152600183018586518101602084015b818310156122dd5760039283018051603f601282901c811687015160f890811b8552600c83901c8216880151811b6001860152600683901c8216880151811b60028601529116860151901b93820193909352600401612283565b6003895106600181146122f7576002811461230857612314565b613d3d60f01b600119830152612314565b603d60f81b6000198301525b509398975050505050505050565b606084826123305784612351565b846040516020016123419190614fa0565b6040516020818303038152906040525b8461236b5760405180602001604052806000815250612386565b604051806040016040528060018152602001600b60fa1b8152505b60405160200161239893929190614fce565b6040516020818303038152906040529050949350505050565b6060838383866040516020016123ca9493929190615052565b60405160208183030381529060405290509392505050565b805160208201516060919060006123fa858484613573565b6124198661240986600b614a97565b612414866009614a97565b613573565b6124338761242887601a614a97565b61241487600f614a97565b61244d8861244288602b614a97565b61241488600e614a97565b6040516020016124609493929190614c5c565b60408051601f198184030181529190529050600061248e86612483866039614a97565b612414866005614a97565b6124a88761249d876040614a97565b61241487600e614a97565b6124c2886124b788602f614a97565b612414886017614a97565b6040516020016124d493929190614ac3565b6040516020818303038152906040529050611154866040015187606001518860800151848660405160200161250a929190614cb3565b604051602081830303815290604052613743565b8051602082015160609190600061253b8584612414856010614a97565b6125508661254a86600b614a97565b85613573565b61256a8761255f876026614a97565b61241487600d614a97565b61258488612579886021614a97565b61241488601e614a97565b6040516020016125979493929190614c5c565b60408051601f19818403018152919052905060006125c5866125ba86602e614a97565b61241486602d614a97565b6125df876125d4876036614a97565b61241487603a614a97565b6125f9886125ee88604e614a97565b612414886042614a97565b60405160200161260b93929190614ac3565b6040516020818303038152906040529050611154866040015187606001518860800151858560405160200161250a929190614cb3565b80516020820151606091906000612659858484613573565b61267386612668866023614a97565b612414601387614b1c565b61268d87612682876032614a97565b612414601588614b1c565b6126a78861269c886037614a97565b612414601089614b1c565b6040516020016126ba9493929190614c5c565b604051602081830303815290604052905061133a85604001518660600151876080015184613743565b805160208201516060919060006126fb858484613573565b6127158661270a866007614a97565b612414600887614b1c565b61272f87612724876011614a97565b612414601488614b1c565b6127498861273e886018614a97565b612414602089614b1c565b61276389612758896015614a97565b61241460298a614b1c565b61277d8a6127728a601e614a97565b612414602f8b614b1c565b604051602001612792969594939291906150eb565b60408051601f19818403018152919052905060006127c0866127b5866009614a97565b612414600287614b1c565b6127da876127cf87601c614a97565b612414600788614b1c565b6127f4886127e9886024614a97565b612414600589614b1c565b61280e89612803896034614a97565b61241460068a614b1c565b6040516020016128219493929190614c5c565b60408051601f198184030181529190529050600061284f8761284487603c614a97565b612414600288614b1c565b6128698861285e886041614a97565b612414600689614b1c565b61288389612878896046614a97565b61241460028a614b1c565b61289d8a6128928a6047614a97565b6124148a6005614a97565b6040516020016128b09493929190614c5c565b60408051601f19818403018152919052905060006128de886128d3886042614a97565b612414886009614a97565b6128f8896128ed89603a614a97565b612414896008614a97565b6129128a6129078a6039614a97565b6124148a6001614a97565b60405160200161292493929190614ac3565b604051602081830303815290604052905060008484848460405160200161294e9493929190614c5c565b604051602081830303815290604052905061297789604001518a606001518b6080015184613743565b9998505050505050505050565b8051602082015160609190600061299c858484613573565b6129b6866129ab86600c614a97565b612414600387614b1c565b6129d0876129c5876014614a97565b612414876005614a97565b6129ea886129df886016614a97565b612414886015614a97565b6040516020016129fd9493929190614c5c565b60408051601f1981840301815291905290506000612a2b86612a20866008614a97565b612414601587614b1c565b612a4587612a3a87600e614a97565b612414601a88614b1c565b612a5f88612a54886012614a97565b612414601589614b1c565b612a7989612a6e89601a614a97565b612414601b8a614b1c565b612a938a612a888a6044614a97565b612414600a8b614b1c565b604051602001612aa795949392919061516a565b60408051601f1981840301815291905290506000612ad587612aca87601d614a97565b612414600b88614b1c565b612aef88612ae4886027614a97565b612414600189614b1c565b604051602001612b00929190614cb3565b60405160208183030381529060405290506000838383604051602001612b2893929190614ac3565b6040516020818303038152906040529050612b51886040015189606001518a6080015184613743565b98975050505050505050565b80516020820151606091906000612b75858484613573565b612b8f86612b84866008614a97565b612414600187614b1c565b612b9e876129c587601e614a97565b604051602001612bb093929190614ac3565b60408051601f1981840301815291905290506000612bde86612bd3866007614a97565b612414866007614a97565b612bf887612bed87600d614a97565b612414876010614a97565b612c1288612c0788601e614a97565b61241488601d614a97565b604051602001612c2493929190614ac3565b60408051601f1981840301815291905290506000612c5287612c47876022614a97565b61241487601a614a97565b612c6c88612c6188603b614a97565b612414886003614a97565b612c8689612c7b896041614a97565b61241460038a614b1c565b604051602001612b0093929190614ac3565b60606000612ca5836139d7565b612cae84613aac565b612cb785613b5d565b604051602001612cc993929190614ac3565b6040516020818303038152906040529050611e2283604001518460600151856080015184613743565b80516020820151606091906000612d0a858484613573565b612d2486612d19866003614a97565b612414601687614b1c565b612d3e87612d3387600b614a97565b612414602088614b1c565b612d5888612d4d886013614a97565b612414601889614b1c565b612d7289612d67896016614a97565b612414896005614a97565b612d8c8a612d818a6009614a97565b6124148a6004614a97565b604051602001612da1969594939291906150eb565b604051602081830303815290604052905061133a85604001518660600151876080015184612de18a896021612dd69190614a97565b6124148a600c614a97565b60405160200161250a929190614cb3565b80516020820151606091906000612e0a858484613573565b612e2486612e19866003614a97565b612414600a87614b1c565b612e3e87612e33876009614a97565b612414600f88614b1c565b612e4d88612ae488600e614a97565b604051602001612e609493929190614c5c565b60408051601f1981840301815291905290506000612e8e86612e83866013614a97565b612414866002614a97565b612ea887612e9d876015614a97565b612414876006614a97565b612ec288612eb7886019614a97565b612414886010614a97565b612edc89612ed1896019614a97565b612414896020614a97565b604051602001612eef9493929190614c5c565b60408051601f1981840301815291905290506000612f1d87612f12876020614a97565b612414876025614a97565b612f3788612f2c88602a614a97565b612414886027614a97565b612f5189612f46896032614a97565b612414896021614a97565b604051602001612f6393929190614ac3565b60408051601f1981840301815291905290506000612f868861257988602f614a97565b612fa089612f9589602c614a97565b612414896017614a97565b604051602001612924929190614cb3565b80516020820151606091906000612fc9858484613573565b612fe386612fd8866006614a97565b612414601187614b1c565b612ffd87612ff2876017614a97565b612414601388614b1c565b60405160200161300f93929190614ac3565b60408051601f198184030181529190529050600061303d86613032866009614a97565b61241486600d614a97565b6130578761304c876007614a97565b612414876012614a97565b604051602001613068929190614cb3565b60408051601f19818403018152919052905060006130968761308b876015614a97565b612414600688614b1c565b612aef886130a5886020614a97565b612414886005614a97565b805160208201516060919060006130d2856130cc856008614a97565b84613573565b6130ec866130e186600b614a97565b612414600b87614b1c565b6130fb87612a3a87600a614a97565b6131158861310a886016614a97565b612414601c89614b1c565b61312f8961312489601c614a97565b612414600a8a614b1c565b60405160200161314395949392919061516a565b60408051601f198184030181529190529050600061317186613166866004614a97565b612414602087614b1c565b6131818786612414602e88614b1c565b61319b88613190886022614a97565b612414602289614b1c565b6040516020016131ad93929190614ac3565b60408051601f19818403018152919052905060006131db876131d0876015614a97565b61241487600c614a97565b6131f5886131ea886018614a97565b61241488600a614a97565b61320f8961320489601e614a97565b612414896012614a97565b60405160200161322193929190614ac3565b60408051601f198184030181529190529050600061324f88613244886021614a97565b612414600789614b1c565b6132698961325e896025614a97565b61241460048a614b1c565b6129128a6132788a6030614a97565b6124148a6009614a97565b8051602082015160609190600061329b858484613573565b6132aa86612e19866004614a97565b6132c4876132b987600e614a97565b612414600c88614b1c565b6132d388612c61886023614a97565b6132ed896132e289602d614a97565b612414896015614a97565b6132fc8a612dd68a601e614a97565b604051602001613311969594939291906150eb565b60408051601f198184030181529190529050600061333486612668866011614a97565b61334e8761334387600b614a97565b612414601e88614b1c565b6125f98861335d886002614a97565b612414601d89614b1c565b80516020820151606091906000613380858484613573565b61338f86612a2086600e614a97565b61339e876132b987601c614a97565b6133ad8861335d88600c614a97565b6133c7896133bc89600b614a97565b61241460318a614b1c565b6040516020016126ba95949392919061516a565b606060006133e883613c54565b6133f184613dbf565b604051602001612cc9929190614cb3565b8051602082015160609190600061341a858484613573565b61343486613429866005614a97565b612414600d87614b1c565b61344387612844876012614a97565b60405160200161345593929190614ac3565b60408051601f198184030181529190529050600061348386613478866012614a97565b61241486600b614a97565b613492876129c5876016614a97565b6134a1886128d3886016614a97565b6040516020016134b393929190614ac3565b60408051601f19818403018152919052905060006134d68761255f876017614a97565b6134e5886128d388601a614a97565b6134ff896134f489601b614a97565b61241489600d614a97565b60405160200161351193929190614ac3565b60408051601f198184030181529190529050600061353f88613534886022614a97565b612414886013614a97565b6135598961354e896031614a97565b612414896018614a97565b6129128a6135688a6033614a97565b6124148a601d614a97565b6060808460c00151156135fc576040805160208101909152600081526135d686604001518760e0015187876040516020016112a0949392919060f09490941b6001600160f01b031916845260028401929092526022830152604282015260620190565b6135f46135e482604761219e565b6135ef90601e614a97565b613ecd565b915050613618565b5060408051808201909152600381526203130360ec1b60208201525b61133a613656604051806040016040528060018152602001601960fa1b8152506040518060c001604052806095815260200161552c60959139611d96565b61368060405180604001604052806004815260200163199a5b1b60e21b8152508860a00151611d96565b6136c9604051806040016040528060068152602001653334b63a32b960d11b8152506040518060400160405280600981526020016875726c2823676c6f2960b81b815250611d96565b613711604051806040016040528060078152602001666f70616369747960c81b815250866040516020016136fd91906151d5565b604051602081830303815290604052611d96565b61371b8989613fec565b60405160200161372f95949392919061516a565b604051602081830303815290604052614036565b606061133a61375386868661406e565b6139b1613795604051806040016040528060028152602001611a5960f21b81525060405180604001604052806003815260200162676c6f60e81b815250611d96565b6138486137df6040518060400160405280600c81526020016b39ba322232bb34b0ba34b7b760a11b815250604051806040016040528060018152602001600d60fa1b815250611d96565b613823604051806040016040528060068152602001651c995cdd5b1d60d21b8152506040518060400160405280600481526020016331363ab960e11b815250611d96565b604051602001613834929190614cb3565b6040516020818303038152906040526140ce565b61398c61389361388e6040518060400160405280600281526020016134b760f11b8152506040518060400160405280600481526020016331363ab960e11b815250611d96565b614110565b6138d661388e6040518060400160405280600281526020016134b760f11b8152506040518060400160405280600481526020016331363ab960e11b815250611d96565b61391961388e6040518060400160405280600281526020016134b760f11b8152506040518060400160405280600481526020016331363ab960e11b815250611d96565b61396561388e6040518060400160405280600281526020016134b760f11b8152506040518060400160405280600d81526020016c536f757263654772617068696360981b815250611d96565b6040516020016139789493929190614c5c565b60405160208183030381529060405261414f565b60405160200161399d929190614cb3565b60405160208183030381529060405261418a565b846040516020016139c3929190614cb3565b6040516020818303038152906040526141b5565b80516020820151606091906139ed848383613573565b613a07856139fc85600b614a97565b612414856005614a97565b613a1686612e83866012614a97565b613a3087613a25876016614a97565b612414876007614a97565b613a4a88613a3f886013614a97565b61241488600d614a97565b613a6489613a59896013614a97565b61241460078a614b1c565b613a7e8a613a738a600b614a97565b61241460118b614b1c565b604051602001613a9497969594939291906151fa565b60405160208183030381529060405292505050919050565b8051602082015160609190613ad184613ac684601b614a97565b612414600685614b1c565b613aeb85613ae085601e614a97565b612414600a86614b1c565b613b0586613afa86601f614a97565b612414601487614b1c565b613b148761268287601a614a97565b613b2e88613b23886024614a97565b612414601489614b1c565b613b4889613b3d89602a614a97565b612414601c8a614b1c565b604051602001613a94969594939291906150eb565b8051602082015160609190613b8284613b77846021614a97565b612414600385614b1c565b613b9c85613b91856024614a97565b612414600986614b1c565b613bb686613bab86602d614a97565b612414600f87614b1c565b613bc587612aca876037614a97565b613bd48861324488603c614a97565b613bee89613be3896037614a97565b612414896006614a97565b613c088a613bfd8a6035614a97565b6124148a600e614a97565b613c228b613c178b602c614a97565b6124148b600c614a97565b613c3c8c613c318c602b614a97565b6124148c6017614a97565b604051602001613a949998979695949392919061528c565b80516020820151606091906000613c6c858484613573565b613c8686613c7b86600a614a97565b612414600c87614b1c565b613c958761308b87600d614a97565b613ca488613244886014614a97565b604051602001613cb79493929190614c5c565b60408051601f1981840301815291905290506000613ce586613cda86600d614a97565b612414866004614a97565b613cf48761242887600d614a97565b613d03886124b788600b614a97565b604051602001613d1593929190614ac3565b60408051601f1981840301815291905290506000613d4387613d3887600d614a97565b612414876022614a97565b613d52886129df886001614a97565b613d6c89613d61896003614a97565b612414896026614a97565b604051602001613d7e93929190614ac3565b6040516020818303038152906040529050828282604051602001613da493929190614ac3565b60405160208183030381529060405295505050505050919050565b80516020820151606091906000613de685613ddb85601c614a97565b612414601086614b1c565b613e0086613df586601d614a97565b612414600687614b1c565b613e0f876127cf876026614a97565b604051602001613e2193929190614ac3565b60408051601f1981840301815291905290506000613e448661240986601c614a97565b613e538761304c87601e614a97565b613e628861257988601e614a97565b604051602001613e7493929190614ac3565b60408051601f1981840301815291905290506000613ea287613e97876019614a97565b612414876023614a97565b613ebc88613eb1886028614a97565b612414886020614a97565b604051602001613d7e929190614cb3565b606081600003613ef45750506040805180820190915260018152600360fc1b602082015290565b8160005b8115613f1b57613f0781614aaa565b9050613f14600a83614f75565b9150613ef8565b6000816001600160401b03811115613f3557613f35614574565b6040519080825280601f01601f191660200182016040528015613f5f576020820181803683370190505b509050815b8515610e5a57613f75600182614b1c565b90506000613f84600a88614f75565b613f8f90600a614f89565b613f999088614b1c565b613fa490603061534d565b905060008160f81b905080848481518110613fc157613fc1614b06565b60200101906001600160f81b031916908160001a905350613fe3600a89614f75565b97505050613f64565b6060611e22604051806040016040528060098152602001687472616e73666f726d60b81b81525061401c85613ecd565b61402585613ecd565b6040516020016136fd929190615366565b606061047e604051806040016040528060048152602001630e0c2e8d60e31b81525083604051806020016040528060008152506123b1565b606061083a604051806040016040528060098152602001687472616e73666f726d60b81b8152506140a28661ffff16613ecd565b6140af8661ffff16613ecd565b6140bc8661ffff16613ecd565b6040516020016136fd939291906153d2565b606061047e6040518060400160405280600e81526020016d3332a3b0bab9b9b4b0b721363ab960911b81525083604051806020016040528060008152506123b1565b606061047e6040518060400160405280600b81526020016a66654d657267654e6f646560a81b81525083604051806020016040528060008152506123b1565b606061047e6040518060400160405280600781526020016666654d6572676560c81b81525060405180602001604052806000815250846123b1565b6060611e22604051806040016040528060068152602001653334b63a32b960d11b81525084846123b1565b6060611e22604051806040016040528060018152602001606760f81b81525084846123b1565b6001600160a01b038116811461089457600080fd5b6000806040838503121561420357600080fd5b823561420e816141db565b946020939093013593505050565b6001600160e01b03198116811461089457600080fd5b60006020828403121561424457600080fd5b8135611e228161421c565b6000806040838503121561426257600080fd5b50508035926020909101359150565b60005b8381101561428c578181015183820152602001614274565b50506000910152565b600081518084526142ad816020860160208601614271565b601f01601f19169290920160200192915050565b602081526000611e226020830184614295565b6000602082840312156142e657600080fd5b5035919050565b6000806000806080858703121561430357600080fd5b843593506020850135925060408501356001600160401b0381111561432757600080fd5b8501610120818803121561433a57600080fd5b9396929550929360600135925050565b60008083601f84011261435c57600080fd5b5081356001600160401b0381111561437357600080fd5b6020830191508360208260051b850101111561438e57600080fd5b9250929050565b60008083601f8401126143a757600080fd5b5081356001600160401b038111156143be57600080fd5b60208301915083602082850101111561438e57600080fd5b60008060008060008060008060a0898b0312156143f257600080fd5b88356143fd816141db565b9750602089013561440d816141db565b965060408901356001600160401b038082111561442957600080fd5b6144358c838d0161434a565b909850965060608b013591508082111561444e57600080fd5b61445a8c838d0161434a565b909650945060808b013591508082111561447357600080fd5b506144808b828c01614395565b999c989b5096995094979396929594505050565b600080600080604085870312156144aa57600080fd5b84356001600160401b03808211156144c157600080fd5b6144cd8883890161434a565b909650945060208701359150808211156144e657600080fd5b506144f38782880161434a565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b818110156145375783518352928401929184019160010161451b565b50909695505050505050565b60006020828403121561455557600080fd5b8135611e22816141db565b80356010811061456f57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156145ac576145ac614574565b60405290565b60405161012081016001600160401b03811182821017156145ac576145ac614574565b600082601f8301126145e657600080fd5b81356001600160401b038082111561460057614600614574565b604051601f8301601f19908116603f0116810190828211818310171561462857614628614574565b8160405283815286602085880101111561464157600080fd5b836020870160208301376000602085830101528094505050505092915050565b803561ffff8116811461456f57600080fd5b803560ff8116811461456f57600080fd5b600060e0828403121561469657600080fd5b61469e61458a565b905081356001600160401b03808211156146b757600080fd5b6146c3858386016145d5565b83526146d160208501614661565b602084015260408401359150808211156146ea57600080fd5b6146f6858386016145d5565b604084015261470760608501614673565b6060840152608084013591508082111561472057600080fd5b61472c858386016145d5565b608084015261473d60a08501614673565b60a084015260c084013591508082111561475657600080fd5b50614763848285016145d5565b60c08301525092915050565b6000610120828403121561478257600080fd5b61478a6145b2565b905081356001600160401b03808211156147a357600080fd5b6147af85838601614684565b83526147bd60208501614661565b60208401526147ce60408501614661565b60408401526147df60608501614661565b60608401526147f060808501614661565b608084015261480160a08501614661565b60a084015261481260c08501614661565b60c084015261482360e08501614661565b60e08401526101009150818401358181111561483e57600080fd5b61484a868287016145d5565b8385015250505092915050565b60008060006060848603121561486c57600080fd5b61487584614560565b92506020840135915060408401356001600160401b0381111561489757600080fd5b6148a38682870161476f565b9150509250925092565b600080600080608085870312156148c357600080fd5b6148cc85614560565b93506020850135925060408501356001600160401b038111156148ee57600080fd5b6148fa8782880161476f565b949793965093946060013593505050565b6000806040838503121561491e57600080fd5b8235614929816141db565b91506020830135801515811461493e57600080fd5b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b602081016010831061498157634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561499a57600080fd5b82356149a5816141db565b9150602083013561493e816141db565b60008060008060008060a087890312156149ce57600080fd5b86356149d9816141db565b955060208701356149e9816141db565b9450604087013593506060870135925060808701356001600160401b03811115614a1257600080fd5b614a1e89828a01614395565b979a9699509497509295939492505050565b600060208284031215614a4257600080fd5b8151611e22816141db565b605b60f81b815260008251614a69816001850160208701614271565b605d60f81b6001939091019283015250600201919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561047e5761047e614a81565b600060018201614abc57614abc614a81565b5060010190565b60008451614ad5818460208901614271565b845190830190614ae9818360208901614271565b8451910190614afc818360208801614271565b0195945050505050565b634e487b7160e01b600052603260045260246000fd5b8181038181111561047e5761047e614a81565b81835260006001600160fb1b03831115614b4857600080fd5b8260051b80836020870137939093016020019392505050565b604081526000614b75604083018688614b2f565b82810360208401526111eb818587614b2f565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0389811682528816602082015260a060408201819052600090614bde908301888a614b2f565b8281036060840152614bf1818789614b2f565b90508281036080840152614c06818587614b88565b9b9a5050505050505050505050565b600060208284031215614c2757600080fd5b8151611e228161421c565b60208082526010908201526f155394d0519157d49150d2541251539560821b604082015260600190565b60008551614c6e818460208a01614271565b855190830190614c82818360208a01614271565b8551910190614c95818360208901614271565b8451910190614ca8818360208801614271565b019695505050505050565b60008351614cc5818460208801614271565b835190830190614cd9818360208801614271565b01949350505050565b600061047e368361476f565b6001600160a01b03878116825286166020820152604081018590526060810184905260a060808201819052600090612b519083018486614b88565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000815260008251614d6181601a850160208701614271565b91909101601a0192915050565b683d913730b6b2911d1160b91b81528551600090614d93816009850160208b01614271565b701116113232b9b1b934b83a34b7b7111d1160791b6009918401918201528651614dc481601a840160208b01614271565b6e11161130ba3a3934b13aba32b9911d60891b601a92909101918201528551614df4816029840160208a01614271565b69161134b6b0b3b2911d1160b11b602992909101918201528451614e1f816033840160208901614271565b7211161130b734b6b0ba34b7b72fbab936111d1160691b603392909101918201528351614e53816046840160208801614271565b01614e656046820161227d60f01b9052565b604801979650505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251614eab81601d850160208701614271565b91909101601d0192915050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190526000906111eb90830184614295565b60008351614f04818460208801614271565b611e9160f11b9083019081528351614f23816002840160208801614271565b61011160f51b60029290910191820152600401949350505050565b634e487b7160e01b600052601260045260246000fd5b600061ffff80841680614f6957614f69614f3e565b92169190910492915050565b600082614f8457614f84614f3e565b500490565b808202811582820484141761047e5761047e614a81565b6000601160f91b8083528351614fbd816001860160208801614271565b600193019283015250600201919050565b6e3d913a3930b4ba2fba3cb832911d1160891b81528351600090614ff981600f850160208901614271565b691116113b30b63ab2911d60b11b600f918401918201528451615023816019840160208901614271565b607d60f81b60199290910191820152835161504581601a840160208801614271565b01601a0195945050505050565b600f60fa1b81526000855161506e816001850160208a01614271565b600160fd1b600191840191820152855161508f816002840160208a01614271565b808201915050601f60f91b80600283015285516150b3816003850160208a01614271565b613c2f60f01b6003939091019283015284516150d6816005850160208901614271565b60059201918201526006019695505050505050565b6000875160206150fe8285838d01614271565b8851918401916151118184848d01614271565b88519201916151238184848c01614271565b87519201916151358184848b01614271565b86519201916151478184848a01614271565b85519201916151598184848901614271565b919091019998505050505050505050565b6000865161517c818460208b01614271565b865190830190615190818360208b01614271565b86519101906151a3818360208a01614271565b85519101906151b6818360208901614271565b84519101906151c9818360208801614271565b01979650505050505050565b600082516151e7818460208701614271565b602560f81b920191825250600101919050565b60008851602061520d8285838e01614271565b8951918401916152208184848e01614271565b89519201916152328184848d01614271565b88519201916152448184848c01614271565b87519201916152568184848b01614271565b86519201916152688184848a01614271565b855192019161527a8184848901614271565b919091019a9950505050505050505050565b60008a5161529e818460208f01614271565b8a516152b08183860160208f01614271565b8a5191840101906152c5818360208e01614271565b89516152d78183850160208e01614271565b89519290910101906152ed818360208c01614271565b87516152ff8183850160208c01614271565b8751929091010190615315818360208a01614271565b85516153278183850160208a01614271565b855192909101019061533d818360208801614271565b019b9a5050505050505050505050565b60ff818116838216019081111561047e5761047e614a81565b690e8e4c2dce6d8c2e8ca560b31b81526000835161538b81600a850160208801614271565b600b60fa1b600a9184019182015283516153ac81600b840160208801614271565b6c29207363616c6528302e30332960981b600b9290910191820152601801949350505050565b660e4dee8c2e8ca560cb1b8152600084516153f4816007850160208901614271565b8083019050600160fd1b8060078301528551615417816008850160208a01614271565b60089201918201528351615432816009840160208801614271565b602960f81b60099290910191820152600a019594505050505056fe436f6e7374656c6c6174696f6e7320617265206f6e2d636861696e20636f6e7374656c6c6174696f6e204e4654732e20436f6e7374656c6c6174696f6e7320617265206f6e2d636861696e20617274206f776e6564206279206f6e2d636861696e206172743b20436f6e7374656c6c6174696f6e732061726520616c6c206f776e6564206279204e6f6e2d46756e6769626c65204d6f6f6e204e4654732e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f4d203430203630204c2036332e3531312037322e333631204c2035392e3032312034362e313830204c2037382e3034322032372e363339204c2035312e3735362032332e383230204c2034302030204c2032382e3234342032332e383230204c20312e3935382032372e363339204c2032302e3937392034362e313830204c2031362e3438392037322e333631204c203430203630a2646970667358221220cb31205f063f44ddfaaf4c8b108646d12f926ceeb970f5937f0a9a014acd706e64736f6c63430008110033

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061018d5760003560e01c806375a9f107116100de578063a22cb46511610097578063e985e9c511610071578063e985e9c5146103f1578063f242432a1461041f578063f2fde38b14610432578063f5d0af361461044557600080fd5b8063a22cb46514610399578063abfeb631146103ac578063bdb135b0146103d157600080fd5b806375a9f107146102f95780638da5cb5b1461030c578063941cbad01461032757806395d89b41146103515780639d264488146103735780639fdfdcf51461038657600080fd5b80631b2ef1ca1161014b57806340f0dfc81161012557806340f0dfc81461029e5780634e1273f4146102be5780635ca2708f146102de578063715018a6146102f157600080fd5b80631b2ef1ca1461026557806324a11047146102785780632eb2c2d61461028b57600080fd5b8062fdd58e1461019257806301ffc9a7146101cd5780630430f835146101f057806306fdde03146102055780630e89341c1461023f57806311104e9414610252575b600080fd5b6101ba6101a03660046141f0565b600060208181529281526040808220909352908152205481565b6040519081526020015b60405180910390f35b6101e06101db366004614232565b610458565b60405190151581526020016101c4565b6102036101fe36600461424f565b610484565b005b6102326040518060400160405280600e81526020016d436f6e7374656c6c6174696f6e7360901b81525081565b6040516101c491906142c1565b61023261024d3660046142d4565b6106fa565b6102036102603660046142d4565b610842565b61020361027336600461424f565b610897565b6102326102863660046142ed565b610938565b6102036102993660046143d6565b610a87565b6101ba6102ac3660046142d4565b60046020526000908152604090205481565b6102d16102cc366004614494565b610d2f565b6040516101c491906144ff565b6102036102ec366004614543565b610e63565b610203610e8d565b610232610307366004614857565b610ea1565b6002546040516001600160a01b0390911681526020016101c4565b60408051808201909152600e81526d436f6e7374656c6c6174696f6e7360901b6020820152610232565b6102326040518060400160405280600381526020016221a62760e91b81525081565b6102326103813660046142ed565b61111a565b6102326103943660046148ad565b61115e565b6102036103a736600461490b565b6111f6565b6102326103ba3660046142ed565b604080516020810190915260008152949350505050565b6103e46103df3660046142d4565b611262565b6040516101c4919061495f565b6101e06103ff366004614987565b600160209081526000928352604080842090915290825290205460ff1681565b61020361042d3660046149b5565b611343565b610203610440366004614543565b61153d565b610203610453366004614543565b6115b3565b600061046382611607565b8061047e57506001600160e01b03198216634332ac1760e11b145b92915050565b6003546040516331a9108f60e11b81526004810184905233916001600160a01b031690636352211e90602401602060405180830381865afa1580156104cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f19190614a30565b6001600160a01b031614158061057b57506003546040516331a9108f60e11b81526004810183905233916001600160a01b031690636352211e90602401602060405180830381865afa15801561054b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056f9190614a30565b6001600160a01b031614155b1561059957604051631163eb1d60e11b815260040160405180910390fd5b6000828152600460209081526040808320805485855293829020805482558490555481519081529182018390528391859133917f1a5ef162048a3a1492035fa30ece6f9956ccb5cff5ac5e7a7ce9dc512bb6e425910160405180910390a46005546001600160a01b0316156106f5576005546003546040516348489b1960e11b81526001600160a01b039182166004820152602481018690526078604482015260006064820152911690639091363290608401600060405180830381600087803b15801561066657600080fd5b505af115801561067a573d6000803e3d6000fd5b50506005546003546040516348489b1960e11b81526001600160a01b0391821660048201526024810187905260786044820152600060648201529116925063909136329150608401600060405180830381600087803b1580156106dc57600080fd5b505af11580156106f0573d6000803e3d6000fd5b505050505b505050565b6060600f82111561071e57604051631a6f232160e01b815260040160405180910390fd5b60408051610200810182526060610120820181815260006101408401819052610160840183905261018084018190526101a084018390526101c084018190526101e0840183905290835292820183905280820183905260c0820183905260e0820183905261010082015260c86080820181905260a0820152602080820152906107c26107bd85600f8111156107b5576107b5614949565b600085610ea1565b611655565b905061083a81826107e387600f8111156107de576107de614949565b611686565b6040518060c00160405280609e815260200161544e609e913961081689600f81111561081157610811614949565b611a33565b6040516020016108269190614a4d565b604051602081830303815290604052611a6e565b949350505050565b6003546001600160a01b0316331461086d57604051631b9a240b60e21b815260040160405180910390fd5b6000818152600460205260409020546108899033906001611aca565b610894816001610897565b50565b6003546001600160a01b031633146108c257604051631b9a240b60e21b815260040160405180910390fd5b815b6108ce8284614a97565b8110156106f55760006108e082611262565b600f8111156108f1576108f1614949565b90508060046000848152602001908152602001600020819055506109273382600160405180602001604052806000815250611b4e565b5061093181614aaa565b90506108c4565b606060008061094686611c96565b915091506109c26040518060400160405280600f81526020016e53746172206272696768746e65737360881b8152508361099d5760405180604001604052806005815260200164119a5e195960da1b8152506109bb565b6040518060400160405280600481526020016308cd8eaf60e31b8152505b6001611cdb565b610a366040518060400160405280600a81526020016929ba30b91031b7b637b960b11b81525083610a125760405180604001604052806007815260200166436c617373696360c81b8152506109bb565b6040518060400160405280600481526020016326b7b7b760e11b8152506001611cdb565b600089815260046020526040902054610a5a90600f81111561081157610811614949565b604051602001610a6c93929190614ac3565b60405160208183030381529060405292505050949350505050565b848314610acd5760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b60448201526064015b60405180910390fd5b336001600160a01b0389161480610b0757506001600160a01b038816600090815260016020908152604080832033845290915290205460ff165b610b445760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ac4565b60008060005b87811015610bff57888882818110610b6457610b64614b06565b905060200201359250868682818110610b7f57610b7f614b06565b6001600160a01b038e1660009081526020818152604080832089845282528220805493909102949094013595508593925090610bbc908490614b1c565b90915550506001600160a01b038a1660009081526020818152604080832086845290915281208054849290610bf2908490614a97565b9091555050600101610b4a565b50886001600160a01b03168a6001600160a01b0316336001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8b8b8b8b604051610c539493929190614b61565b60405180910390a46001600160a01b0389163b15610cfa5760405163bc197c8160e01b808252906001600160a01b038b169063bc197c8190610ca79033908f908e908e908e908e908e908e90600401614bb1565b6020604051808303816000875af1158015610cc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cea9190614c15565b6001600160e01b03191614610d07565b6001600160a01b03891615155b610d235760405162461bcd60e51b8152600401610ac490614c32565b50505050505050505050565b6060838214610d725760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b6044820152606401610ac4565b836001600160401b03811115610d8a57610d8a614574565b604051908082528060200260200182016040528015610db3578160200160208202803683370190505b50905060005b84811015610e5a57600080878784818110610dd657610dd6614b06565b9050602002016020810190610deb9190614543565b6001600160a01b03166001600160a01b031681526020019081526020016000206000858584818110610e1f57610e1f614b06565b90506020020135815260200190815260200160002054828281518110610e4757610e47614b06565b6020908102919091010152600101610db9565b50949350505050565b610e6b611cea565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b610e95611cea565b610e9f6000611d44565b565b606061083a610f0260405180604001604052806005815260200164786d6c6e7360d81b8152506040518060400160405280601a81526020017f687474703a2f2f7777772e77332e6f72672f323030302f737667000000000000815250611d96565b610f44604051806040016040528060058152602001640eed2c8e8d60db1b8152506040518060400160405280600381526020016203430360ec1b815250611d96565b610f87604051806040016040528060068152602001651a195a59da1d60d21b8152506040518060400160405280600381526020016203430360ec1b815250611d96565b610fd3604051806040016040528060078152602001660ecd2caee84def60cb1b8152506040518060400160405280600b81526020016a030203020323030203230360ac1b815250611d96565b604051602001610fe69493929190614c5c565b6040516020818303038152906040526110e861103a604051806040016040528060058152602001640eed2c8e8d60db1b8152506040518060400160405280600381526020016203230360ec1b815250611d96565b61107d604051806040016040528060068152602001651a195a59da1d60d21b8152506040518060400160405280600381526020016203230360ec1b815250611d96565b6110c260405180604001604052806004815260200163199a5b1b60e21b815250604051806040016040528060078152602001662330653131313160c81b815250611d96565b6040516020016110d493929190614ac3565b604051602081830303815290604052611dc2565b6110f5878787600061115e565b604051602001611106929190614cb3565b604051602081830303815290604052611dfa565b60008481526004602052604081205460609190600f81111561113e5761113e614949565b9050611154818661114e87614ce2565b8661115e565b9695505050505050565b606060008061116c86611c96565b915091506111eb604051806060016040528089600f81111561119057611190614949565b81526020018661ffff168152602001841515815250866080015161ffff168760a0015161ffff16846111e1576040518060400160405280600781526020016611a32223221c9b60c91b8152506111e5565b8851515b8a611e29565b979650505050505050565b3360008181526001602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600061127a6040518060200160405280600081525090565b6040805160208101859052449181019190915261053960f01b60608201526112c5906062015b604051602081830303815290604052805190602001208261219a90919063ffffffff16565b60006112d282606461219e565b9050600181116112e6575060009392505050565b806002036112f8575060019392505050565b60006113066002600f614b1c565b611311906001614a97565b9050600261131f848361219e565b6113299190614a97565b600f81111561133a5761133a614949565b95945050505050565b336001600160a01b038716148061137d57506001600160a01b038616600090815260016020908152604080832033845290915290205460ff165b6113ba5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ac4565b6001600160a01b038616600090815260208181526040808320878452909152812080548592906113eb908490614b1c565b90915550506001600160a01b03851660009081526020818152604080832087845290915281208054859290611421908490614a97565b909155505060408051858152602081018590526001600160a01b03808816929089169133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46001600160a01b0385163b1561150c5760405163f23a6e6160e01b808252906001600160a01b0387169063f23a6e61906114b99033908b908a908a908a908a90600401614cee565b6020604051808303816000875af11580156114d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fc9190614c15565b6001600160e01b03191614611519565b6001600160a01b03851615155b6115355760405162461bcd60e51b8152600401610ac490614c32565b505050505050565b611545611cea565b6001600160a01b0381166115aa5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ac4565b61089481611d44565b6115bb611cea565b6003546001600160a01b0316156115e557604051638a0ecb3f60e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60006301ffc9a760e01b6001600160e01b0319831614806116385750636cdb3d1360e11b6001600160e01b03198316145b8061047e5750506001600160e01b0319166303a24d0760e21b1490565b6060611660826121bc565b6040516020016116709190614d29565b6040516020818303038152906040529050919050565b6060600082600f81111561169c5761169c614949565b036116ca57505060408051808201909152600d81526c2634ba3a3632903234b83832b960991b602082015290565b600182600f8111156116de576116de614949565b0361170957505060408051808201909152600a8152692134b3903234b83832b960b11b602082015290565b600282600f81111561171d5761171d614949565b03611743575050604080518082019091526005815264417269657360d81b602082015290565b600382600f81111561175757611757614949565b0361177e57505060408051808201909152600681526550697363657360d01b602082015290565b600482600f81111561179257611792614949565b036117bb575050604080518082019091526008815267417175617269757360c01b602082015290565b600582600f8111156117cf576117cf614949565b036117fb57505060408051808201909152600b81526a4361707269636f726e757360a81b602082015290565b600682600f81111561180f5761180f614949565b0361183b57505060408051808201909152600b81526a536167697474617269757360a81b602082015290565b600782600f81111561184f5761184f614949565b036118795750506040805180820190915260098152684f706869756368757360b81b602082015290565b600882600f81111561188d5761188d614949565b036118b657505060408051808201909152600881526753636f727069757360c01b602082015290565b600982600f8111156118ca576118ca614949565b036118f05750506040805180820190915260058152644c6962726160d81b602082015290565b600a82600f81111561190457611904614949565b0361192a575050604080518082019091526005815264566972676f60d81b602082015290565b600b82600f81111561193e5761193e614949565b036119625750506040805180820190915260038152624c656f60e81b602082015290565b600c82600f81111561197657611976614949565b0361199d57505060408051808201909152600681526521b0b731b2b960d11b602082015290565b600d82600f8111156119b1576119b1614949565b036119d857505060408051808201909152600681526547656d696e6960d01b602082015290565b600e82600f8111156119ec576119ec614949565b03611a1357505060408051808201909152600681526554617572757360d01b602082015290565b50506040805180820190915260048152634e6f6e6560e01b602082015290565b606061047e6040518060400160405280600d81526020016c21b7b739ba32b63630ba34b7b760991b815250611a6784611686565b6000611cdb565b6060611aa08484848989604051602001611a8c959493929190614d6e565b6040516020818303038152906040526121bc565b604051602001611ab09190614e73565b604051602081830303815290604052905095945050505050565b6001600160a01b03831660009081526020818152604080832085845290915281208054839290611afb908490614b1c565b909155505060408051838152602081018390526000916001600160a01b0386169133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4505050565b6001600160a01b03841660009081526020818152604080832086845290915281208054849290611b7f908490614a97565b909155505060408051848152602081018490526001600160a01b0386169160009133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46001600160a01b0384163b15611c675760405163f23a6e6160e01b808252906001600160a01b0386169063f23a6e6190611c14903390600090899089908990600401614eb8565b6020604051808303816000875af1158015611c33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c579190614c15565b6001600160e01b03191614611c74565b6001600160a01b03841615155b611c905760405162461bcd60e51b8152600401610ac490614c32565b50505050565b60008082611ca957506000928392509050565b6040805160208101909152838152611cc281600461219e565b15611cce82601461219e565b6000149250925050915091565b606061083a8484846001612322565b6002546001600160a01b03163314610e9f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ac4565b600280546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60608282604051602001611dab929190614ef2565b604051602081830303815290604052905092915050565b606061047e604051806040016040528060048152602001631c9958dd60e21b81525083604051806020016040528060008152506123b1565b6060611e226040518060400160405280600381526020016273766760e81b81525084846123b1565b9392505050565b6060600f8651600f811115611e4057611e40614949565b03611e5a575060408051602081019091526000815261133a565b60006040518061010001604052806000815260200160008152602001886020015161ffff168152602001600288611e919190614f54565b61ffff168152602001611ea5600288614f54565b61ffff16815260208101869052604089810151151590820152606001849052905060008751600f811115611edb57611edb614949565b03611efc57603c815260966020820152611ef4816123e2565b91505061133a565b60018751600f811115611f1157611f11614949565b03611f2a5760598152600d6020820152611ef48161251e565b60028751600f811115611f3f57611f3f614949565b03611f5857604b815260286020820152611ef481612641565b60038751600f811115611f6d57611f6d614949565b03611f86576019815260936020820152611ef4816126e3565b60048751600f811115611f9b57611f9b614949565b03611fb45760238152609c6020820152611ef481612984565b60058751600f811115611fc957611fc9614949565b03611fe2576023815260916020820152611ef481612b5d565b60068751600f811115611ff757611ff7614949565b03612010576023815260a06020820152611ef481612c98565b60078751600f81111561202557612025614949565b0361203e576023815260a06020820152611ef481612cf2565b60088751600f81111561205357612053614949565b0361206c5760238152608c6020820152611ef481612df2565b60098751600f81111561208157612081614949565b0361209a57604b815260a76020820152611ef481612fb1565b600a8751600f8111156120af576120af614949565b036120c857600f815260786020820152611ef4816130b0565b600b8751600f8111156120dd576120dd614949565b036120f6576037815260a56020820152611ef481613283565b600c8751600f81111561210b5761210b614949565b0361212457606e815260b96020820152611ef481613368565b600d8751600f81111561213957612139614949565b0361215257604b815260986020820152611ef4816133db565b600e8751600f81111561216757612167614949565b036121805760438152609b6020820152611ef481613402565b505060408051602081019091526000815295945050505050565b9052565b60005b60208320905080835281826000030681106121a15706919050565b606081516000036121db57505060408051602081019091526000815290565b60006040518060600160405280604081526020016154ec604091399050600060038451600261220a9190614a97565b6122149190614f75565b61221f906004614f89565b9050600061222e826020614a97565b6001600160401b0381111561224557612245614574565b6040519080825280601f01601f19166020018201604052801561226f576020820181803683370190505b509050818152600183018586518101602084015b818310156122dd5760039283018051603f601282901c811687015160f890811b8552600c83901c8216880151811b6001860152600683901c8216880151811b60028601529116860151901b93820193909352600401612283565b6003895106600181146122f7576002811461230857612314565b613d3d60f01b600119830152612314565b603d60f81b6000198301525b509398975050505050505050565b606084826123305784612351565b846040516020016123419190614fa0565b6040516020818303038152906040525b8461236b5760405180602001604052806000815250612386565b604051806040016040528060018152602001600b60fa1b8152505b60405160200161239893929190614fce565b6040516020818303038152906040529050949350505050565b6060838383866040516020016123ca9493929190615052565b60405160208183030381529060405290509392505050565b805160208201516060919060006123fa858484613573565b6124198661240986600b614a97565b612414866009614a97565b613573565b6124338761242887601a614a97565b61241487600f614a97565b61244d8861244288602b614a97565b61241488600e614a97565b6040516020016124609493929190614c5c565b60408051601f198184030181529190529050600061248e86612483866039614a97565b612414866005614a97565b6124a88761249d876040614a97565b61241487600e614a97565b6124c2886124b788602f614a97565b612414886017614a97565b6040516020016124d493929190614ac3565b6040516020818303038152906040529050611154866040015187606001518860800151848660405160200161250a929190614cb3565b604051602081830303815290604052613743565b8051602082015160609190600061253b8584612414856010614a97565b6125508661254a86600b614a97565b85613573565b61256a8761255f876026614a97565b61241487600d614a97565b61258488612579886021614a97565b61241488601e614a97565b6040516020016125979493929190614c5c565b60408051601f19818403018152919052905060006125c5866125ba86602e614a97565b61241486602d614a97565b6125df876125d4876036614a97565b61241487603a614a97565b6125f9886125ee88604e614a97565b612414886042614a97565b60405160200161260b93929190614ac3565b6040516020818303038152906040529050611154866040015187606001518860800151858560405160200161250a929190614cb3565b80516020820151606091906000612659858484613573565b61267386612668866023614a97565b612414601387614b1c565b61268d87612682876032614a97565b612414601588614b1c565b6126a78861269c886037614a97565b612414601089614b1c565b6040516020016126ba9493929190614c5c565b604051602081830303815290604052905061133a85604001518660600151876080015184613743565b805160208201516060919060006126fb858484613573565b6127158661270a866007614a97565b612414600887614b1c565b61272f87612724876011614a97565b612414601488614b1c565b6127498861273e886018614a97565b612414602089614b1c565b61276389612758896015614a97565b61241460298a614b1c565b61277d8a6127728a601e614a97565b612414602f8b614b1c565b604051602001612792969594939291906150eb565b60408051601f19818403018152919052905060006127c0866127b5866009614a97565b612414600287614b1c565b6127da876127cf87601c614a97565b612414600788614b1c565b6127f4886127e9886024614a97565b612414600589614b1c565b61280e89612803896034614a97565b61241460068a614b1c565b6040516020016128219493929190614c5c565b60408051601f198184030181529190529050600061284f8761284487603c614a97565b612414600288614b1c565b6128698861285e886041614a97565b612414600689614b1c565b61288389612878896046614a97565b61241460028a614b1c565b61289d8a6128928a6047614a97565b6124148a6005614a97565b6040516020016128b09493929190614c5c565b60408051601f19818403018152919052905060006128de886128d3886042614a97565b612414886009614a97565b6128f8896128ed89603a614a97565b612414896008614a97565b6129128a6129078a6039614a97565b6124148a6001614a97565b60405160200161292493929190614ac3565b604051602081830303815290604052905060008484848460405160200161294e9493929190614c5c565b604051602081830303815290604052905061297789604001518a606001518b6080015184613743565b9998505050505050505050565b8051602082015160609190600061299c858484613573565b6129b6866129ab86600c614a97565b612414600387614b1c565b6129d0876129c5876014614a97565b612414876005614a97565b6129ea886129df886016614a97565b612414886015614a97565b6040516020016129fd9493929190614c5c565b60408051601f1981840301815291905290506000612a2b86612a20866008614a97565b612414601587614b1c565b612a4587612a3a87600e614a97565b612414601a88614b1c565b612a5f88612a54886012614a97565b612414601589614b1c565b612a7989612a6e89601a614a97565b612414601b8a614b1c565b612a938a612a888a6044614a97565b612414600a8b614b1c565b604051602001612aa795949392919061516a565b60408051601f1981840301815291905290506000612ad587612aca87601d614a97565b612414600b88614b1c565b612aef88612ae4886027614a97565b612414600189614b1c565b604051602001612b00929190614cb3565b60405160208183030381529060405290506000838383604051602001612b2893929190614ac3565b6040516020818303038152906040529050612b51886040015189606001518a6080015184613743565b98975050505050505050565b80516020820151606091906000612b75858484613573565b612b8f86612b84866008614a97565b612414600187614b1c565b612b9e876129c587601e614a97565b604051602001612bb093929190614ac3565b60408051601f1981840301815291905290506000612bde86612bd3866007614a97565b612414866007614a97565b612bf887612bed87600d614a97565b612414876010614a97565b612c1288612c0788601e614a97565b61241488601d614a97565b604051602001612c2493929190614ac3565b60408051601f1981840301815291905290506000612c5287612c47876022614a97565b61241487601a614a97565b612c6c88612c6188603b614a97565b612414886003614a97565b612c8689612c7b896041614a97565b61241460038a614b1c565b604051602001612b0093929190614ac3565b60606000612ca5836139d7565b612cae84613aac565b612cb785613b5d565b604051602001612cc993929190614ac3565b6040516020818303038152906040529050611e2283604001518460600151856080015184613743565b80516020820151606091906000612d0a858484613573565b612d2486612d19866003614a97565b612414601687614b1c565b612d3e87612d3387600b614a97565b612414602088614b1c565b612d5888612d4d886013614a97565b612414601889614b1c565b612d7289612d67896016614a97565b612414896005614a97565b612d8c8a612d818a6009614a97565b6124148a6004614a97565b604051602001612da1969594939291906150eb565b604051602081830303815290604052905061133a85604001518660600151876080015184612de18a896021612dd69190614a97565b6124148a600c614a97565b60405160200161250a929190614cb3565b80516020820151606091906000612e0a858484613573565b612e2486612e19866003614a97565b612414600a87614b1c565b612e3e87612e33876009614a97565b612414600f88614b1c565b612e4d88612ae488600e614a97565b604051602001612e609493929190614c5c565b60408051601f1981840301815291905290506000612e8e86612e83866013614a97565b612414866002614a97565b612ea887612e9d876015614a97565b612414876006614a97565b612ec288612eb7886019614a97565b612414886010614a97565b612edc89612ed1896019614a97565b612414896020614a97565b604051602001612eef9493929190614c5c565b60408051601f1981840301815291905290506000612f1d87612f12876020614a97565b612414876025614a97565b612f3788612f2c88602a614a97565b612414886027614a97565b612f5189612f46896032614a97565b612414896021614a97565b604051602001612f6393929190614ac3565b60408051601f1981840301815291905290506000612f868861257988602f614a97565b612fa089612f9589602c614a97565b612414896017614a97565b604051602001612924929190614cb3565b80516020820151606091906000612fc9858484613573565b612fe386612fd8866006614a97565b612414601187614b1c565b612ffd87612ff2876017614a97565b612414601388614b1c565b60405160200161300f93929190614ac3565b60408051601f198184030181529190529050600061303d86613032866009614a97565b61241486600d614a97565b6130578761304c876007614a97565b612414876012614a97565b604051602001613068929190614cb3565b60408051601f19818403018152919052905060006130968761308b876015614a97565b612414600688614b1c565b612aef886130a5886020614a97565b612414886005614a97565b805160208201516060919060006130d2856130cc856008614a97565b84613573565b6130ec866130e186600b614a97565b612414600b87614b1c565b6130fb87612a3a87600a614a97565b6131158861310a886016614a97565b612414601c89614b1c565b61312f8961312489601c614a97565b612414600a8a614b1c565b60405160200161314395949392919061516a565b60408051601f198184030181529190529050600061317186613166866004614a97565b612414602087614b1c565b6131818786612414602e88614b1c565b61319b88613190886022614a97565b612414602289614b1c565b6040516020016131ad93929190614ac3565b60408051601f19818403018152919052905060006131db876131d0876015614a97565b61241487600c614a97565b6131f5886131ea886018614a97565b61241488600a614a97565b61320f8961320489601e614a97565b612414896012614a97565b60405160200161322193929190614ac3565b60408051601f198184030181529190529050600061324f88613244886021614a97565b612414600789614b1c565b6132698961325e896025614a97565b61241460048a614b1c565b6129128a6132788a6030614a97565b6124148a6009614a97565b8051602082015160609190600061329b858484613573565b6132aa86612e19866004614a97565b6132c4876132b987600e614a97565b612414600c88614b1c565b6132d388612c61886023614a97565b6132ed896132e289602d614a97565b612414896015614a97565b6132fc8a612dd68a601e614a97565b604051602001613311969594939291906150eb565b60408051601f198184030181529190529050600061333486612668866011614a97565b61334e8761334387600b614a97565b612414601e88614b1c565b6125f98861335d886002614a97565b612414601d89614b1c565b80516020820151606091906000613380858484613573565b61338f86612a2086600e614a97565b61339e876132b987601c614a97565b6133ad8861335d88600c614a97565b6133c7896133bc89600b614a97565b61241460318a614b1c565b6040516020016126ba95949392919061516a565b606060006133e883613c54565b6133f184613dbf565b604051602001612cc9929190614cb3565b8051602082015160609190600061341a858484613573565b61343486613429866005614a97565b612414600d87614b1c565b61344387612844876012614a97565b60405160200161345593929190614ac3565b60408051601f198184030181529190529050600061348386613478866012614a97565b61241486600b614a97565b613492876129c5876016614a97565b6134a1886128d3886016614a97565b6040516020016134b393929190614ac3565b60408051601f19818403018152919052905060006134d68761255f876017614a97565b6134e5886128d388601a614a97565b6134ff896134f489601b614a97565b61241489600d614a97565b60405160200161351193929190614ac3565b60408051601f198184030181529190529050600061353f88613534886022614a97565b612414886013614a97565b6135598961354e896031614a97565b612414896018614a97565b6129128a6135688a6033614a97565b6124148a601d614a97565b6060808460c00151156135fc576040805160208101909152600081526135d686604001518760e0015187876040516020016112a0949392919060f09490941b6001600160f01b031916845260028401929092526022830152604282015260620190565b6135f46135e482604761219e565b6135ef90601e614a97565b613ecd565b915050613618565b5060408051808201909152600381526203130360ec1b60208201525b61133a613656604051806040016040528060018152602001601960fa1b8152506040518060c001604052806095815260200161552c60959139611d96565b61368060405180604001604052806004815260200163199a5b1b60e21b8152508860a00151611d96565b6136c9604051806040016040528060068152602001653334b63a32b960d11b8152506040518060400160405280600981526020016875726c2823676c6f2960b81b815250611d96565b613711604051806040016040528060078152602001666f70616369747960c81b815250866040516020016136fd91906151d5565b604051602081830303815290604052611d96565b61371b8989613fec565b60405160200161372f95949392919061516a565b604051602081830303815290604052614036565b606061133a61375386868661406e565b6139b1613795604051806040016040528060028152602001611a5960f21b81525060405180604001604052806003815260200162676c6f60e81b815250611d96565b6138486137df6040518060400160405280600c81526020016b39ba322232bb34b0ba34b7b760a11b815250604051806040016040528060018152602001600d60fa1b815250611d96565b613823604051806040016040528060068152602001651c995cdd5b1d60d21b8152506040518060400160405280600481526020016331363ab960e11b815250611d96565b604051602001613834929190614cb3565b6040516020818303038152906040526140ce565b61398c61389361388e6040518060400160405280600281526020016134b760f11b8152506040518060400160405280600481526020016331363ab960e11b815250611d96565b614110565b6138d661388e6040518060400160405280600281526020016134b760f11b8152506040518060400160405280600481526020016331363ab960e11b815250611d96565b61391961388e6040518060400160405280600281526020016134b760f11b8152506040518060400160405280600481526020016331363ab960e11b815250611d96565b61396561388e6040518060400160405280600281526020016134b760f11b8152506040518060400160405280600d81526020016c536f757263654772617068696360981b815250611d96565b6040516020016139789493929190614c5c565b60405160208183030381529060405261414f565b60405160200161399d929190614cb3565b60405160208183030381529060405261418a565b846040516020016139c3929190614cb3565b6040516020818303038152906040526141b5565b80516020820151606091906139ed848383613573565b613a07856139fc85600b614a97565b612414856005614a97565b613a1686612e83866012614a97565b613a3087613a25876016614a97565b612414876007614a97565b613a4a88613a3f886013614a97565b61241488600d614a97565b613a6489613a59896013614a97565b61241460078a614b1c565b613a7e8a613a738a600b614a97565b61241460118b614b1c565b604051602001613a9497969594939291906151fa565b60405160208183030381529060405292505050919050565b8051602082015160609190613ad184613ac684601b614a97565b612414600685614b1c565b613aeb85613ae085601e614a97565b612414600a86614b1c565b613b0586613afa86601f614a97565b612414601487614b1c565b613b148761268287601a614a97565b613b2e88613b23886024614a97565b612414601489614b1c565b613b4889613b3d89602a614a97565b612414601c8a614b1c565b604051602001613a94969594939291906150eb565b8051602082015160609190613b8284613b77846021614a97565b612414600385614b1c565b613b9c85613b91856024614a97565b612414600986614b1c565b613bb686613bab86602d614a97565b612414600f87614b1c565b613bc587612aca876037614a97565b613bd48861324488603c614a97565b613bee89613be3896037614a97565b612414896006614a97565b613c088a613bfd8a6035614a97565b6124148a600e614a97565b613c228b613c178b602c614a97565b6124148b600c614a97565b613c3c8c613c318c602b614a97565b6124148c6017614a97565b604051602001613a949998979695949392919061528c565b80516020820151606091906000613c6c858484613573565b613c8686613c7b86600a614a97565b612414600c87614b1c565b613c958761308b87600d614a97565b613ca488613244886014614a97565b604051602001613cb79493929190614c5c565b60408051601f1981840301815291905290506000613ce586613cda86600d614a97565b612414866004614a97565b613cf48761242887600d614a97565b613d03886124b788600b614a97565b604051602001613d1593929190614ac3565b60408051601f1981840301815291905290506000613d4387613d3887600d614a97565b612414876022614a97565b613d52886129df886001614a97565b613d6c89613d61896003614a97565b612414896026614a97565b604051602001613d7e93929190614ac3565b6040516020818303038152906040529050828282604051602001613da493929190614ac3565b60405160208183030381529060405295505050505050919050565b80516020820151606091906000613de685613ddb85601c614a97565b612414601086614b1c565b613e0086613df586601d614a97565b612414600687614b1c565b613e0f876127cf876026614a97565b604051602001613e2193929190614ac3565b60408051601f1981840301815291905290506000613e448661240986601c614a97565b613e538761304c87601e614a97565b613e628861257988601e614a97565b604051602001613e7493929190614ac3565b60408051601f1981840301815291905290506000613ea287613e97876019614a97565b612414876023614a97565b613ebc88613eb1886028614a97565b612414886020614a97565b604051602001613d7e929190614cb3565b606081600003613ef45750506040805180820190915260018152600360fc1b602082015290565b8160005b8115613f1b57613f0781614aaa565b9050613f14600a83614f75565b9150613ef8565b6000816001600160401b03811115613f3557613f35614574565b6040519080825280601f01601f191660200182016040528015613f5f576020820181803683370190505b509050815b8515610e5a57613f75600182614b1c565b90506000613f84600a88614f75565b613f8f90600a614f89565b613f999088614b1c565b613fa490603061534d565b905060008160f81b905080848481518110613fc157613fc1614b06565b60200101906001600160f81b031916908160001a905350613fe3600a89614f75565b97505050613f64565b6060611e22604051806040016040528060098152602001687472616e73666f726d60b81b81525061401c85613ecd565b61402585613ecd565b6040516020016136fd929190615366565b606061047e604051806040016040528060048152602001630e0c2e8d60e31b81525083604051806020016040528060008152506123b1565b606061083a604051806040016040528060098152602001687472616e73666f726d60b81b8152506140a28661ffff16613ecd565b6140af8661ffff16613ecd565b6140bc8661ffff16613ecd565b6040516020016136fd939291906153d2565b606061047e6040518060400160405280600e81526020016d3332a3b0bab9b9b4b0b721363ab960911b81525083604051806020016040528060008152506123b1565b606061047e6040518060400160405280600b81526020016a66654d657267654e6f646560a81b81525083604051806020016040528060008152506123b1565b606061047e6040518060400160405280600781526020016666654d6572676560c81b81525060405180602001604052806000815250846123b1565b6060611e22604051806040016040528060068152602001653334b63a32b960d11b81525084846123b1565b6060611e22604051806040016040528060018152602001606760f81b81525084846123b1565b6001600160a01b038116811461089457600080fd5b6000806040838503121561420357600080fd5b823561420e816141db565b946020939093013593505050565b6001600160e01b03198116811461089457600080fd5b60006020828403121561424457600080fd5b8135611e228161421c565b6000806040838503121561426257600080fd5b50508035926020909101359150565b60005b8381101561428c578181015183820152602001614274565b50506000910152565b600081518084526142ad816020860160208601614271565b601f01601f19169290920160200192915050565b602081526000611e226020830184614295565b6000602082840312156142e657600080fd5b5035919050565b6000806000806080858703121561430357600080fd5b843593506020850135925060408501356001600160401b0381111561432757600080fd5b8501610120818803121561433a57600080fd5b9396929550929360600135925050565b60008083601f84011261435c57600080fd5b5081356001600160401b0381111561437357600080fd5b6020830191508360208260051b850101111561438e57600080fd5b9250929050565b60008083601f8401126143a757600080fd5b5081356001600160401b038111156143be57600080fd5b60208301915083602082850101111561438e57600080fd5b60008060008060008060008060a0898b0312156143f257600080fd5b88356143fd816141db565b9750602089013561440d816141db565b965060408901356001600160401b038082111561442957600080fd5b6144358c838d0161434a565b909850965060608b013591508082111561444e57600080fd5b61445a8c838d0161434a565b909650945060808b013591508082111561447357600080fd5b506144808b828c01614395565b999c989b5096995094979396929594505050565b600080600080604085870312156144aa57600080fd5b84356001600160401b03808211156144c157600080fd5b6144cd8883890161434a565b909650945060208701359150808211156144e657600080fd5b506144f38782880161434a565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b818110156145375783518352928401929184019160010161451b565b50909695505050505050565b60006020828403121561455557600080fd5b8135611e22816141db565b80356010811061456f57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156145ac576145ac614574565b60405290565b60405161012081016001600160401b03811182821017156145ac576145ac614574565b600082601f8301126145e657600080fd5b81356001600160401b038082111561460057614600614574565b604051601f8301601f19908116603f0116810190828211818310171561462857614628614574565b8160405283815286602085880101111561464157600080fd5b836020870160208301376000602085830101528094505050505092915050565b803561ffff8116811461456f57600080fd5b803560ff8116811461456f57600080fd5b600060e0828403121561469657600080fd5b61469e61458a565b905081356001600160401b03808211156146b757600080fd5b6146c3858386016145d5565b83526146d160208501614661565b602084015260408401359150808211156146ea57600080fd5b6146f6858386016145d5565b604084015261470760608501614673565b6060840152608084013591508082111561472057600080fd5b61472c858386016145d5565b608084015261473d60a08501614673565b60a084015260c084013591508082111561475657600080fd5b50614763848285016145d5565b60c08301525092915050565b6000610120828403121561478257600080fd5b61478a6145b2565b905081356001600160401b03808211156147a357600080fd5b6147af85838601614684565b83526147bd60208501614661565b60208401526147ce60408501614661565b60408401526147df60608501614661565b60608401526147f060808501614661565b608084015261480160a08501614661565b60a084015261481260c08501614661565b60c084015261482360e08501614661565b60e08401526101009150818401358181111561483e57600080fd5b61484a868287016145d5565b8385015250505092915050565b60008060006060848603121561486c57600080fd5b61487584614560565b92506020840135915060408401356001600160401b0381111561489757600080fd5b6148a38682870161476f565b9150509250925092565b600080600080608085870312156148c357600080fd5b6148cc85614560565b93506020850135925060408501356001600160401b038111156148ee57600080fd5b6148fa8782880161476f565b949793965093946060013593505050565b6000806040838503121561491e57600080fd5b8235614929816141db565b91506020830135801515811461493e57600080fd5b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b602081016010831061498157634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561499a57600080fd5b82356149a5816141db565b9150602083013561493e816141db565b60008060008060008060a087890312156149ce57600080fd5b86356149d9816141db565b955060208701356149e9816141db565b9450604087013593506060870135925060808701356001600160401b03811115614a1257600080fd5b614a1e89828a01614395565b979a9699509497509295939492505050565b600060208284031215614a4257600080fd5b8151611e22816141db565b605b60f81b815260008251614a69816001850160208701614271565b605d60f81b6001939091019283015250600201919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561047e5761047e614a81565b600060018201614abc57614abc614a81565b5060010190565b60008451614ad5818460208901614271565b845190830190614ae9818360208901614271565b8451910190614afc818360208801614271565b0195945050505050565b634e487b7160e01b600052603260045260246000fd5b8181038181111561047e5761047e614a81565b81835260006001600160fb1b03831115614b4857600080fd5b8260051b80836020870137939093016020019392505050565b604081526000614b75604083018688614b2f565b82810360208401526111eb818587614b2f565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0389811682528816602082015260a060408201819052600090614bde908301888a614b2f565b8281036060840152614bf1818789614b2f565b90508281036080840152614c06818587614b88565b9b9a5050505050505050505050565b600060208284031215614c2757600080fd5b8151611e228161421c565b60208082526010908201526f155394d0519157d49150d2541251539560821b604082015260600190565b60008551614c6e818460208a01614271565b855190830190614c82818360208a01614271565b8551910190614c95818360208901614271565b8451910190614ca8818360208801614271565b019695505050505050565b60008351614cc5818460208801614271565b835190830190614cd9818360208801614271565b01949350505050565b600061047e368361476f565b6001600160a01b03878116825286166020820152604081018590526060810184905260a060808201819052600090612b519083018486614b88565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000815260008251614d6181601a850160208701614271565b91909101601a0192915050565b683d913730b6b2911d1160b91b81528551600090614d93816009850160208b01614271565b701116113232b9b1b934b83a34b7b7111d1160791b6009918401918201528651614dc481601a840160208b01614271565b6e11161130ba3a3934b13aba32b9911d60891b601a92909101918201528551614df4816029840160208a01614271565b69161134b6b0b3b2911d1160b11b602992909101918201528451614e1f816033840160208901614271565b7211161130b734b6b0ba34b7b72fbab936111d1160691b603392909101918201528351614e53816046840160208801614271565b01614e656046820161227d60f01b9052565b604801979650505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251614eab81601d850160208701614271565b91909101601d0192915050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190526000906111eb90830184614295565b60008351614f04818460208801614271565b611e9160f11b9083019081528351614f23816002840160208801614271565b61011160f51b60029290910191820152600401949350505050565b634e487b7160e01b600052601260045260246000fd5b600061ffff80841680614f6957614f69614f3e565b92169190910492915050565b600082614f8457614f84614f3e565b500490565b808202811582820484141761047e5761047e614a81565b6000601160f91b8083528351614fbd816001860160208801614271565b600193019283015250600201919050565b6e3d913a3930b4ba2fba3cb832911d1160891b81528351600090614ff981600f850160208901614271565b691116113b30b63ab2911d60b11b600f918401918201528451615023816019840160208901614271565b607d60f81b60199290910191820152835161504581601a840160208801614271565b01601a0195945050505050565b600f60fa1b81526000855161506e816001850160208a01614271565b600160fd1b600191840191820152855161508f816002840160208a01614271565b808201915050601f60f91b80600283015285516150b3816003850160208a01614271565b613c2f60f01b6003939091019283015284516150d6816005850160208901614271565b60059201918201526006019695505050505050565b6000875160206150fe8285838d01614271565b8851918401916151118184848d01614271565b88519201916151238184848c01614271565b87519201916151358184848b01614271565b86519201916151478184848a01614271565b85519201916151598184848901614271565b919091019998505050505050505050565b6000865161517c818460208b01614271565b865190830190615190818360208b01614271565b86519101906151a3818360208a01614271565b85519101906151b6818360208901614271565b84519101906151c9818360208801614271565b01979650505050505050565b600082516151e7818460208701614271565b602560f81b920191825250600101919050565b60008851602061520d8285838e01614271565b8951918401916152208184848e01614271565b89519201916152328184848d01614271565b88519201916152448184848c01614271565b87519201916152568184848b01614271565b86519201916152688184848a01614271565b855192019161527a8184848901614271565b919091019a9950505050505050505050565b60008a5161529e818460208f01614271565b8a516152b08183860160208f01614271565b8a5191840101906152c5818360208e01614271565b89516152d78183850160208e01614271565b89519290910101906152ed818360208c01614271565b87516152ff8183850160208c01614271565b8751929091010190615315818360208a01614271565b85516153278183850160208a01614271565b855192909101019061533d818360208801614271565b019b9a5050505050505050505050565b60ff818116838216019081111561047e5761047e614a81565b690e8e4c2dce6d8c2e8ca560b31b81526000835161538b81600a850160208801614271565b600b60fa1b600a9184019182015283516153ac81600b840160208801614271565b6c29207363616c6528302e30332960981b600b9290910191820152601801949350505050565b660e4dee8c2e8ca560cb1b8152600084516153f4816007850160208901614271565b8083019050600160fd1b8060078301528551615417816008850160208a01614271565b60089201918201528351615432816009840160208801614271565b602960f81b60099290910191820152600a019594505050505056fe436f6e7374656c6c6174696f6e7320617265206f6e2d636861696e20636f6e7374656c6c6174696f6e204e4654732e20436f6e7374656c6c6174696f6e7320617265206f6e2d636861696e20617274206f776e6564206279206f6e2d636861696e206172743b20436f6e7374656c6c6174696f6e732061726520616c6c206f776e6564206279204e6f6e2d46756e6769626c65204d6f6f6e204e4654732e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f4d203430203630204c2036332e3531312037322e333631204c2035392e3032312034362e313830204c2037382e3034322032372e363339204c2035312e3735362032332e383230204c2034302030204c2032382e3234342032332e383230204c20312e3935382032372e363339204c2032302e3937392034362e313830204c2031362e3438392037322e333631204c203430203630a2646970667358221220cb31205f063f44ddfaaf4c8b108646d12f926ceeb970f5937f0a9a014acd706e64736f6c63430008110033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.