false
true
0

Contract Address Details

0x5a28EEF0eD8cCe44CDa9d7097ecCE041bb51B9D4

Contract Name
MetadataRenderer
Creator
0xee5db9–7c06ae at 0xb3cc29–9bf985
Balance
( )
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
17232758
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
MetadataRenderer




Optimization enabled
true
Compiler version
v0.8.16+commit.07a7930e




Optimization runs
500000
EVM Version
london




Verified at
2026-04-25T23:21:22.495097Z

Constructor Arguments

000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da7174

Arg [0] (address) : 0xd310a3041dfcf14def5ccbc508668974b5da7174

              

src/token/metadata/MetadataRenderer.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { Base64 } from "@openzeppelin/contracts/utils/Base64.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { UriEncode } from "sol-uriencode/src/UriEncode.sol";
import { MetadataBuilder } from "micro-onchain-metadata-utils/MetadataBuilder.sol";
import { MetadataJSONKeys } from "micro-onchain-metadata-utils/MetadataJSONKeys.sol";

import { UUPS } from "../../lib/proxy/UUPS.sol";
import { Initializable } from "../../lib/utils/Initializable.sol";
import { IOwnable } from "../../lib/interfaces/IOwnable.sol";
import { ERC721 } from "../../lib/token/ERC721.sol";

import { MetadataRendererStorageV1 } from "./storage/MetadataRendererStorageV1.sol";
import { MetadataRendererStorageV2 } from "./storage/MetadataRendererStorageV2.sol";
import { IToken } from "../../token/IToken.sol";
import { IPropertyIPFSMetadataRenderer } from "./interfaces/IPropertyIPFSMetadataRenderer.sol";
import { IManager } from "../../manager/IManager.sol";
import { VersionedContract } from "../../VersionedContract.sol";

/// @title Metadata Renderer
/// @author Iain Nash & Rohan Kulkarni
/// @notice A DAO's artwork generator and renderer
/// @custom:repo github.com/ourzora/nouns-protocol 
contract MetadataRenderer is
    IPropertyIPFSMetadataRenderer,
    VersionedContract,
    Initializable,
    UUPS,
    MetadataRendererStorageV1,
    MetadataRendererStorageV2
{
    ///                                                          ///
    ///                          IMMUTABLES                      ///
    ///                                                          ///

    /// @notice The contract upgrade manager
    IManager private immutable manager;

    ///                                                          ///
    ///                          MODIFIERS                       ///
    ///                                                          ///

    /// @notice Checks the token owner if the current action is allowed
    modifier onlyOwner() {
        if (owner() != msg.sender) {
            revert IOwnable.ONLY_OWNER();
        }

        _;
    }

    ///                                                          ///
    ///                          CONSTRUCTOR                     ///
    ///                                                          ///

    /// @param _manager The contract upgrade manager address
    constructor(address _manager) payable initializer {
        manager = IManager(_manager);
    }

    ///                                                          ///
    ///                          INITIALIZER                     ///
    ///                                                          ///

    /// @notice Initializes a DAO's token metadata renderer
    /// @param _initStrings The encoded token and metadata initialization strings
    /// @param _token The ERC-721 token address
    function initialize(bytes calldata _initStrings, address _token) external initializer {
        // Ensure the caller is the contract manager
        if (msg.sender != address(manager)) {
            revert ONLY_MANAGER();
        }

        // Decode the token initialization strings
        (, , string memory _description, string memory _contractImage, string memory _projectURI, string memory _rendererBase) = abi.decode(
            _initStrings,
            (string, string, string, string, string, string)
        );

        // Store the renderer settings
        settings.projectURI = _projectURI;
        settings.description = _description;
        settings.contractImage = _contractImage;
        settings.rendererBase = _rendererBase;
        settings.projectURI = _projectURI;
        settings.token = _token;
    }

    ///                                                          ///
    ///                     PROPERTIES & ITEMS                   ///
    ///                                                          ///

    /// @notice The number of properties
    /// @return properties array length
    function propertiesCount() external view returns (uint256) {
        return properties.length;
    }

    /// @notice The number of items in a property
    /// @param _propertyId The property id
    /// @return items array length
    function itemsCount(uint256 _propertyId) external view returns (uint256) {
        return properties[_propertyId].items.length;
    }

    /// @notice The number of items in the IPFS data store
    /// @return ipfs data array size
    function ipfsDataCount() external view returns (uint256) {
        return ipfsData.length;
    }

    /// @notice Updates the additional token properties associated with the metadata.
    /// @dev Be careful to not conflict with already used keys such as "name", "description", "properties",
    function setAdditionalTokenProperties(AdditionalTokenProperty[] memory _additionalTokenProperties) external onlyOwner {
        delete additionalTokenProperties;
        for (uint256 i = 0; i < _additionalTokenProperties.length; i++) {
            additionalTokenProperties.push(_additionalTokenProperties[i]);
        }

        emit AdditionalTokenPropertiesSet(_additionalTokenProperties);
    }

    /// @notice Adds properties and/or items to be pseudo-randomly chosen from during token minting
    /// @param _names The names of the properties to add
    /// @param _items The items to add to each property
    /// @param _ipfsGroup The IPFS base URI and extension
    function addProperties(
        string[] calldata _names,
        ItemParam[] calldata _items,
        IPFSGroup calldata _ipfsGroup
    ) external onlyOwner {
        _addProperties(_names, _items, _ipfsGroup);
    }

    /// @notice Deletes existing properties and/or items to be pseudo-randomly chosen from during token minting, replacing them with provided properties. WARNING: This function can alter or break existing token metadata if the number of properties for this renderer change before/after the upsert. If the properties selected in any tokens do not exist in the new version those token will not render
    /// @dev We do not require the number of properties for an reset to match the existing property length, to allow multi-stage property additions (for e.g. when there are more properties than can fit in a single transaction)
    /// @param _names The names of the properties to add
    /// @param _items The items to add to each property
    /// @param _ipfsGroup The IPFS base URI and extension
    function deleteAndRecreateProperties(
        string[] calldata _names,
        ItemParam[] calldata _items,
        IPFSGroup calldata _ipfsGroup
    ) external onlyOwner {
        delete ipfsData;
        delete properties;
        _addProperties(_names, _items, _ipfsGroup);
    }

    function _addProperties(
        string[] calldata _names,
        ItemParam[] calldata _items,
        IPFSGroup calldata _ipfsGroup
    ) internal {
        // Cache the existing amount of IPFS data stored
        uint256 dataLength = ipfsData.length;

        // Add the IPFS group information
        ipfsData.push(_ipfsGroup);

        // Cache the number of existing properties
        uint256 numStoredProperties = properties.length;

        // Cache the number of new properties
        uint256 numNewProperties = _names.length;

        // Cache the number of new items
        uint256 numNewItems = _items.length;

        // If this is the first time adding metadata:
        if (numStoredProperties == 0) {
            // Ensure at least one property and one item are included
            if (numNewProperties == 0 || numNewItems == 0) {
                revert ONE_PROPERTY_AND_ITEM_REQUIRED();
            }
        }

        unchecked {
            // Check if not too many items are stored
            if (numStoredProperties + numNewProperties > 15) {
                revert TOO_MANY_PROPERTIES();
            }

            // For each new property:
            for (uint256 i = 0; i < numNewProperties; ++i) {
                // Append storage space
                properties.push();

                // Get the new property id
                uint256 propertyId = numStoredProperties + i;

                // Store the property name
                properties[propertyId].name = _names[i];

                emit PropertyAdded(propertyId, _names[i]);
            }

            // For each new item:
            for (uint256 i = 0; i < numNewItems; ++i) {
                // Cache the id of the associated property
                uint256 _propertyId = _items[i].propertyId;

                // Offset the id if the item is for a new property
                // Note: Property ids under the hood are offset by 1
                if (_items[i].isNewProperty) {
                    _propertyId += numStoredProperties;
                }

                // Ensure the item is for a valid property
                if (_propertyId >= properties.length) {
                    revert INVALID_PROPERTY_SELECTED(_propertyId);
                }

                // Get the pointer to the other items for the property
                Item[] storage items = properties[_propertyId].items;

                // Append storage space
                items.push();

                // Get the index of the new item
                // Cannot underflow as the items array length is ensured to be at least 1
                uint256 newItemIndex = items.length - 1;

                // Store the new item
                Item storage newItem = items[newItemIndex];

                // Store the new item's name and reference slot
                newItem.name = _items[i].name;
                newItem.referenceSlot = uint16(dataLength);
            }
        }
    }

    ///                                                          ///
    ///                     ATTRIBUTE GENERATION                 ///
    ///                                                          ///

    /// @notice Generates attributes for a token upon mint
    /// @param _tokenId The ERC-721 token id
    function onMinted(uint256 _tokenId) external override returns (bool) {
        // Ensure the caller is the token contract
        if (msg.sender != settings.token) revert ONLY_TOKEN();

        // Compute some randomness for the token id
        uint256 seed = _generateSeed(_tokenId);

        // Get the pointer to store generated attributes
        uint16[16] storage tokenAttributes = attributes[_tokenId];

        // Cache the total number of properties available
        uint256 numProperties = properties.length;

        if (numProperties == 0) {
            return false;
        }

        // Store the total as reference in the first slot of the token's array of attributes
        tokenAttributes[0] = uint16(numProperties);

        unchecked {
            // For each property:
            for (uint256 i = 0; i < numProperties; ++i) {
                // Get the number of items to choose from
                uint256 numItems = properties[i].items.length;

                // Use the token's seed to select an item
                tokenAttributes[i + 1] = uint16(seed % numItems);

                // Adjust the randomness
                seed >>= 16;
            }
        }

        return true;
    }

    /// @notice The properties and query string for a generated token
    /// @param _tokenId The ERC-721 token id
    function getAttributes(uint256 _tokenId) public view returns (string memory resultAttributes, string memory queryString) {
        // Get the token's query string
        queryString = string.concat(
            "?contractAddress=",
            Strings.toHexString(uint256(uint160(address(this))), 20),
            "&tokenId=",
            Strings.toString(_tokenId)
        );

        // Get the token's generated attributes
        uint16[16] memory tokenAttributes = attributes[_tokenId];

        // Cache the number of properties when the token was minted
        uint256 numProperties = tokenAttributes[0];

        // Ensure the given token was minted
        if (numProperties == 0) revert TOKEN_NOT_MINTED(_tokenId);

        // Get an array to store the token's generated attribtues
        MetadataBuilder.JSONItem[] memory arrayAttributesItems = new MetadataBuilder.JSONItem[](numProperties);

        unchecked {
            // For each of the token's properties:
            for (uint256 i = 0; i < numProperties; ++i) {
                // Get its name and list of associated items
                Property memory property = properties[i];

                // Get the randomly generated index of the item to select for this token
                uint256 attribute = tokenAttributes[i + 1];

                // Get the associated item data
                Item memory item = property.items[attribute];

                // Store the encoded attributes and query string
                MetadataBuilder.JSONItem memory itemJSON = arrayAttributesItems[i];

                itemJSON.key = property.name;
                itemJSON.value = item.name;
                itemJSON.quote = true;

                queryString = string.concat(queryString, "&images=", _getItemImage(item, property.name));
            }

            resultAttributes = MetadataBuilder.generateJSON(arrayAttributesItems);
        }
    }

    /// @dev Generates a psuedo-random seed for a token id
    function _generateSeed(uint256 _tokenId) private view returns (uint256) {
        return uint256(keccak256(abi.encode(_tokenId, blockhash(block.number), block.coinbase, block.timestamp)));
    }

    /// @dev Encodes the reference URI of an item
    function _getItemImage(Item memory _item, string memory _propertyName) private view returns (string memory) {
        return
            UriEncode.uriEncode(
                string(
                    abi.encodePacked(ipfsData[_item.referenceSlot].baseUri, _propertyName, "/", _item.name, ipfsData[_item.referenceSlot].extension)
                )
            );
    }

    ///                                                          ///
    ///                            URIs                          ///
    ///                                                          ///

    /// @notice Internal getter function for token name
    function _name() internal view returns (string memory) {
        return ERC721(settings.token).name();
    }

    /// @notice The contract URI
    function contractURI() external view override returns (string memory) {
        MetadataBuilder.JSONItem[] memory items = new MetadataBuilder.JSONItem[](4);

        items[0] = MetadataBuilder.JSONItem({ key: MetadataJSONKeys.keyName, value: _name(), quote: true });
        items[1] = MetadataBuilder.JSONItem({ key: MetadataJSONKeys.keyDescription, value: settings.description, quote: true });
        items[2] = MetadataBuilder.JSONItem({ key: MetadataJSONKeys.keyImage, value: settings.contractImage, quote: true });
        items[3] = MetadataBuilder.JSONItem({ key: "external_url", value: settings.projectURI, quote: true });

        return MetadataBuilder.generateEncodedJSON(items);
    }

    /// @notice The token URI
    /// @param _tokenId The ERC-721 token id
    function tokenURI(uint256 _tokenId) external view returns (string memory) {
        (string memory _attributes, string memory queryString) = getAttributes(_tokenId);

        MetadataBuilder.JSONItem[] memory items = new MetadataBuilder.JSONItem[](4 + additionalTokenProperties.length);

        items[0] = MetadataBuilder.JSONItem({
            key: MetadataJSONKeys.keyName,
            value: string.concat(_name(), " #", Strings.toString(_tokenId)),
            quote: true
        });
        items[1] = MetadataBuilder.JSONItem({ key: MetadataJSONKeys.keyDescription, value: settings.description, quote: true });
        items[2] = MetadataBuilder.JSONItem({
            key: MetadataJSONKeys.keyImage,
            value: string.concat(settings.rendererBase, queryString),
            quote: true
        });
        items[3] = MetadataBuilder.JSONItem({ key: MetadataJSONKeys.keyProperties, value: _attributes, quote: false });

        for (uint256 i = 0; i < additionalTokenProperties.length; i++) {
            AdditionalTokenProperty memory tokenProperties = additionalTokenProperties[i];
            items[4 + i] = MetadataBuilder.JSONItem({ key: tokenProperties.key, value: tokenProperties.value, quote: tokenProperties.quote });
        }

        return MetadataBuilder.generateEncodedJSON(items);
    }

    ///                                                          ///
    ///                       METADATA SETTINGS                  ///
    ///                                                          ///

    /// @notice The associated ERC-721 token
    function token() external view returns (address) {
        return settings.token;
    }

    /// @notice The contract image
    function contractImage() external view returns (string memory) {
        return settings.contractImage;
    }

    /// @notice The renderer base
    function rendererBase() external view returns (string memory) {
        return settings.rendererBase;
    }

    /// @notice The collection description
    function description() external view returns (string memory) {
        return settings.description;
    }

    /// @notice The collection description
    function projectURI() external view returns (string memory) {
        return settings.projectURI;
    }

    /// @notice Get the owner of the metadata (here delegated to the token owner)
    function owner() public view returns (address) {
        return IOwnable(settings.token).owner();
    }

    ///                                                          ///
    ///                       UPDATE SETTINGS                    ///
    ///                                                          ///

    /// @notice Updates the contract image
    /// @param _newContractImage The new contract image
    function updateContractImage(string memory _newContractImage) external onlyOwner {
        emit ContractImageUpdated(settings.contractImage, _newContractImage);

        settings.contractImage = _newContractImage;
    }

    /// @notice Updates the renderer base
    /// @param _newRendererBase The new renderer base
    function updateRendererBase(string memory _newRendererBase) external onlyOwner {
        emit RendererBaseUpdated(settings.rendererBase, _newRendererBase);

        settings.rendererBase = _newRendererBase;
    }

    /// @notice Updates the collection description
    /// @param _newDescription The new description
    function updateDescription(string memory _newDescription) external onlyOwner {
        emit DescriptionUpdated(settings.description, _newDescription);

        settings.description = _newDescription;
    }

    function updateProjectURI(string memory _newProjectURI) external onlyOwner {
        emit WebsiteURIUpdated(settings.projectURI, _newProjectURI);

        settings.projectURI = _newProjectURI;
    }

    ///                                                          ///
    ///                        METADATA UPGRADE                  ///
    ///                                                          ///

    /// @notice Ensures the caller is authorized to upgrade the contract to a valid implementation
    /// @dev This function is called in UUPS `upgradeTo` & `upgradeToAndCall`
    /// @param _impl The address of the new implementation
    function _authorizeUpgrade(address _impl) internal view override onlyOwner {
        if (!manager.isRegisteredUpgrade(_getImplementation(), _impl)) revert INVALID_UPGRADE(_impl);
    }
}
        

