Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 30 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Mint | 23837727 | 100 days ago | IN | 0 ETH | 0.00003221 | ||||
| Mint | 23830964 | 101 days ago | IN | 0 ETH | 0.00002652 | ||||
| Mint | 23823166 | 102 days ago | IN | 0 ETH | 0.00004121 | ||||
| Mint | 23815921 | 103 days ago | IN | 0 ETH | 0.00001336 | ||||
| Append Chunks | 23815903 | 103 days ago | IN | 0 ETH | 0.00016823 | ||||
| Append Chunks | 23815902 | 103 days ago | IN | 0 ETH | 0.0015288 | ||||
| Append Chunks | 23815901 | 103 days ago | IN | 0 ETH | 0.00145987 | ||||
| Append Chunks | 23815900 | 103 days ago | IN | 0 ETH | 0.00139277 | ||||
| Append Chunks | 23815897 | 103 days ago | IN | 0 ETH | 0.0014757 | ||||
| Append Chunks | 23815896 | 103 days ago | IN | 0 ETH | 0.00146231 | ||||
| Append Chunks | 23815895 | 103 days ago | IN | 0 ETH | 0.00141653 | ||||
| Append Chunks | 23815894 | 103 days ago | IN | 0 ETH | 0.00137851 | ||||
| Append Chunks | 23815893 | 103 days ago | IN | 0 ETH | 0.00127904 | ||||
| Append Chunks | 23815892 | 103 days ago | IN | 0 ETH | 0.00117534 | ||||
| Append Chunks | 23815891 | 103 days ago | IN | 0 ETH | 0.00113739 | ||||
| Append Chunks | 23815890 | 103 days ago | IN | 0 ETH | 0.00113067 | ||||
| Append Chunks | 23815889 | 103 days ago | IN | 0 ETH | 0.00109674 | ||||
| Overwrite Chunks | 23815888 | 103 days ago | IN | 0 ETH | 0.0010726 | ||||
| Append Chunks | 23815887 | 103 days ago | IN | 0 ETH | 0.00067459 | ||||
| Append Chunks | 23815886 | 103 days ago | IN | 0 ETH | 0.00101494 | ||||
| Append Chunks | 23815885 | 103 days ago | IN | 0 ETH | 0.00098249 | ||||
| Overwrite Chunks | 23815884 | 103 days ago | IN | 0 ETH | 0.0009488 | ||||
| Overwrite Chunks | 23815883 | 103 days ago | IN | 0 ETH | 0.00009984 | ||||
| Overwrite Chunks | 23815882 | 103 days ago | IN | 0 ETH | 0.00007132 | ||||
| Overwrite Chunks | 23815881 | 103 days ago | IN | 0 ETH | 0.00007142 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x61141b80 | 23815903 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815902 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815902 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815901 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815901 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815900 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815900 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815897 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815897 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815896 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815896 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815895 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815895 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815894 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815894 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815893 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815893 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815892 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815892 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815891 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815891 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815890 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815890 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815889 | 103 days ago | Contract Creation | 0 ETH | |||
| 0x615ffb80 | 23815889 | 103 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Manes
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 10 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
import "@manifoldxyz/libraries-solidity/contracts/access/AdminControl.sol";
import "@manifoldxyz/creator-core-solidity/contracts/core/IERC721CreatorCore.sol";
import "@manifoldxyz/creator-core-solidity/contracts/extensions/ICreatorExtensionTokenURI.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./libraries/Color.sol";
import "./libraries/CRC32.sol";
import "solady/src/utils/SSTORE2.sol";
import "solady/src/utils/Base64.sol";
import "./IInterfectorem.sol";
contract Manes is Ownable, AdminControl, ICreatorExtensionTokenURI {
struct File {
string mimeType;
address[] chunks;
}
enum ImageType {
Token1Foreground,
Token2Background,
Token2Character1,
Token2Character2,
Token2Character3,
Token3Complete,
Token4Complete
}
File[] public files;
address diid = 0x735854c506CcEb0b95C949d1acB705b31136d487;
IInterfectorem public interfectorem;
mapping(uint256 => string) public metadata;
constructor(address _interfectorem) {
interfectorem = IInterfectorem(_interfectorem);
// Initialize files array with 7 empty File structs (one for each ImageType)
for (uint8 i = 0; i < 7; i++) {
files.push();
}
}
/**
* @notice A modifier for checking that the sender of the transaction has admin permissions on the Creator Contract they are trying to do something with
*
* Shamelessly borrowed from the Manifold claim page extension.
*
* @param creatorContractAddress The Manifold Creator Contract in question
*/
modifier creatorAdminRequired(address creatorContractAddress) {
AdminControl creatorCoreContract = AdminControl(creatorContractAddress);
require(
creatorCoreContract.isAdmin(msg.sender),
"Wallet is not an administrator for contract"
);
_;
}
/**
* @dev sets (technically appends) to the image the chunks provided
*
* @param imageType the image type for the image
* @param image the image chunks to set
*/
function _setImage(ImageType imageType, bytes[] calldata image) internal {
// loop through the image array, appending a new byte array
// to the chunks. This is because the contract storage limit
// is 24576 but we actually get much further than that before
// running out of gas in the block.
for (uint8 i = 0; i < image.length; i++) {
files[uint256(imageType)].chunks.push(SSTORE2.write(image[i]));
}
}
/**
@notice Mints a token with `metadata` of type `mimeType` and image `image`
@param creatorContractAddress The Manifold contract to mint to
*/
function mint(
address creatorContractAddress
) external payable creatorAdminRequired(creatorContractAddress) onlyOwner {
IERC721CreatorCore(creatorContractAddress).mintExtension(msg.sender);
}
/**
@notice Updates a token with `metadata` of type `mimeType` and image `image`.
@param creatorContractAddress The Manifold contract to mint to
@param tokenId the token to update the data for
@param _metadata The string metadata for the token, expressed as a JSON with no opening or closing bracket, e.g. `"name": "hello!","description": "world!"`
*/
function updateToken(
address creatorContractAddress,
uint256 tokenId,
string calldata _metadata
) external creatorAdminRequired(creatorContractAddress) onlyOwner {
metadata[tokenId] = _metadata;
}
/**
@notice Updates multiple tokens with metadata in a single transaction.
@param creatorContractAddress The Manifold contract to mint to
@param tokenIds Array of token IDs to update
@param metadataArray Array of metadata strings for each token, expressed as JSON with no opening or closing bracket
*/
function updateTokensBulk(
address creatorContractAddress,
uint256[] calldata tokenIds,
string[] calldata metadataArray
) external creatorAdminRequired(creatorContractAddress) onlyOwner {
require(tokenIds.length == metadataArray.length, "Arrays length mismatch");
for (uint256 i = 0; i < tokenIds.length; i++) {
metadata[tokenIds[i]] = metadataArray[i];
}
}
/**
@notice Appends chunks of binary data to the chunks for a given token. If your image won't fit in a single "mint" transaction, you can use this to add data to it.
@param creatorContractAddress The Manifold contract to mint to
@param imageType The image type to add data to
@param chunks The chunks of data to add, max length for each individual chunk is 24576 bytes (EVM contract limit)
*/
function appendChunks(
address creatorContractAddress,
ImageType imageType,
bytes[] calldata chunks
) external creatorAdminRequired(creatorContractAddress) onlyOwner {
_setImage(imageType, chunks);
}
/**
@notice Overwrites the chunks for a given token.
@param creatorContractAddress The Manifold contract to mint to
@param imageType The image type to overwrite the data for
@param mimeType The MIME type of the file (e.g., "image/png", "image/gif")
@param chunks The chunks of data to overwrite, max length for each individual chunk is 24576 bytes (EVM contract limit)
*/
function overwriteChunks(
address creatorContractAddress,
ImageType imageType,
string calldata mimeType,
bytes[] calldata chunks
) external creatorAdminRequired(creatorContractAddress) onlyOwner {
files[uint256(imageType)].mimeType = mimeType;
delete files[uint256(imageType)].chunks;
_setImage(imageType, chunks);
}
/**
* @dev loads just the binary image data without any conversion
*
* @param imageType the image type to load
*/
function loadRawImage(
ImageType imageType
) public view returns (bytes memory) {
bytes memory data;
for (uint8 i = 0; i < files[uint256(imageType)].chunks.length; i++) {
data = abi.encodePacked(
data,
SSTORE2.read(files[uint256(imageType)].chunks[i])
);
}
return data;
}
/**
* @dev loads image data by converting it to base64 and attaching the mime type
*
* @param imageType the image type to load
*/
function loadImage(ImageType imageType) public view returns (string memory) {
return
string(
abi.encodePacked(
"data:",
files[uint256(imageType)].mimeType,
";base64,",
Base64.encode(loadRawImage(imageType))
)
);
}
function _generateBitmap(
uint[2 * 341] memory game1Data
) internal pure returns (bytes memory) {
uint width = 512;
uint height = 341;
// Calculate row padding (each row must be multiple of 4 bytes)
uint rowSize = ((width + 3) / 4) * 4; // Round up to nearest multiple of 4 (= 64 bytes)
uint imageSize = rowSize * height; // 64 * 341 = 21,824 bytes
// Bitmap file header (14 bytes)
// Note: abi.encodePacked uses big-endian, so we arrange bytes to produce correct little-endian output
// File size: 21,886 (0x557E) → LE bytes: 0x7E, 0x55, 0x00, 0x00
// Offset: 62 (0x3E) → LE bytes: 0x3E, 0x00, 0x00, 0x00
bytes memory fileHeader = abi.encodePacked(
uint16(0x424D), // "BM" signature (bytes: 0x42='B', 0x4D='M')
uint32(0x7E550000), // File size: 21,886 bytes (little-endian)
uint32(0), // Reserved
uint32(0x3E000000) // Offset to pixel data: 62 bytes (little-endian)
);
// DIB header (40 bytes)
// Width: 512 (0x200) → LE: 0x00, 0x02, 0x00, 0x00
// Height: 341 (0x155) → LE: 0x55, 0x01, 0x00, 0x00
// Image size: 21,824 (0x5540) → LE: 0x40, 0x55, 0x00, 0x00
bytes memory dibHeader = abi.encodePacked(
uint32(0x28000000), // Header size: 40 (little-endian)
uint32(0x00020000), // Width: 512 (little-endian)
uint32(0x55010000), // Height: 341 (little-endian)
uint16(0x0100), // Planes: 1 (little-endian)
uint16(0x0100), // Bits per pixel: 1 (little-endian)
uint32(0), // Compression: 0 (little-endian)
uint32(0x40550000), // Image size: 21,824 (little-endian)
uint32(0), // X pixels per meter: 0
uint32(0), // Y pixels per meter: 0
uint32(0x02000000), // Colors in palette: 2 (little-endian)
uint32(0) // Important colors: 0
);
// Color palette (8 bytes for 2 colors)
// Color 0: #7e8ffa (RGB: 126, 143, 250)
// Color 1: #2f2f2f (RGB: 47, 47, 47)
bytes memory palette = abi.encodePacked(
uint8(250),
uint8(143),
uint8(126),
uint8(0), // Color 0 (BGR format)
uint8(47),
uint8(47),
uint8(47),
uint8(0) // Color 1 (BGR format)
);
// Convert game1Data to pixel data
bytes memory pixelData = new bytes(imageSize);
for (uint y = 0; y < height; y++) {
uint byteOffset = ((height - 1 - y) * rowSize) / 8;
// Each row has 512 pixels, so we need 2 uints per row (256 bits each)
uint uintIndex = y * 2;
// Convert the two uints to bytes and copy directly
bytes32 data1 = bytes32(game1Data[uintIndex]);
bytes32 data2 = bytes32(game1Data[uintIndex + 1]);
// Copy first 32 bytes (256 bits) from data1
for (uint i = 0; i < 32; i++) {
pixelData[byteOffset + i] = data1[i];
}
// Copy next 32 bytes (256 bits) from data2
for (uint i = 0; i < 32; i++) {
pixelData[byteOffset + 32 + i] = data2[i];
}
}
// Combine all parts
return abi.encodePacked(fileHeader, dibHeader, palette, pixelData);
}
function token1Image() public view returns (string memory) {
// Get game data from the Interfectorem contract
uint[2 * 341] memory game1Data = interfectorem.getGame1Data();
// Generate Windows bitmap with game data
bytes memory bitmap = _generateBitmap(game1Data);
// Convert to base64 data URI
string memory image = string(
abi.encodePacked("data:image/bmp;base64,", Base64.encode(bitmap))
);
string[] memory imageDataUris = new string[](2);
imageDataUris[0] = image;
imageDataUris[1] = loadImage(ImageType.Token1Foreground);
return wrapMultipleImages(imageDataUris, 2048, 1364, 0);
}
function token2Image() public view returns (string memory) {
string[] memory imageDataUris = new string[](4);
uint vote = interfectorem.getGame2Data() / 1000;
imageDataUris[0] = loadImage(ImageType.Token2Background);
if (vote < 75) {
imageDataUris[1] = loadImage(ImageType.Token2Character1);
}
if (vote < 50) {
imageDataUris[2] = loadImage(ImageType.Token2Character2);
}
if (vote < 25) {
imageDataUris[3] = loadImage(ImageType.Token2Character3);
}
return wrapMultipleImages(imageDataUris, 1364, 2048, 0);
}
function replacePngPalette(
bytes memory data,
uint8[] memory colors
) public pure returns (bytes memory) {
// iterate through png chunks until PLTE chunk is found
uint256 offset = 8; // Skip PNG header
bytes4 chunkType;
uint256 chunkLength;
bool foundPLTE = false;
while (offset < data.length && !foundPLTE) {
// Read chunk length (4 bytes)
chunkLength = uint32(
bytes4(
abi.encodePacked(
data[offset],
data[offset + 1],
data[offset + 2],
data[offset + 3]
)
)
);
// Read chunk type (4 bytes)
chunkType = bytes4(
abi.encodePacked(
data[offset + 4],
data[offset + 5],
data[offset + 6],
data[offset + 7]
)
);
if (chunkType == "PLTE") {
foundPLTE = true;
break;
}
// Move to next chunk
offset += 12 + chunkLength; // 4 (len) + 4 (type) + length + 4 (CRC)
}
// convert the PLTE chunk to bytes
bytes memory palette;
for (uint256 i = 0; i < colors.length; i++) {
palette = abi.encodePacked(palette, colors[i]);
}
// generate the CRC32
uint256 crc = CRC32.update(0, abi.encodePacked("PLTE", palette));
for (uint i = 0; i < chunkLength; i++) {
data[offset + 8 + i] = palette[i];
}
// add the CRC32 back to the data
data[offset + 11 + chunkLength] = bytes1(uint8(crc & 0xFF));
data[offset + 10 + chunkLength] = bytes1(uint8((crc >> 8) & 0xFF));
data[offset + 9 + chunkLength] = bytes1(uint8((crc >> 16) & 0xFF));
data[offset + 8 + chunkLength] = bytes1(uint8((crc >> 24) & 0xFF));
return data;
}
function token3Image() public view returns (string memory) {
uint8[13 * 3] memory game3Data = interfectorem.getGame3Data();
uint8[] memory colors = new uint8[](13 * 3);
for (uint i = 0; i < 13 * 3; i++) {
colors[i] = game3Data[i];
}
bytes memory data = loadRawImage(ImageType.Token3Complete);
data = replacePngPalette(data, colors);
return
wrapSingleImage(
string(abi.encodePacked("data:image/png;base64,", Base64.encode(data))),
2048,
2048
);
}
function token4Image() public view returns (string memory) {
// streamline reading because this is a big image
bytes memory data;
uint length = files[6].chunks.length;
for (uint i = 0; i < length; i++) {
data = abi.encodePacked(data, SSTORE2.read(files[6].chunks[i]));
}
uint[6] memory shifts = interfectorem.getGame4Data();
uint8[] memory newData = new uint8[](256 * 3);
for (uint i = 0; i < 3; i++) {
for (uint j = 0; j < 10; j++) {
uint index = i * 10 * 3 + j * 3;
uint offset = index + 0x29;
// Read 3 consecutive bytes to form an RGB color
bytes3 rgbColor = bytes3(
abi.encodePacked(data[offset], data[offset + 1], data[offset + 2])
);
int[3] memory colorInt = Color.getHSV(rgbColor);
uint hueShift = shifts[i * 2];
uint saturationShift = shifts[i * 2 + 1];
uint targetHue = (i * 120 * 256) / 360;
int hue = colorInt[0];
// shift towards target hue
if (hue > int(targetHue) && hue - int(hueShift) > int(targetHue)) {
colorInt[0] = colorInt[0] - int(hueShift);
} else if (
hue < int(targetHue) && hue + int(hueShift) < int(targetHue)
) {
colorInt[0] = colorInt[0] + int(hueShift);
} else {
colorInt[0] = int(targetHue);
}
colorInt[1] = colorInt[1] + int(saturationShift);
if (colorInt[1] < 128) {
colorInt[1] = 0;
} else {
colorInt[1] -= 128;
}
if (colorInt[1] > 255) {
colorInt[1] = 255;
}
bytes3 color = Color.getRGB(colorInt);
newData[index] = uint8(color[0]);
newData[index + 1] = uint8(color[1]);
newData[index + 2] = uint8(color[2]);
}
}
data = replacePngPalette(data, newData);
return
string.concat(
"data:",
files[6].mimeType,
";base64,",
Base64.encode(data)
);
}
function buildImage(uint256 tokenId) public view returns (string memory) {
if (tokenId == 1) {
return token1Image();
} else if (tokenId == 2) {
return token2Image();
} else if (tokenId == 3) {
return token3Image();
} else if (tokenId == 4) {
return token4Image();
}
return "";
}
function tokenURI(
address creatorContractAddress,
uint256 tokenId
) external view override returns (string memory) {
string memory token = string(
abi.encodePacked(
"data:application/json;utf8,{",
metadata[tokenId],
', "image": "',
buildImage(tokenId),
'"'
)
);
token = string(abi.encodePacked(token, "}"));
return token;
}
function withdraw() external onlyOwner {
(bool success, ) = diid.call{ value: address(this).balance }("");
require(success, "withdraw failed");
}
/**
* @dev Wraps multiple images in an SVG with nearest neighbor scaling
* @param imageDataUris Array of complete data URIs (with data:<mime>;base64, prefix)
* @param width Desired width of the final SVG
* @param height Desired height of the final SVG
* @param shift Number of pixels to shift each successive image to the right
* @return SVG string with all images stacked vertically
*/
function wrapMultipleImages(
string[] memory imageDataUris,
uint256 width,
uint256 height,
int256 shift
) public pure returns (string memory) {
require(imageDataUris.length > 0, "Must provide at least one image");
// Start building the SVG
string memory svg = string(
abi.encodePacked(
'<svg viewBox="0 0 ',
Strings.toString(width),
" ",
Strings.toString(height),
'" width="',
Strings.toString(width),
'" height="',
Strings.toString(height),
'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">',
"<defs><style>image {image-rendering: optimizeSpeed;image-rendering: -moz-crisp-edges;image-rendering: -o-crisp-edges;image-rendering: -webkit-optimize-contrast;image-rendering: optimize-contrast;image-rendering: crisp-edges;image-rendering: pixelated;-ms-interpolation-mode: nearest-neighbor;}</style></defs>"
)
);
// Add each image
for (uint256 i = 0; i < imageDataUris.length; i++) {
if (bytes(imageDataUris[i]).length == 0) {
continue;
}
int256 xPosition = int256(i) * shift;
svg = string(
abi.encodePacked(
svg,
'<image x="',
xPosition >= 0
? Strings.toString(uint256(xPosition))
: string(
abi.encodePacked("-", Strings.toString(uint256(-xPosition)))
),
'" y="0px" width="',
Strings.toString(width),
'" height="',
Strings.toString(height),
'" href="',
imageDataUris[i],
'" />'
)
);
}
// Add foreignObject for additional compatibility
svg = string(
abi.encodePacked(
svg,
'<foreignObject width="',
Strings.toString(width),
'px" height="',
Strings.toString(height),
'px"><div xmlns="http://www.w3.org/1999/xhtml" style="width:',
Strings.toString(width),
"px; height:",
Strings.toString(height),
'px;">'
)
);
// Add images in foreignObject as well
for (uint256 i = 0; i < imageDataUris.length; i++) {
if (bytes(imageDataUris[i]).length == 0) {
continue;
}
int256 xPosition = int256(i) * shift;
svg = string(
abi.encodePacked(
svg,
'<img style="position: absolute; top: 0px; left: ',
xPosition >= 0
? Strings.toString(uint256(xPosition))
: string(
abi.encodePacked("-", Strings.toString(uint256(-xPosition)))
),
"px; width:",
Strings.toString(width),
"px; height:",
Strings.toString(height),
'px; image-rendering: optimizeSpeed; image-rendering: -moz-crisp-edges; image-rendering: -o-crisp-edges; image-rendering: -webkit-optimize-contrast; image-rendering: optimize-contrast; image-rendering: crisp-edges; image-rendering: pixelated; -ms-interpolation-mode: nearest-neighbor;" src="',
imageDataUris[i],
'" />'
)
);
}
svg = string(abi.encodePacked(svg, "</div></foreignObject></svg>"));
return
string(
abi.encodePacked(
"data:image/svg+xml;base64,",
Base64.encode(bytes(svg))
)
);
}
/**
* @dev Wraps a single image in an SVG with nearest neighbor scaling
* @param imageDataUri Complete data URI (with data:<mime>;base64, prefix)
* @param width Desired width of the final SVG
* @param height Desired height of the final SVG
* @return SVG string with the image
*/
function wrapSingleImage(
string memory imageDataUri,
uint256 width,
uint256 height
) public pure returns (string memory) {
string[] memory imageDataUris = new string[](1);
imageDataUris[0] = imageDataUri;
return wrapMultipleImages(imageDataUris, width, height, 0);
}
function supportsInterface(
bytes4 interfaceId
) public view virtual override(AdminControl, IERC165) returns (bool) {
return
interfaceId == type(ICreatorExtensionTokenURI).interfaceId ||
AdminControl.supportsInterface(interfaceId) ||
super.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @author: manifold.xyz
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @dev Core creator interface
*/
interface ICreatorCore is IERC165 {
event ExtensionRegistered(address indexed extension, address indexed sender);
event ExtensionUnregistered(address indexed extension, address indexed sender);
event ExtensionBlacklisted(address indexed extension, address indexed sender);
event MintPermissionsUpdated(address indexed extension, address indexed permissions, address indexed sender);
event RoyaltiesUpdated(uint256 indexed tokenId, address payable[] receivers, uint256[] basisPoints);
event DefaultRoyaltiesUpdated(address payable[] receivers, uint256[] basisPoints);
event ApproveTransferUpdated(address extension);
event ExtensionRoyaltiesUpdated(address indexed extension, address payable[] receivers, uint256[] basisPoints);
event ExtensionApproveTransferUpdated(address indexed extension, bool enabled);
/**
* @dev gets address of all extensions
*/
function getExtensions() external view returns (address[] memory);
/**
* @dev add an extension. Can only be called by contract owner or admin.
* extension address must point to a contract implementing ICreatorExtension.
* Returns True if newly added, False if already added.
*/
function registerExtension(address extension, string calldata baseURI) external;
/**
* @dev add an extension. Can only be called by contract owner or admin.
* extension address must point to a contract implementing ICreatorExtension.
* Returns True if newly added, False if already added.
*/
function registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) external;
/**
* @dev add an extension. Can only be called by contract owner or admin.
* Returns True if removed, False if already removed.
*/
function unregisterExtension(address extension) external;
/**
* @dev blacklist an extension. Can only be called by contract owner or admin.
* This function will destroy all ability to reference the metadata of any tokens created
* by the specified extension. It will also unregister the extension if needed.
* Returns True if removed, False if already removed.
*/
function blacklistExtension(address extension) external;
/**
* @dev set the baseTokenURI of an extension. Can only be called by extension.
*/
function setBaseTokenURIExtension(string calldata uri) external;
/**
* @dev set the baseTokenURI of an extension. Can only be called by extension.
* For tokens with no uri configured, tokenURI will return "uri+tokenId"
*/
function setBaseTokenURIExtension(string calldata uri, bool identical) external;
/**
* @dev set the common prefix of an extension. Can only be called by extension.
* If configured, and a token has a uri set, tokenURI will return "prefixURI+tokenURI"
* Useful if you want to use ipfs/arweave
*/
function setTokenURIPrefixExtension(string calldata prefix) external;
/**
* @dev set the tokenURI of a token extension. Can only be called by extension that minted token.
*/
function setTokenURIExtension(uint256 tokenId, string calldata uri) external;
/**
* @dev set the tokenURI of a token extension for multiple tokens. Can only be called by extension that minted token.
*/
function setTokenURIExtension(uint256[] memory tokenId, string[] calldata uri) external;
/**
* @dev set the baseTokenURI for tokens with no extension. Can only be called by owner/admin.
* For tokens with no uri configured, tokenURI will return "uri+tokenId"
*/
function setBaseTokenURI(string calldata uri) external;
/**
* @dev set the common prefix for tokens with no extension. Can only be called by owner/admin.
* If configured, and a token has a uri set, tokenURI will return "prefixURI+tokenURI"
* Useful if you want to use ipfs/arweave
*/
function setTokenURIPrefix(string calldata prefix) external;
/**
* @dev set the tokenURI of a token with no extension. Can only be called by owner/admin.
*/
function setTokenURI(uint256 tokenId, string calldata uri) external;
/**
* @dev set the tokenURI of multiple tokens with no extension. Can only be called by owner/admin.
*/
function setTokenURI(uint256[] memory tokenIds, string[] calldata uris) external;
/**
* @dev set a permissions contract for an extension. Used to control minting.
*/
function setMintPermissions(address extension, address permissions) external;
/**
* @dev Configure so transfers of tokens created by the caller (must be extension) gets approval
* from the extension before transferring
*/
function setApproveTransferExtension(bool enabled) external;
/**
* @dev get the extension of a given token
*/
function tokenExtension(uint256 tokenId) external view returns (address);
/**
* @dev Set default royalties
*/
function setRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints) external;
/**
* @dev Set royalties of a token
*/
function setRoyalties(uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints) external;
/**
* @dev Set royalties of an extension
*/
function setRoyaltiesExtension(address extension, address payable[] calldata receivers, uint256[] calldata basisPoints) external;
/**
* @dev Get royalites of a token. Returns list of receivers and basisPoints
*/
function getRoyalties(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
// Royalty support for various other standards
function getFeeRecipients(uint256 tokenId) external view returns (address payable[] memory);
function getFeeBps(uint256 tokenId) external view returns (uint[] memory);
function getFees(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
function royaltyInfo(uint256 tokenId, uint256 value) external view returns (address, uint256);
/**
* @dev Set the default approve transfer contract location.
*/
function setApproveTransfer(address extension) external;
/**
* @dev Get the default approve transfer contract location.
*/
function getApproveTransfer() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @author: manifold.xyz
import "./ICreatorCore.sol";
/**
* @dev Core ERC721 creator interface
*/
interface IERC721CreatorCore is ICreatorCore {
/**
* @dev mint a token with no extension. Can only be called by an admin.
* Returns tokenId minted
*/
function mintBase(address to) external returns (uint256);
/**
* @dev mint a token with no extension. Can only be called by an admin.
* Returns tokenId minted
*/
function mintBase(address to, string calldata uri) external returns (uint256);
/**
* @dev batch mint a token with no extension. Can only be called by an admin.
* Returns tokenId minted
*/
function mintBaseBatch(address to, uint16 count) external returns (uint256[] memory);
/**
* @dev batch mint a token with no extension. Can only be called by an admin.
* Returns tokenId minted
*/
function mintBaseBatch(address to, string[] calldata uris) external returns (uint256[] memory);
/**
* @dev mint a token. Can only be called by a registered extension.
* Returns tokenId minted
*/
function mintExtension(address to) external returns (uint256);
/**
* @dev mint a token. Can only be called by a registered extension.
* Returns tokenId minted
*/
function mintExtension(address to, string calldata uri) external returns (uint256);
/**
* @dev mint a token. Can only be called by a registered extension.
* Returns tokenId minted
*/
function mintExtension(address to, uint80 data) external returns (uint256);
/**
* @dev batch mint a token. Can only be called by a registered extension.
* Returns tokenIds minted
*/
function mintExtensionBatch(address to, uint16 count) external returns (uint256[] memory);
/**
* @dev batch mint a token. Can only be called by a registered extension.
* Returns tokenId minted
*/
function mintExtensionBatch(address to, string[] calldata uris) external returns (uint256[] memory);
/**
* @dev batch mint a token. Can only be called by a registered extension.
* Returns tokenId minted
*/
function mintExtensionBatch(address to, uint80[] calldata data) external returns (uint256[] memory);
/**
* @dev burn a token. Can only be called by token owner or approved address.
* On burn, calls back to the registered extension's onBurn method
*/
function burn(uint256 tokenId) external;
/**
* @dev get token data
*/
function tokenData(uint256 tokenId) external view returns (uint80);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @author: manifold.xyz
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @dev Implement this if you want your extension to have overloadable URI's
*/
interface ICreatorExtensionTokenURI is IERC165 {
/**
* Get the uri for a given creator/tokenId
*/
function tokenURI(address creator, uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @author: manifold.xyz
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./IAdminControl.sol";
abstract contract AdminControl is Ownable, IAdminControl, ERC165 {
using EnumerableSet for EnumerableSet.AddressSet;
// Track registered admins
EnumerableSet.AddressSet private _admins;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IAdminControl).interfaceId
|| super.supportsInterface(interfaceId);
}
/**
* @dev Only allows approved admins to call the specified function
*/
modifier adminRequired() {
require(owner() == msg.sender || _admins.contains(msg.sender), "AdminControl: Must be owner or admin");
_;
}
/**
* @dev See {IAdminControl-getAdmins}.
*/
function getAdmins() external view override returns (address[] memory admins) {
admins = new address[](_admins.length());
for (uint i = 0; i < _admins.length(); i++) {
admins[i] = _admins.at(i);
}
return admins;
}
/**
* @dev See {IAdminControl-approveAdmin}.
*/
function approveAdmin(address admin) external override onlyOwner {
if (!_admins.contains(admin)) {
emit AdminApproved(admin, msg.sender);
_admins.add(admin);
}
}
/**
* @dev See {IAdminControl-revokeAdmin}.
*/
function revokeAdmin(address admin) external override onlyOwner {
if (_admins.contains(admin)) {
emit AdminRevoked(admin, msg.sender);
_admins.remove(admin);
}
}
/**
* @dev See {IAdminControl-isAdmin}.
*/
function isAdmin(address admin) public override view returns (bool) {
return (owner() == admin || _admins.contains(admin));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @author: manifold.xyz
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @dev Interface for admin control
*/
interface IAdminControl is IERC165 {
event AdminApproved(address indexed account, address indexed sender);
event AdminRevoked(address indexed account, address indexed sender);
/**
* @dev gets address of all admins
*/
function getAdmins() external view returns (address[] memory);
/**
* @dev add an admin. Can only be called by contract owner.
*/
function approveAdmin(address admin) external;
/**
* @dev remove an admin. Can only be called by contract owner.
*/
function revokeAdmin(address admin) external;
/**
* @dev checks whether or not given address is an admin
* Returns True if they are
*/
function isAdmin(address admin) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^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.
*
* ```solidity
* 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.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
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;
if (lastIndex != toDeleteIndex) {
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] = valueIndex; // Replace lastValue's index to valueIndex
}
// 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) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// 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);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// 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))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// 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 in 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));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
interface IInterfectorem {
// a noise map of current deaths
function getGame1Data() external view returns (uint[2 * 341] memory);
// death voting (percentage * 1000)
function getGame2Data() external view returns (uint);
// the color table for game 3
function getGame3Data() external view returns (uint8[13 * 3] memory);
// the shift values for game 4
function getGame4Data() external view returns (uint[6] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
library Color {
function _max(int[3] memory options) private pure returns (int) {
int max = 0;
for (uint i = 0; i < options.length; i++) {
if (options[i] > max) max = options[i];
}
return max;
}
function _min(int[3] memory options) private pure returns (int) {
int min = 0xFFFFFFFFFFFFFFFF;
for (uint i = 0; i < options.length; i++) {
if (options[i] < min) min = options[i];
}
return min;
}
function _norm(
uint n,
int v,
int val,
int min,
int max
) private pure returns (int) {
if (n == 0) return v;
int offset = (8 * ((v * v) / 256 - v + 64)) / int(n);
if (v > 128) {
val -= offset;
if (val < min) val = min;
} else {
val += offset;
if (val > max) val = max;
}
return val;
}
function _shift(int val, int amount) private pure returns (int) {
if (amount != 0) {
val += amount;
if (val < 0) val = 256 + val;
else if (val > 255) val = val - 256;
}
return val;
}
function getHSV(bytes3 color) internal pure returns (int[3] memory) {
int r = int(uint(uint8(color[0])));
int g = int(uint(uint8(color[1])));
int b = int(uint(uint8(color[2])));
int v = _max([r, g, b]);
int c = v - _min([r, g, b]);
int h = 0;
if (c == 0) {
h = c;
} else if (v == r) {
h = (256 * (g - b)) / c;
} else if (v == g) {
h = 512 + (256 * (b - r)) / c;
} else {
h = 1024 + (256 * (r - g)) / c;
}
// sat = c / v
return [(h < 0 ? h + 1536 : h) / 6, v != 0 ? (256 * c) / v : v, v];
}
function getRGBComponent(
int n,
int[3] memory color
) internal pure returns (bytes1) {
int h = color[0];
int s = color[1];
int v = color[2];
int k = (n * 256 + h * 6) % (6 * 256);
int l = _min([k, 1024 - k, 256]);
int m = l > 0 ? l : int(0);
return abi.encodePacked(uint((v * (256 - (s * m) / 256)) / 256))[31];
}
function getRGB(int[3] memory color) internal pure returns (bytes3) {
return
bytes3(
abi.encodePacked(
getRGBComponent(5, color),
getRGBComponent(3, color),
getRGBComponent(1, color)
)
);
}
function normalizeSaturation(
int[3] memory hsvColor,
uint amount
) internal pure returns (int) {
return _norm(amount, hsvColor[2], hsvColor[1], 0, 255);
}
function normalizeHue(
int[3] memory hsvColor,
uint amount
) internal pure returns (int) {
return _norm(amount, hsvColor[2], hsvColor[0], 35, 200);
}
function shiftHue(int hue, int amount) internal pure returns (int) {
return _shift(hue, amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
library CRC32 {
// Replace with your desired CRC polynomial (e.g., 0x1db710640 for CRC-32)
uint256 constant CRC_POLYNOMIAL = 0x1db710641;
function createTable() internal pure returns (uint256[] memory table) {
table = new uint256[](256);
for (uint256 i = 0; i < 256; i++) {
uint256 v = i;
for (uint256 j = 0; j < 8; j++) {
if (v & 1 == 1) {
v = v ^ CRC_POLYNOMIAL;
}
v >>= 1;
}
table[i] = v;
}
return table;
}
function update(
uint256 crc,
bytes memory buf
) internal pure returns (uint256) {
unchecked {
// Mark unchecked for potential overflow
uint256[] memory crcTable = createTable(); // Pre-compute table once per call (optimize for frequent usage)
crc ^= 0xffffffff;
for (uint256 i = 0; i < buf.length; i++) {
crc = (crc >> 8) ^ crcTable[(crc ^ uint256(uint8(buf[i]))) & 0xff];
}
return crc ^ 0xffffffff;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library to encode strings in Base64.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol)
/// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <brecht@loopring.org>.
library Base64 {
/// @dev Encodes `data` using the base64 encoding described in RFC 4648.
/// See: https://datatracker.ietf.org/doc/html/rfc4648
/// @param fileSafe Whether to replace '+' with '-' and '/' with '_'.
/// @param noPadding Whether to strip away the padding.
function encode(bytes memory data, bool fileSafe, bool noPadding)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let dataLength := mload(data)
if dataLength {
// Multiply by 4/3 rounded up.
// The `shl(2, ...)` is equivalent to multiplying by 4.
let encodedLength := shl(2, div(add(dataLength, 2), 3))
// Set `result` to point to the start of the free memory.
result := mload(0x40)
// Store the table into the scratch space.
// Offsetted by -1 byte so that the `mload` will load the character.
// We will rewrite the free memory pointer at `0x40` later with
// the allocated size.
// The magic constant 0x0670 will turn "-_" into "+/".
mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670)))
// Skip the first slot, which stores the length.
let ptr := add(result, 0x20)
let end := add(ptr, encodedLength)
let dataEnd := add(add(0x20, data), dataLength)
let dataEndValue := mload(dataEnd) // Cache the value at the `dataEnd` slot.
mstore(dataEnd, 0x00) // Zeroize the `dataEnd` slot to clear dirty bits.
// Run over the input, 3 bytes at a time.
for {} 1 {} {
data := add(data, 3) // Advance 3 bytes.
let input := mload(data)
// Write 4 bytes. Optimized for fewer stack operations.
mstore8(0, mload(and(shr(18, input), 0x3F)))
mstore8(1, mload(and(shr(12, input), 0x3F)))
mstore8(2, mload(and(shr(6, input), 0x3F)))
mstore8(3, mload(and(input, 0x3F)))
mstore(ptr, mload(0x00))
ptr := add(ptr, 4) // Advance 4 bytes.
if iszero(lt(ptr, end)) { break }
}
mstore(dataEnd, dataEndValue) // Restore the cached value at `dataEnd`.
mstore(0x40, add(end, 0x20)) // Allocate the memory.
// Equivalent to `o = [0, 2, 1][dataLength % 3]`.
let o := div(2, mod(dataLength, 3))
// Offset `ptr` and pad with '='. We can simply write over the end.
mstore(sub(ptr, o), shl(240, 0x3d3d))
// Set `o` to zero if there is padding.
o := mul(iszero(iszero(noPadding)), o)
mstore(sub(ptr, o), 0) // Zeroize the slot after the string.
mstore(result, sub(encodedLength, o)) // Store the length.
}
}
}
/// @dev Encodes `data` using the base64 encoding described in RFC 4648.
/// Equivalent to `encode(data, false, false)`.
function encode(bytes memory data) internal pure returns (string memory result) {
result = encode(data, false, false);
}
/// @dev Encodes `data` using the base64 encoding described in RFC 4648.
/// Equivalent to `encode(data, fileSafe, false)`.
function encode(bytes memory data, bool fileSafe)
internal
pure
returns (string memory result)
{
result = encode(data, fileSafe, false);
}
/// @dev Decodes base64 encoded `data`.
///
/// Supports:
/// - RFC 4648 (both standard and file-safe mode).
/// - RFC 3501 (63: ',').
///
/// Does not support:
/// - Line breaks.
///
/// Note: For performance reasons,
/// this function will NOT revert on invalid `data` inputs.
/// Outputs for invalid inputs will simply be undefined behaviour.
/// It is the user's responsibility to ensure that the `data`
/// is a valid base64 encoded string.
function decode(string memory data) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
let dataLength := mload(data)
if dataLength {
let decodedLength := mul(shr(2, dataLength), 3)
for {} 1 {} {
// If padded.
if iszero(and(dataLength, 3)) {
let t := xor(mload(add(data, dataLength)), 0x3d3d)
// forgefmt: disable-next-item
decodedLength := sub(
decodedLength,
add(iszero(byte(30, t)), iszero(byte(31, t)))
)
break
}
// If non-padded.
decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))
break
}
result := mload(0x40)
// Write the length of the bytes.
mstore(result, decodedLength)
// Skip the first slot, which stores the length.
let ptr := add(result, 0x20)
let end := add(ptr, decodedLength)
// Load the table into the scratch space.
// Constants are optimized for smaller bytecode with zero gas overhead.
// `m` also doubles as the mask of the upper 6 bits.
let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc
mstore(0x5b, m)
mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064)
mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4)
for {} 1 {} {
// Read 4 bytes.
data := add(data, 4)
let input := mload(data)
// Write 3 bytes.
// forgefmt: disable-next-item
mstore(ptr, or(
and(m, mload(byte(28, input))),
shr(6, or(
and(m, mload(byte(29, input))),
shr(6, or(
and(m, mload(byte(30, input))),
shr(6, mload(byte(31, input)))
))
))
))
ptr := add(ptr, 3)
if iszero(lt(ptr, end)) { break }
}
mstore(0x40, add(end, 0x20)) // Allocate the memory.
mstore(end, 0) // Zeroize the slot after the bytes.
mstore(0x60, 0) // Restore the zero slot.
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Read and write to persistent storage at a fraction of the cost.
/// @author Solady (https://github.com/vectorized/solmady/blob/main/src/utils/SSTORE2.sol)
/// @author Saw-mon-and-Natalie (https://github.com/Saw-mon-and-Natalie)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)
/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)
library SSTORE2 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev We skip the first byte as it's a STOP opcode,
/// which ensures the contract can't be called.
uint256 internal constant DATA_OFFSET = 1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unable to deploy the storage contract.
error DeploymentFailed();
/// @dev The storage contract address is invalid.
error InvalidPointer();
/// @dev Attempt to read outside of the storage contract's bytecode bounds.
error ReadOutOfBounds();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* WRITE LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Writes `data` into the bytecode of a storage contract and returns its address.
function write(bytes memory data) internal returns (address pointer) {
/// @solidity memory-safe-assembly
assembly {
let originalDataLength := mload(data)
// Add 1 to data size since we are prefixing it with a STOP opcode.
let dataSize := add(originalDataLength, DATA_OFFSET)
/**
* ------------------------------------------------------------------------------+
* Opcode | Mnemonic | Stack | Memory |
* ------------------------------------------------------------------------------|
* 61 dataSize | PUSH2 dataSize | dataSize | |
* 80 | DUP1 | dataSize dataSize | |
* 60 0xa | PUSH1 0xa | 0xa dataSize dataSize | |
* 3D | RETURNDATASIZE | 0 0xa dataSize dataSize | |
* 39 | CODECOPY | dataSize | [0..dataSize): code |
* 3D | RETURNDATASIZE | 0 dataSize | [0..dataSize): code |
* F3 | RETURN | | [0..dataSize): code |
* 00 | STOP | | |
* ------------------------------------------------------------------------------+
* @dev Prefix the bytecode with a STOP opcode to ensure it cannot be called.
* Also PUSH2 is used since max contract size cap is 24,576 bytes which is less than 2 ** 16.
*/
mstore(
// Do a out-of-gas revert if `dataSize` is more than 2 bytes.
// The actual EVM limit may be smaller and may change over time.
add(data, gt(dataSize, 0xffff)),
// Left shift `dataSize` by 64 so that it lines up with the 0000 after PUSH2.
or(0xfd61000080600a3d393df300, shl(0x40, dataSize))
)
// Deploy a new contract with the generated creation code.
pointer := create(0, add(data, 0x15), add(dataSize, 0xa))
// If `pointer` is zero, revert.
if iszero(pointer) {
// Store the function selector of `DeploymentFailed()`.
mstore(0x00, 0x30116425)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Restore original length of the variable size `data`.
mstore(data, originalDataLength)
}
}
/// @dev Writes `data` into the bytecode of a storage contract with `salt`
/// and returns its deterministic address.
function writeDeterministic(bytes memory data, bytes32 salt)
internal
returns (address pointer)
{
/// @solidity memory-safe-assembly
assembly {
let originalDataLength := mload(data)
let dataSize := add(originalDataLength, DATA_OFFSET)
mstore(
// Do a out-of-gas revert if `dataSize` is more than 2 bytes.
// The actual EVM limit may be smaller and may change over time.
add(data, gt(dataSize, 0xffff)),
// Left shift `dataSize` by 64 so that it lines up with the 0000 after PUSH2.
or(0xfd61000080600a3d393df300, shl(0x40, dataSize))
)
// Deploy a new contract with the generated creation code.
pointer := create2(0, add(data, 0x15), add(dataSize, 0xa), salt)
// If `pointer` is zero, revert.
if iszero(pointer) {
// Store the function selector of `DeploymentFailed()`.
mstore(0x00, 0x30116425)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Restore original length of the variable size `data`.
mstore(data, originalDataLength)
}
}
/// @dev Returns the initialization code hash of the storage contract for `data`.
/// Used for mining vanity addresses with create2crunch.
function initCodeHash(bytes memory data) internal pure returns (bytes32 hash) {
/// @solidity memory-safe-assembly
assembly {
let originalDataLength := mload(data)
let dataSize := add(originalDataLength, DATA_OFFSET)
// Do a out-of-gas revert if `dataSize` is more than 2 bytes.
// The actual EVM limit may be smaller and may change over time.
returndatacopy(returndatasize(), returndatasize(), shr(16, dataSize))
mstore(data, or(0x61000080600a3d393df300, shl(0x40, dataSize)))
hash := keccak256(add(data, 0x15), add(dataSize, 0xa))
// Restore original length of the variable size `data`.
mstore(data, originalDataLength)
}
}
/// @dev Returns the address of the storage contract for `data`
/// deployed with `salt` by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddress(bytes memory data, bytes32 salt, address deployer)
internal
pure
returns (address predicted)
{
bytes32 hash = initCodeHash(data);
/// @solidity memory-safe-assembly
assembly {
// Compute and store the bytecode hash.
mstore8(0x00, 0xff) // Write the prefix.
mstore(0x35, hash)
mstore(0x01, shl(96, deployer))
mstore(0x15, salt)
predicted := keccak256(0x00, 0x55)
// Restore the part of the free memory pointer that has been overwritten.
mstore(0x35, 0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* READ LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns all the `data` from the bytecode of the storage contract at `pointer`.
function read(address pointer) internal view returns (bytes memory data) {
/// @solidity memory-safe-assembly
assembly {
let pointerCodesize := extcodesize(pointer)
if iszero(pointerCodesize) {
// Store the function selector of `InvalidPointer()`.
mstore(0x00, 0x11052bb4)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Offset all indices by 1 to skip the STOP opcode.
let size := sub(pointerCodesize, DATA_OFFSET)
// Get the pointer to the free memory and allocate
// enough 32-byte words for the data and the length of the data,
// then copy the code to the allocated memory.
// Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
data := mload(0x40)
mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
mstore(data, size)
mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
extcodecopy(pointer, add(data, 0x20), DATA_OFFSET, size)
}
}
/// @dev Returns the `data` from the bytecode of the storage contract at `pointer`,
/// from the byte at `start`, to the end of the data stored.
function read(address pointer, uint256 start) internal view returns (bytes memory data) {
/// @solidity memory-safe-assembly
assembly {
let pointerCodesize := extcodesize(pointer)
if iszero(pointerCodesize) {
// Store the function selector of `InvalidPointer()`.
mstore(0x00, 0x11052bb4)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// If `!(pointer.code.size > start)`, reverts.
// This also handles the case where `start + DATA_OFFSET` overflows.
if iszero(gt(pointerCodesize, start)) {
// Store the function selector of `ReadOutOfBounds()`.
mstore(0x00, 0x84eb0dd1)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
let size := sub(pointerCodesize, add(start, DATA_OFFSET))
// Get the pointer to the free memory and allocate
// enough 32-byte words for the data and the length of the data,
// then copy the code to the allocated memory.
// Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
data := mload(0x40)
mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
mstore(data, size)
mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
extcodecopy(pointer, add(data, 0x20), add(start, DATA_OFFSET), size)
}
}
/// @dev Returns the `data` from the bytecode of the storage contract at `pointer`,
/// from the byte at `start`, to the byte at `end` (exclusive) of the data stored.
function read(address pointer, uint256 start, uint256 end)
internal
view
returns (bytes memory data)
{
/// @solidity memory-safe-assembly
assembly {
let pointerCodesize := extcodesize(pointer)
if iszero(pointerCodesize) {
// Store the function selector of `InvalidPointer()`.
mstore(0x00, 0x11052bb4)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// If `!(pointer.code.size > end) || (start > end)`, revert.
// This also handles the cases where
// `end + DATA_OFFSET` or `start + DATA_OFFSET` overflows.
if iszero(
and(
gt(pointerCodesize, end), // Within bounds.
iszero(gt(start, end)) // Valid range.
)
) {
// Store the function selector of `ReadOutOfBounds()`.
mstore(0x00, 0x84eb0dd1)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
let size := sub(end, start)
// Get the pointer to the free memory and allocate
// enough 32-byte words for the data and the length of the data,
// then copy the code to the allocated memory.
// Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
data := mload(0x40)
mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
mstore(data, size)
mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
extcodecopy(pointer, add(data, 0x20), add(start, DATA_OFFSET), size)
}
}
}{
"optimizer": {
"enabled": true,
"runs": 10
},
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_interfectorem","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"AdminApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"AdminRevoked","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"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"enum Manes.ImageType","name":"imageType","type":"uint8"},{"internalType":"bytes[]","name":"chunks","type":"bytes[]"}],"name":"appendChunks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"approveAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"buildImage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"files","outputs":[{"internalType":"string","name":"mimeType","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAdmins","outputs":[{"internalType":"address[]","name":"admins","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interfectorem","outputs":[{"internalType":"contract IInterfectorem","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum Manes.ImageType","name":"imageType","type":"uint8"}],"name":"loadImage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum Manes.ImageType","name":"imageType","type":"uint8"}],"name":"loadRawImage","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"metadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"enum Manes.ImageType","name":"imageType","type":"uint8"},{"internalType":"string","name":"mimeType","type":"string"},{"internalType":"bytes[]","name":"chunks","type":"bytes[]"}],"name":"overwriteChunks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint8[]","name":"colors","type":"uint8[]"}],"name":"replacePngPalette","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"revokeAdmin","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":"token1Image","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token2Image","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token3Image","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token4Image","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"_metadata","type":"string"}],"name":"updateToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"string[]","name":"metadataArray","type":"string[]"}],"name":"updateTokensBulk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"imageDataUris","type":"string[]"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"},{"internalType":"int256","name":"shift","type":"int256"}],"name":"wrapMultipleImages","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"imageDataUri","type":"string"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"name":"wrapSingleImage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
6080346200015157601f62005be338819003918201601f19168301916001600160401b0383118484101762000156578084926020946040528339810103126200015157516001600160a01b0390818116908190036200015157600090815460018060a01b031993338583161784553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e084604051a360049273735854c506cceb0b95c949d1acb705b31136d487818554161784556005541617600555805b600760ff821610620000db57604051615a7690816200016d8239f35b60038054680100000000000000008110156200013e57600181019081835510156200012b57825260ff8091169081146200011857600101620000bf565b506011602492634e487b7160e01b835252fd5b634e487b7160e01b835260328452602483fd5b634e487b7160e01b845260418552602484fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe6080604081815260048036101561001557600080fd5b600092833560e01c90816301ffc9a714611f5457508063177a8abb14611f365780631def138f14611f0c57806324d7806c14611eb957806325b3c67814611c8b5780632ba80eba14611c6a5780632d34567014611bfd57806331ae450b14611b355780633ccfd60b14611a9c5780633db9e12514611a7357806348fbc89b146114f55780635038cbd2146114d75780635aae942f14611420578063663e4463146112695780636a627842146111a85780636d73e66914611136578063715018a6146110eb5780638da5cb5b146110c357806397c04ee5146110a5578063b4a2f00214610761578063c2dc161c146106b7578063d068abc71461047a578063d74b81df1461045c578063e3684e3914610433578063e9dc63751461033c578063f1bcb3f714610263578063f2fde38b146101b35763f4c714b41461015757600080fd5b346101af5760203660031901126101af57356003548110156101af5760039092526101ab916101989060011b600080516020615801833981519152016121af565b9051918291602083526020830190611fe2565b0390f35b8280fd5b50346101af5760203660031901126101af576101cd612007565b6101d561241d565b6001600160a01b03908116918215610211575083546001600160a01b0319811683178555925192166000805160206159418339815191528484a3f35b608490602085519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b508290346103345782600319360112610334576001600160401b039080358281116103385736602382011215610338576102a690369060248185013591016120dc565b90602435928311610338573660238401121561033857820135916102c98361215e565b926102d68651948561209e565b80845260209460248686019260051b8401019236841161033457602401915b83831061031b5787876101ab61030b8989613ca4565b9251928284938452830190611fe2565b823560ff811681036101af5781529186019186016102f5565b5080fd5b8380fd5b505034610334578060031936011261033457906101ab61040b9261035e612007565b50610424602160243580865261037c846020976006895220916151c6565b906103fa600d865180946103b98b8301957b646174613a6170706c69636174696f6e2f6a736f6e3b757466382c7b60201b8752603c8401906128c5565b6b16101134b6b0b3b2911d101160a11b81528151916103e0908390600c8401908f01611fbf565b01601160f91b600c8201520360121981018552018361209e565b845197889251809289850190611fbf565b8101607d60f81b8782015203600181018752018561209e565b51928284938452830190611fe2565b50346101af5760203660031901126101af57816101ab93610198923581526006602052206121af565b5050346103345781600319360112610334576101ab9061019861297d565b5091903461033457608036600319011261033457610496612007565b602435936007851015610338576001600160401b03946044358681116106b3576104c39036908401612131565b9390966064358181116106af576104dd9036908601612022565b95909487518094630935e01b60e21b82523383830152816024602097889360018060a01b03165afa9081156106a5579061051e918b91610678575b5061263c565b61052661241d565b61052f85612352565b5092821161066557506105428254612175565b601f811161062c575b5087601f82116001146105c5578190899a61059e999a926105ba575b50508160011b916000199060031b1c19161790555b600161058783612352565b500190815490888355816105a1575b505050612705565b51f35b6105b292895288209081019061269c565b388080610596565b013590503880610567565b82895283892090601f1983168a5b81811061061557509a83929160019461059e9b9c9d106105fb575b505050811b01905561057c565b0135600019600384901b60f8161c191690553880806105ee565b919286600181928f870135815501940192016105d3565b61065590838a52848a20601f840160051c81019186851061065b575b601f0160051c019061269c565b3861054b565b9091508190610648565b634e487b7160e01b895260419052602488fd5b6106989150863d881161069e575b610690818361209e565b810190612624565b38610518565b503d610686565b89513d8c823e3d90fd5b8780fd5b8580fd5b50829034610334576020366003190112610334573590600782101561075e576101ab61071b8461074c6008866106fe6106f96106f283612352565b509261281a565b61566e565b8451958692643230ba309d60d91b602085015260258401906128c5565b670ed8985cd94d8d0b60c21b815261073c8251809360208785019101611fbf565b010360171981018552018361209e565b51918291602083526020830190611fe2565b80fd5b50919034610334576080366003190112610334578235916001600160401b0380841161033457366023850112156103345783850135936107a08561215e565b916107ad8551938461209e565b858352602091828401906024809860051b820101923684116110a157888201925b84841061107757505050505084359360443596606435968451156110495750506107f78561545e565b926108018861545e565b610aaa6101ca6108108961545e565b9661081a8c61545e565b9786519485927101e39bb33903b34b2bba137bc1e91181018160751b8a85015261084d815180928c603288019101611fbf565b8301600160fd1b603282015261086c825180938c603385019101611fbf565b016811103bb4b23a341e9160b91b6033820152610892825180938b603c85019101611fbf565b01976911103432b4b3b43a1e9160b11b9889603c8201526108bc825180938b604685019101611fbf565b017f2220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f60468201527f7376672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e60668201526f37b93397989c9c9c97bc3634b735911f60811b60868201527f3c646566733e3c7374796c653e696d616765207b696d6167652d72656e64657260968201527f696e673a206f7074696d697a6553706565643b696d6167652d72656e6465726960b68201527f6e673a202d6d6f7a2d63726973702d65646765733b696d6167652d72656e646560d68201527f72696e673a202d6f2d63726973702d65646765733b696d6167652d72656e646560f68201527f72696e673a202d7765626b69742d6f7074696d697a652d636f6e74726173743b6101168201527f696d6167652d72656e646572696e673a206f7074696d697a652d636f6e7472616101368201527f73743b696d6167652d72656e646572696e673a2063726973702d65646765733b6101568201527f696d6167652d72656e646572696e673a20706978656c617465643b2d6d732d696101768201527f6e746572706f6c6174696f6e2d6d6f64653a206e6561726573742d6e65696768610196820152733137b91dbe9e17b9ba3cb6329f1e17b232b3399f60611b6101b6820152036101aa81018452018261209e565b9385945b8251861015610c3f5787908a888b610ac68a88612409565b515115610c31579288610be093610b07610b01605195610aeb8f99610be69b9a6152c9565b908112610bec57610afb9061545e565b9761545e565b9161545e565b610b118d8b612409565b5191898c519886610b2b8b9851809289808c019101611fbf565b8701691e34b6b0b3b2903c1e9160b11b87820152815190610b5482602a948a8685019101611fbf565b01907011103c9e9118383c11103bb4b23a341e9160791b90820152825190610b8482603b95898785019101611fbf565b0191820152815190610b9e82604594878685019101611fbf565b0190671110343932b31e9160c11b90820152610bc482518093604d958685019101611fbf565b0190631110179f60e11b9082015203603181018452018261209e565b956123a7565b94610aae565b610bf8610bfd91615332565b61545e565b610afb8d5191602d60f81b87840152828151610c21816021948b8686019101611fbf565b810103600181018452018261209e565b50505095610be691506123a7565b979450509190610c4e8661545e565b610d62608d610c5c8b61545e565b99610c668a61545e565b610c6f8d61545e565b9b86519583610c8788955180928c8089019101611fbf565b84016000805160206159e183398151915260511b8a820152610cb2825180938c603685019101611fbf565b016b383c11103432b4b3b43a1e9160a11b6036820152610cdb825180938b604285019101611fbf565b0160008051602061590183398151915260428201526000805160206159a183398151915260291b6062820152610d1a825180938a607d85019101611fbf565b019a6a383c1d903432b4b3b43a1d60a91b9b8c607d820152610d45825180938a608885019101611fbf565b0164383c1d911f60d91b608882015203606d81018452018261209e565b9285935b8151851015610fb2578989898989610d7e8a88612409565b515115610fa357886000805160206158c183398151915288610e1e97610f679761018b978f610df38f9891610ded610f6d9f9b8b610de7918c610dcf69383c1d903bb4b23a341d60b11b98876152c9565b918212610f735750610de1915061545e565b9561545e565b9661545e565b96612409565b51976f03a37b81d1018383c1d903632b33a1d160851b8882519e8f8d83829f51948593019101611fbf565b8b01916000805160206157e18339815191528a840152820152825190610e4c826050958b8785019101611fbf565b0191820152825190610e6682605a95898785019101611fbf565b0191820152610e7f825180936065968785019101611fbf565b019182015260008051602061598183398151915260858201526000805160206158e183398151915260a58201526000805160206157c183398151915260c58201526000805160206159c183398151915260e5820152600080516020615821833981519152610105820152600080516020615a218339815191526101258201526000805160206157a1833981519152610145820152600080516020615a01833981519152610165820152611e9160f11b610185820152815190610f4a82610187948d8685019101611fbf565b0190631110179f60e11b908201520361016b81018452018261209e565b946123a7565b93610d66565b610f82610bf8610de193615332565b92518093602d60f81b83830152610c21815180926021958686019101611fbf565b505050505093610f6d906123a7565b836101ab61100a85936106f9603c865183610fd682955180928a8086019101611fbf565b81017b1e17b234bb1f1e17b337b932b4b3b727b13532b1ba1f1e17b9bb339f60211b8882015203601c81018452018261209e565b92610424603a825180966000805160206158618339815191528783015261103981518092898686019101611fbf565b810103601a81018752018561209e565b606493601f9293519362461bcd60e51b85528401528201526000805160206158818339815191526044820152fd5b833582811161109d57869161109283928d3691880101612113565b8152019301926107ce565b8880fd5b8680fd5b5050346103345781600319360112610334576101ab9061019861346f565b505034610334578160031936011261033457905490516001600160a01b039091168152602090f35b50503461033457816003193601126103345761110561241d565b81546001600160a01b03198116835590519082906001600160a01b03166000805160206159418339815191528284a3f35b50503461033457602036600319011261033457611151612007565b61115961241d565b6001600160a01b031661116b81612527565b15611174575051f35b6111a49033817f7e1a1a08d52e4ba0e21554733d66165fd5151f99460116223d9e3a608eec5cb1868651a36124a8565b5051f35b508260209182600319360112610334576001600160a01b036111c8612007565b16845191630935e01b60e21b835233818401528483602481855afa90811561125f576111fe60249287958791610678575061263c565b61120661241d565b86519485938492630525194b60e31b845233908401525af180156112525761122d57505051f35b813d831161124b575b611240818361209e565b810103126103345751f35b503d611236565b50505051903d90823e3d90fd5b86513d86823e3d90fd5b5091903461033457606036600319011261033457611285612007565b926001600160401b039060443582811161141c576112a69036908301612131565b8451630935e01b60e21b815233818501526020979193918890829060249082906001600160a01b03165afa90811561141257906112e99188916113fb575061263c565b6112f161241d565b6024358652600687528486209383116113e8575061130f8354612175565b601f81116113ba575b508495601f83116001146113565750948495829394959261134b575b50508160011b916000199060031b1c191617905551f35b013590503880611334565b90601f198316968487528287209287905b8982106113a25750508360019596979810611388575b505050811b01905551f35b0135600019600384901b60f8161c1916905538808061137d565b80600184968294958701358155019501920190611367565b6113e290848752878720601f850160051c81019189861061065b57601f0160051c019061269c565b38611318565b634e487b7160e01b865260419052602485fd5b6106989150893d8b1161069e57610690818361209e565b86513d89823e3d90fd5b8480fd5b50346101af5760603660031901126101af5761143a612007565b9060243590600782101561141c57604435916001600160401b0383116106b35761146960209336908401612022565b9390926024875180978193630935e01b60e21b8352339083015260018060a01b03165afa9384156114cd5761059e946114a89188916114b5575061263c565b6114b061241d565b612705565b610698915060203d811161069e57610690818361209e565b85513d88823e3d90fd5b5050346103345781600319360112610334576101ab90610198614175565b508290346103345760603660031901126103345780356001600160401b0381116101af576115269036908301612113565b906024359160443591611537612948565b91611541836123cc565b5261154b826123cc565b50815115611a42575061155d8361545e565b906115678361545e565b916115718561545e565b6116256101ca6115808761545e565b958a519384916020967101e39bb33903b34b2bba137bc1e91181018160751b888501526115b6815180928a603288019101611fbf565b8301600160fd1b60328201526115d5825180938a603385019101611fbf565b016811103bb4b23a341e9160b91b60338201526115fb8251809389603c85019101611fbf565b01966911103432b4b3b43a1e9160b11b9788603c8201526108bc8251809389604685019101611fbf565b9186925b815184101561174057869061163e8584612409565b5151156117355790611729605161172f938c8a888b61166d61166761166161539f565b9961545e565b9361545e565b926116788d8c612409565b51945198866116908b9851809287808c019101611fbf565b8701691e34b6b0b3b2903c1e9160b11b858201528151906116b982602a94888685019101611fbf565b01907011103c9e9118383c11103bb4b23a341e9160791b908201526116e882518093603b968785019101611fbf565b0191820152815190611702826045948d8685019101611fbf565b0190671110343932b31e9160c11b90820152815190610bc482604d948c8685019101611fbf565b936123a7565b92611629565b9361172f91506123a7565b935095915061174e8561545e565b611845608d61175c8761545e565b956117668961545e565b61176f8961545e565b978c51958361178788955180928b8089019101611fbf565b84016000805160206159e183398151915260511b898201526117b2825180938b603685019101611fbf565b016b383c11103432b4b3b43a1e9160a11b60368201526117db825180938a604285019101611fbf565b0160008051602061590183398151915260428201526000805160206159a183398151915260291b606282015261181a8251809389607d85019101611fbf565b01966a383c1d903432b4b3b43a1d60a91b9788607d820152610d458251809389608885019101611fbf565b8651831015611a1e57878785878961185d8885612409565b515115611a0f5793611a03936000805160206158c18339815191528861018b95611a0999956118d79969383c1d903bb4b23a341d60b11b6118ac8f6118a6610de1610de161539f565b98612409565b51976f03a37b81d1018383c1d903632b33a1d160851b8682519e8f8d83829f51948593019101611fbf565b8b01916000805160206157e18339815191528884015282015282519061190582605095898785019101611fbf565b019182015261191e82518093605a968785019101611fbf565b0191820152825190611938826065958d8785019101611fbf565b019182015260008051602061598183398151915260858201526000805160206158e183398151915260a58201526000805160206157c183398151915260c58201526000805160206159c183398151915260e5820152600080516020615821833981519152610105820152600080516020615a218339815191526101258201526000805160206157a1833981519152610145820152600080516020615a01833981519152610165820152611e9160f11b610185820152815190610f4a82610187948b8685019101611fbf565b926123a7565b91611845565b505050505091611a09906123a7565b906101ab61100a89936106f9603c865183610fd682955180928a8086019101611fbf565b606490602087519162461bcd60e51b8352820152601f60248201526000805160206158818339815191526044820152fd5b50503461033457816003193601126103345760055490516001600160a01b039091168152602090f35b50346101af57826003193601126101af57611ab561241d565b8054825184918291829147906001600160a01b03165af13d15611b30573d611adc816120c1565b90611ae98551928361209e565b81528460203d92013e5b15611afc575051f35b6020606492519162461bcd60e51b8352820152600f60248201526e1dda5d1a191c985dc819985a5b1959608a1b6044820152fd5b611af3565b5050346103345781600319360112610334576001805492611b558461215e565b611b618451918261209e565b848152611b6d8561215e565b6020828101969091601f1901368837835b818110611bc35750508451948186019282875251809352850195925b828110611ba75785870386f35b83516001600160a01b0316875295810195928101928401611b9a565b85855282852081015495979593949293611bf191906001600160a01b0316611beb8288612409565b526123a7565b96949693929193611b7e565b50503461033457602036600319011261033457611c18612007565b611c2061241d565b6001600160a01b0316611c3281612527565b611c3a575051f35b6111a49033817f7c0c3c84c67c85fcac635147348bfe374c24a1a93d0366d1cfe9d8853cbf89d5868651a361253a565b50913461075e57602036600319011261075e57506101986101ab92356151c6565b50346101af5760603660031901126101af57611ca5612007565b906001600160401b0390602480358381116110a157611cc79036908401612022565b94909160443585811161109d57611ce19036908601612022565b8851630935e01b60e21b8152338782015260209491929185908290869082906001600160a01b03165afa8015611eaf57611d21918c91610678575061263c565b611d2961241d565b818803611e745789805b898110611d3f57508951f35b611d4a8185856126b3565b8c60059484861b8b0135815260068a5220918b8211611e62578e611d6e8454612175565b958a601f97888111611e2c575b50505080958311600114611dc057611dae95909183611db5575b50508160011b916000199060031b1c19161790556123a7565b8a90611d33565b013590503880611d95565b91929394601f1984168584528a8420935b8b828210611e165750509084611dae97969594939210611dfc575b505050600190811b0190556123a7565b0135600019600384901b60f8161c19169055388080611dec565b6001849682939587013581550195019201611dd1565b611e51928785528983862092818901831c8401948910611e59575b01901c019061269c565b388a81611d7b565b93508293611e47565b634e487b7160e01b8f5260418b52878ffd5b885162461bcd60e51b815280870185905260168185015275082e4e4c2f2e640d8cadccee8d040dad2e6dac2e8c6d60531b6044820152606490fd5b8a513d8d823e3d90fd5b5050346103345760203660031901126103345790602091611ed8612007565b91546001600160a01b0392831692168214918215611efa575b50519015158152f35b611f05919250612527565b9038611ef1565b50346101af5760203660031901126101af573591600783101561075e57506101986101ab9261281a565b5050346103345781600319360112610334576101ab90610198614a71565b925050346101af5760203660031901126101af57356001600160e01b03198116808203610338576020935063e9dc637560e01b14908115611fae575b8115611f9e575b5015158152f35b611fa891506155c0565b38611f97565b9050611fb9816155c0565b90611f90565b60005b838110611fd25750506000910152565b8181015183820152602001611fc2565b90602091611ffb81518092818552858086019101611fbf565b601f01601f1916010190565b600435906001600160a01b038216820361201d57565b600080fd5b9181601f8401121561201d578235916001600160401b03831161201d576020808501948460051b01011161201d57565b606081019081106001600160401b0382111761206d57604052565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761206d57604052565b601f909101601f19168101906001600160401b0382119082101761206d57604052565b6001600160401b03811161206d57601f01601f191660200190565b9291926120e8826120c1565b916120f6604051938461209e565b82948184528183011161201d578281602093846000960137010152565b9080601f8301121561201d5781602061212e933591016120dc565b90565b9181601f8401121561201d578235916001600160401b03831161201d576020838186019501011161201d57565b6001600160401b03811161206d5760051b60200190565b90600182811c921680156121a5575b602083101461218f57565b634e487b7160e01b600052602260045260246000fd5b91607f1691612184565b90604051918260008254926121c384612175565b90818452600194858116908160001461223257506001146121ef575b50506121ed9250038361209e565b565b9093915060005260209081600020936000915b81831061221a5750506121ed935082010138806121df565b85548884018501529485019487945091830191612202565b9150506121ed94506020925060ff191682840152151560051b82010138806121df565b6003546005101561228b57600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f86591565b634e487b7160e01b600052603260045260246000fd5b6003541561228b576003600090815260008051602061580183398151915291565b6003546001101561228b576003600090815260008051602061584183398151915291565b6003546002101561228b57600360009081526000805160206158a183398151915291565b6003546003101561228b576003600090815260008051602061596183398151915291565b6003546004101561228b576003600090815260008051602061592183398151915291565b60035481101561228b57600360005260206000209060011b0190600090565b6003546006101561228b57600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f86791565b60001981146123b65760010190565b634e487b7160e01b600052601160045260246000fd5b80511561228b5760200190565b80516001101561228b5760400190565b80516002101561228b5760600190565b80516003101561228b5760800190565b805182101561228b5760209160051b010190565b6000546001600160a01b0316330361243157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60015481101561228b57600160005260206000200190600090565b805482101561228b5760005260206000200190600090565b60008181526002602052604081205461252257600154600160401b81101561250e5790826124fa6124e184600160409601600155612475565b819391549060031b600019811b9283911b169119161790565b905560015492815260026020522055600190565b634e487b7160e01b82526041600452602482fd5b905090565b6000526002602052604060002054151590565b600081815260026020526040812054909190801561261f576000199080820181811161260b57600154908382019182116125f7578082036125c3575b50505060015480156125af5781019061258e82612475565b909182549160031b1b19169055600155815260026020526040812055600190565b634e487b7160e01b84526031600452602484fd5b6125e16125d26124e193612475565b90549060031b1c928392612475565b9055845260026020526040842055388080612576565b634e487b7160e01b86526011600452602486fd5b634e487b7160e01b85526011600452602485fd5b505090565b9081602091031261201d5751801515810361201d5790565b1561264357565b60405162461bcd60e51b815260206004820152602b60248201527f57616c6c6574206973206e6f7420616e2061646d696e6973747261746f72206660448201526a1bdc8818dbdb9d1c9858dd60aa1b6064820152608490fd5b8181106126a7575050565b6000815560010161269c565b919081101561228b5760051b81013590601e198136030182121561201d5701803591906001600160401b03831161201d57602001823603811361201d579190565b60ff1660ff81146123b65760010190565b91909260005b60ff811690838210156127e65760078510156127d05761272a85612352565b5061274561273e600180930194878a6126b3565b36916120dc565b90815181810161ffff8160401b6bfd61000080600a3d393df300179111840152600b8101601584016000f09283156127c257528354600160401b81101561206d576127bd946127979282018155612490565b819291549060031b9160018060a01b039283811b93849216901b169119161790556126f4565b61270b565b63301164256000526004601cfd5b634e487b7160e01b600052602160045260246000fd5b505092505050565b8060001904600311811515166123b65760030290565b8060001904600211811515166123b65760011b90565b600060605b60078310156127d05761283183612352565b5060018091015460ff841610156128be57906128b2612878612861856128b89561285a89612352565b5001612490565b905460039190911b1c6001600160a01b031661575c565b916040518093825161289281602095868087019101611fbf565b82016128a682518093868085019101611fbf565b0103808452018261209e565b916126f4565b9061281f565b5091505090565b6000929181546128d481612175565b9260019180831690811561292d57506001146128f1575b50505050565b90919293945060005260209081600020906000915b85831061291c57505050500190388080806128eb565b805485840152918301918101612906565b60ff19168452505050811515909102019150388080806128eb565b60405161295481612083565b600181528060005b6020808210156129775790606060209282850101520161295c565b50505090565b60055460408051632495a06960e21b8152909161554091908290829060049082906001600160a01b03165afa918215613434576000926133ba575b5050815161424d60f01b6020820152617e5560f01b602282015260006026820152601f60f91b602a820152600e81529091906129f381612083565b815190600560fb1b6020830152602493600160f11b8584015261550160f01b6028840152600160f81b80602c850152602e8401526000603084015261405560f01b6034840152600060388401526000603c840152600160f91b848401526000604484015260288352612a6483612052565b8351607d60f91b6020820152608f60f81b6021820152603f60f91b6022820152600060238201819052602f60f81b878301819052602583018190526026830152602782015260088152612ab681612083565b8451916202aa2083016001600160401b038111848210176133a55786526202aa0080845236602085013760005b6101558110613286575050612b4b93926106f99260209287519583612b118895518092888089019101611fbf565b8401612b2582518093888085019101611fbf565b01612b3882518093878085019101611fbf565b016128a682518093868085019101611fbf565b92612b976036835180967519185d184e9a5b5859d94bd89b5c0ed8985cd94d8d0b60521b6020830152612b878151809260208686019101611fbf565b810103601681018752018561209e565b815193612ba385612052565b6002855260005b8381106132755750612bbb856123cc565b52612bc5846123cc565b5060039081541561326057816000526020600020906060956000965b612be96122a1565b5060018091015460ff8a161015612c4b5790612c3f6020612c27612c138c612c459661285a6122a1565b9054908a1b1c6001600160a01b031661575c565b92895193816128928693518092868087019101611fbf565b976126f4565b96612be1565b50612cb392975060089196945092612c65612c829461566e565b8651948592643230ba309d60d91b602085015260258401906128c5565b670ed8985cd94d8d0b60c21b8152612ca38251809360208785019101611fbf565b010360171981018452018261209e565b612cbc846123d9565b52612cc6836123d9565b508251156132305750612cd7615343565b90612ce0615390565b612d9e6101ca612cee615343565b94612cf7615390565b9585519485927101e39bb33903b34b2bba137bc1e91181018160751b6020850152612d2c815180926020603288019101611fbf565b8301600160fd1b6032820152612d4c825180936020603385019101611fbf565b016811103bb4b23a341e9160b91b6033820152612d73825180936020603c85019101611fbf565b01956911103432b4b3b43a1e9160b11b9687603c8201526108bc825180936020604685019101611fbf565b926000935b8151851015612eb157612db68583612409565b515115612ea757612ea190610f676051612dce61539f565b92612dd7615343565b612ddf615390565b612de98b89612409565b51918a8a519785612e048a975180926020808b019101611fbf565b8601691e34b6b0b3b2903c1e9160b11b6020820152612e2d825180936020602a85019101611fbf565b017011103c9e9118383c11103bb4b23a341e9160791b602a820152825190612e5e82603b9560208785019101611fbf565b0191820152815190612e798260459460208685019101611fbf565b0190671110343932b31e9160c11b90820152815190610bc482604d9460208685019101611fbf565b93612da3565b93612ea1906123a7565b9350909150612ebe615343565b612fb8608d612ecb615390565b95612ed4615343565b612edc615390565b9787519583612ef5889551809260208089019101611fbf565b84016000805160206159e183398151915260511b6020820152612f22825180936020603685019101611fbf565b016b383c11103432b4b3b43a1e9160a11b6036820152612f4c825180936020604285019101611fbf565b0160008051602061590183398151915260428201526000805160206159a183398151915260291b6062820152612f8c825180936020607d85019101611fbf565b01966a383c1d903432b4b3b43a1d60a91b9788607d820152610d45825180936020608885019101611fbf565b926000935b825185101561319557612fd08584612409565b51511561318b57613053610f6761018b6131859387876000805160206158c18339815191528b89612fff61539f565b69383c1d903bb4b23a341d60b11b613027613018615343565b94613021615390565b97612409565b51966f03a37b81d1018383c1d903632b33a1d160851b602082519d8e8c83829e51948593019101611fbf565b8a01916000805160206157e183398151915260208401528201528251906130838260509560208785019101611fbf565b019182015282519061309e82605a9560208785019101611fbf565b01918201528251906130b98260659560208785019101611fbf565b019182015260008051602061598183398151915260858201526000805160206158e183398151915260a58201526000805160206157c183398151915260c58201526000805160206159c183398151915260e5820152600080516020615821833981519152610105820152600080516020615a218339815191526101258201526000805160206157a1833981519152610145820152600080516020615a01833981519152610165820152611e9160f11b610185820152815190610f4a826101879460208685019101611fbf565b93612fbd565b93613185906123a7565b61212e939450603a92506131f591506106f9603c8651836131c0829551809260208086019101611fbf565b81017b1e17b234bb1f1e17b337b932b4b3b727b13532b1ba1f1e17b9bb339f60211b602082015203601c81018452018261209e565b9251809360008051602061586183398151915260208301526132208151809260208686019101611fbf565b810103601a81018452018261209e565b601f606492519162461bcd60e51b8352602060048401528201526000805160206158818339815191526044820152fd5b83634e487b7160e01b60005260326004526000fd5b806060602080938901015201612baa565b610154808281031161337b576000198183141583830382046102001116613390578290046002118215151661337b57600182811b6132c4818661344c565b51918101809111613347576132d9908561344c565b519183900360061b6040600160fd1b0316919060005b6020811061335c57505060005b6020811061331557505050613310906123a7565b612ae3565b602083018311613347578082613342921a61333c613336836020880161343f565b8a61345e565b536123a7565b6132fc565b8a634e487b7160e01b60005260116004526000fd5b8082613376921a61333c613370838861343f565b8b61345e565b6132ef565b88634e487b7160e01b60005260116004526000fd5b89634e487b7160e01b60005260116004526000fd5b87634e487b7160e01b60005260416004526000fd5b803d821161342d575b6133cd818461209e565b82019181818403126103385782601f82011215610338578451938285016001600160401b0381118682101761250e5786528492820193841161075e5750905b82821061341d5750505038806129b8565b815181526020918201910161340c565b503d6133c3565b83513d6000823e3d90fd5b919082018092116123b657565b906102aa81101561228b5760051b0190565b90815181101561228b570160200190565b6040519060a082016001600160401b0381118382101761206d576040526004825260005b60808110613c375750600554604051633a707e8b60e21b815290602090829060049082906001600160a01b03165afa908115613c2b57600091613bf9575b5060035491826001101561228b576003600090815260008051602061584183398151915293909260605b60016135056122c2565b50015460ff861610156135515761354b90613545602061352c61286189600161285a6122c2565b9260405193816128928693518092868087019101611fbf565b946126f4565b936134fb565b612c8292945061358691939561356860089261566e565b604051948592643230ba309d60d91b602085015260258401906128c5565b61358f856123cc565b52613599846123cc565b50604b6103e8820410613b6b575b60326103e8820410613ad6575b6103e86019910410613a48575b50815115613a15576135d1615390565b6135d9615343565b6136986101ca6135e7615390565b936135f0615343565b946040519485927101e39bb33903b34b2bba137bc1e91181018160751b6020850152613626815180926020603288019101611fbf565b8301600160fd1b6032820152613646825180936020603385019101611fbf565b016811103bb4b23a341e9160b91b603382015261366d825180936020603c85019101611fbf565b01946911103432b4b3b43a1e9160b11b9586603c8201526108bc825180936020604685019101611fbf565b906000915b845183101561376b576136b08386612409565b5151156137615761375b90611a0360516136c861539f565b926136d1615390565b6136d9615343565b6136e3898c612409565b51918860405197856136ff8a975180926020808b019101611fbf565b8601691e34b6b0b3b2903c1e9160b11b602082015281519061372a82602a9460208685019101611fbf565b01907011103c9e9118383c11103bb4b23a341e9160791b90820152825190612e5e82603b9560208785019101611fbf565b9161369d565b9161375b906123a7565b92915050613777615390565b613872608d613784615343565b9461378d615390565b613795615343565b9660405195836137af889551809260208089019101611fbf565b84016000805160206159e183398151915260511b60208201526137dc825180936020603685019101611fbf565b016b383c11103432b4b3b43a1e9160a11b6036820152613806825180936020604285019101611fbf565b0160008051602061590183398151915260428201526000805160206159a183398151915260291b6062820152613846825180936020607d85019101611fbf565b01956a383c1d903432b4b3b43a1d60a91b9687607d820152610d45825180936020608885019101611fbf565b906000925b84518410156139bf5761388a8486612409565b5151156139b35761389961539f565b9261055492604051906138ab82612083565b6004825260208201946020368737602483015b6000190190600a906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a835304908982156138ef57506138be565b6139499592506139a59491506000805160206158c183398151915261018b949a98886139ab999b6139228c610ded615343565b519569383c1d903bb4b23a341d60b11b60206040519c8d8b83829d51948593019101611fbf565b89016000805160206157e183398151915260208201526f03a37b81d1018383c1d903632b33a1d160851b604082015283519061398e8260509660208885019101611fbf565b0192830152519061309e82605a9586840190611fbf565b916123a7565b929091613877565b9190926139ab906123a7565b5092506139e491506106f9603c604051836131c0829551809260208086019101611fbf565b61212e603a604051809360008051602061586183398151915260208301526132208151809260208686019101611fbf565b60405162461bcd60e51b815260206004820152601f60248201526000805160206158818339815191526044820152606490fd5b6004101561228b57600360009081526000805160206159218339815191529160605b6001613a7461232e565b50015460ff84161015613aa757613aa190613a9b602061352c61286187600161285a61232e565b926126f4565b91613a6a565b612c829250613abc919361356860089261566e565b613ac5836123f9565b52613acf826123f9565b50386135c1565b9091826003101561228b576003600090815260008051602061596183398151915293909260605b6001613b0761230a565b50015460ff86161015613b3457613b2e90613545602061352c61286189600161285a61230a565b93613afd565b6103e8929450613b4f600860199597613568612c829461566e565b613b58876123e9565b52613b62866123e9565b509150506135b4565b9091826002101561228b57600360009081526000805160206158a183398151915293909260605b6001613b9c6122e6565b50015460ff86161015613bc957613bc390613545602061352c61286189600161285a6122e6565b93613b92565b612c82929450613be091939561356860089261566e565b613be9856123d9565b52613bf3846123d9565b506135a7565b906020823d602011613c23575b81613c136020938361209e565b8101031261075e575051386134d1565b3d9150613c06565b6040513d6000823e3d90fd5b806060602080938601015201613493565b6001600160f81b03199182168152918116600183015291821660028201529116600382015260040190565b906020825192015163ffffffff60e01b908181169360048110613c9557505050565b60040360031b82901b16169150565b919091600860005b825182108061416d575b1561416857506001600160f81b031980613cd0838561345e565b511691600181018082116123b657613ce983918661345e565b511691600282018083116123b657613d0282918761345e565b5116600383018084116123b65782613d1d613d4f928961345e565b511694613d36604096875194859360209a8b8601613c48565b0391613d4a601f199384810183528261209e565b613c73565b60e01c9460049485850180861161415357613d6b85918a61345e565b5116936005860180871161413e57613d8482918b61345e565b51166006870180881161412957613d9c83918c61345e565b511691600788018089116141145791613dce9391613dc0613dda989796948e61345e565b511692519788958601613c48565b0390810183528261209e565b63504c544560e01b906001600160e01b031990613df690613c73565b1614613e2f57600c91838301809311613e1a575090613e149161343f565b90613cac565b601190634e487b7160e01b6000525260246000fd5b9190505b60009260605b8651851015613e9657613e9090610f676021613e55888b612409565b51926040519381859251613e7181602093848088019101611fbf565b83019160ff60f81b9060f81b169082015203600181018452018261209e565b93613e39565b949193509194506040519163504c544560e01b602084015284519483602496613ec58189840160208601611fbf565b810103613edb876004928381018852018661209e565b60405195600061202088016001600160401b0381118982101761410257604052610100908189526120003660208b0137805b8281106140b75750505063ffffffff986000995b87518b1015613f5757600190613f4960ff613f3c8e8c61345e565b5160f81c8318168b612409565b519060081c189a0199613f21565b91959950939792965063ffffffff919550189460005b848110614061575050600b820180831161404d5783613f8b9161343f565b9360ff60f81b94613fa5868860f81b1660001a918961345e565b53600a83018084116140395784613fbb9161343f565b613fce868860f01b1660001a918961345e565b53600983018084116140395784613fe49161343f565b613ff7868860e81b1660001a918961345e565b536008830180931161402657505061402292916140139161343f565b9260e01b1660001a918361345e565b5390565b601190634e487b7160e01b600052526000fd5b50601190634e487b7160e01b600052526000fd5b50634e487b7160e01b600090815260118552fd5b6001600160f81b0319614074828461345e565b5116600885018086116140a3579061333c6140938461409e959461343f565b9160001a918b61345e565b613f6d565b84601189634e487b7160e01b600052526000fd5b80825b600881106140d75750906140d291611beb828d612409565b613f0d565b906140ef90600180808316146140f4575b1c916123a7565b6140ba565b906401db71064118906140e8565b634e487b7160e01b8252604184528982fd5b60118a634e487b7160e01b6000525260246000fd5b601189634e487b7160e01b6000525260246000fd5b601188634e487b7160e01b6000525260246000fd5b601187634e487b7160e01b6000525260246000fd5b613e33565b506001613cb6565b600580546040805163390a270d60e01b815290926104e0926004926001600160a01b039291859082908690829087165afa908115614980576000916148ea575b508551919061050083016001600160401b038111848210176148d55787989394959852602791828552602096368887013760005b8381106148af57505050506000956060876000985b61489c575061420b612255565b509060018092015460ff8a1610156142a657908594939291878a9760009b8c94614233612255565b50019061423f91612490565b90549060031b1c166142509061575c565b918a51928184925190818580860192019161426a92611fbf565b8201815191828580840192019161428092611fbf565b010380835201614290908261209e565b9561429a906126f4565b989591929394956141fe565b90506106f99297506142bb9391969450613ca4565b6143046036835180937519185d184e9a5b5859d94bdc1b99ced8985cd94d8d0b60521b878301526142f481518092898686019101611fbf565b810103601681018452018261209e565b61430c612948565b90614316826123cc565b52614320816123cc565b5080511561486c57614330615343565b92614339615343565b6143f26101ca614347615343565b96614350615343565b9787519485927101e39bb33903b34b2bba137bc1e91181018160751b88850152614383815180928a603288019101611fbf565b8301600160fd1b60328201526143a2825180938a603385019101611fbf565b016811103bb4b23a341e9160b91b60338201526143c88251809389603c85019101611fbf565b01976911103432b4b3b43a1e9160b11b9889603c8201526108bc8251809389604685019101611fbf565b906000915b83518310156145015761440a8385612409565b5151156144f7576144f190611a036051614422615401565b9261442b615343565b614433615343565b878c61443f8b8d612409565b51938d5198866144588b9851809287808c019101611fbf565b8701691e34b6b0b3b2903c1e9160b11b8582015281519061448182602a94888685019101611fbf565b01907011103c9e9118383c11103bb4b23a341e9160791b908201526144b082518093603b968785019101611fbf565b01918201528151906144ca826045948c8685019101611fbf565b0190671110343932b31e9160c11b90820152815190610bc482604d948b8685019101611fbf565b916143f7565b916144f1906123a7565b91509491929350614510615343565b90614519615343565b614521615343565b9161080087519561453187612083565b86528886019089368337602487015b6000190190600a906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a835304908161454057505061464693608d938951968461458a8d8a9751928184928a019101611fbf565b85016000805160206159e183398151915260511b8d8201526145b68d8351938491603685019101611fbf565b016b383c11103432b4b3b43a1e9160a11b60368201526145e08c8351938491604285019101611fbf565b0160008051602061590183398151915260428201526000805160206159a183398151915260291b606282015261461f825180938d607d85019101611fbf565b01610d456a383c1d903432b4b3b43a1d60a91b9788607d8401525180936088840190611fbf565b6000905b83518210156148165761465d8285612409565b51511561480c576146da6139a561018b614806938989896000805160206158c1833981519152898b61468d615401565b69383c1d903bb4b23a341d60b11b6146af6146a6615343565b94613021615343565b51966f03a37b81d1018383c1d903632b33a1d160851b8982519e8f8d83829f51948593019101611fbf565b8b01916000805160206157e18339815191528b840152820152825190614708826050958c8785019101611fbf565b019182015282519061472282605a958a8785019101611fbf565b019182015282519061473c82606595888785019101611fbf565b019182015260008051602061598183398151915260858201526000805160206158e183398151915260a58201526000805160206157c183398151915260c58201526000805160206159c183398151915260e5820152600080516020615821833981519152610105820152600080516020615a218339815191526101258201526000805160206157a1833981519152610145820152600080516020615a01833981519152610165820152611e9160f11b610185820152610f4a82518093610187958685019101611fbf565b9061464a565b90614806906123a7565b603a935061322095925061212e949150614845906106f9603c845183610fd682955180928a8086019101611fbf565b90519482600080516020615861833981519152879485015282519283918686019101611fbf565b505162461bcd60e51b815291820152601f6024820152600080516020615881833981519152604482015260649150fd5b634e487b7160e01b815260218352602490fd5b8060ff6148cb92849c9998979c1b85015116611beb8288612409565b98939495986141e9565b604186634e487b7160e01b6000525260246000fd5b853d8711614979575b6148fd818361209e565b810186828203126101af5780601f830112156101af578751928784016001600160401b03811185821017614966578952839288810192831161033457925b82841061494c5750505050386141b5565b835160ff811681036101af5781526020938401930161493b565b634e487b7160e01b825260418852602482fd5b503d6148f3565b86513d6000823e3d90fd5b6001600160f81b031991821681529181166001830152909116600282015260030190565b906020825192015162ffffff60e81b9081811693600381106149d057505050565b6003908103901b82901b16169150565b90600681101561228b5760051b0190565b90600381101561228b5760051b0190565b90610400600083820393128184128116918413901516176123b657565b90610100600083820393128184128116918413901516176123b657565b818103929160001380158285131691841216176123b657565b919091600083820193841291129080158216911516176123b657565b6060906001614a7e612371565b5001546000905b8082106151a6575050600554604051631c58f5d960e01b815260c0918290829060049082906001600160a01b03165afa918215613c2b5760009261512a575b50506040519061602082016001600160401b0381118382101761206d5760405261030082526160003660208401376000925b60038410156151015760005b600a808210156150ef5785600019048111861515166123b657614b29614b389187026127ee565b614b32836127ee565b9061343f565b90602982018083116123b6576001600160f81b0319614b57828a61345e565b511690602a84018082116123b6576001600160f81b031990614b79908b61345e565b511690602b8501106123b657614bca91614bc590614bb76001600160f81b0319614ba6602b89018e61345e565b51166040519485936020850161498b565b03601f19810183528261209e565b6149af565b6060604051614bd881612052565b369037604051614be781612052565b8160001a81528160011a60208201528160021a6040820152600090815b600381106150b7575050614c43614c3d604051614c2081612052565b8460001a81528460011a60208201528460021a604082015261561d565b82614a3c565b809260008215600014615002575050915b60405192614c6184612052565b600081128015614ff95761060090818084011280158216911516176123b657600691015b058352818015614ff257614c9b614ca09261522b565b6155ec565b60208301526040820152614cbc614cb688612804565b866149e0565b51614cc688612804565b600181018091116123b657614cdb90876149e0565b518860001904607811891515166123b65760788902600019046101001160788a021515166123b657614d3d9161016860788b0260081b0490845182811380614fe0575b15614f9b5750614d3091508451614a3c565b83525b6020830151614a55565b80602083015260808112600014614f825750600060208201525b60ff80602083015113614f77575b5080516020820151614d7b604084015192615264565b91828061050001126001166123b657614de3610100614ddd614de994614dcc61060084986105000107614dbc60405191614db483612052565b808352614a02565b602082015284604082015261561d565b600080821315614f6f5750906152c9565b05614a1f565b906152c9565b0560405190602082015260208152614e0081612083565b8051601f101561228b57603f60ff60f81b910151169080516020820151614e2b604084015192615264565b91828061030001126001166123b657614de3610100614ddd614e6494614dcc61060084986103000107614dbc60405191614db483612052565b0560405190602082015260208152614e7b81612083565b8051601f101561228b57603f60ff60f81b9101511690805190614ea76040602083015192015192615264565b91828061010001126001166123b657614de3610100614ddd614ede94614dcc6106008498850107614dbc60405191614db483612052565b0560405190602082015260208152614ef581612083565b8051601f101561228b57614f2492614bb7614bc592603f60ff60f81b910151166040519485936020850161498b565b918260001a614f338288612409565b52600181018082116123b657614f4d8460011a9188612409565b52600281018091116123b657611beb614f6a9360021a9187612409565b614b02565b9050906152c9565b602082015238614d65565b607f1981019081136001166123b6576020820152614d57565b82828183129283614fcc575b505050600014614fc457614fbd91508451614a55565b8352614d33565b508352614d33565b614fd7929350614a55565b12828238614fa7565b5082614fec8383614a3c565b13614d1e565b9050614ca0565b50600690614c85565b8160001a8414600014615033575090614c9b6150288361502d9460021a9060011a614a3c565b61522b565b91614c54565b8160011a8414600014615071575090614c9b615028836150599460001a9060021a614a3c565b808061020001126001166123b6576102000191614c54565b91614c9b615028836150899460011a9060001a614a3c565b90818061040001126001166150a357506104000191614c54565b634e487b7160e01b81526011600452602490fd5b826150c282846149f1565b51136150d7575b6150d2906123a7565b614c04565b91506150d26150e683836149f1565b519290506150c9565b5050926150fb906123a7565b92614af6565b93612c8293506008915061212e9261511891613ca4565b613568615123612371565b509161566e565b803d821161519f575b61513d818461209e565b82019181818403126103385782601f8201121561033857604051938285016001600160401b0381118682101761250e576040528492820193841161075e5750905b82821061518f575050503880614ac4565b815181526020918201910161517e565b503d615133565b90926151c09061172961287861286187600161285a612371565b90614a85565b600181036151d7575061212e61297d565b600281036151e8575061212e61346f565b600381036151f9575061212e614175565b60041461522357604051602081016001600160401b0381118282101761206d576040526000815290565b61212e614a71565b60008082136001600160ff1b0383900461010011166001166150a3578082126001600160f71b03198312166001166150a3575060081b90565b600060017f1555555555555555555555555555555555555555555555555555555555555555831182841316166150a35760017feaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab831282841216166150a3575060060290565b60008082138184136001600160ff1b0382821686820486111661531e57600160ff1b928487129290831686850588121661260b5786858712940586129084161661531e5785900584129116166150a357500290565b634e487b7160e01b84526011600452602484fd5b600160ff1b81146123b65760000390565b60405161080061535282612083565b6004825260203681840137602482015b6000190190600a906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a835304908161536257505090565b60405161055461535282612083565b60405160006153ad82612083565b6001908183526020368185013760218301825b6153ca5750505090565b6000190190600a906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a8353049182156153fc579190826153c0565b612977565b604051600061540f82612083565b6001908183526020368185013760218301825b61542c5750505090565b6000190190600a906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a8353049182156153fc57919082615422565b6000908072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b808210156155b2575b506904ee2d6d415b85acef8160201b808310156155a3575b50662386f26fc1000080831015615594575b506305f5e10080831015615585575b5061271080831015615576575b506064821015615566575b600a8092101561555c575b600190816021818601956154f1876120c1565b966154ff604051988961209e565b80885261550e601f19916120c1565b01366020890137860101905b615526575b5050505090565b600019019083906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a8353049182156155575791908261551a565b61551f565b91600101916154de565b91906064600291049101916154d3565b600491939204910191386154c8565b600891939204910191386154bb565b601091939204910191386154ac565b6020919392049101913861549a565b604093508104915038615482565b63ffffffff60e01b16632a9f3abf60e11b81149081156155de575090565b6301ffc9a760e01b14919050565b811561560757600160ff1b81146000198314166123b6570590565b634e487b7160e01b600052601260045260246000fd5b6001600160401b039060005b6003811061563657505090565b8261564182846149f1565b5112615656575b615651906123a7565b615629565b915061565161566583836149f1565b51929050615648565b9060609180518061567d575050565b9092506003926002938085840104851b92604051957f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f52603f926106707f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f1884526020880186890160208101956020868901019283519160048660009b8c88525b01928284518d828260121c165190538181600c1c1651600153818160061c16518b53165188538b51815201918983101561573e576004908790615700565b505096506040925201604052613d3d60f01b92069004820352528252565b90813b9182156157925760016000198401916000601f6040519661ffe0603e82011688016040528588528701015260208501903c565b6311052bb46000526004601cfdfe6572696e673a20706978656c617465643b202d6d732d696e746572706f6c61742d65646765733b20696d6167652d72656e646572696e673a202d7765626b69743c696d67207374796c653d22706f736974696f6e3a206162736f6c7574653b20c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b696e673a206f7074696d697a652d636f6e74726173743b20696d6167652d7265c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d646174613a696d6167652f7376672b786d6c3b6261736536342c0000000000004d7573742070726f76696465206174206c65617374206f6e6520696d61676500c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85f70783b20696d6167652d72656e646572696e673a206f7074696d697a6553706565646765733b20696d6167652d72656e646572696e673a202d6f2d63726973707078223e3c64697620786d6c6e733d22687474703a2f2f7777772e77332e6f72c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8638be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f86165643b20696d6167652d72656e646572696e673a202d6d6f7a2d63726973702d00000000003397989c9c9c97bc343a36b6111039ba3cb6329e913bb4b23a341d2d6f7074696d697a652d636f6e74726173743b20696d6167652d72656e646572000000000000000000001e3337b932b4b3b727b13532b1ba103bb4b23a341e91696f6e2d6d6f64653a206e6561726573742d6e65696768626f723b22207372636e646572696e673a2063726973702d65646765733b20696d6167652d72656e64a264697066735822122068c33fec04c0982ac4b96d9687db93a3d4b10bed95d7a6845083e1b3e28ab4e264736f6c63430008100033000000000000000000000000838aada0909e0f5d9260fb59faba2c76afb089a8
Deployed Bytecode
0x6080604081815260048036101561001557600080fd5b600092833560e01c90816301ffc9a714611f5457508063177a8abb14611f365780631def138f14611f0c57806324d7806c14611eb957806325b3c67814611c8b5780632ba80eba14611c6a5780632d34567014611bfd57806331ae450b14611b355780633ccfd60b14611a9c5780633db9e12514611a7357806348fbc89b146114f55780635038cbd2146114d75780635aae942f14611420578063663e4463146112695780636a627842146111a85780636d73e66914611136578063715018a6146110eb5780638da5cb5b146110c357806397c04ee5146110a5578063b4a2f00214610761578063c2dc161c146106b7578063d068abc71461047a578063d74b81df1461045c578063e3684e3914610433578063e9dc63751461033c578063f1bcb3f714610263578063f2fde38b146101b35763f4c714b41461015757600080fd5b346101af5760203660031901126101af57356003548110156101af5760039092526101ab916101989060011b600080516020615801833981519152016121af565b9051918291602083526020830190611fe2565b0390f35b8280fd5b50346101af5760203660031901126101af576101cd612007565b6101d561241d565b6001600160a01b03908116918215610211575083546001600160a01b0319811683178555925192166000805160206159418339815191528484a3f35b608490602085519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b508290346103345782600319360112610334576001600160401b039080358281116103385736602382011215610338576102a690369060248185013591016120dc565b90602435928311610338573660238401121561033857820135916102c98361215e565b926102d68651948561209e565b80845260209460248686019260051b8401019236841161033457602401915b83831061031b5787876101ab61030b8989613ca4565b9251928284938452830190611fe2565b823560ff811681036101af5781529186019186016102f5565b5080fd5b8380fd5b505034610334578060031936011261033457906101ab61040b9261035e612007565b50610424602160243580865261037c846020976006895220916151c6565b906103fa600d865180946103b98b8301957b646174613a6170706c69636174696f6e2f6a736f6e3b757466382c7b60201b8752603c8401906128c5565b6b16101134b6b0b3b2911d101160a11b81528151916103e0908390600c8401908f01611fbf565b01601160f91b600c8201520360121981018552018361209e565b845197889251809289850190611fbf565b8101607d60f81b8782015203600181018752018561209e565b51928284938452830190611fe2565b50346101af5760203660031901126101af57816101ab93610198923581526006602052206121af565b5050346103345781600319360112610334576101ab9061019861297d565b5091903461033457608036600319011261033457610496612007565b602435936007851015610338576001600160401b03946044358681116106b3576104c39036908401612131565b9390966064358181116106af576104dd9036908601612022565b95909487518094630935e01b60e21b82523383830152816024602097889360018060a01b03165afa9081156106a5579061051e918b91610678575b5061263c565b61052661241d565b61052f85612352565b5092821161066557506105428254612175565b601f811161062c575b5087601f82116001146105c5578190899a61059e999a926105ba575b50508160011b916000199060031b1c19161790555b600161058783612352565b500190815490888355816105a1575b505050612705565b51f35b6105b292895288209081019061269c565b388080610596565b013590503880610567565b82895283892090601f1983168a5b81811061061557509a83929160019461059e9b9c9d106105fb575b505050811b01905561057c565b0135600019600384901b60f8161c191690553880806105ee565b919286600181928f870135815501940192016105d3565b61065590838a52848a20601f840160051c81019186851061065b575b601f0160051c019061269c565b3861054b565b9091508190610648565b634e487b7160e01b895260419052602488fd5b6106989150863d881161069e575b610690818361209e565b810190612624565b38610518565b503d610686565b89513d8c823e3d90fd5b8780fd5b8580fd5b50829034610334576020366003190112610334573590600782101561075e576101ab61071b8461074c6008866106fe6106f96106f283612352565b509261281a565b61566e565b8451958692643230ba309d60d91b602085015260258401906128c5565b670ed8985cd94d8d0b60c21b815261073c8251809360208785019101611fbf565b010360171981018552018361209e565b51918291602083526020830190611fe2565b80fd5b50919034610334576080366003190112610334578235916001600160401b0380841161033457366023850112156103345783850135936107a08561215e565b916107ad8551938461209e565b858352602091828401906024809860051b820101923684116110a157888201925b84841061107757505050505084359360443596606435968451156110495750506107f78561545e565b926108018861545e565b610aaa6101ca6108108961545e565b9661081a8c61545e565b9786519485927101e39bb33903b34b2bba137bc1e91181018160751b8a85015261084d815180928c603288019101611fbf565b8301600160fd1b603282015261086c825180938c603385019101611fbf565b016811103bb4b23a341e9160b91b6033820152610892825180938b603c85019101611fbf565b01976911103432b4b3b43a1e9160b11b9889603c8201526108bc825180938b604685019101611fbf565b017f2220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f60468201527f7376672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e60668201526f37b93397989c9c9c97bc3634b735911f60811b60868201527f3c646566733e3c7374796c653e696d616765207b696d6167652d72656e64657260968201527f696e673a206f7074696d697a6553706565643b696d6167652d72656e6465726960b68201527f6e673a202d6d6f7a2d63726973702d65646765733b696d6167652d72656e646560d68201527f72696e673a202d6f2d63726973702d65646765733b696d6167652d72656e646560f68201527f72696e673a202d7765626b69742d6f7074696d697a652d636f6e74726173743b6101168201527f696d6167652d72656e646572696e673a206f7074696d697a652d636f6e7472616101368201527f73743b696d6167652d72656e646572696e673a2063726973702d65646765733b6101568201527f696d6167652d72656e646572696e673a20706978656c617465643b2d6d732d696101768201527f6e746572706f6c6174696f6e2d6d6f64653a206e6561726573742d6e65696768610196820152733137b91dbe9e17b9ba3cb6329f1e17b232b3399f60611b6101b6820152036101aa81018452018261209e565b9385945b8251861015610c3f5787908a888b610ac68a88612409565b515115610c31579288610be093610b07610b01605195610aeb8f99610be69b9a6152c9565b908112610bec57610afb9061545e565b9761545e565b9161545e565b610b118d8b612409565b5191898c519886610b2b8b9851809289808c019101611fbf565b8701691e34b6b0b3b2903c1e9160b11b87820152815190610b5482602a948a8685019101611fbf565b01907011103c9e9118383c11103bb4b23a341e9160791b90820152825190610b8482603b95898785019101611fbf565b0191820152815190610b9e82604594878685019101611fbf565b0190671110343932b31e9160c11b90820152610bc482518093604d958685019101611fbf565b0190631110179f60e11b9082015203603181018452018261209e565b956123a7565b94610aae565b610bf8610bfd91615332565b61545e565b610afb8d5191602d60f81b87840152828151610c21816021948b8686019101611fbf565b810103600181018452018261209e565b50505095610be691506123a7565b979450509190610c4e8661545e565b610d62608d610c5c8b61545e565b99610c668a61545e565b610c6f8d61545e565b9b86519583610c8788955180928c8089019101611fbf565b84016000805160206159e183398151915260511b8a820152610cb2825180938c603685019101611fbf565b016b383c11103432b4b3b43a1e9160a11b6036820152610cdb825180938b604285019101611fbf565b0160008051602061590183398151915260428201526000805160206159a183398151915260291b6062820152610d1a825180938a607d85019101611fbf565b019a6a383c1d903432b4b3b43a1d60a91b9b8c607d820152610d45825180938a608885019101611fbf565b0164383c1d911f60d91b608882015203606d81018452018261209e565b9285935b8151851015610fb2578989898989610d7e8a88612409565b515115610fa357886000805160206158c183398151915288610e1e97610f679761018b978f610df38f9891610ded610f6d9f9b8b610de7918c610dcf69383c1d903bb4b23a341d60b11b98876152c9565b918212610f735750610de1915061545e565b9561545e565b9661545e565b96612409565b51976f03a37b81d1018383c1d903632b33a1d160851b8882519e8f8d83829f51948593019101611fbf565b8b01916000805160206157e18339815191528a840152820152825190610e4c826050958b8785019101611fbf565b0191820152825190610e6682605a95898785019101611fbf565b0191820152610e7f825180936065968785019101611fbf565b019182015260008051602061598183398151915260858201526000805160206158e183398151915260a58201526000805160206157c183398151915260c58201526000805160206159c183398151915260e5820152600080516020615821833981519152610105820152600080516020615a218339815191526101258201526000805160206157a1833981519152610145820152600080516020615a01833981519152610165820152611e9160f11b610185820152815190610f4a82610187948d8685019101611fbf565b0190631110179f60e11b908201520361016b81018452018261209e565b946123a7565b93610d66565b610f82610bf8610de193615332565b92518093602d60f81b83830152610c21815180926021958686019101611fbf565b505050505093610f6d906123a7565b836101ab61100a85936106f9603c865183610fd682955180928a8086019101611fbf565b81017b1e17b234bb1f1e17b337b932b4b3b727b13532b1ba1f1e17b9bb339f60211b8882015203601c81018452018261209e565b92610424603a825180966000805160206158618339815191528783015261103981518092898686019101611fbf565b810103601a81018752018561209e565b606493601f9293519362461bcd60e51b85528401528201526000805160206158818339815191526044820152fd5b833582811161109d57869161109283928d3691880101612113565b8152019301926107ce565b8880fd5b8680fd5b5050346103345781600319360112610334576101ab9061019861346f565b505034610334578160031936011261033457905490516001600160a01b039091168152602090f35b50503461033457816003193601126103345761110561241d565b81546001600160a01b03198116835590519082906001600160a01b03166000805160206159418339815191528284a3f35b50503461033457602036600319011261033457611151612007565b61115961241d565b6001600160a01b031661116b81612527565b15611174575051f35b6111a49033817f7e1a1a08d52e4ba0e21554733d66165fd5151f99460116223d9e3a608eec5cb1868651a36124a8565b5051f35b508260209182600319360112610334576001600160a01b036111c8612007565b16845191630935e01b60e21b835233818401528483602481855afa90811561125f576111fe60249287958791610678575061263c565b61120661241d565b86519485938492630525194b60e31b845233908401525af180156112525761122d57505051f35b813d831161124b575b611240818361209e565b810103126103345751f35b503d611236565b50505051903d90823e3d90fd5b86513d86823e3d90fd5b5091903461033457606036600319011261033457611285612007565b926001600160401b039060443582811161141c576112a69036908301612131565b8451630935e01b60e21b815233818501526020979193918890829060249082906001600160a01b03165afa90811561141257906112e99188916113fb575061263c565b6112f161241d565b6024358652600687528486209383116113e8575061130f8354612175565b601f81116113ba575b508495601f83116001146113565750948495829394959261134b575b50508160011b916000199060031b1c191617905551f35b013590503880611334565b90601f198316968487528287209287905b8982106113a25750508360019596979810611388575b505050811b01905551f35b0135600019600384901b60f8161c1916905538808061137d565b80600184968294958701358155019501920190611367565b6113e290848752878720601f850160051c81019189861061065b57601f0160051c019061269c565b38611318565b634e487b7160e01b865260419052602485fd5b6106989150893d8b1161069e57610690818361209e565b86513d89823e3d90fd5b8480fd5b50346101af5760603660031901126101af5761143a612007565b9060243590600782101561141c57604435916001600160401b0383116106b35761146960209336908401612022565b9390926024875180978193630935e01b60e21b8352339083015260018060a01b03165afa9384156114cd5761059e946114a89188916114b5575061263c565b6114b061241d565b612705565b610698915060203d811161069e57610690818361209e565b85513d88823e3d90fd5b5050346103345781600319360112610334576101ab90610198614175565b508290346103345760603660031901126103345780356001600160401b0381116101af576115269036908301612113565b906024359160443591611537612948565b91611541836123cc565b5261154b826123cc565b50815115611a42575061155d8361545e565b906115678361545e565b916115718561545e565b6116256101ca6115808761545e565b958a519384916020967101e39bb33903b34b2bba137bc1e91181018160751b888501526115b6815180928a603288019101611fbf565b8301600160fd1b60328201526115d5825180938a603385019101611fbf565b016811103bb4b23a341e9160b91b60338201526115fb8251809389603c85019101611fbf565b01966911103432b4b3b43a1e9160b11b9788603c8201526108bc8251809389604685019101611fbf565b9186925b815184101561174057869061163e8584612409565b5151156117355790611729605161172f938c8a888b61166d61166761166161539f565b9961545e565b9361545e565b926116788d8c612409565b51945198866116908b9851809287808c019101611fbf565b8701691e34b6b0b3b2903c1e9160b11b858201528151906116b982602a94888685019101611fbf565b01907011103c9e9118383c11103bb4b23a341e9160791b908201526116e882518093603b968785019101611fbf565b0191820152815190611702826045948d8685019101611fbf565b0190671110343932b31e9160c11b90820152815190610bc482604d948c8685019101611fbf565b936123a7565b92611629565b9361172f91506123a7565b935095915061174e8561545e565b611845608d61175c8761545e565b956117668961545e565b61176f8961545e565b978c51958361178788955180928b8089019101611fbf565b84016000805160206159e183398151915260511b898201526117b2825180938b603685019101611fbf565b016b383c11103432b4b3b43a1e9160a11b60368201526117db825180938a604285019101611fbf565b0160008051602061590183398151915260428201526000805160206159a183398151915260291b606282015261181a8251809389607d85019101611fbf565b01966a383c1d903432b4b3b43a1d60a91b9788607d820152610d458251809389608885019101611fbf565b8651831015611a1e57878785878961185d8885612409565b515115611a0f5793611a03936000805160206158c18339815191528861018b95611a0999956118d79969383c1d903bb4b23a341d60b11b6118ac8f6118a6610de1610de161539f565b98612409565b51976f03a37b81d1018383c1d903632b33a1d160851b8682519e8f8d83829f51948593019101611fbf565b8b01916000805160206157e18339815191528884015282015282519061190582605095898785019101611fbf565b019182015261191e82518093605a968785019101611fbf565b0191820152825190611938826065958d8785019101611fbf565b019182015260008051602061598183398151915260858201526000805160206158e183398151915260a58201526000805160206157c183398151915260c58201526000805160206159c183398151915260e5820152600080516020615821833981519152610105820152600080516020615a218339815191526101258201526000805160206157a1833981519152610145820152600080516020615a01833981519152610165820152611e9160f11b610185820152815190610f4a82610187948b8685019101611fbf565b926123a7565b91611845565b505050505091611a09906123a7565b906101ab61100a89936106f9603c865183610fd682955180928a8086019101611fbf565b606490602087519162461bcd60e51b8352820152601f60248201526000805160206158818339815191526044820152fd5b50503461033457816003193601126103345760055490516001600160a01b039091168152602090f35b50346101af57826003193601126101af57611ab561241d565b8054825184918291829147906001600160a01b03165af13d15611b30573d611adc816120c1565b90611ae98551928361209e565b81528460203d92013e5b15611afc575051f35b6020606492519162461bcd60e51b8352820152600f60248201526e1dda5d1a191c985dc819985a5b1959608a1b6044820152fd5b611af3565b5050346103345781600319360112610334576001805492611b558461215e565b611b618451918261209e565b848152611b6d8561215e565b6020828101969091601f1901368837835b818110611bc35750508451948186019282875251809352850195925b828110611ba75785870386f35b83516001600160a01b0316875295810195928101928401611b9a565b85855282852081015495979593949293611bf191906001600160a01b0316611beb8288612409565b526123a7565b96949693929193611b7e565b50503461033457602036600319011261033457611c18612007565b611c2061241d565b6001600160a01b0316611c3281612527565b611c3a575051f35b6111a49033817f7c0c3c84c67c85fcac635147348bfe374c24a1a93d0366d1cfe9d8853cbf89d5868651a361253a565b50913461075e57602036600319011261075e57506101986101ab92356151c6565b50346101af5760603660031901126101af57611ca5612007565b906001600160401b0390602480358381116110a157611cc79036908401612022565b94909160443585811161109d57611ce19036908601612022565b8851630935e01b60e21b8152338782015260209491929185908290869082906001600160a01b03165afa8015611eaf57611d21918c91610678575061263c565b611d2961241d565b818803611e745789805b898110611d3f57508951f35b611d4a8185856126b3565b8c60059484861b8b0135815260068a5220918b8211611e62578e611d6e8454612175565b958a601f97888111611e2c575b50505080958311600114611dc057611dae95909183611db5575b50508160011b916000199060031b1c19161790556123a7565b8a90611d33565b013590503880611d95565b91929394601f1984168584528a8420935b8b828210611e165750509084611dae97969594939210611dfc575b505050600190811b0190556123a7565b0135600019600384901b60f8161c19169055388080611dec565b6001849682939587013581550195019201611dd1565b611e51928785528983862092818901831c8401948910611e59575b01901c019061269c565b388a81611d7b565b93508293611e47565b634e487b7160e01b8f5260418b52878ffd5b885162461bcd60e51b815280870185905260168185015275082e4e4c2f2e640d8cadccee8d040dad2e6dac2e8c6d60531b6044820152606490fd5b8a513d8d823e3d90fd5b5050346103345760203660031901126103345790602091611ed8612007565b91546001600160a01b0392831692168214918215611efa575b50519015158152f35b611f05919250612527565b9038611ef1565b50346101af5760203660031901126101af573591600783101561075e57506101986101ab9261281a565b5050346103345781600319360112610334576101ab90610198614a71565b925050346101af5760203660031901126101af57356001600160e01b03198116808203610338576020935063e9dc637560e01b14908115611fae575b8115611f9e575b5015158152f35b611fa891506155c0565b38611f97565b9050611fb9816155c0565b90611f90565b60005b838110611fd25750506000910152565b8181015183820152602001611fc2565b90602091611ffb81518092818552858086019101611fbf565b601f01601f1916010190565b600435906001600160a01b038216820361201d57565b600080fd5b9181601f8401121561201d578235916001600160401b03831161201d576020808501948460051b01011161201d57565b606081019081106001600160401b0382111761206d57604052565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761206d57604052565b601f909101601f19168101906001600160401b0382119082101761206d57604052565b6001600160401b03811161206d57601f01601f191660200190565b9291926120e8826120c1565b916120f6604051938461209e565b82948184528183011161201d578281602093846000960137010152565b9080601f8301121561201d5781602061212e933591016120dc565b90565b9181601f8401121561201d578235916001600160401b03831161201d576020838186019501011161201d57565b6001600160401b03811161206d5760051b60200190565b90600182811c921680156121a5575b602083101461218f57565b634e487b7160e01b600052602260045260246000fd5b91607f1691612184565b90604051918260008254926121c384612175565b90818452600194858116908160001461223257506001146121ef575b50506121ed9250038361209e565b565b9093915060005260209081600020936000915b81831061221a5750506121ed935082010138806121df565b85548884018501529485019487945091830191612202565b9150506121ed94506020925060ff191682840152151560051b82010138806121df565b6003546005101561228b57600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f86591565b634e487b7160e01b600052603260045260246000fd5b6003541561228b576003600090815260008051602061580183398151915291565b6003546001101561228b576003600090815260008051602061584183398151915291565b6003546002101561228b57600360009081526000805160206158a183398151915291565b6003546003101561228b576003600090815260008051602061596183398151915291565b6003546004101561228b576003600090815260008051602061592183398151915291565b60035481101561228b57600360005260206000209060011b0190600090565b6003546006101561228b57600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f86791565b60001981146123b65760010190565b634e487b7160e01b600052601160045260246000fd5b80511561228b5760200190565b80516001101561228b5760400190565b80516002101561228b5760600190565b80516003101561228b5760800190565b805182101561228b5760209160051b010190565b6000546001600160a01b0316330361243157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60015481101561228b57600160005260206000200190600090565b805482101561228b5760005260206000200190600090565b60008181526002602052604081205461252257600154600160401b81101561250e5790826124fa6124e184600160409601600155612475565b819391549060031b600019811b9283911b169119161790565b905560015492815260026020522055600190565b634e487b7160e01b82526041600452602482fd5b905090565b6000526002602052604060002054151590565b600081815260026020526040812054909190801561261f576000199080820181811161260b57600154908382019182116125f7578082036125c3575b50505060015480156125af5781019061258e82612475565b909182549160031b1b19169055600155815260026020526040812055600190565b634e487b7160e01b84526031600452602484fd5b6125e16125d26124e193612475565b90549060031b1c928392612475565b9055845260026020526040842055388080612576565b634e487b7160e01b86526011600452602486fd5b634e487b7160e01b85526011600452602485fd5b505090565b9081602091031261201d5751801515810361201d5790565b1561264357565b60405162461bcd60e51b815260206004820152602b60248201527f57616c6c6574206973206e6f7420616e2061646d696e6973747261746f72206660448201526a1bdc8818dbdb9d1c9858dd60aa1b6064820152608490fd5b8181106126a7575050565b6000815560010161269c565b919081101561228b5760051b81013590601e198136030182121561201d5701803591906001600160401b03831161201d57602001823603811361201d579190565b60ff1660ff81146123b65760010190565b91909260005b60ff811690838210156127e65760078510156127d05761272a85612352565b5061274561273e600180930194878a6126b3565b36916120dc565b90815181810161ffff8160401b6bfd61000080600a3d393df300179111840152600b8101601584016000f09283156127c257528354600160401b81101561206d576127bd946127979282018155612490565b819291549060031b9160018060a01b039283811b93849216901b169119161790556126f4565b61270b565b63301164256000526004601cfd5b634e487b7160e01b600052602160045260246000fd5b505092505050565b8060001904600311811515166123b65760030290565b8060001904600211811515166123b65760011b90565b600060605b60078310156127d05761283183612352565b5060018091015460ff841610156128be57906128b2612878612861856128b89561285a89612352565b5001612490565b905460039190911b1c6001600160a01b031661575c565b916040518093825161289281602095868087019101611fbf565b82016128a682518093868085019101611fbf565b0103808452018261209e565b916126f4565b9061281f565b5091505090565b6000929181546128d481612175565b9260019180831690811561292d57506001146128f1575b50505050565b90919293945060005260209081600020906000915b85831061291c57505050500190388080806128eb565b805485840152918301918101612906565b60ff19168452505050811515909102019150388080806128eb565b60405161295481612083565b600181528060005b6020808210156129775790606060209282850101520161295c565b50505090565b60055460408051632495a06960e21b8152909161554091908290829060049082906001600160a01b03165afa918215613434576000926133ba575b5050815161424d60f01b6020820152617e5560f01b602282015260006026820152601f60f91b602a820152600e81529091906129f381612083565b815190600560fb1b6020830152602493600160f11b8584015261550160f01b6028840152600160f81b80602c850152602e8401526000603084015261405560f01b6034840152600060388401526000603c840152600160f91b848401526000604484015260288352612a6483612052565b8351607d60f91b6020820152608f60f81b6021820152603f60f91b6022820152600060238201819052602f60f81b878301819052602583018190526026830152602782015260088152612ab681612083565b8451916202aa2083016001600160401b038111848210176133a55786526202aa0080845236602085013760005b6101558110613286575050612b4b93926106f99260209287519583612b118895518092888089019101611fbf565b8401612b2582518093888085019101611fbf565b01612b3882518093878085019101611fbf565b016128a682518093868085019101611fbf565b92612b976036835180967519185d184e9a5b5859d94bd89b5c0ed8985cd94d8d0b60521b6020830152612b878151809260208686019101611fbf565b810103601681018752018561209e565b815193612ba385612052565b6002855260005b8381106132755750612bbb856123cc565b52612bc5846123cc565b5060039081541561326057816000526020600020906060956000965b612be96122a1565b5060018091015460ff8a161015612c4b5790612c3f6020612c27612c138c612c459661285a6122a1565b9054908a1b1c6001600160a01b031661575c565b92895193816128928693518092868087019101611fbf565b976126f4565b96612be1565b50612cb392975060089196945092612c65612c829461566e565b8651948592643230ba309d60d91b602085015260258401906128c5565b670ed8985cd94d8d0b60c21b8152612ca38251809360208785019101611fbf565b010360171981018452018261209e565b612cbc846123d9565b52612cc6836123d9565b508251156132305750612cd7615343565b90612ce0615390565b612d9e6101ca612cee615343565b94612cf7615390565b9585519485927101e39bb33903b34b2bba137bc1e91181018160751b6020850152612d2c815180926020603288019101611fbf565b8301600160fd1b6032820152612d4c825180936020603385019101611fbf565b016811103bb4b23a341e9160b91b6033820152612d73825180936020603c85019101611fbf565b01956911103432b4b3b43a1e9160b11b9687603c8201526108bc825180936020604685019101611fbf565b926000935b8151851015612eb157612db68583612409565b515115612ea757612ea190610f676051612dce61539f565b92612dd7615343565b612ddf615390565b612de98b89612409565b51918a8a519785612e048a975180926020808b019101611fbf565b8601691e34b6b0b3b2903c1e9160b11b6020820152612e2d825180936020602a85019101611fbf565b017011103c9e9118383c11103bb4b23a341e9160791b602a820152825190612e5e82603b9560208785019101611fbf565b0191820152815190612e798260459460208685019101611fbf565b0190671110343932b31e9160c11b90820152815190610bc482604d9460208685019101611fbf565b93612da3565b93612ea1906123a7565b9350909150612ebe615343565b612fb8608d612ecb615390565b95612ed4615343565b612edc615390565b9787519583612ef5889551809260208089019101611fbf565b84016000805160206159e183398151915260511b6020820152612f22825180936020603685019101611fbf565b016b383c11103432b4b3b43a1e9160a11b6036820152612f4c825180936020604285019101611fbf565b0160008051602061590183398151915260428201526000805160206159a183398151915260291b6062820152612f8c825180936020607d85019101611fbf565b01966a383c1d903432b4b3b43a1d60a91b9788607d820152610d45825180936020608885019101611fbf565b926000935b825185101561319557612fd08584612409565b51511561318b57613053610f6761018b6131859387876000805160206158c18339815191528b89612fff61539f565b69383c1d903bb4b23a341d60b11b613027613018615343565b94613021615390565b97612409565b51966f03a37b81d1018383c1d903632b33a1d160851b602082519d8e8c83829e51948593019101611fbf565b8a01916000805160206157e183398151915260208401528201528251906130838260509560208785019101611fbf565b019182015282519061309e82605a9560208785019101611fbf565b01918201528251906130b98260659560208785019101611fbf565b019182015260008051602061598183398151915260858201526000805160206158e183398151915260a58201526000805160206157c183398151915260c58201526000805160206159c183398151915260e5820152600080516020615821833981519152610105820152600080516020615a218339815191526101258201526000805160206157a1833981519152610145820152600080516020615a01833981519152610165820152611e9160f11b610185820152815190610f4a826101879460208685019101611fbf565b93612fbd565b93613185906123a7565b61212e939450603a92506131f591506106f9603c8651836131c0829551809260208086019101611fbf565b81017b1e17b234bb1f1e17b337b932b4b3b727b13532b1ba1f1e17b9bb339f60211b602082015203601c81018452018261209e565b9251809360008051602061586183398151915260208301526132208151809260208686019101611fbf565b810103601a81018452018261209e565b601f606492519162461bcd60e51b8352602060048401528201526000805160206158818339815191526044820152fd5b83634e487b7160e01b60005260326004526000fd5b806060602080938901015201612baa565b610154808281031161337b576000198183141583830382046102001116613390578290046002118215151661337b57600182811b6132c4818661344c565b51918101809111613347576132d9908561344c565b519183900360061b6040600160fd1b0316919060005b6020811061335c57505060005b6020811061331557505050613310906123a7565b612ae3565b602083018311613347578082613342921a61333c613336836020880161343f565b8a61345e565b536123a7565b6132fc565b8a634e487b7160e01b60005260116004526000fd5b8082613376921a61333c613370838861343f565b8b61345e565b6132ef565b88634e487b7160e01b60005260116004526000fd5b89634e487b7160e01b60005260116004526000fd5b87634e487b7160e01b60005260416004526000fd5b803d821161342d575b6133cd818461209e565b82019181818403126103385782601f82011215610338578451938285016001600160401b0381118682101761250e5786528492820193841161075e5750905b82821061341d5750505038806129b8565b815181526020918201910161340c565b503d6133c3565b83513d6000823e3d90fd5b919082018092116123b657565b906102aa81101561228b5760051b0190565b90815181101561228b570160200190565b6040519060a082016001600160401b0381118382101761206d576040526004825260005b60808110613c375750600554604051633a707e8b60e21b815290602090829060049082906001600160a01b03165afa908115613c2b57600091613bf9575b5060035491826001101561228b576003600090815260008051602061584183398151915293909260605b60016135056122c2565b50015460ff861610156135515761354b90613545602061352c61286189600161285a6122c2565b9260405193816128928693518092868087019101611fbf565b946126f4565b936134fb565b612c8292945061358691939561356860089261566e565b604051948592643230ba309d60d91b602085015260258401906128c5565b61358f856123cc565b52613599846123cc565b50604b6103e8820410613b6b575b60326103e8820410613ad6575b6103e86019910410613a48575b50815115613a15576135d1615390565b6135d9615343565b6136986101ca6135e7615390565b936135f0615343565b946040519485927101e39bb33903b34b2bba137bc1e91181018160751b6020850152613626815180926020603288019101611fbf565b8301600160fd1b6032820152613646825180936020603385019101611fbf565b016811103bb4b23a341e9160b91b603382015261366d825180936020603c85019101611fbf565b01946911103432b4b3b43a1e9160b11b9586603c8201526108bc825180936020604685019101611fbf565b906000915b845183101561376b576136b08386612409565b5151156137615761375b90611a0360516136c861539f565b926136d1615390565b6136d9615343565b6136e3898c612409565b51918860405197856136ff8a975180926020808b019101611fbf565b8601691e34b6b0b3b2903c1e9160b11b602082015281519061372a82602a9460208685019101611fbf565b01907011103c9e9118383c11103bb4b23a341e9160791b90820152825190612e5e82603b9560208785019101611fbf565b9161369d565b9161375b906123a7565b92915050613777615390565b613872608d613784615343565b9461378d615390565b613795615343565b9660405195836137af889551809260208089019101611fbf565b84016000805160206159e183398151915260511b60208201526137dc825180936020603685019101611fbf565b016b383c11103432b4b3b43a1e9160a11b6036820152613806825180936020604285019101611fbf565b0160008051602061590183398151915260428201526000805160206159a183398151915260291b6062820152613846825180936020607d85019101611fbf565b01956a383c1d903432b4b3b43a1d60a91b9687607d820152610d45825180936020608885019101611fbf565b906000925b84518410156139bf5761388a8486612409565b5151156139b35761389961539f565b9261055492604051906138ab82612083565b6004825260208201946020368737602483015b6000190190600a906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a835304908982156138ef57506138be565b6139499592506139a59491506000805160206158c183398151915261018b949a98886139ab999b6139228c610ded615343565b519569383c1d903bb4b23a341d60b11b60206040519c8d8b83829d51948593019101611fbf565b89016000805160206157e183398151915260208201526f03a37b81d1018383c1d903632b33a1d160851b604082015283519061398e8260509660208885019101611fbf565b0192830152519061309e82605a9586840190611fbf565b916123a7565b929091613877565b9190926139ab906123a7565b5092506139e491506106f9603c604051836131c0829551809260208086019101611fbf565b61212e603a604051809360008051602061586183398151915260208301526132208151809260208686019101611fbf565b60405162461bcd60e51b815260206004820152601f60248201526000805160206158818339815191526044820152606490fd5b6004101561228b57600360009081526000805160206159218339815191529160605b6001613a7461232e565b50015460ff84161015613aa757613aa190613a9b602061352c61286187600161285a61232e565b926126f4565b91613a6a565b612c829250613abc919361356860089261566e565b613ac5836123f9565b52613acf826123f9565b50386135c1565b9091826003101561228b576003600090815260008051602061596183398151915293909260605b6001613b0761230a565b50015460ff86161015613b3457613b2e90613545602061352c61286189600161285a61230a565b93613afd565b6103e8929450613b4f600860199597613568612c829461566e565b613b58876123e9565b52613b62866123e9565b509150506135b4565b9091826002101561228b57600360009081526000805160206158a183398151915293909260605b6001613b9c6122e6565b50015460ff86161015613bc957613bc390613545602061352c61286189600161285a6122e6565b93613b92565b612c82929450613be091939561356860089261566e565b613be9856123d9565b52613bf3846123d9565b506135a7565b906020823d602011613c23575b81613c136020938361209e565b8101031261075e575051386134d1565b3d9150613c06565b6040513d6000823e3d90fd5b806060602080938601015201613493565b6001600160f81b03199182168152918116600183015291821660028201529116600382015260040190565b906020825192015163ffffffff60e01b908181169360048110613c9557505050565b60040360031b82901b16169150565b919091600860005b825182108061416d575b1561416857506001600160f81b031980613cd0838561345e565b511691600181018082116123b657613ce983918661345e565b511691600282018083116123b657613d0282918761345e565b5116600383018084116123b65782613d1d613d4f928961345e565b511694613d36604096875194859360209a8b8601613c48565b0391613d4a601f199384810183528261209e565b613c73565b60e01c9460049485850180861161415357613d6b85918a61345e565b5116936005860180871161413e57613d8482918b61345e565b51166006870180881161412957613d9c83918c61345e565b511691600788018089116141145791613dce9391613dc0613dda989796948e61345e565b511692519788958601613c48565b0390810183528261209e565b63504c544560e01b906001600160e01b031990613df690613c73565b1614613e2f57600c91838301809311613e1a575090613e149161343f565b90613cac565b601190634e487b7160e01b6000525260246000fd5b9190505b60009260605b8651851015613e9657613e9090610f676021613e55888b612409565b51926040519381859251613e7181602093848088019101611fbf565b83019160ff60f81b9060f81b169082015203600181018452018261209e565b93613e39565b949193509194506040519163504c544560e01b602084015284519483602496613ec58189840160208601611fbf565b810103613edb876004928381018852018661209e565b60405195600061202088016001600160401b0381118982101761410257604052610100908189526120003660208b0137805b8281106140b75750505063ffffffff986000995b87518b1015613f5757600190613f4960ff613f3c8e8c61345e565b5160f81c8318168b612409565b519060081c189a0199613f21565b91959950939792965063ffffffff919550189460005b848110614061575050600b820180831161404d5783613f8b9161343f565b9360ff60f81b94613fa5868860f81b1660001a918961345e565b53600a83018084116140395784613fbb9161343f565b613fce868860f01b1660001a918961345e565b53600983018084116140395784613fe49161343f565b613ff7868860e81b1660001a918961345e565b536008830180931161402657505061402292916140139161343f565b9260e01b1660001a918361345e565b5390565b601190634e487b7160e01b600052526000fd5b50601190634e487b7160e01b600052526000fd5b50634e487b7160e01b600090815260118552fd5b6001600160f81b0319614074828461345e565b5116600885018086116140a3579061333c6140938461409e959461343f565b9160001a918b61345e565b613f6d565b84601189634e487b7160e01b600052526000fd5b80825b600881106140d75750906140d291611beb828d612409565b613f0d565b906140ef90600180808316146140f4575b1c916123a7565b6140ba565b906401db71064118906140e8565b634e487b7160e01b8252604184528982fd5b60118a634e487b7160e01b6000525260246000fd5b601189634e487b7160e01b6000525260246000fd5b601188634e487b7160e01b6000525260246000fd5b601187634e487b7160e01b6000525260246000fd5b613e33565b506001613cb6565b600580546040805163390a270d60e01b815290926104e0926004926001600160a01b039291859082908690829087165afa908115614980576000916148ea575b508551919061050083016001600160401b038111848210176148d55787989394959852602791828552602096368887013760005b8381106148af57505050506000956060876000985b61489c575061420b612255565b509060018092015460ff8a1610156142a657908594939291878a9760009b8c94614233612255565b50019061423f91612490565b90549060031b1c166142509061575c565b918a51928184925190818580860192019161426a92611fbf565b8201815191828580840192019161428092611fbf565b010380835201614290908261209e565b9561429a906126f4565b989591929394956141fe565b90506106f99297506142bb9391969450613ca4565b6143046036835180937519185d184e9a5b5859d94bdc1b99ced8985cd94d8d0b60521b878301526142f481518092898686019101611fbf565b810103601681018452018261209e565b61430c612948565b90614316826123cc565b52614320816123cc565b5080511561486c57614330615343565b92614339615343565b6143f26101ca614347615343565b96614350615343565b9787519485927101e39bb33903b34b2bba137bc1e91181018160751b88850152614383815180928a603288019101611fbf565b8301600160fd1b60328201526143a2825180938a603385019101611fbf565b016811103bb4b23a341e9160b91b60338201526143c88251809389603c85019101611fbf565b01976911103432b4b3b43a1e9160b11b9889603c8201526108bc8251809389604685019101611fbf565b906000915b83518310156145015761440a8385612409565b5151156144f7576144f190611a036051614422615401565b9261442b615343565b614433615343565b878c61443f8b8d612409565b51938d5198866144588b9851809287808c019101611fbf565b8701691e34b6b0b3b2903c1e9160b11b8582015281519061448182602a94888685019101611fbf565b01907011103c9e9118383c11103bb4b23a341e9160791b908201526144b082518093603b968785019101611fbf565b01918201528151906144ca826045948c8685019101611fbf565b0190671110343932b31e9160c11b90820152815190610bc482604d948b8685019101611fbf565b916143f7565b916144f1906123a7565b91509491929350614510615343565b90614519615343565b614521615343565b9161080087519561453187612083565b86528886019089368337602487015b6000190190600a906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a835304908161454057505061464693608d938951968461458a8d8a9751928184928a019101611fbf565b85016000805160206159e183398151915260511b8d8201526145b68d8351938491603685019101611fbf565b016b383c11103432b4b3b43a1e9160a11b60368201526145e08c8351938491604285019101611fbf565b0160008051602061590183398151915260428201526000805160206159a183398151915260291b606282015261461f825180938d607d85019101611fbf565b01610d456a383c1d903432b4b3b43a1d60a91b9788607d8401525180936088840190611fbf565b6000905b83518210156148165761465d8285612409565b51511561480c576146da6139a561018b614806938989896000805160206158c1833981519152898b61468d615401565b69383c1d903bb4b23a341d60b11b6146af6146a6615343565b94613021615343565b51966f03a37b81d1018383c1d903632b33a1d160851b8982519e8f8d83829f51948593019101611fbf565b8b01916000805160206157e18339815191528b840152820152825190614708826050958c8785019101611fbf565b019182015282519061472282605a958a8785019101611fbf565b019182015282519061473c82606595888785019101611fbf565b019182015260008051602061598183398151915260858201526000805160206158e183398151915260a58201526000805160206157c183398151915260c58201526000805160206159c183398151915260e5820152600080516020615821833981519152610105820152600080516020615a218339815191526101258201526000805160206157a1833981519152610145820152600080516020615a01833981519152610165820152611e9160f11b610185820152610f4a82518093610187958685019101611fbf565b9061464a565b90614806906123a7565b603a935061322095925061212e949150614845906106f9603c845183610fd682955180928a8086019101611fbf565b90519482600080516020615861833981519152879485015282519283918686019101611fbf565b505162461bcd60e51b815291820152601f6024820152600080516020615881833981519152604482015260649150fd5b634e487b7160e01b815260218352602490fd5b8060ff6148cb92849c9998979c1b85015116611beb8288612409565b98939495986141e9565b604186634e487b7160e01b6000525260246000fd5b853d8711614979575b6148fd818361209e565b810186828203126101af5780601f830112156101af578751928784016001600160401b03811185821017614966578952839288810192831161033457925b82841061494c5750505050386141b5565b835160ff811681036101af5781526020938401930161493b565b634e487b7160e01b825260418852602482fd5b503d6148f3565b86513d6000823e3d90fd5b6001600160f81b031991821681529181166001830152909116600282015260030190565b906020825192015162ffffff60e81b9081811693600381106149d057505050565b6003908103901b82901b16169150565b90600681101561228b5760051b0190565b90600381101561228b5760051b0190565b90610400600083820393128184128116918413901516176123b657565b90610100600083820393128184128116918413901516176123b657565b818103929160001380158285131691841216176123b657565b919091600083820193841291129080158216911516176123b657565b6060906001614a7e612371565b5001546000905b8082106151a6575050600554604051631c58f5d960e01b815260c0918290829060049082906001600160a01b03165afa918215613c2b5760009261512a575b50506040519061602082016001600160401b0381118382101761206d5760405261030082526160003660208401376000925b60038410156151015760005b600a808210156150ef5785600019048111861515166123b657614b29614b389187026127ee565b614b32836127ee565b9061343f565b90602982018083116123b6576001600160f81b0319614b57828a61345e565b511690602a84018082116123b6576001600160f81b031990614b79908b61345e565b511690602b8501106123b657614bca91614bc590614bb76001600160f81b0319614ba6602b89018e61345e565b51166040519485936020850161498b565b03601f19810183528261209e565b6149af565b6060604051614bd881612052565b369037604051614be781612052565b8160001a81528160011a60208201528160021a6040820152600090815b600381106150b7575050614c43614c3d604051614c2081612052565b8460001a81528460011a60208201528460021a604082015261561d565b82614a3c565b809260008215600014615002575050915b60405192614c6184612052565b600081128015614ff95761060090818084011280158216911516176123b657600691015b058352818015614ff257614c9b614ca09261522b565b6155ec565b60208301526040820152614cbc614cb688612804565b866149e0565b51614cc688612804565b600181018091116123b657614cdb90876149e0565b518860001904607811891515166123b65760788902600019046101001160788a021515166123b657614d3d9161016860788b0260081b0490845182811380614fe0575b15614f9b5750614d3091508451614a3c565b83525b6020830151614a55565b80602083015260808112600014614f825750600060208201525b60ff80602083015113614f77575b5080516020820151614d7b604084015192615264565b91828061050001126001166123b657614de3610100614ddd614de994614dcc61060084986105000107614dbc60405191614db483612052565b808352614a02565b602082015284604082015261561d565b600080821315614f6f5750906152c9565b05614a1f565b906152c9565b0560405190602082015260208152614e0081612083565b8051601f101561228b57603f60ff60f81b910151169080516020820151614e2b604084015192615264565b91828061030001126001166123b657614de3610100614ddd614e6494614dcc61060084986103000107614dbc60405191614db483612052565b0560405190602082015260208152614e7b81612083565b8051601f101561228b57603f60ff60f81b9101511690805190614ea76040602083015192015192615264565b91828061010001126001166123b657614de3610100614ddd614ede94614dcc6106008498850107614dbc60405191614db483612052565b0560405190602082015260208152614ef581612083565b8051601f101561228b57614f2492614bb7614bc592603f60ff60f81b910151166040519485936020850161498b565b918260001a614f338288612409565b52600181018082116123b657614f4d8460011a9188612409565b52600281018091116123b657611beb614f6a9360021a9187612409565b614b02565b9050906152c9565b602082015238614d65565b607f1981019081136001166123b6576020820152614d57565b82828183129283614fcc575b505050600014614fc457614fbd91508451614a55565b8352614d33565b508352614d33565b614fd7929350614a55565b12828238614fa7565b5082614fec8383614a3c565b13614d1e565b9050614ca0565b50600690614c85565b8160001a8414600014615033575090614c9b6150288361502d9460021a9060011a614a3c565b61522b565b91614c54565b8160011a8414600014615071575090614c9b615028836150599460001a9060021a614a3c565b808061020001126001166123b6576102000191614c54565b91614c9b615028836150899460011a9060001a614a3c565b90818061040001126001166150a357506104000191614c54565b634e487b7160e01b81526011600452602490fd5b826150c282846149f1565b51136150d7575b6150d2906123a7565b614c04565b91506150d26150e683836149f1565b519290506150c9565b5050926150fb906123a7565b92614af6565b93612c8293506008915061212e9261511891613ca4565b613568615123612371565b509161566e565b803d821161519f575b61513d818461209e565b82019181818403126103385782601f8201121561033857604051938285016001600160401b0381118682101761250e576040528492820193841161075e5750905b82821061518f575050503880614ac4565b815181526020918201910161517e565b503d615133565b90926151c09061172961287861286187600161285a612371565b90614a85565b600181036151d7575061212e61297d565b600281036151e8575061212e61346f565b600381036151f9575061212e614175565b60041461522357604051602081016001600160401b0381118282101761206d576040526000815290565b61212e614a71565b60008082136001600160ff1b0383900461010011166001166150a3578082126001600160f71b03198312166001166150a3575060081b90565b600060017f1555555555555555555555555555555555555555555555555555555555555555831182841316166150a35760017feaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab831282841216166150a3575060060290565b60008082138184136001600160ff1b0382821686820486111661531e57600160ff1b928487129290831686850588121661260b5786858712940586129084161661531e5785900584129116166150a357500290565b634e487b7160e01b84526011600452602484fd5b600160ff1b81146123b65760000390565b60405161080061535282612083565b6004825260203681840137602482015b6000190190600a906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a835304908161536257505090565b60405161055461535282612083565b60405160006153ad82612083565b6001908183526020368185013760218301825b6153ca5750505090565b6000190190600a906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a8353049182156153fc579190826153c0565b612977565b604051600061540f82612083565b6001908183526020368185013760218301825b61542c5750505090565b6000190190600a906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a8353049182156153fc57919082615422565b6000908072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b808210156155b2575b506904ee2d6d415b85acef8160201b808310156155a3575b50662386f26fc1000080831015615594575b506305f5e10080831015615585575b5061271080831015615576575b506064821015615566575b600a8092101561555c575b600190816021818601956154f1876120c1565b966154ff604051988961209e565b80885261550e601f19916120c1565b01366020890137860101905b615526575b5050505090565b600019019083906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a8353049182156155575791908261551a565b61551f565b91600101916154de565b91906064600291049101916154d3565b600491939204910191386154c8565b600891939204910191386154bb565b601091939204910191386154ac565b6020919392049101913861549a565b604093508104915038615482565b63ffffffff60e01b16632a9f3abf60e11b81149081156155de575090565b6301ffc9a760e01b14919050565b811561560757600160ff1b81146000198314166123b6570590565b634e487b7160e01b600052601260045260246000fd5b6001600160401b039060005b6003811061563657505090565b8261564182846149f1565b5112615656575b615651906123a7565b615629565b915061565161566583836149f1565b51929050615648565b9060609180518061567d575050565b9092506003926002938085840104851b92604051957f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f52603f926106707f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f1884526020880186890160208101956020868901019283519160048660009b8c88525b01928284518d828260121c165190538181600c1c1651600153818160061c16518b53165188538b51815201918983101561573e576004908790615700565b505096506040925201604052613d3d60f01b92069004820352528252565b90813b9182156157925760016000198401916000601f6040519661ffe0603e82011688016040528588528701015260208501903c565b6311052bb46000526004601cfdfe6572696e673a20706978656c617465643b202d6d732d696e746572706f6c61742d65646765733b20696d6167652d72656e646572696e673a202d7765626b69743c696d67207374796c653d22706f736974696f6e3a206162736f6c7574653b20c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b696e673a206f7074696d697a652d636f6e74726173743b20696d6167652d7265c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d646174613a696d6167652f7376672b786d6c3b6261736536342c0000000000004d7573742070726f76696465206174206c65617374206f6e6520696d61676500c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85f70783b20696d6167652d72656e646572696e673a206f7074696d697a6553706565646765733b20696d6167652d72656e646572696e673a202d6f2d63726973707078223e3c64697620786d6c6e733d22687474703a2f2f7777772e77332e6f72c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8638be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f86165643b20696d6167652d72656e646572696e673a202d6d6f7a2d63726973702d00000000003397989c9c9c97bc343a36b6111039ba3cb6329e913bb4b23a341d2d6f7074696d697a652d636f6e74726173743b20696d6167652d72656e646572000000000000000000001e3337b932b4b3b727b13532b1ba103bb4b23a341e91696f6e2d6d6f64653a206e6561726573742d6e65696768626f723b22207372636e646572696e673a2063726973702d65646765733b20696d6167652d72656e64a264697066735822122068c33fec04c0982ac4b96d9687db93a3d4b10bed95d7a6845083e1b3e28ab4e264736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000838aada0909e0f5d9260fb59faba2c76afb089a8
-----Decoded View---------------
Arg [0] : _interfectorem (address): 0x838AaDa0909E0f5d9260FB59faBA2C76aFB089A8
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000838aada0909e0f5d9260fb59faba2c76afb089a8
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.