ETH Price: $2,285.82 (-3.43%)

Contract

0x1f4126A9D34811E55B9506F011aC1df1396ac909
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Note202136792024-07-01 19:12:2367 days ago1719861143IN
0x1f4126A9...1396ac909
0 ETH0.002186214.48198374
Give Respect202124082024-07-01 14:57:2367 days ago1719845843IN
0x1f4126A9...1396ac909
0 ETH0.0014223511.28282028
Set Alias202123492024-07-01 14:45:2367 days ago1719845123IN
0x1f4126A9...1396ac909
0 ETH0.0005544511.30894008
Toggle Composabl...202123472024-07-01 14:44:5967 days ago1719845099IN
0x1f4126A9...1396ac909
0 ETH0.0005861711.40888891
Push Associated ...202119492024-07-01 13:24:4767 days ago1719840287IN
0x1f4126A9...1396ac909
0 ETH0.000605887.86898773
Push Tag201921512024-06-28 19:03:3570 days ago1719601415IN
0x1f4126A9...1396ac909
0 ETH0.00032993.79158116
Set Main Basics201921382024-06-28 19:00:5970 days ago1719601259IN
0x1f4126A9...1396ac909
0 ETH0.001467384.46853283
Push Associated ...201921182024-06-28 18:56:5970 days ago1719601019IN
0x1f4126A9...1396ac909
0 ETH0.000419365.45507072
Push Additional ...201920902024-06-28 18:51:2370 days ago1719600683IN
0x1f4126A9...1396ac909
0 ETH0.00097925.8145273
Push Additional ...201920662024-06-28 18:46:3570 days ago1719600395IN
0x1f4126A9...1396ac909
0 ETH0.001057065.53347005
Push Associated ...201920462024-06-28 18:42:3570 days ago1719600155IN
0x1f4126A9...1396ac909
0 ETH0.000437835.69345923
Push Tag201920082024-06-28 18:34:5970 days ago1719599699IN
0x1f4126A9...1396ac909
0 ETH0.000322785.998739
Set PFP201920062024-06-28 18:34:3570 days ago1719599675IN
0x1f4126A9...1396ac909
0 ETH0.000410195.93012971
Push Associated ...201920012024-06-28 18:33:3570 days ago1719599615IN
0x1f4126A9...1396ac909
0 ETH0.000457395.94780682
Give Respect201373702024-06-21 3:20:2378 days ago1718940023IN
0x1f4126A9...1396ac909
0 ETH0.000758186.01431192
Push Tag201373692024-06-21 3:20:1178 days ago1718940011IN
0x1f4126A9...1396ac909
0 ETH0.00039835.62383486
Push Associated ...201373682024-06-21 3:19:5978 days ago1718939999IN
0x1f4126A9...1396ac909
0 ETH0.000517395.51412566
Set Main Basics201373622024-06-21 3:18:4778 days ago1718939927IN
0x1f4126A9...1396ac909
0 ETH0.001853865.5833314
Set Detail201373102024-06-21 3:08:2378 days ago1718939303IN
0x1f4126A9...1396ac909
0 ETH0.000432815.27042615
Push Tag201373012024-06-21 3:06:3578 days ago1718939195IN
0x1f4126A9...1396ac909
0 ETH0.000371765.24645838
Give Respect201372992024-06-21 3:06:1178 days ago1718939171IN
0x1f4126A9...1396ac909
0 ETH0.000661665.24864651
Delete Associate...201372982024-06-21 3:05:5978 days ago1718939159IN
0x1f4126A9...1396ac909
0 ETH0.000168635.11697149
Update Associate...201372972024-06-21 3:05:4778 days ago1718939147IN
0x1f4126A9...1396ac909
0 ETH0.000192445.17634792
Set Detail201372872024-06-21 3:03:4778 days ago1718939027IN
0x1f4126A9...1396ac909
0 ETH0.000564425.0939419
Push Tag201372612024-06-21 2:58:1178 days ago1718938691IN
0x1f4126A9...1396ac909
0 ETH0.000391015.51803378
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
EtherEthos

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 6 : EtherEthos.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

interface iDelegate {
    function checkDelegateForContract(
        address _delegate,
        address _vault,
        address _contract,
        bytes32 rights
    ) external view returns (bool);
}

interface iExternalContract {
    function owner() external view returns (address);
}

/// @title EtherEthos (v2.0.2) - offered 'as-is', without warranty, and disclaiming liability for damages resulting from using the contract or data stored on it.
/// @author Matto AKA MonkMatto. More info: matto.xyz.
/// @notice EtherEthos is a hyperstructure that facilitates the creation of a composable EtherEthos (profile) for Ethereum addresses.
/// It empowers users to:
/// - Share links and associated accounts.
/// - Share social proofs by publicly respecting other accounts. 
/// - Write notes for other accounts (requires the recipient to respect the note writer).
/// - Store personal account details such as an alias, a description, preferred website / social media / gallery link, and a preferred NFT to use as a PFP.
/// Users should refrain from submitting Personally Identifying Information (PII) - this is the realm of crypto.
/// @notice User Responsibilities and Data Accessibility
/// - Users are responsible for the data they provide, including text descriptions, URLs, and smart contracts.
/// - By storing data in this contract, the submitted text-data becomes publicly accessible and may be used in smart contract composition.
/// - Opting-out by toggling an account's composable value to false disables most data-returning functions.
/// - However, due to the public nature of the data and immutability of the blockchain, 'opt-outs' cannot be guaranteed to be respected by third-party developers.
/// @notice Composability and Developer Responsibilities
/// - This contract encourages developers to compose with EtherEthos's data, including into tokens, in a responsible manner respecting users' 'opt-out' requests (disabled composability).
/// - Contracts aiming to compose with this contract's data must adhere to using the assemble* functions to retrieve data.
/// @dev Account Delegation and Security
/// - This contract supports account delegation, allowing authorized accounts to add or modify details on behalf of other accounts.
/// - The delegateContract variable stores the address of the Delegate contract responsible for validating delegations.
/// - The checkDelegateForContract function in the Delegate contract is called to verify if an account is authorized to act on behalf of another account.
/// - Account owners should carefully consider the implications of granting delegation permissions to other accounts.
/// @dev Moderation Features
/// - Limited moderation features are supported, allowing authorized accounts to toggle an account's composability, and to block/unblock accounts from writing to the contract.
/// - The allModerators array stores the addresses of all moderator accounts.
/// - The toggleModerator function can be called by the contract owner to grant or revoke moderator permissions.
/// @custom:experimental Warning Experimental Contract
/// - This contract is experimental, and no guarantees are made regarding its functionality, security, or lifespan.
/// - If a new version is deployed, it may not be backwards compatible.
/// - Users and developers should exercise caution when interacting with this contract and understand the potential risks involved.
/// @custom:security-contact For any security concerns, please reach out to [email protected].
/// @custom:legal-disclaimer
/// 1. Users are solely responsible for the data they provide, including text descriptions, URLs, and smart contracts. Submission of illegal, malicious, or harmful data is strictly prohibited.
/// 2. Matto, EtherEthos, Substratum, and all associated entities disclaim all liability for any damages resulting from the use or misuse of data provided by users.
/// 3. EtherEthos does not have control over user-submitted content, nor provides any guarantee on the safety or reliability of any data, including links to third-party websites or contracts.
/// 4. The use of any data, links, or contracts stored within this contract and presented by frontend applications is entirely at the end-user's risk.
/// 5. The act of composing data from this contract into tokens, other contracts, or digital assets lies solely at the discretion and risk of the user and/or contract developer.
/// 6. Such composability carries risks and implications, which may include but are not limited to data permanence, security issues, social costs, and legal considerations. By accessing this contract, users and developers, certify they have considered the potential risks and accept all risks and implications both foreseeable and unforeseeable at the time of use.
/// @notice Legal Variable
/// - If present, the data stored in this contract's 'legal' variable supersedes the above legal disclaimers.
/// - In the event of conflicting terms, the conditions outlined in the 'legal' variable take precedence.