/

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

library MetadataMIMETypes {
    string constant mimeJSON = "application/json";
    string constant mimeSVG = "image/svg+xml";
    string constant mimeTextPlain = "text/plain";
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

library MetadataJSONKeys {
   string constant keyName = "name";
   string constant keyDescription = "description";
   string constant keyImage = "image";
   string constant keyAnimationURL = "animation_url";
   string constant keyAttributes = "attributes";
   string constant keyProperties = "properties";
}
          

/MetadataRendererStorageV2.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { MetadataRendererTypesV2 } from "../types/MetadataRendererTypesV2.sol";

/// @title MetadataRendererTypesV1
/// @author Iain Nash & Rohan Kulkarni
/// @notice The Metadata Renderer storage contract
contract MetadataRendererStorageV2 is MetadataRendererTypesV2 {
    /// @notice Additional JSON key/value properties for each token.
    /// @dev While strings are quoted, JSON needs to be escaped.
    AdditionalTokenProperty[] internal additionalTokenProperties;
}
          

/draft-IERC1822.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822Proxiable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

import {Base64} from "./lib/Base64.sol";
import {Strings} from "./lib/Strings.sol";
import {MetadataMIMETypes} from "./MetadataMIMETypes.sol";

library MetadataBuilder {
    struct JSONItem {
        string key;
        string value;
        bool quote;
    }

    function generateSVG(
        string memory contents,
        string memory viewBox,
        string memory width,
        string memory height
    ) internal pure returns (string memory) {
        return
            string.concat(
                '<svg viewBox="',
                viewBox,
                '" xmlns="http://www.w3.org/2000/svg" width="',
                width,
                '" height="',
                height,
                '">',
                contents,
                "</svg>"
            );
    }

    /// @notice prefer to use properties with key-value object instead of list
    function generateAttributes(string memory displayType, string memory traitType, string memory value) internal pure returns (string memory) {

    }

    function generateEncodedSVG(
        string memory contents,
        string memory viewBox,
        string memory width,
        string memory height
    ) internal pure returns (string memory) {
        return
            encodeURI(
                MetadataMIMETypes.mimeSVG,
                generateSVG(contents, viewBox, width, height)
            );
    }

    function encodeURI(string memory uriType, string memory result)
        internal
        pure
        returns (string memory)
    {
        return
            string.concat(
                "data:",
                uriType,
                ";base64,",
                string(Base64.encode(bytes(result)))
            );
    }

    function generateJSONArray(JSONItem[] memory items)
        internal
        pure
        returns (string memory result)
    {
        result = "[";
        uint256 added = 0;
        for (uint256 i = 0; i < items.length; i++) {
            if (bytes(items[i].value).length == 0) {
                continue;
            }
            if (items[i].quote) {
                result = string.concat(
                    result,
                    added == 0 ? "" : ",",
                    '"',
                    items[i].value,
                    '"'
                );
            } else {
                result = string.concat(
                    result,
                    added == 0 ? "" : ",",
                    items[i].value
                );
            }
            added += 1;
        }
        result = string.concat(result, "]");
    }

    function generateJSON(JSONItem[] memory items)
        internal
        pure
        returns (string memory result)
    {
        result = "{";
        uint256 added = 0;
        for (uint256 i = 0; i < items.length; i++) {
            if (bytes(items[i].value).length == 0) {
                continue;
            }
            if (items[i].quote) {
                result = string.concat(
                    result,
                    added == 0 ? "" : ",",
                    '"',
                    items[i].key,
                    '": "',
                    items[i].value,
                    '"'
                );
            } else {
                result = string.concat(
                    result,
                    added == 0 ? "" : ",",
                    '"',
                    items[i].key,
                    '": ',
                    items[i].value
                );
            }
            added += 1;
        }
        result = string.concat(result, "}");
    }

    function generateEncodedJSON(JSONItem[] memory items)
        internal
        pure
        returns (string memory)
    {
        return encodeURI(MetadataMIMETypes.mimeJSON, generateJSON(items));
    }
}
          

/IPropertyIPFSMetadataRenderer.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { MetadataRendererTypesV1 } from "../types/MetadataRendererTypesV1.sol";
import { MetadataRendererTypesV2 } from "../types/MetadataRendererTypesV2.sol";
import { IBaseMetadata } from "./IBaseMetadata.sol";

/// @title IPropertyIPFSMetadataRenderer
/// @author Iain Nash & Rohan Kulkarni
/// @notice The external Metadata Renderer events, errors, and functions
interface IPropertyIPFSMetadataRenderer is IBaseMetadata, MetadataRendererTypesV1, MetadataRendererTypesV2 {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when a property is added
    event PropertyAdded(uint256 id, string name);

    /// @notice Additional token properties have been set
    event AdditionalTokenPropertiesSet(AdditionalTokenProperty[] _additionalJsonProperties);

    /// @notice Emitted when the contract image is updated
    event ContractImageUpdated(string prevImage, string newImage);

    /// @notice Emitted when the renderer base is updated
    event RendererBaseUpdated(string prevRendererBase, string newRendererBase);

    /// @notice Emitted when the collection description is updated
    event DescriptionUpdated(string prevDescription, string newDescription);

    /// @notice Emitted when the collection uri is updated
    event WebsiteURIUpdated(string lastURI, string newURI);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the caller isn't the token contract
    error ONLY_TOKEN();

    /// @dev Reverts if querying attributes for a token not minted
    error TOKEN_NOT_MINTED(uint256 tokenId);

    /// @dev Reverts if the founder does not include both a property and item during the initial artwork upload
    error ONE_PROPERTY_AND_ITEM_REQUIRED();

    /// @dev Reverts if an item is added for a non-existent property
    error INVALID_PROPERTY_SELECTED(uint256 selectedPropertyId);

    ///
    error TOO_MANY_PROPERTIES();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice Adds properties and/or items to be pseudo-randomly chosen from during token minting
    /// @param names The names of the properties to add
    /// @param items The items to add to each property
    /// @param ipfsGroup The IPFS base URI and extension
    function addProperties(
        string[] calldata names,
        ItemParam[] calldata items,
        IPFSGroup calldata ipfsGroup
    ) external;

    /// @notice The number of properties
    function propertiesCount() external view returns (uint256);

    /// @notice The number of items in a property
    /// @param propertyId The property id
    function itemsCount(uint256 propertyId) external view returns (uint256);

    /// @notice The properties and query string for a generated token
    /// @param tokenId The ERC-721 token id
    function getAttributes(uint256 tokenId) external view returns (string memory resultAttributes, string memory queryString);

    /// @notice The contract image
    function contractImage() external view returns (string memory);

    /// @notice The renderer base
    function rendererBase() external view returns (string memory);

    /// @notice The collection description
    function description() external view returns (string memory);

    /// @notice Updates the contract image
    /// @param newContractImage The new contract image
    function updateContractImage(string memory newContractImage) external;

    /// @notice Updates the renderer base
    /// @param newRendererBase The new renderer base
    function updateRendererBase(string memory newRendererBase) external;

    /// @notice Updates the collection description
    /// @param newDescription The new description
    function updateDescription(string memory newDescription) external;
}
          

/Strings.sol

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

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_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) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

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

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @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] = _HEX_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);
    }
}
          

/Base64.sol

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

pragma solidity ^0.8.0;

/**
 * @dev Provides a set of functions to operate with Base64 strings.
 *
 * _Available since v4.5._
 */
library Base64 {
    /**
     * @dev Base64 Encoding/Decoding Table
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /**
     * @dev Converts a `bytes` to its Bytes64 `string` representation.
     */
    function encode(bytes memory data) internal pure returns (string memory) {
        /**
         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
         */
        if (data.length == 0) return "";

        // Loads the table into memory
        string memory table = _TABLE;

        // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
        // and split into 4 numbers of 6 bits.
        // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
        // - `data.length + 2`  -> Round up
        // - `/ 3`              -> Number of 3-bytes chunks
        // - `4 *`              -> 4 characters for each chunk
        string memory result = new string(4 * ((data.length + 2) / 3));

        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the lookup table (skip the first "length" byte)
            let tablePtr := add(table, 1)

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

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

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

                // To write each character, shift the 3 bytes (18 bits) chunk
                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                // and apply logical AND with 0x3F which is the number of
                // the previous character in the ASCII table prior to the Base64 Table
                // The result is then added to the table to get the character to write,
                // and finally write it in the result pointer but with a left shift
                // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits

                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance
            }

            // When data `bytes` is not exactly 3 bytes long
            // it is padded with `=` characters at the end
            switch mod(mload(data), 3)
            case 1 {
                mstore8(sub(resultPtr, 1), 0x3d)
                mstore8(sub(resultPtr, 2), 0x3d)
            }
            case 2 {
                mstore8(sub(resultPtr, 1), 0x3d)
            }
        }

        return result;
    }
}
          

/StorageSlot.sol

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

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}
          

/MetadataRendererStorageV1.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { MetadataRendererTypesV1 } from "../types/MetadataRendererTypesV1.sol";

/// @title MetadataRendererTypesV1
/// @author Iain Nash & Rohan Kulkarni
/// @notice The Metadata Renderer storage contract
contract MetadataRendererStorageV1 is MetadataRendererTypesV1 {
    /// @notice The metadata renderer settings
    Settings public settings;

    /// @notice The properties chosen from upon generation
    Property[] public properties;

    /// @notice The IPFS data of all property items
    IPFSGroup[] public ipfsData;

    /// @notice The attributes generated for a token - mapping of tokenID uint16 array
    /// @dev Array of size 16 1st element [0] used for number of attributes chosen, next N elements for those selections
    /// @dev token ID
    mapping(uint256 => uint16[16]) public attributes;
}
          

/Strings.sol

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

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_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) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

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

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @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] = _HEX_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);
    }
}
          

/Base64.sol

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

pragma solidity ^0.8.0;

/**
 * @dev Provides a set of functions to operate with Base64 strings.
 *
 * _Available since v4.5._
 */
library Base64 {
    /**
     * @dev Base64 Encoding/Decoding Table
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /**
     * @dev Converts a `bytes` to its Bytes64 `string` representation.
     */
    function encode(bytes memory data) internal pure returns (string memory) {
        /**
         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
         */
        if (data.length == 0) return "";

        // Loads the table into memory
        string memory table = _TABLE;

        // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
        // and split into 4 numbers of 6 bits.
        // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
        // - `data.length + 2`  -> Round up
        // - `/ 3`              -> Number of 3-bytes chunks
        // - `4 *`              -> 4 characters for each chunk
        string memory result = new string(4 * ((data.length + 2) / 3));

        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the lookup table (skip the first "length" byte)
            let tablePtr := add(table, 1)

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

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

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

                // To write each character, shift the 3 bytes (18 bits) chunk
                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                // and apply logical AND with 0x3F which is the number of
                // the previous character in the ASCII table prior to the Base64 Table
                // The result is then added to the table to get the character to write,
                // and finally write it in the result pointer but with a left shift
                // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits

                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance
            }

            // When data `bytes` is not exactly 3 bytes long
            // it is padded with `=` characters at the end
            switch mod(mload(data), 3)
            case 1 {
                mstore8(sub(resultPtr, 1), 0x3d)
                mstore8(sub(resultPtr, 2), 0x3d)
            }
            case 2 {
                mstore8(sub(resultPtr, 1), 0x3d)
            }
        }

        return result;
    }
}
          

/MetadataRendererTypesV2.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title MetadataRendererTypesV2
/// @author Iain Nash & Rohan Kulkarni
/// @notice The Metadata Renderer custom data types
interface MetadataRendererTypesV2 {
    struct AdditionalTokenProperty {
        string key;
        string value;
        bool quote;
    }
}
          

/MetadataRendererTypesV1.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title MetadataRendererTypesV1
/// @author Iain Nash & Rohan Kulkarni
/// @notice The Metadata Renderer custom data types
interface MetadataRendererTypesV1 {
    struct ItemParam {
        uint256 propertyId;
        string name;
        bool isNewProperty;
    }

    struct IPFSGroup {
        string baseUri;
        string extension;
    }

    struct Item {
        uint16 referenceSlot;
        string name;
    }

    struct Property {
        string name;
        Item[] items;
    }

    struct Settings {
        address token;
        string projectURI;
        string description;
        string contractImage;
        string rendererBase;
    }
}
          

/IBaseMetadata.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IUUPS } from "../../../lib/interfaces/IUUPS.sol";


/// @title IBaseMetadata
/// @author Rohan Kulkarni
/// @notice The external Base Metadata errors and functions
interface IBaseMetadata is IUUPS {
    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the caller was not the contract manager
    error ONLY_MANAGER();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice Initializes a DAO's token metadata renderer
    /// @param initStrings The encoded token and metadata initialization strings
    /// @param token The associated ERC-721 token address
    function initialize(
        bytes calldata initStrings,
        address token
    ) external;

    /// @notice Generates attributes for a token upon mint
    /// @param tokenId The ERC-721 token id
    function onMinted(uint256 tokenId) external returns (bool);

    /// @notice The token URI
    /// @param tokenId The ERC-721 token id
    function tokenURI(uint256 tokenId) external view returns (string memory);

    /// @notice The contract URI
    function contractURI() external view returns (string memory);

    /// @notice The associated ERC-721 token
    function token() external view returns (address);

    /// @notice Get metadata owner address
    function owner() external view returns (address);
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC721/utils/ERC721Holder.sol)
abstract contract ERC721TokenReceiver {
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return this.onERC721Received.selector;
    }
}

/// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC1155/utils/ERC1155Holder.sol)
abstract contract ERC1155TokenReceiver {
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return this.onERC1155Received.selector;
    }

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

/

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

