ETH Price: $3,119.01 (-0.09%)

Luchadores (LUCHADORES)
 

Overview

TokenID

1268

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

Luchadores.io is a 100% on-chain P2E auto battler. Customise your name, stats, skills and wearables to win fights and earn $LUCHA.

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Luchadores

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 25 : Luchadores.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "@openzeppelin/contracts/token/ERC721/ERC721Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";

contract Luchadores is ERC721Pausable, Ownable, ReentrancyGuard, VRFConsumerBase {
	using Counters for Counters.Counter;
	using Strings for uint256;

	Counters.Counter private _tokenIds;

	IUniswapV2Router02 public uniswapRouter;

	bytes32 internal keyHash = 0xAA77729D3466CA35AE8D28B3BBAC7CC36A5031EFDC430821C02BC31A238AF445;
	uint256 internal LinkFee = 2 * 10**18; // 2 LINK
	address private VRFCoordinator = 0xf0d54349aDdcf704F77AE15b96510dEA15cb7952;
	address private LinkToken = 0x514910771AF9Ca656af840dff83E8264EcF986CA;

	constructor() public
		ERC721("Luchadores", "LUCHADORES")
		VRFConsumerBase(VRFCoordinator, LinkToken) 
	{
		uniswapRouter = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);

		art.baseColor = ["ebebf7", "1c1d2f", "cc0d3d", "d22f94", "890ec1", "1c49d8", "19b554", "13cac6", "f7c23c", "f18e2f"];
		art.altColor = ["dadae6", "13141f", "ea184d", "e0369f", "9511d2", "2854e6", "1da951", "11b9b5", "e8b63a", "e28327"];
		art.eyeColor = ["3b6ba5", "3b8fa5", "3ba599", "3ba577", "339842", "7fa53b", "a5823b", "a5693b", "844f1d", "4e2906"];
		art.skinColor = ["f9d1b7", "f7b897", "f39c77", "ffcb84", "bd7e47", "b97e4b", "b97a50", "5a3214", "50270e", "3a1b09"];
		art.spirit[0] = Item("Bull", "<path fill='#A9A18A' d='M21 2V1h-1V0h-1v2h1v1h-3v2h2v1h2V5h1V2zM5 3H4V2h1V0H4v1H3v1H2v3h1v1h2V5h2V3H6z'/><g fill='#000' opacity='.15'><path d='M21 4h1v1h-1zM19 5h-1v1h3V5h-1z'/><path d='M2 4h1v1H2zM4 5H3v1h3V5H5z'/></g>");
		art.spirit[1] = Item("Jaguar", "<path class='lucha-base' d='M6 2V1H5v5h1V5h1V3h1V2H7zM18 1v1h-2v1h1v2h1v1h1V1z'/><g fill='#000'><path d='M5 1h1v1H5zM6 2v1h2V2H7zM18 1h1v1h-1zM16 2v1h2V2h-1z' opacity='.3'/><path d='M6 3V2H5v4h1V5h1V3zM18 2v1h-1v2h1v1h1V2z' opacity='.2'/></g>");
		art.cape[0] = Item("Classic", "<path class='lucha-alt' d='M20 11H3v12h1v-1h2v-1h12v1h2v1h1V11z'/><g fill='#000'><path opacity='.2' d='M20 11v12h1V11zM3 12v11h1V11H3z'/><path opacity='.5' d='M19 11H4v11h2v-1h12v1h2V11z'/></g>");
		art.cape[1] = Item("Hooded", "<path class='lucha-alt' d='M20 11H3v12h1v-1h2v-1h12v1h2v1h1V11z'/><g fill='#000'><path opacity='.2' d='M20 11v12h1V11zM3 12v11h1V11H3z'/><path opacity='.5' d='M19 11H4v11h2v-1h12v1h2V11z'/></g>");
		art.torso[0] = Item("Shirt", "<path class='lucha-base' d='M22 12v-1h-1v-1h-1V9H4v1H3v1H2v1H1v5h4v-3h1v1h1v1h1v2h8v-2h1v-1h1v-1h1v3h4v-5z'/><path d='M22 12v-1h-1v-1h-1V9H4v1H3v1H2v1H1v5h4v-3h1v1h1v1h1v2h8v-2h1v-1h1v-1h1v3h4v-5z' fill='#000' opacity='.15'/>");
		art.torso[1] = Item("Open Shirt", "<path class='lucha-base' d='M10 9H4v1H3v1H2v1H1v3h4v-1h1v1h1v1h1v2h3V9zM22 12v-1h-1v-1h-1V9h-7v9h3v-2h1v-1h1v-1h1v1h4v-3z'/><path d='M10 9H4v1H3v1H2v1H1v3h4v-1h1v1h1v1h1v2h3V9zM22 12v-1h-1v-1h-1V9h-7v9h3v-2h1v-1h1v-1h1v1h4v-3z' fill='#000' opacity='.15'/>");
		art.torso[2] = Item("Singlet", "<path class='lucha-base' d='M16 9H7v3h1-1v4h1v1h8v-1h1v-4h-1 1V9z'/><path fill='#000' opacity='.15' d='M16 9H7v7h1v1h8v-1h1V9z'/>");
		art.torso[3] = Item("Suspenders", "<path class='lucha-base' d='M15 9v9h1V9zM8 10v8h1V9H8z'/><path d='M8 10v8h1V9H8zM15 9v9h1V9z' fill='#000' opacity='.15'/>");
		art.arms[0] = Item("Gloves", "<path class='lucha-base' d='M5 16H1v3h4v-1h1v-1H5zM22 16h-3v1h-1v1h1v1h4v-3z'/><path class='lucha-alt' d='M3 16H1v1h4v-1H4zM22 16h-3v1h4v-1z'/>");
		art.arms[1] = Item("Wrist Bands", "<path class='lucha-base' d='M3 15H1v2h4v-2H4zM22 15h-3v2h4v-2z'/>");
		art.arms[2] = Item("Right Band", "<path class='lucha-alt' d='M4 14H1v1h4v-1z'/>");
		art.arms[3] = Item("Left Band", "<path class='lucha-base' d='M22 14h-3v1h4v-1z'/>");
		art.arms[4] = Item("Arm Bands", "<path class='lucha-base' d='M4 14H1v1h4v-1zM22 14h-3v1h4v-1z'/>");
		art.arms[5] = Item("Sleeves", "<path class='lucha-base' d='M22 14h-3v3h4v-3zM3 14H1v3h4v-3H4z'/><path class='lucha-alt' d='M22 14h-3v1h4v-1zM3 14H1v1h4v-1H4z'/>");
		art.mask[0] = Item("Split", "<path d='M11 0H9v1H8v1H7v1H6v2H5v5h1v2h1v1h1v1h1v1h3V0z'/>");
		art.mask[1] = Item("Cross", "<path d='M14 2h-1V0h-2v2H9v2h2v4h2V4h2V2zM12 13h-1v2h2v-2z'/>");
		art.mask[2] = Item("Fierce", "<path d='M17 3v1h-2v1h-1v1h-1v3h5V3zM11 8V6h-1V5H9V4H7V3H6v6h5zM11 13v2h2v-2h-1z'/>");
		art.mask[3] = Item("Striped", "<path d='M11 2h2V1h1V0h-4v1h1zM6 10v2h1v-1h1v-1H7zM17 10h-1v1h1v1h1v-2z'/><path d='M16 3h1V2h-1V1h-1v1h-1v1h-1v1h-2V3h-1V2H9V1H8v1H7v1h1v1h1v1h1v1h1v9h2V6h1V5h1V4h1z'/>");
		art.mask[4] = Item("Bolt", "<path d='M13 3h-3V2h1V1h1V0H9v1H8v1H7v1H6v2h3v1H8v2H7v2h1V9h1V8h1V7h1V6h1V5h1V4h1V3z'/>");
		art.mask[5] = Item("Winged", "<path d='M18 5V3h-1V2h-1v1h-1v1h-1v1h-1v1h-2V5h-1V4H9V3H8V2H7v1H6v2H5v5h1v2h1v-1h1v-1h3V9h2v1h3v1h1v1h1v-2h1V5z'/>");
		art.mask[6] = Item("Classic", "<path d='M18 5V3h-1V2h-1v2h-1v1h-1v1h-1v3h-2V6h-1V5H9V4H8V2H7v1H6v2H5v4h1v1h2v3h1v1h6v-1h1v-3h2V9h1V5z'/>");
		art.mask[7] = Item("Arrow", "<path d='M18 5V3h-1V2h-1V1h-1V0H9v1H8v1H7v1H6v2H5v5h1v2h1v1h1v1h1v1h1v-4h1V5H9V3h1V2h1V1h2v1h1v1h1v2h-2v6h1v4h1v-1h1v-1h1v-1h1v-2h1V5z'/>");
		art.mask[8] = Item("Dash", "<path d='M13 3V2h-2v2h2zM13 1V0h-2v1h1zM10 4H9V1H8v1H7v1H6v2H5v5h1v2h1v1h1v1h1v1h1v-2H9v-3h2V5h-1zM18 5V3h-1V2h-1V1h-1v3h-1v1h-1v5h2v3h-1v2h1v-1h1v-1h1v-1h1v-2h1V5z'/>");
		art.mouth[0] = Item("Moustache", "<path fill='#421c03' opacity='.9' d='M14 10H9v3h1v-2h4v2h1v-3z'/>");
		art.bottoms[0] = Item("Tights", "<path class='lucha-alt' d='M15 17H8v6h3v-3h2v3h3v-6z'/>");
		art.bottoms[1] = Item("Trunk Tights", "<path class='lucha-base' d='M15 17H8v3h8v-3z'/><path class='lucha-alt' d='M15 18v1h-2v4h3v-5zM9 19v-1H8v5h3v-4h-1z'/>");
		art.boots[0] = Item("Two Tone", "<path class='lucha-alt' d='M9 22H8v1H7v1h4v-2h-1zM16 23v-1h-3v2h4v-1z'/>");
		art.boots[1] = Item("High", "<path class='lucha-alt' d='M9 20H8v1h3v-1h-1zM15 20h-2v1h3v-1z'/>");
	}

	struct Item {
		bytes12 name;
		string svg;
	}
	
	struct Art {
		string[] baseColor;
		string[] altColor;
		string[] eyeColor;
		string[] skinColor;
		mapping(uint256 => Item) spirit;
		mapping(uint256 => Item) cape;
		mapping(uint256 => Item) torso;
		mapping(uint256 => Item) arms;
		mapping(uint256 => Item) mask;
		mapping(uint256 => Item) mouth;
		mapping(uint256 => Item) bottoms;
		mapping(uint256 => Item) boots;
	}

	Art art;

	struct Luchador {
		uint256 dna;
  }

	struct VRFRequest {
		uint256 id;
  }

	mapping(uint256 => Luchador) luchadores;
	mapping(bytes32 => VRFRequest) VRFRequests;

	event GenerateLuchador(
		uint256 indexed id,
		uint256 dna
  );

	function generateLuchador(uint256 _quantity, uint256 _deadline) external payable nonReentrant whenNotPaused {
		require(_tokenIds.current() < 10000, "maximum luchadores reached");
		require(_tokenIds.current() + _quantity <= 10000, "mint quantity exceeds max supply");
		require(_quantity > 0 && _quantity <= 20, "mint quantity must be between 1-20");

		uint256 amountOut = LinkFee * _quantity;

		address[] memory path = new address[](2);
    path[0] = uniswapRouter.WETH();
    path[1] = LinkToken;

    uniswapRouter.swapETHForExactTokens{value: msg.value}(amountOut, path, address(this), _deadline);

		for (uint256 i = 0; i < _quantity; i++) {
			getRandomNumber(uint256(blockhash(block.number - i)));
		}
  }

	function getRandomNumber(uint256 _userProvidedSeed) internal {
		require(LINK.balanceOf(address(this)) >= LinkFee, "Not enough LINK - fill contract");
		bytes32 requestId = requestRandomness(keyHash, LinkFee, _userProvidedSeed);

		_tokenIds.increment();

		VRFRequests[requestId] = VRFRequest({
			id: _tokenIds.current()
		});

		_safeMint(msg.sender, _tokenIds.current());
	}

	function fulfillRandomness(bytes32 _requestId, uint256 _randomNumber) internal override {
		luchadores[VRFRequests[_requestId].id].dna = _randomNumber;
		emit GenerateLuchador(VRFRequests[_requestId].id, _randomNumber);
	}

	function imageData(uint256 _tokenId) public view returns (string memory) {
		require(_exists(_tokenId), "imageData: nonexistent token");
		require(luchadores[_tokenId].dna != 0, "imageData: dna not yet generated");

		uint8[12] memory dna = splitNumber(luchadores[_tokenId].dna);

		string memory capeShoulders = (dna[1] == 0 || dna[1] == 1)? "<path class='lucha-alt' d='M20 10V9h-2v1h-1v1h4v-1zM5 9H4v1H3v1h4v-1H6V9z'/><path fill='#000' opacity='.2' d='M6 9H4v1H3v1h4v-1H6zM20 10V9h-2v1h-1v1h4v-1z'/>" : "";
		string memory capeHood = dna[1] == 1 ? "<path class='lucha-alt' d='M18 4V3h-1V2h-1V1h-1V0H9v1H8v1H7v1H6v2H5v5h1V6h1V5h2V4h1V3h4v1h1v1h2v1h1v4h1V5h-1z'/><g fill='#000'><path d='M18 4V3h-1V2h-1V1h-1V0H9v1H8v1H7v1H6v2H5v5h1V5h1V4h1V3h1V2h6v1h1v1h1v1h1v5h1V5h-1z' opacity='.2'/><path d='M16 4V3h-1V2H9v1H8v1H7v1h2V4h1V3h4v1h1v1h2V4zM6 5h1v1H6zM17 5h1v1h-1z' opacity='.5'/></g>" : "";

		return string(abi.encodePacked(
			"<svg id='luchador", _tokenId.toString(), "' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'>",
				styles(_tokenId, dna),
				"<g class='lucha-breathe'>",
					art.spirit[dna[0]].svg,
					art.cape[dna[1]].svg,
					"<path class='lucha-skin' d='M22 12v-1h-1v-1h-1V9h-1V5h-1V3h-1V2h-1V1h-1V0H9v1H8v1H7v1H6v2H5v4H4v1H3v1H2v1H1v8h4v-1h1v-2H5v-3h1v1h1v1h1v2h8v-2h1v-1h1v-1h1v3h-1v2h1v1h4v-8z'/>",
					art.torso[dna[2]].svg,
					art.arms[dna[3]].svg,
					capeShoulders,
					"<path class='lucha-base' d='M18 5V3h-1V2h-1V1h-1V0H9v1H8v1H7v1H6v2H5v5h1v2h1v1h1v1h1v1h6v-1h1v-1h1v-1h1v-2h1V5z'/>",
					"<g class='lucha-alt'>", art.mask[dna[4]].svg, "</g>",
					capeHood,
					"<path fill='#FFF' d='M9 6H6v3h4V6zM17 6h-3v3h4V6z'/><path class='lucha-eyes' d='M16 6h-2v3h3V6zM8 6H7v3h3V6H9z'/><path fill='#FFF' d='M7 6h1v1H7zM16 6h1v1h-1z' opacity='.4'/><path fill='#000' d='M15 7h1v1h-1zM8 7h1v1H8z'/>",
					"<path class='lucha-skin' d='M14 10H9v3h6v-3z'/>",
					"<path fill='#000' opacity='.9' d='M13 11h-3v1h4v-1z'/>",
					art.mouth[dna[5]].svg,
				"</g>",
				"<path class='lucha-skin' d='M16 23v-6H8v6H7v1h4v-4h2v4h4v-1z'/>",
				"<path class='lucha-base' d='M15 17H8v1h1v1h2v1h2v-1h2v-1h1v-1z'/>",
				art.bottoms[dna[6]].svg,
				"<path class='lucha-base' d='M9 21H8v2H7v1h4v-3h-1zM16 23v-2h-3v3h4v-1z'/>",
				art.boots[dna[7]].svg,
			"</svg>"
		));
	}

	function styles(uint256 _tokenId, uint8[12] memory _dna) internal view returns (string memory) {
		return string(abi.encodePacked(
			"<style>#luchador", _tokenId.toString(), " .lucha-base { fill: #", art.baseColor[_dna[8]],
				"; } #luchador", _tokenId.toString(), " .lucha-alt { fill: #", art.altColor[_dna[9]],
				"; } #luchador", _tokenId.toString(), " .lucha-eyes { fill: #", art.eyeColor[_dna[10]],
				"; } #luchador", _tokenId.toString(), " .lucha-skin { fill: #", art.skinColor[_dna[11]],
				"; } #luchador", _tokenId.toString(), " .lucha-breathe { animation: 0.5s lucha-breathe infinite alternate ease-in-out; } @keyframes lucha-breathe { from { transform: translateY(0px); } to { transform: translateY(1%); } }</style>"
		));
	}

	function metadata(uint256 _tokenId) public view returns (string memory) {
		require(_exists(_tokenId), "metadata: nonexistent token");
		require(luchadores[_tokenId].dna != 0, "metadata: dna not yet generated");

		uint8[12] memory dna = splitNumber(luchadores[_tokenId].dna);

		Item[8] memory artItems = [
			art.spirit[dna[0]],
			art.cape[dna[1]],
			art.torso[dna[2]],
			art.arms[dna[3]],
			art.mask[dna[4]],
			art.mouth[dna[5]],
			art.bottoms[dna[6]],
			art.boots[dna[7]]
		];

		string memory attributes;

		string[8] memory traitType = ["Spirit", "Cape", "Torso", "Arms", "Mask", "Mouth", "Bottoms", "Boots"];

		for (uint256 i = 0; i < artItems.length; i++) {
			if (artItems[i].name == "") continue;

			attributes = string(abi.encodePacked(attributes,
				bytes(attributes).length == 0	? '{' : ', {',
					'"trait_type": "', traitType[i],'",',
					'"value": "', bytes12ToString(artItems[i].name), '"',
				'}'
			));
		}

		return string(abi.encodePacked(
			'{',
				'"name": "Luchador #', _tokenId.toString(), '",', 
				'"description": "Luchadores are randomly generated using Chainlink VRF and have 100% on-chain art and metadata - Only 10000 will ever exist!",',
				'"image_data": "', imageData(_tokenId), '",',
				'"external_url": "https://luchadores.io/luchador/', _tokenId.toString(), '",',
				'"attributes": [', attributes, ']',
			'}'
		));
	}

	function splitNumber(uint256 _number) internal pure returns (uint8[12] memory) {
		uint8[12] memory numbers;

		for (uint256 i = 0; i < numbers.length; i++) {
			numbers[i] = uint8(_number % 10);
			_number /= 10;
		}

		return numbers;
	}

	function bytes12ToString(bytes12 _bytes12) internal pure returns (string memory) {
		uint8 i = 0;
		while(i < 12 && _bytes12[i] != 0) {
			i++;
		}

		bytes memory bytesArray = new bytes(i);
		for (i = 0; i < 12 && _bytes12[i] != 0; i++) {
			bytesArray[i] = _bytes12[i];
		}

		return string(bytesArray);
	}

	function pauseSale() public onlyOwner {
		_pause();
	}

	function unpauseSale() public onlyOwner {
		_unpause();
	}

	function setLinkFee(uint256 _LinkFee) public onlyOwner {
		LinkFee = _LinkFee;
	}

	function setBaseURI(string memory _baseURI) public onlyOwner {
    _setBaseURI(_baseURI);
  }

	function tokenURI(uint256 _tokenId) public view virtual override returns (string memory) {
		require(_exists(_tokenId), "ERC721Metadata: URI query for nonexistent token");

		string memory baseURI = baseURI();

		return bytes(baseURI).length > 0
			? string(abi.encodePacked(baseURI, _tokenId.toString(), ".json"))
			: '';
	}

	function withdraw() public onlyOwner {
		(bool success, ) = msg.sender.call{value: address(this).balance}('');
		require(success, "Withdrawal failed");
	}

	receive() external payable {}
}