contract EtherEthos is Ownable {
    using Strings for string;

    // Contains the permissions for each account.
    struct Perms {
        bool composable; // Whether or not the account has an active composable EtherEthos.
        bool accountIsBlocked; // Whether or not the account is blocked.
        bool moderator; // Whether or not the account is a moderator.
        string verificationResponse; // The response to a verification request.
    }

    // Contains basic account information. The 'Detail' string is limited to 320 bytes, while all other strings are limited to 160 bytes.
    struct Basics {
        string accountAlias; // An alias or nickname for the account.
        string detail; // Detailed information about the account.
        string socialLink; // Social media link for the account.
        string website; // Website link for the account.
        string gallery; // Link to a gallery of the account's work or collection.
        uint256 ping; // A timestamp of the last time the account was pinged.
        uint256 pfpTokenId; // The token ID of the profile picture NFT.
        address pfpContract; // The contract address of the profile picture NFT.
        uint8 priorityLink; // stores the priority link for the account.
    }

    // Pairs two strings together for various uses in the contract. k and v are used to represent the key and value type of relationship of the pair.
    struct StrPair {
        string k; // The first string in the pair.
        string v; // The second string associated with the first string.
    }

    // Pairs an address with a string for various uses in the contract. k and v are used to represent the key and value type of relationship of the pair.
    struct AddrPair {
        address k; // The address in the pair.
        string v; // The string associated with the address.
    }

    // The legal disclaimer override for the contract.
    string public legal;
    // The number of active Composable EtherEthos records (EEs) in the contract.
    uint256 public activeEEs;
    // Stores all moderators in a public array.
    address[] public allModerators;
    // Stores the permissions for each account.
    mapping(address => Perms) public permissions;
    // Stores the maximum number of notes allowed per account. This is updatable.
    uint256 private maxNotesPerAccount = 128;

    // The address of the Delegate contract. This is updatable.
    address private delegateContract = 0x00000000000000447e69651d841bD8D104Bed493;

    // Stores the basic information for each account.
    mapping(address => Basics) private basics;
    // Stores a string of any size for use in specific composability scenarios.
    mapping(address => string) private custom;

    // Stores an array of additional link pairs (URL and description) for each account.
    mapping(address => StrPair[]) private additionalLinks;
    // Stores an array of associated account pairs (address and description) for each account.
    mapping(address => AddrPair[]) private associatedAccounts;
    // Stores an array notesReceived pairs (note text and writing account) for each account.
    mapping(address => AddrPair[]) private notesReceived;
    // Stores an array notesReceived pairs (note text and writing account) for each account.
    mapping(address => address[]) private notesSent;

    // Keeps track of the index of each note writer's address in the note recipient's array of noteWriters.
    mapping(address => mapping(address => uint256)) private noteWritersIndex;
    // Keeps track of where each note recipient's address is in the note writer's array of noteRecipients.
    mapping(address => mapping(address => uint256)) private notesSentIndex;
    // Stores an array of tags for each account.
    mapping(address => string[]) private tags;

    // Stores the addresses of accounts who have respected each account.
    mapping(address => address[]) private respecters;
    // Keeps track of where each respecter's address is in the respected account's array of respecters.
    mapping(address => mapping(address => uint256)) private respectersIndex;
    // Stores the addresses of accounts that each account respects.
    mapping(address => address[]) private respecting;
    // Keeps track of where each respected address is in the respecting account's array.
    mapping(address => mapping(address => uint256)) private respectingIndex;

    /// @notice Event to alert clients that a EtherEthos's composability has been changed for an account.
    /// @dev This event is emitted when a user adds basic data to their EtherEthos or toggles their EtherEthos's composability state.
    /// This provides a way to track account composability on-chain.
    /// @param _account The address of the account whose EtherEthos composability has changed.
    /// @param _status The new composability status of the account. True indicates that the account's EtherEthos is now composable, false indicates that the account's EtherEthos is no longer composable.
    event Composable(address indexed _account, bool _status);

    /// @notice Event to alert clients that an account has become or stopped being a moderator.
    /// @dev Emitted when the moderator status of an account is toggled.
    /// @param _account The address of the account whose moderator status has been changed.
    /// @param _status The new moderator status of the account. True indicates that the account is a moderator,
    /// false indicates that the account is not a moderator.
    event Moderator(address indexed _account, bool _status);

    /// @notice Event to alert clients that an account has been blocked or unblocked.
    /// @dev Emitted when an account's access to write data to the contract is toggled.
    /// @param _account The address of the account whose access status has been changed.
    /// @param _status The new access status of the account. True indicates that the account is now blocked from writing to the contract, false indicates that the account is unblocked.
    event Blocked(address indexed _account, bool _status);

    /// @notice Event to alert clients that an account has been respected / unrespected.
    /// @dev Emitted when an account has a change in respect status.
    /// @param _respected The address of the account that has been respected.
    /// @param _respecter The address of the account that has respected the other account.
    /// @param _status The new respect status of the account.
    event Respected(
        address indexed _respected,
        address indexed _respecter,
        bool _status
    );

    /// @notice Event to alert clients that an account recieved a note.
    /// @dev Emitted when an account has a note written for them, or when a note is updated.
    /// @param _noteReceiver The address of the account that has recieved a note.
    /// @param _noteWriter The address of the account that has written the note.
    /// @param _note The note that has been written.
    event Noted(
        address indexed _noteReceiver,
        address indexed _noteWriter,
        string _note
    );

    /// @notice Event to alert clients that the contract has updated terms stored in the legal variable.
    /// @dev Emitted when the content in the legal variable is updated.
    /// @param _legal The new content to be stored in the legal variable.
    event LegalUpdated(string _legal);

    /// @notice Checks if the sender is authorized to act on behalf of a specified account.
    /// @dev The sender must either be the account itself or a valid delegate.
    /// The account must not be blocked. The delegate validity is checked via a separate contract.
    /// @param _account The account for which the sender might be acting.
    modifier isAuthorized(address _account) {
        require(_accountAuthorized(_account), "!Au");
        _;
    }

    /// @notice Checks if the given requester is authorized for the given account.
    /// @dev The requester is considered authorized if they are the account itself or a valid delegate.
    /// The delegate validity is checked via a separate contract.
    /// @param _account The account to be checked for authorization.
    /// @return Returns true if the requester is authorized for the given account, otherwise false.
    function _accountAuthorized(address _account) internal view returns (bool) {
        require(!permissions[_account].accountIsBlocked, "Blocked");
        address requester = msg.sender;
        return
            requester == _account ||
            iDelegate(delegateContract).checkDelegateForContract(
                requester,
                _account,
                address(this),
                ""
            ) ||
            requester == iExternalContract(_account).owner();
    }

    /// @notice Checks if the account has a composable EtherEthos.
    /// @dev simplifies external calls for checking if an account has a composable EtherEthos.
    /// @param _account The account to check.
    /// @return A boolean indicating whether or not the account has a composable EtherEthos.
    function isComposable(address _account) external view returns (bool) {
        return permissions[_account].composable;
    }

    /// @notice This function is used to update the timestamp of the last time an account was pinged.
    /// @dev This contract can be deployed on any Ethereum L2, and keeping data across L1 and L2s in sync is a challenge.
    /// This function is used to update the timestamp of the last time an account was pinged, which can be compared across layers.
    /// @param _account The account whose ping timestamp is being updated.
    function ping(address _account) public isAuthorized(_account) {
        basics[_account].ping = block.timestamp;
    }

    /// @notice Updates the verification response for a given account.
    /// @dev This function is updates a publicly viewable string that is intended to be used as a verification response.
    /// This field is cannot be disabled by setting composable to false.
    /// Calling account must be authorized to act on behalf of the account being updated.
    /// @param _account The account whose verification response is being updated.
    /// @param _verificationResponse The new verification response for the account.
    function setVerificationResponse(
        address _account,
        string calldata _verificationResponse
    ) external isAuthorized(_account) {
        permissions[_account].verificationResponse = _verificationResponse;
    }

    /// @notice Retrieves all additional links associated with the provided account.
    /// @dev This function returns an array of StrPair structures, which contain the URL or identifier of the link and a brief description or detail about the link.
    /// @param _account The account whose additional links are being queried.
    /// @return A dynamic array of StrPair structures (tuples) representing all the additional links associated with the queried account and their associated details.
    function getAdditionalLinkTuples(
        address _account
    ) external view returns (StrPair[] memory) {
        require(permissions[_account].composable);
        return additionalLinks[_account];
    }

    /// @notice Retrieves all associated accounts associated with the provided account.
    /// @dev This function returns an array of AddrPair structures, which contain the address of an associated account and a brief description or detail about that account.
    /// @param _account The account whose associated accounts are being queried.
    /// @return A dynamic array of AddrPair structures (tuples) representing all of an account's associated accounts and their details.
    function getAssociatedAccountTuples(
        address _account
    ) external view returns (AddrPair[] memory) {
        require(permissions[_account].composable);
        return associatedAccounts[_account];
    }

    /// @notice Allows owner to change the maximum number of notes allowed per user.
    /// @dev This function can only be called by the contract owner.
    /// @param _maxNotesPerAccount The new maximum number of notes allowed per user.
    function updateMaxNotesPerAccount(uint256 _maxNotesPerAccount) external onlyOwner {
        maxNotesPerAccount = _maxNotesPerAccount;
    }

    /// @notice Updates the legal disclaimer for the contract.
    /// @dev This function can only be called by the contract owner.
    /// @param _legal The new legal disclaimer.
    function updateLegal(string calldata _legal) external onlyOwner {
        legal = _legal;
        emit LegalUpdated(_legal);
    }

    /// @notice Updates the Delegate contract address.
    /// @dev This function can only be called by the contract owner.
    /// @param _delegateContract The new Delegate contract address.
    function updateDelegateContract(address _delegateContract) external onlyOwner {
        delegateContract = _delegateContract;
    }

    /// @notice Toggles the moderator status of an account.
    /// @dev Moderators have permissions to block/unblock accounts and set records.
    /// Toggling changes the account's moderator status; if the account was a moderator,
    /// it will no longer be one, and vice versa.
    /// The account's address is also added to or removed from the allModerators array.
    /// This function can only be called by the contract owner.
    /// @param _account The account whose moderator status is being changed.
    function toggleModerator(address _account) external onlyOwner {
        if (permissions[_account].moderator) {
            for (uint256 i = 0; i < allModerators.length; i++) {
                if (allModerators[i] == _account) {
                    allModerators[i] = allModerators[allModerators.length - 1];
                    allModerators.pop();
                    break;
                }
            }
        } else {
            allModerators.push(_account);
        }
        permissions[_account].moderator = !permissions[_account].moderator;
        emit Moderator(_account, permissions[_account].moderator);
    }

    /// @notice Toggles an account's access to write data to the contract.
    /// @dev A moderator has the permission to block/unblock accounts from writing to the contract.
    /// This function changes the access status of an account: if it was blocked, it will be unblocked and vice versa.
    /// Note that a moderator cannot block/unblock their own account.
    /// @param _account The account whose access status is being changed.
    function toggleAccountBlock(address _account) external {
        require(permissions[msg.sender].moderator && msg.sender != _account);
        if (!permissions[_account].accountIsBlocked) {
            permissions[_account].accountIsBlocked = true;
            _deactivateComposability(_account);
        } else {
            permissions[_account].accountIsBlocked = false;
        }
        emit Blocked(_account, permissions[_account].accountIsBlocked);
    }

    /// @notice Used by an account to block itself due to a compromised private key.
    /// @dev This function blocks and deactivates composability for the account.
    /// @param _account The account that is blocking itself.
    function blockMyCompromisedAccount(address _account) external isAuthorized(_account) {
        permissions[_account].accountIsBlocked = true;
        _deactivateComposability(_account);
        emit Blocked(_account, true);
    }

    /// @notice Allows setting many of the basic details of an account at once.
    /// @dev By setting many basic details at once, it can help save gas costs and also activates the EtherEthos.
    /// The detail is limited to 320 bytes, while all other strings are limited to 160 bytes.
    /// If a string is longer than allowed, the transaction will fail, costing gas.
    /// This operation can only be performed by an authorized entity.
    /// @param _account The account whose details are being updated.
    /// @param _alias The new alias to be associated with the account. This could be a nickname or a pseudonym.
    /// @param _detail The new detail text to be stored. This could include additional information about the account holder.
    /// @param _socialLink A new socialLink text to be stored. This could be a link to a social media.
    /// @param _website A new website link text to be stored.
    /// @param _gallery A new gallery link text to be stored.
    function setMainBasics(
        address _account,
        string calldata _alias,
        string calldata _detail,
        string calldata _socialLink,
        string calldata _website,
        string calldata _gallery
    ) external isAuthorized(_account) {
        _checkStringLength(_alias, 160, 0);
        _checkStringLength(_socialLink, 160, 2);
        _checkStringLength(_website, 160, 3);
        _checkStringLength(_gallery, 160, 4);
        _checkStringLength(_detail, 320, 1);

        Basics storage userBasics = basics[_account];
        userBasics.accountAlias = _alias;
        userBasics.detail = _detail;
        userBasics.socialLink = _socialLink;
        userBasics.website = _website;
        userBasics.gallery = _gallery;
        _activateComposability(_account);
        ping(_account);
    }

    /// @notice Sets an alias or username for a given account.
    /// @dev Setting an alias not only helps identify the account but also activates the EtherEthos's composability if it's not already active.
    /// Activating the EtherEthos will allow data to be returned from the contract.
    /// Only an authorized user can set the alias.
    /// @param _account The account for which the alias is being set.
    /// @param _alias The new alias to be associated with the account. This could be a nickname or a pseudonym.
    function setAlias(
        address _account,
        string calldata _alias
    ) external isAuthorized(_account) {
        _checkStringLength(_alias, 160, 0);
        basics[_account].accountAlias = _alias;
        _activateComposability(_account);
    }

    /// @notice Assigns a new detail or description to a specified account.
    /// @dev Assigning a detail not only helps provide more context about the account,
    /// but also activates the EtherEthos's composability if it's not already active,
    /// which will allow data to be returned from the contract.
    /// @param _account The account for which the detail is being set.
    /// @param _detail The new detail or description to be associated with the account.
    /// This could provide some context about the account or its owner.
    function setDetail(
        address _account,
        string calldata _detail
    ) external isAuthorized(_account) {
        _checkStringLength(_detail, 320, 1);
        basics[_account].detail = _detail;
        _activateComposability(_account);
    }

    /// @notice Assigns a new socialLink to a specified account.
    /// @dev Assigning a socialLink not only serves as a publicly listed social media link,
    /// but it also activates the EtherEthos's composability if it's not already active,
    /// which allows data to be returned from the contract.
    /// @param _account The account for which the socialLink is being set.
    /// @param _socialLink A new socialLink text to be stored. This could be a social media page.
    function setSocial(
        address _account,
        string calldata _socialLink
    ) external isAuthorized(_account) {
        _checkStringLength(_socialLink, 160, 2);
        basics[_account].socialLink = _socialLink;
        _activateComposability(_account);
    }

    /// @notice Assigns a new website link to a specified account.
    /// @dev Assigning a website link not only serves as a publicly listed website link,
    /// but it also activates the EtherEthos's composability if it's not already active,
    /// which allows data to be returned from the contract.
    /// @param _account The account for which the website link is being set.
    /// @param _website A new website link text to be stored.
    function setWebsite(
        address _account,
        string calldata _website
    ) external isAuthorized(_account) {
        _checkStringLength(_website, 160, 3);
        basics[_account].website = _website;
        _activateComposability(_account);
    }

    /// @notice Assigns a new gallery link to a specified account.
    /// @dev Assigning a gallery link not only serves as a publicly listed gallery link,
    /// but it also activates the EtherEthos's composability if it's not already active,
    /// which allows data to be returned from the contract.
    /// @param _account The account for which the gallery link is being set.
    /// @param _gallery A new gallery link text to be stored.
    function setGallery(
        address _account,
        string calldata _gallery
    ) external isAuthorized(_account) {
        _checkStringLength(_gallery, 160, 4);
        basics[_account].gallery = _gallery;
        _activateComposability(_account);
    }

    /// @notice Assigns a new priority link to a specified account.
    /// @dev The priority link is used to request which link a third-party application would most prominantly display.
    /// The priority link has a default value of 0, meaning the social media link is prioritized.
    /// Use 1 to prioritize the website link, and 2 to prioritize the gallery link.
    /// @param _account The account for which the priority link is being set.
    /// @param _priorityLink A new priority link uint8 value to be stored.
    function setPriorityLink(
        address _account,
        uint8 _priorityLink
    ) external isAuthorized(_account) {
        basics[_account].priorityLink = _priorityLink;
    }

    /// @notice Assigns a preferred NFT (Non-Fungible Token) Profile Picture (PFP) to a specific account.
    /// @dev Assigning an NFT as a PFP doesn't activate the EtherEthos's composability if it's not already active.
    /// This function is used to specify the contract and the token ID of the NFT the account prefers as its PFP.
    /// Please note that PFP ownership is not validated in this contract,
    /// and ownership might need to be validated when the data is being composed live in third party applications.
    /// @param _account The account for which the PFP is being set.
    /// @param _pfpContract The address of the smart contract that controls the NFT to be used as a PFP.
    /// @param _pfpTokenId The unique identifier (token ID) of the NFT to be used as a PFP.
    function setPFP(
        address _account,
        address _pfpContract,
        uint256 _pfpTokenId
    ) external isAuthorized(_account) {
        basics[_account].pfpContract = _pfpContract;
        basics[_account].pfpTokenId = _pfpTokenId;
    }

    /// @notice Sets a custom string for a given account.
    /// @dev The custom field is provided for flexibility in collective composability.
    /// Eg. a DAO wants something composable specific to them -
    /// they could ask their members to each set data in this field appropriately formatted for their use case.
    /// This string is not limited to 160 bytes, and it is not included in standard return functions, but is still publicly accessible.
    /// Only an authorized user can set the custom data.
    /// @param _account The account for which the custom data is being set.
    /// @param _custom The new custom data to be associated with the account. This could be anything.
    function setCustomData(
        address _account,
        string calldata _custom
    ) external isAuthorized(_account) {
        custom[_account] = _custom;
    }

    /// @notice Adds a new link and its description to an account's list of additional links.
    /// @dev This function creates a new StrPair object with the given link and its description,
    /// and then adds this pair to the account's list of additional links. Only authorized users can add links.
    /// @param _account The account for which the additional link is being added.
    /// @param _link The actual URL or identifier of the additional link being added.
    /// @param _detail A brief description or detail about the additional link being added.
    function pushAdditionalLink(
        address _account,
        string calldata _link,
        string calldata _detail
    ) external isAuthorized(_account) {
        _checkStringLength(_link, 160, 5);
        _checkStringLength(_detail, 160, 1);
        StrPair memory newLink = StrPair(_link, _detail);
        additionalLinks[_account].push(newLink);
    }

    /// @notice Allows editing of an existing link and its corresponding description in an account's list of additional links.
    /// @dev This function modifies an existing StrPair object in the account's list of additional links,
    /// based on the provided index. Only authorized users can edit links.
    /// The correct index can be determined by using the public getAdditionalLinkTuples() function.
    /// @param _account The account for which the additonal link is being edited.
    /// @param _index The position in the list of additional links where the link to be edited is located.
    /// @param _link The updated URL or identifier of the additional link.
    /// @param _detail The updated description or detail about the additional link.
    function updateAdditionalLink(
        address _account,
        uint256 _index,
        string calldata _link,
        string calldata _detail
    ) external isAuthorized(_account) {
        require(_index < additionalLinks[_account].length);
        _checkStringLength(_link, 160, 5);
        _checkStringLength(_detail, 160, 1);
        additionalLinks[_account][_index].k = _link;
        additionalLinks[_account][_index].v = _detail;
    }

    /// @notice Allows removal of a link and its corresponding description from an account's list of additional links.
    /// @dev This function removes a specified StrPair object from the account's list of additional links.
    /// The specified link is replaced with the last link in the list and the last link is then removed.
    /// The index can be obtained through the corresponding public getAdditionalLinkTuples() function.
    /// @param _account The account for which the additional link is being removed.
    /// @param _index The position in the list of additional links of the link to be removed.
    function deleteAdditionalLink(
        address _account,
        uint256 _index
    ) external isAuthorized(_account) {
        require(_index < additionalLinks[_account].length);
        additionalLinks[_account][_index] = additionalLinks[_account][
            additionalLinks[_account].length - 1
        ];
        additionalLinks[_account].pop();
    }

    /// @notice Adds a new tag to an account's list of tags.
    /// @dev Individual tags are limited to 32 bytes.
    /// @param _account The account for which the tag is being added.
    /// @param _tag The tag being added. It should not include the '#' symbol.
    function pushTag(
        address _account,
        string calldata _tag
    ) external isAuthorized(_account) {
        _checkStringLength(_tag, 32, 6);
        tags[_account].push(_tag);
    }

    /// @notice Allows removal of a tag from an account's list of additional tags.
    /// @dev This function removes a specified tag from the account's list of tags.
    /// The specified tag is replaced with the last tag in the list and the last tag is then removed.
    /// The index can be obtained through the corresponding public assembleTags() function.
    /// @param _account The account for which the tag is being removed.
    /// @param _index The position in the list of tags of the tag to be removed.
    function deleteTag(
        address _account,
        uint256 _index
    ) external isAuthorized(_account) {
        require(_index < tags[_account].length);
        tags[_account][_index] = tags[_account][tags[_account].length - 1];
        tags[_account].pop();
    }

    /// @notice Adds an associated account and description to an account's list of associated accounts.
    /// @dev The caller must be authorized to access the _account.
    /// The _associatedAccount and its _detail will be stored as an associated account of the _account.
    /// @param _account The account to which an associated account is to be stored.
    /// @param _associatedAccount The associated account to be stored with _account.
    /// @param _detail A description or detail associated with the _associatedAccount.
    function pushAssociatedAccount(
        address _account,
        address _associatedAccount,
        string calldata _detail
    ) external isAuthorized(_account) {
        _checkStringLength(_detail, 160, 1);
        AddrPair memory newAssociatedAccount = AddrPair(
            _associatedAccount,
            _detail
        );
        associatedAccounts[_account].push(newAssociatedAccount);
    }

    /// @notice Modifies the associated account and description in the account's list of associated accounts.
    /// @dev The caller must be authorized to access the _account.
    /// The _associatedAccount and _detail replace the associated account and description at _index in the _account's associated accounts.
    /// The index can be obtained through the corresponding public getAssociatedAccountTuples() function.
    /// @param _account The account for which an associated account is being modified.
    /// @param _index The index in the list of associated accounts where modifications are to be made.
    /// @param _associatedAccount The new associated account to replace the current associated account at the _index position.
    /// @param _detail The new description to replace the current description at the _index position.
    function updateAssociatedAccount(
        address _account,
        uint256 _index,
        address _associatedAccount,
        string calldata _detail
    ) external isAuthorized(_account) {
        require(_index < associatedAccounts[_account].length);
        _checkStringLength(_detail, 160, 1);
        associatedAccounts[_account][_index].k = _associatedAccount;
        associatedAccounts[_account][_index].v = _detail;
    }

    /// @notice Removes an associated account and its description from the account's list of associated accounts.
    /// @dev The caller must be authorized to access the _account.
    /// The _index should point to the associated account and description to be removed in the _account's associated account list.
    /// The index can be obtained through the corresponding public getAssociatedAccountTuples() function.
    /// This function removes the associated account and description by swapping them with the last associated account and description in the list,
    /// and then reducing the list's length by one.
    /// @param _account The account from which an associated account and description is being removed.
    /// @param _index The index in the list of associated accounts where the associated account and description are to be removed.
    function deleteAssociatedAccount(
        address _account,
        uint256 _index
    ) external isAuthorized(_account) {
        require(_index < associatedAccounts[_account].length);
        associatedAccounts[_account][_index] = associatedAccounts[_account][
            associatedAccounts[_account].length - 1
        ];
        associatedAccounts[_account].pop();
    }

    /// @notice Allows an account to respect another account. This allows the respected account to write a note for the respecter.
    /// @dev The respecter's address is added to the respected account's array of respecters.
    /// The index of this new respectater in the array is also stored.
    /// @param _respectGiver The account that is respecting another account.
    /// @param _respectReceiver The account that is being respected by _respectGiver.
    function giveRespect(
        address _respectGiver,
        address _respectReceiver
    ) external isAuthorized(_respectGiver) {
        require(_respectGiver != _respectReceiver);
        require(
            respectersIndex[_respectReceiver][_respectGiver] == 0 &&
                (respecters[_respectReceiver].length == 0 ||
                    respecters[_respectReceiver][0] != _respectGiver),
            "Respecting"
        );

        // Add to respecters array
        respecters[_respectReceiver].push(_respectGiver);
        respectersIndex[_respectReceiver][_respectGiver] =
            respecters[_respectReceiver].length -
            1;

        // Add to respecting array
        respecting[_respectGiver].push(_respectReceiver);
        respectingIndex[_respectGiver][_respectReceiver] =
            respecting[_respectGiver].length -
            1;

        emit Respected(_respectReceiver, _respectGiver, true);
    }

    /// @notice Allows an account to revoke respect that it has made for another account.
    /// @dev The respecter's address is removed from the respected account's array of respecters.
    /// The element at the end of the array is moved to the deleted element's slot to avoid leaving a gap.
    /// The respectersIndex mapping is updated to reflect these changes.
    /// @param _respectRevoker The account that is revoking its respect for another account.
    /// @param _losingRespect The account for which the _respectRevoker's respect is being revoked.
    function revokeRespect(
        address _respectRevoker,
        address _losingRespect
    ) external isAuthorized(_respectRevoker) {
        // Logic for respecters array
        uint index = respectersIndex[_losingRespect][_respectRevoker];
        address[] storage respectedBy = respecters[_losingRespect];
        respectedBy[index] = respectedBy[respectedBy.length - 1];
        respectersIndex[_losingRespect][respectedBy[index]] = index;
        respectedBy.pop();
        delete respectersIndex[_losingRespect][_respectRevoker];

        // Logic for respecting array
        uint indexOfRespecting = respectingIndex[_respectRevoker][
            _losingRespect
        ];
        address[] storage respectsTo = respecting[_respectRevoker];
        respectsTo[indexOfRespecting] = respectsTo[respectsTo.length - 1];
        respectingIndex[_respectRevoker][
            respectsTo[indexOfRespecting]
        ] = indexOfRespecting;
        respectsTo.pop();
        delete respectingIndex[_respectRevoker][_losingRespect];

        emit Respected(_losingRespect, _respectRevoker, false);
    }

    /// @notice Allows an account to write a note for another.
    /// @dev The note will only be shown if the note recipient respects the note writer.
    /// @param _noteWriter The account that is writing a note for another.
    /// @param _noteReceiver The account that is receiving a note.
    /// @param _note The note being written by the _noteWriter for the _noteReceiver.
    function setNote(
        address _noteWriter,
        address _noteReceiver,
        string calldata _note
    ) external isAuthorized(_noteWriter) {
        require(_noteWriter != _noteReceiver, "!self");
        require(
            respectersIndex[_noteWriter][_noteReceiver] != 0 ||
            respecters[_noteWriter][0] == _noteReceiver,
            "!Au"
        );
        _checkStringLength(_note, 160, 7);

        // Cache frequently accessed data in memory variables
        AddrPair[] storage receivedNotes = notesReceived[_noteReceiver];
        mapping(address => uint256) storage writersIndex = noteWritersIndex[_noteReceiver];
        address[] storage sentNotes = notesSent[_noteWriter];
        mapping(address => uint256) storage sentIndex = notesSentIndex[_noteWriter];

        // Check if the note receiver has reached the maximum number of notes
        require(receivedNotes.length < maxNotesPerAccount, "R.lim");

        // Check if the note sender has reached the maximum number of notes
        require(sentNotes.length < maxNotesPerAccount, "S.lim");

        // Handle the case where the receiving account has no notes
        if (receivedNotes.length == 0) {
            writersIndex[_noteWriter] = 0;
            receivedNotes.push(AddrPair(_noteWriter, _note));
        }
        // Handle the case where the receiving account has a note from the writer
        else if (writersIndex[_noteWriter] > 0) {
            receivedNotes[writersIndex[_noteWriter]].v = _note;
        }
        // Handle the case where the receiving account has no note from the writer
        else {
            writersIndex[_noteWriter] = receivedNotes.length;
            receivedNotes.push(AddrPair(_noteWriter, _note));
        }

        // Handle the case where the _noteReceiver is not yet in the _noteWriter's sent notes list
        if (sentIndex[_noteReceiver] == 0) {
            sentNotes.push(_noteReceiver);
            sentIndex[_noteReceiver] = sentNotes.length - 1;
        }

        emit Noted(_noteReceiver, _noteWriter, _note);
    }

    /// @notice Allows an account to remove a note it has received from another account.
    /// The specified note is replaced with the last note in the list and the last note is then removed.
    /// The index can be obtained through the corresponding public getNoteTuples() function.
    /// @param _account The account that is removing a note it has received.
    /// @param _noteAuthor The account that wrote the note.
    function deleteReceivedNote(
        address _account,
        address _noteAuthor
    ) external isAuthorized(_account) {
        uint256 index = noteWritersIndex[_account][_noteAuthor];
        require(notesReceived[_account][index].k == _noteAuthor, "!Exist");

        // Cache frequently accessed data in memory variables
        AddrPair[] storage receivedNotes = notesReceived[_account];
        mapping(address => uint256) storage writersIndex = noteWritersIndex[_account];
        address[] storage sentNotes = notesSent[_noteAuthor];
        mapping(address => uint256) storage sentIndex = notesSentIndex[_noteAuthor];

        // Remove the note from notesReceived
        uint256 lastIndex = receivedNotes.length - 1;
        if (index != lastIndex) {
            AddrPair memory lastNote = receivedNotes[lastIndex];
            receivedNotes[index] = lastNote;
            writersIndex[lastNote.k] = index;
        }
        receivedNotes.pop();
        delete writersIndex[_noteAuthor];

        // Remove _account from _noteAuthor's notesSent array
        uint256 sentIndexToRemove = sentIndex[_account];
        lastIndex = sentNotes.length - 1;
        if (sentIndexToRemove != lastIndex) {
            address lastRecipient = sentNotes[lastIndex];
            sentNotes[sentIndexToRemove] = lastRecipient;
            sentIndex[lastRecipient] = sentIndexToRemove;
        }
        sentNotes.pop();
        delete sentIndex[_account];

        emit Noted(_account, _noteAuthor, "Deleted by receiver");
    }

    /// @notice Allows an account to remove a note it has written for another account.
    /// @dev The recipient is removed from the sender's notesSent array by overwriting it with the last recipient and then popping the last entry.
    /// @param _account The account that is removing a note they wrote for another.
    /// @param _accountLosingNote The account that is having a note removed.
    function deleteWrittenNote(
        address _account,
        address _accountLosingNote
    ) external isAuthorized(_account) {
        uint256 indexToRemove = noteWritersIndex[_accountLosingNote][_account];
        require(indexToRemove > 0 || notesReceived[_accountLosingNote][0].k == _account, "!Exist");

        // Cache frequently accessed data in memory variables
        AddrPair[] storage receivedNotes = notesReceived[_accountLosingNote];
        mapping(address => uint256) storage writersIndex = noteWritersIndex[_accountLosingNote];
        address[] storage sentNotes = notesSent[_account];
        mapping(address => uint256) storage sentIndex = notesSentIndex[_account];

        // Remove the note from notesReceived
        uint256 lastIndex = receivedNotes.length - 1;
        if (indexToRemove != lastIndex) {
            AddrPair memory lastNote = receivedNotes[lastIndex];
            receivedNotes[indexToRemove] = lastNote;
            writersIndex[lastNote.k] = indexToRemove;
        }
        receivedNotes.pop();
        delete writersIndex[_account];

        // Remove _accountLosingNote from _account's notesSent array
        uint256 sentIndexToRemove = sentIndex[_accountLosingNote];
        lastIndex = sentNotes.length - 1;
        if (sentIndexToRemove != lastIndex) {
            address lastRecipient = sentNotes[lastIndex];
            sentNotes[sentIndexToRemove] = lastRecipient;
            sentIndex[lastRecipient] = sentIndexToRemove;
        }
        sentNotes.pop();
        delete sentIndex[_accountLosingNote];

        emit Noted(_accountLosingNote, _account, "Deleted by writer");
    }

    /// @notice Allows a user to reconcile any inconsistencies in their note data.
    /// @dev This function reconciles both sent and received notes for the user.
    /// It iterates through the user's sent notes and checks if each recipient still has the corresponding note.
    /// If a recipient no longer has the note, it is removed from the user's sent notes array.
    /// It also iterates through the user's received notes and checks if the note writer still has the user as a recipient.
    /// If the note writer no longer has the user as a recipient, the note is removed from the user's received notes array.
    /// @param _account The account to reconcile note data for.
    function reconcileNotes(address _account) external isAuthorized(_account) {

        // Cache frequently accessed data in memory variables
        address[] storage sentNotes = notesSent[_account];
        mapping(address => uint256) storage sentIndex = notesSentIndex[_account];
        AddrPair[] storage receivedNotes = notesReceived[_account];
        mapping(address => uint256) storage writersIndex = noteWritersIndex[_account];

        // Reconcile sent notes
        for (uint256 i = 0; i < sentNotes.length; i++) {
            address recipient = sentNotes[i];
            uint256 noteIndex = noteWritersIndex[recipient][_account];

            // Check if the recipient still has the note
            if (noteIndex >= notesReceived[recipient].length || notesReceived[recipient][noteIndex].k != _account) {
                // If the recipient doesn't have the note, remove it from the user's sent notes array
                uint256 lastIndex = sentNotes.length - 1;
                if (i != lastIndex) {
                    address lastRecipient = sentNotes[lastIndex];
                    sentNotes[i] = lastRecipient;
                    sentIndex[lastRecipient] = i;
                }
                sentNotes.pop();
                delete sentIndex[recipient];
                i--; // Adjust the index to account for the removed note
            }
        }

        // Reconcile received notes
        for (uint256 i = 0; i < receivedNotes.length; i++) {
            address writer = receivedNotes[i].k;
            uint256 noteIndex = sentIndex[_account];

            // Check if the note writer still has the user as a recipient
            if (noteIndex >= notesSent[writer].length || notesSent[writer][noteIndex] != _account) {
                // If the note writer doesn't have the user as a recipient, remove the note from the user's received notes array
                uint256 lastIndex = receivedNotes.length - 1;
                if (i != lastIndex) {
                    AddrPair memory lastNote = receivedNotes[lastIndex];
                    receivedNotes[i] = lastNote;
                    writersIndex[lastNote.k] = i;
                }
                receivedNotes.pop();
                delete writersIndex[writer];
                i--; // Adjust the index to account for the removed note
            }
        }
    }


    /// @notice Toggles the visibility state of an account's EtherEthos - the collected reporting of all account data.
    /// @dev If the EtherEthos's composability is active, this function deactivates it, and vice versa.
    /// This function can be called by authorized accounts and by moderators.
    /// An account's composable status can be obtained from the public getter function for an account's permissions.
    /// @param _account The account for which to toggle the composable state.
    function toggleComposable(
        address _account
    ) external {
        require(
            _accountAuthorized(_account) || permissions[msg.sender].moderator,
            "!Au"
        );
        if (!permissions[_account].composable) {
            _activateComposability(_account);
        } else {
            _deactivateComposability(_account);
        }
    }

    /// @notice Returns almost all account data for a given account if it is not blocked and the EtherEthos composability is active.
    /// @dev Subfunctions are called to build respective data arrays.
    /// These subfunctions are also external and can be called individually.
    /// @param _account The account whose data is to be retrieved.
    /// @return accountData A 2D string array containing various account data.
    ///     Indices structure:
    ///     [0]: Basic Data - Includes account alias, detail, socialLink, link priority, PFP contract and Token ID.
    ///     [1]: Additional Links - Includes all the additional links associated with the account.
    ///     [2]: Associated Accounts - List of an account's Associated Accounts.
    ///     [3]: respecters - List of accounts that have respected the account.
    ///     [4]: respecting - List of accounts that the account has respected.
    ///     [5]: notes received - List of notes that have been written for the account.
    ///     [6]: notes sent - List of notes that have been written by the account.
    ///     [7]: tags - List of tags that have been written for the account.
    ///     [8]: custom - List of custom data that has been written for the account.
    function assembleAccountData(
        address _account
    ) external view returns (string[][] memory) {
        string[][] memory accountData = new string[][](9);
        if (permissions[_account].composable) {
            accountData[0] = assembleBasicData(_account);
            accountData[1] = assembleAdditionalLinks(_account);
            accountData[2] = assembleAssociatedAccounts(_account);
            accountData[3] = assembleRespecters(_account);
            accountData[4] = assembleRespecting(_account);
            accountData[5] = assembleNotesReceived(_account);
            accountData[6] = assembleNotesSent(_account);
            accountData[7] = assembleTags(_account);
            accountData[8] = assembleCustomData(_account);
        }
        return accountData;
    }

    /// @notice Returns an account's basic data in string format.
    /// @dev The function converts address and boolean values into string format for uniformity.
    /// The boolean values are returned as "true" or "false" strings.
    /// The function returns an empty array if the EtherEthos's composability is not active or if the account is blocked.
    /// Please note that PFP ownership is not validated in this contract,
    /// and ownership might need to be validated when the data is being composed live in third party applications.
    /// @param _account The account whose data is to be retrieved.
    /// @return basicData A string array containing the basic account data.
    ///     Indecies structure:
    ///     [0]: alias - The account's alias.
    ///     [1]: detail - Detailed information related to the account.
    ///     [2]: socialLink - The socialLink set by the account.
    ///     [3]: website - The website set by the account.
    ///     [4]: gallery - The gallery set by the account.
    ///     [5]: priorityLink - The priorityLink set by the account.
    ///     [6]: pfp contract - The address of the contract of the profile picture (PFP) as a string.
    ///     [7]: pfp tokenId - The token ID of the PFP as a string.
    ///     [8]: ping - The time that the account was last pinged.
    function assembleBasicData(
        address _account
    ) public view returns (string[] memory) {
        if (!permissions[_account].composable) {
            return new string[](9);
        }
        Basics memory basic = basics[_account];
        string[] memory basicData = new string[](9);
        basicData[0] = basic.accountAlias;
        basicData[1] = basic.detail;
        basicData[2] = basic.socialLink;
        basicData[3] = basic.website;
        basicData[4] = basic.gallery;
        basicData[5] = Strings.toString(basic.priorityLink);
        basicData[6] = _addrToStr(basic.pfpContract);
        basicData[7] = Strings.toString(basic.pfpTokenId);
        basicData[8] = Strings.toString(basic.ping);
        return basicData;
    }

    /// @notice Returns the account's link data as pairs of link and detail.
    /// @dev The function returns an empty array if the EtherEthos's composability is not active or if the account is blocked.
    /// The returned indices do not match the indices of the storage array due to the way the data is formatted for return.
    /// @param _account The account whose link data is to be retrieved.
    /// @return additionalLinksArray A string array containing the additional link data,
    /// with alternating link and detail values.
    ///    Indecies structure:
    ///    [0]: link - The first link of the account.
    ///    [1]: detail - The detail of the first link.
    ///    [2]: link - The second link of the account.
    ///    [3]: detail - The detail of the second link.
    ///    etc.
    function assembleAdditionalLinks(
        address _account
    ) public view returns (string[] memory) {
        if (!permissions[_account].composable) {
            return new string[](0);
        }
        uint256 linksCount = additionalLinks[_account].length;
        string[] memory additionalLinksArray = new string[](linksCount * 2);
        for (uint256 i = 0; i < linksCount; i++) {
            additionalLinksArray[i * 2] = additionalLinks[_account][i].k;
            additionalLinksArray[i * 2 + 1] = additionalLinks[_account][i].v;
        }
        return additionalLinksArray;
    }

    /// @notice Returns an account's associated accounts and their details.
    /// @dev The function returns an empty array if the EtherEthos's composability is not active or if the account is blocked.
    /// The returned indices do not match the indices of the storage array due to the way the data is formatted for return.
    /// @param _account The account whose associated accounts and details are to be retrieved.
    /// @return associatedAccountsArray A string array containing associated account data,
    /// with alternating associatedAccount address and detail values.
    ///    Indices structure:
    ///    [0]: associatedAccount - The address of the first associated account.
    ///    [1]: detail - The detail of the first associated account.
    ///    [2]: associatedAccount - The address of the second associated account.
    ///    [3]: detail - The detail of the second associated account.
    ///    etc.
    function assembleAssociatedAccounts(
        address _account
    ) public view returns (string[] memory) {
        if (!permissions[_account].composable) {
            return new string[](0);
        }
        uint256 associatedAccountsCount = associatedAccounts[_account].length;
        string[] memory associatedAccountsArray = new string[](
            associatedAccountsCount * 2
        );
        for (uint256 i = 0; i < associatedAccountsCount; i++) {
            associatedAccountsArray[i * 2] = _addrToStr(
                associatedAccounts[_account][i].k
            );
            associatedAccountsArray[i * 2 + 1] = associatedAccounts[_account][i]
                .v;
        }
        return associatedAccountsArray;
    }

    /// @notice Returns a list of accounts that have respected a specific account.
    /// @dev The function returns an empty array if the EtherEthos's composability is not active or if the account is blocked.
    /// @param _account The account whose respecters are to be retrieved.
    /// @return respectersArray A string array containing the addresses of the accounts that have respected the _account.
    function assembleRespecters(
        address _account
    ) public view returns (string[] memory) {
        if (!permissions[_account].composable) {
            return new string[](0);
        }
        uint256 respectersCount = respecters[_account].length;
        string[] memory respectersArray = new string[](respectersCount);
        for (uint256 i = 0; i < respectersCount; i++) {
            respectersArray[i] = _addrToStr(respecters[_account][i]);
        }
        return respectersArray;
    }

    /// @notice Returns a list of accounts that a specific account has respected.
    /// @dev The function returns an empty array if the EtherEthos's composability is not active or if the account is blocked.
    /// @param _account The account whose respecting accounts are to be retrieved.
    /// @return respectingArray A string array containing the addresses of the accounts that _account has respected.
    function assembleRespecting(
        address _account
    ) public view returns (string[] memory) {
        if (!permissions[_account].composable) {
            return new string[](0);
        }
        uint256 respectingCount = respecting[_account].length;
        string[] memory respectingArray = new string[](respectingCount);
        for (uint256 i = 0; i < respectingCount; i++) {
            respectingArray[i] = _addrToStr(respecting[_account][i]);
        }
        return respectingArray;
    }

    /// @notice Returns the custom data of a specific account.
    /// @dev The function returns an empty array if the EtherEthos's composability is not active or if the account is blocked.
    /// @param _account The account whose custom data is to be retrieved.
    /// @return customDataArray A string array containing one element - the custom data of the _account.
    function assembleCustomData(
        address _account
    ) public view returns (string[] memory) {
        if (!permissions[_account].composable) {
            return new string[](0);
        }
        string[] memory customDataArray = new string[](1);
        customDataArray[0] = custom[_account];
        return customDataArray;
    }

    /// @notice Returns the tags of a specific account.
    /// @dev The function returns an empty array if the EtherEthos's composability is not active or if the account is blocked.
    /// @param _account The account whose tags are to be retrieved.
    /// @return tagsArray A string array containing the tags of the _account.
    function assembleTags(
        address _account
    ) public view returns (string[] memory) {
        if (!permissions[_account].composable) {
            return new string[](0);
        }
        return tags[_account];
    }

    /// @notice Returns an account's notes and their authors.
    /// @dev The function returns an empty array if the account doesn't have any notes or if the note writer is no longer respected.
    /// The returned indices do not match the indices of the storage array due to the way the data is formatted for return.
    /// @param _account The account whose notes are to be retrieved.
    /// @return notesArray A string array containing note data,
    /// with alternating note writer address and note text values.
    ///    Indices structure:
    ///    [0]: noteWriter - The address of the first note writer.
    ///    [1]: note - The note written by the first note writer.
    ///    [2]: noteWriter - The address of the second note writer.
    ///    [3]: note - The note written by the second note writer.
    ///    etc.
    function assembleNotesReceived(
        address _account
    ) public view returns (string[] memory) {
        if (!permissions[_account].composable) {
            return new string[](0);
        }
        uint256 notesCount = notesReceived[_account].length;
        string[] memory notesArray = new string[](notesCount * 2);
        for (uint256 i = 0; i < notesCount; i++) {
            notesArray[i * 2] = _addrToStr(notesReceived[_account][i].k);
            notesArray[i * 2 + 1] = notesReceived[_account][i].v;
        }
        return notesArray;
    }

    /// @notice Returns an account's sent notes along with their recipients and the note content.
    /// @dev The function returns an empty array if the account hasn't written any notes or if notes written were deleted.
    /// @param _account The account whose sent notes and their contents are to be retrieved.
    /// @return notesArray A string array containing note data,
    /// with alternating note recipient address and note text values.
    ///    Indices structure:
    ///    [0]: noteRecipient - The address of the first note writer.
    ///    [1]: note - The note written for this recipient.
    ///    [2]: noteRecipient - The address of the second note writer.
    ///    [3]: note - The note written for this recipient.
    ///    etc.
    function assembleNotesSent(
        address _account
    ) public view returns (string[] memory) {
        uint256 notesCount = notesSent[_account].length;
        string[] memory notesArray = new string[](notesCount * 2);
        for (uint256 i = 0; i < notesCount; i++) {
            address recipient = notesSent[_account][i];
            // Find the index of the note in the recipient's notesReceived array using noteWritersIndex
            uint256 noteIndex = noteWritersIndex[recipient][_account];
            // Retrieve the note content from the recipient's notesReceived array
            string memory noteContent = notesReceived[recipient][noteIndex].v;
            notesArray[i * 2] = _addrToStr(recipient);
            notesArray[i * 2 + 1] = noteContent;
        }
        return notesArray;
    }

    /// @notice Internal function to check the length of a string.
    /// @dev This function is used to check the length of strings passed to the contract, and reverts if the string is too long.
    /// @param _str The string whose length is being checked.
    /// @param _labelIndex The index for the error message to be displayed if the string is too long.
    function _checkStringLength(
        string memory _str,
        uint256 _maxLength,
        uint256 _labelIndex
    ) internal pure {
        string[8] memory labels = [
            "Alias",
            "Detail",
            "Social",
            "Web",
            "Gallery",
            "Link",
            "Tag",
            "Note"
        ];
        string memory _errorMsg = string(abi.encodePacked(labels[_labelIndex], " too long"));
        require(bytes(_str).length < _maxLength + 1, _errorMsg);
    }

    /// @notice Activates a EtherEthos's composability for a specific account.
    /// @dev This internal function used to mark an account as allowing composability and incrementing the total count of composable EEs.
    /// An event, Composable, is emitted upon the successful activation of EtherEthos composability.
    /// @param _account The account for which EtherEthos composability will be activated.
    function _activateComposability(address _account) internal {
        if (!permissions[_account].composable) {
            permissions[_account].composable = true;
            activeEEs++;
            emit Composable(_account, true);
        }
    }

    /// @notice Deactivates a EtherEthos's composability for a specific account.
    /// @dev This internal function used to mark an account as not allowing composability and decrementing the total count of composable EEs.
    /// An event, Composable, is emitted upon the successful deactivation of EtherEthos composability.
    /// @param _account The account for which EtherEthos composability will be deactivated.
    function _deactivateComposability(address _account) internal {
        permissions[_account].composable = false;
        activeEEs--;
        emit Composable(_account, false);
    }

    /// @notice Converts an address to its string representation.
    /// @dev This is a shortcut function used internally to call OpenZeppelin's toHexString function.
    /// @param _address The address to convert into a string.
    /// @return string representation of the input address.
    function _addrToStr(
        address _address
    ) internal pure returns (string memory) {
        return Strings.toHexString(uint160(_address), 20);
    }
}