library UriEncode {
    string internal constant _TABLE = "0123456789abcdef";

    function uriEncode(string memory uri)
        internal
        pure
        returns (string memory)
    {
        bytes memory bytesUri = bytes(uri);

        string memory table = _TABLE;

        // Max size is worse case all chars need to be encoded
        bytes memory result = new bytes(3 * bytesUri.length);

        /// @solidity memory-safe-assembly
        assembly {
            // Get the lookup table
            let tablePtr := add(table, 1)

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

            // Keep track of the final result size string length
            let resultSize := 0

            for {
                let dataPtr := bytesUri
                let endPtr := add(bytesUri, mload(bytesUri))
            } lt(dataPtr, endPtr) {

            } {
                // advance 1 byte
                dataPtr := add(dataPtr, 1)
                // bytemask out a char
                let input := and(mload(dataPtr), 255)

                // Check if is valid URI character
                let isValidUriChar := or(
                    and(gt(input, 96), lt(input, 134)), // a 97 / z 133
                    or(
                        and(gt(input, 64), lt(input, 91)), // A 65 / Z 90
                        or(
                          and(gt(input, 47), lt(input, 58)), // 0 48 / 9 57
                          or(
                            or(
                              eq(input, 46), // . 46
                              eq(input, 95)  // _ 95
                            ),
                            or(
                              eq(input, 45),  // - 45
                              eq(input, 126)  // ~ 126
                            )
                          )
                        )
                    )
                )

                switch isValidUriChar
                // If is valid uri character copy character over and increment the result
                case 1 {
                    mstore8(resultPtr, input)
                    resultPtr := add(resultPtr, 1)
                    resultSize := add(resultSize, 1)
                }
                // If the char is not a valid uri character, uriencode the character
                case 0 {
                    mstore8(resultPtr, 37)
                    resultPtr := add(resultPtr, 1)
                    // table[character >> 4] (take the last 4 bits)
                    mstore8(resultPtr, mload(add(tablePtr, shr(4, input))))
                    resultPtr := add(resultPtr, 1)
                    // table & 15 (take the first 4 bits)
                    mstore8(resultPtr, mload(add(tablePtr, and(input, 15))))
                    resultPtr := add(resultPtr, 1)
                    resultSize := add(resultSize, 3)
                }
            }

            // Set size of result string in memory
            mstore(result, resultSize)
        }

        return string(result);
    }
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IERC1967Upgrade
/// @author Rohan Kulkarni
/// @notice The external ERC1967Upgrade events and errors
interface IERC1967Upgrade {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when the implementation is upgraded
    /// @param impl The address of the implementation
    event Upgraded(address impl);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if an implementation is an invalid upgrade
    /// @param impl The address of the invalid implementation
    error INVALID_UPGRADE(address impl);

    /// @dev Reverts if an implementation upgrade is not stored at the storage slot of the original
    error UNSUPPORTED_UUID();

    /// @dev Reverts if an implementation does not support ERC1822 proxiableUUID()
    error ONLY_UUPS();
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IInitializable
/// @author Rohan Kulkarni
/// @notice The external Initializable events and errors
interface IInitializable {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when the contract has been initialized or reinitialized
    event Initialized(uint256 version);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if incorrectly initialized with address(0)
    error ADDRESS_ZERO();

    /// @dev Reverts if disabling initializers during initialization
    error INITIALIZING();

    /// @dev Reverts if calling an initialization function outside of initialization
    error NOT_INITIALIZING();

    /// @dev Reverts if reinitializing incorrectly
    error ALREADY_INITIALIZED();
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IERC721 } from "./IERC721.sol";
import { IEIP712 } from "./IEIP712.sol";

/// @title IERC721Votes
/// @author Rohan Kulkarni
/// @notice The external ERC721Votes events, errors, and functions
interface IERC721Votes is IERC721, IEIP712 {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when an account changes their delegate
    event DelegateChanged(address indexed delegator, address indexed from, address indexed to);

    /// @notice Emitted when a delegate's number of votes is updated
    event DelegateVotesChanged(address indexed delegate, uint256 prevTotalVotes, uint256 newTotalVotes);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the timestamp provided isn't in the past
    error INVALID_TIMESTAMP();

    ///                                                          ///
    ///                            STRUCTS                       ///
    ///                                                          ///

    /// @notice The checkpoint data type
    /// @param timestamp The recorded timestamp
    /// @param votes The voting weight
    struct Checkpoint {
        uint64 timestamp;
        uint192 votes;
    }

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice The current number of votes for an account
    /// @param account The account address
    function getVotes(address account) external view returns (uint256);

    /// @notice The number of votes for an account at a past timestamp
    /// @param account The account address
    /// @param timestamp The past timestamp
    function getPastVotes(address account, uint256 timestamp) external view returns (uint256);

    /// @notice The delegate for an account
    /// @param account The account address
    function delegates(address account) external view returns (address);

    /// @notice Delegates votes to an account
    /// @param to The address delegating votes to
    function delegate(address to) external;

    /// @notice Delegates votes from a signer to an account
    /// @param from The address delegating votes from
    /// @param to The address delegating votes to
    /// @param deadline The signature deadline
    /// @param v The 129th byte and chain id of the signature
    /// @param r The first 64 bytes of the signature
    /// @param s Bytes 64-128 of the signature
    function delegateBySig(
        address from,
        address to,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title TokenTypesV2
/// @author James Geary
/// @notice The Token custom data types
interface TokenTypesV2 {
    struct MinterParams {
        address minter;
        bool allowed;
    }
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IBaseMetadata } from "../metadata/interfaces/IBaseMetadata.sol";

/// @title TokenTypesV1
/// @author Rohan Kulkarni
/// @notice The Token custom data types
interface TokenTypesV1 {
    /// @notice The settings type
    /// @param auction The DAO auction house
    /// @param totalSupply The number of active tokens
    /// @param numFounders The number of vesting recipients
    /// @param metadatarenderer The token metadata renderer
    /// @param mintCount The number of minted tokens
    /// @param totalPercentage The total percentage owned by founders
    struct Settings {
        address auction;
        uint88 totalSupply;
        uint8 numFounders;
        IBaseMetadata metadataRenderer;
        uint88 mintCount;
        uint8 totalOwnership;
    }

    /// @notice The founder type
    /// @param wallet The address where tokens are sent
    /// @param ownershipPct The percentage of token ownership
    /// @param vestExpiry The timestamp when vesting ends
    struct Founder {
        address wallet;
        uint8 ownershipPct;
        uint32 vestExpiry;
    }
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IERC1822Proxiable } from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import { StorageSlot } from "@openzeppelin/contracts/utils/StorageSlot.sol";

import { IERC1967Upgrade } from "../interfaces/IERC1967Upgrade.sol";
import { Address } from "../utils/Address.sol";

/// @title ERC1967Upgrade
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/ERC1967/ERC1967Upgrade.sol)
/// - Uses custom errors declared in IERC1967Upgrade
/// - Removes ERC1967 admin and beacon support
abstract contract ERC1967Upgrade is IERC1967Upgrade {
    ///                                                          ///
    ///                          CONSTANTS                       ///
    ///                                                          ///

    /// @dev bytes32(uint256(keccak256('eip1967.proxy.rollback')) - 1)
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /// @dev bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    ///                                                          ///
    ///                          FUNCTIONS                       ///
    ///                                                          ///

    /// @dev Upgrades to an implementation with security checks for UUPS proxies and an additional function call
    /// @param _newImpl The new implementation address
    /// @param _data The encoded function call
    function _upgradeToAndCallUUPS(
        address _newImpl,
        bytes memory _data,
        bool _forceCall
    ) internal {
        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(_newImpl);
        } else {
            try IERC1822Proxiable(_newImpl).proxiableUUID() returns (bytes32 slot) {
                if (slot != _IMPLEMENTATION_SLOT) revert UNSUPPORTED_UUID();
            } catch {
                revert ONLY_UUPS();
            }

            _upgradeToAndCall(_newImpl, _data, _forceCall);
        }
    }

    /// @dev Upgrades to an implementation with an additional function call
    /// @param _newImpl The new implementation address
    /// @param _data The encoded function call
    function _upgradeToAndCall(
        address _newImpl,
        bytes memory _data,
        bool _forceCall
    ) internal {
        _upgradeTo(_newImpl);

        if (_data.length > 0 || _forceCall) {
            Address.functionDelegateCall(_newImpl, _data);
        }
    }

    /// @dev Performs an implementation upgrade
    /// @param _newImpl The new implementation address
    function _upgradeTo(address _newImpl) internal {
        _setImplementation(_newImpl);

        emit Upgraded(_newImpl);
    }

    /// @dev Stores the address of an implementation
    /// @param _impl The implementation address
    function _setImplementation(address _impl) private {
        if (!Address.isContract(_impl)) revert INVALID_UPGRADE(_impl);

        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = _impl;
    }

    /// @dev The address of the current implementation
    function _getImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IInitializable } from "../interfaces/IInitializable.sol";
import { Address } from "../utils/Address.sol";

/// @title Initializable
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/utils/Initializable.sol)
/// - Uses custom errors declared in IInitializable
abstract contract Initializable is IInitializable {
    ///                                                          ///
    ///                           STORAGE                        ///
    ///                                                          ///

    /// @dev Indicates the contract has been initialized
    uint8 internal _initialized;

    /// @dev Indicates the contract is being initialized
    bool internal _initializing;

    ///                                                          ///
    ///                          MODIFIERS                       ///
    ///                                                          ///

    /// @dev Ensures an initialization function is only called within an `initializer` or `reinitializer` function
    modifier onlyInitializing() {
        if (!_initializing) revert NOT_INITIALIZING();
        _;
    }

    /// @dev Enables initializing upgradeable contracts
    modifier initializer() {
        bool isTopLevelCall = !_initializing;

        if ((!isTopLevelCall || _initialized != 0) && (Address.isContract(address(this)) || _initialized != 1)) revert ALREADY_INITIALIZED();

        _initialized = 1;

        if (isTopLevelCall) {
            _initializing = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;

            emit Initialized(1);
        }
    }

    /// @dev Enables initializer versioning
    /// @param _version The version to set
    modifier reinitializer(uint8 _version) {
        if (_initializing || _initialized >= _version) revert ALREADY_INITIALIZED();

        _initialized = _version;

        _initializing = true;

        _;

        _initializing = false;

        emit Initialized(_version);
    }

    ///                                                          ///
    ///                          FUNCTIONS                       ///
    ///                                                          ///

    /// @dev Prevents future initialization
    function _disableInitializers() internal virtual {
        if (_initializing) revert INITIALIZING();

        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;

            emit Initialized(type(uint8).max);
        }
    }
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IOwnable
/// @author Rohan Kulkarni
/// @notice The external Ownable events, errors, and functions
interface IOwnable {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when ownership has been updated
    /// @param prevOwner The previous owner address
    /// @param newOwner The new owner address
    event OwnerUpdated(address indexed prevOwner, address indexed newOwner);

    /// @notice Emitted when an ownership transfer is pending
    /// @param owner The current owner address
    /// @param pendingOwner The pending new owner address
    event OwnerPending(address indexed owner, address indexed pendingOwner);

    /// @notice Emitted when a pending ownership transfer has been canceled
    /// @param owner The current owner address
    /// @param canceledOwner The canceled owner address
    event OwnerCanceled(address indexed owner, address indexed canceledOwner);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if an unauthorized user calls an owner function
    error ONLY_OWNER();

    /// @dev Reverts if an unauthorized user calls a pending owner function
    error ONLY_PENDING_OWNER();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice The address of the owner
    function owner() external view returns (address);

    /// @notice The address of the pending owner
    function pendingOwner() external view returns (address);

    /// @notice Forces an ownership transfer
    /// @param newOwner The new owner address
    function transferOwnership(address newOwner) external;

    /// @notice Initiates a two-step ownership transfer
    /// @param newOwner The new owner address
    function safeTransferOwnership(address newOwner) external;

    /// @notice Accepts an ownership transfer
    function acceptOwnership() external;

    /// @notice Cancels a pending ownership transfer
    function cancelOwnershipTransfer() external;
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IERC721
/// @author Rohan Kulkarni
/// @notice The external ERC721 events, errors, and functions
interface IERC721 {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when a token is transferred from sender to recipient
    /// @param from The sender address
    /// @param to The recipient address
    /// @param tokenId The ERC-721 token id
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /// @notice Emitted when an owner approves an account to manage a token
    /// @param owner The owner address
    /// @param approved The account address
    /// @param tokenId The ERC-721 token id
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /// @notice Emitted when an owner sets an approval for a spender to manage all tokens
    /// @param owner The owner address
    /// @param operator The spender address
    /// @param approved If the approval is being set or removed
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if a caller is not authorized to approve or transfer a token
    error INVALID_APPROVAL();

    /// @dev Reverts if a transfer is called with the incorrect token owner
    error INVALID_OWNER();

    /// @dev Reverts if a transfer is attempted to address(0)
    error INVALID_RECIPIENT();

    /// @dev Reverts if an existing token is called to be minted
    error ALREADY_MINTED();

    /// @dev Reverts if a non-existent token is called to be burned
    error NOT_MINTED();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice The number of tokens owned
    /// @param owner The owner address
    function balanceOf(address owner) external view returns (uint256);

    /// @notice The owner of a token
    /// @param tokenId The ERC-721 token id
    function ownerOf(uint256 tokenId) external view returns (address);

    /// @notice The account approved to manage a token
    /// @param tokenId The ERC-721 token id
    function getApproved(uint256 tokenId) external view returns (address);

    /// @notice If an operator is authorized to manage all of an owner's tokens
    /// @param owner The owner address
    /// @param operator The operator address
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /// @notice Authorizes an account to manage a token
    /// @param to The account address
    /// @param tokenId The ERC-721 token id
    function approve(address to, uint256 tokenId) external;

    /// @notice Authorizes an account to manage all tokens
    /// @param operator The account address
    /// @param approved If permission is being given or removed
    function setApprovalForAll(address operator, bool approved) external;

    /// @notice Safe transfers a token from sender to recipient with additional data
    /// @param from The sender address
    /// @param to The recipient address
    /// @param tokenId The ERC-721 token id
    /// @param data The additional data sent in the call to the recipient
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /// @notice Safe transfers a token from sender to recipient
    /// @param from The sender address
    /// @param to The recipient address
    /// @param tokenId The ERC-721 token id
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /// @notice Transfers a token from sender to recipient
    /// @param from The sender address
    /// @param to The recipient address
    /// @param tokenId The ERC-721 token id
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IEIP712
/// @author Rohan Kulkarni
/// @notice The external EIP712 errors and functions
interface IEIP712 {
    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the deadline has passed to submit a signature
    error EXPIRED_SIGNATURE();

    /// @dev Reverts if the recovered signature is invalid
    error INVALID_SIGNATURE();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice The sig nonce for an account
    /// @param account The account address
    function nonce(address account) external view returns (uint256);

    /// @notice The EIP-712 domain separator
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import { IERC1822Proxiable } from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import { IERC1967Upgrade } from "./IERC1967Upgrade.sol";

/// @title IUUPS
/// @author Rohan Kulkarni
/// @notice The external UUPS errors and functions
interface IUUPS is IERC1967Upgrade, IERC1822Proxiable {
    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if not called directly
    error ONLY_CALL();

    /// @dev Reverts if not called via delegatecall
    error ONLY_DELEGATECALL();

    /// @dev Reverts if not called via proxy
    error ONLY_PROXY();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice Upgrades to an implementation
    /// @param newImpl The new implementation address
    function upgradeTo(address newImpl) external;

    /// @notice Upgrades to an implementation with an additional function call
    /// @param newImpl The new implementation address
    /// @param data The encoded function call
    function upgradeToAndCall(address newImpl, bytes memory data) external payable;
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title EIP712
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (utils/Address.sol)
/// - Uses custom errors `INVALID_TARGET()` & `DELEGATE_CALL_FAILED()`
/// - Adds util converting address to bytes32
library Address {
    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the target of a delegatecall is not a contract
    error INVALID_TARGET();

    /// @dev Reverts if a delegatecall has failed
    error DELEGATE_CALL_FAILED();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @dev Utility to convert an address to bytes32
    function toBytes32(address _account) internal pure returns (bytes32) {
        return bytes32(uint256(uint160(_account)) << 96);
    }

    /// @dev If an address is a contract
    function isContract(address _account) internal view returns (bool rv) {
        assembly {
            rv := gt(extcodesize(_account), 0)
        }
    }

    /// @dev Performs a delegatecall on an address
    function functionDelegateCall(address _target, bytes memory _data) internal returns (bytes memory) {
        if (!isContract(_target)) revert INVALID_TARGET();

        (bool success, bytes memory returndata) = _target.delegatecall(_data);

        return verifyCallResult(success, returndata);
    }

    /// @dev Verifies a delegatecall was successful
    function verifyCallResult(bool _success, bytes memory _returndata) internal pure returns (bytes memory) {
        if (_success) {
            return _returndata;
        } else {
            if (_returndata.length > 0) {
                assembly {
                    let returndata_size := mload(_returndata)

                    revert(add(32, _returndata), returndata_size)
                }
            } else {
                revert DELEGATE_CALL_FAILED();
            }
        }
    }
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

abstract contract VersionedContract {
    function contractVersion() external pure returns (string memory) {
        return "1.2.0";
    }
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IUUPS } from "../lib/interfaces/IUUPS.sol";
import { IOwnable } from "../lib/interfaces/IOwnable.sol";

/// @title IManager
/// @author Rohan Kulkarni
/// @notice The external Manager events, errors, structs and functions
interface IManager is IUUPS, IOwnable {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when a DAO is deployed
    /// @param token The ERC-721 token address
    /// @param metadata The metadata renderer address
    /// @param auction The auction address
    /// @param treasury The treasury address
    /// @param governor The governor address
    event DAODeployed(address token, address metadata, address auction, address treasury, address governor);

    /// @notice Emitted when an upgrade is registered by the Builder DAO
    /// @param baseImpl The base implementation address
    /// @param upgradeImpl The upgrade implementation address
    event UpgradeRegistered(address baseImpl, address upgradeImpl);

    /// @notice Emitted when an upgrade is unregistered by the Builder DAO
    /// @param baseImpl The base implementation address
    /// @param upgradeImpl The upgrade implementation address
    event UpgradeRemoved(address baseImpl, address upgradeImpl);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if at least one founder is not provided upon deploy
    error FOUNDER_REQUIRED();

    ///                                                          ///
    ///                            STRUCTS                       ///
    ///                                                          ///

    /// @notice The founder parameters
    /// @param wallet The wallet address
    /// @param ownershipPct The percent ownership of the token
    /// @param vestExpiry The timestamp that vesting expires
    struct FounderParams {
        address wallet;
        uint256 ownershipPct;
        uint256 vestExpiry;
    }

    /// @notice DAO Version Information information struct
    struct DAOVersionInfo {
        string token;
        string metadata;
        string auction;
        string treasury;
        string governor; 
    }

    /// @notice The ERC-721 token parameters
    /// @param initStrings The encoded token name, symbol, collection description, collection image uri, renderer base uri
    struct TokenParams {
        bytes initStrings;
    }

    /// @notice The auction parameters
    /// @param reservePrice The reserve price of each auction
    /// @param duration The duration of each auction
    struct AuctionParams {
        uint256 reservePrice;
        uint256 duration;
    }

    /// @notice The governance parameters
    /// @param timelockDelay The time delay to execute a queued transaction
    /// @param votingDelay The time delay to vote on a created proposal
    /// @param votingPeriod The time period to vote on a proposal
    /// @param proposalThresholdBps The basis points of the token supply required to create a proposal
    /// @param quorumThresholdBps The basis points of the token supply required to reach quorum
    /// @param vetoer The address authorized to veto proposals (address(0) if none desired)
    struct GovParams {
        uint256 timelockDelay;
        uint256 votingDelay;
        uint256 votingPeriod;
        uint256 proposalThresholdBps;
        uint256 quorumThresholdBps;
        address vetoer;
    }

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice The token implementation address
    function tokenImpl() external view returns (address);

    /// @notice The metadata renderer implementation address
    function metadataImpl() external view returns (address);

    /// @notice The auction house implementation address
    function auctionImpl() external view returns (address);

    /// @notice The treasury implementation address
    function treasuryImpl() external view returns (address);

    /// @notice The governor implementation address
    function governorImpl() external view returns (address);

    /// @notice Deploys a DAO with custom token, auction, and governance settings
    /// @param founderParams The DAO founder(s)
    /// @param tokenParams The ERC-721 token settings
    /// @param auctionParams The auction settings
    /// @param govParams The governance settings
    function deploy(
        FounderParams[] calldata founderParams,
        TokenParams calldata tokenParams,
        AuctionParams calldata auctionParams,
        GovParams calldata govParams
    )
        external
        returns (
            address token,
            address metadataRenderer,
            address auction,
            address treasury,
            address governor
        );

    /// @notice A DAO's remaining contract addresses from its token address
    /// @param token The ERC-721 token address
    function getAddresses(address token)
        external
        returns (
            address metadataRenderer,
            address auction,
            address treasury,
            address governor
        );

    /// @notice If an implementation is registered by the Builder DAO as an optional upgrade
    /// @param baseImpl The base implementation address
    /// @param upgradeImpl The upgrade implementation address
    function isRegisteredUpgrade(address baseImpl, address upgradeImpl) external view returns (bool);

    /// @notice Called by the Builder DAO to offer opt-in implementation upgrades for all other DAOs
    /// @param baseImpl The base implementation address
    /// @param upgradeImpl The upgrade implementation address
    function registerUpgrade(address baseImpl, address upgradeImpl) external;

    /// @notice Called by the Builder DAO to remove an upgrade
    /// @param baseImpl The base implementation address
    /// @param upgradeImpl The upgrade implementation address
    function removeUpgrade(address baseImpl, address upgradeImpl) external;
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IERC721 } from "../interfaces/IERC721.sol";
import { Initializable } from "../utils/Initializable.sol";
import { ERC721TokenReceiver } from "../utils/TokenReceiver.sol";
import { Address } from "../utils/Address.sol";

/// @title ERC721
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC721/ERC721Upgradeable.sol)
/// - Uses custom errors declared in IERC721
abstract contract ERC721 is IERC721, Initializable {
    ///                                                          ///
    ///                            STORAGE                       ///
    ///                                                          ///

    /// @notice The token name
    string public name;

    /// @notice The token symbol
    string public symbol;

    /// @notice The token owners
    /// @dev ERC-721 token id => Owner
    mapping(uint256 => address) internal owners;

    /// @notice The owner balances
    /// @dev Owner => Balance
    mapping(address => uint256) internal balances;

    /// @notice The token approvals
    /// @dev ERC-721 token id => Manager
    mapping(uint256 => address) internal tokenApprovals;

    /// @notice The balance approvals
    /// @dev Owner => Operator => Approved
    mapping(address => mapping(address => bool)) internal operatorApprovals;

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @dev Initializes an ERC-721 token
    /// @param _name The ERC-721 token name
    /// @param _symbol The ERC-721 token symbol
    function __ERC721_init(string memory _name, string memory _symbol) internal onlyInitializing {
        name = _name;
        symbol = _symbol;
    }

    /// @notice The token URI
    /// @param _tokenId The ERC-721 token id
    function tokenURI(uint256 _tokenId) public view virtual returns (string memory) {}

    /// @notice The contract URI
    function contractURI() public view virtual returns (string memory) {}

    /// @notice If the contract implements an interface
    /// @param _interfaceId The interface id
    function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
        return
            _interfaceId == 0x01ffc9a7 || // ERC165 Interface ID
            _interfaceId == 0x80ac58cd || // ERC721 Interface ID
            _interfaceId == 0x5b5e139f; // ERC721Metadata Interface ID
    }

    /// @notice The account approved to manage a token
    /// @param _tokenId The ERC-721 token id
    function getApproved(uint256 _tokenId) external view returns (address) {
        return tokenApprovals[_tokenId];
    }

    /// @notice If an operator is authorized to manage all of an owner's tokens
    /// @param _owner The owner address
    /// @param _operator The operator address
    function isApprovedForAll(address _owner, address _operator) external view returns (bool) {
        return operatorApprovals[_owner][_operator];
    }

    /// @notice The number of tokens owned
    /// @param _owner The owner address
    function balanceOf(address _owner) public view returns (uint256) {
        if (_owner == address(0)) revert ADDRESS_ZERO();

        return balances[_owner];
    }

    /// @notice The owner of a token
    /// @param _tokenId The ERC-721 token id
    function ownerOf(uint256 _tokenId) public view returns (address) {
        address owner = owners[_tokenId];

        if (owner == address(0)) revert INVALID_OWNER();

        return owner;
    }

    /// @notice Authorizes an account to manage a token
    /// @param _to The account address
    /// @param _tokenId The ERC-721 token id
    function approve(address _to, uint256 _tokenId) external {
        address owner = owners[_tokenId];

        if (msg.sender != owner && !operatorApprovals[owner][msg.sender]) revert INVALID_APPROVAL();

        tokenApprovals[_tokenId] = _to;

        emit Approval(owner, _to, _tokenId);
    }

    /// @notice Authorizes an account to manage all tokens
    /// @param _operator The account address
    /// @param _approved If permission is being given or removed
    function setApprovalForAll(address _operator, bool _approved) external {
        operatorApprovals[msg.sender][_operator] = _approved;

        emit ApprovalForAll(msg.sender, _operator, _approved);
    }

    /// @notice Transfers a token from sender to recipient
    /// @param _from The sender address
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function transferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) public {
        if (_from != owners[_tokenId]) revert INVALID_OWNER();

        if (_to == address(0)) revert ADDRESS_ZERO();

        if (msg.sender != _from && !operatorApprovals[_from][msg.sender] && msg.sender != tokenApprovals[_tokenId]) revert INVALID_APPROVAL();

        _beforeTokenTransfer(_from, _to, _tokenId);

        unchecked {
            --balances[_from];

            ++balances[_to];
        }

        owners[_tokenId] = _to;

        delete tokenApprovals[_tokenId];

        emit Transfer(_from, _to, _tokenId);

        _afterTokenTransfer(_from, _to, _tokenId);
    }

    /// @notice Safe transfers a token from sender to recipient
    /// @param _from The sender address
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) external {
        transferFrom(_from, _to, _tokenId);

        if (
            Address.isContract(_to) &&
            ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, "") != ERC721TokenReceiver.onERC721Received.selector
        ) revert INVALID_RECIPIENT();
    }

    /// @notice Safe transfers a token from sender to recipient with additional data
    /// @param _from The sender address
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId,
        bytes calldata _data
    ) external {
        transferFrom(_from, _to, _tokenId);

        if (
            Address.isContract(_to) &&
            ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) != ERC721TokenReceiver.onERC721Received.selector
        ) revert INVALID_RECIPIENT();
    }

    /// @dev Mints a token to a recipient
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function _mint(address _to, uint256 _tokenId) internal virtual {
        if (_to == address(0)) revert ADDRESS_ZERO();

        if (owners[_tokenId] != address(0)) revert ALREADY_MINTED();

        _beforeTokenTransfer(address(0), _to, _tokenId);

        unchecked {
            ++balances[_to];
        }

        owners[_tokenId] = _to;

        emit Transfer(address(0), _to, _tokenId);

        _afterTokenTransfer(address(0), _to, _tokenId);
    }

    /// @dev Burns a token to a recipient
    /// @param _tokenId The ERC-721 token id
    function _burn(uint256 _tokenId) internal virtual {
        address owner = owners[_tokenId];

        if (owner == address(0)) revert NOT_MINTED();

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

        unchecked {
            --balances[owner];
        }

        delete owners[_tokenId];

        delete tokenApprovals[_tokenId];

        emit Transfer(owner, address(0), _tokenId);

        _afterTokenTransfer(owner, address(0), _tokenId);
    }

    /// @dev Hook called before a token transfer
    /// @param _from The sender address
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function _beforeTokenTransfer(
        address _from,
        address _to,
        uint256 _tokenId
    ) internal virtual {}

    /// @dev Hook called after a token transfer
    /// @param _from The sender address
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function _afterTokenTransfer(
        address _from,
        address _to,
        uint256 _tokenId
    ) internal virtual {}
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IUUPS } from "../interfaces/IUUPS.sol";
import { ERC1967Upgrade } from "./ERC1967Upgrade.sol";

