ETH Price: $3,414.31 (+3.45%)

Token

EtherPlanets (EP)
 

Overview

Max Total Supply

321 EP

Holders

98

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
8 EP
0x2db37b335fc5c61da6b15a6076c4d2bcb1830133
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
Planets

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 10 : Planets.sol
//SPDX-License-Identifier: MIT

// ███████╗████████╗██╗░░██╗███████╗██████╗░  ██████╗░██╗░░░░░░█████╗░███╗░░██╗███████╗████████╗░██████╗
// ██╔════╝╚══██╔══╝██║░░██║██╔════╝██╔══██╗  ██╔══██╗██║░░░░░██╔══██╗████╗░██║██╔════╝╚══██╔══╝██╔════╝
// █████╗░░░░░██║░░░███████║█████╗░░██████╔╝  ██████╔╝██║░░░░░███████║██╔██╗██║█████╗░░░░░██║░░░╚█████╗░
// ██╔══╝░░░░░██║░░░██╔══██║██╔══╝░░██╔══██╗  ██╔═══╝░██║░░░░░██╔══██║██║╚████║██╔══╝░░░░░██║░░░░╚═══██╗
// ███████╗░░░██║░░░██║░░██║███████╗██║░░██║  ██║░░░░░███████╗██║░░██║██║░╚███║███████╗░░░██║░░░██████╔╝
// ╚══════╝░░░╚═╝░░░╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝  ╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝░░╚══╝╚══════╝░░░╚═╝░░░╚═════╝░

pragma solidity ^0.8.18;

import "./PlanetsThumbnail.sol";
import "./Utilities.sol";
import "./interfaces/IPlanets.sol";
import "./interfaces/IPlanetsRenderer.sol";
import "scripty.sol/contracts/scripty/IScriptyBuilder.sol";
import {ERC721A} from "erc721a/contracts/ERC721A.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

contract Planets is ERC721A, Ownable {
  uint256 public immutable deployBlock;
  uint256 public immutable supply;
  address public thumbnailAddress;
  address public rendererAddress;

  uint256 public price;
  bool public isOpen;

  bool public finalized;

  error MintClosed();
  error SoldOut();
  error InsufficientFunds();
  error TokenDoesntExist();
  error RefundFailed();
  error Finalized();

  constructor(
    string memory name,
    string memory symbol,
    uint256 _supply,
    uint256 _price,
    address _thumbnailAddress,
    address _rendererAddress
  ) ERC721A(name, symbol) {
    thumbnailAddress = _thumbnailAddress;
    rendererAddress = _rendererAddress;

    supply = _supply;
    price = _price;

    deployBlock = block.number;
  }

  /**
   * @notice  Airdrops tokens to a list of recipients. Only callable by the contract owner.
   * @param _recipients List of recipients to receive the airdrop.
   * @param _quantity Quantity of tokens to airdrop to each recipient.
   */
  function airdrop(address[] calldata _recipients, uint256 _quantity) external payable onlyOwner {
    if (totalMinted() + _recipients.length * _quantity > supply) revert SoldOut();
    for (uint256 i = 0; i < _recipients.length; i++) {
      _mint(_recipients[i], _quantity);
    }
  }

  /**
   * @notice Mints new tokens for the caller.
   * @param _quantity Quantity of tokens to mint.
   */
  function mint(uint256 _quantity) public payable {
    if (!isOpen) revert MintClosed();
    if (totalMinted() + _quantity > supply) revert SoldOut();
    if (msg.value < price * _quantity) revert InsufficientFunds();

    _mint(msg.sender, _quantity);

    // Refund any extra ETH sent
    if (msg.value > price * _quantity) {
      (bool status, ) = payable(msg.sender).call{value: msg.value - price * _quantity}("");
      if (!status) revert RefundFailed();
    }
  }

  /**
   * @notice Withdraws the contract's balance. Only callable by the contract owner.
   */
  function withdraw() external onlyOwner {
    require(payable(msg.sender).send(address(this).balance));
  }

  /**
   * @notice Update the mint price.
   * @dev Very doubtful this gets used, but good to have
   * @param _price - The new price.
   */
  function setPrice(uint256 _price) external onlyOwner {
    price = _price;
  }

  /**
   * @notice Update thumbnail contract address
   * @param _thumbnailAddress - Address of the thumbnail contract.
   */
  function setThumbnailAddress(address _thumbnailAddress) external onlyOwner {
    if (finalized) revert Finalized();
    thumbnailAddress = _thumbnailAddress;
  }

  /**
   * @notice Update renderer contract address
   * @param _rendererAddress - Address of the renderer contract.
   */
  function setRendererAddress(address _rendererAddress) external onlyOwner {
    if (finalized) revert Finalized();
    rendererAddress = _rendererAddress;
  }

  /**
   * @notice Open or close minting
   * @param _state - Boolean state for being open or closed.
   */
  function setMintStatus(bool _state) external onlyOwner {
    isOpen = _state;
  }

  function finalize() external onlyOwner {
    finalized = true;
  }

  /**
   * @notice Minting starts at token id #1
   * @return Token id to start minting at
   */
  function _startTokenId() internal pure override returns (uint256) {
    return 1;
  }

  /**
   * @notice Retrieve how many tokens have been minted
   * @return Total number of minted tokens
   */
  function totalMinted() public view returns (uint256) {
    return _totalMinted();
  }

  function formatVar(bytes memory _name, uint256 _value) internal pure returns (bytes memory) {
    return abi.encodePacked("var ", _name, "=", utils.uint2str(_value), ";");
  }

  /**
   * @notice Build all the settings into a struct
   * @param _tokenId - Token ID for seed value
   * @return settings - All settings as a struct
   */
  function buildSettings(uint256 _tokenId) public view returns (Settings memory settings) {
    uint256 randomSeed = _tokenId + deployBlock;

    settings.seed = utils.randomRange(randomSeed, "seed", 1, 1000000);
    settings.vars[0] = formatVar("seed", settings.seed);

    settings.planetSize = utils.randomRange(randomSeed, "planetSize", 30, 100);
    settings.vars[1] = formatVar("planetSize", settings.planetSize);

    // 40% gas, 60% rock
    settings.planetType = utils.randomRange(randomSeed, "planetType", 0, 10) < 4 ? PlanetType.GAS : PlanetType.SOLID;
    settings.vars[4] = formatVar("planetType", uint256(settings.planetType));

    // 30% of gaseous planets;
    settings.hasRings = settings.planetType == PlanetType.GAS && utils.randomRange(randomSeed, "hasRings", 0, 10) < 3;
    settings.vars[2] = formatVar("hasRings", settings.hasRings ? 1 : 0);

    {
      // 25% 1 moon, 12% 2 moons, 3% 3 moons
      uint256 observation = utils.randomRange(randomSeed, "numMoons", 0, 100);
      if (observation < 25) settings.numMoons = 1;
      else if (observation < 37) settings.numMoons = 2;
      else if (observation < 40) settings.numMoons = 3;
      else settings.numMoons = 0;
      settings.vars[3] = formatVar("numMoons", settings.numMoons);
    }

    settings.hue = utils.randomRange(randomSeed, "baseHue", 0, 360);
    settings.vars[5] = formatVar("baseHue", settings.hue);

    // If rocky, 30% water
    settings.hasWater = settings.planetType == PlanetType.SOLID && utils.randomRange(randomSeed, "hasWater", 0, 10) < 3;
    settings.vars[6] = formatVar("hasWater", settings.hasWater ? 1 : 0);

    return settings;
  }

  /**
   * @notice Util function to help build traits
   * @param _key - Trait key as string
   * @param _value - Trait value as string
   * @return trait - object as string
   */
  function buildTraitString(string memory _key, string memory _value) internal pure returns (string memory trait) {
    return string.concat('{"trait_type":"', _key, '","value":"', _value, '"}');
  }

  /**
   * @notice Util function to help build traits where value is continuous
   * @param _key - Trait key as string
   * @param _value - Trait value as string
   * @return trait - object as string
   */
  function buildTraitNumber(string memory _key, string memory _value) internal pure returns (string memory trait) {
    return string.concat('{"trait_type":"', _key, '","value":', _value, "}");
  }

  /**
   * @notice Build attributes for metadata
   * @param settings - Track settings struct
   * @return attr - array as a string
   */
  function buildAttributes(Settings memory settings) public pure returns (string memory attr) {
    return
      string.concat(
        '"attributes": [',
        buildTraitNumber("Planet Size", utils.uint2str(settings.planetSize)),
        ",",
        buildTraitString("Has Rings", settings.hasRings ? "Yes" : "No"),
        ",",
        buildTraitString("Has Water", settings.hasWater ? "Yes" : "No"),
        ",",
        buildTraitString("Number of Moons", utils.uint2str(settings.numMoons)),
        ",",
        buildTraitString("Planet Type", settings.planetType == PlanetType.SOLID ? "Rock" : "Gas"),
        ",",
        buildTraitString("Planet Color", utils.getColorName(settings.hue)),
        "]"
      );
  }

  /**
   * @notice Pack and base64 encode JS compatible vars
   * @param settings - Track settings struct
   * @return vars - base64 encoded JS compatible setting variables
   */
  function buildVars(Settings memory settings) public pure returns (bytes memory vars) {
    return
      bytes(
        utils.encode(
          abi.encodePacked(
            settings.vars[0],
            settings.vars[1],
            settings.vars[2],
            settings.vars[3],
            settings.vars[4],
            settings.vars[5],
            settings.vars[6]
          )
        )
      );
  }

  /**
   * @notice Build the metadata including the full render html for the planet
   * @dev This depends on
   *      - https://ethfs.xyz/ [stores code libraries]
   *      - https://github.com/intartnft/scripty.sol [builds rendering html and stores code libraries]
   * @param _tokenId - TokenId to build planet for
   * @return metadata - as string
   */
  function tokenURI(uint256 _tokenId) public view virtual override(ERC721A) returns (string memory metadata) {
    // show nothing if token doesnt exist
    if (!_exists(_tokenId)) revert TokenDoesntExist();

    // Generate all the settings and various objects for the metadata
    Settings memory settings = buildSettings(_tokenId);
    string memory attr = buildAttributes(settings);
    bytes memory vars = buildVars(settings);
    string memory thumbnail = utils.encode(PlanetsThumbnail(thumbnailAddress).buildThumbnail(settings));

    bytes memory animationUri = IPlanetsRenderer(rendererAddress).buildAnimationURI(vars);

    bytes memory json = abi.encodePacked(
      '{"name":"',
      "EtherPlanet #",
      utils.uint2str(_tokenId),
      '", "description":"',
      "Fully on-chain, procedurally generated, 3D planets.",
      '","image":"data:image/svg+xml;base64,',
      thumbnail,
      '","animation_url":"',
      animationUri,
      '",',
      attr,
      "}"
    );

    return string(abi.encodePacked("data:application/json,", json));
  }
}

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

pragma solidity ^0.8.0;

import "../utils/Context.sol";

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

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

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

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

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

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

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions 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 3 of 10 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

File 4 of 10 : IPlanets.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

enum PlanetType {
  GAS,
  SOLID
}

struct Settings {
  uint256 seed;
  uint256 planetSize;
  bool hasRings;
  uint256 numMoons;
  PlanetType planetType;
  uint256 hue;
  bool hasWater;
  bytes[7] vars;
}

File 5 of 10 : IPlanetsRenderer.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

import "scripty.sol/contracts/scripty/IScriptyBuilder.sol";
import "./IPlanets.sol";

interface IPlanetsRenderer {
  function buildAnimationURI(bytes calldata vars) external view returns (bytes memory html);
}

File 6 of 10 : PlanetsThumbnail.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.18;

import "./interfaces/IPlanets.sol";
import "./Utilities.sol";

contract PlanetsThumbnail {
  uint256 private constant CANVAS_SIZE = 500;
  bytes private constant BACKGROUND =
    '<g fill="#fff"><circle cx="50" cy="100" r="2" fill="#fff"/><circle cx="200" cy="150" r="2" fill="#fff"/><circle cx="300" cy="250" r="2" fill="#fff"/><circle cx="400" cy="75" r="2" fill="#fff"/><circle cx="175" cy="200" r="2" fill="#fff"/><circle cx="450" cy="350" r="2" fill="#fff"/><circle cx="125" cy="400" r="2" fill="#fff"/><circle cx="375" cy="300" r="2" fill="#fff"/><circle cx="225" cy="375" r="2" fill="#fff"/><circle cx="75" cy="250" r="2" fill="#fff"/><circle cx="25" cy="25" r="2" fill="#fff"/></g>';
  bytes private constant PLANET =
    '<path class="rings" stroke-width="8.686" d="M149.379 79.264c0-5.756-32.406-10.423-72.38-10.423-39.976 0-72.382 4.667-72.382 10.423"/><ellipse cx="76.713" cy="69.999" class="body" rx="50.088" ry="49.798"/><mask id="a" width="101" height="102" x="26" y="19" maskUnits="userSpaceOnUse" style="mask-type:alpha"><circle cx="76.515" cy="70" r="50" fill="#AC0000" transform="rotate(-33.909 76.515 70)"/></mask><g mask="url(#a)"><path class="water" d="M84.845 48.333c.476-2.063 2.428-8.047 6.428-15.476 3.049-1.905 10.795-3.016 14.287-3.333h14.048l15 25-8.81 24.285h-.714c-.571.572-2.143.556-2.857.477l-9.762-5.477a20.235 20.235 0 0 0-21.192-12.857c-12.952 1.143-9.682-7.936-6.428-12.619ZM34.137 66.904c-3.239-1.333-6.27 2.46-7.381 4.524l-2.858 1.429 2.143 23.095 25.477 20.953c1.587-1.826 5-6.381 5.952-10 1.19-4.524-3.333-7.858-6.905-9.286-3.571-1.429-1.905-8.572-.714-11.429 1.19-2.857-3.334-8.571-8.334-11.428-5-2.858-3.333-6.19-7.38-7.858Z"/><path class="body-sec" d="M72.5 100.5C67 93.5 80 89.5 78 84c1.334-1.167 5.2-4.4 10-8 6-4.5 19.5 0 23 4.5s-.5 11-3.5 20c-2.4 7.2-10 8-13.5 7.5-5.333-.167-17.1-1.9-21.5-7.5ZM44 70.5c0-2-2.6-8.2-13-17l-4.5-2 20-25.5c2.167 1.833 7.3 4.4 10.5 0 4-5.5 10.5.5 13 5.5S61.5 41 70 42s8 1 8 11.5S72.5 57 72.5 65s-9 11-17 11c-6.4 0-10.333-3.667-11.5-5.5Z"/></g><path class="rings" stroke-width="8.686" d="M149.379 78.106c0 5.757-32.406 10.423-72.38 10.423-39.976 0-72.382-4.666-72.382-10.423"/>';

  string[3] private MOONS = [
    '<circle cx="22" cy="171" r="22" fill="#BBBBBB"/>',
    '<circle cx="370" cy="106" r="16" fill="#BBBBBB"/>',
    '<circle cx="30" cy="11" r="11" fill="#BBBBBB"/>'
  ];

  function getPlanet(uint256 planetSize) internal pure returns (string memory) {
    return
      string(
        abi.encodePacked(
          '<g transform-origin="72 60" transform="translate(-26,-20),translate(200,200),scale(',
          utils.uint2floatstr((planetSize * 1e3) / 40, 3),
          ')">',
          PLANET,
          "</g>"
        )
      );
  }

  function getMoons(uint256 numMoons) internal view returns (bytes memory) {
    bytes memory moons = '<g transform="translate(50,170)">';
    for (uint256 i = 0; i < numMoons; i++) {
      moons = abi.encodePacked(moons, MOONS[i]);
    }
    moons = abi.encodePacked(moons, "</g>");
    return moons;
  }

  /**
   * @notice Build the SVG thumbnail
   * @param _settings - Track settings struct
   * @return final svg as bytes
   */
  function buildThumbnail(Settings calldata _settings) external view returns (bytes memory) {
    bytes memory svg = abi.encodePacked(
      '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ',
      utils.uint2str(CANVAS_SIZE),
      " ",
      utils.uint2str(CANVAS_SIZE),
      '" width="500" height="500" fill="none">',
      // "<defs><style>.rings{stroke:",
      // _settings.hasRings ? getHSL(_settings.hue, 100, 15) : "none",
      // ";}.body{fill:",
      // getHSL(_settings.hue, 70, 34),
      // ";}.water{fill:",
      // _settings.planetType == PlanetType.SOLID ? "#2680D9" : "none",
      // ";}</style></defs>",
      "<defs><style>",
      ".rings { stroke: ",
      _settings.hasRings ? utils.getHSL(_settings.hue, 100, 15) : "none",
      "; }",
      ".body { fill: ",
      utils.getHSL(_settings.hue, 60, 40),
      "; }",
      ".body-sec { fill: ",
      _settings.planetType == PlanetType.SOLID ? utils.getHSL((_settings.hue + 5) % 360, 45, 50) : "none",
      "; }",
      ".water { fill: ",
      _settings.hasWater ? "#2680D9" : "none",
      "; }",
      "</style></defs>",
      '<rect x="0" y="0" width="',
      utils.uint2str(CANVAS_SIZE),
      '" height="',
      utils.uint2str(CANVAS_SIZE),
      '" fill="#000000"/>',
      BACKGROUND,
      getPlanet(_settings.planetSize),
      getMoons(_settings.numMoons),
      '<g transform="translate(440,470)"><text x="13" y="0" fill="#fff" font-size="24" font-family="Helvetica">2D</text><text x="13" y="15" fill="#fff" font-size="12" font-family="Helvetica">VIEW</text></g></svg>'
    );

    return svg;
  }
}