File 2 of 6 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 3 of 6 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

File 4 of 6 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 5 of 6 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"},{"indexed":false,"internalType":"bool","name":"_status","type":"bool"}],"name":"Blocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"},{"indexed":false,"internalType":"bool","name":"_status","type":"bool"}],"name":"Composable","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"_legal","type":"string"}],"name":"LegalUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"},{"indexed":false,"internalType":"bool","name":"_status","type":"bool"}],"name":"Moderator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_noteReceiver","type":"address"},{"indexed":true,"internalType":"address","name":"_noteWriter","type":"address"},{"indexed":false,"internalType":"string","name":"_note","type":"string"}],"name":"Noted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_respected","type":"address"},{"indexed":true,"internalType":"address","name":"_respecter","type":"address"},{"indexed":false,"internalType":"bool","name":"_status","type":"bool"}],"name":"Respected","type":"event"},{"inputs":[],"name":"activeEEs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allModerators","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"assembleAccountData","outputs":[{"internalType":"string[][]","name":"","type":"string[][]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"assembleAdditionalLinks","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"assembleAssociatedAccounts","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"assembleBasicData","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"assembleCustomData","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"assembleNotesReceived","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"assembleNotesSent","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"assembleRespecters","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"assembleRespecting","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"assembleTags","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"blockMyCompromisedAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"deleteAdditionalLink","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"deleteAssociatedAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_noteAuthor","type":"address"}],"name":"deleteReceivedNote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"deleteTag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_accountLosingNote","type":"address"}],"name":"deleteWrittenNote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getAdditionalLinkTuples","outputs":[{"components":[{"internalType":"string","name":"k","type":"string"},{"internalType":"string","name":"v","type":"string"}],"internalType":"struct EtherEthos.StrPair[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getAssociatedAccountTuples","outputs":[{"components":[{"internalType":"address","name":"k","type":"address"},{"internalType":"string","name":"v","type":"string"}],"internalType":"struct EtherEthos.AddrPair[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_respectGiver","type":"address"},{"internalType":"address","name":"_respectReceiver","type":"address"}],"name":"giveRespect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isComposable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"legal","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"permissions","outputs":[{"internalType":"bool","name":"composable","type":"bool"},{"internalType":"bool","name":"accountIsBlocked","type":"bool"},{"internalType":"bool","name":"moderator","type":"bool"},{"internalType":"string","name":"verificationResponse","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"ping","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"string","name":"_link","type":"string"},{"internalType":"string","name":"_detail","type":"string"}],"name":"pushAdditionalLink","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_associatedAccount","type":"address"},{"internalType":"string","name":"_detail","type":"string"}],"name":"pushAssociatedAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"string","name":"_tag","type":"string"}],"name":"pushTag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"reconcileNotes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_respectRevoker","type":"address"},{"internalType":"address","name":"_losingRespect","type":"address"}],"name":"revokeRespect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"string","name":"_alias","type":"string"}],"name":"setAlias","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"string","name":"_custom","type":"string"}],"name":"setCustomData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"string","name":"_detail","type":"string"}],"name":"setDetail","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"string","name":"_gallery","type":"string"}],"name":"setGallery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"string","name":"_alias","type":"string"},{"internalType":"string","name":"_detail","type":"string"},{"internalType":"string","name":"_socialLink","type":"string"},{"internalType":"string","name":"_website","type":"string"},{"internalType":"string","name":"_gallery","type":"string"}],"name":"setMainBasics","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_noteWriter","type":"address"},{"internalType":"address","name":"_noteReceiver","type":"address"},{"internalType":"string","name":"_note","type":"string"}],"name":"setNote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_pfpContract","type":"address"},{"internalType":"uint256","name":"_pfpTokenId","type":"uint256"}],"name":"setPFP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint8","name":"_priorityLink","type":"uint8"}],"name":"setPriorityLink","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"string","name":"_socialLink","type":"string"}],"name":"setSocial","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"string","name":"_verificationResponse","type":"string"}],"name":"setVerificationResponse","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"string","name":"_website","type":"string"}],"name":"setWebsite","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"toggleAccountBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"toggleComposable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"toggleModerator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"},{"internalType":"string","name":"_link","type":"string"},{"internalType":"string","name":"_detail","type":"string"}],"name":"updateAdditionalLink","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"},{"internalType":"address","name":"_associatedAccount","type":"address"},{"internalType":"string","name":"_detail","type":"string"}],"name":"updateAssociatedAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegateContract","type":"address"}],"name":"updateDelegateContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_legal","type":"string"}],"name":"updateLegal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxNotesPerAccount","type":"uint256"}],"name":"updateMaxNotesPerAccount","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040819052600555600680546001600160a01b0319166c447e69651d841bd8d104bed4931790553480156032575f80fd5b50603a33603e565b608d565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b615de88061009a5f395ff3fe608060405234801561000f575f80fd5b50600436106102ff575f3560e01c8063715018a611610195578063b4ab0337116100e4578063c75bc5921161009e578063e377ac3111610079578063e377ac3114610707578063e4c80cd01461071c578063e89d22d71461072f578063f2fde38b1461074f575f80fd5b8063c75bc592146106ce578063caf54d8e146106e1578063ccb4dfd7146106f4575f80fd5b8063b4ab03371461065c578063b4bd9e561461066f578063b59f9fb914610682578063c18cd6ee14610695578063c4889705146106a8578063c4cdcebe146106bb575f80fd5b80638c3a58fe1161014f5780639c2195481161012a5780639c219548146105db578063a449d90a146105ee578063a5c1595914610601578063ad8cc5ba1461063c575f80fd5b80638c3a58fe146105a55780638da5cb5b146105b85780638e62c1f9146105c8575f80fd5b8063715018a61461052d57806376e819bc14610535578063789932861461054c57806379cecf111461056c5780638474f1f71461057f578063855c17c114610592575f80fd5b80634094528f1161025157806350ee5de01161020b5780635ff4bd3b116101e65780635ff4bd3b146104e157806367263c77146104f457806367cc51301461050757806369f51c3b1461051a575f80fd5b806350ee5de0146104a857806353b145c2146104bb578063540c7db5146104ce575f80fd5b80634094528f1461043657806346e80caa146104495780634715dc4f1461045c57806347635b9b1461046f5780634cfbc0b6146104825780634efc647714610495575f80fd5b80631abf2716116102bc5780632662795f116102975780632662795f146103ea5780632c014422146103fd578063362c7259146104105780633a1c6ffe14610423575f80fd5b80631abf2716146103a45780631c1df036146103b75780631dfb1a21146103d7575f80fd5b80630156a98a1461030357806301e882081461033357806302a7c7da146103565780630ce44b0f1461036b5780630eda5e481461037e57806314df9e4314610391575b5f80fd5b61031661031136600461527d565b610762565b6040516001600160a01b0390911681526020015b60405180910390f35b6103466103413660046152b8565b61078a565b60405161032a9493929190615301565b61036961036436600461527d565b610843565b005b610369610379366004615379565b610850565b61036961038c3660046152b8565b6108f9565b61036961039f3660046152b8565b610923565b6103696103b23660046153c9565b610969565b6103ca6103c53660046152b8565b610ad5565b60405161032a919061544e565b6103ca6103e53660046152b8565b610ffc565b6103ca6103f83660046152b8565b611113565b61036961040b3660046152b8565b611220565b61036961041e366004615379565b611298565b6103696104313660046154b0565b611321565b61036961044436600461552c565b6114a5565b610369610457366004615588565b6115d2565b61036961046a3660046155c6565b611634565b61036961047d3660046155fd565b611855565b610369610490366004615379565b61199c565b6103696104a3366004615627565b611a2b565b6103ca6104b63660046152b8565b611a8c565b6103696104c93660046155c6565b611d24565b6103696104dc3660046152b8565b612132565b6103696104ef3660046152b8565b612238565b610369610502366004615379565b61241b565b610369610515366004615658565b6124be565b610369610528366004615658565b6125e4565b610369612a79565b61053e60025481565b60405190815260200161032a565b61055f61055a3660046152b8565b612a8c565b60405161032a91906156b8565b61036961057a366004615379565b612c33565b61036961058d36600461573d565b612c7b565b6103696105a0366004615379565b612cce565b6103ca6105b33660046152b8565b612d5d565b5f546001600160a01b0316610316565b6103696105d63660046152b8565b612f79565b6103696105e93660046155fd565b613415565b6103696105fc3660046152b8565b613529565b61062c61060f3660046152b8565b6001600160a01b03165f9081526004602052604090205460ff1690565b604051901515815260200161032a565b61064f61064a3660046152b8565b6135bf565b60405161032a919061577b565b6103ca61066a3660046152b8565b6136ed565b61036961067d366004615379565b6138eb565b6103ca6106903660046152b8565b61397a565b6103696106a33660046157ea565b613a7f565b6103ca6106b63660046152b8565b613c7c565b6103ca6106c93660046152b8565b613e7c565b6103696106dc3660046155c6565b613f68565b6103696106ef366004615379565b614246565b6103696107023660046155fd565b614291565b61070f6143e6565b60405161032a91906158e4565b61036961072a3660046155c6565b614472565b61074261073d3660046152b8565b61487f565b60405161032a91906158f6565b61036961075d3660046152b8565b614a2b565b60038181548110610771575f80fd5b5f918252602090912001546001600160a01b0316905081565b60046020525f90815260409020805460018201805460ff8084169461010085048216946201000090049091169290916107c29061598a565b80601f01602080910402602001604051908101604052809291908181526020018280546107ee9061598a565b80156108395780601f1061081057610100808354040283529160200191610839565b820191905f5260205f20905b81548152906001019060200180831161081c57829003601f168201915b5050505050905084565b61084b614aa1565b600555565b8261085a81614afa565b61087f5760405162461bcd60e51b8152600401610876906159c2565b60405180910390fd5b6108c483838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610140925060019150614c669050565b6001600160a01b0384165f9081526007602052604090206001016108e9838583615a50565b506108f384614dd6565b50505050565b610901614aa1565b600680546001600160a01b0319166001600160a01b0392909216919091179055565b8061092d81614afa565b6109495760405162461bcd60e51b8152600401610876906159c2565b506001600160a01b03165f90815260076020526040902042600590910155565b8561097381614afa565b61098f5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0387165f9081526009602052604090205486106109b1575f80fd5b6109f585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060059150614c669050565b610a3983838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060019150614c669050565b6001600160a01b0387165f90815260096020526040902080548691869189908110610a6657610a66615b04565b905f5260205f2090600202015f019182610a81929190615a50565b506001600160a01b0387165f90815260096020526040902080548491849189908110610aaf57610aaf615b04565b905f5260205f2090600202016001019182610acb929190615a50565b5050505050505050565b6001600160a01b0381165f9081526004602052604090205460609060ff16610b345760095b604051908082528060200260200182016040528015610b2d57816020015b6060815260200190600190039081610b185790505b5092915050565b6001600160a01b0382165f9081526007602052604080822081516101208101909252805482908290610b659061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054610b919061598a565b8015610bdc5780601f10610bb357610100808354040283529160200191610bdc565b820191905f5260205f20905b815481529060010190602001808311610bbf57829003601f168201915b50505050508152602001600182018054610bf59061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054610c219061598a565b8015610c6c5780601f10610c4357610100808354040283529160200191610c6c565b820191905f5260205f20905b815481529060010190602001808311610c4f57829003601f168201915b50505050508152602001600282018054610c859061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054610cb19061598a565b8015610cfc5780601f10610cd357610100808354040283529160200191610cfc565b820191905f5260205f20905b815481529060010190602001808311610cdf57829003601f168201915b50505050508152602001600382018054610d159061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054610d419061598a565b8015610d8c5780601f10610d6357610100808354040283529160200191610d8c565b820191905f5260205f20905b815481529060010190602001808311610d6f57829003601f168201915b50505050508152602001600482018054610da59061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054610dd19061598a565b8015610e1c5780601f10610df357610100808354040283529160200191610e1c565b820191905f5260205f20905b815481529060010190602001808311610dff57829003601f168201915b505050918352505060058201546020820152600682015460408201526007909101546001600160a01b0381166060830152600160a01b900460ff1660809091015290505f6009604051908082528060200260200182016040528015610e9557816020015b6060815260200190600190039081610e805790505b509050815f0151815f81518110610eae57610eae615b04565b6020026020010181905250816020015181600181518110610ed157610ed1615b04565b6020026020010181905250816040015181600281518110610ef457610ef4615b04565b6020026020010181905250816060015181600381518110610f1757610f17615b04565b6020026020010181905250816080015181600481518110610f3a57610f3a615b04565b6020026020010181905250610f5682610100015160ff16614e66565b81600581518110610f6957610f69615b04565b6020026020010181905250610f818260e00151614ef5565b81600681518110610f9457610f94615b04565b6020026020010181905250610fac8260c00151614e66565b81600781518110610fbf57610fbf615b04565b6020026020010181905250610fd78260a00151614e66565b81600881518110610fea57610fea615b04565b60209081029190910101529392505050565b6001600160a01b0381165f9081526004602052604090205460609060ff16611024575f610afa565b6040805160018082528183019092525f91816020015b606081526020019060019003908161103a5750506001600160a01b0384165f9081526008602052604090208054919250906110749061598a565b80601f01602080910402602001604051908101604052809291908181526020018280546110a09061598a565b80156110eb5780601f106110c2576101008083540402835291602001916110eb565b820191905f5260205f20905b8154815290600101906020018083116110ce57829003601f168201915b5050505050815f8151811061110257611102615b04565b602090810291909101015292915050565b6001600160a01b0381165f9081526004602052604090205460609060ff1661113b575f610afa565b6001600160a01b0382165f908152600f6020908152604080832080548251818502810185019093528083529193909284015b82821015611215578382905f5260205f2001805461118a9061598a565b80601f01602080910402602001604051908101604052809291908181526020018280546111b69061598a565b80156112015780601f106111d857610100808354040283529160200191611201565b820191905f5260205f20905b8154815290600101906020018083116111e457829003601f168201915b50505050508152602001906001019061116d565b505050509050919050565b61122981614afa565b806112485750335f9081526004602052604090205462010000900460ff165b6112645760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0381165f9081526004602052604090205460ff1661128f5761128c81614dd6565b50565b61128c81614f0b565b826112a281614afa565b6112be5760405162461bcd60e51b8152600401610876906159c2565b6112ff83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92018290525060a093509150614c669050565b6001600160a01b0384165f9081526007602052604090206108e9838583615a50565b8461132b81614afa565b6113475760405162461bcd60e51b8152600401610876906159c2565b61138b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060059150614c669050565b6113cf83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060019150614c669050565b6040805160606020601f8801819004028201810183529181018681525f9282919089908990819085018382808284375f92019190915250505090825250604080516020601f8801819004810282018101909252868152918101919087908790819084018382808284375f9201829052509390945250506001600160a01b038a16815260096020908152604082208054600181018255908352912083519394508493600290920201915081906114849082615b18565b50602082015160018201906114999082615b18565b50505050505050505050565b846114af81614afa565b6114cb5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0386165f908152600a602052604090205485106114ed575f80fd5b61153183838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060019150614c669050565b6001600160a01b0386165f908152600a6020526040902080548591908790811061155d5761155d615b04565b5f918252602080832060029290920290910180546001600160a01b0319166001600160a01b039485161790559188168152600a90915260409020805484918491889081106115ad576115ad615b04565b905f5260205f20906002020160010191826115c9929190615a50565b50505050505050565b826115dc81614afa565b6115f85760405162461bcd60e51b8152600401610876906159c2565b506001600160a01b039283165f90815260076020819052604090912090810180546001600160a01b031916939094169290921790925560060155565b8161163e81614afa565b61165a5760405162461bcd60e51b8152600401610876906159c2565b816001600160a01b0316836001600160a01b031603611677575f80fd5b6001600160a01b038083165f9081526011602090815260408083209387168352929052205415801561170757506001600160a01b0382165f90815260106020526040902054158061170757506001600160a01b038281165f9081526010602052604081208054928616929091906116f0576116f0615b04565b5f918252602090912001546001600160a01b031614155b6117405760405162461bcd60e51b815260206004820152600a60248201526952657370656374696e6760b01b6044820152606401610876565b6001600160a01b038281165f81815260106020908152604082208054600180820183558285529284200180546001600160a01b03191695891695909517909455919052905461178f9190615be2565b6001600160a01b038084165f81815260116020908152604080832094891680845294825280832095909555601281529381208054600181810183558284529583200180546001600160a01b03191690931790925591909152546117f29190615be2565b6001600160a01b038481165f8181526013602090815260408083209488168084529482529182902094909455516001815290927f6f0bc8b3499f361c2ff7768f2bd3079d0fea5d0da28fd0189a7da7eef7d4c6ee910160405180910390a3505050565b8161185f81614afa565b61187b5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0383165f90815260096020526040902054821061189d575f80fd5b6001600160a01b0383165f90815260096020526040902080546118c290600190615be2565b815481106118d2576118d2615b04565b905f5260205f20906002020160095f856001600160a01b03166001600160a01b031681526020019081526020015f20838154811061191257611912615b04565b5f91825260209091206002909102018061192c8382615bf5565b5060018181019061193f90840182615bf5565b5050506001600160a01b0383165f90815260096020526040902080548061196857611968615cba565b5f828152602081205f19909201916002830201906119868282615233565b611993600183015f615233565b50509055505050565b826119a681614afa565b6119c25760405162461bcd60e51b8152600401610876906159c2565b611a0683838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060039150614c669050565b6001600160a01b0384165f9081526007602052604090206003016108e9838583615a50565b81611a3581614afa565b611a515760405162461bcd60e51b8152600401610876906159c2565b506001600160a01b039091165f90815260076020819052604090912001805460ff909216600160a01b0260ff60a01b19909216919091179055565b6001600160a01b0381165f9081526004602052604090205460609060ff16611ab4575f610afa565b6001600160a01b0382165f9081526009602052604081205490611ad8826002615cce565b6001600160401b03811115611aef57611aef6159df565b604051908082528060200260200182016040528015611b2257816020015b6060815260200190600190039081611b0d5790505b5090505f5b82811015611d1c576001600160a01b0385165f908152600960205260409020805482908110611b5857611b58615b04565b905f5260205f2090600202015f018054611b719061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054611b9d9061598a565b8015611be85780601f10611bbf57610100808354040283529160200191611be8565b820191905f5260205f20905b815481529060010190602001808311611bcb57829003601f168201915b505050505082826002611bfb9190615cce565b81518110611c0b57611c0b615b04565b602002602001018190525060095f866001600160a01b03166001600160a01b031681526020019081526020015f208181548110611c4a57611c4a615b04565b905f5260205f2090600202016001018054611c649061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054611c909061598a565b8015611cdb5780601f10611cb257610100808354040283529160200191611cdb565b820191905f5260205f20905b815481529060010190602001808311611cbe57829003601f168201915b505050505082826002611cee9190615cce565b611cf9906001615ce5565b81518110611d0957611d09615b04565b6020908102919091010152600101611b27565b509392505050565b81611d2e81614afa565b611d4a5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b038084165f818152600d6020908152604080832094871680845294825280832054938352600b9091529020805491929183908110611d9157611d91615b04565b5f9182526020909120600290910201546001600160a01b031614611de05760405162461bcd60e51b815260206004820152600660248201526508515e1a5cdd60d21b6044820152606401610876565b6001600160a01b038085165f908152600b60209081526040808320600d83528184209488168452600c8352818420600e90935290832081549194939091611e2990600190615be2565b9050808614611f7a575f858281548110611e4557611e45615b04565b5f9182526020918290206040805180820190915260029092020180546001600160a01b031682526001810180549293919291840191611e839061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054611eaf9061598a565b8015611efa5780601f10611ed157610100808354040283529160200191611efa565b820191905f5260205f20905b815481529060010190602001808311611edd57829003601f168201915b505050505081525050905080868881548110611f1857611f18615b04565b5f91825260209182902083516002929092020180546001600160a01b0319166001600160a01b03909216919091178155908201516001820190611f5b9082615b18565b505090516001600160a01b03165f908152602086905260409020879055505b84805480611f8a57611f8a615cba565b5f8281526020812060025f199093019283020180546001600160a01b031916815590611fb96001830182615233565b505090556001600160a01b038089165f90815260208681526040808320839055928c16825284905220548354611ff190600190615be2565b9150818114612076575f84838154811061200d5761200d615b04565b905f5260205f20015f9054906101000a90046001600160a01b031690508085838154811061203d5761203d615b04565b5f91825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290849052604090208190555b8380548061208657612086615cba565b5f828152602080822083015f1990810180546001600160a01b03191690559092019092556001600160a01b038c8116808452918690526040808420939093559151918b16917f3294fc25de801ec383dc5fab48b0d8f281d893fd3f80bf56e15665a4ffd570e49061211e906020808252601390820152722232b632ba32b210313c903932b1b2b4bb32b960691b604082015260600190565b60405180910390a350505050505050505050565b335f9081526004602052604090205462010000900460ff16801561215f5750336001600160a01b03821614155b612167575f80fd5b6001600160a01b0381165f90815260046020526040902054610100900460ff166121bd576001600160a01b0381165f908152600460205260409020805461ff0019166101001790556121b881614f0b565b6121de565b6001600160a01b0381165f908152600460205260409020805461ff00191690555b6001600160a01b0381165f8181526004602090815260409182902054915161010090920460ff16151582527fcecdf9dd6f2193d677b10450a2e4ff64d6b61a566bdc6e34ab5c9fc2f797960b91015b60405180910390a250565b612240614aa1565b6001600160a01b0381165f9081526004602052604090205462010000900460ff1615612362575f5b60035481101561235c57816001600160a01b03166003828154811061228f5761228f615b04565b5f918252602090912001546001600160a01b03160361235457600380546122b890600190615be2565b815481106122c8576122c8615b04565b5f91825260209091200154600380546001600160a01b0390921691839081106122f3576122f3615b04565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550600380548061232f5761232f615cba565b5f8281526020902081015f1990810180546001600160a01b031916905501905561235c565b600101612268565b506123ad565b600380546001810182555f919091527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b0319166001600160a01b0383161790555b6001600160a01b0381165f81815260046020908152604091829020805460ff62010000808304821615810262ff000019909316929092179283905593519104909216151582527f8d46ffd267aefe727b4d0dd43fda31aa5d23c5cb0a042b69ef4dea7914c57906910161222d565b8261242581614afa565b6124415760405162461bcd60e51b8152600401610876906159c2565b61248583838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506020925060069150614c669050565b6001600160a01b0384165f908152600f60209081526040822080546001810182559083529120016124b7838583615a50565b5050505050565b836124c881614afa565b6124e45760405162461bcd60e51b8152600401610876906159c2565b61252883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060019150614c669050565b5f6040518060400160405280866001600160a01b0316815260200185858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509390945250506001600160a01b038981168252600a60209081526040832080546001808201835591855293829020865160029095020180546001600160a01b031916949093169390931782558401519394508493909250908201906125d99082615b18565b505050505050505050565b836125ee81614afa565b61260a5760405162461bcd60e51b8152600401610876906159c2565b836001600160a01b0316856001600160a01b0316036126535760405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b6044820152606401610876565b6001600160a01b038086165f908152601160209081526040808320938816835292905220541515806126c357506001600160a01b038581165f9081526010602052604081208054928716929091906126ad576126ad615b04565b5f918252602090912001546001600160a01b0316145b6126df5760405162461bcd60e51b8152600401610876906159c2565b61272383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060079150614c669050565b6001600160a01b038085165f908152600b60209081526040808320600d8352818420948a168452600c8352818420600e90935292206005548354939493106127955760405162461bcd60e51b8152602060048201526005602482015264522e6c696d60d81b6044820152606401610876565b6005548254106127cf5760405162461bcd60e51b8152602060048201526005602482015264532e6c696d60d81b6044820152606401610876565b83545f0361288a576001600160a01b0389165f8181526020858152604080832092909255815180830183529283528151601f8a01829004820281018201909252888252869291828201918b908b90819084018382808284375f920182905250939094525050835460018082018655948252602091829020845160029092020180546001600160a01b0319166001600160a01b03909216919091178155908301519293909290830191506128829082615b18565b5050506129b1565b6001600160a01b0389165f90815260208490526040902054156128ff57868685855f8d6001600160a01b03166001600160a01b031681526020019081526020015f2054815481106128dd576128dd615b04565b905f5260205f20906002020160010191826128f9929190615a50565b506129b1565b83546001600160a01b038a165f818152602086815260409182902093909355805180820182529182528051601f8a01849004840281018401909152888152869282810191908b908b90819084018382808284375f920182905250939094525050835460018082018655948252602091829020845160029092020180546001600160a01b0319166001600160a01b03909216919091178155908301519293909290830191506129ad9082615b18565b5050505b6001600160a01b0388165f908152602082905260408120549003612a21578154600180820184555f8481526020902090910180546001600160a01b0319166001600160a01b038b161790558254612a089190615be2565b6001600160a01b0389165f908152602083905260409020555b886001600160a01b0316886001600160a01b03167f3294fc25de801ec383dc5fab48b0d8f281d893fd3f80bf56e15665a4ffd570e48989604051612a66929190615cf8565b60405180910390a3505050505050505050565b612a81614aa1565b612a8a5f614f78565b565b6001600160a01b0381165f9081526004602052604090205460609060ff16612ab2575f80fd5b6001600160a01b0382165f90815260096020908152604080832080548251818502810185019093528083529193909284015b82821015611215578382905f5260205f2090600202016040518060400160405290815f82018054612b149061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054612b409061598a565b8015612b8b5780601f10612b6257610100808354040283529160200191612b8b565b820191905f5260205f20905b815481529060010190602001808311612b6e57829003601f168201915b50505050508152602001600182018054612ba49061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054612bd09061598a565b8015612c1b5780601f10612bf257610100808354040283529160200191612c1b565b820191905f5260205f20905b815481529060010190602001808311612bfe57829003601f168201915b50505050508152505081526020019060010190612ae4565b82612c3d81614afa565b612c595760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0384165f9081526008602052604090206124b7838583615a50565b612c83614aa1565b6001612c90828483615a50565b507f5cb699b2db2744e5674f4562b93100efd8d58a530debe3177fb5617f1607334e8282604051612cc2929190615cf8565b60405180910390a15050565b82612cd881614afa565b612cf45760405162461bcd60e51b8152600401610876906159c2565b612d3883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060049150614c669050565b6001600160a01b0384165f9081526007602052604090206004016108e9838583615a50565b6001600160a01b0381165f9081526004602052604090205460609060ff16612d85575f610afa565b6001600160a01b0382165f908152600a602052604081205490612da9826002615cce565b6001600160401b03811115612dc057612dc06159df565b604051908082528060200260200182016040528015612df357816020015b6060815260200190600190039081612dde5790505b5090505f5b82811015611d1c576001600160a01b0385165f908152600a602052604090208054612e4c919083908110612e2e57612e2e615b04565b5f9182526020909120600290910201546001600160a01b0316614ef5565b82612e58836002615cce565b81518110612e6857612e68615b04565b6020026020010181905250600a5f866001600160a01b03166001600160a01b031681526020019081526020015f208181548110612ea757612ea7615b04565b905f5260205f2090600202016001018054612ec19061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054612eed9061598a565b8015612f385780601f10612f0f57610100808354040283529160200191612f38565b820191905f5260205f20905b815481529060010190602001808311612f1b57829003601f168201915b505050505082826002612f4b9190615cce565b612f56906001615ce5565b81518110612f6657612f66615b04565b6020908102919091010152600101612df8565b80612f8381614afa565b612f9f5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0382165f908152600c60209081526040808320600e8352818420600b8452828520600d90945291842090939192915b8454811015613189575f858281548110612ff157612ff1615b04565b5f9182526020808320909101546001600160a01b03908116808452600d83526040808520928d16855291835281842054818552600b909352922054919250908110158061308357506001600160a01b038281165f908152600b602052604090208054918b16918390811061306757613067615b04565b5f9182526020909120600290910201546001600160a01b031614155b156131745786545f9061309890600190615be2565b905080841461311d575f8882815481106130b4576130b4615b04565b905f5260205f20015f9054906101000a90046001600160a01b03169050808986815481106130e4576130e4615b04565b5f91825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290889052604090208490555b8780548061312d5761312d615cba565b5f828152602080822083015f1990810180546001600160a01b03191690559092019092556001600160a01b038516825288905260408120558361316f81615d26565b945050505b5050808061318190615d3b565b915050612fd5565b505f5b82548110156115c9575f8382815481106131a8576131a8615b04565b5f91825260208083206002909202909101546001600160a01b038b8116845288835260408085205491909216808552600c9093529220549092508110158061323057506001600160a01b038281165f908152600c602052604090208054918b16918390811061321957613219615b04565b5f918252602090912001546001600160a01b031614155b156134005784545f9061324590600190615be2565b9050808414613396575f86828154811061326157613261615b04565b5f9182526020918290206040805180820190915260029092020180546001600160a01b03168252600181018054929391929184019161329f9061598a565b80601f01602080910402602001604051908101604052809291908181526020018280546132cb9061598a565b80156133165780601f106132ed57610100808354040283529160200191613316565b820191905f5260205f20905b8154815290600101906020018083116132f957829003601f168201915b50505050508152505090508087868154811061333457613334615b04565b5f91825260209182902083516002929092020180546001600160a01b0319166001600160a01b039092169190911781559082015160018201906133779082615b18565b505090516001600160a01b03165f908152602087905260409020859055505b858054806133a6576133a6615cba565b5f8281526020812060025f199093019283020180546001600160a01b0319168155906133d56001830182615233565b505090556001600160a01b0383165f90815260208690526040812055836133fb81615d26565b945050505b5050808061340d90615d3b565b91505061318c565b8161341f81614afa565b61343b5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0383165f908152600f6020526040902054821061345d575f80fd5b6001600160a01b0383165f908152600f60205260409020805461348290600190615be2565b8154811061349257613492615b04565b905f5260205f2001600f5f856001600160a01b03166001600160a01b031681526020019081526020015f2083815481106134ce576134ce615b04565b905f5260205f200190816134e29190615bf5565b506001600160a01b0383165f908152600f6020526040902080548061350957613509615cba565b600190038181905f5260205f20015f6135229190615233565b9055505050565b8061353381614afa565b61354f5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0382165f908152600460205260409020805461ff00191661010017905561357c82614f0b565b604051600181526001600160a01b038316907fcecdf9dd6f2193d677b10450a2e4ff64d6b61a566bdc6e34ab5c9fc2f797960b9060200160405180910390a25050565b6001600160a01b0381165f9081526004602052604090205460609060ff166135e5575f80fd5b6001600160a01b0382165f908152600a6020908152604080832080548251818502810185019093528083529193909284015b82821015611215575f848152602090819020604080518082019091526002850290910180546001600160a01b03168252600181018054929391929184019161365e9061598a565b80601f016020809104026020016040519081016040528092919081815260200182805461368a9061598a565b80156136d55780601f106136ac576101008083540402835291602001916136d5565b820191905f5260205f20905b8154815290600101906020018083116136b857829003601f168201915b50505050508152505081526020019060010190613617565b6001600160a01b0381165f9081526004602052604090205460609060ff16613715575f610afa565b6001600160a01b0382165f908152600b602052604081205490613739826002615cce565b6001600160401b03811115613750576137506159df565b60405190808252806020026020018201604052801561378357816020015b606081526020019060019003908161376e5790505b5090505f5b82811015611d1c576001600160a01b0385165f908152600b6020526040902080546137be919083908110612e2e57612e2e615b04565b826137ca836002615cce565b815181106137da576137da615b04565b6020026020010181905250600b5f866001600160a01b03166001600160a01b031681526020019081526020015f20818154811061381957613819615b04565b905f5260205f20906002020160010180546138339061598a565b80601f016020809104026020016040519081016040528092919081815260200182805461385f9061598a565b80156138aa5780601f10613881576101008083540402835291602001916138aa565b820191905f5260205f20905b81548152906001019060200180831161388d57829003601f168201915b5050505050828260026138bd9190615cce565b6138c8906001615ce5565b815181106138d8576138d8615b04565b6020908102919091010152600101613788565b826138f581614afa565b6139115760405162461bcd60e51b8152600401610876906159c2565b61395583838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060029150614c669050565b6001600160a01b0384165f9081526007602052604090206002016108e9838583615a50565b6001600160a01b0381165f9081526004602052604090205460609060ff166139a2575f610afa565b6001600160a01b0382165f9081526012602052604081205490816001600160401b038111156139d3576139d36159df565b604051908082528060200260200182016040528015613a0657816020015b60608152602001906001900390816139f15790505b5090505f5b82811015611d1c576001600160a01b0385165f9081526012602052604090208054613a5a919083908110613a4157613a41615b04565b5f918252602090912001546001600160a01b0316614ef5565b828281518110613a6c57613a6c615b04565b6020908102919091010152600101613a0b565b8a613a8981614afa565b613aa55760405162461bcd60e51b8152600401610876906159c2565b613ae68b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92018290525060a093509150614c669050565b613b2a87878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060029150614c669050565b613b6e85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060039150614c669050565b613bb283838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060049150614c669050565b613bf789898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610140925060019150614c669050565b6001600160a01b038c165f90815260076020526040902080613c1a8c8e83615a50565b5060018101613c2a8a8c83615a50565b5060028101613c3a888a83615a50565b5060038101613c4a868883615a50565b5060048101613c5a848683615a50565b50613c648d614dd6565b613c6d8d610923565b50505050505050505050505050565b6001600160a01b0381165f908152600c6020526040812054606091613ca2826002615cce565b6001600160401b03811115613cb957613cb96159df565b604051908082528060200260200182016040528015613cec57816020015b6060815260200190600190039081613cd75790505b5090505f5b82811015611d1c576001600160a01b0385165f908152600c60205260408120805483908110613d2257613d22615b04565b5f9182526020808320909101546001600160a01b03908116808452600d83526040808520928b16855291835281842054818552600b90935290832080549194509192919083908110613d7657613d76615b04565b905f5260205f2090600202016001018054613d909061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054613dbc9061598a565b8015613e075780601f10613dde57610100808354040283529160200191613e07565b820191905f5260205f20905b815481529060010190602001808311613dea57829003601f168201915b50505050509050613e1783614ef5565b85613e23866002615cce565b81518110613e3357613e33615b04565b60209081029190910101528085613e4b866002615cce565b613e56906001615ce5565b81518110613e6657613e66615b04565b6020908102919091010152505050600101613cf1565b6001600160a01b0381165f9081526004602052604090205460609060ff16613ea4575f610afa565b6001600160a01b0382165f9081526010602052604081205490816001600160401b03811115613ed557613ed56159df565b604051908082528060200260200182016040528015613f0857816020015b6060815260200190600190039081613ef35790505b5090505f5b82811015611d1c576001600160a01b0385165f9081526010602052604090208054613f43919083908110613a4157613a41615b04565b828281518110613f5557613f55615b04565b6020908102919091010152600101613f0d565b81613f7281614afa565b613f8e5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b038083165f818152601160209081526040808320948816835293815283822054928252601090529190912080548190613fd090600190615be2565b81548110613fe057613fe0615b04565b905f5260205f20015f9054906101000a90046001600160a01b031681838154811061400d5761400d615b04565b5f91825260208083209190910180546001600160a01b0319166001600160a01b039485161790559186168152601190915260408120825484929084908490811061405957614059615b04565b5f9182526020808320909101546001600160a01b03168352820192909252604001902055805481908061408e5761408e615cba565b5f828152602080822083015f1990810180546001600160a01b03191690559092019092556001600160a01b03868116808452601183526040808520928a168086529284528085208590556013845280852091855290835280842054918452601290925291208054819061410390600190615be2565b8154811061411357614113615b04565b905f5260205f20015f9054906101000a90046001600160a01b031681838154811061414057614140615b04565b5f91825260208083209190910180546001600160a01b0319166001600160a01b039485161790559189168152601390915260408120825484929084908490811061418c5761418c615b04565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205580548190806141c1576141c1615cba565b5f82815260208082205f19908401810180546001600160a01b03191690559092019092556001600160a01b03898116808452601383526040808520928b16808652928452808520859055519384529290917f6f0bc8b3499f361c2ff7768f2bd3079d0fea5d0da28fd0189a7da7eef7d4c6ee910160405180910390a350505050505050565b8261425081614afa565b61426c5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0384165f9081526004602052604090206001016124b7838583615a50565b8161429b81614afa565b6142b75760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0383165f908152600a602052604090205482106142d9575f80fd5b6001600160a01b0383165f908152600a6020526040902080546142fe90600190615be2565b8154811061430e5761430e615b04565b905f5260205f209060020201600a5f856001600160a01b03166001600160a01b031681526020019081526020015f20838154811061434e5761434e615b04565b5f9182526020909120825460029092020180546001600160a01b0319166001600160a01b0390921691909117815560018082019061438e90840182615bf5565b5050506001600160a01b0383165f908152600a602052604090208054806143b7576143b7615cba565b5f8281526020812060025f199093019283020180546001600160a01b0319168155906119936001830182615233565b600180546143f39061598a565b80601f016020809104026020016040519081016040528092919081815260200182805461441f9061598a565b801561446a5780601f106144415761010080835404028352916020019161446a565b820191905f5260205f20905b81548152906001019060200180831161444d57829003601f168201915b505050505081565b8161447c81614afa565b6144985760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b038083165f908152600d60209081526040808320938716835292905220548015158061450e57506001600160a01b038381165f908152600b602052604081208054928716929091906144f3576144f3615b04565b5f9182526020909120600290910201546001600160a01b0316145b6145435760405162461bcd60e51b815260206004820152600660248201526508515e1a5cdd60d21b6044820152606401610876565b6001600160a01b038084165f908152600b60209081526040808320600d83528184209489168452600c8352818420600e9093529083208154919493909161458c90600190615be2565b90508086146146dd575f8582815481106145a8576145a8615b04565b5f9182526020918290206040805180820190915260029092020180546001600160a01b0316825260018101805492939192918401916145e69061598a565b80601f01602080910402602001604051908101604052809291908181526020018280546146129061598a565b801561465d5780601f106146345761010080835404028352916020019161465d565b820191905f5260205f20905b81548152906001019060200180831161464057829003601f168201915b50505050508152505090508086888154811061467b5761467b615b04565b5f91825260209182902083516002929092020180546001600160a01b0319166001600160a01b039092169190911781559082015160018201906146be9082615b18565b505090516001600160a01b03165f908152602086905260409020879055505b848054806146ed576146ed615cba565b5f8281526020812060025f199093019283020180546001600160a01b03191681559061471c6001830182615233565b505090556001600160a01b03808a165f90815260208681526040808320839055928b1682528490522054835461475490600190615be2565b91508181146147d9575f84838154811061477057614770615b04565b905f5260205f20015f9054906101000a90046001600160a01b03169050808583815481106147a0576147a0615b04565b5f91825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290849052604090208190555b838054806147e9576147e9615cba565b5f828152602080822083015f1990810180546001600160a01b03191690559092019092556001600160a01b038b8116808452918690526040808420939093559151918c16917f3294fc25de801ec383dc5fab48b0d8f281d893fd3f80bf56e15665a4ffd570e49061211e906020808252601190820152702232b632ba32b210313c903bb934ba32b960791b604082015260600190565b60408051600980825261014082019092526060915f9190816020015b606081526020019060019003908161489b5750506001600160a01b0384165f9081526004602052604090205490915060ff1615614a25576148db83610ad5565b815f815181106148ed576148ed615b04565b602002602001018190525061490183611a8c565b8160018151811061491457614914615b04565b602002602001018190525061492883612d5d565b8160028151811061493b5761493b615b04565b602002602001018190525061494f83613e7c565b8160038151811061496257614962615b04565b60200260200101819052506149768361397a565b8160048151811061498957614989615b04565b602002602001018190525061499d836136ed565b816005815181106149b0576149b0615b04565b60200260200101819052506149c483613c7c565b816006815181106149d7576149d7615b04565b60200260200101819052506149eb83611113565b816007815181106149fe576149fe615b04565b6020026020010181905250614a1283610ffc565b8160088151811061110257611102615b04565b92915050565b614a33614aa1565b6001600160a01b038116614a985760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610876565b61128c81614f78565b5f546001600160a01b03163314612a8a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610876565b6001600160a01b0381165f90815260046020526040812054610100900460ff1615614b515760405162461bcd60e51b8152602060048201526007602482015266109b1bd8dad95960ca1b6044820152606401610876565b336001600160a01b038316811480614be45750600654604051638988eea960e01b81526001600160a01b03838116600483015285811660248301523060448301525f606483015290911690638988eea990608401602060405180830381865afa158015614bc0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614be49190615d53565b80614c5f5750826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614c26573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614c4a9190615d72565b6001600160a01b0316816001600160a01b0316145b9392505050565b60408051610140810182526005610100820190815264416c69617360d81b61012083015281528151808301835260068082526511195d185a5b60d21b60208381019190915280840192909252835180850185529081526514dbd8da585b60d21b8183015282840152825180840184526003808252622bb2b160e91b82840152606084019190915283518085018552600781526647616c6c65727960c81b818401526080840152835180850185526004808252634c696e6b60e01b8285015260a0850191909152845180860186529182526254616760e81b8284015260c084019190915283518085019094528352634e6f746560e01b9083015260e08101919091525f818360088110614d7a57614d7a615b04565b6020020151604051602001614d8f9190615d8d565b60408051601f198184030181529190529050614dac846001615ce5565b8551108190614dce5760405162461bcd60e51b815260040161087691906158e4565b505050505050565b6001600160a01b0381165f9081526004602052604090205460ff1661128c576001600160a01b0381165f908152600460205260408120805460ff191660011790556002805491614e2583615d3b565b9091555050604051600181526001600160a01b038216907f248e7111eafe9d4fa83a7ee922e702047cf0db3d086a16aebb086341d45c9cd39060200161222d565b60605f614e7283614fc7565b60010190505f816001600160401b03811115614e9057614e906159df565b6040519080825280601f01601f191660200182016040528015614eba576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084614ec457509392505050565b6060614a25826001600160a01b0316601461509e565b6001600160a01b0381165f908152600460205260408120805460ff191690556002805491614f3883615d26565b90915550506040515f81526001600160a01b038216907f248e7111eafe9d4fa83a7ee922e702047cf0db3d086a16aebb086341d45c9cd39060200161222d565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106150055772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310615031576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061504f57662386f26fc10000830492506010015b6305f5e1008310615067576305f5e100830492506008015b612710831061507b57612710830492506004015b6064831061508d576064830492506002015b600a8310614a255760010192915050565b60605f6150ac836002615cce565b6150b7906002615ce5565b6001600160401b038111156150ce576150ce6159df565b6040519080825280601f01601f1916602001820160405280156150f8576020820181803683370190505b509050600360fc1b815f8151811061511257615112615b04565b60200101906001600160f81b03191690815f1a905350600f60fb1b8160018151811061514057615140615b04565b60200101906001600160f81b03191690815f1a9053505f615162846002615cce565b61516d906001615ce5565b90505b60018111156151e4576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106151a1576151a1615b04565b1a60f81b8282815181106151b7576151b7615b04565b60200101906001600160f81b03191690815f1a90535060049490941c936151dd81615d26565b9050615170565b508315614c5f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610876565b50805461523f9061598a565b5f825580601f1061524e575050565b601f0160209004905f5260205f209081019061128c91905b80821115615279575f8155600101615266565b5090565b5f6020828403121561528d575f80fd5b5035919050565b6001600160a01b038116811461128c575f80fd5b80356152b381615294565b919050565b5f602082840312156152c8575f80fd5b8135614c5f81615294565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b841515815283151560208201528215156040820152608060608201525f61532b60808301846152d3565b9695505050505050565b5f8083601f840112615345575f80fd5b5081356001600160401b0381111561535b575f80fd5b602083019150836020828501011115615372575f80fd5b9250929050565b5f805f6040848603121561538b575f80fd5b833561539681615294565b925060208401356001600160401b038111156153b0575f80fd5b6153bc86828701615335565b9497909650939450505050565b5f805f805f80608087890312156153de575f80fd5b86356153e981615294565b95506020870135945060408701356001600160401b038082111561540b575f80fd5b6154178a838b01615335565b9096509450606089013591508082111561542f575f80fd5b5061543c89828a01615335565b979a9699509497509295939492505050565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b828110156154a357603f198886030184526154918583516152d3565b94509285019290850190600101615475565b5092979650505050505050565b5f805f805f606086880312156154c4575f80fd5b85356154cf81615294565b945060208601356001600160401b03808211156154ea575f80fd5b6154f689838a01615335565b9096509450604088013591508082111561550e575f80fd5b5061551b88828901615335565b969995985093965092949392505050565b5f805f805f60808688031215615540575f80fd5b853561554b81615294565b945060208601359350604086013561556281615294565b925060608601356001600160401b0381111561557c575f80fd5b61551b88828901615335565b5f805f6060848603121561559a575f80fd5b83356155a581615294565b925060208401356155b581615294565b929592945050506040919091013590565b5f80604083850312156155d7575f80fd5b82356155e281615294565b915060208301356155f281615294565b809150509250929050565b5f806040838503121561560e575f80fd5b823561561981615294565b946020939093013593505050565b5f8060408385031215615638575f80fd5b823561564381615294565b9150602083013560ff811681146155f2575f80fd5b5f805f806060858703121561566b575f80fd5b843561567681615294565b9350602085013561568681615294565b925060408501356001600160401b038111156156a0575f80fd5b6156ac87828801615335565b95989497509550505050565b5f60208083018184528085518083526040925060408601915060408160051b8701018488015f5b8381101561572f57888303603f1901855281518051878552615703888601826152d3565b91890151858303868b015291905061571b81836152d3565b9689019694505050908601906001016156df565b509098975050505050505050565b5f806020838503121561574e575f80fd5b82356001600160401b03811115615763575f80fd5b61576f85828601615335565b90969095509350505050565b5f60208083018184528085518083526040925060408601915060408160051b8701018488015f5b8381101561572f57888303603f19018552815180516001600160a01b031684528701518784018790526157d7878501826152d3565b95880195935050908601906001016157a2565b5f805f805f805f805f805f60c08c8e031215615804575f80fd5b61580d8c6152a8565b9a506001600160401b038060208e01351115615827575f80fd5b6158378e60208f01358f01615335565b909b50995060408d013581101561584c575f80fd5b61585c8e60408f01358f01615335565b909950975060608d0135811015615871575f80fd5b6158818e60608f01358f01615335565b909750955060808d0135811015615896575f80fd5b6158a68e60808f01358f01615335565b909550935060a08d01358110156158bb575f80fd5b506158cc8d60a08e01358e01615335565b81935080925050509295989b509295989b9093969950565b602081525f614c5f60208301846152d3565b5f60208083018184528085518083526040860191506005925060408160051b8701018488015f5b8381101561572f57888303603f1901855281518051808552908801908885019080891b86018a015f5b8281101561597457601f198883030184526159628286516152d3565b948c0194938c01939150600101615946565b50978a019795505050918701915060010161591d565b600181811c9082168061599e57607f821691505b6020821081036159bc57634e487b7160e01b5f52602260045260245ffd5b50919050565b60208082526003908201526221417560e81b604082015260600190565b634e487b7160e01b5f52604160045260245ffd5b601f821115615a3757805f5260205f20601f840160051c81016020851015615a185750805b601f840160051c820191505b818110156124b7575f8155600101615a24565b505050565b5f19600383901b1c191660019190911b1790565b6001600160401b03831115615a6757615a676159df565b615a7b83615a75835461598a565b836159f3565b5f601f841160018114615aa7575f8515615a955750838201355b615a9f8682615a3c565b8455506124b7565b5f83815260208120601f198716915b82811015615ad65786850135825560209485019460019092019101615ab6565b5086821015615af2575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b634e487b7160e01b5f52603260045260245ffd5b81516001600160401b03811115615b3157615b316159df565b615b4581615b3f845461598a565b846159f3565b602080601f831160018114615b73575f8415615b615750858301515b615b6b8582615a3c565b865550614dce565b5f85815260208120601f198616915b82811015615ba157888601518255948401946001909101908401615b82565b5085821015615bbe57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b5f52601160045260245ffd5b81810381811115614a2557614a25615bce565b818103615c00575050565b615c0a825461598a565b6001600160401b03811115615c2157615c216159df565b615c2f81615b3f845461598a565b5f601f821160018114615c5b575f8315615c495750848201545b615c538482615a3c565b8555506124b7565b5f8581526020808220868352908220601f198616925b83811015615c915782860154825560019586019590910190602001615c71565b5085831015615bbe579301545f1960f8600387901b161c19169092555050600190811b01905550565b634e487b7160e01b5f52603160045260245ffd5b8082028115828204841417614a2557614a25615bce565b80820180821115614a2557614a25615bce565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b5f81615d3457615d34615bce565b505f190190565b5f60018201615d4c57615d4c615bce565b5060010190565b5f60208284031215615d63575f80fd5b81518015158114614c5f575f80fd5b5f60208284031215615d82575f80fd5b8151614c5f81615294565b5f82518060208501845e6820746f6f206c6f6e6760b81b92019182525060090191905056fea2646970667358221220297253ef4e48a9f657b8666768151164aa30438ffbc1e7f1aead72c5671c063f64736f6c63430008190033

