Address Details
contract

0x5388be2a573Dd7501AF207A30177bEe40FfcF333

Contract Name
NounsDescriptorV2
Creator
0x8b2f36–66963a at 0x4081bd–501b50
Balance
0 CELO ( )
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
16193441
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
NounsDescriptorV2




Optimization enabled
false
Compiler version
v0.8.6+commit.11564f7e




EVM Version
berlin




Verified at
2022-11-16T06:19:53.659785Z

contracts/NounsDescriptorV2.sol

// SPDX-License-Identifier: GPL-3.0

/// @title The Nouns NFT descriptor

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.6;

import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
import { Strings } from '@openzeppelin/contracts/utils/Strings.sol';
import { INounsDescriptorV2 } from './interfaces/INounsDescriptorV2.sol';
import { INounsSeeder } from './interfaces/INounsSeeder.sol';
import { NFTDescriptorV2 } from './libs/NFTDescriptorV2.sol';
import { ISVGRenderer } from './interfaces/ISVGRenderer.sol';
import { INounsArt } from './interfaces/INounsArt.sol';
import { IInflator } from './interfaces/IInflator.sol';

contract NounsDescriptorV2 is INounsDescriptorV2, Ownable {
    using Strings for uint256;

    // prettier-ignore
    // https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt
    bytes32 constant COPYRIGHT_CC0_1_0_UNIVERSAL_LICENSE = 0xa2010f343487d3f7618affe54f789f5487602331c0a8d03f49e9a7c547cf0499;

    /// @notice The contract responsible for holding compressed Noun art
    INounsArt public art;

    /// @notice The contract responsible for constructing SVGs
    ISVGRenderer public renderer;

    /// @notice Whether or not new Noun parts can be added
    bool public override arePartsLocked;

    /// @notice Whether or not `tokenURI` should be returned as a data URI (Default: true)
    bool public override isDataURIEnabled = true;

    /// @notice Base URI, used when isDataURIEnabled is false
    string public override baseURI;

    /**
     * @notice Require that the parts have not been locked.
     */
    modifier whenPartsNotLocked() {
        require(!arePartsLocked, 'Parts are locked');
        _;
    }

    constructor(INounsArt _art, ISVGRenderer _renderer) {
        art = _art;
        renderer = _renderer;
    }

    /**
     * @notice Set the Noun's art contract.
     * @dev Only callable by the owner when not locked.
     */
    function setArt(INounsArt _art) external onlyOwner whenPartsNotLocked {
        art = _art;

        emit ArtUpdated(_art);
    }

    /**
     * @notice Set the SVG renderer.
     * @dev Only callable by the owner.
     */
    function setRenderer(ISVGRenderer _renderer) external onlyOwner {
        renderer = _renderer;

        emit RendererUpdated(_renderer);
    }

    /**
     * @notice Set the art contract's `descriptor`.
     * @param descriptor the address to set.
     * @dev Only callable by the owner.
     */
    function setArtDescriptor(address descriptor) external onlyOwner {
        art.setDescriptor(descriptor);
    }

    /**
     * @notice Set the art contract's `inflator`.
     * @param inflator the address to set.
     * @dev Only callable by the owner.
     */
    function setArtInflator(IInflator inflator) external onlyOwner {
        art.setInflator(inflator);
    }

    /**
     * @notice Get the number of available Noun `backgrounds`.
     */
    function backgroundCount() external view override returns (uint256) {
        return art.backgroundsCount();
    }

    /**
     * @notice Get the number of available Noun `bodies`.
     */
    function bodyCount() external view override returns (uint256) {
        return art.getBodiesTrait().storedImagesCount;
    }

    /**
     * @notice Get the number of available Noun `accessories`.
     */
    function accessoryCount() external view override returns (uint256) {
        return art.getAccessoriesTrait().storedImagesCount;
    }

    /**
     * @notice Get the number of available Noun `heads`.
     */
    function headCount() external view override returns (uint256) {
        return art.getHeadsTrait().storedImagesCount;
    }

    /**
     * @notice Get the number of available Noun `glasses`.
     */
    function glassesCount() external view override returns (uint256) {
        return art.getGlassesTrait().storedImagesCount;
    }

    /**
     * @notice Batch add Noun backgrounds.
     * @dev This function can only be called by the owner when not locked.
     */
    function addManyBackgrounds(string[] calldata _backgrounds) external override onlyOwner whenPartsNotLocked {
        art.addManyBackgrounds(_backgrounds);
    }

    /**
     * @notice Add a Noun background.
     * @dev This function can only be called by the owner when not locked.
     */
    function addBackground(string calldata _background) external override onlyOwner whenPartsNotLocked {
        art.addBackground(_background);
    }

    /**
     * @notice Update a single color palette. This function can be used to
     * add a new color palette or update an existing palette.
     * @param paletteIndex the identifier of this palette
     * @param palette byte array of colors. every 3 bytes represent an RGB color. max length: 256 * 3 = 768
     * @dev This function can only be called by the owner when not locked.
     */
    function setPalette(uint8 paletteIndex, bytes calldata palette) external override onlyOwner whenPartsNotLocked {
        art.setPalette(paletteIndex, palette);
    }

    /**
     * @notice Add a batch of body images.
     * @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
     * and finally compressing it using deflate.
     * @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
     * @param imageCount the number of images in this batch; used when searching for images among batches.
     * @dev This function can only be called by the owner when not locked.
     */
    function addBodies(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external override onlyOwner whenPartsNotLocked {
        art.addBodies(encodedCompressed, decompressedLength, imageCount);
    }

    /**
     * @notice Add a batch of accessory images.
     * @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
     * and finally compressing it using deflate.
     * @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
     * @param imageCount the number of images in this batch; used when searching for images among batches.
     * @dev This function can only be called by the owner when not locked.
     */
    function addAccessories(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external override onlyOwner whenPartsNotLocked {
        art.addAccessories(encodedCompressed, decompressedLength, imageCount);
    }

    /**
     * @notice Add a batch of head images.
     * @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
     * and finally compressing it using deflate.
     * @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
     * @param imageCount the number of images in this batch; used when searching for images among batches.
     * @dev This function can only be called by the owner when not locked.
     */
    function addHeads(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external override onlyOwner whenPartsNotLocked {
        art.addHeads(encodedCompressed, decompressedLength, imageCount);
    }

    /**
     * @notice Add a batch of glasses images.
     * @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
     * and finally compressing it using deflate.
     * @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
     * @param imageCount the number of images in this batch; used when searching for images among batches.
     * @dev This function can only be called by the owner when not locked.
     */
    function addGlasses(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external override onlyOwner whenPartsNotLocked {
        art.addGlasses(encodedCompressed, decompressedLength, imageCount);
    }

    /**
     * @notice Update a single color palette. This function can be used to
     * add a new color palette or update an existing palette. This function does not check for data length validity
     * (len <= 768, len % 3 == 0).
     * @param paletteIndex the identifier of this palette
     * @param pointer the address of the contract holding the palette bytes. every 3 bytes represent an RGB color.
     * max length: 256 * 3 = 768.
     * @dev This function can only be called by the owner when not locked.
     */
    function setPalettePointer(uint8 paletteIndex, address pointer) external override onlyOwner whenPartsNotLocked {
        art.setPalettePointer(paletteIndex, pointer);
    }

    /**
     * @notice Add a batch of body images from an existing storage contract.
     * @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
     * format is expected to be like {encodedCompressed}: bytes created by taking a string array of
     * RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
     * @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
     * @param imageCount the number of images in this batch; used when searching for images among batches.
     * @dev This function can only be called by the owner when not locked.
     */
    function addBodiesFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external override onlyOwner whenPartsNotLocked {
        art.addBodiesFromPointer(pointer, decompressedLength, imageCount);
    }

    /**
     * @notice Add a batch of accessory images from an existing storage contract.
     * @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
     * format is expected to be like {encodedCompressed}: bytes created by taking a string array of
     * RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
     * @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
     * @param imageCount the number of images in this batch; used when searching for images among batches.
     * @dev This function can only be called by the owner when not locked.
     */
    function addAccessoriesFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external override onlyOwner whenPartsNotLocked {
        art.addAccessoriesFromPointer(pointer, decompressedLength, imageCount);
    }

    /**
     * @notice Add a batch of head images from an existing storage contract.
     * @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
     * format is expected to be like {encodedCompressed}: bytes created by taking a string array of
     * RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
     * @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
     * @param imageCount the number of images in this batch; used when searching for images among batches.
     * @dev This function can only be called by the owner when not locked.
     */
    function addHeadsFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external override onlyOwner whenPartsNotLocked {
        art.addHeadsFromPointer(pointer, decompressedLength, imageCount);
    }

    /**
     * @notice Add a batch of glasses images from an existing storage contract.
     * @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
     * format is expected to be like {encodedCompressed}: bytes created by taking a string array of
     * RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
     * @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
     * @param imageCount the number of images in this batch; used when searching for images among batches.
     * @dev This function can only be called by the owner when not locked.
     */
    function addGlassesFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external override onlyOwner whenPartsNotLocked {
        art.addGlassesFromPointer(pointer, decompressedLength, imageCount);
    }

    /**
     * @notice Get a background color by ID.
     * @param index the index of the background.
     * @return string the RGB hex value of the background.
     */
    function backgrounds(uint256 index) public view override returns (string memory) {
        return art.backgrounds(index);
    }

    /**
     * @notice Get a head image by ID.
     * @param index the index of the head.
     * @return bytes the RLE-encoded bytes of the image.
     */
    function heads(uint256 index) public view override returns (bytes memory) {
        return art.heads(index);
    }

    /**
     * @notice Get a body image by ID.
     * @param index the index of the body.
     * @return bytes the RLE-encoded bytes of the image.
     */
    function bodies(uint256 index) public view override returns (bytes memory) {
        return art.bodies(index);
    }

    /**
     * @notice Get an accessory image by ID.
     * @param index the index of the accessory.
     * @return bytes the RLE-encoded bytes of the image.
     */
    function accessories(uint256 index) public view override returns (bytes memory) {
        return art.accessories(index);
    }

    /**
     * @notice Get a glasses image by ID.
     * @param index the index of the glasses.
     * @return bytes the RLE-encoded bytes of the image.
     */
    function glasses(uint256 index) public view override returns (bytes memory) {
        return art.glasses(index);
    }

    /**
     * @notice Get a color palette by ID.
     * @param index the index of the palette.
     * @return bytes the palette bytes, where every 3 consecutive bytes represent a color in RGB format.
     */
    function palettes(uint8 index) public view override returns (bytes memory) {
        return art.palettes(index);
    }

    /**
     * @notice Lock all Noun parts.
     * @dev This cannot be reversed and can only be called by the owner when not locked.
     */
    function lockParts() external override onlyOwner whenPartsNotLocked {
        arePartsLocked = true;

        emit PartsLocked();
    }

    /**
     * @notice Toggle a boolean value which determines if `tokenURI` returns a data URI
     * or an HTTP URL.
     * @dev This can only be called by the owner.
     */
    function toggleDataURIEnabled() external override onlyOwner {
        bool enabled = !isDataURIEnabled;

        isDataURIEnabled = enabled;
        emit DataURIToggled(enabled);
    }

    /**
     * @notice Set the base URI for all token IDs. It is automatically
     * added as a prefix to the value returned in {tokenURI}, or to the
     * token ID if {tokenURI} is empty.
     * @dev This can only be called by the owner.
     */
    function setBaseURI(string calldata _baseURI) external override onlyOwner {
        baseURI = _baseURI;

        emit BaseURIUpdated(_baseURI);
    }

    /**
     * @notice Given a token ID and seed, construct a token URI for an official Nouns DAO noun.
     * @dev The returned value may be a base64 encoded data URI or an API URL.
     */
    function tokenURI(uint256 tokenId, INounsSeeder.Seed memory seed) external view override returns (string memory) {
        if (isDataURIEnabled) {
            return dataURI(tokenId, seed);
        }
        return string(abi.encodePacked(baseURI, tokenId.toString()));
    }

    /**
     * @notice Given a token ID and seed, construct a base64 encoded data URI for an official Nouns DAO noun.
     */
    function dataURI(uint256 tokenId, INounsSeeder.Seed memory seed) public view override returns (string memory) {
        string memory nounId = tokenId.toString();
        string memory name = string(abi.encodePacked('Noun ', nounId));
        string memory description = string(abi.encodePacked('Noun ', nounId, ' is a member of the Nouns DAO'));

        return genericDataURI(name, description, seed);
    }

    /**
     * @notice Given a name, description, and seed, construct a base64 encoded data URI.
     */
    function genericDataURI(
        string memory name,
        string memory description,
        INounsSeeder.Seed memory seed
    ) public view override returns (string memory) {
        NFTDescriptorV2.TokenURIParams memory params = NFTDescriptorV2.TokenURIParams({
            name: name,
            description: description,
            parts: getPartsForSeed(seed),
            background: art.backgrounds(seed.background)
        });
        return NFTDescriptorV2.constructTokenURI(renderer, params);
    }

    /**
     * @notice Given a seed, construct a base64 encoded SVG image.
     */
    function generateSVGImage(INounsSeeder.Seed memory seed) external view override returns (string memory) {
        ISVGRenderer.SVGParams memory params = ISVGRenderer.SVGParams({
            parts: getPartsForSeed(seed),
            background: art.backgrounds(seed.background)
        });
        return NFTDescriptorV2.generateSVGImage(renderer, params);
    }

    /**
     * @notice Get all Noun parts for the passed `seed`.
     */
    function getPartsForSeed(INounsSeeder.Seed memory seed) public view returns (ISVGRenderer.Part[] memory) {
        bytes memory body = art.bodies(seed.body);
        bytes memory accessory = art.accessories(seed.accessory);
        bytes memory head = art.heads(seed.head);
        bytes memory glasses_ = art.glasses(seed.glasses);

        ISVGRenderer.Part[] memory parts = new ISVGRenderer.Part[](4);
        parts[0] = ISVGRenderer.Part({ image: body, palette: _getPalette(body) });
        parts[1] = ISVGRenderer.Part({ image: accessory, palette: _getPalette(accessory) });
        parts[2] = ISVGRenderer.Part({ image: head, palette: _getPalette(head) });
        parts[3] = ISVGRenderer.Part({ image: glasses_, palette: _getPalette(glasses_) });
        return parts;
    }

    /**
     * @notice Get the color palette pointer for the passed part.
     */
    function _getPalette(bytes memory part) private view returns (bytes memory) {
        return art.palettes(uint8(part[0]));
    }
}
        

/_openzeppelin/contracts/access/Ownable.sol

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

/_openzeppelin/contracts/utils/Context.sol

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

pragma solidity ^0.8.0;

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

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

/_openzeppelin/contracts/utils/Strings.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.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 `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);
    }
}
          

/_openzeppelin/contracts/utils/math/Math.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 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 10, 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 * 8) < value ? 1 : 0);
        }
    }
}
          

/base64-sol/base64.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0;

/// @title Base64
/// @author Brecht Devos - <brecht@loopring.org>
/// @notice Provides functions for encoding/decoding base64
library Base64 {
    string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    bytes  internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000"
                                            hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"
                                            hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"
                                            hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";

    function encode(bytes memory data) internal pure returns (string memory) {
        if (data.length == 0) return '';

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

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

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

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

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

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

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

            // run over the input, 3 bytes at a time
            for {} lt(dataPtr, endPtr) {}
            {
                // read 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

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

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

        return result;
    }

    function decode(string memory _data) internal pure returns (bytes memory) {
        bytes memory data = bytes(_data);

        if (data.length == 0) return new bytes(0);
        require(data.length % 4 == 0, "invalid base64 decoder input");

        // load the table into memory
        bytes memory table = TABLE_DECODE;

        // every 4 characters represent 3 bytes
        uint256 decodedLen = (data.length / 4) * 3;

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

        assembly {
            // padding with '='
            let lastBytes := mload(add(data, mload(data)))
            if eq(and(lastBytes, 0xFF), 0x3d) {
                decodedLen := sub(decodedLen, 1)
                if eq(and(lastBytes, 0xFFFF), 0x3d3d) {
                    decodedLen := sub(decodedLen, 1)
                }
            }

            // set the actual output length
            mstore(result, decodedLen)

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

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

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

            // run over the input, 4 characters at a time
            for {} lt(dataPtr, endPtr) {}
            {
               // read 4 characters
               dataPtr := add(dataPtr, 4)
               let input := mload(dataPtr)

               // write 3 bytes
               let output := add(
                   add(
                       shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)),
                       shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))),
                   add(
                       shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)),
                               and(mload(add(tablePtr, and(        input , 0xFF))), 0xFF)
                    )
                )
                mstore(resultPtr, shl(232, output))
                resultPtr := add(resultPtr, 3)
            }
        }

        return result;
    }
}
          

/contracts/interfaces/IInflator.sol

// SPDX-License-Identifier: GPL-3.0

/// @title Interface for Inflator

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.6;

import { Inflate } from '../libs/Inflate.sol';

interface IInflator {
    function puff(bytes memory source, uint256 destlen) external pure returns (Inflate.ErrorCode, bytes memory);
}
          

/contracts/interfaces/INounsArt.sol

// SPDX-License-Identifier: GPL-3.0

/// @title Interface for NounsArt

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.6;

import { Inflate } from '../libs/Inflate.sol';
import { IInflator } from './IInflator.sol';

interface INounsArt {
    error SenderIsNotDescriptor();

    error EmptyPalette();

    error BadPaletteLength();

    error EmptyBytes();

    error BadDecompressedLength();

    error BadImageCount();

    error ImageNotFound();

    error PaletteNotFound();

    event DescriptorUpdated(address oldDescriptor, address newDescriptor);

    event InflatorUpdated(address oldInflator, address newInflator);

    event BackgroundsAdded(uint256 count);

    event PaletteSet(uint8 paletteIndex);

    event BodiesAdded(uint16 count);

    event AccessoriesAdded(uint16 count);

    event HeadsAdded(uint16 count);

    event GlassesAdded(uint16 count);

    struct NounArtStoragePage {
        uint16 imageCount;
        uint80 decompressedLength;
        address pointer;
    }

    struct Trait {
        NounArtStoragePage[] storagePages;
        uint256 storedImagesCount;
    }

    function descriptor() external view returns (address);

    function inflator() external view returns (IInflator);

    function setDescriptor(address descriptor) external;

    function setInflator(IInflator inflator) external;

    function addManyBackgrounds(string[] calldata _backgrounds) external;

    function addBackground(string calldata _background) external;

    function palettes(uint8 paletteIndex) external view returns (bytes memory);

    function setPalette(uint8 paletteIndex, bytes calldata palette) external;

    function addBodies(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addAccessories(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addHeads(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addGlasses(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addBodiesFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function setPalettePointer(uint8 paletteIndex, address pointer) external;

    function addAccessoriesFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addHeadsFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addGlassesFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function backgroundsCount() external view returns (uint256);

    function backgrounds(uint256 index) external view returns (string memory);

    function heads(uint256 index) external view returns (bytes memory);

    function bodies(uint256 index) external view returns (bytes memory);

    function accessories(uint256 index) external view returns (bytes memory);

    function glasses(uint256 index) external view returns (bytes memory);

    function getBodiesTrait() external view returns (Trait memory);

    function getAccessoriesTrait() external view returns (Trait memory);

    function getHeadsTrait() external view returns (Trait memory);

    function getGlassesTrait() external view returns (Trait memory);
}
          

/contracts/interfaces/INounsDescriptorMinimal.sol

// SPDX-License-Identifier: GPL-3.0

/// @title Common interface for NounsDescriptor versions, as used by NounsToken and NounsSeeder.

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.6;

import { INounsSeeder } from './INounsSeeder.sol';

interface INounsDescriptorMinimal {
    ///
    /// USED BY TOKEN
    ///

    function tokenURI(uint256 tokenId, INounsSeeder.Seed memory seed) external view returns (string memory);

    function dataURI(uint256 tokenId, INounsSeeder.Seed memory seed) external view returns (string memory);

    ///
    /// USED BY SEEDER
    ///

    function backgroundCount() external view returns (uint256);

    function bodyCount() external view returns (uint256);

    function accessoryCount() external view returns (uint256);

    function headCount() external view returns (uint256);

    function glassesCount() external view returns (uint256);
}
          

/contracts/interfaces/INounsDescriptorV2.sol

// SPDX-License-Identifier: GPL-3.0

/// @title Interface for NounsDescriptorV2

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.6;

import { INounsSeeder } from './INounsSeeder.sol';
import { ISVGRenderer } from './ISVGRenderer.sol';
import { INounsArt } from './INounsArt.sol';
import { INounsDescriptorMinimal } from './INounsDescriptorMinimal.sol';

interface INounsDescriptorV2 is INounsDescriptorMinimal {
    event PartsLocked();

    event DataURIToggled(bool enabled);

    event BaseURIUpdated(string baseURI);

    event ArtUpdated(INounsArt art);

    event RendererUpdated(ISVGRenderer renderer);

    error EmptyPalette();
    error BadPaletteLength();
    error IndexNotFound();

    function arePartsLocked() external returns (bool);

    function isDataURIEnabled() external returns (bool);

    function baseURI() external returns (string memory);

    function palettes(uint8 paletteIndex) external view returns (bytes memory);

    function backgrounds(uint256 index) external view returns (string memory);

    function bodies(uint256 index) external view returns (bytes memory);

    function accessories(uint256 index) external view returns (bytes memory);

    function heads(uint256 index) external view returns (bytes memory);

    function glasses(uint256 index) external view returns (bytes memory);

    function backgroundCount() external view override returns (uint256);

    function bodyCount() external view override returns (uint256);

    function accessoryCount() external view override returns (uint256);

    function headCount() external view override returns (uint256);

    function glassesCount() external view override returns (uint256);

    function addManyBackgrounds(string[] calldata backgrounds) external;

    function addBackground(string calldata background) external;

    function setPalette(uint8 paletteIndex, bytes calldata palette) external;

    function addBodies(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addAccessories(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addHeads(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addGlasses(
        bytes calldata encodedCompressed,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function setPalettePointer(uint8 paletteIndex, address pointer) external;

    function addBodiesFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addAccessoriesFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addHeadsFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function addGlassesFromPointer(
        address pointer,
        uint80 decompressedLength,
        uint16 imageCount
    ) external;

    function lockParts() external;

    function toggleDataURIEnabled() external;

    function setBaseURI(string calldata baseURI) external;

    function tokenURI(uint256 tokenId, INounsSeeder.Seed memory seed) external view override returns (string memory);

    function dataURI(uint256 tokenId, INounsSeeder.Seed memory seed) external view override returns (string memory);

    function genericDataURI(
        string calldata name,
        string calldata description,
        INounsSeeder.Seed memory seed
    ) external view returns (string memory);

    function generateSVGImage(INounsSeeder.Seed memory seed) external view returns (string memory);
}
          

/contracts/interfaces/INounsSeeder.sol

// SPDX-License-Identifier: GPL-3.0

/// @title Interface for NounsSeeder

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.6;

import { INounsDescriptorMinimal } from './INounsDescriptorMinimal.sol';

interface INounsSeeder {
    struct Seed {
        uint48 background;
        uint48 body;
        uint48 accessory;
        uint48 head;
        uint48 glasses;
    }

    function generateSeed(uint256 nounId, INounsDescriptorMinimal descriptor) external view returns (Seed memory);
}
          

/contracts/interfaces/ISVGRenderer.sol

// SPDX-License-Identifier: GPL-3.0

/// @title Interface for SVGRenderer

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.6;

interface ISVGRenderer {
    struct Part {
        bytes image;
        bytes palette;
    }

    struct SVGParams {
        Part[] parts;
        string background;
    }

    function generateSVG(SVGParams memory params) external view returns (string memory svg);

    function generateSVGPart(Part memory part) external view returns (string memory partialSVG);

    function generateSVGParts(Part[] memory parts) external view returns (string memory partialSVG);
}
          

/contracts/libs/Inflate.sol

// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.0 <0.9.0;

/// @notice Based on https://github.com/madler/zlib/blob/master/contrib/puff
/// @dev Modified the original code for gas optimizations
/// 1. Disable overflow/underflow checks
/// 2. Chunk some loop iterations
library Inflate {
    // Maximum bits in a code
    uint256 constant MAXBITS = 15;
    // Maximum number of literal/length codes
    uint256 constant MAXLCODES = 286;
    // Maximum number of distance codes
    uint256 constant MAXDCODES = 30;
    // Maximum codes lengths to read
    uint256 constant MAXCODES = (MAXLCODES + MAXDCODES);
    // Number of fixed literal/length codes
    uint256 constant FIXLCODES = 288;

    // Error codes
    enum ErrorCode {
        ERR_NONE, // 0 successful inflate
        ERR_NOT_TERMINATED, // 1 available inflate data did not terminate
        ERR_OUTPUT_EXHAUSTED, // 2 output space exhausted before completing inflate
        ERR_INVALID_BLOCK_TYPE, // 3 invalid block type (type == 3)
        ERR_STORED_LENGTH_NO_MATCH, // 4 stored block length did not match one's complement
        ERR_TOO_MANY_LENGTH_OR_DISTANCE_CODES, // 5 dynamic block code description: too many length or distance codes
        ERR_CODE_LENGTHS_CODES_INCOMPLETE, // 6 dynamic block code description: code lengths codes incomplete
        ERR_REPEAT_NO_FIRST_LENGTH, // 7 dynamic block code description: repeat lengths with no first length
        ERR_REPEAT_MORE, // 8 dynamic block code description: repeat more than specified lengths
        ERR_INVALID_LITERAL_LENGTH_CODE_LENGTHS, // 9 dynamic block code description: invalid literal/length code lengths
        ERR_INVALID_DISTANCE_CODE_LENGTHS, // 10 dynamic block code description: invalid distance code lengths
        ERR_MISSING_END_OF_BLOCK, // 11 dynamic block code description: missing end-of-block code
        ERR_INVALID_LENGTH_OR_DISTANCE_CODE, // 12 invalid literal/length or distance code in fixed or dynamic block
        ERR_DISTANCE_TOO_FAR, // 13 distance is too far back in fixed or dynamic block
        ERR_CONSTRUCT // 14 internal: error in construct()
    }

    // Input and output state
    struct State {
        //////////////////
        // Output state //
        //////////////////
        // Output buffer
        bytes output;
        // Bytes written to out so far
        uint256 outcnt;
        /////////////////
        // Input state //
        /////////////////
        // Input buffer
        bytes input;
        // Bytes read so far
        uint256 incnt;
        ////////////////
        // Temp state //
        ////////////////
        // Bit buffer
        uint256 bitbuf;
        // Number of bits in bit buffer
        uint256 bitcnt;
        //////////////////////////
        // Static Huffman codes //
        //////////////////////////
        Huffman lencode;
        Huffman distcode;
    }

    // Huffman code decoding tables
    struct Huffman {
        uint256[] counts;
        uint256[] symbols;
    }

    function bits(State memory s, uint256 need) private pure returns (ErrorCode, uint256) {
        unchecked {
            // Bit accumulator (can use up to 20 bits)
            uint256 val;

            // Load at least need bits into val
            val = s.bitbuf;
            while (s.bitcnt < need) {
                if (s.incnt == s.input.length) {
                    // Out of input
                    return (ErrorCode.ERR_NOT_TERMINATED, 0);
                }

                // Load eight bits
                val |= uint256(uint8(s.input[s.incnt++])) << s.bitcnt;
                s.bitcnt += 8;
            }

            // Drop need bits and update buffer, always zero to seven bits left
            s.bitbuf = val >> need;
            s.bitcnt -= need;

            // Return need bits, zeroing the bits above that
            uint256 ret = (val & ((1 << need) - 1));
            return (ErrorCode.ERR_NONE, ret);
        }
    }

    function _stored(State memory s) private pure returns (ErrorCode) {
        unchecked {
            // Length of stored block
            uint256 len;

            // Discard leftover bits from current byte (assumes s.bitcnt < 8)
            s.bitbuf = 0;
            s.bitcnt = 0;

            // Get length and check against its one's complement
            if (s.incnt + 4 > s.input.length) {
                // Not enough input
                return ErrorCode.ERR_NOT_TERMINATED;
            }
            len = uint256(uint8(s.input[s.incnt++]));
            len |= uint256(uint8(s.input[s.incnt++])) << 8;

            if (uint8(s.input[s.incnt++]) != (~len & 0xFF) || uint8(s.input[s.incnt++]) != ((~len >> 8) & 0xFF)) {
                // Didn't match complement!
                return ErrorCode.ERR_STORED_LENGTH_NO_MATCH;
            }

            // Copy len bytes from in to out
            if (s.incnt + len > s.input.length) {
                // Not enough input
                return ErrorCode.ERR_NOT_TERMINATED;
            }
            if (s.outcnt + len > s.output.length) {
                // Not enough output space
                return ErrorCode.ERR_OUTPUT_EXHAUSTED;
            }
            while (len != 0) {
                // Note: Solidity reverts on underflow, so we decrement here
                len -= 1;
                s.output[s.outcnt++] = s.input[s.incnt++];
            }

            // Done with a valid stored block
            return ErrorCode.ERR_NONE;
        }
    }

    function _decode(State memory s, Huffman memory h) private pure returns (ErrorCode, uint256) {
        unchecked {
            // Current number of bits in code
            uint256 len;
            // Len bits being decoded
            uint256 code = 0;
            // First code of length len
            uint256 first = 0;
            // Number of codes of length len
            uint256 count;
            // Index of first code of length len in symbol table
            uint256 index = 0;
            // Error code
            ErrorCode err;

            uint256 tempCode;
            for (len = 1; len <= MAXBITS; len += 5) {
                // Get next bit
                (err, tempCode) = bits(s, 1);
                if (err != ErrorCode.ERR_NONE) {
                    return (err, 0);
                }
                code |= tempCode;
                count = h.counts[len];

                // If length len, return symbol
                if (code < first + count) {
                    return (ErrorCode.ERR_NONE, h.symbols[index + (code - first)]);
                }
                // Else update for next length
                index += count;
                first += count;
                first <<= 1;
                code <<= 1;

                // Get next bit
                (err, tempCode) = bits(s, 1);
                if (err != ErrorCode.ERR_NONE) {
                    return (err, 0);
                }
                code |= tempCode;
                count = h.counts[len + 1];

                // If length len, return symbol
                if (code < first + count) {
                    return (ErrorCode.ERR_NONE, h.symbols[index + (code - first)]);
                }
                // Else update for next length
                index += count;
                first += count;
                first <<= 1;
                code <<= 1;

                // Get next bit
                (err, tempCode) = bits(s, 1);
                if (err != ErrorCode.ERR_NONE) {
                    return (err, 0);
                }
                code |= tempCode;
                count = h.counts[len + 2];

                // If length len, return symbol
                if (code < first + count) {
                    return (ErrorCode.ERR_NONE, h.symbols[index + (code - first)]);
                }
                // Else update for next length
                index += count;
                first += count;
                first <<= 1;
                code <<= 1;

                // Get next bit
                (err, tempCode) = bits(s, 1);
                if (err != ErrorCode.ERR_NONE) {
                    return (err, 0);
                }
                code |= tempCode;
                count = h.counts[len + 3];

                // If length len, return symbol
                if (code < first + count) {
                    return (ErrorCode.ERR_NONE, h.symbols[index + (code - first)]);
                }
                // Else update for next length
                index += count;
                first += count;
                first <<= 1;
                code <<= 1;

                // Get next bit
                (err, tempCode) = bits(s, 1);
                if (err != ErrorCode.ERR_NONE) {
                    return (err, 0);
                }
                code |= tempCode;
                count = h.counts[len + 4];

                // If length len, return symbol
                if (code < first + count) {
                    return (ErrorCode.ERR_NONE, h.symbols[index + (code - first)]);
                }
                // Else update for next length
                index += count;
                first += count;
                first <<= 1;
                code <<= 1;
            }

            // Ran out of codes
            return (ErrorCode.ERR_INVALID_LENGTH_OR_DISTANCE_CODE, 0);
        }
    }

    function _construct(
        Huffman memory h,
        uint256[] memory lengths,
        uint256 n,
        uint256 start
    ) private pure returns (ErrorCode) {
        unchecked {
            // Current symbol when stepping through lengths[]
            uint256 symbol;
            // Current length when stepping through h.counts[]
            uint256 len;
            // Number of possible codes left of current length
            uint256 left;
            // Offsets in symbol table for each length
            uint256[MAXBITS + 1] memory offs;

            // Count number of codes of each length
            for (len = 0; len <= MAXBITS; ++len) {
                h.counts[len] = 0;
            }
            for (symbol = 0; symbol < n; ++symbol) {
                // Assumes lengths are within bounds
                ++h.counts[lengths[start + symbol]];
            }
            // No codes!
            if (h.counts[0] == n) {
                // Complete, but decode() will fail
                return (ErrorCode.ERR_NONE);
            }

            // Check for an over-subscribed or incomplete set of lengths

            // One possible code of zero length
            left = 1;

            for (len = 1; len <= MAXBITS; len += 5) {
                // One more bit, double codes left
                left <<= 1;
                if (left < h.counts[len]) {
                    // Over-subscribed--return error
                    return ErrorCode.ERR_CONSTRUCT;
                }
                // Deduct count from possible codes
                left -= h.counts[len];

                // One more bit, double codes left
                left <<= 1;
                if (left < h.counts[len + 1]) {
                    // Over-subscribed--return error
                    return ErrorCode.ERR_CONSTRUCT;
                }
                // Deduct count from possible codes
                left -= h.counts[len + 1];

                // One more bit, double codes left
                left <<= 1;
                if (left < h.counts[len + 2]) {
                    // Over-subscribed--return error
                    return ErrorCode.ERR_CONSTRUCT;
                }
                // Deduct count from possible codes
                left -= h.counts[len + 2];

                // One more bit, double codes left
                left <<= 1;
                if (left < h.counts[len + 3]) {
                    // Over-subscribed--return error
                    return ErrorCode.ERR_CONSTRUCT;
                }
                // Deduct count from possible codes
                left -= h.counts[len + 3];

                // One more bit, double codes left
                left <<= 1;
                if (left < h.counts[len + 4]) {
                    // Over-subscribed--return error
                    return ErrorCode.ERR_CONSTRUCT;
                }
                // Deduct count from possible codes
                left -= h.counts[len + 4];
            }

            // Generate offsets into symbol table for each length for sorting
            offs[1] = 0;
            for (len = 1; len < MAXBITS; ++len) {
                offs[len + 1] = offs[len] + h.counts[len];
            }

            // Put symbols in table sorted by length, by symbol order within each length
            for (symbol = 0; symbol < n; ++symbol) {
                if (lengths[start + symbol] != 0) {
                    h.symbols[offs[lengths[start + symbol]]++] = symbol;
                }
            }

            // Left > 0 means incomplete
            return left > 0 ? ErrorCode.ERR_CONSTRUCT : ErrorCode.ERR_NONE;
        }
    }

    function _codes(
        State memory s,
        Huffman memory lencode,
        Huffman memory distcode
    ) private pure returns (ErrorCode) {
        unchecked {
            // Decoded symbol
            uint256 symbol;
            // Length for copy
            uint256 len;
            // Distance for copy
            uint256 dist;
            // TODO Solidity doesn't support constant arrays, but these are fixed at compile-time
            // Size base for length codes 257..285
            uint16[29] memory lens = [
                3,
                4,
                5,
                6,
                7,
                8,
                9,
                10,
                11,
                13,
                15,
                17,
                19,
                23,
                27,
                31,
                35,
                43,
                51,
                59,
                67,
                83,
                99,
                115,
                131,
                163,
                195,
                227,
                258
            ];
            // Extra bits for length codes 257..285
            uint8[29] memory lext = [
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                1,
                1,
                1,
                1,
                2,
                2,
                2,
                2,
                3,
                3,
                3,
                3,
                4,
                4,
                4,
                4,
                5,
                5,
                5,
                5,
                0
            ];
            // Offset base for distance codes 0..29
            uint16[30] memory dists = [
                1,
                2,
                3,
                4,
                5,
                7,
                9,
                13,
                17,
                25,
                33,
                49,
                65,
                97,
                129,
                193,
                257,
                385,
                513,
                769,
                1025,
                1537,
                2049,
                3073,
                4097,
                6145,
                8193,
                12289,
                16385,
                24577
            ];
            // Extra bits for distance codes 0..29
            uint8[30] memory dext = [
                0,
                0,
                0,
                0,
                1,
                1,
                2,
                2,
                3,
                3,
                4,
                4,
                5,
                5,
                6,
                6,
                7,
                7,
                8,
                8,
                9,
                9,
                10,
                10,
                11,
                11,
                12,
                12,
                13,
                13
            ];
            // Error code
            ErrorCode err;

            // Decode literals and length/distance pairs
            while (symbol != 256) {
                (err, symbol) = _decode(s, lencode);
                if (err != ErrorCode.ERR_NONE) {
                    // Invalid symbol
                    return err;
                }

                if (symbol < 256) {
                    // Literal: symbol is the byte
                    // Write out the literal
                    if (s.outcnt == s.output.length) {
                        return ErrorCode.ERR_OUTPUT_EXHAUSTED;
                    }
                    s.output[s.outcnt] = bytes1(uint8(symbol));
                    ++s.outcnt;
                } else if (symbol > 256) {
                    uint256 tempBits;
                    // Length
                    // Get and compute length
                    symbol -= 257;
                    if (symbol >= 29) {
                        // Invalid fixed code
                        return ErrorCode.ERR_INVALID_LENGTH_OR_DISTANCE_CODE;
                    }

                    (err, tempBits) = bits(s, lext[symbol]);
                    if (err != ErrorCode.ERR_NONE) {
                        return err;
                    }
                    len = lens[symbol] + tempBits;

                    // Get and check distance
                    (err, symbol) = _decode(s, distcode);
                    if (err != ErrorCode.ERR_NONE) {
                        // Invalid symbol
                        return err;
                    }
                    (err, tempBits) = bits(s, dext[symbol]);
                    if (err != ErrorCode.ERR_NONE) {
                        return err;
                    }
                    dist = dists[symbol] + tempBits;
                    if (dist > s.outcnt) {
                        // Distance too far back
                        return ErrorCode.ERR_DISTANCE_TOO_FAR;
                    }

                    // Copy length bytes from distance bytes back
                    if (s.outcnt + len > s.output.length) {
                        return ErrorCode.ERR_OUTPUT_EXHAUSTED;
                    }
                    while (len != 0) {
                        // Note: Solidity reverts on underflow, so we decrement here
                        len -= 1;
                        s.output[s.outcnt] = s.output[s.outcnt - dist];
                        ++s.outcnt;
                    }
                } else {
                    s.outcnt += len;
                }
            }

            // Done with a valid fixed or dynamic block
            return ErrorCode.ERR_NONE;
        }
    }

    function _build_fixed(State memory s) private pure returns (ErrorCode) {
        unchecked {
            // Build fixed Huffman tables
            // TODO this is all a compile-time constant
            uint256 symbol;
            uint256[] memory lengths = new uint256[](FIXLCODES);

            // Literal/length table
            for (symbol = 0; symbol < 144; ++symbol) {
                lengths[symbol] = 8;
            }
            for (; symbol < 256; ++symbol) {
                lengths[symbol] = 9;
            }
            for (; symbol < 280; ++symbol) {
                lengths[symbol] = 7;
            }
            for (; symbol < FIXLCODES; ++symbol) {
                lengths[symbol] = 8;
            }

            _construct(s.lencode, lengths, FIXLCODES, 0);

            // Distance table
            for (symbol = 0; symbol < MAXDCODES; ++symbol) {
                lengths[symbol] = 5;
            }

            _construct(s.distcode, lengths, MAXDCODES, 0);

            return ErrorCode.ERR_NONE;
        }
    }

    function _fixed(State memory s) private pure returns (ErrorCode) {
        unchecked {
            // Decode data until end-of-block code
            return _codes(s, s.lencode, s.distcode);
        }
    }

    function _build_dynamic_lengths(State memory s) private pure returns (ErrorCode, uint256[] memory) {
        unchecked {
            uint256 ncode;
            // Index of lengths[]
            uint256 index;
            // Descriptor code lengths
            uint256[] memory lengths = new uint256[](MAXCODES);
            // Error code
            ErrorCode err;
            // Permutation of code length codes
            uint8[19] memory order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];

            (err, ncode) = bits(s, 4);
            if (err != ErrorCode.ERR_NONE) {
                return (err, lengths);
            }
            ncode += 4;

            // Read code length code lengths (really), missing lengths are zero
            for (index = 0; index < ncode; ++index) {
                (err, lengths[order[index]]) = bits(s, 3);
                if (err != ErrorCode.ERR_NONE) {
                    return (err, lengths);
                }
            }
            for (; index < 19; ++index) {
                lengths[order[index]] = 0;
            }

            return (ErrorCode.ERR_NONE, lengths);
        }
    }

    function _build_dynamic(State memory s)
        private
        pure
        returns (
            ErrorCode,
            Huffman memory,
            Huffman memory
        )
    {
        unchecked {
            // Number of lengths in descriptor
            uint256 nlen;
            uint256 ndist;
            // Index of lengths[]
            uint256 index;
            // Error code
            ErrorCode err;
            // Descriptor code lengths
            uint256[] memory lengths = new uint256[](MAXCODES);
            // Length and distance codes
            Huffman memory lencode = Huffman(new uint256[](MAXBITS + 1), new uint256[](MAXLCODES));
            Huffman memory distcode = Huffman(new uint256[](MAXBITS + 1), new uint256[](MAXDCODES));
            uint256 tempBits;

            // Get number of lengths in each table, check lengths
            (err, nlen) = bits(s, 5);
            if (err != ErrorCode.ERR_NONE) {
                return (err, lencode, distcode);
            }
            nlen += 257;
            (err, ndist) = bits(s, 5);
            if (err != ErrorCode.ERR_NONE) {
                return (err, lencode, distcode);
            }
            ndist += 1;

            if (nlen > MAXLCODES || ndist > MAXDCODES) {
                // Bad counts
                return (ErrorCode.ERR_TOO_MANY_LENGTH_OR_DISTANCE_CODES, lencode, distcode);
            }

            (err, lengths) = _build_dynamic_lengths(s);
            if (err != ErrorCode.ERR_NONE) {
                return (err, lencode, distcode);
            }

            // Build huffman table for code lengths codes (use lencode temporarily)
            err = _construct(lencode, lengths, 19, 0);
            if (err != ErrorCode.ERR_NONE) {
                // Require complete code set here
                return (ErrorCode.ERR_CODE_LENGTHS_CODES_INCOMPLETE, lencode, distcode);
            }

            // Read length/literal and distance code length tables
            index = 0;
            while (index < nlen + ndist) {
                // Decoded value
                uint256 symbol;
                // Last length to repeat
                uint256 len;

                (err, symbol) = _decode(s, lencode);
                if (err != ErrorCode.ERR_NONE) {
                    // Invalid symbol
                    return (err, lencode, distcode);
                }

                if (symbol < 16) {
                    // Length in 0..15
                    lengths[index++] = symbol;
                } else {
                    // Repeat instruction
                    // Assume repeating zeros
                    len = 0;
                    if (symbol == 16) {
                        // Repeat last length 3..6 times
                        if (index == 0) {
                            // No last length!
                            return (ErrorCode.ERR_REPEAT_NO_FIRST_LENGTH, lencode, distcode);
                        }
                        // Last length
                        len = lengths[index - 1];
                        (err, tempBits) = bits(s, 2);
                        if (err != ErrorCode.ERR_NONE) {
                            return (err, lencode, distcode);
                        }
                        symbol = 3 + tempBits;
                    } else if (symbol == 17) {
                        // Repeat zero 3..10 times
                        (err, tempBits) = bits(s, 3);
                        if (err != ErrorCode.ERR_NONE) {
                            return (err, lencode, distcode);
                        }
                        symbol = 3 + tempBits;
                    } else {
                        // == 18, repeat zero 11..138 times
                        (err, tempBits) = bits(s, 7);
                        if (err != ErrorCode.ERR_NONE) {
                            return (err, lencode, distcode);
                        }
                        symbol = 11 + tempBits;
                    }

                    if (index + symbol > nlen + ndist) {
                        // Too many lengths!
                        return (ErrorCode.ERR_REPEAT_MORE, lencode, distcode);
                    }
                    while (symbol != 0) {
                        // Note: Solidity reverts on underflow, so we decrement here
                        symbol -= 1;

                        // Repeat last or zero symbol times
                        lengths[index++] = len;
                    }
                }
            }

            // Check for end-of-block code -- there better be one!
            if (lengths[256] == 0) {
                return (ErrorCode.ERR_MISSING_END_OF_BLOCK, lencode, distcode);
            }

            // Build huffman table for literal/length codes
            err = _construct(lencode, lengths, nlen, 0);
            if (
                err != ErrorCode.ERR_NONE &&
                (err == ErrorCode.ERR_NOT_TERMINATED ||
                    err == ErrorCode.ERR_OUTPUT_EXHAUSTED ||
                    nlen != lencode.counts[0] + lencode.counts[1])
            ) {
                // Incomplete code ok only for single length 1 code
                return (ErrorCode.ERR_INVALID_LITERAL_LENGTH_CODE_LENGTHS, lencode, distcode);
            }

            // Build huffman table for distance codes
            err = _construct(distcode, lengths, ndist, nlen);
            if (
                err != ErrorCode.ERR_NONE &&
                (err == ErrorCode.ERR_NOT_TERMINATED ||
                    err == ErrorCode.ERR_OUTPUT_EXHAUSTED ||
                    ndist != distcode.counts[0] + distcode.counts[1])
            ) {
                // Incomplete code ok only for single length 1 code
                return (ErrorCode.ERR_INVALID_DISTANCE_CODE_LENGTHS, lencode, distcode);
            }

            return (ErrorCode.ERR_NONE, lencode, distcode);
        }
    }

    function _dynamic(State memory s) private pure returns (ErrorCode) {
        unchecked {
            // Length and distance codes
            Huffman memory lencode;
            Huffman memory distcode;
            // Error code
            ErrorCode err;

            (err, lencode, distcode) = _build_dynamic(s);
            if (err != ErrorCode.ERR_NONE) {
                return err;
            }

            // Decode data until end-of-block code
            return _codes(s, lencode, distcode);
        }
    }

    function puff(bytes memory source, uint256 destlen) internal pure returns (ErrorCode, bytes memory) {
        unchecked {
            // Input/output state
            State memory s = State(
                new bytes(destlen),
                0,
                source,
                0,
                0,
                0,
                Huffman(new uint256[](MAXBITS + 1), new uint256[](FIXLCODES)),
                Huffman(new uint256[](MAXBITS + 1), new uint256[](MAXDCODES))
            );
            // Temp: last bit
            uint256 last;
            // Temp: block type bit
            uint256 t;
            // Error code
            ErrorCode err;

            // Build fixed Huffman tables
            err = _build_fixed(s);
            if (err != ErrorCode.ERR_NONE) {
                return (err, s.output);
            }

            // Process blocks until last block or error
            while (last == 0) {
                // One if last block
                (err, last) = bits(s, 1);
                if (err != ErrorCode.ERR_NONE) {
                    return (err, s.output);
                }

                // Block type 0..3
                (err, t) = bits(s, 2);
                if (err != ErrorCode.ERR_NONE) {
                    return (err, s.output);
                }

                err = (
                    t == 0
                        ? _stored(s)
                        : (t == 1 ? _fixed(s) : (t == 2 ? _dynamic(s) : ErrorCode.ERR_INVALID_BLOCK_TYPE))
                );
                // type == 3, invalid

                if (err != ErrorCode.ERR_NONE) {
                    // Return with error
                    break;
                }
            }

            return (err, s.output);
        }
    }
}
          

/contracts/libs/NFTDescriptorV2.sol

// SPDX-License-Identifier: GPL-3.0

/// @title A library used to construct ERC721 token URIs and SVG images

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.6;

import { Base64 } from 'base64-sol/base64.sol';
import { ISVGRenderer } from '../interfaces/ISVGRenderer.sol';

library NFTDescriptorV2 {
    struct TokenURIParams {
        string name;
        string description;
        string background;
        ISVGRenderer.Part[] parts;
    }

    /**
     * @notice Construct an ERC721 token URI.
     */
    function constructTokenURI(ISVGRenderer renderer, TokenURIParams memory params)
        public
        view
        returns (string memory)
    {
        string memory image = generateSVGImage(
            renderer,
            ISVGRenderer.SVGParams({ parts: params.parts, background: params.background })
        );

        // prettier-ignore
        return string(
            abi.encodePacked(
                'data:application/json;base64,',
                Base64.encode(
                    bytes(
                        abi.encodePacked('{"name":"', params.name, '", "description":"', params.description, '", "image": "', 'data:image/svg+xml;base64,', image, '"}')
                    )
                )
            )
        );
    }

    /**
     * @notice Generate an SVG image for use in the ERC721 token URI.
     */
    function generateSVGImage(ISVGRenderer renderer, ISVGRenderer.SVGParams memory params)
        public
        view
        returns (string memory svg)
    {
        return Base64.encode(bytes(renderer.generateSVG(params)));
    }
}
          

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_art","internalType":"contract INounsArt"},{"type":"address","name":"_renderer","internalType":"contract ISVGRenderer"}]},{"type":"error","name":"BadPaletteLength","inputs":[]},{"type":"error","name":"EmptyPalette","inputs":[]},{"type":"error","name":"IndexNotFound","inputs":[]},{"type":"event","name":"ArtUpdated","inputs":[{"type":"address","name":"art","internalType":"contract INounsArt","indexed":false}],"anonymous":false},{"type":"event","name":"BaseURIUpdated","inputs":[{"type":"string","name":"baseURI","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"DataURIToggled","inputs":[{"type":"bool","name":"enabled","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"PartsLocked","inputs":[],"anonymous":false},{"type":"event","name":"RendererUpdated","inputs":[{"type":"address","name":"renderer","internalType":"contract ISVGRenderer","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"accessories","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"accessoryCount","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addAccessories","inputs":[{"type":"bytes","name":"encodedCompressed","internalType":"bytes"},{"type":"uint80","name":"decompressedLength","internalType":"uint80"},{"type":"uint16","name":"imageCount","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addAccessoriesFromPointer","inputs":[{"type":"address","name":"pointer","internalType":"address"},{"type":"uint80","name":"decompressedLength","internalType":"uint80"},{"type":"uint16","name":"imageCount","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addBackground","inputs":[{"type":"string","name":"_background","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addBodies","inputs":[{"type":"bytes","name":"encodedCompressed","internalType":"bytes"},{"type":"uint80","name":"decompressedLength","internalType":"uint80"},{"type":"uint16","name":"imageCount","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addBodiesFromPointer","inputs":[{"type":"address","name":"pointer","internalType":"address"},{"type":"uint80","name":"decompressedLength","internalType":"uint80"},{"type":"uint16","name":"imageCount","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addGlasses","inputs":[{"type":"bytes","name":"encodedCompressed","internalType":"bytes"},{"type":"uint80","name":"decompressedLength","internalType":"uint80"},{"type":"uint16","name":"imageCount","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addGlassesFromPointer","inputs":[{"type":"address","name":"pointer","internalType":"address"},{"type":"uint80","name":"decompressedLength","internalType":"uint80"},{"type":"uint16","name":"imageCount","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addHeads","inputs":[{"type":"bytes","name":"encodedCompressed","internalType":"bytes"},{"type":"uint80","name":"decompressedLength","internalType":"uint80"},{"type":"uint16","name":"imageCount","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addHeadsFromPointer","inputs":[{"type":"address","name":"pointer","internalType":"address"},{"type":"uint80","name":"decompressedLength","internalType":"uint80"},{"type":"uint16","name":"imageCount","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addManyBackgrounds","inputs":[{"type":"string[]","name":"_backgrounds","internalType":"string[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"arePartsLocked","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract INounsArt"}],"name":"art","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"backgroundCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"backgrounds","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"baseURI","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"bodies","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"bodyCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"dataURI","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"tuple","name":"seed","internalType":"struct INounsSeeder.Seed","components":[{"type":"uint48","name":"background","internalType":"uint48"},{"type":"uint48","name":"body","internalType":"uint48"},{"type":"uint48","name":"accessory","internalType":"uint48"},{"type":"uint48","name":"head","internalType":"uint48"},{"type":"uint48","name":"glasses","internalType":"uint48"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"generateSVGImage","inputs":[{"type":"tuple","name":"seed","internalType":"struct INounsSeeder.Seed","components":[{"type":"uint48","name":"background","internalType":"uint48"},{"type":"uint48","name":"body","internalType":"uint48"},{"type":"uint48","name":"accessory","internalType":"uint48"},{"type":"uint48","name":"head","internalType":"uint48"},{"type":"uint48","name":"glasses","internalType":"uint48"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"genericDataURI","inputs":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"description","internalType":"string"},{"type":"tuple","name":"seed","internalType":"struct INounsSeeder.Seed","components":[{"type":"uint48","name":"background","internalType":"uint48"},{"type":"uint48","name":"body","internalType":"uint48"},{"type":"uint48","name":"accessory","internalType":"uint48"},{"type":"uint48","name":"head","internalType":"uint48"},{"type":"uint48","name":"glasses","internalType":"uint48"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct ISVGRenderer.Part[]","components":[{"type":"bytes","name":"image","internalType":"bytes"},{"type":"bytes","name":"palette","internalType":"bytes"}]}],"name":"getPartsForSeed","inputs":[{"type":"tuple","name":"seed","internalType":"struct INounsSeeder.Seed","components":[{"type":"uint48","name":"background","internalType":"uint48"},{"type":"uint48","name":"body","internalType":"uint48"},{"type":"uint48","name":"accessory","internalType":"uint48"},{"type":"uint48","name":"head","internalType":"uint48"},{"type":"uint48","name":"glasses","internalType":"uint48"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"glasses","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"glassesCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"headCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"heads","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isDataURIEnabled","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"lockParts","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"palettes","inputs":[{"type":"uint8","name":"index","internalType":"uint8"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ISVGRenderer"}],"name":"renderer","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setArt","inputs":[{"type":"address","name":"_art","internalType":"contract INounsArt"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setArtDescriptor","inputs":[{"type":"address","name":"descriptor","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setArtInflator","inputs":[{"type":"address","name":"inflator","internalType":"contract IInflator"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBaseURI","inputs":[{"type":"string","name":"_baseURI","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPalette","inputs":[{"type":"uint8","name":"paletteIndex","internalType":"uint8"},{"type":"bytes","name":"palette","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPalettePointer","inputs":[{"type":"uint8","name":"paletteIndex","internalType":"uint8"},{"type":"address","name":"pointer","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRenderer","inputs":[{"type":"address","name":"_renderer","internalType":"contract ISVGRenderer"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"toggleDataURIEnabled","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"tokenURI","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"tuple","name":"seed","internalType":"struct INounsSeeder.Seed","components":[{"type":"uint48","name":"background","internalType":"uint48"},{"type":"uint48","name":"body","internalType":"uint48"},{"type":"uint48","name":"accessory","internalType":"uint48"},{"type":"uint48","name":"head","internalType":"uint48"},{"type":"uint48","name":"glasses","internalType":"uint48"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]}]
              

Contract Creation Code

0x60806040526001600260156101000a81548160ff0219169083151502179055503480156200002c57600080fd5b5060405162004c1438038062004c148339818101604052810190620000529190620001f6565b6200007262000066620000fc60201b60201c565b6200010460201b60201c565b81600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050620002d2565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600081519050620001d9816200029e565b92915050565b600081519050620001f081620002b8565b92915050565b6000806040838503121562000210576200020f62000299565b5b60006200022085828601620001c8565b92505060206200023385828601620001df565b9150509250929050565b60006200024a8262000279565b9050919050565b60006200025e826200023d565b9050919050565b600062000272826200023d565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600080fd5b620002a98162000251565b8114620002b557600080fd5b50565b620002c38162000265565b8114620002cf57600080fd5b50565b61493280620002e26000396000f3fe608060405234801561001057600080fd5b50600436106102695760003560e01c806373ac736b11610151578063bc2d45fe116100c3578063dfe8478b11610087578063dfe8478b14610746578063e6b1a3ae14610750578063e79c9ea61461076c578063eba8180614610788578063f2fde38b146107a6578063f4513a6a146107c257610269565b8063bc2d45fe1461068e578063bf61df1b146106be578063cc2aa091146106ee578063cd2b82501461070c578063ce2f4f531461072857610269565b80638bd54c06116101155780638bd54c06146105d05780638da5cb5b146105ec57806391b7916a1461060a57806394f3df6114610626578063aa5bf7d814610642578063b982d1b91461065e57610269565b806373ac736b14610518578063773b9771146105345780637ca942101461055257806387db11bd146105825780638ada6b0f146105b257610269565b80634531c0a8116101ea5780635a503f13116101ae5780635a503f13146104585780635e70664c14610488578063638ac270146104a45780636c0360eb146104d45780636e856531146104f2578063715018a61461050e57610269565b80634531c0a8146103c8578063461fc5af146103e65780634daebac21461040257806355f804b31461042057806356d3163d1461043c57610269565b8063301bd28e11610231578063301bd28e14610310578063353c36a01461032e5780633cfdafd31461034a5780634479cef21461037a57806344cee73c1461039857610269565b8063010ecde71461026e57806304bde4dd1461028a5780630ba3db1a146102ba5780632a1d0769146102d65780632ea04300146102e0575b600080fd5b6102886004803603810190610283919061330a565b6107de565b005b6102a4600480360381019061029f91906136b2565b610876565b6040516102b19190614100565b60405180910390f35b6102d460048036038101906102cf91906133d7565b61092f565b005b6102de610a20565b005b6102fa60048036038101906102f5919061363c565b610ac1565b6040516103079190614100565b60405180910390f35b610318610c4f565b6040516103259190614046565b60405180910390f35b610348600480360381019061034391906133d7565b610c75565b005b610364600480360381019061035f919061370c565b610d66565b6040516103719190614100565b60405180910390f35b610382610dc2565b60405161038f9190614182565b60405180910390f35b6103b260048036038101906103ad91906136b2565b610e72565b6040516103bf9190614009565b60405180910390f35b6103d0610f2b565b6040516103dd9190614182565b60405180910390f35b61040060048036038101906103fb9190613337565b610fd2565b005b61040a6110c0565b6040516104179190614182565b60405180910390f35b61043a6004803603810190610435919061351b565b611170565b005b610456600480360381019061045191906134ee565b6111c7565b005b610472600480360381019061046d91906136b2565b61124a565b60405161047f9190614009565b60405180910390f35b6104a2600480360381019061049d919061351b565b611303565b005b6104be60048036038101906104b9919061370c565b6113ee565b6040516104cb9190614100565b60405180910390f35b6104dc61145b565b6040516104e99190614100565b60405180910390f35b61050c60048036038101906105079190613337565b6114e9565b005b6105166115d7565b005b610532600480360381019061052d9190613337565b6115eb565b005b61053c6116d9565b6040516105499190613fae565b60405180910390f35b61056c600480360381019061056791906136b2565b6116ec565b6040516105799190614009565b60405180910390f35b61059c600480360381019061059791906135b1565b6117a5565b6040516105a99190614100565b60405180910390f35b6105ba611941565b6040516105c79190614061565b60405180910390f35b6105ea60048036038101906105e59190613779565b611967565b005b6105f4611a52565b6040516106019190613f16565b60405180910390f35b610624600480360381019061061f919061338a565b611a7b565b005b610640600480360381019061063b91906133d7565b611b66565b005b61065c600480360381019061065791906133d7565b611c57565b005b610678600480360381019061067391906136b2565b611d48565b6040516106859190614009565b60405180910390f35b6106a860048036038101906106a3919061374c565b611e01565b6040516106b59190614009565b60405180910390f35b6106d860048036038101906106d3919061363c565b611eba565b6040516106e59190613f8c565b60405180910390f35b6106f66122f2565b6040516107039190614182565b60405180910390f35b61072660048036038101906107219190613337565b6123a2565b005b610730612490565b60405161073d9190613fae565b60405180910390f35b61074e6124a3565b005b61076a600480360381019061076591906134c1565b612514565b005b610786600480360381019061078191906137b9565b6125e7565b005b6107906126d5565b60405161079d9190614182565b60405180910390f35b6107c060048036038101906107bb919061330a565b612785565b005b6107dc60048036038101906107d79190613494565b612809565b005b6107e66128a1565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166301b9a397826040518263ffffffff1660e01b81526004016108419190613f16565b600060405180830381600087803b15801561085b57600080fd5b505af115801561086f573d6000803e3d6000fd5b5050505050565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166304bde4dd836040518263ffffffff1660e01b81526004016108d39190614182565b60006040518083038186803b1580156108eb57600080fd5b505afa1580156108ff573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906109289190613568565b9050919050565b6109376128a1565b600260149054906101000a900460ff1615610987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097e90614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630ba3db1a858585856040518563ffffffff1660e01b81526004016109e89493929190613fc9565b600060405180830381600087803b158015610a0257600080fd5b505af1158015610a16573d6000803e3d6000fd5b5050505050505050565b610a286128a1565b600260149054906101000a900460ff1615610a78576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a6f90614122565b60405180910390fd5b6001600260146101000a81548160ff0219169083151502179055507f1680ee6d421f70ed6030d2fc4fcb50217a5dd617858d56562b119eca59172e5760405160405180910390a1565b606060006040518060400160405280610ad985611eba565b8152602001600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166304bde4dd86600001516040518263ffffffff1660e01b8152600401610b3d919061419d565b60006040518083038186803b158015610b5557600080fd5b505afa158015610b69573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610b929190613568565b8152509050736e924ee093a1b626a01c699760fd51e1e25550e66322cc1ad6600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401610bf292919061407c565b60006040518083038186803b158015610c0a57600080fd5b505af4158015610c1e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610c479190613568565b915050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610c7d6128a1565b600260149054906101000a900460ff1615610ccd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc490614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663353c36a0858585856040518563ffffffff1660e01b8152600401610d2e9493929190613fc9565b600060405180830381600087803b158015610d4857600080fd5b505af1158015610d5c573d6000803e3d6000fd5b5050505050505050565b6060600260159054906101000a900460ff1615610d8e57610d8783836113ee565b9050610dbc565b6003610d998461291f565b604051602001610daa929190613ea3565b60405160208183030381529060405290505b92915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e73dd3836040518163ffffffff1660e01b815260040160006040518083038186803b158015610e2c57600080fd5b505afa158015610e40573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610e699190613669565b60200151905090565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166344cee73c836040518263ffffffff1660e01b8152600401610ecf9190614182565b60006040518083038186803b158015610ee757600080fd5b505afa158015610efb573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610f24919061344b565b9050919050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fd30704b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f9557600080fd5b505afa158015610fa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcd91906136df565b905090565b610fda6128a1565b600260149054906101000a900460ff161561102a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102190614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663461fc5af8484846040518463ffffffff1660e01b815260040161108993929190613f31565b600060405180830381600087803b1580156110a357600080fd5b505af11580156110b7573d6000803e3d6000fd5b50505050505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c64b2f5d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561112a57600080fd5b505afa15801561113e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906111679190613669565b60200151905090565b6111786128a1565b818160039190611189929190612cf0565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad82826040516111bb9291906140dc565b60405180910390a15050565b6111cf6128a1565b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f482cbbbcf912da3be80deb8503ae1e94c0b7d5d1d0ec0af3d9d6403e06e609ee8160405161123f9190614061565b60405180910390a150565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a503f13836040518263ffffffff1660e01b81526004016112a79190614182565b60006040518083038186803b1580156112bf57600080fd5b505afa1580156112d3573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906112fc919061344b565b9050919050565b61130b6128a1565b600260149054906101000a900460ff161561135b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161135290614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635e70664c83836040518363ffffffff1660e01b81526004016113b89291906140dc565b600060405180830381600087803b1580156113d257600080fd5b505af11580156113e6573d6000803e3d6000fd5b505050505050565b606060006113fb8461291f565b90506000816040516020016114109190613ec7565b60405160208183030381529060405290506000826040516020016114349190613ee9565b60405160208183030381529060405290506114508282876117a5565b935050505092915050565b60038054611468906145d3565b80601f0160208091040260200160405190810160405280929190818152602001828054611494906145d3565b80156114e15780601f106114b6576101008083540402835291602001916114e1565b820191906000526020600020905b8154815290600101906020018083116114c457829003601f168201915b505050505081565b6114f16128a1565b600260149054906101000a900460ff1615611541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161153890614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636e8565318484846040518463ffffffff1660e01b81526004016115a093929190613f31565b600060405180830381600087803b1580156115ba57600080fd5b505af11580156115ce573d6000803e3d6000fd5b50505050505050565b6115df6128a1565b6115e960006129f7565b565b6115f36128a1565b600260149054906101000a900460ff1615611643576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161163a90614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166373ac736b8484846040518463ffffffff1660e01b81526004016116a293929190613f31565b600060405180830381600087803b1580156116bc57600080fd5b505af11580156116d0573d6000803e3d6000fd5b50505050505050565b600260149054906101000a900460ff1681565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637ca94210836040518263ffffffff1660e01b81526004016117499190614182565b60006040518083038186803b15801561176157600080fd5b505afa158015611775573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061179e919061344b565b9050919050565b606060006040518060800160405280868152602001858152602001600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166304bde4dd86600001516040518263ffffffff1660e01b815260040161181f919061419d565b60006040518083038186803b15801561183757600080fd5b505afa15801561184b573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906118749190613568565b815260200161188285611eba565b8152509050736e924ee093a1b626a01c699760fd51e1e25550e66392ba0e90600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b81526004016118e29291906140ac565b60006040518083038186803b1580156118fa57600080fd5b505af415801561190e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906119379190613568565b9150509392505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61196f6128a1565b600260149054906101000a900460ff16156119bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119b690614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638bd54c0683836040518363ffffffff1660e01b8152600401611a1c9291906141d3565b600060405180830381600087803b158015611a3657600080fd5b505af1158015611a4a573d6000803e3d6000fd5b505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611a836128a1565b600260149054906101000a900460ff1615611ad3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611aca90614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391b7916a83836040518363ffffffff1660e01b8152600401611b30929190613f68565b600060405180830381600087803b158015611b4a57600080fd5b505af1158015611b5e573d6000803e3d6000fd5b505050505050565b611b6e6128a1565b600260149054906101000a900460ff1615611bbe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bb590614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166394f3df61858585856040518563ffffffff1660e01b8152600401611c1f9493929190613fc9565b600060405180830381600087803b158015611c3957600080fd5b505af1158015611c4d573d6000803e3d6000fd5b5050505050505050565b611c5f6128a1565b600260149054906101000a900460ff1615611caf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ca690614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aa5bf7d8858585856040518563ffffffff1660e01b8152600401611d109493929190613fc9565b600060405180830381600087803b158015611d2a57600080fd5b505af1158015611d3e573d6000803e3d6000fd5b5050505050505050565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b982d1b9836040518263ffffffff1660e01b8152600401611da59190614182565b60006040518083038186803b158015611dbd57600080fd5b505afa158015611dd1573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611dfa919061344b565b9050919050565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bc2d45fe836040518263ffffffff1660e01b8152600401611e5e91906141b8565b60006040518083038186803b158015611e7657600080fd5b505afa158015611e8a573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611eb3919061344b565b9050919050565b60606000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166344cee73c84602001516040518263ffffffff1660e01b8152600401611f1d919061419d565b60006040518083038186803b158015611f3557600080fd5b505afa158015611f49573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611f72919061344b565b90506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637ca9421085604001516040518263ffffffff1660e01b8152600401611fd5919061419d565b60006040518083038186803b158015611fed57600080fd5b505afa158015612001573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061202a919061344b565b90506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a503f1386606001516040518263ffffffff1660e01b815260040161208d919061419d565b60006040518083038186803b1580156120a557600080fd5b505afa1580156120b9573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906120e2919061344b565b90506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b982d1b987608001516040518263ffffffff1660e01b8152600401612145919061419d565b60006040518083038186803b15801561215d57600080fd5b505afa158015612171573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061219a919061344b565b90506000600467ffffffffffffffff8111156121b9576121b86146c3565b5b6040519080825280602002602001820160405280156121f257816020015b6121df612d76565b8152602001906001900390816121d75790505b509050604051806040016040528086815260200161220f87612abb565b8152508160008151811061222657612225614694565b5b6020026020010181905250604051806040016040528085815260200161224b86612abb565b8152508160018151811061226257612261614694565b5b6020026020010181905250604051806040016040528084815260200161228785612abb565b8152508160028151811061229e5761229d614694565b5b602002602001018190525060405180604001604052808381526020016122c384612abb565b815250816003815181106122da576122d9614694565b5b60200260200101819052508095505050505050919050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663368013dc6040518163ffffffff1660e01b815260040160006040518083038186803b15801561235c57600080fd5b505afa158015612370573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906123999190613669565b60200151905090565b6123aa6128a1565b600260149054906101000a900460ff16156123fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123f190614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cd2b82508484846040518463ffffffff1660e01b815260040161245993929190613f31565b600060405180830381600087803b15801561247357600080fd5b505af1158015612487573d6000803e3d6000fd5b50505050505050565b600260159054906101000a900460ff1681565b6124ab6128a1565b6000600260159054906101000a900460ff1615905080600260156101000a81548160ff0219169083151502179055507f360c3d72ee193226275b842f85231c259c934e85459fed80fa68e502ffa9dbde816040516125099190613fae565b60405180910390a150565b61251c6128a1565b600260149054906101000a900460ff161561256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161256390614122565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f89382d75256b43b6826ad8d6cbd8e517eaf5e10f1ef4c8f123c9a25ac4529b55816040516125dc9190614046565b60405180910390a150565b6125ef6128a1565b600260149054906101000a900460ff161561263f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161263690614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e79c9ea68484846040518463ffffffff1660e01b815260040161269e939291906141fc565b600060405180830381600087803b1580156126b857600080fd5b505af11580156126cc573d6000803e3d6000fd5b50505050505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663222a36d06040518163ffffffff1660e01b815260040160006040518083038186803b15801561273f57600080fd5b505afa158015612753573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061277c9190613669565b60200151905090565b61278d6128a1565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156127fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016127f490614142565b60405180910390fd5b612806816129f7565b50565b6128116128a1565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166372aa4a96826040518263ffffffff1660e01b815260040161286c919061402b565b600060405180830381600087803b15801561288657600080fd5b505af115801561289a573d6000803e3d6000fd5b5050505050565b6128a9612b95565b73ffffffffffffffffffffffffffffffffffffffff166128c7611a52565b73ffffffffffffffffffffffffffffffffffffffff161461291d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161291490614162565b60405180910390fd5b565b60606000600161292e84612b9d565b01905060008167ffffffffffffffff81111561294d5761294c6146c3565b5b6040519080825280601f01601f19166020018201604052801561297f5781602001600182028036833780820191505090505b509050600082602001820190505b6001156129ec578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a85816129d6576129d5614636565b5b04945060008514156129e7576129ec565b61298d565b819350505050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bc2d45fe83600081518110612b0f57612b0e614694565b5b602001015160f81c60f81b60f81c6040518263ffffffff1660e01b8152600401612b3991906141b8565b60006040518083038186803b158015612b5157600080fd5b505afa158015612b65573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190612b8e919061344b565b9050919050565b600033905090565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612bfb577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381612bf157612bf0614636565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612c38576d04ee2d6d415b85acef81000000008381612c2e57612c2d614636565b5b0492506020810190505b662386f26fc100008310612c6757662386f26fc100008381612c5d57612c5c614636565b5b0492506010810190505b6305f5e1008310612c90576305f5e1008381612c8657612c85614636565b5b0492506008810190505b6127108310612cb5576127108381612cab57612caa614636565b5b0492506004810190505b60648310612cd85760648381612cce57612ccd614636565b5b0492506002810190505b600a8310612ce7576001810190505b80915050919050565b828054612cfc906145d3565b90600052602060002090601f016020900481019282612d1e5760008555612d65565b82601f10612d3757803560ff1916838001178555612d65565b82800160010185558215612d65579182015b82811115612d64578235825591602001919060010190612d49565b5b509050612d729190612d90565b5090565b604051806040016040528060608152602001606081525090565b5b80821115612da9576000816000905550600101612d91565b5090565b6000612dc0612dbb84614253565b61422e565b90508083825260208201905082856060860282011115612de357612de2614710565b5b60005b85811015612e135781612df98882613106565b845260208401935060608301925050600181019050612de6565b5050509392505050565b6000612e30612e2b8461427f565b61422e565b905082815260208101848484011115612e4c57612e4b614715565b5b612e578482856145a0565b509392505050565b6000612e72612e6d846142b0565b61422e565b905082815260208101848484011115612e8e57612e8d614715565b5b612e99848285614591565b509392505050565b6000612eb4612eaf846142b0565b61422e565b905082815260208101848484011115612ed057612ecf614715565b5b612edb8482856145a0565b509392505050565b600081359050612ef28161482d565b92915050565b600081519050612f078161482d565b92915050565b60008083601f840112612f2357612f226146fc565b5b8235905067ffffffffffffffff811115612f4057612f3f6146f7565b5b602083019150836020820283011115612f5c57612f5b614710565b5b9250929050565b600082601f830112612f7857612f776146fc565b5b8151612f88848260208601612dad565b91505092915050565b60008083601f840112612fa757612fa66146fc565b5b8235905067ffffffffffffffff811115612fc457612fc36146f7565b5b602083019150836001820283011115612fe057612fdf614710565b5b9250929050565b600082601f830112612ffc57612ffb6146fc565b5b815161300c848260208601612e1d565b91505092915050565b60008135905061302481614844565b92915050565b6000813590506130398161485b565b92915050565b60008135905061304e81614872565b92915050565b60008083601f84011261306a576130696146fc565b5b8235905067ffffffffffffffff811115613087576130866146f7565b5b6020830191508360018202830111156130a3576130a2614710565b5b9250929050565b600082601f8301126130bf576130be6146fc565b5b81356130cf848260208601612e5f565b91505092915050565b600082601f8301126130ed576130ec6146fc565b5b81516130fd848260208601612ea1565b91505092915050565b60006060828403121561311c5761311b614701565b5b613126606061422e565b9050600061313684828501613277565b600083015250602061314a848285016132f5565b602083015250604061315e84828501612ef8565b60408301525092915050565b600060a082840312156131805761317f614701565b5b61318a60a061422e565b9050600061319a848285016132b6565b60008301525060206131ae848285016132b6565b60208301525060406131c2848285016132b6565b60408301525060606131d6848285016132b6565b60608301525060806131ea848285016132b6565b60808301525092915050565b60006040828403121561320c5761320b614701565b5b613216604061422e565b9050600082015167ffffffffffffffff8111156132365761323561470b565b5b61324284828501612f63565b6000830152506020613256848285016132a1565b60208301525092915050565b60008135905061327181614889565b92915050565b60008151905061328681614889565b92915050565b60008135905061329b816148a0565b92915050565b6000815190506132b0816148a0565b92915050565b6000813590506132c5816148b7565b92915050565b6000813590506132da816148ce565b92915050565b6000813590506132ef816148e5565b92915050565b600081519050613304816148e5565b92915050565b6000602082840312156133205761331f614724565b5b600061332e84828501612ee3565b91505092915050565b6000806000606084860312156133505761334f614724565b5b600061335e86828701612ee3565b935050602061336f868287016132e0565b925050604061338086828701613262565b9150509250925092565b600080602083850312156133a1576133a0614724565b5b600083013567ffffffffffffffff8111156133bf576133be61471a565b5b6133cb85828601612f0d565b92509250509250929050565b600080600080606085870312156133f1576133f0614724565b5b600085013567ffffffffffffffff81111561340f5761340e61471a565b5b61341b87828801612f91565b9450945050602061342e878288016132e0565b925050604061343f87828801613262565b91505092959194509250565b60006020828403121561346157613460614724565b5b600082015167ffffffffffffffff81111561347f5761347e61471a565b5b61348b84828501612fe7565b91505092915050565b6000602082840312156134aa576134a9614724565b5b60006134b884828501613015565b91505092915050565b6000602082840312156134d7576134d6614724565b5b60006134e58482850161302a565b91505092915050565b60006020828403121561350457613503614724565b5b60006135128482850161303f565b91505092915050565b6000806020838503121561353257613531614724565b5b600083013567ffffffffffffffff8111156135505761354f61471a565b5b61355c85828601613054565b92509250509250929050565b60006020828403121561357e5761357d614724565b5b600082015167ffffffffffffffff81111561359c5761359b61471a565b5b6135a8848285016130d8565b91505092915050565b600080600060e084860312156135ca576135c9614724565b5b600084013567ffffffffffffffff8111156135e8576135e761471a565b5b6135f4868287016130aa565b935050602084013567ffffffffffffffff8111156136155761361461471a565b5b613621868287016130aa565b92505060406136328682870161316a565b9150509250925092565b600060a0828403121561365257613651614724565b5b60006136608482850161316a565b91505092915050565b60006020828403121561367f5761367e614724565b5b600082015167ffffffffffffffff81111561369d5761369c61471a565b5b6136a9848285016131f6565b91505092915050565b6000602082840312156136c8576136c7614724565b5b60006136d68482850161328c565b91505092915050565b6000602082840312156136f5576136f4614724565b5b6000613703848285016132a1565b91505092915050565b60008060c0838503121561372357613722614724565b5b60006137318582860161328c565b92505060206137428582860161316a565b9150509250929050565b60006020828403121561376257613761614724565b5b6000613770848285016132cb565b91505092915050565b600080604083850312156137905761378f614724565b5b600061379e858286016132cb565b92505060206137af85828601612ee3565b9150509250929050565b6000806000604084860312156137d2576137d1614724565b5b60006137e0868287016132cb565b935050602084013567ffffffffffffffff8111156138015761380061471a565b5b61380d86828701612f91565b92509250509250925092565b6000613826848484613ae9565b90509392505050565b600061383b8383613d14565b905092915050565b600061384f8383613d58565b905092915050565b61386081614452565b82525050565b6000613872838561434b565b935083602084028501613884846142e1565b8060005b878110156138ca57848403895261389f82846143ef565b6138aa868284613819565b95506138b584614331565b935060208b019a505050600181019050613888565b50829750879450505050509392505050565b60006138e782614310565b6138f1818561435c565b935083602082028501613903856142eb565b8060005b8581101561393f5784840389528151613920858261382f565b945061392b8361433e565b925060208a01995050600181019050613907565b50829750879550505050505092915050565b600061395c82614310565b613966818561436d565b935083602082028501613978856142eb565b8060005b858110156139b457848403895281516139958582613843565b94506139a08361433e565b925060208a0199505060018101905061397c565b50829750879550505050505092915050565b6139cf81614464565b82525050565b60006139e1838561438f565b93506139ee838584614591565b6139f783614729565b840190509392505050565b6000613a0d8261431b565b613a17818561437e565b9350613a278185602086016145a0565b613a3081614729565b840191505092915050565b6000613a468261431b565b613a50818561438f565b9350613a608185602086016145a0565b613a6981614729565b840191505092915050565b6000613a7f8261431b565b613a8981856143a0565b9350613a998185602086016145a0565b613aa281614729565b840191505092915050565b613ab681614513565b82525050565b613ac581614537565b82525050565b613ad48161455b565b82525050565b613ae38161455b565b82525050565b6000613af583856143b1565b9350613b02838584614591565b613b0b83614729565b840190509392505050565b6000613b2283856143c2565b9350613b2f838584614591565b613b3883614729565b840190509392505050565b6000613b4e82614326565b613b5881856143c2565b9350613b688185602086016145a0565b613b7181614729565b840191505092915050565b6000613b8782614326565b613b9181856143d3565b9350613ba18185602086016145a0565b613baa81614729565b840191505092915050565b6000613bc082614326565b613bca81856143e4565b9350613bda8185602086016145a0565b80840191505092915050565b60008154613bf3816145d3565b613bfd81866143e4565b94506001821660008114613c185760018114613c2957613c5c565b60ff19831686528186019350613c5c565b613c32856142fb565b60005b83811015613c5457815481890152600182019150602081019050613c35565b838801955050505b50505092915050565b6000613c726010836143c2565b9150613c7d8261473a565b602082019050919050565b6000613c956026836143c2565b9150613ca082614763565b604082019050919050565b6000613cb86005836143e4565b9150613cc3826147b2565b600582019050919050565b6000613cdb6020836143c2565b9150613ce6826147db565b602082019050919050565b6000613cfe601d836143e4565b9150613d0982614804565b601d82019050919050565b60006040830160008301518482036000860152613d318282613a02565b91505060208301518482036020860152613d4b8282613a02565b9150508091505092915050565b60006040830160008301518482036000860152613d758282613a74565b91505060208301518482036020860152613d8f8282613a74565b9150508091505092915050565b60006040830160008301518482036000860152613db98282613951565b91505060208301518482036020860152613dd38282613b7c565b9150508091505092915050565b60006080830160008301518482036000860152613dfd8282613b7c565b91505060208301518482036020860152613e178282613b7c565b91505060408301518482036040860152613e318282613b7c565b91505060608301518482036060860152613e4b8282613951565b9150508091505092915050565b613e61816144a6565b82525050565b613e70816144d4565b82525050565b613e7f8161457f565b82525050565b613e8e816144fd565b82525050565b613e9d816144f0565b82525050565b6000613eaf8285613be6565b9150613ebb8284613bb5565b91508190509392505050565b6000613ed282613cab565b9150613ede8284613bb5565b915081905092915050565b6000613ef482613cab565b9150613f008284613bb5565b9150613f0b82613cf1565b915081905092915050565b6000602082019050613f2b6000830184613857565b92915050565b6000606082019050613f466000830186613857565b613f536020830185613e85565b613f606040830184613e58565b949350505050565b60006020820190508181036000830152613f83818486613866565b90509392505050565b60006020820190508181036000830152613fa681846138dc565b905092915050565b6000602082019050613fc360008301846139c6565b92915050565b60006060820190508181036000830152613fe48186886139d5565b9050613ff36020830185613e85565b6140006040830184613e58565b95945050505050565b600060208201905081810360008301526140238184613a3b565b905092915050565b60006020820190506140406000830184613aad565b92915050565b600060208201905061405b6000830184613abc565b92915050565b60006020820190506140766000830184613acb565b92915050565b60006040820190506140916000830185613ada565b81810360208301526140a38184613d9c565b90509392505050565b60006040820190506140c16000830185613ada565b81810360208301526140d38184613de0565b90509392505050565b600060208201905081810360008301526140f7818486613b16565b90509392505050565b6000602082019050818103600083015261411a8184613b43565b905092915050565b6000602082019050818103600083015261413b81613c65565b9050919050565b6000602082019050818103600083015261415b81613c88565b9050919050565b6000602082019050818103600083015261417b81613cce565b9050919050565b60006020820190506141976000830184613e67565b92915050565b60006020820190506141b26000830184613e76565b92915050565b60006020820190506141cd6000830184613e94565b92915050565b60006040820190506141e86000830185613e94565b6141f56020830184613857565b9392505050565b60006040820190506142116000830186613e94565b81810360208301526142248184866139d5565b9050949350505050565b6000614238614249565b90506142448282614605565b919050565b6000604051905090565b600067ffffffffffffffff82111561426e5761426d6146c3565b5b602082029050602081019050919050565b600067ffffffffffffffff82111561429a576142996146c3565b5b6142a382614729565b9050602081019050919050565b600067ffffffffffffffff8211156142cb576142ca6146c3565b5b6142d482614729565b9050602081019050919050565b6000819050919050565b6000819050602082019050919050565b60008190508160005260206000209050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b6000808335600160200384360303811261440c5761440b61471f565b5b83810192508235915060208301925067ffffffffffffffff821115614434576144336146f2565b5b60018202360384131561444a57614449614706565b5b509250929050565b600061445d826144b4565b9050919050565b60008115159050919050565b600061447b82614452565b9050919050565b600061448d82614452565b9050919050565b600061449f82614452565b9050919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600065ffffffffffff82169050919050565b600060ff82169050919050565b600069ffffffffffffffffffff82169050919050565b600061451e82614525565b9050919050565b6000614530826144b4565b9050919050565b600061454282614549565b9050919050565b6000614554826144b4565b9050919050565b60006145668261456d565b9050919050565b6000614578826144b4565b9050919050565b600061458a826144de565b9050919050565b82818337600083830152505050565b60005b838110156145be5780820151818401526020810190506145a3565b838111156145cd576000848401525b50505050565b600060028204905060018216806145eb57607f821691505b602082108114156145ff576145fe614665565b5b50919050565b61460e82614729565b810181811067ffffffffffffffff8211171561462d5761462c6146c3565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f506172747320617265206c6f636b656400000000000000000000000000000000600082015250565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b7f4e6f756e20000000000000000000000000000000000000000000000000000000600082015250565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b7f2069732061206d656d626572206f6620746865204e6f756e732044414f000000600082015250565b61483681614452565b811461484157600080fd5b50565b61484d81614470565b811461485857600080fd5b50565b61486481614482565b811461486f57600080fd5b50565b61487b81614494565b811461488657600080fd5b50565b614892816144a6565b811461489d57600080fd5b50565b6148a9816144d4565b81146148b457600080fd5b50565b6148c0816144de565b81146148cb57600080fd5b50565b6148d7816144f0565b81146148e257600080fd5b50565b6148ee816144fd565b81146148f957600080fd5b5056fea26469706673582212205befd001c240aad6f4c4f537c3550cf48cb964091b1be60f8258a541e7baddb964736f6c6343000806003300000000000000000000000034ea9b587dd98b7f84541a55c27b5a6cba6b815c0000000000000000000000006ccef0d7ec1e2530af733a00b800e5cf41cb3d62

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106102695760003560e01c806373ac736b11610151578063bc2d45fe116100c3578063dfe8478b11610087578063dfe8478b14610746578063e6b1a3ae14610750578063e79c9ea61461076c578063eba8180614610788578063f2fde38b146107a6578063f4513a6a146107c257610269565b8063bc2d45fe1461068e578063bf61df1b146106be578063cc2aa091146106ee578063cd2b82501461070c578063ce2f4f531461072857610269565b80638bd54c06116101155780638bd54c06146105d05780638da5cb5b146105ec57806391b7916a1461060a57806394f3df6114610626578063aa5bf7d814610642578063b982d1b91461065e57610269565b806373ac736b14610518578063773b9771146105345780637ca942101461055257806387db11bd146105825780638ada6b0f146105b257610269565b80634531c0a8116101ea5780635a503f13116101ae5780635a503f13146104585780635e70664c14610488578063638ac270146104a45780636c0360eb146104d45780636e856531146104f2578063715018a61461050e57610269565b80634531c0a8146103c8578063461fc5af146103e65780634daebac21461040257806355f804b31461042057806356d3163d1461043c57610269565b8063301bd28e11610231578063301bd28e14610310578063353c36a01461032e5780633cfdafd31461034a5780634479cef21461037a57806344cee73c1461039857610269565b8063010ecde71461026e57806304bde4dd1461028a5780630ba3db1a146102ba5780632a1d0769146102d65780632ea04300146102e0575b600080fd5b6102886004803603810190610283919061330a565b6107de565b005b6102a4600480360381019061029f91906136b2565b610876565b6040516102b19190614100565b60405180910390f35b6102d460048036038101906102cf91906133d7565b61092f565b005b6102de610a20565b005b6102fa60048036038101906102f5919061363c565b610ac1565b6040516103079190614100565b60405180910390f35b610318610c4f565b6040516103259190614046565b60405180910390f35b610348600480360381019061034391906133d7565b610c75565b005b610364600480360381019061035f919061370c565b610d66565b6040516103719190614100565b60405180910390f35b610382610dc2565b60405161038f9190614182565b60405180910390f35b6103b260048036038101906103ad91906136b2565b610e72565b6040516103bf9190614009565b60405180910390f35b6103d0610f2b565b6040516103dd9190614182565b60405180910390f35b61040060048036038101906103fb9190613337565b610fd2565b005b61040a6110c0565b6040516104179190614182565b60405180910390f35b61043a6004803603810190610435919061351b565b611170565b005b610456600480360381019061045191906134ee565b6111c7565b005b610472600480360381019061046d91906136b2565b61124a565b60405161047f9190614009565b60405180910390f35b6104a2600480360381019061049d919061351b565b611303565b005b6104be60048036038101906104b9919061370c565b6113ee565b6040516104cb9190614100565b60405180910390f35b6104dc61145b565b6040516104e99190614100565b60405180910390f35b61050c60048036038101906105079190613337565b6114e9565b005b6105166115d7565b005b610532600480360381019061052d9190613337565b6115eb565b005b61053c6116d9565b6040516105499190613fae565b60405180910390f35b61056c600480360381019061056791906136b2565b6116ec565b6040516105799190614009565b60405180910390f35b61059c600480360381019061059791906135b1565b6117a5565b6040516105a99190614100565b60405180910390f35b6105ba611941565b6040516105c79190614061565b60405180910390f35b6105ea60048036038101906105e59190613779565b611967565b005b6105f4611a52565b6040516106019190613f16565b60405180910390f35b610624600480360381019061061f919061338a565b611a7b565b005b610640600480360381019061063b91906133d7565b611b66565b005b61065c600480360381019061065791906133d7565b611c57565b005b610678600480360381019061067391906136b2565b611d48565b6040516106859190614009565b60405180910390f35b6106a860048036038101906106a3919061374c565b611e01565b6040516106b59190614009565b60405180910390f35b6106d860048036038101906106d3919061363c565b611eba565b6040516106e59190613f8c565b60405180910390f35b6106f66122f2565b6040516107039190614182565b60405180910390f35b61072660048036038101906107219190613337565b6123a2565b005b610730612490565b60405161073d9190613fae565b60405180910390f35b61074e6124a3565b005b61076a600480360381019061076591906134c1565b612514565b005b610786600480360381019061078191906137b9565b6125e7565b005b6107906126d5565b60405161079d9190614182565b60405180910390f35b6107c060048036038101906107bb919061330a565b612785565b005b6107dc60048036038101906107d79190613494565b612809565b005b6107e66128a1565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166301b9a397826040518263ffffffff1660e01b81526004016108419190613f16565b600060405180830381600087803b15801561085b57600080fd5b505af115801561086f573d6000803e3d6000fd5b5050505050565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166304bde4dd836040518263ffffffff1660e01b81526004016108d39190614182565b60006040518083038186803b1580156108eb57600080fd5b505afa1580156108ff573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906109289190613568565b9050919050565b6109376128a1565b600260149054906101000a900460ff1615610987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097e90614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630ba3db1a858585856040518563ffffffff1660e01b81526004016109e89493929190613fc9565b600060405180830381600087803b158015610a0257600080fd5b505af1158015610a16573d6000803e3d6000fd5b5050505050505050565b610a286128a1565b600260149054906101000a900460ff1615610a78576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a6f90614122565b60405180910390fd5b6001600260146101000a81548160ff0219169083151502179055507f1680ee6d421f70ed6030d2fc4fcb50217a5dd617858d56562b119eca59172e5760405160405180910390a1565b606060006040518060400160405280610ad985611eba565b8152602001600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166304bde4dd86600001516040518263ffffffff1660e01b8152600401610b3d919061419d565b60006040518083038186803b158015610b5557600080fd5b505afa158015610b69573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610b929190613568565b8152509050736e924ee093a1b626a01c699760fd51e1e25550e66322cc1ad6600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401610bf292919061407c565b60006040518083038186803b158015610c0a57600080fd5b505af4158015610c1e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610c479190613568565b915050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610c7d6128a1565b600260149054906101000a900460ff1615610ccd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc490614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663353c36a0858585856040518563ffffffff1660e01b8152600401610d2e9493929190613fc9565b600060405180830381600087803b158015610d4857600080fd5b505af1158015610d5c573d6000803e3d6000fd5b5050505050505050565b6060600260159054906101000a900460ff1615610d8e57610d8783836113ee565b9050610dbc565b6003610d998461291f565b604051602001610daa929190613ea3565b60405160208183030381529060405290505b92915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e73dd3836040518163ffffffff1660e01b815260040160006040518083038186803b158015610e2c57600080fd5b505afa158015610e40573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610e699190613669565b60200151905090565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166344cee73c836040518263ffffffff1660e01b8152600401610ecf9190614182565b60006040518083038186803b158015610ee757600080fd5b505afa158015610efb573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610f24919061344b565b9050919050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fd30704b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f9557600080fd5b505afa158015610fa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcd91906136df565b905090565b610fda6128a1565b600260149054906101000a900460ff161561102a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102190614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663461fc5af8484846040518463ffffffff1660e01b815260040161108993929190613f31565b600060405180830381600087803b1580156110a357600080fd5b505af11580156110b7573d6000803e3d6000fd5b50505050505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c64b2f5d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561112a57600080fd5b505afa15801561113e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906111679190613669565b60200151905090565b6111786128a1565b818160039190611189929190612cf0565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad82826040516111bb9291906140dc565b60405180910390a15050565b6111cf6128a1565b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f482cbbbcf912da3be80deb8503ae1e94c0b7d5d1d0ec0af3d9d6403e06e609ee8160405161123f9190614061565b60405180910390a150565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a503f13836040518263ffffffff1660e01b81526004016112a79190614182565b60006040518083038186803b1580156112bf57600080fd5b505afa1580156112d3573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906112fc919061344b565b9050919050565b61130b6128a1565b600260149054906101000a900460ff161561135b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161135290614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635e70664c83836040518363ffffffff1660e01b81526004016113b89291906140dc565b600060405180830381600087803b1580156113d257600080fd5b505af11580156113e6573d6000803e3d6000fd5b505050505050565b606060006113fb8461291f565b90506000816040516020016114109190613ec7565b60405160208183030381529060405290506000826040516020016114349190613ee9565b60405160208183030381529060405290506114508282876117a5565b935050505092915050565b60038054611468906145d3565b80601f0160208091040260200160405190810160405280929190818152602001828054611494906145d3565b80156114e15780601f106114b6576101008083540402835291602001916114e1565b820191906000526020600020905b8154815290600101906020018083116114c457829003601f168201915b505050505081565b6114f16128a1565b600260149054906101000a900460ff1615611541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161153890614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636e8565318484846040518463ffffffff1660e01b81526004016115a093929190613f31565b600060405180830381600087803b1580156115ba57600080fd5b505af11580156115ce573d6000803e3d6000fd5b50505050505050565b6115df6128a1565b6115e960006129f7565b565b6115f36128a1565b600260149054906101000a900460ff1615611643576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161163a90614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166373ac736b8484846040518463ffffffff1660e01b81526004016116a293929190613f31565b600060405180830381600087803b1580156116bc57600080fd5b505af11580156116d0573d6000803e3d6000fd5b50505050505050565b600260149054906101000a900460ff1681565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637ca94210836040518263ffffffff1660e01b81526004016117499190614182565b60006040518083038186803b15801561176157600080fd5b505afa158015611775573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061179e919061344b565b9050919050565b606060006040518060800160405280868152602001858152602001600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166304bde4dd86600001516040518263ffffffff1660e01b815260040161181f919061419d565b60006040518083038186803b15801561183757600080fd5b505afa15801561184b573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906118749190613568565b815260200161188285611eba565b8152509050736e924ee093a1b626a01c699760fd51e1e25550e66392ba0e90600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b81526004016118e29291906140ac565b60006040518083038186803b1580156118fa57600080fd5b505af415801561190e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906119379190613568565b9150509392505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61196f6128a1565b600260149054906101000a900460ff16156119bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119b690614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638bd54c0683836040518363ffffffff1660e01b8152600401611a1c9291906141d3565b600060405180830381600087803b158015611a3657600080fd5b505af1158015611a4a573d6000803e3d6000fd5b505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611a836128a1565b600260149054906101000a900460ff1615611ad3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611aca90614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391b7916a83836040518363ffffffff1660e01b8152600401611b30929190613f68565b600060405180830381600087803b158015611b4a57600080fd5b505af1158015611b5e573d6000803e3d6000fd5b505050505050565b611b6e6128a1565b600260149054906101000a900460ff1615611bbe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bb590614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166394f3df61858585856040518563ffffffff1660e01b8152600401611c1f9493929190613fc9565b600060405180830381600087803b158015611c3957600080fd5b505af1158015611c4d573d6000803e3d6000fd5b5050505050505050565b611c5f6128a1565b600260149054906101000a900460ff1615611caf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ca690614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aa5bf7d8858585856040518563ffffffff1660e01b8152600401611d109493929190613fc9565b600060405180830381600087803b158015611d2a57600080fd5b505af1158015611d3e573d6000803e3d6000fd5b5050505050505050565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b982d1b9836040518263ffffffff1660e01b8152600401611da59190614182565b60006040518083038186803b158015611dbd57600080fd5b505afa158015611dd1573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611dfa919061344b565b9050919050565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bc2d45fe836040518263ffffffff1660e01b8152600401611e5e91906141b8565b60006040518083038186803b158015611e7657600080fd5b505afa158015611e8a573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611eb3919061344b565b9050919050565b60606000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166344cee73c84602001516040518263ffffffff1660e01b8152600401611f1d919061419d565b60006040518083038186803b158015611f3557600080fd5b505afa158015611f49573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611f72919061344b565b90506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637ca9421085604001516040518263ffffffff1660e01b8152600401611fd5919061419d565b60006040518083038186803b158015611fed57600080fd5b505afa158015612001573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061202a919061344b565b90506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a503f1386606001516040518263ffffffff1660e01b815260040161208d919061419d565b60006040518083038186803b1580156120a557600080fd5b505afa1580156120b9573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906120e2919061344b565b90506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b982d1b987608001516040518263ffffffff1660e01b8152600401612145919061419d565b60006040518083038186803b15801561215d57600080fd5b505afa158015612171573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061219a919061344b565b90506000600467ffffffffffffffff8111156121b9576121b86146c3565b5b6040519080825280602002602001820160405280156121f257816020015b6121df612d76565b8152602001906001900390816121d75790505b509050604051806040016040528086815260200161220f87612abb565b8152508160008151811061222657612225614694565b5b6020026020010181905250604051806040016040528085815260200161224b86612abb565b8152508160018151811061226257612261614694565b5b6020026020010181905250604051806040016040528084815260200161228785612abb565b8152508160028151811061229e5761229d614694565b5b602002602001018190525060405180604001604052808381526020016122c384612abb565b815250816003815181106122da576122d9614694565b5b60200260200101819052508095505050505050919050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663368013dc6040518163ffffffff1660e01b815260040160006040518083038186803b15801561235c57600080fd5b505afa158015612370573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906123999190613669565b60200151905090565b6123aa6128a1565b600260149054906101000a900460ff16156123fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123f190614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cd2b82508484846040518463ffffffff1660e01b815260040161245993929190613f31565b600060405180830381600087803b15801561247357600080fd5b505af1158015612487573d6000803e3d6000fd5b50505050505050565b600260159054906101000a900460ff1681565b6124ab6128a1565b6000600260159054906101000a900460ff1615905080600260156101000a81548160ff0219169083151502179055507f360c3d72ee193226275b842f85231c259c934e85459fed80fa68e502ffa9dbde816040516125099190613fae565b60405180910390a150565b61251c6128a1565b600260149054906101000a900460ff161561256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161256390614122565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f89382d75256b43b6826ad8d6cbd8e517eaf5e10f1ef4c8f123c9a25ac4529b55816040516125dc9190614046565b60405180910390a150565b6125ef6128a1565b600260149054906101000a900460ff161561263f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161263690614122565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e79c9ea68484846040518463ffffffff1660e01b815260040161269e939291906141fc565b600060405180830381600087803b1580156126b857600080fd5b505af11580156126cc573d6000803e3d6000fd5b50505050505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663222a36d06040518163ffffffff1660e01b815260040160006040518083038186803b15801561273f57600080fd5b505afa158015612753573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061277c9190613669565b60200151905090565b61278d6128a1565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156127fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016127f490614142565b60405180910390fd5b612806816129f7565b50565b6128116128a1565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166372aa4a96826040518263ffffffff1660e01b815260040161286c919061402b565b600060405180830381600087803b15801561288657600080fd5b505af115801561289a573d6000803e3d6000fd5b5050505050565b6128a9612b95565b73ffffffffffffffffffffffffffffffffffffffff166128c7611a52565b73ffffffffffffffffffffffffffffffffffffffff161461291d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161291490614162565b60405180910390fd5b565b60606000600161292e84612b9d565b01905060008167ffffffffffffffff81111561294d5761294c6146c3565b5b6040519080825280601f01601f19166020018201604052801561297f5781602001600182028036833780820191505090505b509050600082602001820190505b6001156129ec578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a85816129d6576129d5614636565b5b04945060008514156129e7576129ec565b61298d565b819350505050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bc2d45fe83600081518110612b0f57612b0e614694565b5b602001015160f81c60f81b60f81c6040518263ffffffff1660e01b8152600401612b3991906141b8565b60006040518083038186803b158015612b5157600080fd5b505afa158015612b65573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190612b8e919061344b565b9050919050565b600033905090565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612bfb577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381612bf157612bf0614636565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612c38576d04ee2d6d415b85acef81000000008381612c2e57612c2d614636565b5b0492506020810190505b662386f26fc100008310612c6757662386f26fc100008381612c5d57612c5c614636565b5b0492506010810190505b6305f5e1008310612c90576305f5e1008381612c8657612c85614636565b5b0492506008810190505b6127108310612cb5576127108381612cab57612caa614636565b5b0492506004810190505b60648310612cd85760648381612cce57612ccd614636565b5b0492506002810190505b600a8310612ce7576001810190505b80915050919050565b828054612cfc906145d3565b90600052602060002090601f016020900481019282612d1e5760008555612d65565b82601f10612d3757803560ff1916838001178555612d65565b82800160010185558215612d65579182015b82811115612d64578235825591602001919060010190612d49565b5b509050612d729190612d90565b5090565b604051806040016040528060608152602001606081525090565b5b80821115612da9576000816000905550600101612d91565b5090565b6000612dc0612dbb84614253565b61422e565b90508083825260208201905082856060860282011115612de357612de2614710565b5b60005b85811015612e135781612df98882613106565b845260208401935060608301925050600181019050612de6565b5050509392505050565b6000612e30612e2b8461427f565b61422e565b905082815260208101848484011115612e4c57612e4b614715565b5b612e578482856145a0565b509392505050565b6000612e72612e6d846142b0565b61422e565b905082815260208101848484011115612e8e57612e8d614715565b5b612e99848285614591565b509392505050565b6000612eb4612eaf846142b0565b61422e565b905082815260208101848484011115612ed057612ecf614715565b5b612edb8482856145a0565b509392505050565b600081359050612ef28161482d565b92915050565b600081519050612f078161482d565b92915050565b60008083601f840112612f2357612f226146fc565b5b8235905067ffffffffffffffff811115612f4057612f3f6146f7565b5b602083019150836020820283011115612f5c57612f5b614710565b5b9250929050565b600082601f830112612f7857612f776146fc565b5b8151612f88848260208601612dad565b91505092915050565b60008083601f840112612fa757612fa66146fc565b5b8235905067ffffffffffffffff811115612fc457612fc36146f7565b5b602083019150836001820283011115612fe057612fdf614710565b5b9250929050565b600082601f830112612ffc57612ffb6146fc565b5b815161300c848260208601612e1d565b91505092915050565b60008135905061302481614844565b92915050565b6000813590506130398161485b565b92915050565b60008135905061304e81614872565b92915050565b60008083601f84011261306a576130696146fc565b5b8235905067ffffffffffffffff811115613087576130866146f7565b5b6020830191508360018202830111156130a3576130a2614710565b5b9250929050565b600082601f8301126130bf576130be6146fc565b5b81356130cf848260208601612e5f565b91505092915050565b600082601f8301126130ed576130ec6146fc565b5b81516130fd848260208601612ea1565b91505092915050565b60006060828403121561311c5761311b614701565b5b613126606061422e565b9050600061313684828501613277565b600083015250602061314a848285016132f5565b602083015250604061315e84828501612ef8565b60408301525092915050565b600060a082840312156131805761317f614701565b5b61318a60a061422e565b9050600061319a848285016132b6565b60008301525060206131ae848285016132b6565b60208301525060406131c2848285016132b6565b60408301525060606131d6848285016132b6565b60608301525060806131ea848285016132b6565b60808301525092915050565b60006040828403121561320c5761320b614701565b5b613216604061422e565b9050600082015167ffffffffffffffff8111156132365761323561470b565b5b61324284828501612f63565b6000830152506020613256848285016132a1565b60208301525092915050565b60008135905061327181614889565b92915050565b60008151905061328681614889565b92915050565b60008135905061329b816148a0565b92915050565b6000815190506132b0816148a0565b92915050565b6000813590506132c5816148b7565b92915050565b6000813590506132da816148ce565b92915050565b6000813590506132ef816148e5565b92915050565b600081519050613304816148e5565b92915050565b6000602082840312156133205761331f614724565b5b600061332e84828501612ee3565b91505092915050565b6000806000606084860312156133505761334f614724565b5b600061335e86828701612ee3565b935050602061336f868287016132e0565b925050604061338086828701613262565b9150509250925092565b600080602083850312156133a1576133a0614724565b5b600083013567ffffffffffffffff8111156133bf576133be61471a565b5b6133cb85828601612f0d565b92509250509250929050565b600080600080606085870312156133f1576133f0614724565b5b600085013567ffffffffffffffff81111561340f5761340e61471a565b5b61341b87828801612f91565b9450945050602061342e878288016132e0565b925050604061343f87828801613262565b91505092959194509250565b60006020828403121561346157613460614724565b5b600082015167ffffffffffffffff81111561347f5761347e61471a565b5b61348b84828501612fe7565b91505092915050565b6000602082840312156134aa576134a9614724565b5b60006134b884828501613015565b91505092915050565b6000602082840312156134d7576134d6614724565b5b60006134e58482850161302a565b91505092915050565b60006020828403121561350457613503614724565b5b60006135128482850161303f565b91505092915050565b6000806020838503121561353257613531614724565b5b600083013567ffffffffffffffff8111156135505761354f61471a565b5b61355c85828601613054565b92509250509250929050565b60006020828403121561357e5761357d614724565b5b600082015167ffffffffffffffff81111561359c5761359b61471a565b5b6135a8848285016130d8565b91505092915050565b600080600060e084860312156135ca576135c9614724565b5b600084013567ffffffffffffffff8111156135e8576135e761471a565b5b6135f4868287016130aa565b935050602084013567ffffffffffffffff8111156136155761361461471a565b5b613621868287016130aa565b92505060406136328682870161316a565b9150509250925092565b600060a0828403121561365257613651614724565b5b60006136608482850161316a565b91505092915050565b60006020828403121561367f5761367e614724565b5b600082015167ffffffffffffffff81111561369d5761369c61471a565b5b6136a9848285016131f6565b91505092915050565b6000602082840312156136c8576136c7614724565b5b60006136d68482850161328c565b91505092915050565b6000602082840312156136f5576136f4614724565b5b6000613703848285016132a1565b91505092915050565b60008060c0838503121561372357613722614724565b5b60006137318582860161328c565b92505060206137428582860161316a565b9150509250929050565b60006020828403121561376257613761614724565b5b6000613770848285016132cb565b91505092915050565b600080604083850312156137905761378f614724565b5b600061379e858286016132cb565b92505060206137af85828601612ee3565b9150509250929050565b6000806000604084860312156137d2576137d1614724565b5b60006137e0868287016132cb565b935050602084013567ffffffffffffffff8111156138015761380061471a565b5b61380d86828701612f91565b92509250509250925092565b6000613826848484613ae9565b90509392505050565b600061383b8383613d14565b905092915050565b600061384f8383613d58565b905092915050565b61386081614452565b82525050565b6000613872838561434b565b935083602084028501613884846142e1565b8060005b878110156138ca57848403895261389f82846143ef565b6138aa868284613819565b95506138b584614331565b935060208b019a505050600181019050613888565b50829750879450505050509392505050565b60006138e782614310565b6138f1818561435c565b935083602082028501613903856142eb565b8060005b8581101561393f5784840389528151613920858261382f565b945061392b8361433e565b925060208a01995050600181019050613907565b50829750879550505050505092915050565b600061395c82614310565b613966818561436d565b935083602082028501613978856142eb565b8060005b858110156139b457848403895281516139958582613843565b94506139a08361433e565b925060208a0199505060018101905061397c565b50829750879550505050505092915050565b6139cf81614464565b82525050565b60006139e1838561438f565b93506139ee838584614591565b6139f783614729565b840190509392505050565b6000613a0d8261431b565b613a17818561437e565b9350613a278185602086016145a0565b613a3081614729565b840191505092915050565b6000613a468261431b565b613a50818561438f565b9350613a608185602086016145a0565b613a6981614729565b840191505092915050565b6000613a7f8261431b565b613a8981856143a0565b9350613a998185602086016145a0565b613aa281614729565b840191505092915050565b613ab681614513565b82525050565b613ac581614537565b82525050565b613ad48161455b565b82525050565b613ae38161455b565b82525050565b6000613af583856143b1565b9350613b02838584614591565b613b0b83614729565b840190509392505050565b6000613b2283856143c2565b9350613b2f838584614591565b613b3883614729565b840190509392505050565b6000613b4e82614326565b613b5881856143c2565b9350613b688185602086016145a0565b613b7181614729565b840191505092915050565b6000613b8782614326565b613b9181856143d3565b9350613ba18185602086016145a0565b613baa81614729565b840191505092915050565b6000613bc082614326565b613bca81856143e4565b9350613bda8185602086016145a0565b80840191505092915050565b60008154613bf3816145d3565b613bfd81866143e4565b94506001821660008114613c185760018114613c2957613c5c565b60ff19831686528186019350613c5c565b613c32856142fb565b60005b83811015613c5457815481890152600182019150602081019050613c35565b838801955050505b50505092915050565b6000613c726010836143c2565b9150613c7d8261473a565b602082019050919050565b6000613c956026836143c2565b9150613ca082614763565b604082019050919050565b6000613cb86005836143e4565b9150613cc3826147b2565b600582019050919050565b6000613cdb6020836143c2565b9150613ce6826147db565b602082019050919050565b6000613cfe601d836143e4565b9150613d0982614804565b601d82019050919050565b60006040830160008301518482036000860152613d318282613a02565b91505060208301518482036020860152613d4b8282613a02565b9150508091505092915050565b60006040830160008301518482036000860152613d758282613a74565b91505060208301518482036020860152613d8f8282613a74565b9150508091505092915050565b60006040830160008301518482036000860152613db98282613951565b91505060208301518482036020860152613dd38282613b7c565b9150508091505092915050565b60006080830160008301518482036000860152613dfd8282613b7c565b91505060208301518482036020860152613e178282613b7c565b91505060408301518482036040860152613e318282613b7c565b91505060608301518482036060860152613e4b8282613951565b9150508091505092915050565b613e61816144a6565b82525050565b613e70816144d4565b82525050565b613e7f8161457f565b82525050565b613e8e816144fd565b82525050565b613e9d816144f0565b82525050565b6000613eaf8285613be6565b9150613ebb8284613bb5565b91508190509392505050565b6000613ed282613cab565b9150613ede8284613bb5565b915081905092915050565b6000613ef482613cab565b9150613f008284613bb5565b9150613f0b82613cf1565b915081905092915050565b6000602082019050613f2b6000830184613857565b92915050565b6000606082019050613f466000830186613857565b613f536020830185613e85565b613f606040830184613e58565b949350505050565b60006020820190508181036000830152613f83818486613866565b90509392505050565b60006020820190508181036000830152613fa681846138dc565b905092915050565b6000602082019050613fc360008301846139c6565b92915050565b60006060820190508181036000830152613fe48186886139d5565b9050613ff36020830185613e85565b6140006040830184613e58565b95945050505050565b600060208201905081810360008301526140238184613a3b565b905092915050565b60006020820190506140406000830184613aad565b92915050565b600060208201905061405b6000830184613abc565b92915050565b60006020820190506140766000830184613acb565b92915050565b60006040820190506140916000830185613ada565b81810360208301526140a38184613d9c565b90509392505050565b60006040820190506140c16000830185613ada565b81810360208301526140d38184613de0565b90509392505050565b600060208201905081810360008301526140f7818486613b16565b90509392505050565b6000602082019050818103600083015261411a8184613b43565b905092915050565b6000602082019050818103600083015261413b81613c65565b9050919050565b6000602082019050818103600083015261415b81613c88565b9050919050565b6000602082019050818103600083015261417b81613cce565b9050919050565b60006020820190506141976000830184613e67565b92915050565b60006020820190506141b26000830184613e76565b92915050565b60006020820190506141cd6000830184613e94565b92915050565b60006040820190506141e86000830185613e94565b6141f56020830184613857565b9392505050565b60006040820190506142116000830186613e94565b81810360208301526142248184866139d5565b9050949350505050565b6000614238614249565b90506142448282614605565b919050565b6000604051905090565b600067ffffffffffffffff82111561426e5761426d6146c3565b5b602082029050602081019050919050565b600067ffffffffffffffff82111561429a576142996146c3565b5b6142a382614729565b9050602081019050919050565b600067ffffffffffffffff8211156142cb576142ca6146c3565b5b6142d482614729565b9050602081019050919050565b6000819050919050565b6000819050602082019050919050565b60008190508160005260206000209050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b6000808335600160200384360303811261440c5761440b61471f565b5b83810192508235915060208301925067ffffffffffffffff821115614434576144336146f2565b5b60018202360384131561444a57614449614706565b5b509250929050565b600061445d826144b4565b9050919050565b60008115159050919050565b600061447b82614452565b9050919050565b600061448d82614452565b9050919050565b600061449f82614452565b9050919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600065ffffffffffff82169050919050565b600060ff82169050919050565b600069ffffffffffffffffffff82169050919050565b600061451e82614525565b9050919050565b6000614530826144b4565b9050919050565b600061454282614549565b9050919050565b6000614554826144b4565b9050919050565b60006145668261456d565b9050919050565b6000614578826144b4565b9050919050565b600061458a826144de565b9050919050565b82818337600083830152505050565b60005b838110156145be5780820151818401526020810190506145a3565b838111156145cd576000848401525b50505050565b600060028204905060018216806145eb57607f821691505b602082108114156145ff576145fe614665565b5b50919050565b61460e82614729565b810181811067ffffffffffffffff8211171561462d5761462c6146c3565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f506172747320617265206c6f636b656400000000000000000000000000000000600082015250565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b7f4e6f756e20000000000000000000000000000000000000000000000000000000600082015250565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b7f2069732061206d656d626572206f6620746865204e6f756e732044414f000000600082015250565b61483681614452565b811461484157600080fd5b50565b61484d81614470565b811461485857600080fd5b50565b61486481614482565b811461486f57600080fd5b50565b61487b81614494565b811461488657600080fd5b50565b614892816144a6565b811461489d57600080fd5b50565b6148a9816144d4565b81146148b457600080fd5b50565b6148c0816144de565b81146148cb57600080fd5b50565b6148d7816144f0565b81146148e257600080fd5b50565b6148ee816144fd565b81146148f957600080fd5b5056fea26469706673582212205befd001c240aad6f4c4f537c3550cf48cb964091b1be60f8258a541e7baddb964736f6c63430008060033