/// @title UUPS
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/utils/UUPSUpgradeable.sol)
/// - Uses custom errors declared in IUUPS
/// - Inherits a modern, minimal ERC1967Upgrade
abstract contract UUPS is IUUPS, ERC1967Upgrade {
    ///                                                          ///
    ///                          IMMUTABLES                      ///
    ///                                                          ///

    /// @dev The address of the implementation
    address private immutable __self = address(this);

    ///                                                          ///
    ///                           MODIFIERS                      ///
    ///                                                          ///

    /// @dev Ensures that execution is via proxy delegatecall with the correct implementation
    modifier onlyProxy() {
        if (address(this) == __self) revert ONLY_DELEGATECALL();
        if (_getImplementation() != __self) revert ONLY_PROXY();
        _;
    }

    /// @dev Ensures that execution is via direct call
    modifier notDelegated() {
        if (address(this) != __self) revert ONLY_CALL();
        _;
    }

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @dev Hook to authorize an implementation upgrade
    /// @param _newImpl The new implementation address
    function _authorizeUpgrade(address _newImpl) internal virtual;

    /// @notice Upgrades to an implementation
    /// @param _newImpl The new implementation address
    function upgradeTo(address _newImpl) external onlyProxy {
        _authorizeUpgrade(_newImpl);
        _upgradeToAndCallUUPS(_newImpl, "", false);
    }

    /// @notice Upgrades to an implementation with an additional function call
    /// @param _newImpl The new implementation address
    /// @param _data The encoded function call
    function upgradeToAndCall(address _newImpl, bytes memory _data) external payable onlyProxy {
        _authorizeUpgrade(_newImpl);
        _upgradeToAndCallUUPS(_newImpl, _data, true);
    }

    /// @notice The storage slot of the implementation address
    function proxiableUUID() external view notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }
}
          

/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IUUPS } from "../lib/interfaces/IUUPS.sol";
import { IERC721Votes } from "../lib/interfaces/IERC721Votes.sol";
import { IManager } from "../manager/IManager.sol";
import { TokenTypesV1 } from "./types/TokenTypesV1.sol";
import { TokenTypesV2 } from "./types/TokenTypesV2.sol";

/// @title IToken
/// @author Rohan Kulkarni
/// @notice The external Token events, errors and functions
interface IToken is IUUPS, IERC721Votes, TokenTypesV1, TokenTypesV2 {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when a token is scheduled to be allocated
    /// @param baseTokenId The
    /// @param founderId The founder's id
    /// @param founder The founder's vesting details
    event MintScheduled(uint256 baseTokenId, uint256 founderId, Founder founder);

    /// @notice Emitted when a token allocation is unscheduled (removed)
    /// @param baseTokenId The token ID % 100
    /// @param founderId The founder's id
    /// @param founder The founder's vesting details
    event MintUnscheduled(uint256 baseTokenId, uint256 founderId, Founder founder);

    /// @notice Emitted when a tokens founders are deleted from storage
    /// @param newFounders the list of founders
    event FounderAllocationsCleared(IManager.FounderParams[] newFounders);

    /// @notice Emitted when minters are updated
    /// @param minter Address of added or removed minter
    /// @param allowed Whether address is allowed to mint
    event MinterUpdated(address minter, bool allowed);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the founder ownership exceeds 100 percent
    error INVALID_FOUNDER_OWNERSHIP();

    /// @dev Reverts if the caller was not the auction contract
    error ONLY_AUCTION();

    /// @dev Reverts if the caller was not a minter
    error ONLY_AUCTION_OR_MINTER();

    /// @dev Reverts if the caller was not the token owner
    error ONLY_TOKEN_OWNER();

    /// @dev Reverts if no metadata was generated upon mint
    error NO_METADATA_GENERATED();

    /// @dev Reverts if the caller was not the contract manager
    error ONLY_MANAGER();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice Initializes a DAO's ERC-721 token
    /// @param founders The founding members to receive vesting allocations
    /// @param initStrings The encoded token and metadata initialization strings
    /// @param metadataRenderer The token's metadata renderer
    /// @param auction The token's auction house
    function initialize(
        IManager.FounderParams[] calldata founders,
        bytes calldata initStrings,
        address metadataRenderer,
        address auction,
        address initialOwner
    ) external;

    /// @notice Mints tokens to the caller and handles founder vesting
    function mint() external returns (uint256 tokenId);

    /// @notice Mints tokens to the recipient and handles founder vesting
    function mintTo(address recipient) external returns (uint256 tokenId);

    /// @notice Mints the specified amount of tokens to the recipient and handles founder vesting
    function mintBatchTo(uint256 amount, address recipient) external returns (uint256[] memory tokenIds);

    /// @notice Burns a token owned by the caller
    /// @param tokenId The ERC-721 token id
    function burn(uint256 tokenId) external;

    /// @notice The URI for a token
    /// @param tokenId The ERC-721 token id
    function tokenURI(uint256 tokenId) external view returns (string memory);

    /// @notice The URI for the contract
    function contractURI() external view returns (string memory);

    /// @notice The number of founders
    function totalFounders() external view returns (uint256);

    /// @notice The founders total percent ownership
    function totalFounderOwnership() external view returns (uint256);

    /// @notice The vesting details of a founder
    /// @param founderId The founder id
    function getFounder(uint256 founderId) external view returns (Founder memory);

    /// @notice The vesting details of all founders
    function getFounders() external view returns (Founder[] memory);

    /// @notice Update the list of allocation owners
    /// @param newFounders the full list of FounderParam structs
    function updateFounders(IManager.FounderParams[] calldata newFounders) external;

    /// @notice The founder scheduled to receive the given token id
    /// NOTE: If a founder is returned, there's no guarantee they'll receive the token as vesting expiration is not considered
    /// @param tokenId The ERC-721 token id
    function getScheduledRecipient(uint256 tokenId) external view returns (Founder memory);

    /// @notice The total supply of tokens
    function totalSupply() external view returns (uint256);

    /// @notice The token's auction house
    function auction() external view returns (address);

    /// @notice The token's metadata renderer
    function metadataRenderer() external view returns (address);

    /// @notice The owner of the token and metadata renderer
    function owner() external view returns (address);

    /// @notice Update minters
    /// @param _minters Array of structs containing address status as a minter
    function updateMinters(MinterParams[] calldata _minters) external;

    /// @notice Check if an address is a minter
    /// @param _minter Address to check
    function isMinter(address _minter) external view returns (bool);

    /// @notice Callback called by auction on first auction started to transfer ownership to treasury from founder
    function onFirstAuctionStarted() external;
}
          

Compiler Settings