Deployed Bytecode

0x608060405234801561000f575f80fd5b50600436106102ff575f3560e01c8063715018a611610195578063b4ab0337116100e4578063c75bc5921161009e578063e377ac3111610079578063e377ac3114610707578063e4c80cd01461071c578063e89d22d71461072f578063f2fde38b1461074f575f80fd5b8063c75bc592146106ce578063caf54d8e146106e1578063ccb4dfd7146106f4575f80fd5b8063b4ab03371461065c578063b4bd9e561461066f578063b59f9fb914610682578063c18cd6ee14610695578063c4889705146106a8578063c4cdcebe146106bb575f80fd5b80638c3a58fe1161014f5780639c2195481161012a5780639c219548146105db578063a449d90a146105ee578063a5c1595914610601578063ad8cc5ba1461063c575f80fd5b80638c3a58fe146105a55780638da5cb5b146105b85780638e62c1f9146105c8575f80fd5b8063715018a61461052d57806376e819bc14610535578063789932861461054c57806379cecf111461056c5780638474f1f71461057f578063855c17c114610592575f80fd5b80634094528f1161025157806350ee5de01161020b5780635ff4bd3b116101e65780635ff4bd3b146104e157806367263c77146104f457806367cc51301461050757806369f51c3b1461051a575f80fd5b806350ee5de0146104a857806353b145c2146104bb578063540c7db5146104ce575f80fd5b80634094528f1461043657806346e80caa146104495780634715dc4f1461045c57806347635b9b1461046f5780634cfbc0b6146104825780634efc647714610495575f80fd5b80631abf2716116102bc5780632662795f116102975780632662795f146103ea5780632c014422146103fd578063362c7259146104105780633a1c6ffe14610423575f80fd5b80631abf2716146103a45780631c1df036146103b75780631dfb1a21146103d7575f80fd5b80630156a98a1461030357806301e882081461033357806302a7c7da146103565780630ce44b0f1461036b5780630eda5e481461037e57806314df9e4314610391575b5f80fd5b61031661031136600461527d565b610762565b6040516001600160a01b0390911681526020015b60405180910390f35b6103466103413660046152b8565b61078a565b60405161032a9493929190615301565b61036961036436600461527d565b610843565b005b610369610379366004615379565b610850565b61036961038c3660046152b8565b6108f9565b61036961039f3660046152b8565b610923565b6103696103b23660046153c9565b610969565b6103ca6103c53660046152b8565b610ad5565b60405161032a919061544e565b6103ca6103e53660046152b8565b610ffc565b6103ca6103f83660046152b8565b611113565b61036961040b3660046152b8565b611220565b61036961041e366004615379565b611298565b6103696104313660046154b0565b611321565b61036961044436600461552c565b6114a5565b610369610457366004615588565b6115d2565b61036961046a3660046155c6565b611634565b61036961047d3660046155fd565b611855565b610369610490366004615379565b61199c565b6103696104a3366004615627565b611a2b565b6103ca6104b63660046152b8565b611a8c565b6103696104c93660046155c6565b611d24565b6103696104dc3660046152b8565b612132565b6103696104ef3660046152b8565b612238565b610369610502366004615379565b61241b565b610369610515366004615658565b6124be565b610369610528366004615658565b6125e4565b610369612a79565b61053e60025481565b60405190815260200161032a565b61055f61055a3660046152b8565b612a8c565b60405161032a91906156b8565b61036961057a366004615379565b612c33565b61036961058d36600461573d565b612c7b565b6103696105a0366004615379565b612cce565b6103ca6105b33660046152b8565b612d5d565b5f546001600160a01b0316610316565b6103696105d63660046152b8565b612f79565b6103696105e93660046155fd565b613415565b6103696105fc3660046152b8565b613529565b61062c61060f3660046152b8565b6001600160a01b03165f9081526004602052604090205460ff1690565b604051901515815260200161032a565b61064f61064a3660046152b8565b6135bf565b60405161032a919061577b565b6103ca61066a3660046152b8565b6136ed565b61036961067d366004615379565b6138eb565b6103ca6106903660046152b8565b61397a565b6103696106a33660046157ea565b613a7f565b6103ca6106b63660046152b8565b613c7c565b6103ca6106c93660046152b8565b613e7c565b6103696106dc3660046155c6565b613f68565b6103696106ef366004615379565b614246565b6103696107023660046155fd565b614291565b61070f6143e6565b60405161032a91906158e4565b61036961072a3660046155c6565b614472565b61074261073d3660046152b8565b61487f565b60405161032a91906158f6565b61036961075d3660046152b8565b614a2b565b60038181548110610771575f80fd5b5f918252602090912001546001600160a01b0316905081565b60046020525f90815260409020805460018201805460ff8084169461010085048216946201000090049091169290916107c29061598a565b80601f01602080910402602001604051908101604052809291908181526020018280546107ee9061598a565b80156108395780601f1061081057610100808354040283529160200191610839565b820191905f5260205f20905b81548152906001019060200180831161081c57829003601f168201915b5050505050905084565b61084b614aa1565b600555565b8261085a81614afa565b61087f5760405162461bcd60e51b8152600401610876906159c2565b60405180910390fd5b6108c483838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610140925060019150614c669050565b6001600160a01b0384165f9081526007602052604090206001016108e9838583615a50565b506108f384614dd6565b50505050565b610901614aa1565b600680546001600160a01b0319166001600160a01b0392909216919091179055565b8061092d81614afa565b6109495760405162461bcd60e51b8152600401610876906159c2565b506001600160a01b03165f90815260076020526040902042600590910155565b8561097381614afa565b61098f5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0387165f9081526009602052604090205486106109b1575f80fd5b6109f585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060059150614c669050565b610a3983838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060019150614c669050565b6001600160a01b0387165f90815260096020526040902080548691869189908110610a6657610a66615b04565b905f5260205f2090600202015f019182610a81929190615a50565b506001600160a01b0387165f90815260096020526040902080548491849189908110610aaf57610aaf615b04565b905f5260205f2090600202016001019182610acb929190615a50565b5050505050505050565b6001600160a01b0381165f9081526004602052604090205460609060ff16610b345760095b604051908082528060200260200182016040528015610b2d57816020015b6060815260200190600190039081610b185790505b5092915050565b6001600160a01b0382165f9081526007602052604080822081516101208101909252805482908290610b659061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054610b919061598a565b8015610bdc5780601f10610bb357610100808354040283529160200191610bdc565b820191905f5260205f20905b815481529060010190602001808311610bbf57829003601f168201915b50505050508152602001600182018054610bf59061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054610c219061598a565b8015610c6c5780601f10610c4357610100808354040283529160200191610c6c565b820191905f5260205f20905b815481529060010190602001808311610c4f57829003601f168201915b50505050508152602001600282018054610c859061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054610cb19061598a565b8015610cfc5780601f10610cd357610100808354040283529160200191610cfc565b820191905f5260205f20905b815481529060010190602001808311610cdf57829003601f168201915b50505050508152602001600382018054610d159061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054610d419061598a565b8015610d8c5780601f10610d6357610100808354040283529160200191610d8c565b820191905f5260205f20905b815481529060010190602001808311610d6f57829003601f168201915b50505050508152602001600482018054610da59061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054610dd19061598a565b8015610e1c5780601f10610df357610100808354040283529160200191610e1c565b820191905f5260205f20905b815481529060010190602001808311610dff57829003601f168201915b505050918352505060058201546020820152600682015460408201526007909101546001600160a01b0381166060830152600160a01b900460ff1660809091015290505f6009604051908082528060200260200182016040528015610e9557816020015b6060815260200190600190039081610e805790505b509050815f0151815f81518110610eae57610eae615b04565b6020026020010181905250816020015181600181518110610ed157610ed1615b04565b6020026020010181905250816040015181600281518110610ef457610ef4615b04565b6020026020010181905250816060015181600381518110610f1757610f17615b04565b6020026020010181905250816080015181600481518110610f3a57610f3a615b04565b6020026020010181905250610f5682610100015160ff16614e66565b81600581518110610f6957610f69615b04565b6020026020010181905250610f818260e00151614ef5565b81600681518110610f9457610f94615b04565b6020026020010181905250610fac8260c00151614e66565b81600781518110610fbf57610fbf615b04565b6020026020010181905250610fd78260a00151614e66565b81600881518110610fea57610fea615b04565b60209081029190910101529392505050565b6001600160a01b0381165f9081526004602052604090205460609060ff16611024575f610afa565b6040805160018082528183019092525f91816020015b606081526020019060019003908161103a5750506001600160a01b0384165f9081526008602052604090208054919250906110749061598a565b80601f01602080910402602001604051908101604052809291908181526020018280546110a09061598a565b80156110eb5780601f106110c2576101008083540402835291602001916110eb565b820191905f5260205f20905b8154815290600101906020018083116110ce57829003601f168201915b5050505050815f8151811061110257611102615b04565b602090810291909101015292915050565b6001600160a01b0381165f9081526004602052604090205460609060ff1661113b575f610afa565b6001600160a01b0382165f908152600f6020908152604080832080548251818502810185019093528083529193909284015b82821015611215578382905f5260205f2001805461118a9061598a565b80601f01602080910402602001604051908101604052809291908181526020018280546111b69061598a565b80156112015780601f106111d857610100808354040283529160200191611201565b820191905f5260205f20905b8154815290600101906020018083116111e457829003601f168201915b50505050508152602001906001019061116d565b505050509050919050565b61122981614afa565b806112485750335f9081526004602052604090205462010000900460ff165b6112645760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0381165f9081526004602052604090205460ff1661128f5761128c81614dd6565b50565b61128c81614f0b565b826112a281614afa565b6112be5760405162461bcd60e51b8152600401610876906159c2565b6112ff83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92018290525060a093509150614c669050565b6001600160a01b0384165f9081526007602052604090206108e9838583615a50565b8461132b81614afa565b6113475760405162461bcd60e51b8152600401610876906159c2565b61138b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060059150614c669050565b6113cf83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060019150614c669050565b6040805160606020601f8801819004028201810183529181018681525f9282919089908990819085018382808284375f92019190915250505090825250604080516020601f8801819004810282018101909252868152918101919087908790819084018382808284375f9201829052509390945250506001600160a01b038a16815260096020908152604082208054600181018255908352912083519394508493600290920201915081906114849082615b18565b50602082015160018201906114999082615b18565b50505050505050505050565b846114af81614afa565b6114cb5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0386165f908152600a602052604090205485106114ed575f80fd5b61153183838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060019150614c669050565b6001600160a01b0386165f908152600a6020526040902080548591908790811061155d5761155d615b04565b5f918252602080832060029290920290910180546001600160a01b0319166001600160a01b039485161790559188168152600a90915260409020805484918491889081106115ad576115ad615b04565b905f5260205f20906002020160010191826115c9929190615a50565b50505050505050565b826115dc81614afa565b6115f85760405162461bcd60e51b8152600401610876906159c2565b506001600160a01b039283165f90815260076020819052604090912090810180546001600160a01b031916939094169290921790925560060155565b8161163e81614afa565b61165a5760405162461bcd60e51b8152600401610876906159c2565b816001600160a01b0316836001600160a01b031603611677575f80fd5b6001600160a01b038083165f9081526011602090815260408083209387168352929052205415801561170757506001600160a01b0382165f90815260106020526040902054158061170757506001600160a01b038281165f9081526010602052604081208054928616929091906116f0576116f0615b04565b5f918252602090912001546001600160a01b031614155b6117405760405162461bcd60e51b815260206004820152600a60248201526952657370656374696e6760b01b6044820152606401610876565b6001600160a01b038281165f81815260106020908152604082208054600180820183558285529284200180546001600160a01b03191695891695909517909455919052905461178f9190615be2565b6001600160a01b038084165f81815260116020908152604080832094891680845294825280832095909555601281529381208054600181810183558284529583200180546001600160a01b03191690931790925591909152546117f29190615be2565b6001600160a01b038481165f8181526013602090815260408083209488168084529482529182902094909455516001815290927f6f0bc8b3499f361c2ff7768f2bd3079d0fea5d0da28fd0189a7da7eef7d4c6ee910160405180910390a3505050565b8161185f81614afa565b61187b5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0383165f90815260096020526040902054821061189d575f80fd5b6001600160a01b0383165f90815260096020526040902080546118c290600190615be2565b815481106118d2576118d2615b04565b905f5260205f20906002020160095f856001600160a01b03166001600160a01b031681526020019081526020015f20838154811061191257611912615b04565b5f91825260209091206002909102018061192c8382615bf5565b5060018181019061193f90840182615bf5565b5050506001600160a01b0383165f90815260096020526040902080548061196857611968615cba565b5f828152602081205f19909201916002830201906119868282615233565b611993600183015f615233565b50509055505050565b826119a681614afa565b6119c25760405162461bcd60e51b8152600401610876906159c2565b611a0683838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060039150614c669050565b6001600160a01b0384165f9081526007602052604090206003016108e9838583615a50565b81611a3581614afa565b611a515760405162461bcd60e51b8152600401610876906159c2565b506001600160a01b039091165f90815260076020819052604090912001805460ff909216600160a01b0260ff60a01b19909216919091179055565b6001600160a01b0381165f9081526004602052604090205460609060ff16611ab4575f610afa565b6001600160a01b0382165f9081526009602052604081205490611ad8826002615cce565b6001600160401b03811115611aef57611aef6159df565b604051908082528060200260200182016040528015611b2257816020015b6060815260200190600190039081611b0d5790505b5090505f5b82811015611d1c576001600160a01b0385165f908152600960205260409020805482908110611b5857611b58615b04565b905f5260205f2090600202015f018054611b719061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054611b9d9061598a565b8015611be85780601f10611bbf57610100808354040283529160200191611be8565b820191905f5260205f20905b815481529060010190602001808311611bcb57829003601f168201915b505050505082826002611bfb9190615cce565b81518110611c0b57611c0b615b04565b602002602001018190525060095f866001600160a01b03166001600160a01b031681526020019081526020015f208181548110611c4a57611c4a615b04565b905f5260205f2090600202016001018054611c649061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054611c909061598a565b8015611cdb5780601f10611cb257610100808354040283529160200191611cdb565b820191905f5260205f20905b815481529060010190602001808311611cbe57829003601f168201915b505050505082826002611cee9190615cce565b611cf9906001615ce5565b81518110611d0957611d09615b04565b6020908102919091010152600101611b27565b509392505050565b81611d2e81614afa565b611d4a5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b038084165f818152600d6020908152604080832094871680845294825280832054938352600b9091529020805491929183908110611d9157611d91615b04565b5f9182526020909120600290910201546001600160a01b031614611de05760405162461bcd60e51b815260206004820152600660248201526508515e1a5cdd60d21b6044820152606401610876565b6001600160a01b038085165f908152600b60209081526040808320600d83528184209488168452600c8352818420600e90935290832081549194939091611e2990600190615be2565b9050808614611f7a575f858281548110611e4557611e45615b04565b5f9182526020918290206040805180820190915260029092020180546001600160a01b031682526001810180549293919291840191611e839061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054611eaf9061598a565b8015611efa5780601f10611ed157610100808354040283529160200191611efa565b820191905f5260205f20905b815481529060010190602001808311611edd57829003601f168201915b505050505081525050905080868881548110611f1857611f18615b04565b5f91825260209182902083516002929092020180546001600160a01b0319166001600160a01b03909216919091178155908201516001820190611f5b9082615b18565b505090516001600160a01b03165f908152602086905260409020879055505b84805480611f8a57611f8a615cba565b5f8281526020812060025f199093019283020180546001600160a01b031916815590611fb96001830182615233565b505090556001600160a01b038089165f90815260208681526040808320839055928c16825284905220548354611ff190600190615be2565b9150818114612076575f84838154811061200d5761200d615b04565b905f5260205f20015f9054906101000a90046001600160a01b031690508085838154811061203d5761203d615b04565b5f91825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290849052604090208190555b8380548061208657612086615cba565b5f828152602080822083015f1990810180546001600160a01b03191690559092019092556001600160a01b038c8116808452918690526040808420939093559151918b16917f3294fc25de801ec383dc5fab48b0d8f281d893fd3f80bf56e15665a4ffd570e49061211e906020808252601390820152722232b632ba32b210313c903932b1b2b4bb32b960691b604082015260600190565b60405180910390a350505050505050505050565b335f9081526004602052604090205462010000900460ff16801561215f5750336001600160a01b03821614155b612167575f80fd5b6001600160a01b0381165f90815260046020526040902054610100900460ff166121bd576001600160a01b0381165f908152600460205260409020805461ff0019166101001790556121b881614f0b565b6121de565b6001600160a01b0381165f908152600460205260409020805461ff00191690555b6001600160a01b0381165f8181526004602090815260409182902054915161010090920460ff16151582527fcecdf9dd6f2193d677b10450a2e4ff64d6b61a566bdc6e34ab5c9fc2f797960b91015b60405180910390a250565b612240614aa1565b6001600160a01b0381165f9081526004602052604090205462010000900460ff1615612362575f5b60035481101561235c57816001600160a01b03166003828154811061228f5761228f615b04565b5f918252602090912001546001600160a01b03160361235457600380546122b890600190615be2565b815481106122c8576122c8615b04565b5f91825260209091200154600380546001600160a01b0390921691839081106122f3576122f3615b04565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550600380548061232f5761232f615cba565b5f8281526020902081015f1990810180546001600160a01b031916905501905561235c565b600101612268565b506123ad565b600380546001810182555f919091527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b0319166001600160a01b0383161790555b6001600160a01b0381165f81815260046020908152604091829020805460ff62010000808304821615810262ff000019909316929092179283905593519104909216151582527f8d46ffd267aefe727b4d0dd43fda31aa5d23c5cb0a042b69ef4dea7914c57906910161222d565b8261242581614afa565b6124415760405162461bcd60e51b8152600401610876906159c2565b61248583838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506020925060069150614c669050565b6001600160a01b0384165f908152600f60209081526040822080546001810182559083529120016124b7838583615a50565b5050505050565b836124c881614afa565b6124e45760405162461bcd60e51b8152600401610876906159c2565b61252883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060019150614c669050565b5f6040518060400160405280866001600160a01b0316815260200185858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509390945250506001600160a01b038981168252600a60209081526040832080546001808201835591855293829020865160029095020180546001600160a01b031916949093169390931782558401519394508493909250908201906125d99082615b18565b505050505050505050565b836125ee81614afa565b61260a5760405162461bcd60e51b8152600401610876906159c2565b836001600160a01b0316856001600160a01b0316036126535760405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b6044820152606401610876565b6001600160a01b038086165f908152601160209081526040808320938816835292905220541515806126c357506001600160a01b038581165f9081526010602052604081208054928716929091906126ad576126ad615b04565b5f918252602090912001546001600160a01b0316145b6126df5760405162461bcd60e51b8152600401610876906159c2565b61272383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060079150614c669050565b6001600160a01b038085165f908152600b60209081526040808320600d8352818420948a168452600c8352818420600e90935292206005548354939493106127955760405162461bcd60e51b8152602060048201526005602482015264522e6c696d60d81b6044820152606401610876565b6005548254106127cf5760405162461bcd60e51b8152602060048201526005602482015264532e6c696d60d81b6044820152606401610876565b83545f0361288a576001600160a01b0389165f8181526020858152604080832092909255815180830183529283528151601f8a01829004820281018201909252888252869291828201918b908b90819084018382808284375f920182905250939094525050835460018082018655948252602091829020845160029092020180546001600160a01b0319166001600160a01b03909216919091178155908301519293909290830191506128829082615b18565b5050506129b1565b6001600160a01b0389165f90815260208490526040902054156128ff57868685855f8d6001600160a01b03166001600160a01b031681526020019081526020015f2054815481106128dd576128dd615b04565b905f5260205f20906002020160010191826128f9929190615a50565b506129b1565b83546001600160a01b038a165f818152602086815260409182902093909355805180820182529182528051601f8a01849004840281018401909152888152869282810191908b908b90819084018382808284375f920182905250939094525050835460018082018655948252602091829020845160029092020180546001600160a01b0319166001600160a01b03909216919091178155908301519293909290830191506129ad9082615b18565b5050505b6001600160a01b0388165f908152602082905260408120549003612a21578154600180820184555f8481526020902090910180546001600160a01b0319166001600160a01b038b161790558254612a089190615be2565b6001600160a01b0389165f908152602083905260409020555b886001600160a01b0316886001600160a01b03167f3294fc25de801ec383dc5fab48b0d8f281d893fd3f80bf56e15665a4ffd570e48989604051612a66929190615cf8565b60405180910390a3505050505050505050565b612a81614aa1565b612a8a5f614f78565b565b6001600160a01b0381165f9081526004602052604090205460609060ff16612ab2575f80fd5b6001600160a01b0382165f90815260096020908152604080832080548251818502810185019093528083529193909284015b82821015611215578382905f5260205f2090600202016040518060400160405290815f82018054612b149061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054612b409061598a565b8015612b8b5780601f10612b6257610100808354040283529160200191612b8b565b820191905f5260205f20905b815481529060010190602001808311612b6e57829003601f168201915b50505050508152602001600182018054612ba49061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054612bd09061598a565b8015612c1b5780601f10612bf257610100808354040283529160200191612c1b565b820191905f5260205f20905b815481529060010190602001808311612bfe57829003601f168201915b50505050508152505081526020019060010190612ae4565b82612c3d81614afa565b612c595760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0384165f9081526008602052604090206124b7838583615a50565b612c83614aa1565b6001612c90828483615a50565b507f5cb699b2db2744e5674f4562b93100efd8d58a530debe3177fb5617f1607334e8282604051612cc2929190615cf8565b60405180910390a15050565b82612cd881614afa565b612cf45760405162461bcd60e51b8152600401610876906159c2565b612d3883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060049150614c669050565b6001600160a01b0384165f9081526007602052604090206004016108e9838583615a50565b6001600160a01b0381165f9081526004602052604090205460609060ff16612d85575f610afa565b6001600160a01b0382165f908152600a602052604081205490612da9826002615cce565b6001600160401b03811115612dc057612dc06159df565b604051908082528060200260200182016040528015612df357816020015b6060815260200190600190039081612dde5790505b5090505f5b82811015611d1c576001600160a01b0385165f908152600a602052604090208054612e4c919083908110612e2e57612e2e615b04565b5f9182526020909120600290910201546001600160a01b0316614ef5565b82612e58836002615cce565b81518110612e6857612e68615b04565b6020026020010181905250600a5f866001600160a01b03166001600160a01b031681526020019081526020015f208181548110612ea757612ea7615b04565b905f5260205f2090600202016001018054612ec19061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054612eed9061598a565b8015612f385780601f10612f0f57610100808354040283529160200191612f38565b820191905f5260205f20905b815481529060010190602001808311612f1b57829003601f168201915b505050505082826002612f4b9190615cce565b612f56906001615ce5565b81518110612f6657612f66615b04565b6020908102919091010152600101612df8565b80612f8381614afa565b612f9f5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0382165f908152600c60209081526040808320600e8352818420600b8452828520600d90945291842090939192915b8454811015613189575f858281548110612ff157612ff1615b04565b5f9182526020808320909101546001600160a01b03908116808452600d83526040808520928d16855291835281842054818552600b909352922054919250908110158061308357506001600160a01b038281165f908152600b602052604090208054918b16918390811061306757613067615b04565b5f9182526020909120600290910201546001600160a01b031614155b156131745786545f9061309890600190615be2565b905080841461311d575f8882815481106130b4576130b4615b04565b905f5260205f20015f9054906101000a90046001600160a01b03169050808986815481106130e4576130e4615b04565b5f91825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290889052604090208490555b8780548061312d5761312d615cba565b5f828152602080822083015f1990810180546001600160a01b03191690559092019092556001600160a01b038516825288905260408120558361316f81615d26565b945050505b5050808061318190615d3b565b915050612fd5565b505f5b82548110156115c9575f8382815481106131a8576131a8615b04565b5f91825260208083206002909202909101546001600160a01b038b8116845288835260408085205491909216808552600c9093529220549092508110158061323057506001600160a01b038281165f908152600c602052604090208054918b16918390811061321957613219615b04565b5f918252602090912001546001600160a01b031614155b156134005784545f9061324590600190615be2565b9050808414613396575f86828154811061326157613261615b04565b5f9182526020918290206040805180820190915260029092020180546001600160a01b03168252600181018054929391929184019161329f9061598a565b80601f01602080910402602001604051908101604052809291908181526020018280546132cb9061598a565b80156133165780601f106132ed57610100808354040283529160200191613316565b820191905f5260205f20905b8154815290600101906020018083116132f957829003601f168201915b50505050508152505090508087868154811061333457613334615b04565b5f91825260209182902083516002929092020180546001600160a01b0319166001600160a01b039092169190911781559082015160018201906133779082615b18565b505090516001600160a01b03165f908152602087905260409020859055505b858054806133a6576133a6615cba565b5f8281526020812060025f199093019283020180546001600160a01b0319168155906133d56001830182615233565b505090556001600160a01b0383165f90815260208690526040812055836133fb81615d26565b945050505b5050808061340d90615d3b565b91505061318c565b8161341f81614afa565b61343b5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0383165f908152600f6020526040902054821061345d575f80fd5b6001600160a01b0383165f908152600f60205260409020805461348290600190615be2565b8154811061349257613492615b04565b905f5260205f2001600f5f856001600160a01b03166001600160a01b031681526020019081526020015f2083815481106134ce576134ce615b04565b905f5260205f200190816134e29190615bf5565b506001600160a01b0383165f908152600f6020526040902080548061350957613509615cba565b600190038181905f5260205f20015f6135229190615233565b9055505050565b8061353381614afa565b61354f5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0382165f908152600460205260409020805461ff00191661010017905561357c82614f0b565b604051600181526001600160a01b038316907fcecdf9dd6f2193d677b10450a2e4ff64d6b61a566bdc6e34ab5c9fc2f797960b9060200160405180910390a25050565b6001600160a01b0381165f9081526004602052604090205460609060ff166135e5575f80fd5b6001600160a01b0382165f908152600a6020908152604080832080548251818502810185019093528083529193909284015b82821015611215575f848152602090819020604080518082019091526002850290910180546001600160a01b03168252600181018054929391929184019161365e9061598a565b80601f016020809104026020016040519081016040528092919081815260200182805461368a9061598a565b80156136d55780601f106136ac576101008083540402835291602001916136d5565b820191905f5260205f20905b8154815290600101906020018083116136b857829003601f168201915b50505050508152505081526020019060010190613617565b6001600160a01b0381165f9081526004602052604090205460609060ff16613715575f610afa565b6001600160a01b0382165f908152600b602052604081205490613739826002615cce565b6001600160401b03811115613750576137506159df565b60405190808252806020026020018201604052801561378357816020015b606081526020019060019003908161376e5790505b5090505f5b82811015611d1c576001600160a01b0385165f908152600b6020526040902080546137be919083908110612e2e57612e2e615b04565b826137ca836002615cce565b815181106137da576137da615b04565b6020026020010181905250600b5f866001600160a01b03166001600160a01b031681526020019081526020015f20818154811061381957613819615b04565b905f5260205f20906002020160010180546138339061598a565b80601f016020809104026020016040519081016040528092919081815260200182805461385f9061598a565b80156138aa5780601f10613881576101008083540402835291602001916138aa565b820191905f5260205f20905b81548152906001019060200180831161388d57829003601f168201915b5050505050828260026138bd9190615cce565b6138c8906001615ce5565b815181106138d8576138d8615b04565b6020908102919091010152600101613788565b826138f581614afa565b6139115760405162461bcd60e51b8152600401610876906159c2565b61395583838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060029150614c669050565b6001600160a01b0384165f9081526007602052604090206002016108e9838583615a50565b6001600160a01b0381165f9081526004602052604090205460609060ff166139a2575f610afa565b6001600160a01b0382165f9081526012602052604081205490816001600160401b038111156139d3576139d36159df565b604051908082528060200260200182016040528015613a0657816020015b60608152602001906001900390816139f15790505b5090505f5b82811015611d1c576001600160a01b0385165f9081526012602052604090208054613a5a919083908110613a4157613a41615b04565b5f918252602090912001546001600160a01b0316614ef5565b828281518110613a6c57613a6c615b04565b6020908102919091010152600101613a0b565b8a613a8981614afa565b613aa55760405162461bcd60e51b8152600401610876906159c2565b613ae68b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92018290525060a093509150614c669050565b613b2a87878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060029150614c669050565b613b6e85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060039150614c669050565b613bb283838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525060a0925060049150614c669050565b613bf789898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610140925060019150614c669050565b6001600160a01b038c165f90815260076020526040902080613c1a8c8e83615a50565b5060018101613c2a8a8c83615a50565b5060028101613c3a888a83615a50565b5060038101613c4a868883615a50565b5060048101613c5a848683615a50565b50613c648d614dd6565b613c6d8d610923565b50505050505050505050505050565b6001600160a01b0381165f908152600c6020526040812054606091613ca2826002615cce565b6001600160401b03811115613cb957613cb96159df565b604051908082528060200260200182016040528015613cec57816020015b6060815260200190600190039081613cd75790505b5090505f5b82811015611d1c576001600160a01b0385165f908152600c60205260408120805483908110613d2257613d22615b04565b5f9182526020808320909101546001600160a01b03908116808452600d83526040808520928b16855291835281842054818552600b90935290832080549194509192919083908110613d7657613d76615b04565b905f5260205f2090600202016001018054613d909061598a565b80601f0160208091040260200160405190810160405280929190818152602001828054613dbc9061598a565b8015613e075780601f10613dde57610100808354040283529160200191613e07565b820191905f5260205f20905b815481529060010190602001808311613dea57829003601f168201915b50505050509050613e1783614ef5565b85613e23866002615cce565b81518110613e3357613e33615b04565b60209081029190910101528085613e4b866002615cce565b613e56906001615ce5565b81518110613e6657613e66615b04565b6020908102919091010152505050600101613cf1565b6001600160a01b0381165f9081526004602052604090205460609060ff16613ea4575f610afa565b6001600160a01b0382165f9081526010602052604081205490816001600160401b03811115613ed557613ed56159df565b604051908082528060200260200182016040528015613f0857816020015b6060815260200190600190039081613ef35790505b5090505f5b82811015611d1c576001600160a01b0385165f9081526010602052604090208054613f43919083908110613a4157613a41615b04565b828281518110613f5557613f55615b04565b6020908102919091010152600101613f0d565b81613f7281614afa565b613f8e5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b038083165f818152601160209081526040808320948816835293815283822054928252601090529190912080548190613fd090600190615be2565b81548110613fe057613fe0615b04565b905f5260205f20015f9054906101000a90046001600160a01b031681838154811061400d5761400d615b04565b5f91825260208083209190910180546001600160a01b0319166001600160a01b039485161790559186168152601190915260408120825484929084908490811061405957614059615b04565b5f9182526020808320909101546001600160a01b03168352820192909252604001902055805481908061408e5761408e615cba565b5f828152602080822083015f1990810180546001600160a01b03191690559092019092556001600160a01b03868116808452601183526040808520928a168086529284528085208590556013845280852091855290835280842054918452601290925291208054819061410390600190615be2565b8154811061411357614113615b04565b905f5260205f20015f9054906101000a90046001600160a01b031681838154811061414057614140615b04565b5f91825260208083209190910180546001600160a01b0319166001600160a01b039485161790559189168152601390915260408120825484929084908490811061418c5761418c615b04565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205580548190806141c1576141c1615cba565b5f82815260208082205f19908401810180546001600160a01b03191690559092019092556001600160a01b03898116808452601383526040808520928b16808652928452808520859055519384529290917f6f0bc8b3499f361c2ff7768f2bd3079d0fea5d0da28fd0189a7da7eef7d4c6ee910160405180910390a350505050505050565b8261425081614afa565b61426c5760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0384165f9081526004602052604090206001016124b7838583615a50565b8161429b81614afa565b6142b75760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b0383165f908152600a602052604090205482106142d9575f80fd5b6001600160a01b0383165f908152600a6020526040902080546142fe90600190615be2565b8154811061430e5761430e615b04565b905f5260205f209060020201600a5f856001600160a01b03166001600160a01b031681526020019081526020015f20838154811061434e5761434e615b04565b5f9182526020909120825460029092020180546001600160a01b0319166001600160a01b0390921691909117815560018082019061438e90840182615bf5565b5050506001600160a01b0383165f908152600a602052604090208054806143b7576143b7615cba565b5f8281526020812060025f199093019283020180546001600160a01b0319168155906119936001830182615233565b600180546143f39061598a565b80601f016020809104026020016040519081016040528092919081815260200182805461441f9061598a565b801561446a5780601f106144415761010080835404028352916020019161446a565b820191905f5260205f20905b81548152906001019060200180831161444d57829003601f168201915b505050505081565b8161447c81614afa565b6144985760405162461bcd60e51b8152600401610876906159c2565b6001600160a01b038083165f908152600d60209081526040808320938716835292905220548015158061450e57506001600160a01b038381165f908152600b602052604081208054928716929091906144f3576144f3615b04565b5f9182526020909120600290910201546001600160a01b0316145b6145435760405162461bcd60e51b815260206004820152600660248201526508515e1a5cdd60d21b6044820152606401610876565b6001600160a01b038084165f908152600b60209081526040808320600d83528184209489168452600c8352818420600e9093529083208154919493909161458c90600190615be2565b90508086146146dd575f8582815481106145a8576145a8615b04565b5f9182526020918290206040805180820190915260029092020180546001600160a01b0316825260018101805492939192918401916145e69061598a565b80601f01602080910402602001604051908101604052809291908181526020018280546146129061598a565b801561465d5780601f106146345761010080835404028352916020019161465d565b820191905f5260205f20905b81548152906001019060200180831161464057829003601f168201915b50505050508152505090508086888154811061467b5761467b615b04565b5f91825260209182902083516002929092020180546001600160a01b0319166001600160a01b039092169190911781559082015160018201906146be9082615b18565b505090516001600160a01b03165f908152602086905260409020879055505b848054806146ed576146ed615cba565b5f8281526020812060025f199093019283020180546001600160a01b03191681559061471c6001830182615233565b505090556001600160a01b03808a165f90815260208681526040808320839055928b1682528490522054835461475490600190615be2565b91508181146147d9575f84838154811061477057614770615b04565b905f5260205f20015f9054906101000a90046001600160a01b03169050808583815481106147a0576147a0615b04565b5f91825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290849052604090208190555b838054806147e9576147e9615cba565b5f828152602080822083015f1990810180546001600160a01b03191690559092019092556001600160a01b038b8116808452918690526040808420939093559151918c16917f3294fc25de801ec383dc5fab48b0d8f281d893fd3f80bf56e15665a4ffd570e49061211e906020808252601190820152702232b632ba32b210313c903bb934ba32b960791b604082015260600190565b60408051600980825261014082019092526060915f9190816020015b606081526020019060019003908161489b5750506001600160a01b0384165f9081526004602052604090205490915060ff1615614a25576148db83610ad5565b815f815181106148ed576148ed615b04565b602002602001018190525061490183611a8c565b8160018151811061491457614914615b04565b602002602001018190525061492883612d5d565b8160028151811061493b5761493b615b04565b602002602001018190525061494f83613e7c565b8160038151811061496257614962615b04565b60200260200101819052506149768361397a565b8160048151811061498957614989615b04565b602002602001018190525061499d836136ed565b816005815181106149b0576149b0615b04565b60200260200101819052506149c483613c7c565b816006815181106149d7576149d7615b04565b60200260200101819052506149eb83611113565b816007815181106149fe576149fe615b04565b6020026020010181905250614a1283610ffc565b8160088151811061110257611102615b04565b92915050565b614a33614aa1565b6001600160a01b038116614a985760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610876565b61128c81614f78565b5f546001600160a01b03163314612a8a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610876565b6001600160a01b0381165f90815260046020526040812054610100900460ff1615614b515760405162461bcd60e51b8152602060048201526007602482015266109b1bd8dad95960ca1b6044820152606401610876565b336001600160a01b038316811480614be45750600654604051638988eea960e01b81526001600160a01b03838116600483015285811660248301523060448301525f606483015290911690638988eea990608401602060405180830381865afa158015614bc0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614be49190615d53565b80614c5f5750826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614c26573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614c4a9190615d72565b6001600160a01b0316816001600160a01b0316145b9392505050565b60408051610140810182526005610100820190815264416c69617360d81b61012083015281528151808301835260068082526511195d185a5b60d21b60208381019190915280840192909252835180850185529081526514dbd8da585b60d21b8183015282840152825180840184526003808252622bb2b160e91b82840152606084019190915283518085018552600781526647616c6c65727960c81b818401526080840152835180850185526004808252634c696e6b60e01b8285015260a0850191909152845180860186529182526254616760e81b8284015260c084019190915283518085019094528352634e6f746560e01b9083015260e08101919091525f818360088110614d7a57614d7a615b04565b6020020151604051602001614d8f9190615d8d565b60408051601f198184030181529190529050614dac846001615ce5565b8551108190614dce5760405162461bcd60e51b815260040161087691906158e4565b505050505050565b6001600160a01b0381165f9081526004602052604090205460ff1661128c576001600160a01b0381165f908152600460205260408120805460ff191660011790556002805491614e2583615d3b565b9091555050604051600181526001600160a01b038216907f248e7111eafe9d4fa83a7ee922e702047cf0db3d086a16aebb086341d45c9cd39060200161222d565b60605f614e7283614fc7565b60010190505f816001600160401b03811115614e9057614e906159df565b6040519080825280601f01601f191660200182016040528015614eba576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084614ec457509392505050565b6060614a25826001600160a01b0316601461509e565b6001600160a01b0381165f908152600460205260408120805460ff191690556002805491614f3883615d26565b90915550506040515f81526001600160a01b038216907f248e7111eafe9d4fa83a7ee922e702047cf0db3d086a16aebb086341d45c9cd39060200161222d565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106150055772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310615031576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061504f57662386f26fc10000830492506010015b6305f5e1008310615067576305f5e100830492506008015b612710831061507b57612710830492506004015b6064831061508d576064830492506002015b600a8310614a255760010192915050565b60605f6150ac836002615cce565b6150b7906002615ce5565b6001600160401b038111156150ce576150ce6159df565b6040519080825280601f01601f1916602001820160405280156150f8576020820181803683370190505b509050600360fc1b815f8151811061511257615112615b04565b60200101906001600160f81b03191690815f1a905350600f60fb1b8160018151811061514057615140615b04565b60200101906001600160f81b03191690815f1a9053505f615162846002615cce565b61516d906001615ce5565b90505b60018111156151e4576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106151a1576151a1615b04565b1a60f81b8282815181106151b7576151b7615b04565b60200101906001600160f81b03191690815f1a90535060049490941c936151dd81615d26565b9050615170565b508315614c5f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610876565b50805461523f9061598a565b5f825580601f1061524e575050565b601f0160209004905f5260205f209081019061128c91905b80821115615279575f8155600101615266565b5090565b5f6020828403121561528d575f80fd5b5035919050565b6001600160a01b038116811461128c575f80fd5b80356152b381615294565b919050565b5f602082840312156152c8575f80fd5b8135614c5f81615294565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b841515815283151560208201528215156040820152608060608201525f61532b60808301846152d3565b9695505050505050565b5f8083601f840112615345575f80fd5b5081356001600160401b0381111561535b575f80fd5b602083019150836020828501011115615372575f80fd5b9250929050565b5f805f6040848603121561538b575f80fd5b833561539681615294565b925060208401356001600160401b038111156153b0575f80fd5b6153bc86828701615335565b9497909650939450505050565b5f805f805f80608087890312156153de575f80fd5b86356153e981615294565b95506020870135945060408701356001600160401b038082111561540b575f80fd5b6154178a838b01615335565b9096509450606089013591508082111561542f575f80fd5b5061543c89828a01615335565b979a9699509497509295939492505050565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b828110156154a357603f198886030184526154918583516152d3565b94509285019290850190600101615475565b5092979650505050505050565b5f805f805f606086880312156154c4575f80fd5b85356154cf81615294565b945060208601356001600160401b03808211156154ea575f80fd5b6154f689838a01615335565b9096509450604088013591508082111561550e575f80fd5b5061551b88828901615335565b969995985093965092949392505050565b5f805f805f60808688031215615540575f80fd5b853561554b81615294565b945060208601359350604086013561556281615294565b925060608601356001600160401b0381111561557c575f80fd5b61551b88828901615335565b5f805f6060848603121561559a575f80fd5b83356155a581615294565b925060208401356155b581615294565b929592945050506040919091013590565b5f80604083850312156155d7575f80fd5b82356155e281615294565b915060208301356155f281615294565b809150509250929050565b5f806040838503121561560e575f80fd5b823561561981615294565b946020939093013593505050565b5f8060408385031215615638575f80fd5b823561564381615294565b9150602083013560ff811681146155f2575f80fd5b5f805f806060858703121561566b575f80fd5b843561567681615294565b9350602085013561568681615294565b925060408501356001600160401b038111156156a0575f80fd5b6156ac87828801615335565b95989497509550505050565b5f60208083018184528085518083526040925060408601915060408160051b8701018488015f5b8381101561572f57888303603f1901855281518051878552615703888601826152d3565b91890151858303868b015291905061571b81836152d3565b9689019694505050908601906001016156df565b509098975050505050505050565b5f806020838503121561574e575f80fd5b82356001600160401b03811115615763575f80fd5b61576f85828601615335565b90969095509350505050565b5f60208083018184528085518083526040925060408601915060408160051b8701018488015f5b8381101561572f57888303603f19018552815180516001600160a01b031684528701518784018790526157d7878501826152d3565b95880195935050908601906001016157a2565b5f805f805f805f805f805f60c08c8e031215615804575f80fd5b61580d8c6152a8565b9a506001600160401b038060208e01351115615827575f80fd5b6158378e60208f01358f01615335565b909b50995060408d013581101561584c575f80fd5b61585c8e60408f01358f01615335565b909950975060608d0135811015615871575f80fd5b6158818e60608f01358f01615335565b909750955060808d0135811015615896575f80fd5b6158a68e60808f01358f01615335565b909550935060a08d01358110156158bb575f80fd5b506158cc8d60a08e01358e01615335565b81935080925050509295989b509295989b9093969950565b602081525f614c5f60208301846152d3565b5f60208083018184528085518083526040860191506005925060408160051b8701018488015f5b8381101561572f57888303603f1901855281518051808552908801908885019080891b86018a015f5b8281101561597457601f198883030184526159628286516152d3565b948c0194938c01939150600101615946565b50978a019795505050918701915060010161591d565b600181811c9082168061599e57607f821691505b6020821081036159bc57634e487b7160e01b5f52602260045260245ffd5b50919050565b60208082526003908201526221417560e81b604082015260600190565b634e487b7160e01b5f52604160045260245ffd5b601f821115615a3757805f5260205f20601f840160051c81016020851015615a185750805b601f840160051c820191505b818110156124b7575f8155600101615a24565b505050565b5f19600383901b1c191660019190911b1790565b6001600160401b03831115615a6757615a676159df565b615a7b83615a75835461598a565b836159f3565b5f601f841160018114615aa7575f8515615a955750838201355b615a9f8682615a3c565b8455506124b7565b5f83815260208120601f198716915b82811015615ad65786850135825560209485019460019092019101615ab6565b5086821015615af2575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b634e487b7160e01b5f52603260045260245ffd5b81516001600160401b03811115615b3157615b316159df565b615b4581615b3f845461598a565b846159f3565b602080601f831160018114615b73575f8415615b615750858301515b615b6b8582615a3c565b865550614dce565b5f85815260208120601f198616915b82811015615ba157888601518255948401946001909101908401615b82565b5085821015615bbe57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b5f52601160045260245ffd5b81810381811115614a2557614a25615bce565b818103615c00575050565b615c0a825461598a565b6001600160401b03811115615c2157615c216159df565b615c2f81615b3f845461598a565b5f601f821160018114615c5b575f8315615c495750848201545b615c538482615a3c565b8555506124b7565b5f8581526020808220868352908220601f198616925b83811015615c915782860154825560019586019590910190602001615c71565b5085831015615bbe579301545f1960f8600387901b161c19169092555050600190811b01905550565b634e487b7160e01b5f52603160045260245ffd5b8082028115828204841417614a2557614a25615bce565b80820180821115614a2557614a25615bce565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b5f81615d3457615d34615bce565b505f190190565b5f60018201615d4c57615d4c615bce565b5060010190565b5f60208284031215615d63575f80fd5b81518015158114614c5f575f80fd5b5f60208284031215615d82575f80fd5b8151614c5f81615294565b5f82518060208501845e6820746f6f206c6f6e6760b81b92019182525060090191905056fea2646970667358221220297253ef4e48a9f657b8666768151164aa30438ffbc1e7f1aead72c5671c063f64736f6c63430008190033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.