File 7 of 10 : Utilities.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.12;

library utils {
  function getColorName(uint256 _hue) public pure returns (string memory) {
    string[12] memory colorNames = [
      "Red",
      "Orange",
      "Yellow",
      "Chartreuse",
      "Green",
      "Spring",
      "Cyan",
      "Azure",
      "Blue",
      "Violet",
      "Magenta",
      "Rose"
    ];

    require(_hue <= 360, "Hue must be between 0 and 360");

    uint256 colorIndex = (_hue * 12) / 360;
    return colorNames[colorIndex];
  }

  function getHSL(uint256 hue, uint256 saturation, uint256 lightness) internal pure returns (string memory) {
    return
      string.concat(
        "hsl(",
        utils.uint2str(hue),
        ", ",
        utils.uint2str(saturation),
        "%, ",
        utils.uint2str(lightness),
        "%)"
      );
  }

  function assemblyKeccak(bytes memory _input) public pure returns (bytes32 x) {
    assembly {
      x := keccak256(add(_input, 0x20), mload(_input))
    }
  }

  function random(string memory input) internal pure returns (uint256) {
    return uint256(assemblyKeccak(abi.encodePacked(input)));
  }

  function randomRange(
    uint256 tokenId,
    string memory keyPrefix,
    uint256 lower,
    uint256 upper
  ) internal pure returns (uint256) {
    uint256 rand = random(string(abi.encodePacked(keyPrefix, uint2str(tokenId))));
    return (rand % (upper - lower + 1)) + lower;
  }

  function min(uint256 a, uint256 b) internal pure returns (uint256) {
    return a < b ? a : b;
  }

  function max(uint256 a, uint256 b) internal pure returns (uint256) {
    return a > b ? a : b;
  }

  function sliceUint(bytes memory bs, uint256 start) internal pure returns (uint256) {
    require(bs.length >= start + 32, "slicing out of range");
    uint256 x;
    assembly {
      x := mload(add(bs, add(0x20, start)))
    }
    return x;
  }

  function int2str(int256 _i) internal pure returns (string memory _uintAsString) {
    if (_i < 0) {
      return string.concat("-", uint2str(uint256(-_i)));
    } else {
      return uint2str(uint256(_i));
    }
  }

  function uint2floatstr(uint256 _i_scaled, uint256 _decimals) internal pure returns (string memory) {
    return string.concat(uint2str(_i_scaled / (10 ** _decimals)), ".", uint2str(_i_scaled % (10 ** _decimals)));
  }

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

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

      let w := not(0) // Tsk.
      // We write the string from rightmost digit to leftmost digit.
      // The following is essentially a do-while loop that also handles the zero case.
      for {
        let temp := value
      } 1 {

      } {
        str := add(str, w) // `sub(str, 1)`.
        // Write the character to the pointer.
        // The ASCII index of the '0' character is 48.
        mstore8(str, add(48, mod(temp, 10)))
        // Keep dividing `temp` until zero.
        temp := div(temp, 10)
        if iszero(temp) {
          break
        }
      }

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

  /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
  /// See: https://datatracker.ietf.org/doc/html/rfc4648
  /// @param fileSafe  Whether to replace '+' with '-' and '/' with '_'.
  /// @param noPadding Whether to strip away the padding.
  function encode(bytes memory data, bool fileSafe, bool noPadding) internal pure returns (string memory result) {
    /// @solidity memory-safe-assembly
    assembly {
      let dataLength := mload(data)

      if dataLength {
        // Multiply by 4/3 rounded up.
        // The `shl(2, ...)` is equivalent to multiplying by 4.
        let encodedLength := shl(2, div(add(dataLength, 2), 3))

        // Set `result` to point to the start of the free memory.
        result := mload(0x40)

        // Store the table into the scratch space.
        // Offsetted by -1 byte so that the `mload` will load the character.
        // We will rewrite the free memory pointer at `0x40` later with
        // the allocated size.
        // The magic constant 0x0230 will translate "-_" + "+/".
        mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
        mstore(0x3f, sub("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0230)))

        // Skip the first slot, which stores the length.
        let ptr := add(result, 0x20)
        let end := add(ptr, encodedLength)

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

        } 1 {

        } {
          data := add(data, 3) // Advance 3 bytes.
          let input := mload(data)

          // Write 4 bytes. Optimized for fewer stack operations.
          mstore8(0, mload(and(shr(18, input), 0x3F)))
          mstore8(1, mload(and(shr(12, input), 0x3F)))
          mstore8(2, mload(and(shr(6, input), 0x3F)))
          mstore8(3, mload(and(input, 0x3F)))
          mstore(ptr, mload(0x00))

          ptr := add(ptr, 4) // Advance 4 bytes.

          if iszero(lt(ptr, end)) {
            break
          }
        }

        // Allocate the memory for the string.
        // Add 31 and mask with `not(31)` to round the
        // free memory pointer up the next multiple of 32.
        mstore(0x40, and(add(end, 31), not(31)))

        // Equivalent to `o = [0, 2, 1][dataLength % 3]`.
        let o := div(2, mod(dataLength, 3))

        // Offset `ptr` and pad with '='. We can simply write over the end.
        mstore(sub(ptr, o), shl(240, 0x3d3d))
        // Set `o` to zero if there is padding.
        o := mul(iszero(iszero(noPadding)), o)
        // Zeroize the slot after the string.
        mstore(sub(ptr, o), 0)
        // Write the length of the string.
        mstore(result, sub(encodedLength, o))
      }
    }
  }

  /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
  /// Equivalent to `encode(data, false, false)`.
  function encode(bytes memory data) internal pure returns (string memory result) {
    result = encode(data, false, false);
  }
}

File 8 of 10 : ERC721A.sol
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import './IERC721A.sol';

/**
 * @dev Interface of ERC721 token receiver.
 */
interface ERC721A__IERC721Receiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

/**
 * @title ERC721A
 *
 * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
 * Non-Fungible Token Standard, including the Metadata extension.
 * Optimized for lower gas during batch mints.
 *
 * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
 * starting from `_startTokenId()`.
 *
 * Assumptions:
 *
 * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
 * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
 */
contract ERC721A is IERC721A {
    // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
    struct TokenApprovalRef {
        address value;
    }

    // =============================================================
    //                           CONSTANTS
    // =============================================================

    // Mask of an entry in packed address data.
    uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;

    // The bit position of `numberMinted` in packed address data.
    uint256 private constant _BITPOS_NUMBER_MINTED = 64;

    // The bit position of `numberBurned` in packed address data.
    uint256 private constant _BITPOS_NUMBER_BURNED = 128;

    // The bit position of `aux` in packed address data.
    uint256 private constant _BITPOS_AUX = 192;

    // Mask of all 256 bits in packed address data except the 64 bits for `aux`.
    uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;

    // The bit position of `startTimestamp` in packed ownership.
    uint256 private constant _BITPOS_START_TIMESTAMP = 160;

    // The bit mask of the `burned` bit in packed ownership.
    uint256 private constant _BITMASK_BURNED = 1 << 224;

    // The bit position of the `nextInitialized` bit in packed ownership.
    uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;

    // The bit mask of the `nextInitialized` bit in packed ownership.
    uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;

    // The bit position of `extraData` in packed ownership.
    uint256 private constant _BITPOS_EXTRA_DATA = 232;

    // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
    uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;

    // The mask of the lower 160 bits for addresses.
    uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;

    // The maximum `quantity` that can be minted with {_mintERC2309}.
    // This limit is to prevent overflows on the address data entries.
    // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
    // is required to cause an overflow, which is unrealistic.
    uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;

    // The `Transfer` event signature is given by:
    // `keccak256(bytes("Transfer(address,address,uint256)"))`.
    bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    // =============================================================
    //                            STORAGE
    // =============================================================

    // The next token ID to be minted.
    uint256 private _currentIndex;

    // The number of tokens burned.
    uint256 private _burnCounter;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to ownership details
    // An empty struct value does not necessarily mean the token is unowned.
    // See {_packedOwnershipOf} implementation for details.
    //
    // Bits Layout:
    // - [0..159]   `addr`
    // - [160..223] `startTimestamp`
    // - [224]      `burned`
    // - [225]      `nextInitialized`
    // - [232..255] `extraData`
    mapping(uint256 => uint256) private _packedOwnerships;

    // Mapping owner address to address data.
    //
    // Bits Layout:
    // - [0..63]    `balance`
    // - [64..127]  `numberMinted`
    // - [128..191] `numberBurned`
    // - [192..255] `aux`
    mapping(address => uint256) private _packedAddressData;

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

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

    // =============================================================
    //                          CONSTRUCTOR
    // =============================================================

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
        _currentIndex = _startTokenId();
    }

    // =============================================================
    //                   TOKEN COUNTING OPERATIONS
    // =============================================================

    /**
     * @dev Returns the starting token ID.
     * To change the starting token ID, please override this function.
     */
    function _startTokenId() internal view virtual returns (uint256) {
        return 0;
    }

    /**
     * @dev Returns the next token ID to be minted.
     */
    function _nextTokenId() internal view virtual returns (uint256) {
        return _currentIndex;
    }

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        // Counter underflow is impossible as _burnCounter cannot be incremented
        // more than `_currentIndex - _startTokenId()` times.
        unchecked {
            return _currentIndex - _burnCounter - _startTokenId();
        }
    }

    /**
     * @dev Returns the total amount of tokens minted in the contract.
     */
    function _totalMinted() internal view virtual returns (uint256) {
        // Counter underflow is impossible as `_currentIndex` does not decrement,
        // and it is initialized to `_startTokenId()`.
        unchecked {
            return _currentIndex - _startTokenId();
        }
    }

    /**
     * @dev Returns the total number of tokens burned.
     */
    function _totalBurned() internal view virtual returns (uint256) {
        return _burnCounter;
    }

    // =============================================================
    //                    ADDRESS DATA OPERATIONS
    // =============================================================

    /**
     * @dev Returns the number of tokens in `owner`'s account.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        if (owner == address(0)) revert BalanceQueryForZeroAddress();
        return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the number of tokens minted by `owner`.
     */
    function _numberMinted(address owner) internal view returns (uint256) {
        return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the number of tokens burned by or on behalf of `owner`.
     */
    function _numberBurned(address owner) internal view returns (uint256) {
        return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
     */
    function _getAux(address owner) internal view returns (uint64) {
        return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
    }

    /**
     * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
     * If there are multiple variables, please pack them into a uint64.
     */
    function _setAux(address owner, uint64 aux) internal virtual {
        uint256 packed = _packedAddressData[owner];
        uint256 auxCasted;
        // Cast `aux` with assembly to avoid redundant masking.
        assembly {
            auxCasted := aux
        }
        packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
        _packedAddressData[owner] = packed;
    }

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        // The interface IDs are constants representing the first 4 bytes
        // of the XOR of all function selectors in the interface.
        // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
        // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
        return
            interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
            interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
            interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
    }

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

    /**
     * @dev Returns the token collection name.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        if (!_exists(tokenId)) revert URIQueryForNonexistentToken();

        string memory baseURI = _baseURI();
        return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
    }

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

    // =============================================================
    //                     OWNERSHIPS OPERATIONS
    // =============================================================

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        return address(uint160(_packedOwnershipOf(tokenId)));
    }

    /**
     * @dev Gas spent here starts off proportional to the maximum mint batch size.
     * It gradually moves to O(1) as tokens get transferred around over time.
     */
    function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
        return _unpackedOwnership(_packedOwnershipOf(tokenId));
    }

    /**
     * @dev Returns the unpacked `TokenOwnership` struct at `index`.
     */
    function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
        return _unpackedOwnership(_packedOwnerships[index]);
    }

    /**
     * @dev Initializes the ownership slot minted at `index` for efficiency purposes.
     */
    function _initializeOwnershipAt(uint256 index) internal virtual {
        if (_packedOwnerships[index] == 0) {
            _packedOwnerships[index] = _packedOwnershipOf(index);
        }
    }

    /**
     * Returns the packed ownership data of `tokenId`.
     */
    function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {
        uint256 curr = tokenId;

        unchecked {
            if (_startTokenId() <= curr)
                if (curr < _currentIndex) {
                    uint256 packed = _packedOwnerships[curr];
                    // If not burned.
                    if (packed & _BITMASK_BURNED == 0) {
                        // Invariant:
                        // There will always be an initialized ownership slot
                        // (i.e. `ownership.addr != address(0) && ownership.burned == false`)
                        // before an unintialized ownership slot
                        // (i.e. `ownership.addr == address(0) && ownership.burned == false`)
                        // Hence, `curr` will not underflow.
                        //
                        // We can directly compare the packed value.
                        // If the address is zero, packed will be zero.
                        while (packed == 0) {
                            packed = _packedOwnerships[--curr];
                        }
                        return packed;
                    }
                }
        }
        revert OwnerQueryForNonexistentToken();
    }

    /**
     * @dev Returns the unpacked `TokenOwnership` struct from `packed`.
     */
    function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
        ownership.addr = address(uint160(packed));
        ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
        ownership.burned = packed & _BITMASK_BURNED != 0;
        ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
    }

    /**
     * @dev Packs ownership data into a single uint256.
     */
    function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
        assembly {
            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
            owner := and(owner, _BITMASK_ADDRESS)
            // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
            result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
        }
    }

    /**
     * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
     */
    function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
        // For branchless setting of the `nextInitialized` flag.
        assembly {
            // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
            result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
        }
    }

    // =============================================================
    //                      APPROVAL OPERATIONS
    // =============================================================

    /**
     * @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) public payable virtual override {
        address owner = ownerOf(tokenId);

        if (_msgSenderERC721A() != owner)
            if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                revert ApprovalCallerNotOwnerNorApproved();
            }

        _tokenApprovals[tokenId].value = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();

        return _tokenApprovals[tokenId].value;
    }

    /**
     * @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) public virtual override {
        _operatorApprovals[_msgSenderERC721A()][operator] = approved;
        emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
    }

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

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted. See {_mint}.
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return
            _startTokenId() <= tokenId &&
            tokenId < _currentIndex && // If within bounds,
            _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
    }

    /**
     * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
     */
    function _isSenderApprovedOrOwner(
        address approvedAddress,
        address owner,
        address msgSender
    ) private pure returns (bool result) {
        assembly {
            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
            owner := and(owner, _BITMASK_ADDRESS)
            // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
            msgSender := and(msgSender, _BITMASK_ADDRESS)
            // `msgSender == owner || msgSender == approvedAddress`.
            result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
        }
    }

    /**
     * @dev Returns the storage slot and value for the approved address of `tokenId`.
     */
    function _getApprovedSlotAndAddress(uint256 tokenId)
        private
        view
        returns (uint256 approvedAddressSlot, address approvedAddress)
    {
        TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
        // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
        assembly {
            approvedAddressSlot := tokenApproval.slot
            approvedAddress := sload(approvedAddressSlot)
        }
    }

    // =============================================================
    //                      TRANSFER OPERATIONS
    // =============================================================

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *
     * 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
    ) public payable virtual override {
        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);

        if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();

        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);

        // The nested ifs save around 20+ gas over a compound boolean condition.
        if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
            if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();

        if (to == address(0)) revert TransferToZeroAddress();

        _beforeTokenTransfers(from, to, tokenId, 1);

        // Clear approvals from the previous owner.
        assembly {
            if approvedAddress {
                // This is equivalent to `delete _tokenApprovals[tokenId]`.
                sstore(approvedAddressSlot, 0)
            }
        }

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
        unchecked {
            // We can directly increment and decrement the balances.
            --_packedAddressData[from]; // Updates: `balance -= 1`.
            ++_packedAddressData[to]; // Updates: `balance += 1`.

            // Updates:
            // - `address` to the next owner.
            // - `startTimestamp` to the timestamp of transfering.
            // - `burned` to `false`.
            // - `nextInitialized` to `true`.
            _packedOwnerships[tokenId] = _packOwnershipData(
                to,
                _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
            );

            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                uint256 nextTokenId = tokenId + 1;
                // If the next slot's address is zero and not burned (i.e. packed value is zero).
                if (_packedOwnerships[nextTokenId] == 0) {
                    // If the next slot is within bounds.
                    if (nextTokenId != _currentIndex) {
                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                    }
                }
            }
        }

        emit Transfer(from, to, tokenId);
        _afterTokenTransfers(from, to, tokenId, 1);
    }

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public payable virtual override {
        safeTransferFrom(from, to, tokenId, '');
    }

    /**
     * @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 memory _data
    ) public payable virtual override {
        transferFrom(from, to, tokenId);
        if (to.code.length != 0)
            if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                revert TransferToNonERC721ReceiverImplementer();
            }
    }

    /**
     * @dev Hook that is called before a set of serially-ordered token IDs
     * are about to be transferred. This includes minting.
     * And also called before burning one token.
     *
     * `startTokenId` - the first token ID to be transferred.
     * `quantity` - the amount to be transferred.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _beforeTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Hook that is called after a set of serially-ordered token IDs
     * have been transferred. This includes minting.
     * And also called after one token has been burned.
     *
     * `startTokenId` - the first token ID to be transferred.
     * `quantity` - the amount to be transferred.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
     * transferred to `to`.
     * - When `from` is zero, `tokenId` has been minted for `to`.
     * - When `to` is zero, `tokenId` has been burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _afterTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
     *
     * `from` - Previous owner of the given token ID.
     * `to` - Target address that will receive the token.
     * `tokenId` - Token ID to be transferred.
     * `_data` - Optional data to send along with the call.
     *
     * Returns whether the call correctly returned the expected magic value.
     */
    function _checkContractOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
            bytes4 retval
        ) {
            return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
        } catch (bytes memory reason) {
            if (reason.length == 0) {
                revert TransferToNonERC721ReceiverImplementer();
            } else {
                assembly {
                    revert(add(32, reason), mload(reason))
                }
            }
        }
    }

    // =============================================================
    //                        MINT OPERATIONS
    // =============================================================

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {Transfer} event for each mint.
     */
    function _mint(address to, uint256 quantity) internal virtual {
        uint256 startTokenId = _currentIndex;
        if (quantity == 0) revert MintZeroQuantity();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are incredibly unrealistic.
        // `balance` and `numberMinted` have a maximum limit of 2**64.
        // `tokenId` has a maximum limit of 2**256.
        unchecked {
            // Updates:
            // - `balance += quantity`.
            // - `numberMinted += quantity`.
            //
            // We can directly add to the `balance` and `numberMinted`.
            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);

            // Updates:
            // - `address` to the owner.
            // - `startTimestamp` to the timestamp of minting.
            // - `burned` to `false`.
            // - `nextInitialized` to `quantity == 1`.
            _packedOwnerships[startTokenId] = _packOwnershipData(
                to,
                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
            );

            uint256 toMasked;
            uint256 end = startTokenId + quantity;

            // Use assembly to loop and emit the `Transfer` event for gas savings.
            // The duplicated `log4` removes an extra check and reduces stack juggling.
            // The assembly, together with the surrounding Solidity code, have been
            // delicately arranged to nudge the compiler into producing optimized opcodes.
            assembly {
                // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
                toMasked := and(to, _BITMASK_ADDRESS)
                // Emit the `Transfer` event.
                log4(
                    0, // Start of data (0, since no data).
                    0, // End of data (0, since no data).
                    _TRANSFER_EVENT_SIGNATURE, // Signature.
                    0, // `address(0)`.
                    toMasked, // `to`.
                    startTokenId // `tokenId`.
                )

                // The `iszero(eq(,))` check ensures that large values of `quantity`
                // that overflows uint256 will make the loop run out of gas.
                // The compiler will optimize the `iszero` away for performance.
                for {
                    let tokenId := add(startTokenId, 1)
                } iszero(eq(tokenId, end)) {
                    tokenId := add(tokenId, 1)
                } {
                    // Emit the `Transfer` event. Similar to above.
                    log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                }
            }
            if (toMasked == 0) revert MintToZeroAddress();

            _currentIndex = end;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * This function is intended for efficient minting only during contract creation.
     *
     * It emits only one {ConsecutiveTransfer} as defined in
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
     * instead of a sequence of {Transfer} event(s).
     *
     * Calling this function outside of contract creation WILL make your contract
     * non-compliant with the ERC721 standard.
     * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
     * {ConsecutiveTransfer} event is only permissible during contract creation.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {ConsecutiveTransfer} event.
     */
    function _mintERC2309(address to, uint256 quantity) internal virtual {
        uint256 startTokenId = _currentIndex;
        if (to == address(0)) revert MintToZeroAddress();
        if (quantity == 0) revert MintZeroQuantity();
        if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are unrealistic due to the above check for `quantity` to be below the limit.
        unchecked {
            // Updates:
            // - `balance += quantity`.
            // - `numberMinted += quantity`.
            //
            // We can directly add to the `balance` and `numberMinted`.
            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);

            // Updates:
            // - `address` to the owner.
            // - `startTimestamp` to the timestamp of minting.
            // - `burned` to `false`.
            // - `nextInitialized` to `quantity == 1`.
            _packedOwnerships[startTokenId] = _packOwnershipData(
                to,
                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
            );

            emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);

            _currentIndex = startTokenId + quantity;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Safely mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement
     * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
     * - `quantity` must be greater than 0.
     *
     * See {_mint}.
     *
     * Emits a {Transfer} event for each mint.
     */
    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal virtual {
        _mint(to, quantity);

        unchecked {
            if (to.code.length != 0) {
                uint256 end = _currentIndex;
                uint256 index = end - quantity;
                do {
                    if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                        revert TransferToNonERC721ReceiverImplementer();
                    }
                } while (index < end);
                // Reentrancy protection.
                if (_currentIndex != end) revert();
            }
        }
    }

    /**
     * @dev Equivalent to `_safeMint(to, quantity, '')`.
     */
    function _safeMint(address to, uint256 quantity) internal virtual {
        _safeMint(to, quantity, '');
    }

    // =============================================================
    //                        BURN OPERATIONS
    // =============================================================

    /**
     * @dev Equivalent to `_burn(tokenId, false)`.
     */
    function _burn(uint256 tokenId) internal virtual {
        _burn(tokenId, false);
    }

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

        address from = address(uint160(prevOwnershipPacked));

        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);

        if (approvalCheck) {
            // The nested ifs save around 20+ gas over a compound boolean condition.
            if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
        }

        _beforeTokenTransfers(from, address(0), tokenId, 1);

        // Clear approvals from the previous owner.
        assembly {
            if approvedAddress {
                // This is equivalent to `delete _tokenApprovals[tokenId]`.
                sstore(approvedAddressSlot, 0)
            }
        }

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
        unchecked {
            // Updates:
            // - `balance -= 1`.
            // - `numberBurned += 1`.
            //
            // We can directly decrement the balance, and increment the number burned.
            // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
            _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;

            // Updates:
            // - `address` to the last owner.
            // - `startTimestamp` to the timestamp of burning.
            // - `burned` to `true`.
            // - `nextInitialized` to `true`.
            _packedOwnerships[tokenId] = _packOwnershipData(
                from,
                (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
            );

            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                uint256 nextTokenId = tokenId + 1;
                // If the next slot's address is zero and not burned (i.e. packed value is zero).
                if (_packedOwnerships[nextTokenId] == 0) {
                    // If the next slot is within bounds.
                    if (nextTokenId != _currentIndex) {
                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                    }
                }
            }
        }

        emit Transfer(from, address(0), tokenId);
        _afterTokenTransfers(from, address(0), tokenId, 1);

        // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
        unchecked {
            _burnCounter++;
        }
    }

    // =============================================================
    //                     EXTRA DATA OPERATIONS
    // =============================================================

    /**
     * @dev Directly sets the extra data for the ownership data `index`.
     */
    function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
        uint256 packed = _packedOwnerships[index];
        if (packed == 0) revert OwnershipNotInitializedForExtraData();
        uint256 extraDataCasted;
        // Cast `extraData` with assembly to avoid redundant masking.
        assembly {
            extraDataCasted := extraData
        }
        packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
        _packedOwnerships[index] = packed;
    }

    /**
     * @dev Called during each token transfer to set the 24bit `extraData` field.
     * Intended to be overridden by the cosumer contract.
     *
     * `previousExtraData` - the value of `extraData` before transfer.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _extraData(
        address from,
        address to,
        uint24 previousExtraData
    ) internal view virtual returns (uint24) {}

    /**
     * @dev Returns the next extra data for the packed ownership data.
     * The returned result is shifted into position.
     */
    function _nextExtraData(
        address from,
        address to,
        uint256 prevOwnershipPacked
    ) private view returns (uint256) {
        uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
        return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
    }

    // =============================================================
    //                       OTHER OPERATIONS
    // =============================================================

    /**
     * @dev Returns the message sender (defaults to `msg.sender`).
     *
     * If you are writing GSN compatible contracts, you need to override this function.
     */
    function _msgSenderERC721A() internal view virtual returns (address) {
        return msg.sender;
    }

    /**
     * @dev Converts a uint256 to its ASCII string decimal representation.
     */
    function _toString(uint256 value) internal pure virtual returns (string memory str) {
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
            // We will need 1 word for the trailing zeros padding, 1 word for the length,
            // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
            let m := add(mload(0x40), 0xa0)
            // Update the free memory pointer to allocate.
            mstore(0x40, m)
            // Assign the `str` to the end.
            str := sub(m, 0x20)
            // Zeroize the slot after the string.
            mstore(str, 0)

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

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

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

File 9 of 10 : IERC721A.sol
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs

pragma solidity ^0.8.4;

/**
 * @dev Interface of ERC721A.
 */
interface IERC721A {
    /**
     * The caller must own the token or be an approved operator.
     */
    error ApprovalCallerNotOwnerNorApproved();

    /**
     * The token does not exist.
     */
    error ApprovalQueryForNonexistentToken();

    /**
     * Cannot query the balance for the zero address.
     */
    error BalanceQueryForZeroAddress();

    /**
     * Cannot mint to the zero address.
     */
    error MintToZeroAddress();

    /**
     * The quantity of tokens minted must be more than zero.
     */
    error MintZeroQuantity();

    /**
     * The token does not exist.
     */
    error OwnerQueryForNonexistentToken();

    /**
     * The caller must own the token or be an approved operator.
     */
    error TransferCallerNotOwnerNorApproved();

    /**
     * The token must be owned by `from`.
     */
    error TransferFromIncorrectOwner();

    /**
     * Cannot safely transfer to a contract that does not implement the
     * ERC721Receiver interface.
     */
    error TransferToNonERC721ReceiverImplementer();

    /**
     * Cannot transfer to the zero address.
     */
    error TransferToZeroAddress();

    /**
     * The token does not exist.
     */
    error URIQueryForNonexistentToken();

    /**
     * The `quantity` minted with ERC2309 exceeds the safety limit.
     */
    error MintERC2309QuantityExceedsLimit();

    /**
     * The `extraData` cannot be set on an unintialized ownership slot.
     */
    error OwnershipNotInitializedForExtraData();

    // =============================================================
    //                            STRUCTS
    // =============================================================

    struct TokenOwnership {
        // The address of the owner.
        address addr;
        // Stores the start time of ownership with minimal overhead for tokenomics.
        uint64 startTimestamp;
        // Whether the token has been burned.
        bool burned;
        // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
        uint24 extraData;
    }

    // =============================================================
    //                         TOKEN COUNTERS
    // =============================================================

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() external view returns (uint256);

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);

    // =============================================================
    //                            IERC721
    // =============================================================

    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

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

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

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

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

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

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external payable;

    /**
     * @dev Transfers `tokenId` 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 payable;

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

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

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

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

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

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

    // =============================================================
    //                           IERC2309
    // =============================================================

    /**
     * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
     * (inclusive) is transferred from `from` to `to`, as defined in the
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
     *
     * See {_mintERC2309} for more details.
     */
    event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}

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