File 2 of 25 : VRFConsumerBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "./vendor/SafeMathChainlink.sol";

import "./interfaces/LinkTokenInterface.sol";

import "./VRFRequestIDBase.sol";

/** ****************************************************************************
 * @notice Interface for contracts using VRF randomness
 * *****************************************************************************
 * @dev PURPOSE
 *
 * @dev Reggie the Random Oracle (not his real job) wants to provide randomness
 * @dev to Vera the verifier in such a way that Vera can be sure he's not
 * @dev making his output up to suit himself. Reggie provides Vera a public key
 * @dev to which he knows the secret key. Each time Vera provides a seed to
 * @dev Reggie, he gives back a value which is computed completely
 * @dev deterministically from the seed and the secret key.
 *
 * @dev Reggie provides a proof by which Vera can verify that the output was
 * @dev correctly computed once Reggie tells it to her, but without that proof,
 * @dev the output is indistinguishable to her from a uniform random sample
 * @dev from the output space.
 *
 * @dev The purpose of this contract is to make it easy for unrelated contracts
 * @dev to talk to Vera the verifier about the work Reggie is doing, to provide
 * @dev simple access to a verifiable source of randomness.
 * *****************************************************************************
 * @dev USAGE
 *
 * @dev Calling contracts must inherit from VRFConsumerBase, and can
 * @dev initialize VRFConsumerBase's attributes in their constructor as
 * @dev shown:
 *
 * @dev   contract VRFConsumer {
 * @dev     constuctor(<other arguments>, address _vrfCoordinator, address _link)
 * @dev       VRFConsumerBase(_vrfCoordinator, _link) public {
 * @dev         <initialization with other arguments goes here>
 * @dev       }
 * @dev   }
 *
 * @dev The oracle will have given you an ID for the VRF keypair they have
 * @dev committed to (let's call it keyHash), and have told you the minimum LINK
 * @dev price for VRF service. Make sure your contract has sufficient LINK, and
 * @dev call requestRandomness(keyHash, fee, seed), where seed is the input you
 * @dev want to generate randomness from.
 *
 * @dev Once the VRFCoordinator has received and validated the oracle's response
 * @dev to your request, it will call your contract's fulfillRandomness method.
 *
 * @dev The randomness argument to fulfillRandomness is the actual random value
 * @dev generated from your seed.
 *
 * @dev The requestId argument is generated from the keyHash and the seed by
 * @dev makeRequestId(keyHash, seed). If your contract could have concurrent
 * @dev requests open, you can use the requestId to track which seed is
 * @dev associated with which randomness. See VRFRequestIDBase.sol for more
 * @dev details. (See "SECURITY CONSIDERATIONS" for principles to keep in mind,
 * @dev if your contract could have multiple requests in flight simultaneously.)
 *
 * @dev Colliding `requestId`s are cryptographically impossible as long as seeds
 * @dev differ. (Which is critical to making unpredictable randomness! See the
 * @dev next section.)
 *
 * *****************************************************************************
 * @dev SECURITY CONSIDERATIONS
 *
 * @dev A method with the ability to call your fulfillRandomness method directly
 * @dev could spoof a VRF response with any random value, so it's critical that
 * @dev it cannot be directly called by anything other than this base contract
 * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method).
 *
 * @dev For your users to trust that your contract's random behavior is free
 * @dev from malicious interference, it's best if you can write it so that all
 * @dev behaviors implied by a VRF response are executed *during* your
 * @dev fulfillRandomness method. If your contract must store the response (or
 * @dev anything derived from it) and use it later, you must ensure that any
 * @dev user-significant behavior which depends on that stored value cannot be
 * @dev manipulated by a subsequent VRF request.
 *
 * @dev Similarly, both miners and the VRF oracle itself have some influence
 * @dev over the order in which VRF responses appear on the blockchain, so if
 * @dev your contract could have multiple VRF requests in flight simultaneously,
 * @dev you must ensure that the order in which the VRF responses arrive cannot
 * @dev be used to manipulate your contract's user-significant behavior.
 *
 * @dev Since the ultimate input to the VRF is mixed with the block hash of the
 * @dev block in which the request is made, user-provided seeds have no impact
 * @dev on its economic security properties. They are only included for API
 * @dev compatability with previous versions of this contract.
 *
 * @dev Since the block hash of the block which contains the requestRandomness
 * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful
 * @dev miner could, in principle, fork the blockchain to evict the block
 * @dev containing the request, forcing the request to be included in a
 * @dev different block with a different hash, and therefore a different input
 * @dev to the VRF. However, such an attack would incur a substantial economic
 * @dev cost. This cost scales with the number of blocks the VRF oracle waits
 * @dev until it calls responds to a request.
 */
abstract contract VRFConsumerBase is VRFRequestIDBase {

  using SafeMathChainlink for uint256;

  /**
   * @notice fulfillRandomness handles the VRF response. Your contract must
   * @notice implement it. See "SECURITY CONSIDERATIONS" above for important
   * @notice principles to keep in mind when implementing your fulfillRandomness
   * @notice method.
   *
   * @dev VRFConsumerBase expects its subcontracts to have a method with this
   * @dev signature, and will call it once it has verified the proof
   * @dev associated with the randomness. (It is triggered via a call to
   * @dev rawFulfillRandomness, below.)
   *
   * @param requestId The Id initially returned by requestRandomness
   * @param randomness the VRF output
   */
  function fulfillRandomness(bytes32 requestId, uint256 randomness)
    internal virtual;

  /**
   * @notice requestRandomness initiates a request for VRF output given _seed
   *
   * @dev The fulfillRandomness method receives the output, once it's provided
   * @dev by the Oracle, and verified by the vrfCoordinator.
   *
   * @dev The _keyHash must already be registered with the VRFCoordinator, and
   * @dev the _fee must exceed the fee specified during registration of the
   * @dev _keyHash.
   *
   * @dev The _seed parameter is vestigial, and is kept only for API
   * @dev compatibility with older versions. It can't *hurt* to mix in some of
   * @dev your own randomness, here, but it's not necessary because the VRF
   * @dev oracle will mix the hash of the block containing your request into the
   * @dev VRF seed it ultimately uses.
   *
   * @param _keyHash ID of public key against which randomness is generated
   * @param _fee The amount of LINK to send with the request
   * @param _seed seed mixed into the input of the VRF.
   *
   * @return requestId unique ID for this request
   *
   * @dev The returned requestId can be used to distinguish responses to
   * @dev concurrent requests. It is passed as the first argument to
   * @dev fulfillRandomness.
   */
  function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed)
    internal returns (bytes32 requestId)
  {
    LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, _seed));
    // This is the seed passed to VRFCoordinator. The oracle will mix this with
    // the hash of the block containing this request to obtain the seed/input
    // which is finally passed to the VRF cryptographic machinery.
    uint256 vRFSeed  = makeVRFInputSeed(_keyHash, _seed, address(this), nonces[_keyHash]);
    // nonces[_keyHash] must stay in sync with
    // VRFCoordinator.nonces[_keyHash][this], which was incremented by the above
    // successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest).
    // This provides protection against the user repeating their input seed,
    // which would result in a predictable/duplicate output, if multiple such
    // requests appeared in the same block.
    nonces[_keyHash] = nonces[_keyHash].add(1);
    return makeRequestId(_keyHash, vRFSeed);
  }

  LinkTokenInterface immutable internal LINK;
  address immutable private vrfCoordinator;

  // Nonces for each VRF key from which randomness has been requested.
  //
  // Must stay in sync with VRFCoordinator[_keyHash][this]
  mapping(bytes32 /* keyHash */ => uint256 /* nonce */) private nonces;

  /**
   * @param _vrfCoordinator address of VRFCoordinator contract
   * @param _link address of LINK token contract
   *
   * @dev https://docs.chain.link/docs/link-token-contracts
   */
  constructor(address _vrfCoordinator, address _link) public {
    vrfCoordinator = _vrfCoordinator;
    LINK = LinkTokenInterface(_link);
  }

  // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
  // proof. rawFulfillRandomness then calls fulfillRandomness, after validating
  // the origin of the call
  function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external {
    require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill");
    fulfillRandomness(requestId, randomness);
  }
}

File 3 of 25 : VRFRequestIDBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract VRFRequestIDBase {

  /**
   * @notice returns the seed which is actually input to the VRF coordinator
   *
   * @dev To prevent repetition of VRF output due to repetition of the
   * @dev user-supplied seed, that seed is combined in a hash with the
   * @dev user-specific nonce, and the address of the consuming contract. The
   * @dev risk of repetition is mostly mitigated by inclusion of a blockhash in
   * @dev the final seed, but the nonce does protect against repetition in
   * @dev requests which are included in a single block.
   *
   * @param _userSeed VRF seed input provided by user
   * @param _requester Address of the requesting contract
   * @param _nonce User-specific nonce at the time of the request
   */
  function makeVRFInputSeed(bytes32 _keyHash, uint256 _userSeed,
    address _requester, uint256 _nonce)
    internal pure returns (uint256)
  {
    return  uint256(keccak256(abi.encode(_keyHash, _userSeed, _requester, _nonce)));
  }

  /**
   * @notice Returns the id for this request
   * @param _keyHash The serviceAgreement ID to be used for this request
   * @param _vRFInputSeed The seed to be passed directly to the VRF
   * @return The id for this request
   *
   * @dev Note that _vRFInputSeed is not the seed passed by the consuming
   * @dev contract, but the one generated by makeVRFInputSeed
   */
  function makeRequestId(
    bytes32 _keyHash, uint256 _vRFInputSeed) internal pure returns (bytes32) {
    return keccak256(abi.encodePacked(_keyHash, _vRFInputSeed));
  }
}

File 4 of 25 : LinkTokenInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

interface LinkTokenInterface {
  function allowance(address owner, address spender) external view returns (uint256 remaining);
  function approve(address spender, uint256 value) external returns (bool success);
  function balanceOf(address owner) external view returns (uint256 balance);
  function decimals() external view returns (uint8 decimalPlaces);
  function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
  function increaseApproval(address spender, uint256 subtractedValue) external;
  function name() external view returns (string memory tokenName);
  function symbol() external view returns (string memory tokenSymbol);
  function totalSupply() external view returns (uint256 totalTokensIssued);
  function transfer(address to, uint256 value) external returns (bool success);
  function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success);
  function transferFrom(address from, address to, uint256 value) external returns (bool success);
}

File 5 of 25 : SafeMathChainlink.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMathChainlink {
  /**
    * @dev Returns the addition of two unsigned integers, reverting on
    * overflow.
    *
    * Counterpart to Solidity's `+` operator.
    *
    * Requirements:
    * - Addition cannot overflow.
    */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    require(c >= a, "SafeMath: addition overflow");

    return c;
  }

  /**
    * @dev Returns the subtraction of two unsigned integers, reverting on
    * overflow (when the result is negative).
    *
    * Counterpart to Solidity's `-` operator.
    *
    * Requirements:
    * - Subtraction cannot overflow.
    */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b <= a, "SafeMath: subtraction overflow");
    uint256 c = a - b;

    return c;
  }

  /**
    * @dev Returns the multiplication of two unsigned integers, reverting on
    * overflow.
    *
    * Counterpart to Solidity's `*` operator.
    *
    * Requirements:
    * - Multiplication cannot overflow.
    */
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
    if (a == 0) {
      return 0;
    }

    uint256 c = a * b;
    require(c / a == b, "SafeMath: multiplication overflow");

    return c;
  }

  /**
    * @dev Returns the integer division of two unsigned integers. Reverts on
    * division by zero. The result is rounded towards zero.
    *
    * Counterpart to Solidity's `/` operator. Note: this function uses a
    * `revert` opcode (which leaves remaining gas untouched) while Solidity
    * uses an invalid opcode to revert (consuming all remaining gas).
    *
    * Requirements:
    * - The divisor cannot be zero.
    */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // Solidity only automatically asserts when dividing by 0
    require(b > 0, "SafeMath: division by zero");
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold

    return c;
  }

  /**
    * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
    * Reverts when dividing by zero.
    *
    * Counterpart to Solidity's `%` operator. This function uses a `revert`
    * opcode (which leaves remaining gas untouched) while Solidity uses an
    * invalid opcode to revert (consuming all remaining gas).
    *
    * Requirements:
    * - The divisor cannot be zero.
    */
  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0, "SafeMath: modulo by zero");
    return a % b;
  }
}

File 6 of 25 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

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

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

File 7 of 25 : ERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
abstract contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    /**
     * @dev Mapping of interface ids to whether or not it's supported.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () internal {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal virtual {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}

File 8 of 25 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

File 9 of 25 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 10 of 25 : ERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../../utils/Context.sol";
import "./IERC721.sol";
import "./IERC721Metadata.sol";
import "./IERC721Enumerable.sol";
import "./IERC721Receiver.sol";
import "../../introspection/ERC165.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
import "../../utils/EnumerableSet.sol";
import "../../utils/EnumerableMap.sol";
import "../../utils/Strings.sol";

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
    using SafeMath for uint256;
    using Address for address;
    using EnumerableSet for EnumerableSet.UintSet;
    using EnumerableMap for EnumerableMap.UintToAddressMap;
    using Strings for uint256;

    // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    // Mapping from holder address to their (enumerable) set of owned tokens
    mapping (address => EnumerableSet.UintSet) private _holderTokens;

    // Enumerable mapping from token ids to their owners
    EnumerableMap.UintToAddressMap private _tokenOwners;

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

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

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Optional mapping for token URIs
    mapping (uint256 => string) private _tokenURIs;

    // Base URI
    string private _baseURI;

    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
     *        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    /*
     *     bytes4(keccak256('name()')) == 0x06fdde03
     *     bytes4(keccak256('symbol()')) == 0x95d89b41
     *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
     *
     *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
     */
    bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;

    /*
     *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
     *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
     *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
     *
     *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
     */
    bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;

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

        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
        _registerInterface(_INTERFACE_ID_ERC721_METADATA);
        _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _holderTokens[owner].length();
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
    }

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

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

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

        string memory _tokenURI = _tokenURIs[tokenId];
        string memory base = baseURI();

        // If there is no base URI, return the token URI.
        if (bytes(base).length == 0) {
            return _tokenURI;
        }
        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
        if (bytes(_tokenURI).length > 0) {
            return string(abi.encodePacked(base, _tokenURI));
        }
        // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
        return string(abi.encodePacked(base, tokenId.toString()));
    }

    /**
    * @dev Returns the base URI set via {_setBaseURI}. This will be
    * automatically added as a prefix in {tokenURI} to each token's URI, or
    * to the token ID if no specific URI is set for that token ID.
    */
    function baseURI() public view virtual returns (string memory) {
        return _baseURI;
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
        return _holderTokens[owner].at(index);
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
        return _tokenOwners.length();
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
        (uint256 tokenId, ) = _tokenOwners.at(index);
        return tokenId;
    }

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

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

        _approve(to, tokenId);
    }

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

        return _tokenApprovals[tokenId];
    }

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

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

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

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

        _transfer(from, to, tokenId);
    }

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

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

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

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

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

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

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

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

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

        _holderTokens[to].add(tokenId);

        _tokenOwners.set(tokenId, to);

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

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

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

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

        // Clear metadata (if any)
        if (bytes(_tokenURIs[tokenId]).length != 0) {
            delete _tokenURIs[tokenId];
        }

        _holderTokens[owner].remove(tokenId);

        _tokenOwners.remove(tokenId);

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

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(address from, address to, uint256 tokenId) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

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

        _holderTokens[from].remove(tokenId);
        _holderTokens[to].add(tokenId);

        _tokenOwners.set(tokenId, to);

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
        require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
        _tokenURIs[tokenId] = _tokenURI;
    }

    /**
     * @dev Internal function to set the base URI for all token IDs. It is
     * automatically added as a prefix to the value returned in {tokenURI},
     * or to the token ID if {tokenURI} is empty.
     */
    function _setBaseURI(string memory baseURI_) internal virtual {
        _baseURI = baseURI_;
    }

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

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

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