{"remappings":[":@openzeppelin/=node_modules/@openzeppelin/",":ds-test/=node_modules/ds-test/src/",":forge-std/=node_modules/forge-std/src/",":micro-onchain-metadata-utils/=node_modules/micro-onchain-metadata-utils/src/",":sol-uriencode/=node_modules/sol-uriencode/",":sol2string/=node_modules/sol2string/"],"optimizer":{"runs":500000,"enabled":true},"metadata":{"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"london","compilationTarget":{"src/token/metadata/MetadataRenderer.sol":"MetadataRenderer"}}
              

Contract ABI

[{"type":"constructor","stateMutability":"payable","inputs":[{"type":"address","name":"_manager","internalType":"address"}]},{"type":"error","name":"ADDRESS_ZERO","inputs":[]},{"type":"error","name":"ALREADY_INITIALIZED","inputs":[]},{"type":"error","name":"DELEGATE_CALL_FAILED","inputs":[]},{"type":"error","name":"INITIALIZING","inputs":[]},{"type":"error","name":"INVALID_PROPERTY_SELECTED","inputs":[{"type":"uint256","name":"selectedPropertyId","internalType":"uint256"}]},{"type":"error","name":"INVALID_TARGET","inputs":[]},{"type":"error","name":"INVALID_UPGRADE","inputs":[{"type":"address","name":"impl","internalType":"address"}]},{"type":"error","name":"NOT_INITIALIZING","inputs":[]},{"type":"error","name":"ONE_PROPERTY_AND_ITEM_REQUIRED","inputs":[]},{"type":"error","name":"ONLY_CALL","inputs":[]},{"type":"error","name":"ONLY_DELEGATECALL","inputs":[]},{"type":"error","name":"ONLY_MANAGER","inputs":[]},{"type":"error","name":"ONLY_OWNER","inputs":[]},{"type":"error","name":"ONLY_PROXY","inputs":[]},{"type":"error","name":"ONLY_TOKEN","inputs":[]},{"type":"error","name":"ONLY_UUPS","inputs":[]},{"type":"error","name":"TOKEN_NOT_MINTED","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"error","name":"TOO_MANY_PROPERTIES","inputs":[]},{"type":"error","name":"UNSUPPORTED_UUID","inputs":[]},{"type":"event","name":"AdditionalTokenPropertiesSet","inputs":[{"type":"tuple[]","name":"_additionalJsonProperties","internalType":"struct MetadataRendererTypesV2.AdditionalTokenProperty[]","indexed":false,"components":[{"type":"string","name":"key","internalType":"string"},{"type":"string","name":"value","internalType":"string"},{"type":"bool","name":"quote","internalType":"bool"}]}],"anonymous":false},{"type":"event","name":"ContractImageUpdated","inputs":[{"type":"string","name":"prevImage","internalType":"string","indexed":false},{"type":"string","name":"newImage","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"DescriptionUpdated","inputs":[{"type":"string","name":"prevDescription","internalType":"string","indexed":false},{"type":"string","name":"newDescription","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint256","name":"version","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"PropertyAdded","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":false},{"type":"string","name":"name","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"RendererBaseUpdated","inputs":[{"type":"string","name":"prevRendererBase","internalType":"string","indexed":false},{"type":"string","name":"newRendererBase","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"type":"address","name":"impl","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"WebsiteURIUpdated","inputs":[{"type":"string","name":"lastURI","internalType":"string","indexed":false},{"type":"string","name":"newURI","internalType":"string","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addProperties","inputs":[{"type":"string[]","name":"_names","internalType":"string[]"},{"type":"tuple[]","name":"_items","internalType":"struct MetadataRendererTypesV1.ItemParam[]","components":[{"type":"uint256","name":"propertyId","internalType":"uint256"},{"type":"string","name":"name","internalType":"string"},{"type":"bool","name":"isNewProperty","internalType":"bool"}]},{"type":"tuple","name":"_ipfsGroup","internalType":"struct MetadataRendererTypesV1.IPFSGroup","components":[{"type":"string","name":"baseUri","internalType":"string"},{"type":"string","name":"extension","internalType":"string"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"attributes","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"contractImage","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"contractURI","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"contractVersion","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deleteAndRecreateProperties","inputs":[{"type":"string[]","name":"_names","internalType":"string[]"},{"type":"tuple[]","name":"_items","internalType":"struct MetadataRendererTypesV1.ItemParam[]","components":[{"type":"uint256","name":"propertyId","internalType":"uint256"},{"type":"string","name":"name","internalType":"string"},{"type":"bool","name":"isNewProperty","internalType":"bool"}]},{"type":"tuple","name":"_ipfsGroup","internalType":"struct MetadataRendererTypesV1.IPFSGroup","components":[{"type":"string","name":"baseUri","internalType":"string"},{"type":"string","name":"extension","internalType":"string"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"description","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"resultAttributes","internalType":"string"},{"type":"string","name":"queryString","internalType":"string"}],"name":"getAttributes","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"bytes","name":"_initStrings","internalType":"bytes"},{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"baseUri","internalType":"string"},{"type":"string","name":"extension","internalType":"string"}],"name":"ipfsData","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ipfsDataCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"itemsCount","inputs":[{"type":"uint256","name":"_propertyId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"onMinted","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"projectURI","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"name","internalType":"string"}],"name":"properties","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"propertiesCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"proxiableUUID","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"rendererBase","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAdditionalTokenProperties","inputs":[{"type":"tuple[]","name":"_additionalTokenProperties","internalType":"struct MetadataRendererTypesV2.AdditionalTokenProperty[]","components":[{"type":"string","name":"key","internalType":"string"},{"type":"string","name":"value","internalType":"string"},{"type":"bool","name":"quote","internalType":"bool"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"token","internalType":"address"},{"type":"string","name":"projectURI","internalType":"string"},{"type":"string","name":"description","internalType":"string"},{"type":"string","name":"contractImage","internalType":"string"},{"type":"string","name":"rendererBase","internalType":"string"}],"name":"settings","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"token","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"tokenURI","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateContractImage","inputs":[{"type":"string","name":"_newContractImage","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateDescription","inputs":[{"type":"string","name":"_newDescription","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateProjectURI","inputs":[{"type":"string","name":"_newProjectURI","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateRendererBase","inputs":[{"type":"string","name":"_newRendererBase","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgradeTo","inputs":[{"type":"address","name":"_newImpl","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"upgradeToAndCall","inputs":[{"type":"address","name":"_newImpl","internalType":"address"},{"type":"bytes","name":"_data","internalType":"bytes"}]}]
              

Contract Creation Code

0x60c060408190523060805262004f533881900390819083398101604081905262000029916200011c565b600054610100900460ff161580158062000047575060005460ff1615155b801562000077575062000065306200011660201b6200245a1760201c565b8062000077575060005460ff16600114155b15620000965760405163439a74c960e01b815260040160405180910390fd5b6000805460ff191660011790558015620000ba576000805461ff0019166101001790555b6001600160a01b03821660a05280156200010e576000805461ff0019169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b50506200014e565b3b151590565b6000602082840312156200012f57600080fd5b81516001600160a01b03811681146200014757600080fd5b9392505050565b60805160a051614dbc620001976000396000818161199601526127ef015260008181610a7a01528181610ad401528181610ff20152818161104c015261113b0152614dbc6000f3fe6080604052600436106101c25760003560e01c80638da5cb5b116100f7578063cce2df0311610095578063eaf1cdf311610064578063eaf1cdf314610517578063ecb12ca814610537578063f7b1080814610557578063fc0c546a1461057757600080fd5b8063cce2df031461049c578063e06174e4146104bc578063e735b48a146104e2578063e8a3d4851461050257600080fd5b8063a802047c116100d1578063a802047c14610432578063b2846b8114610452578063c042f64714610467578063c87b56dd1461047c57600080fd5b80638da5cb5b1461039d5780638eab84ee146103d7578063a0a8e460146103ec57600080fd5b80633659cfe61161016457806352d1902d1161013e57806352d1902d146103315780636e6fb49f146103465780637284e4161461036857806381341fd21461037d57600080fd5b80633659cfe6146102de5780634378a6e3146102fe5780634f1ef2861461031e57600080fd5b8063228b5679116101a0578063228b56791461022d57806325b4e7be146102605780632658fd0a146102905780632b313ab8146102be57600080fd5b80630af1ec7a146101c75780631117b207146101e957806311447e8714610209575b600080fd5b3480156101d357600080fd5b506101e76101e2366004613a0a565b6105a2565b005b3480156101f557600080fd5b506101e7610204366004613a8b565b610643565b34801561021557600080fd5b506006545b6040519081526020015b60405180910390f35b34801561023957600080fd5b5061024d610248366004613b26565b6106c5565b60405161ffff9091168152602001610224565b34801561026c57600080fd5b5061028061027b366004613b48565b610702565b6040519015158152602001610224565b34801561029c57600080fd5b506102b06102ab366004613b48565b610882565b604051610224929190613bcf565b3480156102ca57600080fd5b506101e76102d9366004613a0a565b6109c6565b3480156102ea57600080fd5b506101e76102f9366004613c16565b610a63565b34801561030a57600080fd5b506102b0610319366004613b48565b610bbb565b6101e761032c366004613c33565b610fdb565b34801561033d57600080fd5b5061021a611121565b34801561035257600080fd5b5061035b6111b7565b6040516102249190613c97565b34801561037457600080fd5b5061035b61124b565b34801561038957600080fd5b5061021a610398366004613b48565b61125d565b3480156103a957600080fd5b506103b261128c565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610224565b3480156103e357600080fd5b5061035b611325565b3480156103f857600080fd5b5060408051808201909152600581527f312e322e30000000000000000000000000000000000000000000000000000000602082015261035b565b34801561043e57600080fd5b506101e761044d366004613a8b565b611337565b34801561045e57600080fd5b5061035b61138d565b34801561047357600080fd5b5060075461021a565b34801561048857600080fd5b5061035b610497366004613b48565b61139f565b3480156104a857600080fd5b506101e76104b7366004613caa565b6118b0565b3480156104c857600080fd5b506104d1611afb565b604051610224959493929190613d2d565b3480156104ee57600080fd5b506101e76104fd366004613a0a565b611d53565b34801561050e57600080fd5b5061035b611df0565b34801561052357600080fd5b506101e7610532366004613a0a565b6121b7565b34801561054357600080fd5b506101e7610552366004613db0565b612254565b34801561056357600080fd5b5061035b610572366004613b48565b6123a4565b34801561058357600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166103b2565b336105ab61128c565b73ffffffffffffffffffffffffffffffffffffffff16146105f8576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa4a51e61fd2a8836d039388e309e7301de08bb26931de504cded9cf6e5a90a0e9061062b906004908490613f54565b60405180910390a1600461063f8282614056565b5050565b3361064c61128c565b73ffffffffffffffffffffffffffffffffffffffff1614610699576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106a5600760006136f7565b6106b160066000613718565b6106be8585858585612460565b5050505050565b600860205281600052604060002081601081106106e157600080fd5b60109182820401919006600202915091509054906101000a900461ffff1681565b60015460009073ffffffffffffffffffffffffffffffffffffffff163314610756576040517f3ff0b6ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516020808201859052434082840152416060830152426080808401919091528351808403909101815260a090920183528151918101919091206000858152600890925291812060065490918190036107b657506000949350505050565b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff821617825560005b818110156108765760006006828154811061080257610802614170565b90600052602060002090600202016001018054905090508085816108285761082861419f565b0684836001016010811061083e5761083e614170565b601091828204019190066002026101000a81548161ffff021916908361ffff160217905550601085901c9450508060010190506107e5565b50600195945050505050565b6007818154811061089257600080fd5b90600052602060002090600202016000915090508060000180546108b590613f01565b80601f01602080910402602001604051908101604052809291908181526020018280546108e190613f01565b801561092e5780601f106109035761010080835404028352916020019161092e565b820191906000526020600020905b81548152906001019060200180831161091157829003601f168201915b50505050509080600101805461094390613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461096f90613f01565b80156109bc5780601f10610991576101008083540402835291602001916109bc565b820191906000526020600020905b81548152906001019060200180831161099f57829003601f168201915b5050505050905082565b336109cf61128c565b73ffffffffffffffffffffffffffffffffffffffff1614610a1c576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fcc0881496fc7df5b2e39876ca077298fecc92707f462d28e9fc8f14161b3107390610a4f906002908490613f54565b60405180910390a1600261063f8282614056565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163003610ad2576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16610b477f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614610b94576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b9d81612797565b610bb88160405180602001604052806000815250600061294a565b50565b606080610bc9306014612aa2565b610bd284612cee565b604051602001610be39291906141ce565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181526000868152600860205282812061020085019384905291945092916010908285855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610c3057905050505050509050600081600060108110610c8457610c84614170565b602002015161ffff16905080600003610cd1576040517f531c95b1000000000000000000000000000000000000000000000000000000008152600481018690526024015b60405180910390fd5b60008167ffffffffffffffff811115610cec57610cec6138bf565b604051908082528060200260200182016040528015610d3957816020015b60408051606080820183528082526020820152600091810191909152815260200190600190039081610d0a5790505b50905060005b82811015610fc757600060068281548110610d5c57610d5c614170565b9060005260206000209060020201604051806040016040529081600082018054610d8590613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054610db190613f01565b8015610dfe5780601f10610dd357610100808354040283529160200191610dfe565b820191906000526020600020905b815481529060010190602001808311610de157829003601f168201915b5050505050815260200160018201805480602002602001604051908101604052809291908181526020016000905b82821015610f005760008481526020908190206040805180820190915260028502909101805461ffff1682526001810180549293919291840191610e6f90613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054610e9b90613f01565b8015610ee85780601f10610ebd57610100808354040283529160200191610ee8565b820191906000526020600020905b815481529060010190602001808311610ecb57829003601f168201915b50505050508152505081526020019060010190610e2c565b505050508152505090506000858360010160108110610f2157610f21614170565b602002015161ffff169050600082602001518281518110610f4457610f44614170565b602002602001015190506000858581518110610f6257610f62614170565b6020908102919091018101518551815283820151918101919091526001604082015284519091508990610f96908490612e2b565b604051602001610fa792919061424f565b604051602081830303815290604052985050505050806001019050610d3f565b50610fd181612eb5565b9450505050915091565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016300361104a576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166110bf7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461110c576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61111582612797565b61063f8282600161294a565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611192576040517f575bc92e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b60606001800180546111c890613f01565b80601f01602080910402602001604051908101604052809291908181526020018280546111f490613f01565b80156112415780601f1061121657610100808354040283529160200191611241565b820191906000526020600020905b81548152906001019060200180831161122457829003601f168201915b5050505050905090565b6060600160020180546111c890613f01565b60006006828154811061127257611272614170565b600091825260209091206001600290920201015492915050565b600154604080517f8da5cb5b000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff1691638da5cb5b9160048083019260209291908290030181865afa1580156112fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132091906142a7565b905090565b6060600160030180546111c890613f01565b3361134061128c565b73ffffffffffffffffffffffffffffffffffffffff16146106b1576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060600160040180546111c890613f01565b60606000806113ad84610bbb565b60095491935091506000906113c39060046142f3565b67ffffffffffffffff8111156113db576113db6138bf565b60405190808252806020026020018201604052801561142857816020015b604080516060808201835280825260208201526000918101919091528152602001906001900390816113f95790505b506040805160a081019091526004606082019081527f6e616d650000000000000000000000000000000000000000000000000000000060808301528152909150602081016114746130f5565b61147d88612cee565b60405160200161148e929190614306565b604051602081830303815290604052815260200160011515815250816000815181106114bc576114bc614170565b602002602001018190525060405180606001604052806040518060400160405280600b81526020017f6465736372697074696f6e00000000000000000000000000000000000000000081525081526020016001600201805461151d90613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461154990613f01565b80156115965780601f1061156b57610100808354040283529160200191611596565b820191906000526020600020905b81548152906001019060200180831161157957829003601f168201915b5050505050815260200160011515815250816001815181106115ba576115ba614170565b602002602001018190525060405180606001604052806040518060400160405280600581526020017f696d61676500000000000000000000000000000000000000000000000000000081525081526020016001600401846040516020016116229291906143ef565b6040516020818303038152906040528152602001600115158152508160028151811061165057611650614170565b602002602001018190525060405180606001604052806040518060400160405280600a81526020017f70726f7065727469657300000000000000000000000000000000000000000000815250815260200184815260200160001515815250816003815181106116c1576116c1614170565b602002602001018190525060005b60095481101561189d576000600982815481106116ee576116ee614170565b906000526020600020906003020160405180606001604052908160008201805461171790613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461174390613f01565b80156117905780601f1061176557610100808354040283529160200191611790565b820191906000526020600020905b81548152906001019060200180831161177357829003601f168201915b505050505081526020016001820180546117a990613f01565b80601f01602080910402602001604051908101604052809291908181526020018280546117d590613f01565b80156118225780601f106117f757610100808354040283529160200191611822565b820191906000526020600020905b81548152906001019060200180831161180557829003601f168201915b50505091835250506002919091015460ff16151560209182015260408051606081018252835181528383015192810192909252808301511515908201529091508361186e8460046142f3565b8151811061187e5761187e614170565b602002602001018190525050808061189590614414565b9150506116cf565b506118a7816131ab565b95945050505050565b600054610100900460ff16158015806118cd575060005460ff1615155b80156118e95750303b1515806118e9575060005460ff16600114155b15611920576040517f439a74c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561197e57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146119ed576040517fa2ddd97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080806119fe8789018961444c565b9298509096509450925060029150611a1890508382614056565b506003611a258582614056565b506004611a328482614056565b506005611a3f8282614056565b506002611a4c8382614056565b5050600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716179055505081159050611af557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b50505050565b600180546002805473ffffffffffffffffffffffffffffffffffffffff9092169291611b2690613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054611b5290613f01565b8015611b9f5780601f10611b7457610100808354040283529160200191611b9f565b820191906000526020600020905b815481529060010190602001808311611b8257829003601f168201915b505050505090806002018054611bb490613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054611be090613f01565b8015611c2d5780601f10611c0257610100808354040283529160200191611c2d565b820191906000526020600020905b815481529060010190602001808311611c1057829003601f168201915b505050505090806003018054611c4290613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054611c6e90613f01565b8015611cbb5780601f10611c9057610100808354040283529160200191611cbb565b820191906000526020600020905b815481529060010190602001808311611c9e57829003601f168201915b505050505090806004018054611cd090613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054611cfc90613f01565b8015611d495780601f10611d1e57610100808354040283529160200191611d49565b820191906000526020600020905b815481529060010190602001808311611d2c57829003601f168201915b5050505050905085565b33611d5c61128c565b73ffffffffffffffffffffffffffffffffffffffff1614611da9576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe21432e1fe2b572d5803dd7316b7a854952317b42017f920a616ec70cdb8a5c190611ddc906003908490613f54565b60405180910390a1600361063f8282614056565b60408051600480825260a0820190925260609160009190816020015b60408051606080820183528082526020820152600091810191909152815260200190600190039081611e0c5750506040805160a081019091526004606082019081527f6e616d65000000000000000000000000000000000000000000000000000000006080830152815290915060208101611e856130f5565b81526020016001151581525081600081518110611ea457611ea4614170565b602002602001018190525060405180606001604052806040518060400160405280600b81526020017f6465736372697074696f6e000000000000000000000000000000000000000000815250815260200160016002018054611f0590613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054611f3190613f01565b8015611f7e5780601f10611f5357610100808354040283529160200191611f7e565b820191906000526020600020905b815481529060010190602001808311611f6157829003601f168201915b505050505081526020016001151581525081600181518110611fa257611fa2614170565b602002602001018190525060405180606001604052806040518060400160405280600581526020017f696d61676500000000000000000000000000000000000000000000000000000081525081526020016001600301805461200390613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461202f90613f01565b801561207c5780601f106120515761010080835404028352916020019161207c565b820191906000526020600020905b81548152906001019060200180831161205f57829003601f168201915b5050505050815260200160011515815250816002815181106120a0576120a0614170565b602002602001018190525060405180606001604052806040518060400160405280600c81526020017f65787465726e616c5f75726c0000000000000000000000000000000000000000815250815260200160018001805461210090613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461212c90613f01565b80156121795780601f1061214e57610100808354040283529160200191612179565b820191906000526020600020905b81548152906001019060200180831161215c57829003601f168201915b50505050508152602001600115158152508160038151811061219d5761219d614170565b60200260200101819052506121b1816131ab565b91505090565b336121c061128c565b73ffffffffffffffffffffffffffffffffffffffff161461220d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc5d098cca4f56032ca7e04c4bf7fccc90f26576acaa949a5f67bc9eba4ef414990612240906005908490613f54565b60405180910390a1600561063f8282614056565b3361225d61128c565b73ffffffffffffffffffffffffffffffffffffffff16146122aa576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122b660096000613739565b60005b81518110156123695760098282815181106122d6576122d6614170565b602090810291909101810151825460018101845560009384529190922082516003909202019081906123089082614056565b506020820151600182019061231d9082614056565b5060409190910151600290910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558061236181614414565b9150506122b9565b507fbf5f7405282e2c6b004f386e14b57c8a744e1a3e7f221b9af8031b911f6db59a816040516123999190614541565b60405180910390a150565b600681815481106123b457600080fd5b90600052602060002090600202016000915090508060000180546123d790613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461240390613f01565b80156124505780601f1061242557610100808354040283529160200191612450565b820191906000526020600020905b81548152906001019060200180831161243357829003601f168201915b5050505050905081565b3b151590565b6007805460018101825560009190915281600282027fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688016124a18282614771565b5050600654858460008390036124f3578115806124bc575080155b156124f3576040517f279ec20e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f8284011115612530576040517f8c90470900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82811015612606576006805460010181556000528381018a8a8381811061255c5761255c614170565b905060200281019061256e91906145f2565b6006838154811061258157612581614170565b9060005260206000209060020201600001918261259f929190614657565b507febf63270254042d3527778299325aabb702431e95ad5e9055f4cb3b047ecdccc818c8c858181106125d4576125d4614170565b90506020028101906125e691906145f2565b6040516125f5939291906148ae565b60405180910390a150600101612533565b5060005b8181101561278b57600088888381811061262657612626614170565b90506020028101906126389190614902565b35905088888381811061264d5761264d614170565b905060200281019061265f9190614902565b612670906060810190604001614940565b156126785784015b60065481106126b6576040517f0dfb793000000000000000000000000000000000000000000000000000000000815260048101829052602401610cc8565b6000600682815481106126cb576126cb614170565b60009182526020822060016002909202018101805491820180825581845290935090919083908390811061270157612701614170565b906000526020600020906002020190508b8b8681811061272357612723614170565b90506020028101906127359190614902565b6127439060208101906145f2565b6001830191612753919083614657565b5080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff8a1617905550505060010161260a565b50505050505050505050565b336127a061128c565b73ffffffffffffffffffffffffffffffffffffffff16146127ed576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639bb8dcfd6128677f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084166024820152604401602060405180830381865afa1580156128d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fc919061495d565b610bb8576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610cc8565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156129825761297d836131f4565b505050565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612a07575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612a049181019061497a565b60015b612a3d576040517fc0bb20b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114612a96576040517f0849b49600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061297d8383836132aa565b60606000612ab1836002614993565b612abc9060026142f3565b67ffffffffffffffff811115612ad457612ad46138bf565b6040519080825280601f01601f191660200182016040528015612afe576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612b3557612b35614170565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612b9857612b98614170565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612bd4846002614993565b612bdf9060016142f3565b90505b6001811115612c7c577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612c2057612c20614170565b1a60f81b828281518110612c3657612c36614170565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612c75816149d0565b9050612be2565b508315612ce5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610cc8565b90505b92915050565b606081600003612d3157505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115612d5b5780612d4581614414565b9150612d549050600a83614a05565b9150612d35565b60008167ffffffffffffffff811115612d7657612d766138bf565b6040519080825280601f01601f191660200182016040528015612da0576020820181803683370190505b5090505b8415612e2357612db5600183614a19565b9150612dc2600a86614a2c565b612dcd9060306142f3565b60f81b818381518110612de257612de2614170565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612e1c600a86614a05565b9450612da4565b949350505050565b6060612ce56007846000015161ffff1681548110612e4b57612e4b614170565b90600052602060002090600202016000018385602001516007876000015161ffff1681548110612e7d57612e7d614170565b9060005260206000209060020201600101604051602001612ea19493929190614a40565b6040516020818303038152906040526132cf565b60408051808201909152600181527f7b0000000000000000000000000000000000000000000000000000000000000060208201526000805b83518110156130cc57838181518110612f0857612f08614170565b60200260200101516020015151600003156130ba57838181518110612f2f57612f2f614170565b60200260200101516040015115612ff857828215612f82576040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250612f93565b604051806020016040528060008152505b858381518110612fa557612fa5614170565b602002602001015160000151868481518110612fc357612fc3614170565b602002602001015160200151604051602001612fe29493929190614aa4565b60405160208183030381529060405292506130ac565b82821561303a576040518060400160405280600181526020017f2c0000000000000000000000000000000000000000000000000000000000000081525061304b565b604051806020016040528060008152505b85838151811061305d5761305d614170565b60200260200101516000015186848151811061307b5761307b614170565b60200260200101516020015160405160200161309a9493929190614b59565b60405160208183030381529060405292505b6130b76001836142f3565b91505b806130c481614414565b915050612eed565b50816040516020016130de9190614c04565b604051602081830303815290604052915050919050565b600154604080517f06fdde03000000000000000000000000000000000000000000000000000000008152905160609273ffffffffffffffffffffffffffffffffffffffff16916306fdde039160048083019260009291908290030181865afa158015613165573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526113209190810190614c45565b6060612ce86040518060400160405280601081526020017f6170706c69636174696f6e2f6a736f6e000000000000000000000000000000008152506131ef84612eb5565b61341f565b803b613244576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610cc8565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6132b383613453565b6000825111806132c05750805b1561297d57611af583836134a2565b60408051808201909152601081527f3031323334353637383961626364656600000000000000000000000000000000602082015281516060918391600090613318906003614993565b67ffffffffffffffff811115613330576133306138bf565b6040519080825280601f01601f19166020018201604052801561335a576020820181803683370190505b5090506001820160208201600085865187015b808210156134105760018201915060ff825116607e8114602d821417605f8214602e83141717603a8210602f83111617605b82106040831116176086821060608311161780600181146133c55780156133d957613408565b828753600187019650600186019550613408565b602587536001870196508260041c8801518753600187019650600f831688015187536001870196506003860195505b50505061336d565b50508352509095945050505050565b60608261342b83613553565b60405160200161343c929190614cb3565b604051602081830303815290604052905092915050565b61345c816131f4565b60405173ffffffffffffffffffffffffffffffffffffffff821681527fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90602001612399565b6060823b6134dc576040517f37f2022900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff16846040516135049190614d34565b600060405180830381855af49150503d806000811461353f576040519150601f19603f3d011682016040523d82523d6000602084013e613544565b606091505b50915091506118a782826136a6565b6060815160000361357257505060408051602081019091526000815290565b6000604051806060016040528060408152602001614d4760409139905060006003845160026135a191906142f3565b6135ab9190614a05565b6135b6906004614993565b67ffffffffffffffff8111156135ce576135ce6138bf565b6040519080825280601f01601f1916602001820160405280156135f8576020820181803683370190505b509050600182016020820185865187015b80821015613664576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250613609565b505060038651066001811461368057600281146136935761369b565b603d6001830353603d600283035361369b565b603d60018303535b509195945050505050565b606082156136b5575080612ce8565b8151156136c55781518083602001fd5b6040517f62536b1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5080546000825560020290600052602060002090810190610bb8919061375a565b5080546000825560020290600052602060002090810190610bb89190613789565b5080546000825560030290600052602060002090810190610bb891906137b4565b8082111561378557600061376e8282613809565b61377c600183016000613809565b5060020161375a565b5090565b8082111561378557600061379d8282613809565b6137ab600183016000613843565b50600201613789565b808211156137855760006137c88282613809565b6137d6600183016000613809565b506002810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556003016137b4565b50805461381590613f01565b6000825580601f10613825575050565b601f016020900490600052602060002090810190610bb89190613864565b5080546000825560020290600052602060002090810190610bb89190613879565b5b808211156137855760008155600101613865565b808211156137855780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016815560006138b66001830182613809565b50600201613879565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715613911576139116138bf565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561395e5761395e6138bf565b604052919050565b600067ffffffffffffffff821115613980576139806138bf565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60006139bf6139ba84613966565b613917565b90508281528383830111156139d357600080fd5b828260208301376000602084830101529392505050565b600082601f8301126139fb57600080fd5b612ce5838335602085016139ac565b600060208284031215613a1c57600080fd5b813567ffffffffffffffff811115613a3357600080fd5b612e23848285016139ea565b60008083601f840112613a5157600080fd5b50813567ffffffffffffffff811115613a6957600080fd5b6020830191508360208260051b8501011115613a8457600080fd5b9250929050565b600080600080600060608688031215613aa357600080fd5b853567ffffffffffffffff80821115613abb57600080fd5b613ac789838a01613a3f565b90975095506020880135915080821115613ae057600080fd5b613aec89838a01613a3f565b90955093506040880135915080821115613b0557600080fd5b50860160408189031215613b1857600080fd5b809150509295509295909350565b60008060408385031215613b3957600080fd5b50508035926020909101359150565b600060208284031215613b5a57600080fd5b5035919050565b60005b83811015613b7c578181015183820152602001613b64565b50506000910152565b60008151808452613b9d816020860160208601613b61565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b604081526000613be26040830185613b85565b82810360208401526118a78185613b85565b73ffffffffffffffffffffffffffffffffffffffff81168114610bb857600080fd5b600060208284031215613c2857600080fd5b8135612ce581613bf4565b60008060408385031215613c4657600080fd5b8235613c5181613bf4565b9150602083013567ffffffffffffffff811115613c6d57600080fd5b8301601f81018513613c7e57600080fd5b613c8d858235602084016139ac565b9150509250929050565b602081526000612ce56020830184613b85565b600080600060408486031215613cbf57600080fd5b833567ffffffffffffffff80821115613cd757600080fd5b818601915086601f830112613ceb57600080fd5b813581811115613cfa57600080fd5b876020828501011115613d0c57600080fd5b60209283019550935050840135613d2281613bf4565b809150509250925092565b73ffffffffffffffffffffffffffffffffffffffff8616815260a060208201526000613d5c60a0830187613b85565b8281036040840152613d6e8187613b85565b90508281036060840152613d828186613b85565b90508281036080840152613d968185613b85565b98975050505050505050565b8015158114610bb857600080fd5b60006020808385031215613dc357600080fd5b823567ffffffffffffffff80821115613ddb57600080fd5b818501915085601f830112613def57600080fd5b813581811115613e0157613e016138bf565b8060051b613e10858201613917565b9182528381018501918581019089841115613e2a57600080fd5b86860192505b83831015613ef457823585811115613e485760008081fd5b86016060818c037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001811315613e7e5760008081fd5b613e866138ee565b8983013588811115613e985760008081fd5b613ea68e8c838701016139ea565b82525060408084013589811115613ebd5760008081fd5b613ecb8f8d838801016139ea565b838d0152509282013592613ede84613da2565b8101929092525082529186019190860190613e30565b9998505050505050505050565b600181811c90821680613f1557607f821691505b602082108103613f4e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b604081526000808454613f6681613f01565b8060408601526060600180841660008114613f885760018114613fc057613ff1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550613ff1565b8960005260208060002060005b86811015613fe85781548b8201870152908401908201613fcd565b8a018501975050505b505050505082810360208401526118a78185613b85565b601f82111561297d57600081815260208120601f850160051c8101602086101561402f5750805b601f850160051c820191505b8181101561404e5782815560010161403b565b505050505050565b815167ffffffffffffffff811115614070576140706138bf565b6140848161407e8454613f01565b84614008565b602080601f8311600181146140d757600084156140a15750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561404e565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561412457888601518255948401946001909101908401614105565b508582101561416057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f3f636f6e7472616374416464726573733d000000000000000000000000000000815260008351614206816011850160208801613b61565b7f26746f6b656e49643d0000000000000000000000000000000000000000000000601191840191820152835161424381601a840160208801613b61565b01601a01949350505050565b60008351614261818460208801613b61565b7f26696d616765733d000000000000000000000000000000000000000000000000908301908152835161429b816008840160208801613b61565b01600801949350505050565b6000602082840312156142b957600080fd5b8151612ce581613bf4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115612ce857612ce86142c4565b60008351614318818460208801613b61565b7f20230000000000000000000000000000000000000000000000000000000000009083019081528351614352816002840160208801613b61565b01600201949350505050565b6000815461436b81613f01565b6001828116801561438357600181146143b6576143e5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506143e5565b8560005260208060002060005b858110156143dc5781548a8201529084019082016143c3565b50505082870194505b5050505092915050565b60006143fb828561435e565b835161440b818360208801613b61565b01949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614445576144456142c4565b5060010190565b60008060008060008060c0878903121561446557600080fd5b863567ffffffffffffffff8082111561447d57600080fd5b6144898a838b016139ea565b9750602089013591508082111561449f57600080fd5b6144ab8a838b016139ea565b965060408901359150808211156144c157600080fd5b6144cd8a838b016139ea565b955060608901359150808211156144e357600080fd5b6144ef8a838b016139ea565b9450608089013591508082111561450557600080fd5b6145118a838b016139ea565b935060a089013591508082111561452757600080fd5b5061453489828a016139ea565b9150509295509295509295565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156145e4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08984030185528151606081518186526145ac82870182613b85565b915050888201518582038a8701526145c48282613b85565b928901511515958901959095525094870194925090860190600101614568565b509098975050505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261462757600080fd5b83018035915067ffffffffffffffff82111561464257600080fd5b602001915036819003821315613a8457600080fd5b67ffffffffffffffff83111561466f5761466f6138bf565b6146838361467d8354613f01565b83614008565b6000601f8411600181146146d5576000851561469f5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556106be565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156147245786850135825560209485019460019092019101614704565b508682101561475f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b61477b82836145f2565b67ffffffffffffffff811115614793576147936138bf565b6147a7816147a18554613f01565b85614008565b6000601f8211600181146147f957600083156147c35750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b17855561488f565b6000858152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0841690835b828110156148485786850135825560209485019460019092019101614828565b5084821015614883577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88660031b161c19848701351681555b505060018360011b0185555b505050506148a060208301836145f2565b611af5818360018601614657565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261493657600080fd5b9190910192915050565b60006020828403121561495257600080fd5b8135612ce581613da2565b60006020828403121561496f57600080fd5b8151612ce581613da2565b60006020828403121561498c57600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156149cb576149cb6142c4565b500290565b6000816149df576149df6142c4565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600082614a1457614a1461419f565b500490565b81810381811115612ce857612ce86142c4565b600082614a3b57614a3b61419f565b500690565b6000614a4c828761435e565b8551614a5c818360208a01613b61565b7f2f0000000000000000000000000000000000000000000000000000000000000091019081528451614a95816001840160208901613b61565b613d966001828401018661435e565b60008551614ab6818460208a01613b61565b855190830190614aca818360208a01613b61565b7f220000000000000000000000000000000000000000000000000000000000000091018181528551909190614b06816001850160208a01613b61565b7f223a202200000000000000000000000000000000000000000000000000000000600193909101928301528451614b44816005850160208901613b61565b60059201918201526006019695505050505050565b60008551614b6b818460208a01613b61565b855190830190614b7f818360208a01613b61565b7f220000000000000000000000000000000000000000000000000000000000000091019081528451614bb8816001840160208901613b61565b7f223a200000000000000000000000000000000000000000000000000000000000600192909101918201528351614bf6816004840160208801613b61565b016004019695505050505050565b60008251614c16818460208701613b61565b7f7d00000000000000000000000000000000000000000000000000000000000000920191825250600101919050565b600060208284031215614c5757600080fd5b815167ffffffffffffffff811115614c6e57600080fd5b8201601f81018413614c7f57600080fd5b8051614c8d6139ba82613966565b818152856020838501011115614ca257600080fd5b6118a7826020830160208601613b61565b7f646174613a000000000000000000000000000000000000000000000000000000815260008351614ceb816005850160208801613b61565b7f3b6261736536342c0000000000000000000000000000000000000000000000006005918401918201528351614d2881600d840160208801613b61565b01600d01949350505050565b60008251614936818460208701613b6156fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122021bd4085e21d7ea8312d8a669802ee4a5e946121e844a34dac1876a9474eca5564736f6c63430008100033000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da7174

Deployed ByteCode

0x6080604052600436106101c25760003560e01c80638da5cb5b116100f7578063cce2df0311610095578063eaf1cdf311610064578063eaf1cdf314610517578063ecb12ca814610537578063f7b1080814610557578063fc0c546a1461057757600080fd5b8063cce2df031461049c578063e06174e4146104bc578063e735b48a146104e2578063e8a3d4851461050257600080fd5b8063a802047c116100d1578063a802047c14610432578063b2846b8114610452578063c042f64714610467578063c87b56dd1461047c57600080fd5b80638da5cb5b1461039d5780638eab84ee146103d7578063a0a8e460146103ec57600080fd5b80633659cfe61161016457806352d1902d1161013e57806352d1902d146103315780636e6fb49f146103465780637284e4161461036857806381341fd21461037d57600080fd5b80633659cfe6146102de5780634378a6e3146102fe5780634f1ef2861461031e57600080fd5b8063228b5679116101a0578063228b56791461022d57806325b4e7be146102605780632658fd0a146102905780632b313ab8146102be57600080fd5b80630af1ec7a146101c75780631117b207146101e957806311447e8714610209575b600080fd5b3480156101d357600080fd5b506101e76101e2366004613a0a565b6105a2565b005b3480156101f557600080fd5b506101e7610204366004613a8b565b610643565b34801561021557600080fd5b506006545b6040519081526020015b60405180910390f35b34801561023957600080fd5b5061024d610248366004613b26565b6106c5565b60405161ffff9091168152602001610224565b34801561026c57600080fd5b5061028061027b366004613b48565b610702565b6040519015158152602001610224565b34801561029c57600080fd5b506102b06102ab366004613b48565b610882565b604051610224929190613bcf565b3480156102ca57600080fd5b506101e76102d9366004613a0a565b6109c6565b3480156102ea57600080fd5b506101e76102f9366004613c16565b610a63565b34801561030a57600080fd5b506102b0610319366004613b48565b610bbb565b6101e761032c366004613c33565b610fdb565b34801561033d57600080fd5b5061021a611121565b34801561035257600080fd5b5061035b6111b7565b6040516102249190613c97565b34801561037457600080fd5b5061035b61124b565b34801561038957600080fd5b5061021a610398366004613b48565b61125d565b3480156103a957600080fd5b506103b261128c565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610224565b3480156103e357600080fd5b5061035b611325565b3480156103f857600080fd5b5060408051808201909152600581527f312e322e30000000000000000000000000000000000000000000000000000000602082015261035b565b34801561043e57600080fd5b506101e761044d366004613a8b565b611337565b34801561045e57600080fd5b5061035b61138d565b34801561047357600080fd5b5060075461021a565b34801561048857600080fd5b5061035b610497366004613b48565b61139f565b3480156104a857600080fd5b506101e76104b7366004613caa565b6118b0565b3480156104c857600080fd5b506104d1611afb565b604051610224959493929190613d2d565b3480156104ee57600080fd5b506101e76104fd366004613a0a565b611d53565b34801561050e57600080fd5b5061035b611df0565b34801561052357600080fd5b506101e7610532366004613a0a565b6121b7565b34801561054357600080fd5b506101e7610552366004613db0565b612254565b34801561056357600080fd5b5061035b610572366004613b48565b6123a4565b34801561058357600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166103b2565b336105ab61128c565b73ffffffffffffffffffffffffffffffffffffffff16146105f8576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa4a51e61fd2a8836d039388e309e7301de08bb26931de504cded9cf6e5a90a0e9061062b906004908490613f54565b60405180910390a1600461063f8282614056565b5050565b3361064c61128c565b73ffffffffffffffffffffffffffffffffffffffff1614610699576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106a5600760006136f7565b6106b160066000613718565b6106be8585858585612460565b5050505050565b600860205281600052604060002081601081106106e157600080fd5b60109182820401919006600202915091509054906101000a900461ffff1681565b60015460009073ffffffffffffffffffffffffffffffffffffffff163314610756576040517f3ff0b6ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516020808201859052434082840152416060830152426080808401919091528351808403909101815260a090920183528151918101919091206000858152600890925291812060065490918190036107b657506000949350505050565b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff821617825560005b818110156108765760006006828154811061080257610802614170565b90600052602060002090600202016001018054905090508085816108285761082861419f565b0684836001016010811061083e5761083e614170565b601091828204019190066002026101000a81548161ffff021916908361ffff160217905550601085901c9450508060010190506107e5565b50600195945050505050565b6007818154811061089257600080fd5b90600052602060002090600202016000915090508060000180546108b590613f01565b80601f01602080910402602001604051908101604052809291908181526020018280546108e190613f01565b801561092e5780601f106109035761010080835404028352916020019161092e565b820191906000526020600020905b81548152906001019060200180831161091157829003601f168201915b50505050509080600101805461094390613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461096f90613f01565b80156109bc5780601f10610991576101008083540402835291602001916109bc565b820191906000526020600020905b81548152906001019060200180831161099f57829003601f168201915b5050505050905082565b336109cf61128c565b73ffffffffffffffffffffffffffffffffffffffff1614610a1c576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fcc0881496fc7df5b2e39876ca077298fecc92707f462d28e9fc8f14161b3107390610a4f906002908490613f54565b60405180910390a1600261063f8282614056565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005a28eef0ed8cce44cda9d7097ecce041bb51b9d4163003610ad2576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000005a28eef0ed8cce44cda9d7097ecce041bb51b9d473ffffffffffffffffffffffffffffffffffffffff16610b477f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614610b94576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b9d81612797565b610bb88160405180602001604052806000815250600061294a565b50565b606080610bc9306014612aa2565b610bd284612cee565b604051602001610be39291906141ce565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181526000868152600860205282812061020085019384905291945092916010908285855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610c3057905050505050509050600081600060108110610c8457610c84614170565b602002015161ffff16905080600003610cd1576040517f531c95b1000000000000000000000000000000000000000000000000000000008152600481018690526024015b60405180910390fd5b60008167ffffffffffffffff811115610cec57610cec6138bf565b604051908082528060200260200182016040528015610d3957816020015b60408051606080820183528082526020820152600091810191909152815260200190600190039081610d0a5790505b50905060005b82811015610fc757600060068281548110610d5c57610d5c614170565b9060005260206000209060020201604051806040016040529081600082018054610d8590613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054610db190613f01565b8015610dfe5780601f10610dd357610100808354040283529160200191610dfe565b820191906000526020600020905b815481529060010190602001808311610de157829003601f168201915b5050505050815260200160018201805480602002602001604051908101604052809291908181526020016000905b82821015610f005760008481526020908190206040805180820190915260028502909101805461ffff1682526001810180549293919291840191610e6f90613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054610e9b90613f01565b8015610ee85780601f10610ebd57610100808354040283529160200191610ee8565b820191906000526020600020905b815481529060010190602001808311610ecb57829003601f168201915b50505050508152505081526020019060010190610e2c565b505050508152505090506000858360010160108110610f2157610f21614170565b602002015161ffff169050600082602001518281518110610f4457610f44614170565b602002602001015190506000858581518110610f6257610f62614170565b6020908102919091018101518551815283820151918101919091526001604082015284519091508990610f96908490612e2b565b604051602001610fa792919061424f565b604051602081830303815290604052985050505050806001019050610d3f565b50610fd181612eb5565b9450505050915091565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005a28eef0ed8cce44cda9d7097ecce041bb51b9d416300361104a576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000005a28eef0ed8cce44cda9d7097ecce041bb51b9d473ffffffffffffffffffffffffffffffffffffffff166110bf7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461110c576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61111582612797565b61063f8282600161294a565b60003073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005a28eef0ed8cce44cda9d7097ecce041bb51b9d41614611192576040517f575bc92e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b60606001800180546111c890613f01565b80601f01602080910402602001604051908101604052809291908181526020018280546111f490613f01565b80156112415780601f1061121657610100808354040283529160200191611241565b820191906000526020600020905b81548152906001019060200180831161122457829003601f168201915b5050505050905090565b6060600160020180546111c890613f01565b60006006828154811061127257611272614170565b600091825260209091206001600290920201015492915050565b600154604080517f8da5cb5b000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff1691638da5cb5b9160048083019260209291908290030181865afa1580156112fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132091906142a7565b905090565b6060600160030180546111c890613f01565b3361134061128c565b73ffffffffffffffffffffffffffffffffffffffff16146106b1576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060600160040180546111c890613f01565b60606000806113ad84610bbb565b60095491935091506000906113c39060046142f3565b67ffffffffffffffff8111156113db576113db6138bf565b60405190808252806020026020018201604052801561142857816020015b604080516060808201835280825260208201526000918101919091528152602001906001900390816113f95790505b506040805160a081019091526004606082019081527f6e616d650000000000000000000000000000000000000000000000000000000060808301528152909150602081016114746130f5565b61147d88612cee565b60405160200161148e929190614306565b604051602081830303815290604052815260200160011515815250816000815181106114bc576114bc614170565b602002602001018190525060405180606001604052806040518060400160405280600b81526020017f6465736372697074696f6e00000000000000000000000000000000000000000081525081526020016001600201805461151d90613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461154990613f01565b80156115965780601f1061156b57610100808354040283529160200191611596565b820191906000526020600020905b81548152906001019060200180831161157957829003601f168201915b5050505050815260200160011515815250816001815181106115ba576115ba614170565b602002602001018190525060405180606001604052806040518060400160405280600581526020017f696d61676500000000000000000000000000000000000000000000000000000081525081526020016001600401846040516020016116229291906143ef565b6040516020818303038152906040528152602001600115158152508160028151811061165057611650614170565b602002602001018190525060405180606001604052806040518060400160405280600a81526020017f70726f7065727469657300000000000000000000000000000000000000000000815250815260200184815260200160001515815250816003815181106116c1576116c1614170565b602002602001018190525060005b60095481101561189d576000600982815481106116ee576116ee614170565b906000526020600020906003020160405180606001604052908160008201805461171790613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461174390613f01565b80156117905780601f1061176557610100808354040283529160200191611790565b820191906000526020600020905b81548152906001019060200180831161177357829003601f168201915b505050505081526020016001820180546117a990613f01565b80601f01602080910402602001604051908101604052809291908181526020018280546117d590613f01565b80156118225780601f106117f757610100808354040283529160200191611822565b820191906000526020600020905b81548152906001019060200180831161180557829003601f168201915b50505091835250506002919091015460ff16151560209182015260408051606081018252835181528383015192810192909252808301511515908201529091508361186e8460046142f3565b8151811061187e5761187e614170565b602002602001018190525050808061189590614414565b9150506116cf565b506118a7816131ab565b95945050505050565b600054610100900460ff16158015806118cd575060005460ff1615155b80156118e95750303b1515806118e9575060005460ff16600114155b15611920576040517f439a74c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561197e57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da717416146119ed576040517fa2ddd97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080806119fe8789018961444c565b9298509096509450925060029150611a1890508382614056565b506003611a258582614056565b506004611a328482614056565b506005611a3f8282614056565b506002611a4c8382614056565b5050600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716179055505081159050611af557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b50505050565b600180546002805473ffffffffffffffffffffffffffffffffffffffff9092169291611b2690613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054611b5290613f01565b8015611b9f5780601f10611b7457610100808354040283529160200191611b9f565b820191906000526020600020905b815481529060010190602001808311611b8257829003601f168201915b505050505090806002018054611bb490613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054611be090613f01565b8015611c2d5780601f10611c0257610100808354040283529160200191611c2d565b820191906000526020600020905b815481529060010190602001808311611c1057829003601f168201915b505050505090806003018054611c4290613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054611c6e90613f01565b8015611cbb5780601f10611c9057610100808354040283529160200191611cbb565b820191906000526020600020905b815481529060010190602001808311611c9e57829003601f168201915b505050505090806004018054611cd090613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054611cfc90613f01565b8015611d495780601f10611d1e57610100808354040283529160200191611d49565b820191906000526020600020905b815481529060010190602001808311611d2c57829003601f168201915b5050505050905085565b33611d5c61128c565b73ffffffffffffffffffffffffffffffffffffffff1614611da9576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe21432e1fe2b572d5803dd7316b7a854952317b42017f920a616ec70cdb8a5c190611ddc906003908490613f54565b60405180910390a1600361063f8282614056565b60408051600480825260a0820190925260609160009190816020015b60408051606080820183528082526020820152600091810191909152815260200190600190039081611e0c5750506040805160a081019091526004606082019081527f6e616d65000000000000000000000000000000000000000000000000000000006080830152815290915060208101611e856130f5565b81526020016001151581525081600081518110611ea457611ea4614170565b602002602001018190525060405180606001604052806040518060400160405280600b81526020017f6465736372697074696f6e000000000000000000000000000000000000000000815250815260200160016002018054611f0590613f01565b80601f0160208091040260200160405190810160405280929190818152602001828054611f3190613f01565b8015611f7e5780601f10611f5357610100808354040283529160200191611f7e565b820191906000526020600020905b815481529060010190602001808311611f6157829003601f168201915b505050505081526020016001151581525081600181518110611fa257611fa2614170565b602002602001018190525060405180606001604052806040518060400160405280600581526020017f696d61676500000000000000000000000000000000000000000000000000000081525081526020016001600301805461200390613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461202f90613f01565b801561207c5780601f106120515761010080835404028352916020019161207c565b820191906000526020600020905b81548152906001019060200180831161205f57829003601f168201915b5050505050815260200160011515815250816002815181106120a0576120a0614170565b602002602001018190525060405180606001604052806040518060400160405280600c81526020017f65787465726e616c5f75726c0000000000000000000000000000000000000000815250815260200160018001805461210090613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461212c90613f01565b80156121795780601f1061214e57610100808354040283529160200191612179565b820191906000526020600020905b81548152906001019060200180831161215c57829003601f168201915b50505050508152602001600115158152508160038151811061219d5761219d614170565b60200260200101819052506121b1816131ab565b91505090565b336121c061128c565b73ffffffffffffffffffffffffffffffffffffffff161461220d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc5d098cca4f56032ca7e04c4bf7fccc90f26576acaa949a5f67bc9eba4ef414990612240906005908490613f54565b60405180910390a1600561063f8282614056565b3361225d61128c565b73ffffffffffffffffffffffffffffffffffffffff16146122aa576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122b660096000613739565b60005b81518110156123695760098282815181106122d6576122d6614170565b602090810291909101810151825460018101845560009384529190922082516003909202019081906123089082614056565b506020820151600182019061231d9082614056565b5060409190910151600290910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558061236181614414565b9150506122b9565b507fbf5f7405282e2c6b004f386e14b57c8a744e1a3e7f221b9af8031b911f6db59a816040516123999190614541565b60405180910390a150565b600681815481106123b457600080fd5b90600052602060002090600202016000915090508060000180546123d790613f01565b80601f016020809104026020016040519081016040528092919081815260200182805461240390613f01565b80156124505780601f1061242557610100808354040283529160200191612450565b820191906000526020600020905b81548152906001019060200180831161243357829003601f168201915b5050505050905081565b3b151590565b6007805460018101825560009190915281600282027fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688016124a18282614771565b5050600654858460008390036124f3578115806124bc575080155b156124f3576040517f279ec20e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f8284011115612530576040517f8c90470900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82811015612606576006805460010181556000528381018a8a8381811061255c5761255c614170565b905060200281019061256e91906145f2565b6006838154811061258157612581614170565b9060005260206000209060020201600001918261259f929190614657565b507febf63270254042d3527778299325aabb702431e95ad5e9055f4cb3b047ecdccc818c8c858181106125d4576125d4614170565b90506020028101906125e691906145f2565b6040516125f5939291906148ae565b60405180910390a150600101612533565b5060005b8181101561278b57600088888381811061262657612626614170565b90506020028101906126389190614902565b35905088888381811061264d5761264d614170565b905060200281019061265f9190614902565b612670906060810190604001614940565b156126785784015b60065481106126b6576040517f0dfb793000000000000000000000000000000000000000000000000000000000815260048101829052602401610cc8565b6000600682815481106126cb576126cb614170565b60009182526020822060016002909202018101805491820180825581845290935090919083908390811061270157612701614170565b906000526020600020906002020190508b8b8681811061272357612723614170565b90506020028101906127359190614902565b6127439060208101906145f2565b6001830191612753919083614657565b5080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff8a1617905550505060010161260a565b50505050505050505050565b336127a061128c565b73ffffffffffffffffffffffffffffffffffffffff16146127ed576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da717473ffffffffffffffffffffffffffffffffffffffff16639bb8dcfd6128677f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084166024820152604401602060405180830381865afa1580156128d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fc919061495d565b610bb8576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610cc8565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156129825761297d836131f4565b505050565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612a07575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612a049181019061497a565b60015b612a3d576040517fc0bb20b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114612a96576040517f0849b49600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061297d8383836132aa565b60606000612ab1836002614993565b612abc9060026142f3565b67ffffffffffffffff811115612ad457612ad46138bf565b6040519080825280601f01601f191660200182016040528015612afe576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612b3557612b35614170565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612b9857612b98614170565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612bd4846002614993565b612bdf9060016142f3565b90505b6001811115612c7c577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612c2057612c20614170565b1a60f81b828281518110612c3657612c36614170565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612c75816149d0565b9050612be2565b508315612ce5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610cc8565b90505b92915050565b606081600003612d3157505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115612d5b5780612d4581614414565b9150612d549050600a83614a05565b9150612d35565b60008167ffffffffffffffff811115612d7657612d766138bf565b6040519080825280601f01601f191660200182016040528015612da0576020820181803683370190505b5090505b8415612e2357612db5600183614a19565b9150612dc2600a86614a2c565b612dcd9060306142f3565b60f81b818381518110612de257612de2614170565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612e1c600a86614a05565b9450612da4565b949350505050565b6060612ce56007846000015161ffff1681548110612e4b57612e4b614170565b90600052602060002090600202016000018385602001516007876000015161ffff1681548110612e7d57612e7d614170565b9060005260206000209060020201600101604051602001612ea19493929190614a40565b6040516020818303038152906040526132cf565b60408051808201909152600181527f7b0000000000000000000000000000000000000000000000000000000000000060208201526000805b83518110156130cc57838181518110612f0857612f08614170565b60200260200101516020015151600003156130ba57838181518110612f2f57612f2f614170565b60200260200101516040015115612ff857828215612f82576040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250612f93565b604051806020016040528060008152505b858381518110612fa557612fa5614170565b602002602001015160000151868481518110612fc357612fc3614170565b602002602001015160200151604051602001612fe29493929190614aa4565b60405160208183030381529060405292506130ac565b82821561303a576040518060400160405280600181526020017f2c0000000000000000000000000000000000000000000000000000000000000081525061304b565b604051806020016040528060008152505b85838151811061305d5761305d614170565b60200260200101516000015186848151811061307b5761307b614170565b60200260200101516020015160405160200161309a9493929190614b59565b60405160208183030381529060405292505b6130b76001836142f3565b91505b806130c481614414565b915050612eed565b50816040516020016130de9190614c04565b604051602081830303815290604052915050919050565b600154604080517f06fdde03000000000000000000000000000000000000000000000000000000008152905160609273ffffffffffffffffffffffffffffffffffffffff16916306fdde039160048083019260009291908290030181865afa158015613165573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526113209190810190614c45565b6060612ce86040518060400160405280601081526020017f6170706c69636174696f6e2f6a736f6e000000000000000000000000000000008152506131ef84612eb5565b61341f565b803b613244576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610cc8565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6132b383613453565b6000825111806132c05750805b1561297d57611af583836134a2565b60408051808201909152601081527f3031323334353637383961626364656600000000000000000000000000000000602082015281516060918391600090613318906003614993565b67ffffffffffffffff811115613330576133306138bf565b6040519080825280601f01601f19166020018201604052801561335a576020820181803683370190505b5090506001820160208201600085865187015b808210156134105760018201915060ff825116607e8114602d821417605f8214602e83141717603a8210602f83111617605b82106040831116176086821060608311161780600181146133c55780156133d957613408565b828753600187019650600186019550613408565b602587536001870196508260041c8801518753600187019650600f831688015187536001870196506003860195505b50505061336d565b50508352509095945050505050565b60608261342b83613553565b60405160200161343c929190614cb3565b604051602081830303815290604052905092915050565b61345c816131f4565b60405173ffffffffffffffffffffffffffffffffffffffff821681527fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90602001612399565b6060823b6134dc576040517f37f2022900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff16846040516135049190614d34565b600060405180830381855af49150503d806000811461353f576040519150601f19603f3d011682016040523d82523d6000602084013e613544565b606091505b50915091506118a782826136a6565b6060815160000361357257505060408051602081019091526000815290565b6000604051806060016040528060408152602001614d4760409139905060006003845160026135a191906142f3565b6135ab9190614a05565b6135b6906004614993565b67ffffffffffffffff8111156135ce576135ce6138bf565b6040519080825280601f01601f1916602001820160405280156135f8576020820181803683370190505b509050600182016020820185865187015b80821015613664576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250613609565b505060038651066001811461368057600281146136935761369b565b603d6001830353603d600283035361369b565b603d60018303535b509195945050505050565b606082156136b5575080612ce8565b8151156136c55781518083602001fd5b6040517f62536b1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5080546000825560020290600052602060002090810190610bb8919061375a565b5080546000825560020290600052602060002090810190610bb89190613789565b5080546000825560030290600052602060002090810190610bb891906137b4565b8082111561378557600061376e8282613809565b61377c600183016000613809565b5060020161375a565b5090565b8082111561378557600061379d8282613809565b6137ab600183016000613843565b50600201613789565b808211156137855760006137c88282613809565b6137d6600183016000613809565b506002810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556003016137b4565b50805461381590613f01565b6000825580601f10613825575050565b601f016020900490600052602060002090810190610bb89190613864565b5080546000825560020290600052602060002090810190610bb89190613879565b5b808211156137855760008155600101613865565b808211156137855780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016815560006138b66001830182613809565b50600201613879565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715613911576139116138bf565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561395e5761395e6138bf565b604052919050565b600067ffffffffffffffff821115613980576139806138bf565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60006139bf6139ba84613966565b613917565b90508281528383830111156139d357600080fd5b828260208301376000602084830101529392505050565b600082601f8301126139fb57600080fd5b612ce5838335602085016139ac565b600060208284031215613a1c57600080fd5b813567ffffffffffffffff811115613a3357600080fd5b612e23848285016139ea565b60008083601f840112613a5157600080fd5b50813567ffffffffffffffff811115613a6957600080fd5b6020830191508360208260051b8501011115613a8457600080fd5b9250929050565b600080600080600060608688031215613aa357600080fd5b853567ffffffffffffffff80821115613abb57600080fd5b613ac789838a01613a3f565b90975095506020880135915080821115613ae057600080fd5b613aec89838a01613a3f565b90955093506040880135915080821115613b0557600080fd5b50860160408189031215613b1857600080fd5b809150509295509295909350565b60008060408385031215613b3957600080fd5b50508035926020909101359150565b600060208284031215613b5a57600080fd5b5035919050565b60005b83811015613b7c578181015183820152602001613b64565b50506000910152565b60008151808452613b9d816020860160208601613b61565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b604081526000613be26040830185613b85565b82810360208401526118a78185613b85565b73ffffffffffffffffffffffffffffffffffffffff81168114610bb857600080fd5b600060208284031215613c2857600080fd5b8135612ce581613bf4565b60008060408385031215613c4657600080fd5b8235613c5181613bf4565b9150602083013567ffffffffffffffff811115613c6d57600080fd5b8301601f81018513613c7e57600080fd5b613c8d858235602084016139ac565b9150509250929050565b602081526000612ce56020830184613b85565b600080600060408486031215613cbf57600080fd5b833567ffffffffffffffff80821115613cd757600080fd5b818601915086601f830112613ceb57600080fd5b813581811115613cfa57600080fd5b876020828501011115613d0c57600080fd5b60209283019550935050840135613d2281613bf4565b809150509250925092565b73ffffffffffffffffffffffffffffffffffffffff8616815260a060208201526000613d5c60a0830187613b85565b8281036040840152613d6e8187613b85565b90508281036060840152613d828186613b85565b90508281036080840152613d968185613b85565b98975050505050505050565b8015158114610bb857600080fd5b60006020808385031215613dc357600080fd5b823567ffffffffffffffff80821115613ddb57600080fd5b818501915085601f830112613def57600080fd5b813581811115613e0157613e016138bf565b8060051b613e10858201613917565b9182528381018501918581019089841115613e2a57600080fd5b86860192505b83831015613ef457823585811115613e485760008081fd5b86016060818c037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001811315613e7e5760008081fd5b613e866138ee565b8983013588811115613e985760008081fd5b613ea68e8c838701016139ea565b82525060408084013589811115613ebd5760008081fd5b613ecb8f8d838801016139ea565b838d0152509282013592613ede84613da2565b8101929092525082529186019190860190613e30565b9998505050505050505050565b600181811c90821680613f1557607f821691505b602082108103613f4e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b604081526000808454613f6681613f01565b8060408601526060600180841660008114613f885760018114613fc057613ff1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550613ff1565b8960005260208060002060005b86811015613fe85781548b8201870152908401908201613fcd565b8a018501975050505b505050505082810360208401526118a78185613b85565b601f82111561297d57600081815260208120601f850160051c8101602086101561402f5750805b601f850160051c820191505b8181101561404e5782815560010161403b565b505050505050565b815167ffffffffffffffff811115614070576140706138bf565b6140848161407e8454613f01565b84614008565b602080601f8311600181146140d757600084156140a15750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561404e565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561412457888601518255948401946001909101908401614105565b508582101561416057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f3f636f6e7472616374416464726573733d000000000000000000000000000000815260008351614206816011850160208801613b61565b7f26746f6b656e49643d0000000000000000000000000000000000000000000000601191840191820152835161424381601a840160208801613b61565b01601a01949350505050565b60008351614261818460208801613b61565b7f26696d616765733d000000000000000000000000000000000000000000000000908301908152835161429b816008840160208801613b61565b01600801949350505050565b6000602082840312156142b957600080fd5b8151612ce581613bf4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115612ce857612ce86142c4565b60008351614318818460208801613b61565b7f20230000000000000000000000000000000000000000000000000000000000009083019081528351614352816002840160208801613b61565b01600201949350505050565b6000815461436b81613f01565b6001828116801561438357600181146143b6576143e5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506143e5565b8560005260208060002060005b858110156143dc5781548a8201529084019082016143c3565b50505082870194505b5050505092915050565b60006143fb828561435e565b835161440b818360208801613b61565b01949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614445576144456142c4565b5060010190565b60008060008060008060c0878903121561446557600080fd5b863567ffffffffffffffff8082111561447d57600080fd5b6144898a838b016139ea565b9750602089013591508082111561449f57600080fd5b6144ab8a838b016139ea565b965060408901359150808211156144c157600080fd5b6144cd8a838b016139ea565b955060608901359150808211156144e357600080fd5b6144ef8a838b016139ea565b9450608089013591508082111561450557600080fd5b6145118a838b016139ea565b935060a089013591508082111561452757600080fd5b5061453489828a016139ea565b9150509295509295509295565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156145e4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08984030185528151606081518186526145ac82870182613b85565b915050888201518582038a8701526145c48282613b85565b928901511515958901959095525094870194925090860190600101614568565b509098975050505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261462757600080fd5b83018035915067ffffffffffffffff82111561464257600080fd5b602001915036819003821315613a8457600080fd5b67ffffffffffffffff83111561466f5761466f6138bf565b6146838361467d8354613f01565b83614008565b6000601f8411600181146146d5576000851561469f5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556106be565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156147245786850135825560209485019460019092019101614704565b508682101561475f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b61477b82836145f2565b67ffffffffffffffff811115614793576147936138bf565b6147a7816147a18554613f01565b85614008565b6000601f8211600181146147f957600083156147c35750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b17855561488f565b6000858152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0841690835b828110156148485786850135825560209485019460019092019101614828565b5084821015614883577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88660031b161c19848701351681555b505060018360011b0185555b505050506148a060208301836145f2565b611af5818360018601614657565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261493657600080fd5b9190910192915050565b60006020828403121561495257600080fd5b8135612ce581613da2565b60006020828403121561496f57600080fd5b8151612ce581613da2565b60006020828403121561498c57600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156149cb576149cb6142c4565b500290565b6000816149df576149df6142c4565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600082614a1457614a1461419f565b500490565b81810381811115612ce857612ce86142c4565b600082614a3b57614a3b61419f565b500690565b6000614a4c828761435e565b8551614a5c818360208a01613b61565b7f2f0000000000000000000000000000000000000000000000000000000000000091019081528451614a95816001840160208901613b61565b613d966001828401018661435e565b60008551614ab6818460208a01613b61565b855190830190614aca818360208a01613b61565b7f220000000000000000000000000000000000000000000000000000000000000091018181528551909190614b06816001850160208a01613b61565b7f223a202200000000000000000000000000000000000000000000000000000000600193909101928301528451614b44816005850160208901613b61565b60059201918201526006019695505050505050565b60008551614b6b818460208a01613b61565b855190830190614b7f818360208a01613b61565b7f220000000000000000000000000000000000000000000000000000000000000091019081528451614bb8816001840160208901613b61565b7f223a200000000000000000000000000000000000000000000000000000000000600192909101918201528351614bf6816004840160208801613b61565b016004019695505050505050565b60008251614c16818460208701613b61565b7f7d00000000000000000000000000000000000000000000000000000000000000920191825250600101919050565b600060208284031215614c5757600080fd5b815167ffffffffffffffff811115614c6e57600080fd5b8201601f81018413614c7f57600080fd5b8051614c8d6139ba82613966565b818152856020838501011115614ca257600080fd5b6118a7826020830160208601613b61565b7f646174613a000000000000000000000000000000000000000000000000000000815260008351614ceb816005850160208801613b61565b7f3b6261736536342c0000000000000000000000000000000000000000000000006005918401918201528351614d2881600d840160208801613b61565b01600d01949350505050565b60008251614936818460208701613b6156fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122021bd4085e21d7ea8312d8a669802ee4a5e946121e844a34dac1876a9474eca5564736f6c63430008100033