///////////////////////////////////////////////////////////
// ░██████╗░█████╗░██████╗░██╗██████╗░████████╗██╗░░░██╗ //
// ██╔════╝██╔══██╗██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗░██╔╝ //
// ╚█████╗░██║░░╚═╝██████╔╝██║██████╔╝░░░██║░░░░╚████╔╝░ //
// ░╚═══██╗██║░░██╗██╔══██╗██║██╔═══╝░░░░██║░░░░░╚██╔╝░░ //
// ██████╔╝╚█████╔╝██║░░██║██║██║░░░░░░░░██║░░░░░░██║░░░ //
// ╚═════╝░░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░░░░░░░╚═╝░░░░░░╚═╝░░░ //
///////////////////////////////////////////////////////////

// =============================================================
//                            STRUCTS
// =============================================================

struct WrappedScriptRequest {
    string name;
    address contractAddress;
    bytes contractData;
    uint8 wrapType;
    bytes wrapPrefix;
    bytes wrapSuffix;
    bytes scriptContent;
}

struct InlineScriptRequest {
    string name;
    address contractAddress;
    bytes contractData;
    bytes scriptContent;
}

interface IScriptyBuilder {

    // =============================================================
    //                            ERRORS
    // =============================================================

    /**
     * @notice Error for, Invalid length of requests
     */
    error InvalidRequestsLength();