File 11 of 25 : ERC721Pausable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./ERC721.sol";
import "../../utils/Pausable.sol";

/**
 * @dev ERC721 token with pausable token transfers, minting and burning.
 *
 * Useful for scenarios such as preventing trades until the end of an evaluation
 * period, or having an emergency switch for freezing all token transfers in the
 * event of a large bug.
 */
abstract contract ERC721Pausable is ERC721, Pausable {
    /**
     * @dev See {ERC721-_beforeTokenTransfer}.
     *
     * Requirements:
     *
     * - the contract must not be paused.
     */
    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override {
        super._beforeTokenTransfer(from, to, tokenId);

        require(!paused(), "ERC721Pausable: token transfer while paused");
    }
}

File 12 of 25 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "../../introspection/IERC165.sol";

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

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity >=0.6.2 <0.8.0;

import "./IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {

    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

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

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

File 14 of 25 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "./IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {

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

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

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

File 15 of 25 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

File 16 of 25 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

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

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

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

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

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

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

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

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 17 of 25 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 GSN 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 payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 18 of 25 : Counters.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../math/SafeMath.sol";

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
 * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
 * directly accessed.
 */
library Counters {
    using SafeMath for uint256;

    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        // The {SafeMath} overflow check can be skipped here, see the comment at the top
        counter._value += 1;
    }

    function decrement(Counter storage counter) internal {
        counter._value = counter._value.sub(1);
    }
}

File 19 of 25 : EnumerableMap.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Library for managing an enumerable variant of Solidity's
 * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
 * type.
 *
 * Maps have the following properties:
 *
 * - Entries are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Entries are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableMap for EnumerableMap.UintToAddressMap;
 *
 *     // Declare a set state variable
 *     EnumerableMap.UintToAddressMap private myMap;
 * }
 * ```
 *
 * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are
 * supported.
 */
library EnumerableMap {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Map type with
    // bytes32 keys and values.
    // The Map implementation uses private functions, and user-facing
    // implementations (such as Uint256ToAddressMap) are just wrappers around
    // the underlying Map.
    // This means that we can only create new EnumerableMaps for types that fit
    // in bytes32.

    struct MapEntry {
        bytes32 _key;
        bytes32 _value;
    }

    struct Map {
        // Storage of map keys and values
        MapEntry[] _entries;

        // Position of the entry defined by a key in the `entries` array, plus 1
        // because index 0 means a key is not in the map.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) {
        // We read and store the key's index to prevent multiple reads from the same storage slot
        uint256 keyIndex = map._indexes[key];

        if (keyIndex == 0) { // Equivalent to !contains(map, key)
            map._entries.push(MapEntry({ _key: key, _value: value }));
            // The entry is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            map._indexes[key] = map._entries.length;
            return true;
        } else {
            map._entries[keyIndex - 1]._value = value;
            return false;
        }
    }

    /**
     * @dev Removes a key-value pair from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function _remove(Map storage map, bytes32 key) private returns (bool) {
        // We read and store the key's index to prevent multiple reads from the same storage slot
        uint256 keyIndex = map._indexes[key];

        if (keyIndex != 0) { // Equivalent to contains(map, key)
            // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one
            // in the array, and then remove the last entry (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = keyIndex - 1;
            uint256 lastIndex = map._entries.length - 1;

            // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            MapEntry storage lastEntry = map._entries[lastIndex];

            // Move the last entry to the index where the entry to delete is
            map._entries[toDeleteIndex] = lastEntry;
            // Update the index for the moved entry
            map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved entry was stored
            map._entries.pop();

            // Delete the index for the deleted slot
            delete map._indexes[key];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function _contains(Map storage map, bytes32 key) private view returns (bool) {
        return map._indexes[key] != 0;
    }

    /**
     * @dev Returns the number of key-value pairs in the map. O(1).
     */
    function _length(Map storage map) private view returns (uint256) {
        return map._entries.length;
    }

   /**
    * @dev Returns the key-value pair stored at position `index` in the map. O(1).
    *
    * Note that there are no guarantees on the ordering of entries inside the
    * array, and it may change when more entries are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) {
        require(map._entries.length > index, "EnumerableMap: index out of bounds");

        MapEntry storage entry = map._entries[index];
        return (entry._key, entry._value);
    }

    /**
     * @dev Tries to returns the value associated with `key`.  O(1).
     * Does not revert if `key` is not in the map.
     */
    function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) {
        uint256 keyIndex = map._indexes[key];
        if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key)
        return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based
    }

    /**
     * @dev Returns the value associated with `key`.  O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function _get(Map storage map, bytes32 key) private view returns (bytes32) {
        uint256 keyIndex = map._indexes[key];
        require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key)
        return map._entries[keyIndex - 1]._value; // All indexes are 1-based
    }

    /**
     * @dev Same as {_get}, with a custom error message when `key` is not in the map.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {_tryGet}.
     */
    function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
        uint256 keyIndex = map._indexes[key];
        require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)
        return map._entries[keyIndex - 1]._value; // All indexes are 1-based
    }

    // UintToAddressMap

    struct UintToAddressMap {
        Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
        return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
        return _remove(map._inner, bytes32(key));
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
        return _contains(map._inner, bytes32(key));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToAddressMap storage map) internal view returns (uint256) {
        return _length(map._inner);
    }

   /**
    * @dev Returns the element stored at position `index` in the set. O(1).
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
        (bytes32 key, bytes32 value) = _at(map._inner, index);
        return (uint256(key), address(uint160(uint256(value))));
    }

    /**
     * @dev Tries to returns the value associated with `key`.  O(1).
     * Does not revert if `key` is not in the map.
     *
     * _Available since v3.4._
     */
    function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
        (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
        return (success, address(uint160(uint256(value))));
    }

    /**
     * @dev Returns the value associated with `key`.  O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
        return address(uint160(uint256(_get(map._inner, bytes32(key)))));
    }

    /**
     * @dev Same as {get}, with a custom error message when `key` is not in the map.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryGet}.
     */
    function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
        return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage))));
    }
}

File 20 of 25 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }


    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}

File 21 of 25 : Pausable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor () internal {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 22 of 25 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

File 23 of 25 : Strings.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

File 24 of 25 : IUniswapV2Router01.sol
pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

File 25 of 25 : IUniswapV2Router02.sol
pragma solidity >=0.6.2;

import './IUniswapV2Router01.sol';

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

Settings
{
  "remappings": [],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dna","type":"uint256"}],"name":"GenerateLuchador","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_quantity","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"generateLuchador","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"imageData","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"metadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"uint256","name":"randomness","type":"uint256"}],"name":"rawFulfillRandomness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_LinkFee","type":"uint256"}],"name":"setLinkFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapRouter","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpauseSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040527faa77729d3466ca35ae8d28b3bbac7cc36a5031efdc430821c02bc31a238af445600f55671bc16d674ec80000601055601180546001600160a01b031990811673f0d54349addcf704f77ae15b96510dea15cb7952179091556012805490911673514910771af9ca656af840dff83e8264ecf986ca1790553480156200008957600080fd5b50601154601254604080518082018252600a808252694c75636861646f72657360b01b6020808401919091528351808501909452908352694c55434841444f52455360b01b908301526001600160a01b03938416939092169190620000f56301ffc9a760e01b62001cca565b81516200010a90600690602085019062001d53565b5080516200012090600790602084019062001d53565b50620001336380ac58cd60e01b62001cca565b62000145635b5e139f60e01b62001cca565b6200015763780e9d6360e01b62001cca565b5050600a805460ff1916905560006200016f62001d4f565b600a8054610100600160a81b0319166101006001600160a01b03841690810291909117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600b556001600160601b0319606092831b811660a090815291831b166080908152600e80546001600160a01b031916737a250d5630b4cf539739df2c5dacb4c659f2488d1790556040805161018081018252600661014082018181526565626562663760d01b6101608401528252825180840184528181526518b198b2193360d11b60208281019190915283810191909152835180850185528281526518d8cc190cd960d21b81830152838501528351808501855282815265190c8c998e4d60d21b8183015296830196909652825180840184528181526538393065633160d01b81880152938201939093528151808301835283815265062c66872c8760d31b818701529381019390935280518082018252828152650c4e588d4d4d60d21b8186015260c084015280518082018252828152651899b1b0b19b60d11b8186015260e0840152805180820182528281526566376332336360d01b8186015261010084015280518082019091529081526533189c32993360d11b928101929092526101208101919091526200035f90601390600a62001dd8565b50604080516101808101825260066101408201818152653230b230b29b60d11b610160840152825282518084018452818152651899989a18b360d11b60208281019190915280840191909152835180850185528281526519584c4e0d1960d21b818301528385015283518085018552828152653298199b1cb360d11b81830152606084015283518085018552828152651c9a9898b21960d11b8183015260808401528351808501855282815265191c1a9a329b60d11b8183015260a0840152835180850185528281526531646139353160d01b8183015260c0840152835180850185528281526531316239623560d01b8183015260e0840152835180850185528281526565386236336160d01b8183015261010084015283518085019094529083526565323833323760d01b90830152610120810191909152620004a890601490600a62001dd8565b506040805161018081018252600661014082018181526533623662613560d01b6101608401528252825180840184528181526533623866613560d01b60208281019190915280840191909152835180850185528281526533626135393960d01b8183015283850152835180850185528281526533626135373760d01b818301526060840152835180850185528281526519999c9c1a1960d11b81830152608084015283518085018552828152651bb3309a99b160d11b8183015260a08401528351808501855282815265309a9c1919b160d11b8183015260c08401528351808501855282815265309a9b1c99b160d11b8183015260e084015283518085018552828152650e0d0d198c5960d21b818301526101008401528351808501909452908352651a32991c981b60d11b90830152610120810191909152620005f190601590600a62001dd8565b506040805161018081018252600661014082018181526566396431623760d01b6101608401528252825180840184528181526566376238393760d01b60208281019190915280840191909152835180850185528281526566333963373760d01b81830152838501528351808501855282815265199998d88e0d60d21b818301526060840152835180850185528281526562643765343760d01b8183015260808401528351808501855282815265311c9bb29a3160d11b8183015260a0840152835180850185528281526506239376135360d41b8183015260c084015283518085018552828152650d584ccc8c4d60d21b8183015260e0840152835180850185528281526535303237306560d01b8183015261010084015283518085019094529083526533613162303960d01b908301526101208101919091526200073a90601690600a62001dd8565b50604051806040016040528063109d5b1b60e21b6001600160a01b031916815260200160405180610100016040528060db81526020016200744b60db91399052600080526017602090815281517fd840e16649f6b9a295d95876f4633d3a6b10b55e8162971cf78afd886d5ec89b80546001600160601b03191660a09290921c9190911781558282015180519192620007f9927fd840e16649f6b9a295d95876f4633d3a6b10b55e8162971cf78afd886d5ec89c929091019062001d53565b509050506040518060400160405280652530b3bab0b960d11b6001600160a01b031916815260200160405180610120016040528060f281526020016200735960f29139905260016000526017602090815281517ff36d6bc9642eb6fb6ee9998b09ce990566df752ab06e11f8de7ab633bbd57b8f80546001600160601b03191660a09290921c9190911781558282015180519192620008be927ff36d6bc9642eb6fb6ee9998b09ce990566df752ab06e11f8de7ab633bbd57b90929091019062001d53565b50905050604051806040016040528066436c617373696360c81b6001600160a01b031916815260200160405180610100016040528060c181526020016200772a60c191399052600080526018602090815281517f999d26de3473317ead3eeaf34ca78057f1439db67b6953469c3c96ce9caf6bd780546001600160601b03191660a09290921c919091178155828201518051919262000983927f999d26de3473317ead3eeaf34ca78057f1439db67b6953469c3c96ce9caf6bd8929091019062001d53565b50905050604051806040016040528065121bdbd9195960d21b6001600160a01b031916815260200160405180610100016040528060c181526020016200772a60c19139905260016000526018602090815281517ff3794665d3af9b6fb6f858b70185898134f96768ef31c325d52e04f0ac195a4d80546001600160601b03191660a09290921c919091178155828201518051919262000a48927ff3794665d3af9b6fb6f858b70185898134f96768ef31c325d52e04f0ac195a4e929091019062001d53565b5090505060405180604001604052806414da1a5c9d60da1b6001600160a01b031916815260200160405180610120016040528060e18152602001620070ee60e191399052600080526019602090815281517fd2ac945fcc0096878c763e37d6929b78378c1a2defabde8ba7ee5ed1d6e7a5b280546001600160601b03191660a09290921c919091178155828201518051919262000b0b927fd2ac945fcc0096878c763e37d6929b78378c1a2defabde8ba7ee5ed1d6e7a5b3929091019062001d53565b5090505060405180604001604052806913dc195b8814da1a5c9d60b21b6001600160a01b031916815260200160405180610120016040528060ff81526020016200762b60ff9139905260016000526019602090815281517ffc941c3961fb6541da34150022cddf959da0fb2353866a6bfbd249c2da09291480546001600160601b03191660a09290921c919091178155828201518051919262000bd4927ffc941c3961fb6541da34150022cddf959da0fb2353866a6bfbd249c2da092915929091019062001d53565b5090505060405180604001604052806614da5b99db195d60ca1b6001600160a01b03191681526020016040518060c00160405280608181526020016200790460819139905260026000526019602090815281517f6f678ad17c55bce407239525f4bf7f1fe99197d3eb69bfdd9a0db84a9a11b58180546001600160601b03191660a09290921c919091178155828201518051919262000c99927f6f678ad17c55bce407239525f4bf7f1fe99197d3eb69bfdd9a0db84a9a11b582929091019062001d53565b5090505060405180604001604052806953757370656e6465727360b01b6001600160a01b03191681526020016040518060a001604052806079815260200162007a6160799139905260036000526019602090815281517f3e323a6e0522b016fa22111dfed945f89456f9f44f69eac00209d92607a5b94080546001600160601b03191660a09290921c919091178155828201518051919262000d61927f3e323a6e0522b016fa22111dfed945f89456f9f44f69eac00209d92607a5b941929091019062001d53565b50905050604051806040016040528065476c6f76657360d01b6001600160a01b03191681526020016040518060c00160405280608f815260200162006f34608f9139905260008052601a602090815281517fb75ecc04ed35f89790e98640e901bda41eceff0cb896cf2765fb69768025375080546001600160601b03191660a09290921c919091178155828201518051919262000e24927fb75ecc04ed35f89790e98640e901bda41eceff0cb896cf2765fb697680253751929091019062001d53565b5090505060405180604001604052806a57726973742042616e647360a81b6001600160a01b0319168152602001604051806080016040528060418152602001620072eb6041913990526001600052601a602090815281517ff88cd8d612926ebb404e40725c01084b6e9b3ce0344cde068570342cbd448c6180546001600160601b03191660a09290921c919091178155828201518051919262000eed927ff88cd8d612926ebb404e40725c01084b6e9b3ce0344cde068570342cbd448c62929091019062001d53565b50905050604051806040016040528069149a59da1d0810985b9960b21b6001600160a01b03191681526020016040518060600160405280602d81526020016200732c602d913990526002600052601a602090815281517f4c287b3e2c2cb129ae3ba596d613d760b15affdac7242e12903c37a886ea1c4f80546001600160601b03191660a09290921c919091178155828201518051919262000fb5927f4c287b3e2c2cb129ae3ba596d613d760b15affdac7242e12903c37a886ea1c50929091019062001d53565b509050506040518060400160405280681319599d0810985b9960ba1b6001600160a01b031916815260200160405180606001604052806030815260200162006f046030913990526003600052601a602090815281517f4ac83fca211703e3ddb90093cd219714e5e3715bf0b4fd15b0441390534a24e280546001600160601b03191660a09290921c91909117815582820151805191926200107c927f4ac83fca211703e3ddb90093cd219714e5e3715bf0b4fd15b0441390534a24e3929091019062001d53565b5090505060405180604001604052806841726d2042616e647360b81b6001600160a01b03191681526020016040518060600160405280603f8152602001620075ec603f913990526004600052601a602090815281517f06b28f262ad931a15c9e47271fc159a891b2bcb0da2659cac5bbfed4886cf26e80546001600160601b03191660a09290921c919091178155828201518051919262001143927f06b28f262ad931a15c9e47271fc159a891b2bcb0da2659cac5bbfed4886cf26f929091019062001d53565b50905050604051806040016040528066536c656576657360c81b6001600160a01b03191681526020016040518060c0016040528060818152602001620070046081913990526005600052601a602090815281517f82f07edc09f3a46c1925d02252613a7fcc7be7d03b538b0c268df85f2f13a7ab80546001600160601b03191660a09290921c919091178155828201518051919262001208927f82f07edc09f3a46c1925d02252613a7fcc7be7d03b538b0c268df85f2f13a7ac929091019062001d53565b5090505060405180604001604052806414dc1b1a5d60da1b6001600160a01b03191681526020016040518060600160405280603a8152602001620077eb603a9139905260008052601b602090815281517f584f46c60af19681376031579adb04a2416e54ee5505351c2a8435e3766026ea80546001600160601b03191660a09290921c9190911781558282015180519192620012ca927f584f46c60af19681376031579adb04a2416e54ee5505351c2a8435e3766026eb929091019062001d53565b5090505060405180604001604052806443726f737360d81b6001600160a01b03191681526020016040518060600160405280603d8152602001620075af603d913990526001600052601b602090815281517f9fafca4c9c0d5c2cbf85f49fd8ab8212430ce78c2a0cb75b51e0f9c4f9ace00380546001600160601b03191660a09290921c91909117815582820151805191926200138d927f9fafca4c9c0d5c2cbf85f49fd8ab8212430ce78c2a0cb75b51e0f9c4f9ace004929091019062001d53565b5090505060405180604001604052806546696572636560d01b6001600160a01b0319168152602001604051806080016040528060538152602001620079856053913990526002600052601b602090815281517f1dd2f4b94a51cfb409e6e317a497f7cfd9013960a1c723f830c49c05a25f08a580546001600160601b03191660a09290921c919091178155828201518051919262001451927f1dd2f4b94a51cfb409e6e317a497f7cfd9013960a1c723f830c49c05a25f08a6929091019062001d53565b5090505060405180604001604052806614dd1c9a5c195960ca1b6001600160a01b03191681526020016040518060e0016040528060a881526020016200785c60a8913990526003600052601b602090815281517f804a3d0621e73505f5f0c57c922f3e57d6b48e175551184eb12f80d7b4a9c78380546001600160601b03191660a09290921c919091178155828201518051919262001516927f804a3d0621e73505f5f0c57c922f3e57d6b48e175551184eb12f80d7b4a9c784929091019062001d53565b50905050604051806040016040528063109bdb1d60e21b6001600160a01b031916815260200160405180608001604052806057815260200162007b4c6057913990526004600052601b602090815281517fa952f8c0f40734b22d2328e0f7ff57eeffee78885b9cf2147ff941cc37e1c86e80546001600160601b03191660a09290921c9190911781558282015180519192620015d8927fa952f8c0f40734b22d2328e0f7ff57eeffee78885b9cf2147ff941cc37e1c86f929091019062001d53565b5090505060405180604001604052806515da5b99d95960d21b6001600160a01b03191681526020016040518060a001604052806072815260200162007ada6072913990526005600052601b602090815281517fb48400cb19cf39e58355a7c9fd856f9b5b7298c53856a6766c6b39755ccafa7980546001600160601b03191660a09290921c91909117815582820151805191926200169c927fb48400cb19cf39e58355a7c9fd856f9b5b7298c53856a6766c6b39755ccafa7a929091019062001d53565b50905050604051806040016040528066436c617373696360c81b6001600160a01b03191681526020016040518060a0016040528060698152602001620070856069913990526006600052601b602090815281517ff5ddd0b8f160eab91dc4f82b50a485a96cf6ab0bfb38460d73171763afb6d5cf80546001600160601b03191660a09290921c919091178155828201518051919262001761927ff5ddd0b8f160eab91dc4f82b50a485a96cf6ab0bfb38460d73171763afb6d5d0929091019062001d53565b509050506040518060400160405280644172726f7760d81b6001600160a01b03191681526020016040518060c0016040528060898152602001620075266089913990526007600052601b602090815281517f6fa0adbc19babfec7e85ff6417830cdb284ababb3de438515569d7f3d9b3493180546001600160601b03191660a09290921c919091178155828201518051919262001824927f6fa0adbc19babfec7e85ff6417830cdb284ababb3de438515569d7f3d9b34932929091019062001d53565b50905050604051806040016040528063088c2e6d60e31b6001600160a01b03191681526020016040518060e0016040528060a78152602001620071cf60a7913990526008600052601b602090815281517f90dc0d05fc750d51b3e484087edb4e9beb1a58b38bc8386c0e048690482d89ed80546001600160601b03191660a09290921c9190911781558282015180519192620018e6927f90dc0d05fc750d51b3e484087edb4e9beb1a58b38bc8386c0e048690482d89ee929091019062001d53565b509050506040518060400160405280684d6f7573746163686560b81b6001600160a01b031916815260200160405180608001604052806041815260200162007a2060419139905260008052601c602090815281517fb9c6de81004e18dedadca3e5eabaab449ca91dff6f58efc9461da635fe77f84980546001600160601b03191660a09290921c9190911781558282015180519192620019ac927fb9c6de81004e18dedadca3e5eabaab449ca91dff6f58efc9461da635fe77f84a929091019062001d53565b5090505060405180604001604052806554696768747360d01b6001600160a01b03191681526020016040518060600160405280603781526020016200782560379139905260008052601d602090815281517f0a51588b1664495f089dd83d2d26f247920f94a57a4a09f20cf068efc8f82bd480546001600160601b03191660a09290921c919091178155828201518051919262001a6f927f0a51588b1664495f089dd83d2d26f247920f94a57a4a09f20cf068efc8f82bd5929091019062001d53565b5090505060405180604001604052806b5472756e6b2054696768747360a01b6001600160a01b03191681526020016040518060a0016040528060758152602001620072766075913990526001600052601d602090815281517f9de6abd965d55c3bb0cdbf6fa175050624c6ff8fe86f682dc08f2a450ede227880546001600160601b03191660a09290921c919091178155828201518051919262001b39927f9de6abd965d55c3bb0cdbf6fa175050624c6ff8fe86f682dc08f2a450ede2279929091019062001d53565b5090505060405180604001604052806754776f20546f6e6560c01b6001600160a01b0319168152602001604051806080016040528060488152602001620079d860489139905260008052601e602090815281517f65ce8396b736f5da9d881cc6fbcb11ef9721292dc41ec8c40879fd9edea5744d80546001600160601b03191660a09290921c919091178155828201518051919262001bfe927f65ce8396b736f5da9d881cc6fbcb11ef9721292dc41ec8c40879fd9edea5744e929091019062001d53565b50905050604051806040016040528063090d2ced60e31b6001600160a01b031916815260200160405180608001604052806041815260200162006fc36041913990526001600052601e602090815281517f873299c6a6c39b8b92f01922bb622df4a3236ea2876aac2da76f6c092cf7e98f80546001600160601b03191660a09290921c919091178155828201518051919262001cc0927f873299c6a6c39b8b92f01922bb622df4a3236ea2876aac2da76f6c092cf7e990929091019062001d53565b5090505062001ebb565b6001600160e01b0319808216141562001d2a576040805162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015290519081900360640190fd5b6001600160e01b0319166000908152602081905260409020805460ff19166001179055565b3390565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1062001d9657805160ff191683800117855562001dc6565b8280016001018555821562001dc6579182015b8281111562001dc657825182559160200191906001019062001da9565b5062001dd492915062001e38565b5090565b82805482825590600052602060002090810192821562001e2a579160200282015b8281111562001e2a578251805162001e1991849160209091019062001d53565b509160200191906001019062001df9565b5062001dd492915062001e4f565b5b8082111562001dd4576000815560010162001e39565b8082111562001dd457600062001e66828262001e70565b5060010162001e4f565b50805460018160011615610100020316600290046000825580601f1062001e98575062001eb8565b601f01602090049060005260206000209081019062001eb8919062001e38565b50565b60805160601c60a05160601c61501562001eef60003980611a865280613b605250806136645280613b3152506150156000f3fe6080604052600436106101dc5760003560e01c80636352211e11610102578063a22cb46511610095578063cd8ff65711610064578063cd8ff657146107cd578063e3684e39146107f7578063e985e9c514610821578063f2fde38b1461085c576101e3565b8063a22cb46514610680578063b88d4fde146106bb578063bb33d7291461078e578063c87b56dd146107a3576101e3565b8063735de9f7116100d1578063735de9f7146106115780638da5cb5b1461062657806394985ddd1461063b57806395d89b411461066b576101e3565b80636352211e1461058a5780636c0360eb146105b457806370a08231146105c9578063715018a6146105fc576101e3565b80632f745c591161017a57806355367ba91161014957806355367ba91461048a57806355f804b31461049f5780635a0a3a56146105525780635c975abb14610575576101e3565b80632f745c59146103cf5780633ccfd60b1461040857806342842e0e1461041d5780634f6ccce714610460576101e3565b8063081812fc116101b6578063081812fc146102e4578063095ea7b31461032a57806318160ddd1461036557806323b872dd1461038c576101e3565b806301ffc9a7146101e8578063061ba2f11461023057806306fdde03146102cf576101e3565b366101e357005b600080fd5b3480156101f457600080fd5b5061021c6004803603602081101561020b57600080fd5b50356001600160e01b03191661088f565b604080519115158252519081900360200190f35b34801561023c57600080fd5b5061025a6004803603602081101561025357600080fd5b50356108b2565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029457818101518382015260200161027c565b50505050905090810190601f1680156102c15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156102db57600080fd5b5061025a611012565b3480156102f057600080fd5b5061030e6004803603602081101561030757600080fd5b50356110a8565b604080516001600160a01b039092168252519081900360200190f35b34801561033657600080fd5b506103636004803603604081101561034d57600080fd5b506001600160a01b03813516906020013561110a565b005b34801561037157600080fd5b5061037a6111e5565b60408051918252519081900360200190f35b34801561039857600080fd5b50610363600480360360608110156103af57600080fd5b506001600160a01b038135811691602081013590911690604001356111f6565b3480156103db57600080fd5b5061037a600480360360408110156103f257600080fd5b506001600160a01b03813516906020013561124d565b34801561041457600080fd5b50610363611278565b34801561042957600080fd5b506103636004803603606081101561044057600080fd5b506001600160a01b0381358116916020810135909116906040013561136e565b34801561046c57600080fd5b5061037a6004803603602081101561048357600080fd5b5035611389565b34801561049657600080fd5b5061036361139f565b3480156104ab57600080fd5b50610363600480360360208110156104c257600080fd5b8101906020810181356401000000008111156104dd57600080fd5b8201836020820111156104ef57600080fd5b8035906020019184600183028401116401000000008311171561051157600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061140b945050505050565b6103636004803603604081101561056857600080fd5b5080359060200135611476565b34801561058157600080fd5b5061021c6118ac565b34801561059657600080fd5b5061030e600480360360208110156105ad57600080fd5b50356118b5565b3480156105c057600080fd5b5061025a6118dd565b3480156105d557600080fd5b5061037a600480360360208110156105ec57600080fd5b50356001600160a01b031661193e565b34801561060857600080fd5b506103636119a6565b34801561061d57600080fd5b5061030e611a58565b34801561063257600080fd5b5061030e611a67565b34801561064757600080fd5b506103636004803603604081101561065e57600080fd5b5080359060200135611a7b565b34801561067757600080fd5b5061025a611b06565b34801561068c57600080fd5b50610363600480360360408110156106a357600080fd5b506001600160a01b0381351690602001351515611b67565b3480156106c757600080fd5b50610363600480360360808110156106de57600080fd5b6001600160a01b0382358116926020810135909116916040820135919081019060808101606082013564010000000081111561071957600080fd5b82018360208201111561072b57600080fd5b8035906020019184600183028401116401000000008311171561074d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611c6c945050505050565b34801561079a57600080fd5b50610363611cca565b3480156107af57600080fd5b5061025a600480360360208110156107c657600080fd5b5035611d34565b3480156107d957600080fd5b50610363600480360360208110156107f057600080fd5b5035611e75565b34801561080357600080fd5b5061025a6004803603602081101561081a57600080fd5b5035611edc565b34801561082d57600080fd5b5061021c6004803603604081101561084457600080fd5b506001600160a01b0381358116916020013516612bb9565b34801561086857600080fd5b506103636004803603602081101561087f57600080fd5b50356001600160a01b0316612be7565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b60606108bd82612cf5565b61090e576040805162461bcd60e51b815260206004820152601c60248201527f696d616765446174613a206e6f6e6578697374656e7420746f6b656e00000000604482015290519081900360640190fd5b6000828152601f602052604090205461096e576040805162461bcd60e51b815260206004820181905260248201527f696d616765446174613a20646e61206e6f74207965742067656e657261746564604482015290519081900360640190fd5b610976614518565b6000838152601f602052604090205461098e90612d02565b90506060816001602002015160ff1615806109b05750602082015160ff166001145b6109c957604051806020016040528060008152506109e3565b6040518060c00160405280609d8152602001614eaa609d91395b90506060826001602002015160ff16600114610a0e5760405180602001604052806000815250610a2b565b60405180610180016040528061014c8152602001614c6e61014c91395b9050610a3685612d50565b610a408685612e2b565b845160ff9081166000908152601760209081526040808320828a01518516845260188352818420828b0151861685526019845282852060608c015187168652601a855283862060808d015188168752601b865284872060a08e015189168852601c875285882060c08f01519099168852601d9096529386206001938401979284019691840195948401948c94908101938c939082019290910190601e908f6007602002015160ff1681526020019081526020016000206001016040516020018080701e39bb339034b21e93b63ab1b430b237b960791b8152506011018d805190602001908083835b60208310610b475780518252601f199092019160209182019101610b28565b6001836020036101000a03801982511681845116808217855250505050505090500180614f78603991396039018c805190602001908083835b60208310610b9f5780518252601f199092019160209182019101610b80565b6001836020036101000a038019825116818451168082178552505050505050905001807f3c6720636c6173733d276c756368612d62726561746865273e000000000000008152506019018b805460018160011615610100020316600290048015610c405780601f10610c1e576101008083540402835291820191610c40565b820191906000526020600020905b815481529060010190602001808311610c2c575b50508a805460018160011615610100020316600290048015610c995780601f10610c77576101008083540402835291820191610c99565b820191906000526020600020905b815481529060010190602001808311610c85575b505080614dfd60ad913960ad0189805460018160011615610100020316600290048015610cfd5780601f10610cdb576101008083540402835291820191610cfd565b820191906000526020600020905b815481529060010190602001808311610ce9575b505088805460018160011615610100020316600290048015610d565780601f10610d34576101008083540402835291820191610d56565b820191906000526020600020905b815481529060010190602001808311610d42575b5050875160208901908083835b60208310610d825780518252601f199092019160209182019101610d63565b6001836020036101000a03801982511681845116808217855250505050505090500180614bcc6072913960720180741e339031b630b9b99e93b63ab1b43096b0b63a139f60591b81525060150186805460018160011615610100020316600290048015610e265780601f10610e04576101008083540402835291820191610e26565b820191906000526020600020905b815481529060010190602001808311610e12575b505080631e17b39f60e11b81525060040185805190602001908083835b60208310610e625780518252601f199092019160209182019101610e43565b6001836020036101000a0380198251168184511680821785525050505050509050018061477960de913960de01602f614fb18239602f01603661465b823960360184805460018160011615610100020316600290048015610efa5780601f10610ed8576101008083540402835291820191610efa565b820191906000526020600020905b815481529060010190602001808311610ee6575b5050631e17b39f60e11b8152600401603f6148578239603f0160416148ee823960410183805460018160011615610100020316600290048015610f745780601f10610f52576101008083540402835291820191610f74565b820191906000526020600020905b815481529060010190602001808311610f60575b505080614b0b6049913960490182805460018160011615610100020316600290048015610fd85780601f10610fb6576101008083540402835291820191610fd8565b820191906000526020600020905b815481529060010190602001808311610fc4575b505080651e17b9bb339f60d11b8152506006019c505050505050505050505050506040516020818303038152906040529350505050919050565b60068054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561109e5780601f106110735761010080835404028352916020019161109e565b820191906000526020600020905b81548152906001019060200180831161108157829003601f168201915b5050505050905090565b60006110b382612cf5565b6110ee5760405162461bcd60e51b815260040180806020018281038252602c815260200180614adf602c913960400191505060405180910390fd5b506000908152600460205260409020546001600160a01b031690565b6000611115826118b5565b9050806001600160a01b0316836001600160a01b031614156111685760405162461bcd60e51b8152600401808060200182810382526021815260200180614dba6021913960400191505060405180910390fd5b806001600160a01b031661117a6132f5565b6001600160a01b0316148061119b575061119b816111966132f5565b612bb9565b6111d65760405162461bcd60e51b81526004018080602001828103825260388152602001806149a56038913960400191505060405180910390fd5b6111e083836132f9565b505050565b60006111f16002613367565b905090565b6112076112016132f5565b82613372565b6112425760405162461bcd60e51b8152600401808060200182810382526031815260200180614f476031913960400191505060405180910390fd5b6111e0838383613416565b6001600160a01b038216600090815260016020526040812061126f9083613562565b90505b92915050565b6112806132f5565b6001600160a01b0316611291611a67565b6001600160a01b0316146112da576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b604051600090339047908381818185875af1925050503d806000811461131c576040519150601f19603f3d011682016040523d82523d6000602084013e611321565b606091505b505090508061136b576040805162461bcd60e51b815260206004820152601160248201527015da5d1a191c985dd85b0819985a5b1959607a1b604482015290519081900360640190fd5b50565b6111e083838360405180602001604052806000815250611c6c565b60008061139760028461356e565b509392505050565b6113a76132f5565b6001600160a01b03166113b8611a67565b6001600160a01b031614611401576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b61140961358a565b565b6114136132f5565b6001600160a01b0316611424611a67565b6001600160a01b03161461146d576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b61136b8161362a565b6002600b5414156114ce576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600b556114db6118ac565b15611520576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b61271061152d600d61363d565b1061157f576040805162461bcd60e51b815260206004820152601a60248201527f6d6178696d756d206c75636861646f7265732072656163686564000000000000604482015290519081900360640190fd5b6127108261158d600d61363d565b0111156115e1576040805162461bcd60e51b815260206004820181905260248201527f6d696e74207175616e746974792065786365656473206d617820737570706c79604482015290519081900360640190fd5b6000821180156115f2575060148211155b61162d5760405162461bcd60e51b8152600401808060200182810382526022815260200180614ddb6022913960400191505060405180910390fd5b6010546040805160028082526060808301845293860293926020830190803683375050600e54604080516315ab88c960e31b815290519394506001600160a01b039091169263ad5c464892506004808301926020929190829003018186803b15801561169857600080fd5b505afa1580156116ac573d6000803e3d6000fd5b505050506040513d60208110156116c257600080fd5b5051815182906000906116d157fe5b6001600160a01b0392831660209182029290920101526012548251911690829060019081106116fc57fe5b6001600160a01b03928316602091820292909201810191909152600e5460405163fb3bdb4160e01b815260048101868152306044830181905260648301899052608060248401908152875160848501528751949096169563fb3bdb419534958a958a958d949093909260a490920191878201910280838360005b8381101561178e578181015183820152602001611776565b50505050905001955050505050506000604051808303818588803b1580156117b557600080fd5b505af11580156117c9573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f1916820160405260208110156117f357600080fd5b810190808051604051939291908464010000000082111561181357600080fd5b90830190602082018581111561182857600080fd5b825186602082028301116401000000008211171561184557600080fd5b82525081516020918201928201910280838360005b8381101561187257818101518382015260200161185a565b505050509050016040525050505060005b848110156118a0576118984382900340613641565b600101611883565b50506001600b55505050565b600a5460ff1690565b600061127282604051806060016040528060298152602001614a076029913960029190613781565b60098054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561109e5780601f106110735761010080835404028352916020019161109e565b60006001600160a01b0382166119855760405162461bcd60e51b815260040180806020018281038252602a8152602001806149dd602a913960400191505060405180910390fd5b6001600160a01b038216600090815260016020526040902061127290613367565b6119ae6132f5565b6001600160a01b03166119bf611a67565b6001600160a01b031614611a08576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b600a5460405160009161010090046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600a8054610100600160a81b0319169055565b600e546001600160a01b031681565b600a5461010090046001600160a01b031690565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611af8576040805162461bcd60e51b815260206004820152601f60248201527f4f6e6c7920565246436f6f7264696e61746f722063616e2066756c66696c6c00604482015290519081900360640190fd5b611b02828261378e565b5050565b60078054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561109e5780601f106110735761010080835404028352916020019161109e565b611b6f6132f5565b6001600160a01b0316826001600160a01b03161415611bd5576040805162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015290519081900360640190fd5b8060056000611be26132f5565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff191692151592909217909155611c266132f5565b6001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318360405180821515815260200191505060405180910390a35050565b611c7d611c776132f5565b83613372565b611cb85760405162461bcd60e51b8152600401808060200182810382526031815260200180614f476031913960400191505060405180910390fd5b611cc4848484846137ea565b50505050565b611cd26132f5565b6001600160a01b0316611ce3611a67565b6001600160a01b031614611d2c576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b61140961383c565b6060611d3f82612cf5565b611d7a5760405162461bcd60e51b815260040180806020018281038252602f815260200180614b9d602f913960400191505060405180910390fd5b6060611d846118dd565b90506000815111611da45760405180602001604052806000815250611e6e565b80611dae84612d50565b6040516020018083805190602001908083835b60208310611de05780518252601f199092019160209182019101611dc1565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310611e285780518252601f199092019160209182019101611e09565b6001836020036101000a0380198251168184511680821785525050505050509050018064173539b7b760d91b815250600501925050506040516020818303038152906040525b9392505050565b611e7d6132f5565b6001600160a01b0316611e8e611a67565b6001600160a01b031614611ed7576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b601055565b6060611ee782612cf5565b611f38576040805162461bcd60e51b815260206004820152601b60248201527f6d657461646174613a206e6f6e6578697374656e7420746f6b656e0000000000604482015290519081900360640190fd5b6000828152601f6020526040902054611f98576040805162461bcd60e51b815260206004820152601f60248201527f6d657461646174613a20646e61206e6f74207965742067656e65726174656400604482015290519081900360640190fd5b611fa0614518565b6000838152601f6020526040902054611fb890612d02565b9050611fc2614537565b60408051610100808201808452855160ff166000908152601760209081529085902061014085018652805460a01b6001600160a01b0319168352600180820180548851600293821615909702600019011691909104601f8101849004840286018401909752868552949586959394919361012087019390919083018282801561208c5780601f106120615761010080835404028352916020019161208c565b820191906000526020600020905b81548152906001019060200180831161206f57829003601f168201915b50505091909252505050815260208481015160ff1660009081526018825260409081902081518083018352815460a01b6001600160a01b0319168152600180830180548551600261010094831615949094026000190190911692909204601f810187900487028301870190955284825295850195919492938584019391929183018282801561215c5780601f106121315761010080835404028352916020019161215c565b820191906000526020600020905b81548152906001019060200180831161213f57829003601f168201915b50505091909252505050815260408481015160ff166000908152601960209081529082902082518084018452815460a01b6001600160a01b0319168152600180830180548651600261010094831615949094026000190190911692909204601f81018690048602830186019096528582529584019591949293858101939192919083018282801561222e5780601f106122035761010080835404028352916020019161222e565b820191906000526020600020905b81548152906001019060200180831161221157829003601f168201915b505050919092525050508152606084015160ff166000908152601a602090815260409182902082518084018452815460a01b6001600160a01b0319168152600180830180548651600261010094831615949094026000190190911692909204601f8101869004860283018601909652858252958401959194929385810193919291908301828280156123015780601f106122d657610100808354040283529160200191612301565b820191906000526020600020905b8154815290600101906020018083116122e457829003601f168201915b505050919092525050508152608084015160ff166000908152601b602090815260409182902082518084018452815460a01b6001600160a01b0319168152600180830180548651600261010094831615949094026000190190911692909204601f8101869004860283018601909652858252958401959194929385810193919291908301828280156123d45780601f106123a9576101008083540402835291602001916123d4565b820191906000526020600020905b8154815290600101906020018083116123b757829003601f168201915b50505091909252505050815260a08481015160ff166000908152601c602090815260409182902082518084018452815490941b6001600160a01b0319168452600180820180548551600261010094831615949094026000190190911692909204601f8101859004850283018501909552848252958301959193858401939192918301828280156124a55780601f1061247a576101008083540402835291602001916124a5565b820191906000526020600020905b81548152906001019060200180831161248857829003601f168201915b50505091909252505050815260c084015160ff166000908152601d602090815260409182902082518084018452815460a01b6001600160a01b0319168152600180830180548651600261010094831615949094026000190190911692909204601f8101869004860283018601909652858252958401959194929385810193919291908301828280156125785780601f1061254d57610100808354040283529160200191612578565b820191906000526020600020905b81548152906001019060200180831161255b57829003601f168201915b50505091909252505050815260e084015160ff166000908152601e602090815260409182902082518084018452815460a01b6001600160a01b0319168152600180830180548651600261010094831615949094026000190190911692909204601f81018690048602830186019096528582529584019591949293858101939192919083018282801561264b5780601f106126205761010080835404028352916020019161264b565b820191906000526020600020905b81548152906001019060200180831161262e57829003601f168201915b50505050508152505081525090506060612663614565565b506040805161014081018252600661010082019081526514dc1a5c9a5d60d21b6101208301528152815180830183526004808252634361706560e01b6020838101919091528084019290925283518085018552600580825264546f72736f60d81b8285015284860191909152845180860186528281526341726d7360e01b81850152606085015284518086018652918252634d61736b60e01b828401526080840191909152835180850185528181526409adeeae8d60db1b8184015260a0840152835180850185526007815266426f74746f6d7360c81b8184015260c08401528351808501909452835264426f6f747360d81b9083015260e081019190915260005b60088110156129a15783816008811061277a57fe5b6020020151516001600160a01b03191661279357612999565b8283516000146127be57604051806040016040528060038152602001622c207b60e81b8152506127d9565b604051806040016040528060018152602001607b60f81b8152505b8383600881106127e557fe5b60200201516128048785600881106127f957fe5b6020020151516138bf565b6040516020018085805190602001908083835b602083106128365780518252601f199092019160209182019101612817565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b6020831061287e5780518252601f19909201916020918201910161285f565b51815160209384036101000a60001901801990921691161790526e113a3930b4ba2fba3cb832911d101160891b919093019081528551600f90910192860191508083835b602083106128e15780518252601f1990920191602091820191016128c2565b51815160209384036101000a600019018019909216911617905261088b60f21b9190930190815269113b30b63ab2911d101160b11b60028201528451600c90910192850191508083835b6020831061294a5780518252601f19909201916020918201910161292b565b5181516020939093036101000a6000190180199091169216919091179052601160f91b920191825250607d60f81b600182015260408051808303601d1901815260029092019052975050505050505b600101612765565b506129ab86612d50565b6129b4876108b2565b6129bd88612d50565b604051607b60f81b602080830191825272226e616d65223a20224c75636861646f72202360681b602184015285518893603401918701908083835b60208310612a175780518252601f1990920191602091820191016129f8565b5181516020939093036101000a600019018019909116921691909117905261088b60f21b920191825250600201608d614a528239608d01806e1134b6b0b3b2afb230ba30911d101160891b815250600f0184805190602001908083835b60208310612a935780518252601f199092019160209182019101612a74565b5181516020939093036101000a600019018019909116921691909117905261088b60f21b9201918252506002016030614c3e823960300183805190602001908083835b60208310612af55780518252601f199092019160209182019101612ad6565b51815160209384036101000a600019018019909216911617905261088b60f21b919093019081526e2261747472696275746573223a205b60881b60028201528451601190910192850191508083835b60208310612b635780518252601f199092019160209182019101612b44565b5181516020939093036101000a6000190180199091169216919091179052605d60f81b920191825250607d60f81b600182015260408051808303601d19018152600290920190529b9a5050505050505050505050565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b612bef6132f5565b6001600160a01b0316612c00611a67565b6001600160a01b031614612c49576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b6001600160a01b038116612c8e5760405162461bcd60e51b81526004018080602001828103825260268152602001806148c86026913960400191505060405180910390fd5b600a546040516001600160a01b0380841692610100900416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600a80546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60006112726002836139c5565b612d0a614518565b612d12614518565b60005b600c811015612d4957600a84068282600c8110612d2e57fe5b60ff9092166020929092020152600a84049350600101612d15565b5092915050565b606081612d7557506040805180820190915260018152600360fc1b60208201526108ad565b8160005b8115612d8d57600101600a82049150612d79565b60608167ffffffffffffffff81118015612da657600080fd5b506040519080825280601f01601f191660200182016040528015612dd1576020820181803683370190505b50859350905060001982015b8315612e2257600a840660300160f81b82828060019003935081518110612e0057fe5b60200101906001600160f81b031916908160001a905350600a84049350612ddd565b50949350505050565b6060612e3683612d50565b6013836008602002015160ff1681548110612e4d57fe5b90600052602060002001612e6085612d50565b6014856009602002015160ff1681548110612e7757fe5b90600052602060002001612e8a87612d50565b601587600a602002015160ff1681548110612ea157fe5b90600052602060002001612eb489612d50565b601689600b602002015160ff1681548110612ecb57fe5b90600052602060002001612ede8b612d50565b60405160200180806f1e39ba3cb6329f11b63ab1b430b237b960811b8152506010018a805190602001908083835b60208310612f2b5780518252601f199092019160209182019101612f0c565b6001836020036101000a0380198251168184511680821785525050505050509050018075202e6c756368612d62617365207b2066696c6c3a202360501b81525060160189805460018160011615610100020316600290048015612fc55780601f10612fa3576101008083540402835291820191612fc5565b820191906000526020600020905b815481529060010190602001808311612fb1575b5050806c1d903e9011b63ab1b430b237b960991b815250600d0188805190602001908083835b6020831061300a5780518252601f199092019160209182019101612feb565b6001836020036101000a0380198251168184511680821785525050505050509050018074202e6c756368612d616c74207b2066696c6c3a202360581b815250601501878054600181600116156101000203166002900480156130a35780601f106130815761010080835404028352918201916130a3565b820191906000526020600020905b81548152906001019060200180831161308f575b5050806c1d903e9011b63ab1b430b237b960991b815250600d0186805190602001908083835b602083106130e85780518252601f1990920191602091820191016130c9565b6001836020036101000a0380198251168184511680821785525050505050509050018075202e6c756368612d65796573207b2066696c6c3a202360501b815250601601858054600181600116156101000203166002900480156131825780601f10613160576101008083540402835291820191613182565b820191906000526020600020905b81548152906001019060200180831161316e575b5050806c1d903e9011b63ab1b430b237b960991b815250600d0184805190602001908083835b602083106131c75780518252601f1990920191602091820191016131a8565b6001836020036101000a0380198251168184511680821785525050505050509050018075202e6c756368612d736b696e207b2066696c6c3a202360501b815250601601838054600181600116156101000203166002900480156132615780601f1061323f576101008083540402835291820191613261565b820191906000526020600020905b81548152906001019060200180831161324d575b5050806c1d903e9011b63ab1b430b237b960991b815250600d0182805190602001908083835b602083106132a65780518252601f199092019160209182019101613287565b6001836020036101000a038019825116818451168082178552505050505050905001806146bc60bd913960bd019950505050505050505050604051602081830303815290604052905092915050565b3390565b600081815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061332e826118b5565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006112728261363d565b600061337d82612cf5565b6133b85760405162461bcd60e51b815260040180806020018281038252602c815260200180614979602c913960400191505060405180910390fd5b60006133c3836118b5565b9050806001600160a01b0316846001600160a01b031614806133fe5750836001600160a01b03166133f3846110a8565b6001600160a01b0316145b8061340e575061340e8185612bb9565b949350505050565b826001600160a01b0316613429826118b5565b6001600160a01b03161461346e5760405162461bcd60e51b8152600401808060200182810382526029815260200180614b746029913960400191505060405180910390fd5b6001600160a01b0382166134b35760405162461bcd60e51b815260040180806020018281038252602481526020018061492f6024913960400191505060405180910390fd5b6134be8383836139d1565b6134c96000826132f9565b6001600160a01b03831660009081526001602052604090206134eb9082613a20565b506001600160a01b038216600090815260016020526040902061350e9082613a2c565b5061351b60028284613a38565b5080826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b600061126f8383613a4e565b600080808061357d8686613ab2565b9097909650945050505050565b6135926118ac565b156135d7576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b600a805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861360d6132f5565b604080516001600160a01b039092168252519081900360200190a1565b8051611b0290600990602084019061458d565b5490565b601054604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a08231916024808301926020929190829003018186803b1580156136aa57600080fd5b505afa1580156136be573d6000803e3d6000fd5b505050506040513d60208110156136d457600080fd5b50511015613729576040805162461bcd60e51b815260206004820152601f60248201527f4e6f7420656e6f756768204c494e4b202d2066696c6c20636f6e747261637400604482015290519081900360640190fd5b600061373a600f5460105484613b2d565b9050613746600d613ce0565b604051806020016040528061375b600d61363d565b90526000828152602080526040902090519055611b023361377c600d61363d565b613ce9565b600061340e848484613d03565b60008281526020808052604080832080548452601f83528184208590559285905281805291548251848152925190927f1d584699e20b45cf7fb70771dbd92bb407c244dd750faf0d3c3108aaae7d0e7292908290030190a25050565b6137f5848484613416565b61380184848484613dcd565b611cc45760405162461bcd60e51b81526004018080602001828103825260328152602001806148966032913960400191505060405180910390fd5b6138446118ac565b61388c576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b600a805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61360d6132f5565b606060005b600c8160ff161080156138f25750828160ff16600c81106138e157fe5b1a60f81b6001600160f81b03191615155b156138ff576001016138c4565b60608160ff1667ffffffffffffffff8111801561391b57600080fd5b506040519080825280601f01601f191660200182016040528015613946576020820181803683370190505b509050600091505b600c8260ff1610801561397c5750838260ff16600c811061396b57fe5b1a60f81b6001600160f81b03191615155b15611e6e57838260ff16600c811061399057fe5b1a60f81b818360ff16815181106139a357fe5b60200101906001600160f81b031916908160001a90535060019091019061394e565b600061126f8383613f35565b6139dc8383836111e0565b6139e46118ac565b156111e05760405162461bcd60e51b815260040180806020018281038252602b815260200180614691602b913960400191505060405180910390fd5b600061126f8383613f4d565b600061126f8383614013565b600061340e84846001600160a01b03851661405d565b81546000908210613a905760405162461bcd60e51b81526004018080602001828103825260228152602001806146396022913960400191505060405180910390fd5b826000018281548110613a9f57fe5b9060005260206000200154905092915050565b815460009081908310613af65760405162461bcd60e51b8152600401808060200182810382526022815260200180614a306022913960400191505060405180910390fd5b6000846000018481548110613b0757fe5b906000526020600020906002020190508060000154816001015492509250509250929050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634000aea07f000000000000000000000000000000000000000000000000000000000000000085878660405160200180838152602001828152602001925050506040516020818303038152906040526040518463ffffffff1660e01b815260040180846001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015613c09578181015183820152602001613bf1565b50505050905090810190601f168015613c365780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b158015613c5757600080fd5b505af1158015613c6b573d6000803e3d6000fd5b505050506040513d6020811015613c8157600080fd5b50506000848152600c6020526040812054613ca1908690859030906140f4565b6000868152600c6020526040902054909150613cbe90600161413b565b6000868152600c6020526040902055613cd78582614195565b95945050505050565b80546001019055565b611b028282604051806020016040528060008152506141c1565b60008281526001840160205260408120548281613d9e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613d63578181015183820152602001613d4b565b50505050905090810190601f168015613d905780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50846000016001820381548110613db157fe5b9060005260206000209060020201600101549150509392505050565b6000613de1846001600160a01b0316614213565b613ded5750600161340e565b6060613efb630a85bd0160e11b613e026132f5565b88878760405160240180856001600160a01b03168152602001846001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015613e69578181015183820152602001613e51565b50505050905090810190601f168015613e965780820380516001836020036101000a031916815260200191505b5095505050505050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050604051806060016040528060328152602001614896603291396001600160a01b0388169190614219565b90506000818060200190516020811015613f1457600080fd5b50516001600160e01b031916630a85bd0160e11b1492505050949350505050565b60009081526001919091016020526040902054151590565b600081815260018301602052604081205480156140095783546000198083019190810190600090879083908110613f8057fe5b9060005260206000200154905080876000018481548110613f9d57fe5b600091825260208083209091019290925582815260018981019092526040902090840190558654879080613fcd57fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611272565b6000915050611272565b600061401f8383613f35565b61405557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611272565b506000611272565b6000828152600184016020526040812054806140c2575050604080518082018252838152602080820184815286546001818101895560008981528481209551600290930290950191825591519082015586548684528188019092529290912055611e6e565b828560000160018303815481106140d557fe5b9060005260206000209060020201600101819055506000915050611e6e565b60408051602080820196909652808201949094526001600160a01b039290921660608401526080808401919091528151808403909101815260a09092019052805191012090565b60008282018381101561126f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b6141cb8383614228565b6141d86000848484613dcd565b6111e05760405162461bcd60e51b81526004018080602001828103825260328152602001806148966032913960400191505060405180910390fd5b3b151590565b606061340e8484600085614356565b6001600160a01b038216614283576040805162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015290519081900360640190fd5b61428c81612cf5565b156142de576040805162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015290519081900360640190fd5b6142ea600083836139d1565b6001600160a01b038216600090815260016020526040902061430c9082613a2c565b5061431960028284613a38565b5060405181906001600160a01b038416906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6060824710156143975760405162461bcd60e51b81526004018080602001828103825260268152602001806149536026913960400191505060405180910390fd5b6143a085614213565b6143f1576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106144305780518252601f199092019160209182019101614411565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614492576040519150601f19603f3d011682016040523d82523d6000602084013e614497565b606091505b50915091506144a78282866144b2565b979650505050505050565b606083156144c1575081611e6e565b8251156144d15782518084602001fd5b60405162461bcd60e51b8152602060048201818152845160248401528451859391928392604401919085019080838360008315613d63578181015183820152602001613d4b565b604051806101800160405280600c906020820280368337509192915050565b6040518061010001604052806008905b61454f61460b565b8152602001906001900390816145475790505090565b6040518061010001604052806008905b60608152602001906001900390816145755790505090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106145ce57805160ff19168380011785556145fb565b828001600101855582156145fb579182015b828111156145fb5782518255916020019190600101906145e0565b50614607929150614623565b5090565b60408051808201909152600081526060602082015290565b5b80821115614607576000815560010161462456fe456e756d657261626c655365743a20696e646578206f7574206f6620626f756e64733c706174682066696c6c3d272330303027206f7061636974793d272e392720643d274d3133203131682d3376316834762d317a272f3e4552433732315061757361626c653a20746f6b656e207472616e73666572207768696c6520706175736564202e6c756368612d62726561746865207b20616e696d6174696f6e3a20302e3573206c756368612d6272656174686520696e66696e69746520616c7465726e61746520656173652d696e2d6f75743b207d20406b65796672616d6573206c756368612d62726561746865207b2066726f6d207b207472616e73666f726d3a207472616e736c6174655928307078293b207d20746f207b207472616e73666f726d3a207472616e736c61746559283125293b207d207d3c2f7374796c653e3c706174682066696c6c3d27234646462720643d274d39203648367633683456367a4d31372036682d337633683456367a272f3e3c7061746820636c6173733d276c756368612d657965732720643d274d31362036682d327633683356367a4d382036483776336833563648397a272f3e3c706174682066696c6c3d27234646462720643d274d3720366831763148377a4d3136203668317631682d317a27206f7061636974793d272e34272f3e3c706174682066696c6c3d27233030302720643d274d3135203768317631682d317a4d3820376831763148387a272f3e3c7061746820636c6173733d276c756368612d736b696e2720643d274d3136203233762d3648387636483776316834762d34683276346834762d317a272f3e4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573733c7061746820636c6173733d276c756368612d626173652720643d274d31352031374838763168317631683276316832762d316832762d316831762d317a272f3e4552433732313a207472616e7366657220746f20746865207a65726f2061646472657373416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656420666f7220616c6c4552433732313a2062616c616e636520717565727920666f7220746865207a65726f20616464726573734552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656e456e756d657261626c654d61703a20696e646578206f7574206f6620626f756e6473226465736372697074696f6e223a20224c75636861646f726573206172652072616e646f6d6c792067656e657261746564207573696e6720436861696e6c696e6b2056524620616e6420686176652031303025206f6e2d636861696e2061727420616e64206d65746164617461202d204f6e6c792031303030302077696c6c206576657220657869737421222c4552433732313a20617070726f76656420717565727920666f72206e6f6e6578697374656e7420746f6b656e3c7061746820636c6173733d276c756368612d626173652720643d274d3920323148387632483776316834762d33682d317a4d3136203233762d32682d3376336834762d317a272f3e4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65724552433732313a207472616e73666572206f6620746f6b656e2074686174206973206e6f74206f776e4552433732314d657461646174613a2055524920717565727920666f72206e6f6e6578697374656e7420746f6b656e3c7061746820636c6173733d276c756368612d626173652720643d274d313820355633682d315632682d315631682d3156304839763148387631483776314836763248357635683176326831763168317631683176316836762d316831762d316831762d316831762d32683156357a272f3e2265787465726e616c5f75726c223a202268747470733a2f2f6c75636861646f7265732e696f2f6c75636861646f722f3c7061746820636c6173733d276c756368612d616c742720643d274d313820345633682d315632682d315631682d3156304839763148387631483776314836763248357635683156366831563568325634683156336834763168317631683276316831763468315635682d317a272f3e3c672066696c6c3d2723303030273e3c7061746820643d274d313820345633682d315632682d315631682d3156304839763148387631483776314836763248357635683156356831563468315633683156326836763168317631683176316831763568315635682d317a27206f7061636974793d272e32272f3e3c7061746820643d274d313620345633682d31563248397631483876314837763168325634683156336834763168317631683256347a4d3620356831763148367a4d3137203568317631682d317a27206f7061636974793d272e35272f3e3c2f673e4552433732313a20617070726f76616c20746f2063757272656e74206f776e65726d696e74207175616e74697479206d757374206265206265747765656e20312d32303c7061746820636c6173733d276c756368612d736b696e2720643d274d3232203132762d31682d31762d31682d315639682d315635682d315633682d315632682d315631682d3156304839763148387631483776314836763248357634483476314833763148327631483176386834762d316831762d324835762d336831763168317631683176326838762d326831762d316831762d3168317633682d317632683176316834762d387a272f3e3c7061746820636c6173733d276c756368612d616c742720643d274d32302031305639682d327631682d3176316834762d317a4d35203948347631483376316834762d31483656397a272f3e3c706174682066696c6c3d272330303027206f7061636974793d272e322720643d274d36203948347631483376316834762d3148367a4d32302031305639682d327631682d3176316834762d317a272f3e4552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665642720786d6c6e733d27687474703a2f2f7777772e77332e6f72672f323030302f737667272076696577426f783d27302030203234203234273e3c7061746820636c6173733d276c756368612d736b696e2720643d274d3134203130483976336836762d337a272f3ea2646970667358221220f07ff78f47503188bddd1cb2cc6410513aab09c35bef87db8e84d77cf54338e964736f6c634300060c00333c7061746820636c6173733d276c756368612d626173652720643d274d3232203134682d3376316834762d317a272f3e3c7061746820636c6173733d276c756368612d626173652720643d274d35203136483176336834762d316831762d3148357a4d3232203136682d337631682d317631683176316834762d337a272f3e3c7061746820636c6173733d276c756368612d616c742720643d274d33203136483176316834762d3148347a4d3232203136682d3376316834762d317a272f3e3c7061746820636c6173733d276c756368612d616c742720643d274d39203230483876316833762d31682d317a4d3135203230682d3276316833762d317a272f3e3c7061746820636c6173733d276c756368612d626173652720643d274d3232203134682d3376336834762d337a4d33203134483176336834762d3348347a272f3e3c7061746820636c6173733d276c756368612d616c742720643d274d3232203134682d3376316834762d317a4d33203134483176316834762d3148347a272f3e3c7061746820643d274d313820355633682d315632682d317632682d317631682d317631682d317633682d325636682d31563548395634483856324837763148367632483576346831763168327633683176316836762d316831762d3368325639683156357a272f3e3c7061746820636c6173733d276c756368612d626173652720643d274d3232203132762d31682d31762d31682d315639483476314833763148327631483176356834762d336831763168317631683176326838762d326831762d316831762d31683176336834762d357a272f3e3c7061746820643d274d3232203132762d31682d31762d31682d315639483476314833763148327631483176356834762d336831763168317631683176326838762d326831762d316831762d31683176336834762d357a272066696c6c3d272330303027206f7061636974793d272e3135272f3e3c7061746820643d274d313320335632682d32763268327a4d313320315630682d32763168317a4d313020344839563148387631483776314836763248357635683176326831763168317631683176316831762d324839762d3368325635682d317a4d313820355633682d315632682d315631682d317633682d317631682d31763568327633682d3176326831762d316831762d316831762d316831762d32683156357a272f3e3c7061746820636c6173733d276c756368612d626173652720643d274d3135203137483876336838762d337a272f3e3c7061746820636c6173733d276c756368612d616c742720643d274d31352031387631682d3276346833762d357a4d39203139762d31483876356833762d34682d317a272f3e3c7061746820636c6173733d276c756368612d626173652720643d274d33203135483176326834762d3248347a4d3232203135682d3376326834762d327a272f3e3c7061746820636c6173733d276c756368612d616c742720643d274d34203134483176316834762d317a272f3e3c7061746820636c6173733d276c756368612d626173652720643d274d36203256314835763568315635683156336831563248377a4d313820317631682d3276316831763268317631683156317a272f3e3c672066696c6c3d2723303030273e3c7061746820643d274d3520316831763148357a4d36203276316832563248377a4d3138203168317631682d317a4d31362032763168325632682d317a27206f7061636974793d272e33272f3e3c7061746820643d274d36203356324835763468315635683156337a4d313820327631682d31763268317631683156327a27206f7061636974793d272e32272f3e3c2f673e3c706174682066696c6c3d27234139413138412720643d274d323120325631682d315630682d31763268317631682d3376326832763168325635683156327a4d352033483456326831563048347631483376314832763368317631683256356832563348367a272f3e3c672066696c6c3d272330303027206f7061636974793d272e3135273e3c7061746820643d274d3231203468317631682d317a4d31392035682d31763168335635682d317a272f3e3c7061746820643d274d3220346831763148327a4d342035483376316833563548357a272f3e3c2f673e3c7061746820643d274d313820355633682d315632682d315631682d3156304839763148387631483776314836763248357635683176326831763168317631683176316831762d3468315635483956336831563268315631683276316831763168317632682d327636683176346831762d316831762d316831762d316831762d32683156357a272f3e3c7061746820643d274d31342032682d315630682d327632483976326832763468325634683256327a4d3132203133682d3176326832762d327a272f3e3c7061746820636c6173733d276c756368612d626173652720643d274d34203134483176316834762d317a4d3232203134682d3376316834762d317a272f3e3c7061746820636c6173733d276c756368612d626173652720643d274d31302039483476314833763148327631483176336834762d31683176316831763168317632683356397a4d3232203132762d31682d31762d31682d315639682d3776396833762d326831762d316831762d31683176316834762d337a272f3e3c7061746820643d274d31302039483476314833763148327631483176336834762d31683176316831763168317632683356397a4d3232203132762d31682d31762d31682d315639682d3776396833762d326831762d316831762d31683176316834762d337a272066696c6c3d272330303027206f7061636974793d272e3135272f3e3c7061746820636c6173733d276c756368612d616c742720643d274d323020313148337631326831762d316832762d3168313276316832763168315631317a272f3e3c672066696c6c3d2723303030273e3c70617468206f7061636974793d272e322720643d274d323020313176313268315631317a4d33203132763131683156313148337a272f3e3c70617468206f7061636974793d272e352720643d274d313920313148347631316832762d31683132763168325631317a272f3e3c2f673e3c7061746820643d274d31312030483976314838763148377631483676324835763568317632683176316831763168317631683356307a272f3e3c7061746820636c6173733d276c756368612d616c742720643d274d3135203137483876366833762d33683276336833762d367a272f3e3c7061746820643d274d313120326832563168315630682d34763168317a4d3620313076326831762d316831762d3148377a4d3137203130682d317631683176316831762d327a272f3e3c7061746820643d274d3136203368315632682d315631682d317631682d317631682d317631682d325633682d3156324839563148387631483776316831763168317631683176316831763968325636683156356831563468317a272f3e3c7061746820636c6173733d276c756368612d626173652720643d274d313620394837763368312d317634683176316838762d316831762d34682d31203156397a272f3e3c706174682066696c6c3d272330303027206f7061636974793d272e31352720643d274d3136203948377637683176316838762d31683156397a272f3e3c7061746820643d274d313720337631682d327631682d317631682d317633683556337a4d313120385636682d31563548395634483756334836763668357a4d313120313376326832762d32682d317a272f3e3c7061746820636c6173733d276c756368612d616c742720643d274d3920323248387631483776316834762d32682d317a4d3136203233762d31682d3376326834762d317a272f3e3c706174682066696c6c3d272334323163303327206f7061636974793d272e392720643d274d3134203130483976336831762d32683476326831762d337a272f3e3c7061746820636c6173733d276c756368612d626173652720643d274d313520397639683156397a4d3820313076386831563948387a272f3e3c7061746820643d274d3820313076386831563948387a4d313520397639683156397a272066696c6c3d272330303027206f7061636974793d272e3135272f3e3c7061746820643d274d313820355633682d315632682d317631682d317631682d317631682d317631682d325635682d3156344839563348385632483776314836763248357635683176326831762d316831762d31683356396832763168337631683176316831762d32683156357a272f3e3c7061746820643d274d31332033682d335632683156316831563048397631483876314837763148367632683376314838763248377632683156396831563868315637683156366831563568315634683156337a272f3e

Deployed Bytecode

0x6080604052600436106101dc5760003560e01c80636352211e11610102578063a22cb46511610095578063cd8ff65711610064578063cd8ff657146107cd578063e3684e39146107f7578063e985e9c514610821578063f2fde38b1461085c576101e3565b8063a22cb46514610680578063b88d4fde146106bb578063bb33d7291461078e578063c87b56dd146107a3576101e3565b8063735de9f7116100d1578063735de9f7146106115780638da5cb5b1461062657806394985ddd1461063b57806395d89b411461066b576101e3565b80636352211e1461058a5780636c0360eb146105b457806370a08231146105c9578063715018a6146105fc576101e3565b80632f745c591161017a57806355367ba91161014957806355367ba91461048a57806355f804b31461049f5780635a0a3a56146105525780635c975abb14610575576101e3565b80632f745c59146103cf5780633ccfd60b1461040857806342842e0e1461041d5780634f6ccce714610460576101e3565b8063081812fc116101b6578063081812fc146102e4578063095ea7b31461032a57806318160ddd1461036557806323b872dd1461038c576101e3565b806301ffc9a7146101e8578063061ba2f11461023057806306fdde03146102cf576101e3565b366101e357005b600080fd5b3480156101f457600080fd5b5061021c6004803603602081101561020b57600080fd5b50356001600160e01b03191661088f565b604080519115158252519081900360200190f35b34801561023c57600080fd5b5061025a6004803603602081101561025357600080fd5b50356108b2565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029457818101518382015260200161027c565b50505050905090810190601f1680156102c15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156102db57600080fd5b5061025a611012565b3480156102f057600080fd5b5061030e6004803603602081101561030757600080fd5b50356110a8565b604080516001600160a01b039092168252519081900360200190f35b34801561033657600080fd5b506103636004803603604081101561034d57600080fd5b506001600160a01b03813516906020013561110a565b005b34801561037157600080fd5b5061037a6111e5565b60408051918252519081900360200190f35b34801561039857600080fd5b50610363600480360360608110156103af57600080fd5b506001600160a01b038135811691602081013590911690604001356111f6565b3480156103db57600080fd5b5061037a600480360360408110156103f257600080fd5b506001600160a01b03813516906020013561124d565b34801561041457600080fd5b50610363611278565b34801561042957600080fd5b506103636004803603606081101561044057600080fd5b506001600160a01b0381358116916020810135909116906040013561136e565b34801561046c57600080fd5b5061037a6004803603602081101561048357600080fd5b5035611389565b34801561049657600080fd5b5061036361139f565b3480156104ab57600080fd5b50610363600480360360208110156104c257600080fd5b8101906020810181356401000000008111156104dd57600080fd5b8201836020820111156104ef57600080fd5b8035906020019184600183028401116401000000008311171561051157600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061140b945050505050565b6103636004803603604081101561056857600080fd5b5080359060200135611476565b34801561058157600080fd5b5061021c6118ac565b34801561059657600080fd5b5061030e600480360360208110156105ad57600080fd5b50356118b5565b3480156105c057600080fd5b5061025a6118dd565b3480156105d557600080fd5b5061037a600480360360208110156105ec57600080fd5b50356001600160a01b031661193e565b34801561060857600080fd5b506103636119a6565b34801561061d57600080fd5b5061030e611a58565b34801561063257600080fd5b5061030e611a67565b34801561064757600080fd5b506103636004803603604081101561065e57600080fd5b5080359060200135611a7b565b34801561067757600080fd5b5061025a611b06565b34801561068c57600080fd5b50610363600480360360408110156106a357600080fd5b506001600160a01b0381351690602001351515611b67565b3480156106c757600080fd5b50610363600480360360808110156106de57600080fd5b6001600160a01b0382358116926020810135909116916040820135919081019060808101606082013564010000000081111561071957600080fd5b82018360208201111561072b57600080fd5b8035906020019184600183028401116401000000008311171561074d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611c6c945050505050565b34801561079a57600080fd5b50610363611cca565b3480156107af57600080fd5b5061025a600480360360208110156107c657600080fd5b5035611d34565b3480156107d957600080fd5b50610363600480360360208110156107f057600080fd5b5035611e75565b34801561080357600080fd5b5061025a6004803603602081101561081a57600080fd5b5035611edc565b34801561082d57600080fd5b5061021c6004803603604081101561084457600080fd5b506001600160a01b0381358116916020013516612bb9565b34801561086857600080fd5b506103636004803603602081101561087f57600080fd5b50356001600160a01b0316612be7565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b60606108bd82612cf5565b61090e576040805162461bcd60e51b815260206004820152601c60248201527f696d616765446174613a206e6f6e6578697374656e7420746f6b656e00000000604482015290519081900360640190fd5b6000828152601f602052604090205461096e576040805162461bcd60e51b815260206004820181905260248201527f696d616765446174613a20646e61206e6f74207965742067656e657261746564604482015290519081900360640190fd5b610976614518565b6000838152601f602052604090205461098e90612d02565b90506060816001602002015160ff1615806109b05750602082015160ff166001145b6109c957604051806020016040528060008152506109e3565b6040518060c00160405280609d8152602001614eaa609d91395b90506060826001602002015160ff16600114610a0e5760405180602001604052806000815250610a2b565b60405180610180016040528061014c8152602001614c6e61014c91395b9050610a3685612d50565b610a408685612e2b565b845160ff9081166000908152601760209081526040808320828a01518516845260188352818420828b0151861685526019845282852060608c015187168652601a855283862060808d015188168752601b865284872060a08e015189168852601c875285882060c08f01519099168852601d9096529386206001938401979284019691840195948401948c94908101938c939082019290910190601e908f6007602002015160ff1681526020019081526020016000206001016040516020018080701e39bb339034b21e93b63ab1b430b237b960791b8152506011018d805190602001908083835b60208310610b475780518252601f199092019160209182019101610b28565b6001836020036101000a03801982511681845116808217855250505050505090500180614f78603991396039018c805190602001908083835b60208310610b9f5780518252601f199092019160209182019101610b80565b6001836020036101000a038019825116818451168082178552505050505050905001807f3c6720636c6173733d276c756368612d62726561746865273e000000000000008152506019018b805460018160011615610100020316600290048015610c405780601f10610c1e576101008083540402835291820191610c40565b820191906000526020600020905b815481529060010190602001808311610c2c575b50508a805460018160011615610100020316600290048015610c995780601f10610c77576101008083540402835291820191610c99565b820191906000526020600020905b815481529060010190602001808311610c85575b505080614dfd60ad913960ad0189805460018160011615610100020316600290048015610cfd5780601f10610cdb576101008083540402835291820191610cfd565b820191906000526020600020905b815481529060010190602001808311610ce9575b505088805460018160011615610100020316600290048015610d565780601f10610d34576101008083540402835291820191610d56565b820191906000526020600020905b815481529060010190602001808311610d42575b5050875160208901908083835b60208310610d825780518252601f199092019160209182019101610d63565b6001836020036101000a03801982511681845116808217855250505050505090500180614bcc6072913960720180741e339031b630b9b99e93b63ab1b43096b0b63a139f60591b81525060150186805460018160011615610100020316600290048015610e265780601f10610e04576101008083540402835291820191610e26565b820191906000526020600020905b815481529060010190602001808311610e12575b505080631e17b39f60e11b81525060040185805190602001908083835b60208310610e625780518252601f199092019160209182019101610e43565b6001836020036101000a0380198251168184511680821785525050505050509050018061477960de913960de01602f614fb18239602f01603661465b823960360184805460018160011615610100020316600290048015610efa5780601f10610ed8576101008083540402835291820191610efa565b820191906000526020600020905b815481529060010190602001808311610ee6575b5050631e17b39f60e11b8152600401603f6148578239603f0160416148ee823960410183805460018160011615610100020316600290048015610f745780601f10610f52576101008083540402835291820191610f74565b820191906000526020600020905b815481529060010190602001808311610f60575b505080614b0b6049913960490182805460018160011615610100020316600290048015610fd85780601f10610fb6576101008083540402835291820191610fd8565b820191906000526020600020905b815481529060010190602001808311610fc4575b505080651e17b9bb339f60d11b8152506006019c505050505050505050505050506040516020818303038152906040529350505050919050565b60068054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561109e5780601f106110735761010080835404028352916020019161109e565b820191906000526020600020905b81548152906001019060200180831161108157829003601f168201915b5050505050905090565b60006110b382612cf5565b6110ee5760405162461bcd60e51b815260040180806020018281038252602c815260200180614adf602c913960400191505060405180910390fd5b506000908152600460205260409020546001600160a01b031690565b6000611115826118b5565b9050806001600160a01b0316836001600160a01b031614156111685760405162461bcd60e51b8152600401808060200182810382526021815260200180614dba6021913960400191505060405180910390fd5b806001600160a01b031661117a6132f5565b6001600160a01b0316148061119b575061119b816111966132f5565b612bb9565b6111d65760405162461bcd60e51b81526004018080602001828103825260388152602001806149a56038913960400191505060405180910390fd5b6111e083836132f9565b505050565b60006111f16002613367565b905090565b6112076112016132f5565b82613372565b6112425760405162461bcd60e51b8152600401808060200182810382526031815260200180614f476031913960400191505060405180910390fd5b6111e0838383613416565b6001600160a01b038216600090815260016020526040812061126f9083613562565b90505b92915050565b6112806132f5565b6001600160a01b0316611291611a67565b6001600160a01b0316146112da576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b604051600090339047908381818185875af1925050503d806000811461131c576040519150601f19603f3d011682016040523d82523d6000602084013e611321565b606091505b505090508061136b576040805162461bcd60e51b815260206004820152601160248201527015da5d1a191c985dd85b0819985a5b1959607a1b604482015290519081900360640190fd5b50565b6111e083838360405180602001604052806000815250611c6c565b60008061139760028461356e565b509392505050565b6113a76132f5565b6001600160a01b03166113b8611a67565b6001600160a01b031614611401576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b61140961358a565b565b6114136132f5565b6001600160a01b0316611424611a67565b6001600160a01b03161461146d576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b61136b8161362a565b6002600b5414156114ce576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600b556114db6118ac565b15611520576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b61271061152d600d61363d565b1061157f576040805162461bcd60e51b815260206004820152601a60248201527f6d6178696d756d206c75636861646f7265732072656163686564000000000000604482015290519081900360640190fd5b6127108261158d600d61363d565b0111156115e1576040805162461bcd60e51b815260206004820181905260248201527f6d696e74207175616e746974792065786365656473206d617820737570706c79604482015290519081900360640190fd5b6000821180156115f2575060148211155b61162d5760405162461bcd60e51b8152600401808060200182810382526022815260200180614ddb6022913960400191505060405180910390fd5b6010546040805160028082526060808301845293860293926020830190803683375050600e54604080516315ab88c960e31b815290519394506001600160a01b039091169263ad5c464892506004808301926020929190829003018186803b15801561169857600080fd5b505afa1580156116ac573d6000803e3d6000fd5b505050506040513d60208110156116c257600080fd5b5051815182906000906116d157fe5b6001600160a01b0392831660209182029290920101526012548251911690829060019081106116fc57fe5b6001600160a01b03928316602091820292909201810191909152600e5460405163fb3bdb4160e01b815260048101868152306044830181905260648301899052608060248401908152875160848501528751949096169563fb3bdb419534958a958a958d949093909260a490920191878201910280838360005b8381101561178e578181015183820152602001611776565b50505050905001955050505050506000604051808303818588803b1580156117b557600080fd5b505af11580156117c9573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f1916820160405260208110156117f357600080fd5b810190808051604051939291908464010000000082111561181357600080fd5b90830190602082018581111561182857600080fd5b825186602082028301116401000000008211171561184557600080fd5b82525081516020918201928201910280838360005b8381101561187257818101518382015260200161185a565b505050509050016040525050505060005b848110156118a0576118984382900340613641565b600101611883565b50506001600b55505050565b600a5460ff1690565b600061127282604051806060016040528060298152602001614a076029913960029190613781565b60098054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561109e5780601f106110735761010080835404028352916020019161109e565b60006001600160a01b0382166119855760405162461bcd60e51b815260040180806020018281038252602a8152602001806149dd602a913960400191505060405180910390fd5b6001600160a01b038216600090815260016020526040902061127290613367565b6119ae6132f5565b6001600160a01b03166119bf611a67565b6001600160a01b031614611a08576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b600a5460405160009161010090046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600a8054610100600160a81b0319169055565b600e546001600160a01b031681565b600a5461010090046001600160a01b031690565b336001600160a01b037f000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb79521614611af8576040805162461bcd60e51b815260206004820152601f60248201527f4f6e6c7920565246436f6f7264696e61746f722063616e2066756c66696c6c00604482015290519081900360640190fd5b611b02828261378e565b5050565b60078054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561109e5780601f106110735761010080835404028352916020019161109e565b611b6f6132f5565b6001600160a01b0316826001600160a01b03161415611bd5576040805162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015290519081900360640190fd5b8060056000611be26132f5565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff191692151592909217909155611c266132f5565b6001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318360405180821515815260200191505060405180910390a35050565b611c7d611c776132f5565b83613372565b611cb85760405162461bcd60e51b8152600401808060200182810382526031815260200180614f476031913960400191505060405180910390fd5b611cc4848484846137ea565b50505050565b611cd26132f5565b6001600160a01b0316611ce3611a67565b6001600160a01b031614611d2c576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b61140961383c565b6060611d3f82612cf5565b611d7a5760405162461bcd60e51b815260040180806020018281038252602f815260200180614b9d602f913960400191505060405180910390fd5b6060611d846118dd565b90506000815111611da45760405180602001604052806000815250611e6e565b80611dae84612d50565b6040516020018083805190602001908083835b60208310611de05780518252601f199092019160209182019101611dc1565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310611e285780518252601f199092019160209182019101611e09565b6001836020036101000a0380198251168184511680821785525050505050509050018064173539b7b760d91b815250600501925050506040516020818303038152906040525b9392505050565b611e7d6132f5565b6001600160a01b0316611e8e611a67565b6001600160a01b031614611ed7576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b601055565b6060611ee782612cf5565b611f38576040805162461bcd60e51b815260206004820152601b60248201527f6d657461646174613a206e6f6e6578697374656e7420746f6b656e0000000000604482015290519081900360640190fd5b6000828152601f6020526040902054611f98576040805162461bcd60e51b815260206004820152601f60248201527f6d657461646174613a20646e61206e6f74207965742067656e65726174656400604482015290519081900360640190fd5b611fa0614518565b6000838152601f6020526040902054611fb890612d02565b9050611fc2614537565b60408051610100808201808452855160ff166000908152601760209081529085902061014085018652805460a01b6001600160a01b0319168352600180820180548851600293821615909702600019011691909104601f8101849004840286018401909752868552949586959394919361012087019390919083018282801561208c5780601f106120615761010080835404028352916020019161208c565b820191906000526020600020905b81548152906001019060200180831161206f57829003601f168201915b50505091909252505050815260208481015160ff1660009081526018825260409081902081518083018352815460a01b6001600160a01b0319168152600180830180548551600261010094831615949094026000190190911692909204601f810187900487028301870190955284825295850195919492938584019391929183018282801561215c5780601f106121315761010080835404028352916020019161215c565b820191906000526020600020905b81548152906001019060200180831161213f57829003601f168201915b50505091909252505050815260408481015160ff166000908152601960209081529082902082518084018452815460a01b6001600160a01b0319168152600180830180548651600261010094831615949094026000190190911692909204601f81018690048602830186019096528582529584019591949293858101939192919083018282801561222e5780601f106122035761010080835404028352916020019161222e565b820191906000526020600020905b81548152906001019060200180831161221157829003601f168201915b505050919092525050508152606084015160ff166000908152601a602090815260409182902082518084018452815460a01b6001600160a01b0319168152600180830180548651600261010094831615949094026000190190911692909204601f8101869004860283018601909652858252958401959194929385810193919291908301828280156123015780601f106122d657610100808354040283529160200191612301565b820191906000526020600020905b8154815290600101906020018083116122e457829003601f168201915b505050919092525050508152608084015160ff166000908152601b602090815260409182902082518084018452815460a01b6001600160a01b0319168152600180830180548651600261010094831615949094026000190190911692909204601f8101869004860283018601909652858252958401959194929385810193919291908301828280156123d45780601f106123a9576101008083540402835291602001916123d4565b820191906000526020600020905b8154815290600101906020018083116123b757829003601f168201915b50505091909252505050815260a08481015160ff166000908152601c602090815260409182902082518084018452815490941b6001600160a01b0319168452600180820180548551600261010094831615949094026000190190911692909204601f8101859004850283018501909552848252958301959193858401939192918301828280156124a55780601f1061247a576101008083540402835291602001916124a5565b820191906000526020600020905b81548152906001019060200180831161248857829003601f168201915b50505091909252505050815260c084015160ff166000908152601d602090815260409182902082518084018452815460a01b6001600160a01b0319168152600180830180548651600261010094831615949094026000190190911692909204601f8101869004860283018601909652858252958401959194929385810193919291908301828280156125785780601f1061254d57610100808354040283529160200191612578565b820191906000526020600020905b81548152906001019060200180831161255b57829003601f168201915b50505091909252505050815260e084015160ff166000908152601e602090815260409182902082518084018452815460a01b6001600160a01b0319168152600180830180548651600261010094831615949094026000190190911692909204601f81018690048602830186019096528582529584019591949293858101939192919083018282801561264b5780601f106126205761010080835404028352916020019161264b565b820191906000526020600020905b81548152906001019060200180831161262e57829003601f168201915b50505050508152505081525090506060612663614565565b506040805161014081018252600661010082019081526514dc1a5c9a5d60d21b6101208301528152815180830183526004808252634361706560e01b6020838101919091528084019290925283518085018552600580825264546f72736f60d81b8285015284860191909152845180860186528281526341726d7360e01b81850152606085015284518086018652918252634d61736b60e01b828401526080840191909152835180850185528181526409adeeae8d60db1b8184015260a0840152835180850185526007815266426f74746f6d7360c81b8184015260c08401528351808501909452835264426f6f747360d81b9083015260e081019190915260005b60088110156129a15783816008811061277a57fe5b6020020151516001600160a01b03191661279357612999565b8283516000146127be57604051806040016040528060038152602001622c207b60e81b8152506127d9565b604051806040016040528060018152602001607b60f81b8152505b8383600881106127e557fe5b60200201516128048785600881106127f957fe5b6020020151516138bf565b6040516020018085805190602001908083835b602083106128365780518252601f199092019160209182019101612817565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b6020831061287e5780518252601f19909201916020918201910161285f565b51815160209384036101000a60001901801990921691161790526e113a3930b4ba2fba3cb832911d101160891b919093019081528551600f90910192860191508083835b602083106128e15780518252601f1990920191602091820191016128c2565b51815160209384036101000a600019018019909216911617905261088b60f21b9190930190815269113b30b63ab2911d101160b11b60028201528451600c90910192850191508083835b6020831061294a5780518252601f19909201916020918201910161292b565b5181516020939093036101000a6000190180199091169216919091179052601160f91b920191825250607d60f81b600182015260408051808303601d1901815260029092019052975050505050505b600101612765565b506129ab86612d50565b6129b4876108b2565b6129bd88612d50565b604051607b60f81b602080830191825272226e616d65223a20224c75636861646f72202360681b602184015285518893603401918701908083835b60208310612a175780518252601f1990920191602091820191016129f8565b5181516020939093036101000a600019018019909116921691909117905261088b60f21b920191825250600201608d614a528239608d01806e1134b6b0b3b2afb230ba30911d101160891b815250600f0184805190602001908083835b60208310612a935780518252601f199092019160209182019101612a74565b5181516020939093036101000a600019018019909116921691909117905261088b60f21b9201918252506002016030614c3e823960300183805190602001908083835b60208310612af55780518252601f199092019160209182019101612ad6565b51815160209384036101000a600019018019909216911617905261088b60f21b919093019081526e2261747472696275746573223a205b60881b60028201528451601190910192850191508083835b60208310612b635780518252601f199092019160209182019101612b44565b5181516020939093036101000a6000190180199091169216919091179052605d60f81b920191825250607d60f81b600182015260408051808303601d19018152600290920190529b9a5050505050505050505050565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b612bef6132f5565b6001600160a01b0316612c00611a67565b6001600160a01b031614612c49576040805162461bcd60e51b81526020600482018190526024820152600080516020614b54833981519152604482015290519081900360640190fd5b6001600160a01b038116612c8e5760405162461bcd60e51b81526004018080602001828103825260268152602001806148c86026913960400191505060405180910390fd5b600a546040516001600160a01b0380841692610100900416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600a80546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60006112726002836139c5565b612d0a614518565b612d12614518565b60005b600c811015612d4957600a84068282600c8110612d2e57fe5b60ff9092166020929092020152600a84049350600101612d15565b5092915050565b606081612d7557506040805180820190915260018152600360fc1b60208201526108ad565b8160005b8115612d8d57600101600a82049150612d79565b60608167ffffffffffffffff81118015612da657600080fd5b506040519080825280601f01601f191660200182016040528015612dd1576020820181803683370190505b50859350905060001982015b8315612e2257600a840660300160f81b82828060019003935081518110612e0057fe5b60200101906001600160f81b031916908160001a905350600a84049350612ddd565b50949350505050565b6060612e3683612d50565b6013836008602002015160ff1681548110612e4d57fe5b90600052602060002001612e6085612d50565b6014856009602002015160ff1681548110612e7757fe5b90600052602060002001612e8a87612d50565b601587600a602002015160ff1681548110612ea157fe5b90600052602060002001612eb489612d50565b601689600b602002015160ff1681548110612ecb57fe5b90600052602060002001612ede8b612d50565b60405160200180806f1e39ba3cb6329f11b63ab1b430b237b960811b8152506010018a805190602001908083835b60208310612f2b5780518252601f199092019160209182019101612f0c565b6001836020036101000a0380198251168184511680821785525050505050509050018075202e6c756368612d62617365207b2066696c6c3a202360501b81525060160189805460018160011615610100020316600290048015612fc55780601f10612fa3576101008083540402835291820191612fc5565b820191906000526020600020905b815481529060010190602001808311612fb1575b5050806c1d903e9011b63ab1b430b237b960991b815250600d0188805190602001908083835b6020831061300a5780518252601f199092019160209182019101612feb565b6001836020036101000a0380198251168184511680821785525050505050509050018074202e6c756368612d616c74207b2066696c6c3a202360581b815250601501878054600181600116156101000203166002900480156130a35780601f106130815761010080835404028352918201916130a3565b820191906000526020600020905b81548152906001019060200180831161308f575b5050806c1d903e9011b63ab1b430b237b960991b815250600d0186805190602001908083835b602083106130e85780518252601f1990920191602091820191016130c9565b6001836020036101000a0380198251168184511680821785525050505050509050018075202e6c756368612d65796573207b2066696c6c3a202360501b815250601601858054600181600116156101000203166002900480156131825780601f10613160576101008083540402835291820191613182565b820191906000526020600020905b81548152906001019060200180831161316e575b5050806c1d903e9011b63ab1b430b237b960991b815250600d0184805190602001908083835b602083106131c75780518252601f1990920191602091820191016131a8565b6001836020036101000a0380198251168184511680821785525050505050509050018075202e6c756368612d736b696e207b2066696c6c3a202360501b815250601601838054600181600116156101000203166002900480156132615780601f1061323f576101008083540402835291820191613261565b820191906000526020600020905b81548152906001019060200180831161324d575b5050806c1d903e9011b63ab1b430b237b960991b815250600d0182805190602001908083835b602083106132a65780518252601f199092019160209182019101613287565b6001836020036101000a038019825116818451168082178552505050505050905001806146bc60bd913960bd019950505050505050505050604051602081830303815290604052905092915050565b3390565b600081815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061332e826118b5565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006112728261363d565b600061337d82612cf5565b6133b85760405162461bcd60e51b815260040180806020018281038252602c815260200180614979602c913960400191505060405180910390fd5b60006133c3836118b5565b9050806001600160a01b0316846001600160a01b031614806133fe5750836001600160a01b03166133f3846110a8565b6001600160a01b0316145b8061340e575061340e8185612bb9565b949350505050565b826001600160a01b0316613429826118b5565b6001600160a01b03161461346e5760405162461bcd60e51b8152600401808060200182810382526029815260200180614b746029913960400191505060405180910390fd5b6001600160a01b0382166134b35760405162461bcd60e51b815260040180806020018281038252602481526020018061492f6024913960400191505060405180910390fd5b6134be8383836139d1565b6134c96000826132f9565b6001600160a01b03831660009081526001602052604090206134eb9082613a20565b506001600160a01b038216600090815260016020526040902061350e9082613a2c565b5061351b60028284613a38565b5080826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b600061126f8383613a4e565b600080808061357d8686613ab2565b9097909650945050505050565b6135926118ac565b156135d7576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b600a805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861360d6132f5565b604080516001600160a01b039092168252519081900360200190a1565b8051611b0290600990602084019061458d565b5490565b601054604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca16916370a08231916024808301926020929190829003018186803b1580156136aa57600080fd5b505afa1580156136be573d6000803e3d6000fd5b505050506040513d60208110156136d457600080fd5b50511015613729576040805162461bcd60e51b815260206004820152601f60248201527f4e6f7420656e6f756768204c494e4b202d2066696c6c20636f6e747261637400604482015290519081900360640190fd5b600061373a600f5460105484613b2d565b9050613746600d613ce0565b604051806020016040528061375b600d61363d565b90526000828152602080526040902090519055611b023361377c600d61363d565b613ce9565b600061340e848484613d03565b60008281526020808052604080832080548452601f83528184208590559285905281805291548251848152925190927f1d584699e20b45cf7fb70771dbd92bb407c244dd750faf0d3c3108aaae7d0e7292908290030190a25050565b6137f5848484613416565b61380184848484613dcd565b611cc45760405162461bcd60e51b81526004018080602001828103825260328152602001806148966032913960400191505060405180910390fd5b6138446118ac565b61388c576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b600a805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61360d6132f5565b606060005b600c8160ff161080156138f25750828160ff16600c81106138e157fe5b1a60f81b6001600160f81b03191615155b156138ff576001016138c4565b60608160ff1667ffffffffffffffff8111801561391b57600080fd5b506040519080825280601f01601f191660200182016040528015613946576020820181803683370190505b509050600091505b600c8260ff1610801561397c5750838260ff16600c811061396b57fe5b1a60f81b6001600160f81b03191615155b15611e6e57838260ff16600c811061399057fe5b1a60f81b818360ff16815181106139a357fe5b60200101906001600160f81b031916908160001a90535060019091019061394e565b600061126f8383613f35565b6139dc8383836111e0565b6139e46118ac565b156111e05760405162461bcd60e51b815260040180806020018281038252602b815260200180614691602b913960400191505060405180910390fd5b600061126f8383613f4d565b600061126f8383614013565b600061340e84846001600160a01b03851661405d565b81546000908210613a905760405162461bcd60e51b81526004018080602001828103825260228152602001806146396022913960400191505060405180910390fd5b826000018281548110613a9f57fe5b9060005260206000200154905092915050565b815460009081908310613af65760405162461bcd60e51b8152600401808060200182810382526022815260200180614a306022913960400191505060405180910390fd5b6000846000018481548110613b0757fe5b906000526020600020906002020190508060000154816001015492509250509250929050565b60007f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca6001600160a01b0316634000aea07f000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb795285878660405160200180838152602001828152602001925050506040516020818303038152906040526040518463ffffffff1660e01b815260040180846001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015613c09578181015183820152602001613bf1565b50505050905090810190601f168015613c365780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b158015613c5757600080fd5b505af1158015613c6b573d6000803e3d6000fd5b505050506040513d6020811015613c8157600080fd5b50506000848152600c6020526040812054613ca1908690859030906140f4565b6000868152600c6020526040902054909150613cbe90600161413b565b6000868152600c6020526040902055613cd78582614195565b95945050505050565b80546001019055565b611b028282604051806020016040528060008152506141c1565b60008281526001840160205260408120548281613d9e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613d63578181015183820152602001613d4b565b50505050905090810190601f168015613d905780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50846000016001820381548110613db157fe5b9060005260206000209060020201600101549150509392505050565b6000613de1846001600160a01b0316614213565b613ded5750600161340e565b6060613efb630a85bd0160e11b613e026132f5565b88878760405160240180856001600160a01b03168152602001846001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015613e69578181015183820152602001613e51565b50505050905090810190601f168015613e965780820380516001836020036101000a031916815260200191505b5095505050505050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050604051806060016040528060328152602001614896603291396001600160a01b0388169190614219565b90506000818060200190516020811015613f1457600080fd5b50516001600160e01b031916630a85bd0160e11b1492505050949350505050565b60009081526001919091016020526040902054151590565b600081815260018301602052604081205480156140095783546000198083019190810190600090879083908110613f8057fe5b9060005260206000200154905080876000018481548110613f9d57fe5b600091825260208083209091019290925582815260018981019092526040902090840190558654879080613fcd57fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611272565b6000915050611272565b600061401f8383613f35565b61405557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611272565b506000611272565b6000828152600184016020526040812054806140c2575050604080518082018252838152602080820184815286546001818101895560008981528481209551600290930290950191825591519082015586548684528188019092529290912055611e6e565b828560000160018303815481106140d557fe5b9060005260206000209060020201600101819055506000915050611e6e565b60408051602080820196909652808201949094526001600160a01b039290921660608401526080808401919091528151808403909101815260a09092019052805191012090565b60008282018381101561126f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b6141cb8383614228565b6141d86000848484613dcd565b6111e05760405162461bcd60e51b81526004018080602001828103825260328152602001806148966032913960400191505060405180910390fd5b3b151590565b606061340e8484600085614356565b6001600160a01b038216614283576040805162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015290519081900360640190fd5b61428c81612cf5565b156142de576040805162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015290519081900360640190fd5b6142ea600083836139d1565b6001600160a01b038216600090815260016020526040902061430c9082613a2c565b5061431960028284613a38565b5060405181906001600160a01b038416906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6060824710156143975760405162461bcd60e51b81526004018080602001828103825260268152602001806149536026913960400191505060405180910390fd5b6143a085614213565b6143f1576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106144305780518252601f199092019160209182019101614411565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614492576040519150601f19603f3d011682016040523d82523d6000602084013e614497565b606091505b50915091506144a78282866144b2565b979650505050505050565b606083156144c1575081611e6e565b8251156144d15782518084602001fd5b60405162461bcd60e51b8152602060048201818152845160248401528451859391928392604401919085019080838360008315613d63578181015183820152602001613d4b565b604051806101800160405280600c906020820280368337509192915050565b6040518061010001604052806008905b61454f61460b565b8152602001906001900390816145475790505090565b6040518061010001604052806008905b60608152602001906001900390816145755790505090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106145ce57805160ff19168380011785556145fb565b828001600101855582156145fb579182015b828111156145fb5782518255916020019190600101906145e0565b50614607929150614623565b5090565b60408051808201909152600081526060602082015290565b5b80821115614607576000815560010161462456fe456e756d657261626c655365743a20696e646578206f7574206f6620626f756e64733c706174682066696c6c3d272330303027206f7061636974793d272e392720643d274d3133203131682d3376316834762d317a272f3e4552433732315061757361626c653a20746f6b656e207472616e73666572207768696c6520706175736564202e6c756368612d62726561746865207b20616e696d6174696f6e3a20302e3573206c756368612d6272656174686520696e66696e69746520616c7465726e61746520656173652d696e2d6f75743b207d20406b65796672616d6573206c756368612d62726561746865207b2066726f6d207b207472616e73666f726d3a207472616e736c6174655928307078293b207d20746f207b207472616e73666f726d3a207472616e736c61746559283125293b207d207d3c2f7374796c653e3c706174682066696c6c3d27234646462720643d274d39203648367633683456367a4d31372036682d337633683456367a272f3e3c7061746820636c6173733d276c756368612d657965732720643d274d31362036682d327633683356367a4d382036483776336833563648397a272f3e3c706174682066696c6c3d27234646462720643d274d3720366831763148377a4d3136203668317631682d317a27206f7061636974793d272e34272f3e3c706174682066696c6c3d27233030302720643d274d3135203768317631682d317a4d3820376831763148387a272f3e3c7061746820636c6173733d276c756368612d736b696e2720643d274d3136203233762d3648387636483776316834762d34683276346834762d317a272f3e4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573733c7061746820636c6173733d276c756368612d626173652720643d274d31352031374838763168317631683276316832762d316832762d316831762d317a272f3e4552433732313a207472616e7366657220746f20746865207a65726f2061646472657373416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656420666f7220616c6c4552433732313a2062616c616e636520717565727920666f7220746865207a65726f20616464726573734552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656e456e756d657261626c654d61703a20696e646578206f7574206f6620626f756e6473226465736372697074696f6e223a20224c75636861646f726573206172652072616e646f6d6c792067656e657261746564207573696e6720436861696e6c696e6b2056524620616e6420686176652031303025206f6e2d636861696e2061727420616e64206d65746164617461202d204f6e6c792031303030302077696c6c206576657220657869737421222c4552433732313a20617070726f76656420717565727920666f72206e6f6e6578697374656e7420746f6b656e3c7061746820636c6173733d276c756368612d626173652720643d274d3920323148387632483776316834762d33682d317a4d3136203233762d32682d3376336834762d317a272f3e4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65724552433732313a207472616e73666572206f6620746f6b656e2074686174206973206e6f74206f776e4552433732314d657461646174613a2055524920717565727920666f72206e6f6e6578697374656e7420746f6b656e3c7061746820636c6173733d276c756368612d626173652720643d274d313820355633682d315632682d315631682d3156304839763148387631483776314836763248357635683176326831763168317631683176316836762d316831762d316831762d316831762d32683156357a272f3e2265787465726e616c5f75726c223a202268747470733a2f2f6c75636861646f7265732e696f2f6c75636861646f722f3c7061746820636c6173733d276c756368612d616c742720643d274d313820345633682d315632682d315631682d3156304839763148387631483776314836763248357635683156366831563568325634683156336834763168317631683276316831763468315635682d317a272f3e3c672066696c6c3d2723303030273e3c7061746820643d274d313820345633682d315632682d315631682d3156304839763148387631483776314836763248357635683156356831563468315633683156326836763168317631683176316831763568315635682d317a27206f7061636974793d272e32272f3e3c7061746820643d274d313620345633682d31563248397631483876314837763168325634683156336834763168317631683256347a4d3620356831763148367a4d3137203568317631682d317a27206f7061636974793d272e35272f3e3c2f673e4552433732313a20617070726f76616c20746f2063757272656e74206f776e65726d696e74207175616e74697479206d757374206265206265747765656e20312d32303c7061746820636c6173733d276c756368612d736b696e2720643d274d3232203132762d31682d31762d31682d315639682d315635682d315633682d315632682d315631682d3156304839763148387631483776314836763248357634483476314833763148327631483176386834762d316831762d324835762d336831763168317631683176326838762d326831762d316831762d3168317633682d317632683176316834762d387a272f3e3c7061746820636c6173733d276c756368612d616c742720643d274d32302031305639682d327631682d3176316834762d317a4d35203948347631483376316834762d31483656397a272f3e3c706174682066696c6c3d272330303027206f7061636974793d272e322720643d274d36203948347631483376316834762d3148367a4d32302031305639682d327631682d3176316834762d317a272f3e4552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665642720786d6c6e733d27687474703a2f2f7777772e77332e6f72672f323030302f737667272076696577426f783d27302030203234203234273e3c7061746820636c6173733d276c756368612d736b696e2720643d274d3134203130483976336836762d337a272f3ea2646970667358221220f07ff78f47503188bddd1cb2cc6410513aab09c35bef87db8e84d77cf54338e964736f6c634300060c0033

Loading...
Loading
Loading...
Loading
[ 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.