    // =============================================================
    //                      RAW HTML GETTERS
    // =============================================================

    /**
     * @notice Get requested scripts housed in <body> with custom wrappers
     * @dev Your requested scripts are returned in the following format:
     *      <html>
     *          <head></head>
     *          <body style='margin:0;'>
     *              [wrapPrefix[0]]{request[0]}[wrapSuffix[0]]
     *              [wrapPrefix[1]]{request[1]}[wrapSuffix[1]]
     *              ...
     *              [wrapPrefix[n]]{request[n]}[wrapSuffix[n]]
     *          </body>
     *      </html>
     * @param requests - Array of WrappedScriptRequests
     * @param bufferSize - Total buffer size of all requested scripts
     * @return Full html wrapped scripts
     */
    function getHTMLWrapped(
        WrappedScriptRequest[] calldata requests,
        uint256 bufferSize
    ) external view returns (bytes memory);

    /**
     * @notice Get requested scripts housed in URL Safe wrappers
     * @dev Any wrapper type 0 scripts are converted to base64 and wrapped
     *      with <script src="data:text/javascript;base64,[SCRIPT]"></script>
     *
     *      [WARNING]: Large non-base64 libraries that need base64 encoding
     *      carry a high risk of causing a gas out. Highly advised to use
     *      base64 encoded scripts where possible
     *
     *      Your requested scripts are returned in the following format:
     *      <html>
     *          <head></head>
     *          <body style='margin:0;'>
     *              [wrapPrefix[0]]{request[0]}[wrapSuffix[0]]
     *              [wrapPrefix[1]]{request[1]}[wrapSuffix[1]]
     *              ...
     *              [wrapPrefix[n]]{request[n]}[wrapSuffix[n]]
     *          </body>
     *      </html>
     * @param requests - Array of WrappedScriptRequests
     * @param bufferSize - Total buffer size of all requested scripts
     * @return Full URL Safe wrapped scripts
     */
    function getHTMLWrappedURLSafe(
        WrappedScriptRequest[] calldata requests,
        uint256 bufferSize
    ) external view returns (bytes memory);

    /**
     * @notice Get requested scripts housed in <body> all wrapped in <script></script>
     * @dev Your requested scripts are returned in the following format:
     *      <html>
     *          <head></head>
     *          <body style='margin:0;'>
     *              <script>
     *                  {request[0]}
     *                  {request[1]}
     *                  ...
     *                  {request[n]}
     *              </script>
     *          </body>
     *      </html>
     * @param requests - Array of InlineScriptRequest
     * @param bufferSize - Total buffer size of all requested scripts
     * @return Full html wrapped scripts
     */
    function getHTMLInline(
        InlineScriptRequest[] calldata requests,
        uint256 bufferSize
    ) external view returns (bytes memory);

    // =============================================================
    //                      ENCODED HTML GETTERS
    // =============================================================

    /**
     * @notice Get {getHTMLWrapped} and base64 encode it
     * @param requests - Array of WrappedScriptRequests
     * @param bufferSize - Total buffer size of all requested scripts
     * @return Full html wrapped scripts, base64 encoded
     */
    function getEncodedHTMLWrapped(
        WrappedScriptRequest[] calldata requests,
        uint256 bufferSize
    ) external view returns (bytes memory);

    /**
     * @notice Get {getHTMLInline} and base64 encode it
     * @param requests - Array of InlineScriptRequests
     * @param bufferSize - Total buffer size of all requested scripts
     * @return Full html wrapped scripts, base64 encoded
     */
    function getEncodedHTMLInline(
        InlineScriptRequest[] calldata requests,
        uint256 bufferSize
    ) external view returns (bytes memory);

    // =============================================================
    //                      STRING UTILITIES
    // =============================================================

    /**
     * @notice Convert {getHTMLWrapped} output to a string
     * @param requests - Array of WrappedScriptRequests
     * @param bufferSize - Total buffer size of all requested scripts
     * @return {getHTMLWrapped} as a string
     */
    function getHTMLWrappedString(
        WrappedScriptRequest[] calldata requests,
        uint256 bufferSize
    ) external view returns (string memory);

    /**
     * @notice Convert {getHTMLInline} output to a string
     * @param requests - Array of InlineScriptRequests
     * @param bufferSize - Total buffer size of all requested scripts
     * @return {getHTMLInline} as a string
     */
    function getHTMLInlineString(
        InlineScriptRequest[] calldata requests,
        uint256 bufferSize
    ) external view returns (string memory);

    /**
     * @notice Convert {getEncodedHTMLWrapped} output to a string
     * @param requests - Array of WrappedScriptRequests
     * @param bufferSize - Total buffer size of all requested scripts
     *                     before encoding.
     * @return {getEncodedHTMLWrapped} as a string
     */
    function getEncodedHTMLWrappedString(
        WrappedScriptRequest[] calldata requests,
        uint256 bufferSize
    ) external view returns (string memory);

    /**
     * @notice Convert {getEncodedHTMLInline} output to a string
     * @param requests - Array of InlineScriptRequests
     * @param bufferSize - Total buffer size of all requested scripts
     *                     before encoding.
     * @return {getEncodedHTMLInline} as a string
     */
    function getEncodedHTMLInlineString(
        InlineScriptRequest[] calldata requests,
        uint256 bufferSize
    ) external view returns (string memory);

    // =============================================================
    //                      OFF-CHAIN UTILITIES
    // =============================================================

    /**
     * @notice Get the buffer size of a single inline requested code
     * @param request - InlineScriptRequest data for code
     * @return Buffer size as an unit256
     */
    function getInlineScriptSize(InlineScriptRequest memory request)
        external
        view
        returns (uint256);

    /**
     * @notice Get the buffer size of a single wrapped requested code
     * @param request - WrappedScriptRequest data for code
     * @return Buffer size as an unit256
     */
    function getWrappedScriptSize(WrappedScriptRequest memory request)
        external
        view
        returns (uint256);

    /**
     * @notice Get the buffer size of a single wrapped requested code
     * @dev If the script is of wrapper type 0, we get buffer size for
     *      base64 encoded version.
     * @param request - WrappedScriptRequest data for code
     * @return Buffer size as an unit256
     */
    function getURLSafeWrappedScriptSize(WrappedScriptRequest memory request)
    external
    view
    returns (uint256);

    /**
     * @notice Get the buffer size of an array of html wrapped inline scripts
     * @param requests - InlineScriptRequests data for code
     * @return Buffer size as an unit256
     */
    function getBufferSizeForHTMLInline(InlineScriptRequest[] calldata requests)
        external
        view
        returns (uint256);

    /**
     * @notice Get the buffer size of an array of html wrapped, wrapped scripts
     * @param requests - WrappedScriptRequests data for code
     * @return Buffer size as an unit256
     */
    function getBufferSizeForHTMLWrapped(
        WrappedScriptRequest[] calldata requests
    ) external view returns (uint256);

    /**
     * @notice Get the buffer size of an array of URL safe html wrapped scripts
     * @param requests - WrappedScriptRequests data for code
     * @return Buffer size as an unit256
     */
    function getBufferSizeForURLSafeHTMLWrapped(
        WrappedScriptRequest[] calldata requests
    ) external view returns (uint256);
    
    /**
     * @notice Get the buffer size for encoded HTML inline scripts
     * @param requests - InlineScriptRequests data for code
     * @return Buffer size as an unit256
     */
    function getBufferSizeForEncodedHTMLInline(
        InlineScriptRequest[] calldata requests
    ) external view returns (uint256);

    /**
     * @notice Get the buffer size for encoded HTML inline scripts
     * @param requests - InlineScriptRequests data for code
     * @return Buffer size as an unit256
     */
    function getBufferSizeForEncodedHTMLWrapped(
        WrappedScriptRequest[] calldata requests
    ) external view returns (uint256);
}

Settings
{
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {
    "contracts/Utilities.sol": {
      "utils": "0x0e47a2b3de8c3dc9d7f11952164d73a0c1d9d5ac"
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"_supply","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"address","name":"_thumbnailAddress","type":"address"},{"internalType":"address","name":"_rendererAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"Finalized","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"MintClosed","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"RefundFailed","type":"error"},{"inputs":[],"name":"SoldOut","type":"error"},{"inputs":[],"name":"TokenDoesntExist","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address[]","name":"_recipients","type":"address[]"},{"internalType":"uint256","name":"_quantity","type":"uint256"}],"name":"airdrop","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"planetSize","type":"uint256"},{"internalType":"bool","name":"hasRings","type":"bool"},{"internalType":"uint256","name":"numMoons","type":"uint256"},{"internalType":"enum PlanetType","name":"planetType","type":"uint8"},{"internalType":"uint256","name":"hue","type":"uint256"},{"internalType":"bool","name":"hasWater","type":"bool"},{"internalType":"bytes[7]","name":"vars","type":"bytes[7]"}],"internalType":"struct Settings","name":"settings","type":"tuple"}],"name":"buildAttributes","outputs":[{"internalType":"string","name":"attr","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"buildSettings","outputs":[{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"planetSize","type":"uint256"},{"internalType":"bool","name":"hasRings","type":"bool"},{"internalType":"uint256","name":"numMoons","type":"uint256"},{"internalType":"enum PlanetType","name":"planetType","type":"uint8"},{"internalType":"uint256","name":"hue","type":"uint256"},{"internalType":"bool","name":"hasWater","type":"bool"},{"internalType":"bytes[7]","name":"vars","type":"bytes[7]"}],"internalType":"struct Settings","name":"settings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"planetSize","type":"uint256"},{"internalType":"bool","name":"hasRings","type":"bool"},{"internalType":"uint256","name":"numMoons","type":"uint256"},{"internalType":"enum PlanetType","name":"planetType","type":"uint8"},{"internalType":"uint256","name":"hue","type":"uint256"},{"internalType":"bool","name":"hasWater","type":"bool"},{"internalType":"bytes[7]","name":"vars","type":"bytes[7]"}],"internalType":"struct Settings","name":"settings","type":"tuple"}],"name":"buildVars","outputs":[{"internalType":"bytes","name":"vars","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finalized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_quantity","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rendererAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_state","type":"bool"}],"name":"setMintStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rendererAddress","type":"address"}],"name":"setRendererAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_thumbnailAddress","type":"address"}],"name":"setThumbnailAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"thumbnailAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"metadata","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c06040523480156200001157600080fd5b506040516200515338038062005153833981810160405281019062000037919062000444565b858581600290816200004a91906200075f565b5080600390816200005c91906200075f565b506200006d6200013a60201b60201c565b600081905550505062000095620000896200014360201b60201c565b6200014b60201b60201c565b81600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360a0818152505082600b81905550436080818152505050505050505062000846565b60006001905090565b600033905090565b6000600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200027a826200022f565b810181811067ffffffffffffffff821117156200029c576200029b62000240565b5b80604052505050565b6000620002b162000211565b9050620002bf82826200026f565b919050565b600067ffffffffffffffff821115620002e257620002e162000240565b5b620002ed826200022f565b9050602081019050919050565b60005b838110156200031a578082015181840152602081019050620002fd565b60008484015250505050565b60006200033d6200033784620002c4565b620002a5565b9050828152602081018484840111156200035c576200035b6200022a565b5b62000369848285620002fa565b509392505050565b600082601f83011262000389576200038862000225565b5b81516200039b84826020860162000326565b91505092915050565b6000819050919050565b620003b981620003a4565b8114620003c557600080fd5b50565b600081519050620003d981620003ae565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200040c82620003df565b9050919050565b6200041e81620003ff565b81146200042a57600080fd5b50565b6000815190506200043e8162000413565b92915050565b60008060008060008060c087890312156200046457620004636200021b565b5b600087015167ffffffffffffffff81111562000485576200048462000220565b5b6200049389828a0162000371565b965050602087015167ffffffffffffffff811115620004b757620004b662000220565b5b620004c589828a0162000371565b9550506040620004d889828a01620003c8565b9450506060620004eb89828a01620003c8565b9350506080620004fe89828a016200042d565b92505060a06200051189828a016200042d565b9150509295509295509295565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200057157607f821691505b60208210810362000587576200058662000529565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620005f17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620005b2565b620005fd8683620005b2565b95508019841693508086168417925050509392505050565b6000819050919050565b6000620006406200063a6200063484620003a4565b62000615565b620003a4565b9050919050565b6000819050919050565b6200065c836200061f565b620006746200066b8262000647565b848454620005bf565b825550505050565b600090565b6200068b6200067c565b6200069881848462000651565b505050565b5b81811015620006c057620006b460008262000681565b6001810190506200069e565b5050565b601f8211156200070f57620006d9816200058d565b620006e484620005a2565b81016020851015620006f4578190505b6200070c6200070385620005a2565b8301826200069d565b50505b505050565b600082821c905092915050565b6000620007346000198460080262000714565b1980831691505092915050565b60006200074f838362000721565b9150826002028217905092915050565b6200076a826200051e565b67ffffffffffffffff81111562000786576200078562000240565b5b62000792825462000558565b6200079f828285620006c4565b600060209050601f831160018114620007d75760008415620007c2578287015190505b620007ce858262000741565b8655506200083e565b601f198416620007e7866200058d565b60005b828110156200081157848901518255600182019150602085019450602081019050620007ea565b868310156200083157848901516200082d601f89168262000721565b8355505b6001600288020188555050505b505050505050565b60805160a0516148d262000881600039600081816108b401528181611b5f01526120510152600081816113e60152611e0b01526148d26000f3fe60806040526004361061020f5760003560e01c806391b7f5ed11610118578063afbfbaa0116100a0578063c87b56dd1161006f578063c87b56dd14610729578063d67c52eb14610766578063d949bc5f14610791578063e985e9c5146107ba578063f2fde38b146107f75761020f565b8063afbfbaa014610689578063b3f05b97146106c6578063b88d4fde146106f1578063c204642c1461070d5761020f565b8063a0712d68116100e7578063a0712d68146105c5578063a22cb465146105e1578063a2309ff81461060a578063a3ec191a14610635578063a556f60f146106605761020f565b806391b7f5ed1461051b57806395d89b411461054457806399e8fa261461056f578063a035b1fe1461059a5761020f565b806342842e0e1161019b57806366d76b2c1161016a57806366d76b2c1461042257806370a082311461045f578063715018a61461049c5780637607b6db146104b35780638da5cb5b146104f05761020f565b806342842e0e1461038757806347535d7b146103a35780634bb278f3146103ce5780636352211e146103e55761020f565b8063095ea7b3116101e2578063095ea7b3146102e457806318160ddd146103005780631f85e3ca1461032b57806323b872dd146103545780633ccfd60b146103705761020f565b806301ffc9a714610214578063047fc9aa1461025157806306fdde031461027c578063081812fc146102a7575b600080fd5b34801561022057600080fd5b5061023b60048036038101906102369190612f2e565b610820565b6040516102489190612f76565b60405180910390f35b34801561025d57600080fd5b506102666108b2565b6040516102739190612faa565b60405180910390f35b34801561028857600080fd5b506102916108d6565b60405161029e9190613055565b60405180910390f35b3480156102b357600080fd5b506102ce60048036038101906102c991906130a3565b610968565b6040516102db9190613111565b60405180910390f35b6102fe60048036038101906102f99190613158565b6109e7565b005b34801561030c57600080fd5b50610315610b2b565b6040516103229190612faa565b60405180910390f35b34801561033757600080fd5b50610352600480360381019061034d91906131c4565b610b42565b005b61036e600480360381019061036991906131f1565b610b67565b005b34801561037c57600080fd5b50610385610e89565b005b6103a1600480360381019061039c91906131f1565b610ed1565b005b3480156103af57600080fd5b506103b8610ef1565b6040516103c59190612f76565b60405180910390f35b3480156103da57600080fd5b506103e3610f04565b005b3480156103f157600080fd5b5061040c600480360381019061040791906130a3565b610f29565b6040516104199190613111565b60405180910390f35b34801561042e57600080fd5b5061044960048036038101906104449190613562565b610f3b565b6040516104569190613055565b60405180910390f35b34801561046b57600080fd5b50610486600480360381019061048191906135ab565b61130e565b6040516104939190612faa565b60405180910390f35b3480156104a857600080fd5b506104b16113c6565b005b3480156104bf57600080fd5b506104da60048036038101906104d591906130a3565b6113da565b6040516104e79190613828565b60405180910390f35b3480156104fc57600080fd5b50610505611a1d565b6040516105129190613111565b60405180910390f35b34801561052757600080fd5b50610542600480360381019061053d91906130a3565b611a47565b005b34801561055057600080fd5b50610559611a59565b6040516105669190613055565b60405180910390f35b34801561057b57600080fd5b50610584611aeb565b6040516105919190613111565b60405180910390f35b3480156105a657600080fd5b506105af611b11565b6040516105bc9190612faa565b60405180910390f35b6105df60048036038101906105da91906130a3565b611b17565b005b3480156105ed57600080fd5b506106086004803603810190610603919061384a565b611cef565b005b34801561061657600080fd5b5061061f611dfa565b60405161062c9190612faa565b60405180910390f35b34801561064157600080fd5b5061064a611e09565b6040516106579190612faa565b60405180910390f35b34801561066c57600080fd5b50610687600480360381019061068291906135ab565b611e2d565b005b34801561069557600080fd5b506106b060048036038101906106ab9190613562565b611ec0565b6040516106bd91906138d4565b60405180910390f35b3480156106d257600080fd5b506106db611fc1565b6040516106e89190612f76565b60405180910390f35b61070b600480360381019061070691906138f6565b611fd4565b005b610727600480360381019061072291906139d4565b612047565b005b34801561073557600080fd5b50610750600480360381019061074b91906130a3565b612121565b60405161075d9190613055565b60405180910390f35b34801561077257600080fd5b5061077b61233a565b6040516107889190613111565b60405180910390f35b34801561079d57600080fd5b506107b860048036038101906107b391906135ab565b612360565b005b3480156107c657600080fd5b506107e160048036038101906107dc9190613a34565b6123f3565b6040516107ee9190612f76565b60405180910390f35b34801561080357600080fd5b5061081e600480360381019061081991906135ab565b612487565b005b60006301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061087b57506380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108ab5750635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6060600280546108e590613aa3565b80601f016020809104026020016040519081016040528092919081815260200182805461091190613aa3565b801561095e5780601f106109335761010080835404028352916020019161095e565b820191906000526020600020905b81548152906001019060200180831161094157829003601f168201915b5050505050905090565b60006109738261250a565b6109a9576040517fcf4700e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60006109f282610f29565b90508073ffffffffffffffffffffffffffffffffffffffff16610a13612569565b73ffffffffffffffffffffffffffffffffffffffff1614610a7657610a3f81610a3a612569565b6123f3565b610a75576040517fcfb3b94200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b826006600084815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b6000610b35612571565b6001546000540303905090565b610b4a61257a565b80600c60006101000a81548160ff02191690831515021790555050565b6000610b72826125f8565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610bd9576040517fa114810000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080610be5846126c4565b91509150610bfb8187610bf6612569565b6126eb565b610c4757610c1086610c0b612569565b6123f3565b610c46576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610cad576040517fea553b3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cba868686600161272f565b8015610cc557600082555b600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081546001900391905081905550600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815460010191905081905550610d9385610d6f888887612735565b7c02000000000000000000000000000000000000000000000000000000001761275d565b600460008681526020019081526020016000208190555060007c0200000000000000000000000000000000000000000000000000000000841603610e195760006001850190506000600460008381526020019081526020016000205403610e17576000548114610e16578360046000838152602001908152602001600020819055505b5b505b838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4610e818686866001612788565b505050505050565b610e9161257a565b3373ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050610ecf57600080fd5b565b610eec83838360405180602001604052806000815250611fd4565b505050565b600c60009054906101000a900460ff1681565b610f0c61257a565b6001600c60016101000a81548160ff021916908315150217905550565b6000610f34826125f8565b9050919050565b6060610f886040518060400160405280600b81526020017f506c616e65742053697a65000000000000000000000000000000000000000000815250610f83846020015161278e565b6127df565b6110416040518060400160405280600981526020017f4861732052696e677300000000000000000000000000000000000000000000008152508460400151611005576040518060400160405280600281526020017f4e6f00000000000000000000000000000000000000000000000000000000000081525061103c565b6040518060400160405280600381526020017f59657300000000000000000000000000000000000000000000000000000000008152505b61280b565b6110fa6040518060400160405280600981526020017f48617320576174657200000000000000000000000000000000000000000000008152508560c001516110be576040518060400160405280600281526020017f4e6f0000000000000000000000000000000000000000000000000000000000008152506110f5565b6040518060400160405280600381526020017f59657300000000000000000000000000000000000000000000000000000000008152505b61280b565b6111456040518060400160405280600f81526020017f4e756d626572206f66204d6f6f6e730000000000000000000000000000000000815250611140876060015161278e565b61280b565b6112246040518060400160405280600b81526020017f506c616e65742054797065000000000000000000000000000000000000000000815250600180811115611191576111906135f6565b5b886080015160018111156111a8576111a76135f6565b5b146111e8576040518060400160405280600381526020017f476173000000000000000000000000000000000000000000000000000000000081525061121f565b6040518060400160405280600481526020017f526f636b000000000000000000000000000000000000000000000000000000008152505b61280b565b6112e36040518060400160405280600c81526020017f506c616e657420436f6c6f720000000000000000000000000000000000000000815250730e47a2b3de8c3dc9d7f11952164d73a0c1d9d5ac630d56fe878a60a001516040518263ffffffff1660e01b81526004016112989190613ae3565b600060405180830381865af41580156112b5573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906112de9190613b9f565b61280b565b6040516020016112f896959493929190613c96565b6040516020818303038152906040529050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611375576040517f8f4eb60400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054169050919050565b6113ce61257a565b6113d86000612837565b565b6113e2612e3a565b60007f0000000000000000000000000000000000000000000000000000000000000000836114109190613d86565b9050611457816040518060400160405280600481526020017f73656564000000000000000000000000000000000000000000000000000000008152506001620f42406128fd565b8260000181815250506114a36040518060400160405280600481526020017f7365656400000000000000000000000000000000000000000000000000000000815250836000015161296d565b8260e001516000600781106114bb576114ba613dba565b5b6020020181905250611506816040518060400160405280600a81526020017f706c616e657453697a6500000000000000000000000000000000000000000000815250601e60646128fd565b8260200181815250506115526040518060400160405280600a81526020017f706c616e657453697a6500000000000000000000000000000000000000000000815250836020015161296d565b8260e0015160016007811061156a57611569613dba565b5b602002018190525060046115b7826040518060400160405280600a81526020017f706c616e657454797065000000000000000000000000000000000000000000008152506000600a6128fd565b106115c35760016115c6565b60005b826080019060018111156115dd576115dc6135f6565b5b908160018111156115f1576115f06135f6565b5b8152505061164a6040518060400160405280600a81526020017f706c616e6574547970650000000000000000000000000000000000000000000081525083608001516001811115611645576116446135f6565b5b61296d565b8260e0015160046007811061166257611661613dba565b5b60200201819052506000600181111561167e5761167d6135f6565b5b82608001516001811115611695576116946135f6565b5b1480156116e4575060036116e2826040518060400160405280600881526020017f68617352696e67730000000000000000000000000000000000000000000000008152506000600a6128fd565b105b8260400190151590811515815250506117476040518060400160405280600881526020017f68617352696e6773000000000000000000000000000000000000000000000000815250836040015161173c57600061173f565b60015b60ff1661296d565b8260e0015160026007811061175f5761175e613dba565b5b602002018190525060006117ac826040518060400160405280600881526020017f6e756d4d6f6f6e73000000000000000000000000000000000000000000000000815250600060646128fd565b905060198110156117c7576001836060018181525050611807565b60258110156117e0576002836060018181525050611806565b60288110156117f9576003836060018181525050611805565b60008360600181815250505b5b5b61184a6040518060400160405280600881526020017f6e756d4d6f6f6e73000000000000000000000000000000000000000000000000815250846060015161296d565b8360e0015160036007811061186257611861613dba565b5b6020020181905250506118af816040518060400160405280600781526020017f626173654875650000000000000000000000000000000000000000000000000081525060006101686128fd565b8260a00181815250506118fb6040518060400160405280600781526020017f62617365487565000000000000000000000000000000000000000000000000008152508360a0015161296d565b8260e0015160056007811061191357611912613dba565b5b602002018190525060018081111561192e5761192d6135f6565b5b82608001516001811115611945576119446135f6565b5b14801561199457506003611992826040518060400160405280600881526020017f68617357617465720000000000000000000000000000000000000000000000008152506000600a6128fd565b105b8260c00190151590811515815250506119f76040518060400160405280600881526020017f68617357617465720000000000000000000000000000000000000000000000008152508360c001516119ec5760006119ef565b60015b60ff1661296d565b8260e00151600660078110611a0f57611a0e613dba565b5b602002018190525050919050565b6000600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611a4f61257a565b80600b8190555050565b606060038054611a6890613aa3565b80601f0160208091040260200160405190810160405280929190818152602001828054611a9490613aa3565b8015611ae15780601f10611ab657610100808354040283529160200191611ae1565b820191906000526020600020905b815481529060010190602001808311611ac457829003601f168201915b5050505050905090565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600b5481565b600c60009054906101000a900460ff16611b5d576040517f589ed34b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081611b87611dfa565b611b919190613d86565b1115611bc9576040517f52df9fe500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600b54611bd79190613de9565b341015611c10576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c1a33826129a1565b80600b54611c289190613de9565b341115611cec5760003373ffffffffffffffffffffffffffffffffffffffff1682600b54611c569190613de9565b34611c619190613e2b565b604051611c6d90613e90565b60006040518083038185875af1925050503d8060008114611caa576040519150601f19603f3d011682016040523d82523d6000602084013e611caf565b606091505b5050905080611cea576040517ff0c49d4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b50565b8060076000611cfc612569565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16611da9612569565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611dee9190612f76565b60405180910390a35050565b6000611e04612b5c565b905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b611e3561257a565b600c60019054906101000a900460ff1615611e7c576040517f6823b07300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6060611fba8260e00151600060078110611edd57611edc613dba565b5b60200201518360e00151600160078110611efa57611ef9613dba565b5b60200201518460e00151600260078110611f1757611f16613dba565b5b60200201518560e00151600360078110611f3457611f33613dba565b5b60200201518660e00151600460078110611f5157611f50613dba565b5b60200201518760e00151600560078110611f6e57611f6d613dba565b5b60200201518860e00151600660078110611f8b57611f8a613dba565b5b6020020151604051602001611fa69796959493929190613ed6565b604051602081830303815290604052612b6f565b9050919050565b600c60019054906101000a900460ff1681565b611fdf848484610b67565b60008373ffffffffffffffffffffffffffffffffffffffff163b146120415761200a84848484612b84565b612040576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b50505050565b61204f61257a565b7f0000000000000000000000000000000000000000000000000000000000000000818484905061207f9190613de9565b612087611dfa565b6120919190613d86565b11156120c9576040517f52df9fe500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8383905081101561211b576121088484838181106120ed576120ec613dba565b5b905060200201602081019061210291906135ab565b836129a1565b808061211390613f3b565b9150506120cc565b50505050565b606061212c8261250a565b612162576040517feb7d192800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061216d836113da565b9050600061217a82610f3b565b9050600061218783611ec0565b90506000612234600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c7d3625b866040518263ffffffff1660e01b81526004016121e99190613828565b600060405180830381865afa158015612206573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061222f9190613ff3565b612b6f565b90506000600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bf471ba7846040518263ffffffff1660e01b815260040161229391906138d4565b600060405180830381865afa1580156122b0573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906122d99190613ff3565b905060006122e68861278e565b8383876040516020016122fc94939291906142e8565b60405160208183030381529060405290508060405160200161231e91906143ca565b6040516020818303038152906040529650505050505050919050565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61236861257a565b600c60019054906101000a900460ff16156123af576040517f6823b07300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b61248f61257a565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036124fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124f59061445e565b60405180910390fd5b61250781612837565b50565b600081612515612571565b11158015612524575060005482105b8015612562575060007c0100000000000000000000000000000000000000000000000000000000600460008581526020019081526020016000205416145b9050919050565b600033905090565b60006001905090565b612582612cd4565b73ffffffffffffffffffffffffffffffffffffffff166125a0611a1d565b73ffffffffffffffffffffffffffffffffffffffff16146125f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125ed906144ca565b60405180910390fd5b565b60008082905080612607612571565b1161268d5760005481101561268c5760006004600083815260200190815260200160002054905060007c010000000000000000000000000000000000000000000000000000000082160361268a575b60008103612680576004600083600190039350838152602001908152602001600020549050612656565b80925050506126bf565b505b5b6040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b60008060006006600085815260200190815260200160002090508092508254915050915091565b600073ffffffffffffffffffffffffffffffffffffffff8316925073ffffffffffffffffffffffffffffffffffffffff821691508382148383141790509392505050565b50505050565b60008060e883901c905060e861274c868684612cdc565b62ffffff16901b9150509392505050565b600073ffffffffffffffffffffffffffffffffffffffff83169250814260a01b178317905092915050565b50505050565b60606080604051019050602081016040526000815280600019835b6001156127ca578184019350600a81066030018453600a81049050806127a9575b50828203602084039350808452505050919050565b606082826040516020016127f492919061455c565b604051602081830303815290604052905092915050565b606082826040516020016128209291906145f9565b604051602081830303815290604052905092915050565b6000600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000806129328561290d8861278e565b60405160200161291e92919061464a565b604051602081830303815290604052612ce5565b905083600185856129439190613e2b565b61294d9190613d86565b82612958919061469d565b6129629190613d86565b915050949350505050565b6060826129798361278e565b60405160200161298a9291906147b2565b604051602081830303815290604052905092915050565b600080549050600082036129e1576040517fb562e8dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129ee600084838561272f565b600160406001901b178202600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550612a6583612a566000866000612735565b612a5f85612d19565b1761275d565b6004600083815260200190815260200160002081905550600080838301905073ffffffffffffffffffffffffffffffffffffffff85169150828260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600183015b818114612b0657808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600181019050612acb565b5060008203612b41576040517f2e07630000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806000819055505050612b576000848385612788565b505050565b6000612b66612571565b60005403905090565b6060612b7d82600080612d29565b9050919050565b60008373ffffffffffffffffffffffffffffffffffffffff1663150b7a02612baa612569565b8786866040518563ffffffff1660e01b8152600401612bcc94939291906147f7565b6020604051808303816000875af1925050508015612c0857506040513d601f19601f82011682018060405250810190612c059190614858565b60015b612c81573d8060008114612c38576040519150601f19603f3d011682016040523d82523d6000602084013e612c3d565b606091505b506000815103612c79576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050949350505050565b600033905090565b60009392505050565b6000612d0f82604051602001612cfb9190614885565b604051602081830303815290604052612e2a565b60001c9050919050565b60006001821460e11b9050919050565b606083518015612e22576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b600115612def576003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f8116516003536000518352600483019250818310612de95750612def565b50612d99565b601f19601f82011660405260038406600204613d3d60f01b81840352808715150290506000818403528084038652505050505b509392505050565b6000815160208301209050919050565b60405180610100016040528060008152602001600081526020016000151581526020016000815260200160006001811115612e7857612e776135f6565b5b815260200160008152602001600015158152602001612e95612e9b565b81525090565b6040518060e001604052806007905b6060815260200190600190039081612eaa5790505090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612f0b81612ed6565b8114612f1657600080fd5b50565b600081359050612f2881612f02565b92915050565b600060208284031215612f4457612f43612ecc565b5b6000612f5284828501612f19565b91505092915050565b60008115159050919050565b612f7081612f5b565b82525050565b6000602082019050612f8b6000830184612f67565b92915050565b6000819050919050565b612fa481612f91565b82525050565b6000602082019050612fbf6000830184612f9b565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612fff578082015181840152602081019050612fe4565b60008484015250505050565b6000601f19601f8301169050919050565b600061302782612fc5565b6130318185612fd0565b9350613041818560208601612fe1565b61304a8161300b565b840191505092915050565b6000602082019050818103600083015261306f818461301c565b905092915050565b61308081612f91565b811461308b57600080fd5b50565b60008135905061309d81613077565b92915050565b6000602082840312156130b9576130b8612ecc565b5b60006130c78482850161308e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006130fb826130d0565b9050919050565b61310b816130f0565b82525050565b60006020820190506131266000830184613102565b92915050565b613135816130f0565b811461314057600080fd5b50565b6000813590506131528161312c565b92915050565b6000806040838503121561316f5761316e612ecc565b5b600061317d85828601613143565b925050602061318e8582860161308e565b9150509250929050565b6131a181612f5b565b81146131ac57600080fd5b50565b6000813590506131be81613198565b92915050565b6000602082840312156131da576131d9612ecc565b5b60006131e8848285016131af565b91505092915050565b60008060006060848603121561320a57613209612ecc565b5b600061321886828701613143565b935050602061322986828701613143565b925050604061323a8682870161308e565b9150509250925092565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6132818261300b565b810181811067ffffffffffffffff821117156132a05761329f613249565b5b80604052505050565b60006132b3612ec2565b90506132bf8282613278565b919050565b600080fd5b600281106132d657600080fd5b50565b6000813590506132e8816132c9565b92915050565b600080fd5b600067ffffffffffffffff82111561330e5761330d613249565b5b602082029050919050565b600080fd5b600080fd5b600067ffffffffffffffff82111561333e5761333d613249565b5b6133478261300b565b9050602081019050919050565b82818337600083830152505050565b600061337661337184613323565b6132a9565b9050828152602081018484840111156133925761339161331e565b5b61339d848285613354565b509392505050565b600082601f8301126133ba576133b96132ee565b5b81356133ca848260208601613363565b91505092915050565b60006133e66133e1846132f3565b6132a9565b90508060208402830185811115613400576133ff613319565b5b835b8181101561344757803567ffffffffffffffff811115613425576134246132ee565b5b80860161343289826133a5565b85526020850194505050602081019050613402565b5050509392505050565b600082601f830112613466576134656132ee565b5b60076134738482856133d3565b91505092915050565b6000610100828403121561349357613492613244565b5b61349e6101006132a9565b905060006134ae8482850161308e565b60008301525060206134c28482850161308e565b60208301525060406134d6848285016131af565b60408301525060606134ea8482850161308e565b60608301525060806134fe848285016132d9565b60808301525060a06135128482850161308e565b60a08301525060c0613526848285016131af565b60c08301525060e082013567ffffffffffffffff81111561354a576135496132c4565b5b61355684828501613451565b60e08301525092915050565b60006020828403121561357857613577612ecc565b5b600082013567ffffffffffffffff81111561359657613595612ed1565b5b6135a28482850161347c565b91505092915050565b6000602082840312156135c1576135c0612ecc565b5b60006135cf84828501613143565b91505092915050565b6135e181612f91565b82525050565b6135f081612f5b565b82525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60028110613636576136356135f6565b5b50565b600081905061364782613625565b919050565b600061365782613639565b9050919050565b6136678161364c565b82525050565b600060079050919050565b600081905092915050565b6000819050919050565b600081519050919050565b600082825260208201905092915050565b60006136b48261368d565b6136be8185613698565b93506136ce818560208601612fe1565b6136d78161300b565b840191505092915050565b60006136ee83836136a9565b905092915050565b6000602082019050919050565b600061370e8261366d565b6137188185613678565b93508360208202850161372a85613683565b8060005b85811015613766578484038952815161374785826136e2565b9450613752836136f6565b925060208a0199505060018101905061372e565b50829750879550505050505092915050565b60006101008301600083015161379160008601826135d8565b5060208301516137a460208601826135d8565b5060408301516137b760408601826135e7565b5060608301516137ca60608601826135d8565b5060808301516137dd608086018261365e565b5060a08301516137f060a08601826135d8565b5060c083015161380360c08601826135e7565b5060e083015184820360e086015261381b8282613703565b9150508091505092915050565b600060208201905081810360008301526138428184613778565b905092915050565b6000806040838503121561386157613860612ecc565b5b600061386f85828601613143565b9250506020613880858286016131af565b9150509250929050565b600082825260208201905092915050565b60006138a68261368d565b6138b0818561388a565b93506138c0818560208601612fe1565b6138c98161300b565b840191505092915050565b600060208201905081810360008301526138ee818461389b565b905092915050565b600080600080608085870312156139105761390f612ecc565b5b600061391e87828801613143565b945050602061392f87828801613143565b93505060406139408782880161308e565b925050606085013567ffffffffffffffff81111561396157613960612ed1565b5b61396d878288016133a5565b91505092959194509250565b600080fd5b60008083601f840112613994576139936132ee565b5b8235905067ffffffffffffffff8111156139b1576139b0613979565b5b6020830191508360208202830111156139cd576139cc613319565b5b9250929050565b6000806000604084860312156139ed576139ec612ecc565b5b600084013567ffffffffffffffff811115613a0b57613a0a612ed1565b5b613a178682870161397e565b93509350506020613a2a8682870161308e565b9150509250925092565b60008060408385031215613a4b57613a4a612ecc565b5b6000613a5985828601613143565b9250506020613a6a85828601613143565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680613abb57607f821691505b602082108103613ace57613acd613a74565b5b50919050565b613add81612f91565b82525050565b6000602082019050613af86000830184613ad4565b92915050565b600067ffffffffffffffff821115613b1957613b18613249565b5b613b228261300b565b9050602081019050919050565b6000613b42613b3d84613afe565b6132a9565b905082815260208101848484011115613b5e57613b5d61331e565b5b613b69848285612fe1565b509392505050565b600082601f830112613b8657613b856132ee565b5b8151613b96848260208601613b2f565b91505092915050565b600060208284031215613bb557613bb4612ecc565b5b600082015167ffffffffffffffff811115613bd357613bd2612ed1565b5b613bdf84828501613b71565b91505092915050565b7f2261747472696275746573223a205b0000000000000000000000000000000000815250565b600081905092915050565b6000613c2482612fc5565b613c2e8185613c0e565b9350613c3e818560208601612fe1565b80840191505092915050565b7f2c00000000000000000000000000000000000000000000000000000000000000815250565b7f5d00000000000000000000000000000000000000000000000000000000000000815250565b6000613ca182613be8565b600f82019150613cb18289613c19565b9150613cbc82613c4a565b600182019150613ccc8288613c19565b9150613cd782613c4a565b600182019150613ce78287613c19565b9150613cf282613c4a565b600182019150613d028286613c19565b9150613d0d82613c4a565b600182019150613d1d8285613c19565b9150613d2882613c4a565b600182019150613d388284613c19565b9150613d4382613c70565b600182019150819050979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000613d9182612f91565b9150613d9c83612f91565b9250828201905080821115613db457613db3613d57565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000613df482612f91565b9150613dff83612f91565b9250828202613e0d81612f91565b91508282048414831517613e2457613e23613d57565b5b5092915050565b6000613e3682612f91565b9150613e4183612f91565b9250828203905081811115613e5957613e58613d57565b5b92915050565b600081905092915050565b50565b6000613e7a600083613e5f565b9150613e8582613e6a565b600082019050919050565b6000613e9b82613e6d565b9150819050919050565b6000613eb08261368d565b613eba8185613e5f565b9350613eca818560208601612fe1565b80840191505092915050565b6000613ee2828a613ea5565b9150613eee8289613ea5565b9150613efa8288613ea5565b9150613f068287613ea5565b9150613f128286613ea5565b9150613f1e8285613ea5565b9150613f2a8284613ea5565b915081905098975050505050505050565b6000613f4682612f91565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f7857613f77613d57565b5b600182019050919050565b6000613f96613f9184613323565b6132a9565b905082815260208101848484011115613fb257613fb161331e565b5b613fbd848285612fe1565b509392505050565b600082601f830112613fda57613fd96132ee565b5b8151613fea848260208601613f83565b91505092915050565b60006020828403121561400957614008612ecc565b5b600082015167ffffffffffffffff81111561402757614026612ed1565b5b61403384828501613fc5565b91505092915050565b7f7b226e616d65223a220000000000000000000000000000000000000000000000600082015250565b6000614072600983613c0e565b915061407d8261403c565b600982019050919050565b7f4574686572506c616e6574202300000000000000000000000000000000000000600082015250565b60006140be600d83613c0e565b91506140c982614088565b600d82019050919050565b7f222c20226465736372697074696f6e223a220000000000000000000000000000600082015250565b600061410a601283613c0e565b9150614115826140d4565b601282019050919050565b7f46756c6c79206f6e2d636861696e2c2070726f6365647572616c6c792067656e60008201527f6572617465642c20334420706c616e6574732e00000000000000000000000000602082015250565b600061417c603383613c0e565b915061418782614120565b603382019050919050565b7f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b626160008201527f736536342c000000000000000000000000000000000000000000000000000000602082015250565b60006141ee602583613c0e565b91506141f982614192565b602582019050919050565b7f222c22616e696d6174696f6e5f75726c223a2200000000000000000000000000600082015250565b600061423a601383613c0e565b915061424582614204565b601382019050919050565b7f222c000000000000000000000000000000000000000000000000000000000000600082015250565b6000614286600283613c0e565b915061429182614250565b600282019050919050565b7f7d00000000000000000000000000000000000000000000000000000000000000600082015250565b60006142d2600183613c0e565b91506142dd8261429c565b600182019050919050565b60006142f382614065565b91506142fe826140b1565b915061430a8287613c19565b9150614315826140fd565b91506143208261416f565b915061432b826141e1565b91506143378286613c19565b91506143428261422d565b915061434e8285613ea5565b915061435982614279565b91506143658284613c19565b9150614370826142c5565b915081905095945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e2c00000000000000000000600082015250565b60006143b4601683613c0e565b91506143bf8261437e565b601682019050919050565b60006143d5826143a7565b91506143e18284613ea5565b915081905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000614448602683612fd0565b9150614453826143ec565b604082019050919050565b600060208201905081810360008301526144778161443b565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006144b4602083612fd0565b91506144bf8261447e565b602082019050919050565b600060208201905081810360008301526144e3816144a7565b9050919050565b7f7b2274726169745f74797065223a220000000000000000000000000000000000815250565b7f222c2276616c7565223a00000000000000000000000000000000000000000000815250565b7f7d00000000000000000000000000000000000000000000000000000000000000815250565b6000614567826144ea565b600f820191506145778285613c19565b915061458282614510565b600a820191506145928284613c19565b915061459d82614536565b6001820191508190509392505050565b7f222c2276616c7565223a22000000000000000000000000000000000000000000815250565b7f227d000000000000000000000000000000000000000000000000000000000000815250565b6000614604826144ea565b600f820191506146148285613c19565b915061461f826145ad565b600b8201915061462f8284613c19565b915061463a826145d3565b6002820191508190509392505050565b60006146568285613c19565b91506146628284613c19565b91508190509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006146a882612f91565b91506146b383612f91565b9250826146c3576146c261466e565b5b828206905092915050565b7f7661722000000000000000000000000000000000000000000000000000000000600082015250565b6000614704600483613c0e565b915061470f826146ce565b600482019050919050565b7f3d00000000000000000000000000000000000000000000000000000000000000600082015250565b6000614750600183613c0e565b915061475b8261471a565b600182019050919050565b7f3b00000000000000000000000000000000000000000000000000000000000000600082015250565b600061479c600183613c0e565b91506147a782614766565b600182019050919050565b60006147bd826146f7565b91506147c98285613ea5565b91506147d482614743565b91506147e08284613c19565b91506147eb8261478f565b91508190509392505050565b600060808201905061480c6000830187613102565b6148196020830186613102565b6148266040830185612f9b565b8181036060830152614838818461389b565b905095945050505050565b60008151905061485281612f02565b92915050565b60006020828403121561486e5761486d612ecc565b5b600061487c84828501614843565b91505092915050565b60006148918284613c19565b91508190509291505056fea264697066735822122086b5c7449e29e8de509c70ef7a3f2fac4937ae0790460649313afd14a874a0b564736f6c6343000812003300000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001092000000000000000000000000000000000000000000000000000eebe0b40e800000000000000000000000000007e12f3f0bfceee2b92b68ed485e85b896761c7500000000000000000000000016ec9b5a0aef45ca3642000df11f0b2c42bdac45000000000000000000000000000000000000000000000000000000000000000c4574686572506c616e657473000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024550000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x60806040526004361061020f5760003560e01c806391b7f5ed11610118578063afbfbaa0116100a0578063c87b56dd1161006f578063c87b56dd14610729578063d67c52eb14610766578063d949bc5f14610791578063e985e9c5146107ba578063f2fde38b146107f75761020f565b8063afbfbaa014610689578063b3f05b97146106c6578063b88d4fde146106f1578063c204642c1461070d5761020f565b8063a0712d68116100e7578063a0712d68146105c5578063a22cb465146105e1578063a2309ff81461060a578063a3ec191a14610635578063a556f60f146106605761020f565b806391b7f5ed1461051b57806395d89b411461054457806399e8fa261461056f578063a035b1fe1461059a5761020f565b806342842e0e1161019b57806366d76b2c1161016a57806366d76b2c1461042257806370a082311461045f578063715018a61461049c5780637607b6db146104b35780638da5cb5b146104f05761020f565b806342842e0e1461038757806347535d7b146103a35780634bb278f3146103ce5780636352211e146103e55761020f565b8063095ea7b3116101e2578063095ea7b3146102e457806318160ddd146103005780631f85e3ca1461032b57806323b872dd146103545780633ccfd60b146103705761020f565b806301ffc9a714610214578063047fc9aa1461025157806306fdde031461027c578063081812fc146102a7575b600080fd5b34801561022057600080fd5b5061023b60048036038101906102369190612f2e565b610820565b6040516102489190612f76565b60405180910390f35b34801561025d57600080fd5b506102666108b2565b6040516102739190612faa565b60405180910390f35b34801561028857600080fd5b506102916108d6565b60405161029e9190613055565b60405180910390f35b3480156102b357600080fd5b506102ce60048036038101906102c991906130a3565b610968565b6040516102db9190613111565b60405180910390f35b6102fe60048036038101906102f99190613158565b6109e7565b005b34801561030c57600080fd5b50610315610b2b565b6040516103229190612faa565b60405180910390f35b34801561033757600080fd5b50610352600480360381019061034d91906131c4565b610b42565b005b61036e600480360381019061036991906131f1565b610b67565b005b34801561037c57600080fd5b50610385610e89565b005b6103a1600480360381019061039c91906131f1565b610ed1565b005b3480156103af57600080fd5b506103b8610ef1565b6040516103c59190612f76565b60405180910390f35b3480156103da57600080fd5b506103e3610f04565b005b3480156103f157600080fd5b5061040c600480360381019061040791906130a3565b610f29565b6040516104199190613111565b60405180910390f35b34801561042e57600080fd5b5061044960048036038101906104449190613562565b610f3b565b6040516104569190613055565b60405180910390f35b34801561046b57600080fd5b50610486600480360381019061048191906135ab565b61130e565b6040516104939190612faa565b60405180910390f35b3480156104a857600080fd5b506104b16113c6565b005b3480156104bf57600080fd5b506104da60048036038101906104d591906130a3565b6113da565b6040516104e79190613828565b60405180910390f35b3480156104fc57600080fd5b50610505611a1d565b6040516105129190613111565b60405180910390f35b34801561052757600080fd5b50610542600480360381019061053d91906130a3565b611a47565b005b34801561055057600080fd5b50610559611a59565b6040516105669190613055565b60405180910390f35b34801561057b57600080fd5b50610584611aeb565b6040516105919190613111565b60405180910390f35b3480156105a657600080fd5b506105af611b11565b6040516105bc9190612faa565b60405180910390f35b6105df60048036038101906105da91906130a3565b611b17565b005b3480156105ed57600080fd5b506106086004803603810190610603919061384a565b611cef565b005b34801561061657600080fd5b5061061f611dfa565b60405161062c9190612faa565b60405180910390f35b34801561064157600080fd5b5061064a611e09565b6040516106579190612faa565b60405180910390f35b34801561066c57600080fd5b50610687600480360381019061068291906135ab565b611e2d565b005b34801561069557600080fd5b506106b060048036038101906106ab9190613562565b611ec0565b6040516106bd91906138d4565b60405180910390f35b3480156106d257600080fd5b506106db611fc1565b6040516106e89190612f76565b60405180910390f35b61070b600480360381019061070691906138f6565b611fd4565b005b610727600480360381019061072291906139d4565b612047565b005b34801561073557600080fd5b50610750600480360381019061074b91906130a3565b612121565b60405161075d9190613055565b60405180910390f35b34801561077257600080fd5b5061077b61233a565b6040516107889190613111565b60405180910390f35b34801561079d57600080fd5b506107b860048036038101906107b391906135ab565b612360565b005b3480156107c657600080fd5b506107e160048036038101906107dc9190613a34565b6123f3565b6040516107ee9190612f76565b60405180910390f35b34801561080357600080fd5b5061081e600480360381019061081991906135ab565b612487565b005b60006301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061087b57506380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108ab5750635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b7f000000000000000000000000000000000000000000000000000000000000109281565b6060600280546108e590613aa3565b80601f016020809104026020016040519081016040528092919081815260200182805461091190613aa3565b801561095e5780601f106109335761010080835404028352916020019161095e565b820191906000526020600020905b81548152906001019060200180831161094157829003601f168201915b5050505050905090565b60006109738261250a565b6109a9576040517fcf4700e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60006109f282610f29565b90508073ffffffffffffffffffffffffffffffffffffffff16610a13612569565b73ffffffffffffffffffffffffffffffffffffffff1614610a7657610a3f81610a3a612569565b6123f3565b610a75576040517fcfb3b94200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b826006600084815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b6000610b35612571565b6001546000540303905090565b610b4a61257a565b80600c60006101000a81548160ff02191690831515021790555050565b6000610b72826125f8565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610bd9576040517fa114810000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080610be5846126c4565b91509150610bfb8187610bf6612569565b6126eb565b610c4757610c1086610c0b612569565b6123f3565b610c46576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610cad576040517fea553b3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cba868686600161272f565b8015610cc557600082555b600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081546001900391905081905550600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815460010191905081905550610d9385610d6f888887612735565b7c02000000000000000000000000000000000000000000000000000000001761275d565b600460008681526020019081526020016000208190555060007c0200000000000000000000000000000000000000000000000000000000841603610e195760006001850190506000600460008381526020019081526020016000205403610e17576000548114610e16578360046000838152602001908152602001600020819055505b5b505b838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4610e818686866001612788565b505050505050565b610e9161257a565b3373ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050610ecf57600080fd5b565b610eec83838360405180602001604052806000815250611fd4565b505050565b600c60009054906101000a900460ff1681565b610f0c61257a565b6001600c60016101000a81548160ff021916908315150217905550565b6000610f34826125f8565b9050919050565b6060610f886040518060400160405280600b81526020017f506c616e65742053697a65000000000000000000000000000000000000000000815250610f83846020015161278e565b6127df565b6110416040518060400160405280600981526020017f4861732052696e677300000000000000000000000000000000000000000000008152508460400151611005576040518060400160405280600281526020017f4e6f00000000000000000000000000000000000000000000000000000000000081525061103c565b6040518060400160405280600381526020017f59657300000000000000000000000000000000000000000000000000000000008152505b61280b565b6110fa6040518060400160405280600981526020017f48617320576174657200000000000000000000000000000000000000000000008152508560c001516110be576040518060400160405280600281526020017f4e6f0000000000000000000000000000000000000000000000000000000000008152506110f5565b6040518060400160405280600381526020017f59657300000000000000000000000000000000000000000000000000000000008152505b61280b565b6111456040518060400160405280600f81526020017f4e756d626572206f66204d6f6f6e730000000000000000000000000000000000815250611140876060015161278e565b61280b565b6112246040518060400160405280600b81526020017f506c616e65742054797065000000000000000000000000000000000000000000815250600180811115611191576111906135f6565b5b886080015160018111156111a8576111a76135f6565b5b146111e8576040518060400160405280600381526020017f476173000000000000000000000000000000000000000000000000000000000081525061121f565b6040518060400160405280600481526020017f526f636b000000000000000000000000000000000000000000000000000000008152505b61280b565b6112e36040518060400160405280600c81526020017f506c616e657420436f6c6f720000000000000000000000000000000000000000815250730e47a2b3de8c3dc9d7f11952164d73a0c1d9d5ac630d56fe878a60a001516040518263ffffffff1660e01b81526004016112989190613ae3565b600060405180830381865af41580156112b5573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906112de9190613b9f565b61280b565b6040516020016112f896959493929190613c96565b6040516020818303038152906040529050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611375576040517f8f4eb60400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054169050919050565b6113ce61257a565b6113d86000612837565b565b6113e2612e3a565b60007f000000000000000000000000000000000000000000000000000000000103c531836114109190613d86565b9050611457816040518060400160405280600481526020017f73656564000000000000000000000000000000000000000000000000000000008152506001620f42406128fd565b8260000181815250506114a36040518060400160405280600481526020017f7365656400000000000000000000000000000000000000000000000000000000815250836000015161296d565b8260e001516000600781106114bb576114ba613dba565b5b6020020181905250611506816040518060400160405280600a81526020017f706c616e657453697a6500000000000000000000000000000000000000000000815250601e60646128fd565b8260200181815250506115526040518060400160405280600a81526020017f706c616e657453697a6500000000000000000000000000000000000000000000815250836020015161296d565b8260e0015160016007811061156a57611569613dba565b5b602002018190525060046115b7826040518060400160405280600a81526020017f706c616e657454797065000000000000000000000000000000000000000000008152506000600a6128fd565b106115c35760016115c6565b60005b826080019060018111156115dd576115dc6135f6565b5b908160018111156115f1576115f06135f6565b5b8152505061164a6040518060400160405280600a81526020017f706c616e6574547970650000000000000000000000000000000000000000000081525083608001516001811115611645576116446135f6565b5b61296d565b8260e0015160046007811061166257611661613dba565b5b60200201819052506000600181111561167e5761167d6135f6565b5b82608001516001811115611695576116946135f6565b5b1480156116e4575060036116e2826040518060400160405280600881526020017f68617352696e67730000000000000000000000000000000000000000000000008152506000600a6128fd565b105b8260400190151590811515815250506117476040518060400160405280600881526020017f68617352696e6773000000000000000000000000000000000000000000000000815250836040015161173c57600061173f565b60015b60ff1661296d565b8260e0015160026007811061175f5761175e613dba565b5b602002018190525060006117ac826040518060400160405280600881526020017f6e756d4d6f6f6e73000000000000000000000000000000000000000000000000815250600060646128fd565b905060198110156117c7576001836060018181525050611807565b60258110156117e0576002836060018181525050611806565b60288110156117f9576003836060018181525050611805565b60008360600181815250505b5b5b61184a6040518060400160405280600881526020017f6e756d4d6f6f6e73000000000000000000000000000000000000000000000000815250846060015161296d565b8360e0015160036007811061186257611861613dba565b5b6020020181905250506118af816040518060400160405280600781526020017f626173654875650000000000000000000000000000000000000000000000000081525060006101686128fd565b8260a00181815250506118fb6040518060400160405280600781526020017f62617365487565000000000000000000000000000000000000000000000000008152508360a0015161296d565b8260e0015160056007811061191357611912613dba565b5b602002018190525060018081111561192e5761192d6135f6565b5b82608001516001811115611945576119446135f6565b5b14801561199457506003611992826040518060400160405280600881526020017f68617357617465720000000000000000000000000000000000000000000000008152506000600a6128fd565b105b8260c00190151590811515815250506119f76040518060400160405280600881526020017f68617357617465720000000000000000000000000000000000000000000000008152508360c001516119ec5760006119ef565b60015b60ff1661296d565b8260e00151600660078110611a0f57611a0e613dba565b5b602002018190525050919050565b6000600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611a4f61257a565b80600b8190555050565b606060038054611a6890613aa3565b80601f0160208091040260200160405190810160405280929190818152602001828054611a9490613aa3565b8015611ae15780601f10611ab657610100808354040283529160200191611ae1565b820191906000526020600020905b815481529060010190602001808311611ac457829003601f168201915b5050505050905090565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600b5481565b600c60009054906101000a900460ff16611b5d576040517f589ed34b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000109281611b87611dfa565b611b919190613d86565b1115611bc9576040517f52df9fe500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600b54611bd79190613de9565b341015611c10576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c1a33826129a1565b80600b54611c289190613de9565b341115611cec5760003373ffffffffffffffffffffffffffffffffffffffff1682600b54611c569190613de9565b34611c619190613e2b565b604051611c6d90613e90565b60006040518083038185875af1925050503d8060008114611caa576040519150601f19603f3d011682016040523d82523d6000602084013e611caf565b606091505b5050905080611cea576040517ff0c49d4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b50565b8060076000611cfc612569565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16611da9612569565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611dee9190612f76565b60405180910390a35050565b6000611e04612b5c565b905090565b7f000000000000000000000000000000000000000000000000000000000103c53181565b611e3561257a565b600c60019054906101000a900460ff1615611e7c576040517f6823b07300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6060611fba8260e00151600060078110611edd57611edc613dba565b5b60200201518360e00151600160078110611efa57611ef9613dba565b5b60200201518460e00151600260078110611f1757611f16613dba565b5b60200201518560e00151600360078110611f3457611f33613dba565b5b60200201518660e00151600460078110611f5157611f50613dba565b5b60200201518760e00151600560078110611f6e57611f6d613dba565b5b60200201518860e00151600660078110611f8b57611f8a613dba565b5b6020020151604051602001611fa69796959493929190613ed6565b604051602081830303815290604052612b6f565b9050919050565b600c60019054906101000a900460ff1681565b611fdf848484610b67565b60008373ffffffffffffffffffffffffffffffffffffffff163b146120415761200a84848484612b84565b612040576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b50505050565b61204f61257a565b7f0000000000000000000000000000000000000000000000000000000000001092818484905061207f9190613de9565b612087611dfa565b6120919190613d86565b11156120c9576040517f52df9fe500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8383905081101561211b576121088484838181106120ed576120ec613dba565b5b905060200201602081019061210291906135ab565b836129a1565b808061211390613f3b565b9150506120cc565b50505050565b606061212c8261250a565b612162576040517feb7d192800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061216d836113da565b9050600061217a82610f3b565b9050600061218783611ec0565b90506000612234600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c7d3625b866040518263ffffffff1660e01b81526004016121e99190613828565b600060405180830381865afa158015612206573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061222f9190613ff3565b612b6f565b90506000600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bf471ba7846040518263ffffffff1660e01b815260040161229391906138d4565b600060405180830381865afa1580156122b0573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906122d99190613ff3565b905060006122e68861278e565b8383876040516020016122fc94939291906142e8565b60405160208183030381529060405290508060405160200161231e91906143ca565b6040516020818303038152906040529650505050505050919050565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61236861257a565b600c60019054906101000a900460ff16156123af576040517f6823b07300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b61248f61257a565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036124fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124f59061445e565b60405180910390fd5b61250781612837565b50565b600081612515612571565b11158015612524575060005482105b8015612562575060007c0100000000000000000000000000000000000000000000000000000000600460008581526020019081526020016000205416145b9050919050565b600033905090565b60006001905090565b612582612cd4565b73ffffffffffffffffffffffffffffffffffffffff166125a0611a1d565b73ffffffffffffffffffffffffffffffffffffffff16146125f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125ed906144ca565b60405180910390fd5b565b60008082905080612607612571565b1161268d5760005481101561268c5760006004600083815260200190815260200160002054905060007c010000000000000000000000000000000000000000000000000000000082160361268a575b60008103612680576004600083600190039350838152602001908152602001600020549050612656565b80925050506126bf565b505b5b6040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b60008060006006600085815260200190815260200160002090508092508254915050915091565b600073ffffffffffffffffffffffffffffffffffffffff8316925073ffffffffffffffffffffffffffffffffffffffff821691508382148383141790509392505050565b50505050565b60008060e883901c905060e861274c868684612cdc565b62ffffff16901b9150509392505050565b600073ffffffffffffffffffffffffffffffffffffffff83169250814260a01b178317905092915050565b50505050565b60606080604051019050602081016040526000815280600019835b6001156127ca578184019350600a81066030018453600a81049050806127a9575b50828203602084039350808452505050919050565b606082826040516020016127f492919061455c565b604051602081830303815290604052905092915050565b606082826040516020016128209291906145f9565b604051602081830303815290604052905092915050565b6000600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000806129328561290d8861278e565b60405160200161291e92919061464a565b604051602081830303815290604052612ce5565b905083600185856129439190613e2b565b61294d9190613d86565b82612958919061469d565b6129629190613d86565b915050949350505050565b6060826129798361278e565b60405160200161298a9291906147b2565b604051602081830303815290604052905092915050565b600080549050600082036129e1576040517fb562e8dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129ee600084838561272f565b600160406001901b178202600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550612a6583612a566000866000612735565b612a5f85612d19565b1761275d565b6004600083815260200190815260200160002081905550600080838301905073ffffffffffffffffffffffffffffffffffffffff85169150828260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600183015b818114612b0657808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600181019050612acb565b5060008203612b41576040517f2e07630000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806000819055505050612b576000848385612788565b505050565b6000612b66612571565b60005403905090565b6060612b7d82600080612d29565b9050919050565b60008373ffffffffffffffffffffffffffffffffffffffff1663150b7a02612baa612569565b8786866040518563ffffffff1660e01b8152600401612bcc94939291906147f7565b6020604051808303816000875af1925050508015612c0857506040513d601f19601f82011682018060405250810190612c059190614858565b60015b612c81573d8060008114612c38576040519150601f19603f3d011682016040523d82523d6000602084013e612c3d565b606091505b506000815103612c79576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050949350505050565b600033905090565b60009392505050565b6000612d0f82604051602001612cfb9190614885565b604051602081830303815290604052612e2a565b60001c9050919050565b60006001821460e11b9050919050565b606083518015612e22576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b600115612def576003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f8116516003536000518352600483019250818310612de95750612def565b50612d99565b601f19601f82011660405260038406600204613d3d60f01b81840352808715150290506000818403528084038652505050505b509392505050565b6000815160208301209050919050565b60405180610100016040528060008152602001600081526020016000151581526020016000815260200160006001811115612e7857612e776135f6565b5b815260200160008152602001600015158152602001612e95612e9b565b81525090565b6040518060e001604052806007905b6060815260200190600190039081612eaa5790505090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612f0b81612ed6565b8114612f1657600080fd5b50565b600081359050612f2881612f02565b92915050565b600060208284031215612f4457612f43612ecc565b5b6000612f5284828501612f19565b91505092915050565b60008115159050919050565b612f7081612f5b565b82525050565b6000602082019050612f8b6000830184612f67565b92915050565b6000819050919050565b612fa481612f91565b82525050565b6000602082019050612fbf6000830184612f9b565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612fff578082015181840152602081019050612fe4565b60008484015250505050565b6000601f19601f8301169050919050565b600061302782612fc5565b6130318185612fd0565b9350613041818560208601612fe1565b61304a8161300b565b840191505092915050565b6000602082019050818103600083015261306f818461301c565b905092915050565b61308081612f91565b811461308b57600080fd5b50565b60008135905061309d81613077565b92915050565b6000602082840312156130b9576130b8612ecc565b5b60006130c78482850161308e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006130fb826130d0565b9050919050565b61310b816130f0565b82525050565b60006020820190506131266000830184613102565b92915050565b613135816130f0565b811461314057600080fd5b50565b6000813590506131528161312c565b92915050565b6000806040838503121561316f5761316e612ecc565b5b600061317d85828601613143565b925050602061318e8582860161308e565b9150509250929050565b6131a181612f5b565b81146131ac57600080fd5b50565b6000813590506131be81613198565b92915050565b6000602082840312156131da576131d9612ecc565b5b60006131e8848285016131af565b91505092915050565b60008060006060848603121561320a57613209612ecc565b5b600061321886828701613143565b935050602061322986828701613143565b925050604061323a8682870161308e565b9150509250925092565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6132818261300b565b810181811067ffffffffffffffff821117156132a05761329f613249565b5b80604052505050565b60006132b3612ec2565b90506132bf8282613278565b919050565b600080fd5b600281106132d657600080fd5b50565b6000813590506132e8816132c9565b92915050565b600080fd5b600067ffffffffffffffff82111561330e5761330d613249565b5b602082029050919050565b600080fd5b600080fd5b600067ffffffffffffffff82111561333e5761333d613249565b5b6133478261300b565b9050602081019050919050565b82818337600083830152505050565b600061337661337184613323565b6132a9565b9050828152602081018484840111156133925761339161331e565b5b61339d848285613354565b509392505050565b600082601f8301126133ba576133b96132ee565b5b81356133ca848260208601613363565b91505092915050565b60006133e66133e1846132f3565b6132a9565b90508060208402830185811115613400576133ff613319565b5b835b8181101561344757803567ffffffffffffffff811115613425576134246132ee565b5b80860161343289826133a5565b85526020850194505050602081019050613402565b5050509392505050565b600082601f830112613466576134656132ee565b5b60076134738482856133d3565b91505092915050565b6000610100828403121561349357613492613244565b5b61349e6101006132a9565b905060006134ae8482850161308e565b60008301525060206134c28482850161308e565b60208301525060406134d6848285016131af565b60408301525060606134ea8482850161308e565b60608301525060806134fe848285016132d9565b60808301525060a06135128482850161308e565b60a08301525060c0613526848285016131af565b60c08301525060e082013567ffffffffffffffff81111561354a576135496132c4565b5b61355684828501613451565b60e08301525092915050565b60006020828403121561357857613577612ecc565b5b600082013567ffffffffffffffff81111561359657613595612ed1565b5b6135a28482850161347c565b91505092915050565b6000602082840312156135c1576135c0612ecc565b5b60006135cf84828501613143565b91505092915050565b6135e181612f91565b82525050565b6135f081612f5b565b82525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60028110613636576136356135f6565b5b50565b600081905061364782613625565b919050565b600061365782613639565b9050919050565b6136678161364c565b82525050565b600060079050919050565b600081905092915050565b6000819050919050565b600081519050919050565b600082825260208201905092915050565b60006136b48261368d565b6136be8185613698565b93506136ce818560208601612fe1565b6136d78161300b565b840191505092915050565b60006136ee83836136a9565b905092915050565b6000602082019050919050565b600061370e8261366d565b6137188185613678565b93508360208202850161372a85613683565b8060005b85811015613766578484038952815161374785826136e2565b9450613752836136f6565b925060208a0199505060018101905061372e565b50829750879550505050505092915050565b60006101008301600083015161379160008601826135d8565b5060208301516137a460208601826135d8565b5060408301516137b760408601826135e7565b5060608301516137ca60608601826135d8565b5060808301516137dd608086018261365e565b5060a08301516137f060a08601826135d8565b5060c083015161380360c08601826135e7565b5060e083015184820360e086015261381b8282613703565b9150508091505092915050565b600060208201905081810360008301526138428184613778565b905092915050565b6000806040838503121561386157613860612ecc565b5b600061386f85828601613143565b9250506020613880858286016131af565b9150509250929050565b600082825260208201905092915050565b60006138a68261368d565b6138b0818561388a565b93506138c0818560208601612fe1565b6138c98161300b565b840191505092915050565b600060208201905081810360008301526138ee818461389b565b905092915050565b600080600080608085870312156139105761390f612ecc565b5b600061391e87828801613143565b945050602061392f87828801613143565b93505060406139408782880161308e565b925050606085013567ffffffffffffffff81111561396157613960612ed1565b5b61396d878288016133a5565b91505092959194509250565b600080fd5b60008083601f840112613994576139936132ee565b5b8235905067ffffffffffffffff8111156139b1576139b0613979565b5b6020830191508360208202830111156139cd576139cc613319565b5b9250929050565b6000806000604084860312156139ed576139ec612ecc565b5b600084013567ffffffffffffffff811115613a0b57613a0a612ed1565b5b613a178682870161397e565b93509350506020613a2a8682870161308e565b9150509250925092565b60008060408385031215613a4b57613a4a612ecc565b5b6000613a5985828601613143565b9250506020613a6a85828601613143565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680613abb57607f821691505b602082108103613ace57613acd613a74565b5b50919050565b613add81612f91565b82525050565b6000602082019050613af86000830184613ad4565b92915050565b600067ffffffffffffffff821115613b1957613b18613249565b5b613b228261300b565b9050602081019050919050565b6000613b42613b3d84613afe565b6132a9565b905082815260208101848484011115613b5e57613b5d61331e565b5b613b69848285612fe1565b509392505050565b600082601f830112613b8657613b856132ee565b5b8151613b96848260208601613b2f565b91505092915050565b600060208284031215613bb557613bb4612ecc565b5b600082015167ffffffffffffffff811115613bd357613bd2612ed1565b5b613bdf84828501613b71565b91505092915050565b7f2261747472696275746573223a205b0000000000000000000000000000000000815250565b600081905092915050565b6000613c2482612fc5565b613c2e8185613c0e565b9350613c3e818560208601612fe1565b80840191505092915050565b7f2c00000000000000000000000000000000000000000000000000000000000000815250565b7f5d00000000000000000000000000000000000000000000000000000000000000815250565b6000613ca182613be8565b600f82019150613cb18289613c19565b9150613cbc82613c4a565b600182019150613ccc8288613c19565b9150613cd782613c4a565b600182019150613ce78287613c19565b9150613cf282613c4a565b600182019150613d028286613c19565b9150613d0d82613c4a565b600182019150613d1d8285613c19565b9150613d2882613c4a565b600182019150613d388284613c19565b9150613d4382613c70565b600182019150819050979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000613d9182612f91565b9150613d9c83612f91565b9250828201905080821115613db457613db3613d57565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000613df482612f91565b9150613dff83612f91565b9250828202613e0d81612f91565b91508282048414831517613e2457613e23613d57565b5b5092915050565b6000613e3682612f91565b9150613e4183612f91565b9250828203905081811115613e5957613e58613d57565b5b92915050565b600081905092915050565b50565b6000613e7a600083613e5f565b9150613e8582613e6a565b600082019050919050565b6000613e9b82613e6d565b9150819050919050565b6000613eb08261368d565b613eba8185613e5f565b9350613eca818560208601612fe1565b80840191505092915050565b6000613ee2828a613ea5565b9150613eee8289613ea5565b9150613efa8288613ea5565b9150613f068287613ea5565b9150613f128286613ea5565b9150613f1e8285613ea5565b9150613f2a8284613ea5565b915081905098975050505050505050565b6000613f4682612f91565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f7857613f77613d57565b5b600182019050919050565b6000613f96613f9184613323565b6132a9565b905082815260208101848484011115613fb257613fb161331e565b5b613fbd848285612fe1565b509392505050565b600082601f830112613fda57613fd96132ee565b5b8151613fea848260208601613f83565b91505092915050565b60006020828403121561400957614008612ecc565b5b600082015167ffffffffffffffff81111561402757614026612ed1565b5b61403384828501613fc5565b91505092915050565b7f7b226e616d65223a220000000000000000000000000000000000000000000000600082015250565b6000614072600983613c0e565b915061407d8261403c565b600982019050919050565b7f4574686572506c616e6574202300000000000000000000000000000000000000600082015250565b60006140be600d83613c0e565b91506140c982614088565b600d82019050919050565b7f222c20226465736372697074696f6e223a220000000000000000000000000000600082015250565b600061410a601283613c0e565b9150614115826140d4565b601282019050919050565b7f46756c6c79206f6e2d636861696e2c2070726f6365647572616c6c792067656e60008201527f6572617465642c20334420706c616e6574732e00000000000000000000000000602082015250565b600061417c603383613c0e565b915061418782614120565b603382019050919050565b7f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b626160008201527f736536342c000000000000000000000000000000000000000000000000000000602082015250565b60006141ee602583613c0e565b91506141f982614192565b602582019050919050565b7f222c22616e696d6174696f6e5f75726c223a2200000000000000000000000000600082015250565b600061423a601383613c0e565b915061424582614204565b601382019050919050565b7f222c000000000000000000000000000000000000000000000000000000000000600082015250565b6000614286600283613c0e565b915061429182614250565b600282019050919050565b7f7d00000000000000000000000000000000000000000000000000000000000000600082015250565b60006142d2600183613c0e565b91506142dd8261429c565b600182019050919050565b60006142f382614065565b91506142fe826140b1565b915061430a8287613c19565b9150614315826140fd565b91506143208261416f565b915061432b826141e1565b91506143378286613c19565b91506143428261422d565b915061434e8285613ea5565b915061435982614279565b91506143658284613c19565b9150614370826142c5565b915081905095945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e2c00000000000000000000600082015250565b60006143b4601683613c0e565b91506143bf8261437e565b601682019050919050565b60006143d5826143a7565b91506143e18284613ea5565b915081905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000614448602683612fd0565b9150614453826143ec565b604082019050919050565b600060208201905081810360008301526144778161443b565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006144b4602083612fd0565b91506144bf8261447e565b602082019050919050565b600060208201905081810360008301526144e3816144a7565b9050919050565b7f7b2274726169745f74797065223a220000000000000000000000000000000000815250565b7f222c2276616c7565223a00000000000000000000000000000000000000000000815250565b7f7d00000000000000000000000000000000000000000000000000000000000000815250565b6000614567826144ea565b600f820191506145778285613c19565b915061458282614510565b600a820191506145928284613c19565b915061459d82614536565b6001820191508190509392505050565b7f222c2276616c7565223a22000000000000000000000000000000000000000000815250565b7f227d000000000000000000000000000000000000000000000000000000000000815250565b6000614604826144ea565b600f820191506146148285613c19565b915061461f826145ad565b600b8201915061462f8284613c19565b915061463a826145d3565b6002820191508190509392505050565b60006146568285613c19565b91506146628284613c19565b91508190509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006146a882612f91565b91506146b383612f91565b9250826146c3576146c261466e565b5b828206905092915050565b7f7661722000000000000000000000000000000000000000000000000000000000600082015250565b6000614704600483613c0e565b915061470f826146ce565b600482019050919050565b7f3d00000000000000000000000000000000000000000000000000000000000000600082015250565b6000614750600183613c0e565b915061475b8261471a565b600182019050919050565b7f3b00000000000000000000000000000000000000000000000000000000000000600082015250565b600061479c600183613c0e565b91506147a782614766565b600182019050919050565b60006147bd826146f7565b91506147c98285613ea5565b91506147d482614743565b91506147e08284613c19565b91506147eb8261478f565b91508190509392505050565b600060808201905061480c6000830187613102565b6148196020830186613102565b6148266040830185612f9b565b8181036060830152614838818461389b565b905095945050505050565b60008151905061485281612f02565b92915050565b60006020828403121561486e5761486d612ecc565b5b600061487c84828501614843565b91505092915050565b60006148918284613c19565b91508190509291505056fea264697066735822122086b5c7449e29e8de509c70ef7a3f2fac4937ae0790460649313afd14a874a0b564736f6c63430008120033

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

00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001092000000000000000000000000000000000000000000000000000eebe0b40e800000000000000000000000000007e12f3f0bfceee2b92b68ed485e85b896761c7500000000000000000000000016ec9b5a0aef45ca3642000df11f0b2c42bdac45000000000000000000000000000000000000000000000000000000000000000c4574686572506c616e657473000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024550000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : name (string): EtherPlanets
Arg [1] : symbol (string): EP
Arg [2] : _supply (uint256): 4242
Arg [3] : _price (uint256): 4200000000000000
Arg [4] : _thumbnailAddress (address): 0x07e12F3F0bFCeEE2B92B68eD485E85B896761C75
Arg [5] : _rendererAddress (address): 0x16ec9b5a0aef45cA3642000Df11f0b2C42Bdac45

-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [2] : 0000000000000000000000000000000000000000000000000000000000001092
Arg [3] : 000000000000000000000000000000000000000000000000000eebe0b40e8000
Arg [4] : 00000000000000000000000007e12f3f0bfceee2b92b68ed485e85b896761c75
Arg [5] : 00000000000000000000000016ec9b5a0aef45ca3642000df11f0b2c42bdac45
Arg [6] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [7] : 4574686572506c616e6574730000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [9] : 4550000000000000000000000000000000000000000000000000000000000000


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

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