false
false

Contract Address Details

0x057509d22E54dbfeB991a00ad6136eaF0373F488

Contract Name
Publication
Creator
0x26f145–4d2c46 at 0x66550b–534a4b
Balance
0 Berg
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
29741727
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
Publication




Optimization enabled
false
Compiler version
v0.8.12+commit.f00d7308




EVM Version
london




Verified at
2025-02-21T18:28:21.599709Z

Publication.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "./Editor.sol";
import "./Identity.sol";
import "./HitchensUnorderedAddressSet.sol";
import "./OwnableUpgradeable.sol";

// Decentral Publication Contracts v1.0 (contracts/Publication.sol)
/** @title Contract for one specific publication which is owned by the publication's author */
contract Publication is OwnableUpgradeable {
    using HitchensUnorderedAddressSetLib for HitchensUnorderedAddressSetLib.Set;
    // Different roles an endorser can have
    enum EndorserRole{ NONE, READER, SUPERVISOR, EXAMINER }
    // Different states a publication can have
    enum PublicationState{ NONE, SUBMITTED, PUBLISHED, RETRACTED }
    struct Endorsement {
        bool exists;
        string document;
        EndorserRole role;
    }
    // Version of the publication contract
    uint8 public constant version = 1;
    // List of endorsers of the publication
    mapping(address => Endorsement) public endorsers;
    HitchensUnorderedAddressSetLib.Set internal endorsersSet;
    // Identifier of the publishing journal
    uint8 public journal;
    // File hashes for the published document and it's meta data
    string public document;
    string public metadata;
    // State of the publication process
    PublicationState public state;
    // Address of the editor proxy contract
    Editor public editorProxy;
    // Address of the identity proxy contract
    Identity public identityProxy;
    event LogNewPublication(address sender, string document, string metadata, PublicationState state);
    event LogNewEndorsement(address sender, string document, string comment);
    event LogUpdateEndorserRole(address sender, address endorser, string document, EndorserRole oldRole, EndorserRole newRole);
    event LogUpdateEndorsementDocument(address sender, address endorser, string oldDocument, string newDocument);
    event LogUpdateEndorsementComment(address sender, address endorser, string document, string comment);
    event LogEndorsementRevocation(address sender, address endorser, string document, string comment);
    event LogUpdatePublicationDocument(address sender, string oldDocument, string newDocument, string comment);
    event LogUpdatePublicationMetadata(address sender, string oldMetadata, string newMetadata, string comment);
    event LogPublicationPublished(address sender, string document, string metadata);
    event LogPublicationRetraction(address sender, string comment);
    /**
    *  Called by the author to initialize the contract variables
    *  @param _owner Address of the author of the publication
    *  @param _document Off-chain reference to the main document of the publication (e.g., IPFS hash)
    *  @param _metadata Off-chain reference to the publication metadata document (e.g., IPFS hash)
    *  @param _identity Off-chain reference to the identity document (e.g., IPFS hash)
    *  @param _editorProxy Address to the Editor (proxy) contract with which the clones are initialized
    *  @param _identityProxy Address to the Identity (proxy) contract which maps addresses to real world identities
    *  @param _journal Identifier of the publishing journal
    */
    function initialize(address _owner, string memory _document, string memory _metadata, string memory _identity, Editor _editorProxy, Identity _identityProxy, uint8 _journal) external initializer {
        require(
            bytes(_document).length > 0 && 
            bytes(_metadata).length > 0 &&
            bytes(_identity).length > 0, 
            "Input for document, identity, or metadata cannot be empty"
        );    
        identityProxy = _identityProxy;
        try identityProxy.hasIdentity(tx.origin) returns (bool result) {
            if(!result) {
                try identityProxy.addIdentity(_identity) {
                } catch Error(string memory reason){
                    require(false, reason);
                }
            }
        } catch Error(string memory reason){
            require(false, reason);
        }
        editorProxy = _editorProxy;
        journal = _journal;
        document = _document;
        metadata = _metadata;
        state = PublicationState.SUBMITTED;
        emit LogNewPublication(tx.origin, _document, _metadata, state);
        __Ownable_init();
        transferOwnership(_owner);
    }
    /**
    *  Endorse the current publication document hash. Function automatically creates a new mapping
    *  in the Identity contract for the endorser if no mapping exists.
    *  @param _identity Off-chain reference to the identity document (e.g., IPFS hash)
    *  @param _comment Comment of the endorser (e.g., reason for his endorsement)
    */
    function endorse(string memory _identity, string calldata _comment) notRetracted external {
        require(msg.sender != owner(), "Function cannot be called by the contract owner");
        require(!endorsersSet.exists(msg.sender), "Function cannot be called by an endorser");
        try identityProxy.hasIdentity(msg.sender) returns (bool result) {
            if(!result) {
                try identityProxy.addIdentity(_identity) {
                } catch {
                require(false, "Identity could not be stored in Identity contract");
                }
            }
        } catch {
            require(false, "Identity could not be stored in Identity contract");
        }
        endorsersSet.insert(msg.sender);
        endorsers[msg.sender] = Endorsement(true,document,EndorserRole.READER);
        emit LogNewEndorsement(msg.sender, document, _comment);
    }
    /**
    *  Updates the current role assigned to the specified endorser
    *  @param _endorser Address of the endorser whose role is to be updated
    *  @param _role New role to be assigned
    */
    function updateEndorserRole(address _endorser, EndorserRole _role) onlyOwnerOrEditor(keccak256(abi.encodePacked(_endorser,_role))) endorsementExists(_endorser) external {
        require(_role != EndorserRole.NONE, "Invalid endorser role");
        Endorsement memory e = endorsers[_endorser];
        EndorserRole oldRole = e.role;
        e.role = _role;
        endorsers[_endorser] = e;
        emit LogUpdateEndorserRole(msg.sender, _endorser, e.document, oldRole, _role);
    }
    /**
    *  Updates the endorsement of the caller to the current document hash version
    */
    function updateEndorsementDocument() endorsementExists(msg.sender) external {
        string memory oldDocument = endorsers[msg.sender].document;
        endorsers[msg.sender].document = document;
        emit LogUpdateEndorsementDocument(msg.sender, msg.sender, oldDocument, document);
    }
    /**
    *  Updates the endorsement comment of the caller to the provided text
    *  @param _comment New comment of the endorser (e.g., reason for his endorsement)
    */
    function updateEndorsementComment(string calldata _comment) endorsementExists(msg.sender) external {
        emit LogUpdateEndorsementComment(msg.sender, msg.sender, endorsers[msg.sender].document, _comment);
    }
    /**
    *  Updates the endorsement comment of the specified endorser to the provided text
    *  @param _endorser Address of the endorser whose comment is to be updated
    *  @param _comment New comment of the endorser (e.g., reason for his endorsement)
    */        
    function updateEndorsementCommentExt(address _endorser, string calldata _comment) onlyEditor(keccak256(abi.encodePacked(_endorser,_comment))) endorsementExists(_endorser) external {
        emit LogUpdateEndorsementComment(msg.sender, _endorser, endorsers[_endorser].document, _comment);
    }
    /**
    *  Removes the endorsement of the caller from the publication
    *  @param _comment Reason for retracting the endorsement
    */
    function revokeEndorsement(string calldata _comment) endorsementExists(msg.sender) external {
        __deleteEndorsement(msg.sender, _comment);
    }
    /**
    *  Removes the endorsement of the specified endorser from the publication
    *  @param _endorser Address of the endorser whose endorsement is to be revoked
    *  @param _comment Reason for revoking the endorsement
    */
    function revokeEndorsementExt(address _endorser, string calldata _comment) onlyOwnerOrEditor(keccak256(abi.encodePacked(_endorser,_comment))) endorsementExists(_endorser) external {
        __deleteEndorsement(_endorser, _comment);
    }
    /**
    *  Publishes the publication if the contract state includes the required document hashes 
    *  and at least one privileged edorsement (i.e., from an endorser with supervisor or examiner role)
    */
    function publish() onlyEditor(keccak256("")) external {
        require(state == PublicationState.SUBMITTED, "Function requires contract state: submitted");
        require(
            bytes(document).length > 0 && 
            bytes(metadata).length > 0, 
            "Input for document or metadata cannot be empty"
        );  
        uint counter = 0;
        for(uint i = 0; i < endorsersSet.count(); i++) {
            Endorsement memory e = endorsers[endorsersSet.keyAtIndex(i)];
            if((e.role == EndorserRole.SUPERVISOR || e.role == EndorserRole.EXAMINER) && keccak256(bytes(e.document)) == keccak256(bytes(document))) {
                counter++;
            }       
        }
        require(counter >= 1,"Insufficient number of privileged endorsements");
        state = PublicationState.PUBLISHED;
        emit LogPublicationPublished(msg.sender, document, metadata);
    }
    /**
    *  Update the document hash
    *  @param _document Off-chain reference to the new main document of the publication (e.g., IPFS hash)
    *  @param _comment Comment describing the document changes
    */
    function updateDocument(string memory _document, string calldata _comment) onlyOwnerOrEditor(keccak256(abi.encodePacked(_document,_comment))) notRetracted external {
        require(
            bytes(_document).length > 0, 
            "Input for document cannot be empty"
        );
        string memory oldDocument = document;
        document = _document;
        emit LogUpdatePublicationDocument(msg.sender, oldDocument, document, _comment);
    }
    /**
    *  Update the metadata hash
    *  @param _metadata Off-chain reference to the new publication metadata document (e.g., IPFS hash)
    *  @param _comment Comment describing the document changes
    */
    function updateMetadata(string memory _metadata, string calldata _comment) onlyOwnerOrEditor(keccak256(abi.encodePacked(_metadata,_comment))) notRetracted external {
        require(
            bytes(_metadata).length > 0, 
            "Input for metadata cannot be empty"
        );
        string memory oldMetadata = metadata;
        metadata = _metadata;
        emit LogUpdatePublicationMetadata(msg.sender, oldMetadata, metadata, _comment);
    }
    /**
    *  Ireversibly retracts the publication
    *  @param _comment Comment describing the reason for retracting the publication
    */
    function retractPublication(string calldata _comment) onlyOwnerOrEditor(keccak256(abi.encodePacked(_comment))) notRetracted external {
        state = PublicationState.RETRACTED;
        delete document; 
        delete metadata;
        while (endorsersSet.count() > 0) {
            address key = endorsersSet.keyAtIndex(0);
            delete endorsers[key];
            endorsersSet.remove(key);
        }
        delete endorsersSet;
        emit LogPublicationRetraction(msg.sender, _comment);
    }
    /**
    *  Removes the endorsement of the specified endorser from the publication
    *  @param _endorser Address of the endorser whose endorsement is to be removed
    *  @param _comment Reason for removing the endorsement
    */
    function __deleteEndorsement(address _endorser, string calldata _comment) internal {
        endorsersSet.remove(_endorser);
        string memory doc = endorsers[_endorser].document;
        delete endorsers[_endorser];
        emit LogEndorsementRevocation(msg.sender, _endorser, doc, _comment);
    }
    /**
    *  Asserts whether the caller is allowed to perform a certain action
    *  @param _data Encoded description of the action
    */
    function assertEditorialPermission(bytes32 _data) internal view returns (bool) {
        bytes32 action = keccak256(abi.encodePacked(msg.sig,_data));
        try editorProxy.actionAllowed(action) returns (bool allowed) {
            return allowed;
        } catch {
            return false;
        }
    }
    /**
    *  Only editors may perfom the asserted action
    *  @param _data Encoded description of the action
    */
    modifier onlyEditor(bytes32 _data){
        require(assertEditorialPermission(_data), "Function can only be called with editorial access rights");
        _;
    }
    /**
    *  Only the publication author or an editor may perform the asserted action
    *  @param _data Encoded description of the action
    */
    modifier onlyOwnerOrEditor(bytes32 _data){
        require(msg.sender == owner() || assertEditorialPermission(_data), "Function is restricted to the contract owner and editors");
        _;
    }
    /**
    *  Allows to only call a function if the given endorsement exists
    *  @param _endorser Address of the endorser to be admitted
    */
    modifier endorsementExists(address _endorser) {
        require(endorsersSet.exists(_endorser), "No matching endorsement found");
        _;
    }
    /**
    *  Allows to only call a function only if the publication has not been retracted earlier
    */
    modifier notRetracted(){
        require(state != PublicationState.RETRACTED, "Function cannot be called on a retracted publication");
        _;
    }
}
        

AddressUpgradeable.sol

// File: @openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.
        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }
    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");
        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }
    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }
    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }
    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }
    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }
    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }
    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}
          

ClonesUpgradeable.sol

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

// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)
/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library ClonesUpgradeable {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create(0, ptr, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create2(0, ptr, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }
    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
            mstore(add(ptr, 0x38), shl(0x60, deployer))
            mstore(add(ptr, 0x4c), salt)
            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
            predicted := keccak256(add(ptr, 0x37), 0x55)
        }
    }
    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(address implementation, bytes32 salt)
        internal
        view
        returns (address predicted)
    {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}
          

Context.sol

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

import "./Initializable.sol";
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
/**
 * @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;
    }
}
          

ContextUpgradeable.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;
import "./Initializable.sol";
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
/**
 * @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 ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
        __Context_init_unchained();
    }
    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }
    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
    uint256[50] private __gap;
}
          

Editor.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "./HitchensUnorderedAddressSet.sol";
import "./OwnableUpgradeable.sol";

// Decentral Publication Contracts v1.0 (contracts/Editor.sol)
/** @title Upgradeable contract for managing editorial functions */
contract Editor is OwnableUpgradeable {
    using HitchensUnorderedAddressSetLib for HitchensUnorderedAddressSetLib.Set;
    // Version of the contract
    uint8 public constant version = 1;
    // Set of current editors
    HitchensUnorderedAddressSetLib.Set internal editorsSet;
    event LogEditorAdded(address con, address sender, address editor);
    event LogEditorRemoved(address sender, address editor);
    /**
    *  Initializes the contract variables. Replaces constructor to enable
    *  upgradeability of the contract.
    */
    function initialize() external initializer {
        __Ownable_init(); // contract creator becomes the owner
        addEditor(tx.origin);
    }
    /**
    *  Removes an editor from the editorial list
    *  @param _editor Address of the editor to be removed
    */
    function removeEditor(address _editor) onlyOwner external {
        editorsSet.remove(_editor);
        emit LogEditorRemoved(msg.sender, _editor);
    }
    /**
    *  Provides a plain array of all editor addresses
    *  @return Address array of all editors
    */
    function getEditors() external view returns (address[] memory) {
        return editorsSet.keyList;
    }
    /**
    *  Checks if a requested action is allowed to be performed by the requesting 
    *  address on the given contract
    *  @return bool True if the action is allowed 
    *  @dev In the current contract version, editors may perform all actions. Future
    *       contract versions may utilize msg.sender (address of the target
    *       contract) and the first parameter (signiture of the requested action) for a
    *       more granular access management system.
    */
    function actionAllowed(bytes32) external view returns (bool) {
        return (isEditor(tx.origin));
    }
    /**
    *  Checks if a given address is an editor
    *  @param _addr Address of the potential editor
    *  @return bool true if it is an editor
    */
    function isEditor(address _addr) public view returns (bool) {
        return (editorsSet.exists(_addr));
    }
    /**
    *  Adds a new editor to the editorial list
    *  @param _addr Address of the editor to be added
    */
    function addEditor(address _addr) onlyOwner public {
        editorsSet.insert(_addr); // will fail automatically if the key already exists.  
        emit LogEditorAdded(address(this), msg.sender, _addr);
    }
}
          

HitchensUnorderedAddressSet.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;
/*
Hitchens UnorderedAddressSet v0.93
Library for managing CRUD operations in dynamic address sets.
https://github.com/rob-Hitchens/UnorderedKeySet
Copyright (c), 2019, Rob Hitchens, the MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
THIS SOFTWARE IS NOT TESTED OR AUDITED. DO NOT USE FOR PRODUCTION.
*/
library HitchensUnorderedAddressSetLib {
    struct Set {
        mapping(address => uint) keyPointers;
        address[] keyList;
    }
    function insert(Set storage self, address key) internal {
        require(key != address(0), "UnorderedKeySet(100) - Key cannot be 0x0");
        require(!exists(self, key), "UnorderedAddressSet(101) - Address (key) already exists in the set.");
        self.keyList.push(key);
        self.keyPointers[key] = self.keyList.length - 1;
    }
    function remove(Set storage self, address key) internal {
        require(exists(self, key), "UnorderedKeySet(102) - Address (key) does not exist in the set.");
        address keyToMove = self.keyList[count(self)-1];
        uint rowToReplace = self.keyPointers[key];
        self.keyPointers[keyToMove] = rowToReplace;
        self.keyList[rowToReplace] = keyToMove;
        delete self.keyPointers[key];
        self.keyList.pop();
    }
    function count(Set storage self) internal view returns(uint) {
        return(self.keyList.length);
    }
    function exists(Set storage self, address key) internal view returns(bool) {
        if(self.keyList.length == 0) return false;
        return self.keyList[self.keyPointers[key]] == key;
    }
    function keyAtIndex(Set storage self, uint index) internal view returns(address) {
        return self.keyList[index];
    }
}
          

Identity.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "./Editor.sol";
import "./HitchensUnorderedAddressSet.sol";
import "./OwnableUpgradeable.sol";

// Decentral Publication Contracts v1.0 (contracts/Identity.sol)
/** @title Upgradeable contract for managing the mapping between identities and addesses */
contract Identity is OwnableUpgradeable {
    using HitchensUnorderedAddressSetLib for HitchensUnorderedAddressSetLib.Set;
    struct IDMeta {
        bool exists;
        string metadata;
        bool validated;
    }
    // Version of the contract
    uint8 public constant version = 1;
    // Address of the editor proxy contract
    Editor public editorProxy;
    // Mapping between addresses and a respective identity metadata struct
    HitchensUnorderedAddressSetLib.Set internal identitiesSet;
    mapping(address => IDMeta) public identities;
    // List of blocked addresses that have no write permissions
    HitchensUnorderedAddressSetLib.Set internal blockedSet;
    event LogIdentityAdded(address sender, address identity, string metadata);
    event LogIdentityUpdated(address sender, address identity, string oldMetadata, string newMetadata, string comment);
    event LogIdentityRemoved(address sender, address identity, string metadata, string comment);
    event LogIdentityValidated(address sender, address identity, string comment);
    event LogIdentityInvalidated(address sender, address identity, string comment);
    event LogIdentityBlocked(address sender, address identity, string comment);
    event LogIdentityUnblocked(address sender, address identity, string comment);   
    /**
    *  Initializes the contract variables. Replaces constructor to enable
    *  upgradeability of the contract.
    *  @param _editorProxy Address of the Editor (proxy) contract 
    */
    function initialize(Editor _editorProxy) external initializer {
        editorProxy = _editorProxy;
        __Ownable_init();
    }
    /**
    *  Add new identity mapping between the caller and the given metadata document hash
    *  @param _metadata Off-chain reference to the identity document (e.g., IPFS hash) 
    */
    function addIdentity(string memory _metadata) notBlocked(tx.origin) external {
        __addIdentity(tx.origin, _metadata);
    }
    /**
    *  Add new identity mapping between the given address and the given metadata document hash
    *  @param _addr Address of the account to be mapped to the given identity document hash 
    *  @param _metadata Off-chain reference to the identity document (e.g., IPFS hash) 
    */
    function addIdentityExt(address _addr, string memory _metadata) notBlocked(_addr) onlyEditor external {
        __addIdentity(_addr, _metadata);
    }
    /**
    *  Update the metadata document hash of an existing identity mapping of the caller
    *  @param _metadata Off-chain reference to the new identity document (e.g., IPFS hash) 
    *  @param _comment Comment describing the document changes
    */
    function updateIdentity(string memory _metadata, string calldata _comment) hasIdent(tx.origin) external {
        __updateIdentity(tx.origin, _metadata, _comment);
    }
    /**
    *  Update the metadata document hash of an existing identity mapping of the given address
    *  @param _addr Address of the account whose mapping is to be updated 
    *  @param _metadata Off-chain reference to the new identity document (e.g., IPFS hash) 
    *  @param _comment Comment describing the document changes
    */
    function updateIdentityExt(address _addr, string memory _metadata, string calldata _comment) hasIdent(_addr) onlyEditor external {
        __updateIdentity(_addr, _metadata, _comment);
    }
    /**
    *  Remove the mapping of the caller
    *  @param _comment Comment describing the reason for removing the mapping
    */
    function removeIdentity(string calldata _comment) hasIdent(tx.origin) external {
        __removeIdentity(tx.origin, _comment);
    }
    /**
    *  Remove the mapping of the given address
    *  @param _addr Address of the account whose mapping is to be removed 
    *  @param _comment Comment describing the reason for removing the mapping
    */
    function removeIdentityExt(address _addr, string calldata _comment) hasIdent(_addr) onlyEditor external {
        __removeIdentity(_addr, _comment);
    }
    /**
    *  Change the state of the mapping to validated
    *  @param _addr Address of the account whose mapping is to be updated
    *  @param _comment Comment describing the reason for validating the mapping
    */
    function validate(address _addr, string calldata _comment) hasIdent(_addr) onlyEditor external {
        identities[_addr].validated = true;
        emit LogIdentityValidated(msg.sender, _addr, _comment);
    }
    /**
    *  Change the state of the mapping to invalidated
    *  @param _addr Address of the account whose mapping is to be updated
    *  @param _comment Comment describing the reason for invalidating the mapping
    */
    function invalidate(address _addr, string calldata _comment) hasIdent(_addr) onlyEditor external {
        identities[_addr].validated = false;
        emit LogIdentityInvalidated(msg.sender, _addr, _comment);
    }
    /**
    *  Adding the given address to the block list and removing its mapping
    *  @param _addr Address of the account to be blocked
    *  @param _comment Comment describing the reason for blocking the address
    */
    function blockAddress(address _addr, string calldata _comment) notBlocked(_addr) onlyEditor external {
        if(identitiesSet.exists(_addr)) {
            __removeIdentity(_addr,"Added to blocklist");
        }
        blockedSet.insert(_addr);
        emit LogIdentityBlocked(msg.sender, _addr, _comment);
    }
    /**
    *  Removing the given address from the block list
    *  @param _addr Address of the account to be unblocked
    *  @param _comment Comment describing the reason for unblocking the address
    */
    function unblockAddress(address _addr, string calldata _comment) onlyEditor external {
        require(blockedSet.exists(_addr),"Address is not blocked");
        blockedSet.remove(_addr);
        emit LogIdentityUnblocked(msg.sender, _addr, _comment);
    }
    /**
    *  Setting a new address for the Editor contract, which handels the access management of the 
    *  editorial functions in this contract.
    *  @param _editorProxy Address of the new Editor contract
    */
    function updateEditorProxy(Editor _editorProxy) onlyOwner external {
        editorProxy = _editorProxy;
    }
    /**
    *  Checks if a given address has a validated identity mapping
    *  @param _addr Address to be checked
    *  @return bool True if the validated mapping exists
    */
    function isValidated(address _addr) hasIdent(_addr) external view returns(bool) {
        return identities[_addr].validated;
    }
    /** 
    *  Checks if a given address has an identity mapping
    *  @param _addr Address to be checked
    *  @return bool True if the mapping exists
    */
    function hasIdentity(address _addr) external view returns(bool) {
        return identitiesSet.exists(_addr);
    }
    /** 
    *  Provides a list of all addresses with an identity mapping
    *  @return address[] Array of all mapped addresses
    */
    function getIdentities() external view returns(address[] memory) {
        return identitiesSet.keyList;
    }
    /** 
    *  Checks if a given address is on the block list
    *  @param _addr Address to be checked
    *  @return bool True if the address is on the block list
    */
    function isBlocked(address _addr) external view returns(bool) {
        return blockedSet.exists(_addr);
    }
    /** 
    *  Provides a list of all addresses on the block list
    *  @return address[] Array of all blocked addresses
    */
    function getBlocked() external view returns(address[] memory) {
        return blockedSet.keyList;
    }
    /**
    *  Add new identity mapping between the given address and the given metadata document hash
    *  @param _addr Address of the account to be mapped to the given identity document hash 
    *  @param _metadata Off-chain reference to the identity document (e.g., IPFS hash) 
    */
    function __addIdentity(address _addr, string memory _metadata) internal {
        require(!identitiesSet.exists(_addr),"Identity already exists");
        identitiesSet.insert(_addr);
        identities[_addr] = IDMeta(true,_metadata,false);
        emit LogIdentityAdded(msg.sender, _addr, _metadata);
    }
    /**
    *  Remove the mapping of the given address
    *  @param _addr Address of the account whose mapping is to be removed 
    *  @param _comment Comment describing the reason for removing the mapping
    */
    function __removeIdentity(address _addr, string memory _comment) internal {
        identitiesSet.remove(_addr);
        string memory metadata = identities[_addr].metadata;
        delete identities[_addr];
        emit LogIdentityRemoved(msg.sender, _addr, metadata, _comment);
    }
    /**
    *  Update the metadata document hash of an existing identity mapping of the given address
    *  @param _addr Address of the account whose mapping is to be updated 
    *  @param _metadata Off-chain reference to the new identity document (e.g., IPFS hash) 
    *  @param _comment Comment describing the document changes
    */
    function __updateIdentity(address _addr, string memory _metadata, string calldata _comment) internal {
        string memory oldMetadata = identities[_addr].metadata;
        identities[_addr].metadata = _metadata;
        emit LogIdentityUpdated(msg.sender, _addr, oldMetadata, _metadata, _comment);
        identities[_addr].validated = false;
        emit LogIdentityInvalidated(msg.sender, _addr, "Updated metadata");
    }
    /**
    *  Only editors may perfom the asserted action
    */
    modifier onlyEditor {
        try editorProxy.actionAllowed('') returns (bool allowed) {
            require(allowed, "Function can only be called with editorial access rights");
        } catch {
            require(false, "Editor contract unavailable");
        }
        _;
    }
    /**
    *  Only addresses that are not on the block list may perform the asserted action
    *  @param _addr Address to be checked
    */
    modifier notBlocked(address _addr) {
        require(!blockedSet.exists(_addr), "Address is blocked");
        _;
    }
    /**
    *  Only addresses that have a identity mapping may perform the asserted action
    *  @param _addr Address to be checked
    */
    modifier hasIdent(address _addr) {
        require(identitiesSet.exists(_addr), "No matching identity found");
        _;
    }
}
          

Initializable.sol

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

import "./AddressUpgradeable.sol";

// OpenZeppelin Contracts v4.4.1 (proxy/utils/Initializable.sol)
/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() initializer {}
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;
    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;
    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        // If the contract is initializing we ignore whether _initialized is set in order to support multiple
        // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
        // contract may have been reentered.
        require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");
        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
        }
    }
    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} modifier, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }
    function _isConstructor() private view returns (bool) {
        return !AddressUpgradeable.isContract(address(this));
    }
}
          

Ownable.sol

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

import "./Context.sol";
// OpenZeppelin Contracts v4.4.1 (access/Ownable.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 Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }
    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }
    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _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);
    }
}
          

OwnableUpgradeable.sol

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

import "./Initializable.sol";
import "./ContextUpgradeable.sol";

// OpenZeppelin Contracts v4.4.1 (access/Ownable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Context_init_unchained();
        __Ownable_init_unchained();
    }
    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }
    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }
    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }
    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _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);
    }
    uint256[49] private __gap;
}
          

PublicationFactory.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import './Identity.sol';
import './Publication.sol';
import "./HitchensUnorderedAddressSet.sol";
import "./Ownable.sol";
import "./ClonesUpgradeable.sol";

// Decentral Publication Contracts v1.0 (contracts/PublicationFactory.sol)
/** @title Upgradeable factory contract for creating Publication contract clones */
contract PublicationFactory is Ownable {
    using HitchensUnorderedAddressSetLib for HitchensUnorderedAddressSetLib.Set;
    // Master copy for the publication contract clones
    address public publicationImpl;
    // Editor contract 
    Editor public editorProxy;
    // Identity contract 
    Identity public identityProxy;
    // Set of all deployed publication contract clones
    HitchensUnorderedAddressSetLib.Set internal publicationsSet;
    event LogPublicationContractCreated(address addr, address sender);
    /**
    *  Constructur sets the master copy contract for the factory and
    *  the address of the Editor (proxy) contract.
    *  @param _publicationImpl Address to the master copy contract for the clone factory
    *  @param _editorProxy Address to the Editor (proxy) contract with which the clones are initialized
    *  @param _identityProxy Address to the Identity (proxy) contract which maps addresses to real world identities
    */
    constructor (address _publicationImpl, address _editorProxy, address _identityProxy) {
        publicationImpl = _publicationImpl;
        editorProxy = Editor(_editorProxy);
        identityProxy = Identity(_identityProxy);
    }
    /**
    *  Creates a clone of the the maste copy publication contract. To be called by the author of the publication to initiate the
    *  submission process. The clone is initialized with the provided submission documents (location of the main document and 
    *  respectiv metadata) and the owner of the cloned contract is set to sender's address. 
    *  The addresses of all clones are automatically stored in the publicationsSet.
    *  @param _document Off-chain reference to the main document of the publication (e.g., IPFS hash)
    *  @param _metadata Off-chain reference to the publication metadata document (e.g., IPFS hash)
    *  @param _identity Off-chain reference to the identity document (e.g., IPFS hash)
    *  @return address Address of the newly created contract clone 
    */
    function createPublication(string memory _document, string memory _metadata, string memory _identity) external returns (address){
        address clone = ClonesUpgradeable.clone(publicationImpl);
        try Publication(clone).initialize(msg.sender, _document, _metadata, _identity, editorProxy, identityProxy, 1) {
            //require(initialized, "publication initialization failed");
        } catch Error(string memory reason){
            require(false, reason);
        }
        publicationsSet.insert(clone);
        emit LogPublicationContractCreated(clone, msg.sender);
        return clone;
    }
    /**
    *  Returns the addresses of all clone contracts created by the factory
    *  @return address[] Array of clone contract addresses
    */
    function getPublications() external view returns (address[] memory) {
        return publicationsSet.keyList;
    }
}
          

Contract ABI

[{"type":"event","name":"LogEndorsementRevocation","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"endorser","internalType":"address","indexed":false},{"type":"string","name":"document","internalType":"string","indexed":false},{"type":"string","name":"comment","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"LogNewEndorsement","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"string","name":"document","internalType":"string","indexed":false},{"type":"string","name":"comment","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"LogNewPublication","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"string","name":"document","internalType":"string","indexed":false},{"type":"string","name":"metadata","internalType":"string","indexed":false},{"type":"uint8","name":"state","internalType":"enum Publication.PublicationState","indexed":false}],"anonymous":false},{"type":"event","name":"LogPublicationPublished","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"string","name":"document","internalType":"string","indexed":false},{"type":"string","name":"metadata","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"LogPublicationRetraction","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"string","name":"comment","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"LogUpdateEndorsementComment","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"endorser","internalType":"address","indexed":false},{"type":"string","name":"document","internalType":"string","indexed":false},{"type":"string","name":"comment","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"LogUpdateEndorsementDocument","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"endorser","internalType":"address","indexed":false},{"type":"string","name":"oldDocument","internalType":"string","indexed":false},{"type":"string","name":"newDocument","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"LogUpdateEndorserRole","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"endorser","internalType":"address","indexed":false},{"type":"string","name":"document","internalType":"string","indexed":false},{"type":"uint8","name":"oldRole","internalType":"enum Publication.EndorserRole","indexed":false},{"type":"uint8","name":"newRole","internalType":"enum Publication.EndorserRole","indexed":false}],"anonymous":false},{"type":"event","name":"LogUpdatePublicationDocument","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"string","name":"oldDocument","internalType":"string","indexed":false},{"type":"string","name":"newDocument","internalType":"string","indexed":false},{"type":"string","name":"comment","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"LogUpdatePublicationMetadata","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"string","name":"oldMetadata","internalType":"string","indexed":false},{"type":"string","name":"newMetadata","internalType":"string","indexed":false},{"type":"string","name":"comment","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"document","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract Editor"}],"name":"editorProxy","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"endorse","inputs":[{"type":"string","name":"_identity","internalType":"string"},{"type":"string","name":"_comment","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"exists","internalType":"bool"},{"type":"string","name":"document","internalType":"string"},{"type":"uint8","name":"role","internalType":"enum Publication.EndorserRole"}],"name":"endorsers","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract Identity"}],"name":"identityProxy","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"string","name":"_document","internalType":"string"},{"type":"string","name":"_metadata","internalType":"string"},{"type":"string","name":"_identity","internalType":"string"},{"type":"address","name":"_editorProxy","internalType":"contract Editor"},{"type":"address","name":"_identityProxy","internalType":"contract Identity"},{"type":"uint8","name":"_journal","internalType":"uint8"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"journal","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"metadata","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"publish","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"retractPublication","inputs":[{"type":"string","name":"_comment","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeEndorsement","inputs":[{"type":"string","name":"_comment","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeEndorsementExt","inputs":[{"type":"address","name":"_endorser","internalType":"address"},{"type":"string","name":"_comment","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"enum Publication.PublicationState"}],"name":"state","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateDocument","inputs":[{"type":"string","name":"_document","internalType":"string"},{"type":"string","name":"_comment","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateEndorsementComment","inputs":[{"type":"string","name":"_comment","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateEndorsementCommentExt","inputs":[{"type":"address","name":"_endorser","internalType":"address"},{"type":"string","name":"_comment","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateEndorsementDocument","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateEndorserRole","inputs":[{"type":"address","name":"_endorser","internalType":"address"},{"type":"uint8","name":"_role","internalType":"enum Publication.EndorserRole"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateMetadata","inputs":[{"type":"string","name":"_metadata","internalType":"string"},{"type":"string","name":"_comment","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"version","inputs":[]}]
              

Contract Creation Code

Verify & Publish
0x608060405234801561001057600080fd5b50614e26806100206000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c8063715018a6116100c3578063c19d93fb1161007c578063c19d93fb1461032c578063c27e3e991461034a578063f16fce2014610368578063f2fde38b14610384578063f3458b19146103a0578063fafc1de5146103aa5761014d565b8063715018a6146102925780637c0380341461029c578063868db57c146102b85780638da5cb5b146102d457806391e57554146102f2578063bf8ad0f0146103105761014d565b80633515a20b116101155780633515a20b146101ce578063392f37e9146102005780634d300e0c1461021e57806354fd4d501461023a57806356ce0e6c1461025857806361471425146102745761014d565b8063072ca49014610152578063075d47821461016e578063137d8e9b146101785780631ddddb18146101945780631f4339d8146101b0575b600080fd5b61016c60048036038101906101679190613145565b6103c6565b005b61017661049f565b005b610192600480360381019061018d91906131f0565b6108aa565b005b6101ae60048036038101906101a99190613391565b6109c0565b005b6101b8610e79565b6040516101c59190613495565b60405180910390f35b6101e860048036038101906101e391906134b7565b610f07565b6040516101f793929190613576565b60405180910390f35b610208610fd3565b6040516102159190613495565b60405180910390f35b61023860048036038101906102339190613391565b611061565b005b6102426112b8565b60405161024f91906135d0565b60405180910390f35b610272600480360381019061026d9190613391565b6112bd565b005b61027c611514565b60405161028991906135d0565b60405180910390f35b61029a611527565b005b6102b660048036038101906102b19190613145565b6115af565b005b6102d260048036038101906102cd9190613693565b611613565b005b6102dc611ae3565b6040516102e99190613798565b60405180910390f35b6102fa611b0d565b6040516103079190613812565b60405180910390f35b61032a60048036038101906103259190613852565b611b33565b005b610334611f07565b60405161034191906138da565b60405180910390f35b610352611f1a565b60405161035f9190613916565b60405180910390f35b610382600480360381019061037d9190613145565b611f40565b005b61039e600480360381019061039991906134b7565b6121c1565b005b6103a86122b9565b005b6103c460048036038101906103bf91906131f0565b61247a565b005b336103db8160666125c890919063ffffffff16565b61041a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104119061397d565b60405180910390fd5b7f434679b17d9cd53f23bfca42fae8a2054170516a440ff32561a15400cff4763e3333606560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018686604051610492959493929190613ac0565b60405180910390a1505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4706104c98161269b565b610508576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ff90613b87565b60405180910390fd5b6001600381111561051c5761051b6134ff565b5b606b60009054906101000a900460ff16600381111561053e5761053d6134ff565b5b1461057e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161057590613c19565b60405180910390fd5b60006069805461058d906139cc565b90501180156105aa57506000606a80546105a6906139cc565b9050115b6105e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105e090613cab565b60405180910390fd5b6000805b6105f7606661279b565b8110156107f9576000606560006106188460666127ac90919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900460ff16151515158152602001600182018054610688906139cc565b80601f01602080910402602001604051908101604052809291908181526020018280546106b4906139cc565b80156107015780601f106106d657610100808354040283529160200191610701565b820191906000526020600020905b8154815290600101906020018083116106e457829003601f168201915b505050505081526020016002820160009054906101000a900460ff16600381111561072f5761072e6134ff565b5b6003811115610741576107406134ff565b5b8152505090506002600381111561075b5761075a6134ff565b5b81604001516003811115610772576107716134ff565b5b14806107a5575060038081111561078c5761078b6134ff565b5b816040015160038111156107a3576107a26134ff565b5b145b80156107d1575060696040516107bb9190613d6a565b6040518091039020816020015180519060200120145b156107e55782806107e190613dba565b9350505b5080806107f190613dba565b9150506105ed565b50600181101561083e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161083590613e75565b60405180910390fd5b6002606b60006101000a81548160ff02191690836003811115610864576108636134ff565b5b02179055507fc0f0a609e353b791e4d3d6234d43ac4ab40f4406257a427e3661ffa39f651614336069606a60405161089e93929190613e95565b60405180910390a15050565b8282826040516020016108bf93929190613f52565b604051602081830303815290604052805190602001206108dd611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061091b575061091a8161269b565b5b61095a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161095190613fee565b60405180910390fd5b8361096f8160666125c890919063ffffffff16565b6109ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a59061397d565b60405180910390fd5b6109b98585856127f7565b5050505050565b6003808111156109d3576109d26134ff565b5b606b60009054906101000a900460ff1660038111156109f5576109f46134ff565b5b1415610a36576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a2d90614080565b60405180910390fd5b610a3e611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610aac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aa390614112565b60405180910390fd5b610ac03360666125c890919063ffffffff16565b15610b00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af7906141a4565b60405180910390fd5b606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663237f1a21336040518263ffffffff1660e01b8152600401610b5b9190613798565b602060405180830381865afa925050508015610b9557506040513d601f19601f82011682018060405250810190610b9291906141f0565b60015b610bdf576000610bda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bd19061428f565b60405180910390fd5b610cb8565b80610cb657606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633ce65e1f856040518263ffffffff1660e01b8152600401610c3f9190613495565b600060405180830381600087803b158015610c5957600080fd5b505af1925050508015610c6a575060015b610cb4576000610caf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca69061428f565b60405180910390fd5b610cb5565b5b5b505b610ccc33606661299990919063ffffffff16565b604051806060016040528060011515815260200160698054610ced906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054610d19906139cc565b8015610d665780601f10610d3b57610100808354040283529160200191610d66565b820191906000526020600020905b815481529060010190602001808311610d4957829003601f168201915b5050505050815260200160016003811115610d8457610d836134ff565b5b815250606560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001019080519060200190610e02929190612f3b565b5060408201518160020160006101000a81548160ff02191690836003811115610e2e57610e2d6134ff565b5b02179055509050507f4b9cb2b363a5ee858fb0cc2bd085673d8dd76f7e593577e376442e1fc5a8e7de3360698484604051610e6c94939291906142af565b60405180910390a1505050565b60698054610e86906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054610eb2906139cc565b8015610eff5780601f10610ed457610100808354040283529160200191610eff565b820191906000526020600020905b815481529060010190602001808311610ee257829003601f168201915b505050505081565b60656020528060005260406000206000915090508060000160009054906101000a900460ff1690806001018054610f3d906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054610f69906139cc565b8015610fb65780601f10610f8b57610100808354040283529160200191610fb6565b820191906000526020600020905b815481529060010190602001808311610f9957829003601f168201915b5050505050908060020160009054906101000a900460ff16905083565b606a8054610fe0906139cc565b80601f016020809104026020016040519081016040528092919081815260200182805461100c906139cc565b80156110595780601f1061102e57610100808354040283529160200191611059565b820191906000526020600020905b81548152906001019060200180831161103c57829003601f168201915b505050505081565b82828260405160200161107693929190614327565b60405160208183030381529060405280519060200120611094611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806110d257506110d18161269b565b5b611111576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161110890613fee565b60405180910390fd5b600380811115611124576111236134ff565b5b606b60009054906101000a900460ff166003811115611146576111456134ff565b5b1415611187576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161117e90614080565b60405180910390fd5b60008451116111cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111c2906143bf565b60405180910390fd5b6000606980546111da906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054611206906139cc565b80156112535780601f1061122857610100808354040283529160200191611253565b820191906000526020600020905b81548152906001019060200180831161123657829003601f168201915b505050505090508460699080519060200190611270929190612f3b565b507f485b8b5d49d7e96530987bf1396564ae0ea49128c95cbbbfcd0ea512f4a4c23f3382606987876040516112a99594939291906143df565b60405180910390a15050505050565b600181565b8282826040516020016112d293929190614327565b604051602081830303815290604052805190602001206112f0611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061132e575061132d8161269b565b5b61136d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161136490613fee565b60405180910390fd5b6003808111156113805761137f6134ff565b5b606b60009054906101000a900460ff1660038111156113a2576113a16134ff565b5b14156113e3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113da90614080565b60405180910390fd5b6000845111611427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161141e906144ad565b60405180910390fd5b6000606a8054611436906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054611462906139cc565b80156114af5780601f10611484576101008083540402835291602001916114af565b820191906000526020600020905b81548152906001019060200180831161149257829003601f168201915b5050505050905084606a90805190602001906114cc929190612f3b565b507f0227bf25436408f256b28c9940609926c6075e64036bbb8b91f45c40b283c6b63382606a87876040516115059594939291906143df565b60405180910390a15050505050565b606860009054906101000a900460ff1681565b61152f612b15565b73ffffffffffffffffffffffffffffffffffffffff1661154d611ae3565b73ffffffffffffffffffffffffffffffffffffffff16146115a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161159a90614519565b60405180910390fd5b6115ad6000612b1d565b565b336115c48160666125c890919063ffffffff16565b611603576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115fa9061397d565b60405180910390fd5b61160e3384846127f7565b505050565b600060019054906101000a900460ff1661163b5760008054906101000a900460ff1615611644565b611643612be3565b5b611683576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161167a906145ab565b60405180910390fd5b60008060019054906101000a900460ff1615905080156116d3576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b600087511180156116e5575060008651115b80156116f2575060008551115b611731576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117289061463d565b60405180910390fd5b82606c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663237f1a21326040518263ffffffff1660e01b81526004016117cd9190613798565b602060405180830381865afa92505050801561180757506040513d601f19601f8201168201806040525081019061180491906141f0565b60015b61188f5761181361466a565b806308c379a0141561187e575061182861468c565b806118335750611880565b60008190611877576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186e9190613495565b60405180910390fd5b505061188a565b505b3d6000803e3d6000fd5b6119a6565b806119a457606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633ce65e1f876040518263ffffffff1660e01b81526004016118ef9190613495565b600060405180830381600087803b15801561190957600080fd5b505af192505050801561191a575060015b6119a25761192661466a565b806308c379a01415611991575061193b61468c565b806119465750611993565b6000819061198a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119819190613495565b60405180910390fd5b505061199d565b505b3d6000803e3d6000fd5b6119a3565b5b5b505b83606b60016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081606860006101000a81548160ff021916908360ff1602179055508660699080519060200190611a18929190612f3b565b5085606a9080519060200190611a2f929190612f3b565b506001606b60006101000a81548160ff02191690836003811115611a5657611a556134ff565b5b02179055507f6e6e8aadd6568bf7641708904cac7c1c943f46f4dc249646de39cbd4156f8c6c328888606b60009054906101000a900460ff16604051611a9f9493929190614722565b60405180910390a1611aaf612bf4565b611ab8886121c1565b8015611ad95760008060016101000a81548160ff0219169083151502179055505b5050505050505050565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606b60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b8181604051602001611b469291906147ab565b60405160208183030381529060405280519060200120611b64611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611ba25750611ba18161269b565b5b611be1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bd890613fee565b60405180910390fd5b82611bf68160666125c890919063ffffffff16565b611c35576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2c9061397d565b60405180910390fd5b60006003811115611c4957611c486134ff565b5b836003811115611c5c57611c5b6134ff565b5b1415611c9d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c9490614823565b60405180910390fd5b6000606560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900460ff16151515158152602001600182018054611d14906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054611d40906139cc565b8015611d8d5780601f10611d6257610100808354040283529160200191611d8d565b820191906000526020600020905b815481529060010190602001808311611d7057829003601f168201915b505050505081526020016002820160009054906101000a900460ff166003811115611dbb57611dba6134ff565b5b6003811115611dcd57611dcc6134ff565b5b8152505090506000816040015190508482604001906003811115611df457611df36134ff565b5b90816003811115611e0857611e076134ff565b5b8152505081606560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001019080519060200190611e88929190612f3b565b5060408201518160020160006101000a81548160ff02191690836003811115611eb457611eb36134ff565b5b02179055509050507f6a7d00b353117270b48f660782a3ce72fec3209c5400b6eea672a09134068815338784602001518489604051611ef7959493929190614843565b60405180910390a1505050505050565b606b60009054906101000a900460ff1681565b606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b8181604051602001611f5392919061489d565b60405160208183030381529060405280519060200120611f71611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611faf5750611fae8161269b565b5b611fee576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fe590613fee565b60405180910390fd5b600380811115612001576120006134ff565b5b606b60009054906101000a900460ff166003811115612023576120226134ff565b5b1415612064576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161205b90614080565b60405180910390fd5b6003606b60006101000a81548160ff0219169083600381111561208a576120896134ff565b5b02179055506069600061209d9190612fc1565b606a60006120ab9190612fc1565b5b60006120b8606661279b565b111561216b5760006120d5600060666127ac90919063ffffffff16565b9050606560008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160006101000a81549060ff021916905560018201600061213b9190612fc1565b6002820160006101000a81549060ff02191690555050612165816066612c5590919063ffffffff16565b506120ac565b6066600060018201600061217f9190613001565b50507f9379a610ba2120f051e2a8333e1011c463a0006ec61a37e171538871b19a4c973384846040516121b4939291906148b6565b60405180910390a1505050565b6121c9612b15565b73ffffffffffffffffffffffffffffffffffffffff166121e7611ae3565b73ffffffffffffffffffffffffffffffffffffffff161461223d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161223490614519565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156122ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122a49061495a565b60405180910390fd5b6122b681612b1d565b50565b336122ce8160666125c890919063ffffffff16565b61230d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123049061397d565b60405180910390fd5b6000606560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101805461235c906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054612388906139cc565b80156123d55780601f106123aa576101008083540402835291602001916123d5565b820191906000526020600020905b8154815290600101906020018083116123b857829003601f168201915b505050505090506069606560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010190805461242c906139cc565b612437929190613022565b507f324ad7caca7f94ae22e76fe579057d163b9db28c4c267335946f9b5b1f0c4ed2333383606960405161246e949392919061497a565b60405180910390a15050565b82828260405160200161248f93929190613f52565b604051602081830303815290604052805190602001206124ae8161269b565b6124ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124e490613b87565b60405180910390fd5b836125028160666125c890919063ffffffff16565b612541576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125389061397d565b60405180910390fd5b7f434679b17d9cd53f23bfca42fae8a2054170516a440ff32561a15400cff4763e3386606560008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010187876040516125b9959493929190613ac0565b60405180910390a15050505050565b600080836001018054905014156125e25760009050612695565b8173ffffffffffffffffffffffffffffffffffffffff16836001018460000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054815481106126505761264f6149cd565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161490505b92915050565b6000806000357fffffffff0000000000000000000000000000000000000000000000000000000016836040516020016126d5929190614a74565b604051602081830303815290604052805190602001209050606b60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fc45c05d826040518263ffffffff1660e01b81526004016127489190614aaf565b602060405180830381865afa92505050801561278257506040513d601f19601f8201168201806040525081019061277f91906141f0565b60015b612790576000915050612796565b80925050505b919050565b600081600101805490509050919050565b60008260010182815481106127c4576127c36149cd565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905092915050565b61280b836066612c5590919063ffffffff16565b6000606560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101805461285a906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054612886906139cc565b80156128d35780601f106128a8576101008083540402835291602001916128d3565b820191906000526020600020905b8154815290600101906020018083116128b657829003601f168201915b50505050509050606560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160006101000a81549060ff021916905560018201600061293e9190612fc1565b6002820160006101000a81549060ff021916905550507feeac29556e3934bb9013dbc6bfb03c354307b574ef88c920c1c580233327bf80338583868660405161298b959493929190614aca565b60405180910390a150505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612a09576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a0090614b91565b60405180910390fd5b612a1382826125c8565b15612a53576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a4a90614c49565b60405180910390fd5b81600101819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060018260010180549050612acc9190614c69565b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050565b600033905090565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081603360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000612bee30612e76565b15905090565b600060019054906101000a900460ff16612c43576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c3a90614d0f565b60405180910390fd5b612c4b612e89565b612c53612eda565b565b612c5f82826125c8565b612c9e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c9590614da1565b60405180910390fd5b6000826001016001612caf8561279b565b612cb99190614c69565b81548110612cca57612cc96149cd565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050808460000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081846001018281548110612d9a57612d996149cd565b5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000905583600101805480612e3b57612e3a614dc1565b5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055905550505050565b600080823b905060008111915050919050565b600060019054906101000a900460ff16612ed8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ecf90614d0f565b60405180910390fd5b565b600060019054906101000a900460ff16612f29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f2090614d0f565b60405180910390fd5b612f39612f34612b15565b612b1d565b565b828054612f47906139cc565b90600052602060002090601f016020900481019282612f695760008555612fb0565b82601f10612f8257805160ff1916838001178555612fb0565b82800160010185558215612fb0579182015b82811115612faf578251825591602001919060010190612f94565b5b509050612fbd91906130af565b5090565b508054612fcd906139cc565b6000825580601f10612fdf5750612ffe565b601f016020900490600052602060002090810190612ffd91906130af565b5b50565b508054600082559060005260206000209081019061301f91906130af565b50565b82805461302e906139cc565b90600052602060002090601f016020900481019282613050576000855561309e565b82601f10613061578054855561309e565b8280016001018555821561309e57600052602060002091601f016020900482015b8281111561309d578254825591600101919060010190613082565b5b5090506130ab91906130af565b5090565b5b808211156130c85760008160009055506001016130b0565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112613105576131046130e0565b5b8235905067ffffffffffffffff811115613122576131216130e5565b5b60208301915083600182028301111561313e5761313d6130ea565b5b9250929050565b6000806020838503121561315c5761315b6130d6565b5b600083013567ffffffffffffffff81111561317a576131796130db565b5b613186858286016130ef565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006131bd82613192565b9050919050565b6131cd816131b2565b81146131d857600080fd5b50565b6000813590506131ea816131c4565b92915050565b600080600060408486031215613209576132086130d6565b5b6000613217868287016131db565b935050602084013567ffffffffffffffff811115613238576132376130db565b5b613244868287016130ef565b92509250509250925092565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61329e82613255565b810181811067ffffffffffffffff821117156132bd576132bc613266565b5b80604052505050565b60006132d06130cc565b90506132dc8282613295565b919050565b600067ffffffffffffffff8211156132fc576132fb613266565b5b61330582613255565b9050602081019050919050565b82818337600083830152505050565b600061333461332f846132e1565b6132c6565b9050828152602081018484840111156133505761334f613250565b5b61335b848285613312565b509392505050565b600082601f830112613378576133776130e0565b5b8135613388848260208601613321565b91505092915050565b6000806000604084860312156133aa576133a96130d6565b5b600084013567ffffffffffffffff8111156133c8576133c76130db565b5b6133d486828701613363565b935050602084013567ffffffffffffffff8111156133f5576133f46130db565b5b613401868287016130ef565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b60005b8381101561344757808201518184015260208101905061342c565b83811115613456576000848401525b50505050565b60006134678261340d565b6134718185613418565b9350613481818560208601613429565b61348a81613255565b840191505092915050565b600060208201905081810360008301526134af818461345c565b905092915050565b6000602082840312156134cd576134cc6130d6565b5b60006134db848285016131db565b91505092915050565b60008115159050919050565b6134f9816134e4565b82525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6004811061353f5761353e6134ff565b5b50565b60008190506135508261352e565b919050565b600061356082613542565b9050919050565b61357081613555565b82525050565b600060608201905061358b60008301866134f0565b818103602083015261359d818561345c565b90506135ac6040830184613567565b949350505050565b600060ff82169050919050565b6135ca816135b4565b82525050565b60006020820190506135e560008301846135c1565b92915050565b60006135f6826131b2565b9050919050565b613606816135eb565b811461361157600080fd5b50565b600081359050613623816135fd565b92915050565b6000613634826131b2565b9050919050565b61364481613629565b811461364f57600080fd5b50565b6000813590506136618161363b565b92915050565b613670816135b4565b811461367b57600080fd5b50565b60008135905061368d81613667565b92915050565b600080600080600080600060e0888a0312156136b2576136b16130d6565b5b60006136c08a828b016131db565b975050602088013567ffffffffffffffff8111156136e1576136e06130db565b5b6136ed8a828b01613363565b965050604088013567ffffffffffffffff81111561370e5761370d6130db565b5b61371a8a828b01613363565b955050606088013567ffffffffffffffff81111561373b5761373a6130db565b5b6137478a828b01613363565b94505060806137588a828b01613614565b93505060a06137698a828b01613652565b92505060c061377a8a828b0161367e565b91505092959891949750929550565b613792816131b2565b82525050565b60006020820190506137ad6000830184613789565b92915050565b6000819050919050565b60006137d86137d36137ce84613192565b6137b3565b613192565b9050919050565b60006137ea826137bd565b9050919050565b60006137fc826137df565b9050919050565b61380c816137f1565b82525050565b60006020820190506138276000830184613803565b92915050565b6004811061383a57600080fd5b50565b60008135905061384c8161382d565b92915050565b60008060408385031215613869576138686130d6565b5b6000613877858286016131db565b92505060206138888582860161383d565b9150509250929050565b600481106138a3576138a26134ff565b5b50565b60008190506138b482613892565b919050565b60006138c4826138a6565b9050919050565b6138d4816138b9565b82525050565b60006020820190506138ef60008301846138cb565b92915050565b6000613900826137df565b9050919050565b613910816138f5565b82525050565b600060208201905061392b6000830184613907565b92915050565b7f4e6f206d61746368696e6720656e646f7273656d656e7420666f756e64000000600082015250565b6000613967601d83613418565b915061397282613931565b602082019050919050565b600060208201905081810360008301526139968161395a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806139e457607f821691505b602082108114156139f8576139f761399d565b5b50919050565b60008190508160005260206000209050919050565b60008154613a20816139cc565b613a2a8186613418565b94506001821660008114613a455760018114613a5757613a8a565b60ff1983168652602086019350613a8a565b613a60856139fe565b60005b83811015613a8257815481890152600182019150602081019050613a63565b808801955050505b50505092915050565b6000613a9f8385613418565b9350613aac838584613312565b613ab583613255565b840190509392505050565b6000608082019050613ad56000830188613789565b613ae26020830187613789565b8181036040830152613af48186613a13565b90508181036060830152613b09818486613a93565b90509695505050505050565b7f46756e6374696f6e2063616e206f6e6c792062652063616c6c6564207769746860008201527f20656469746f7269616c20616363657373207269676874730000000000000000602082015250565b6000613b71603883613418565b9150613b7c82613b15565b604082019050919050565b60006020820190508181036000830152613ba081613b64565b9050919050565b7f46756e6374696f6e20726571756972657320636f6e747261637420737461746560008201527f3a207375626d6974746564000000000000000000000000000000000000000000602082015250565b6000613c03602b83613418565b9150613c0e82613ba7565b604082019050919050565b60006020820190508181036000830152613c3281613bf6565b9050919050565b7f496e70757420666f7220646f63756d656e74206f72206d65746164617461206360008201527f616e6e6f7420626520656d707479000000000000000000000000000000000000602082015250565b6000613c95602e83613418565b9150613ca082613c39565b604082019050919050565b60006020820190508181036000830152613cc481613c88565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b60008154613cf8816139cc565b613d028186613ccb565b94506001821660008114613d1d5760018114613d2e57613d61565b60ff19831686528186019350613d61565b613d3785613cd6565b60005b83811015613d5957815481890152600182019150602081019050613d3a565b838801955050505b50505092915050565b6000613d768284613ceb565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000819050919050565b6000613dc582613db0565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613df857613df7613d81565b5b600182019050919050565b7f496e73756666696369656e74206e756d626572206f662070726976696c65676560008201527f6420656e646f7273656d656e7473000000000000000000000000000000000000602082015250565b6000613e5f602e83613418565b9150613e6a82613e03565b604082019050919050565b60006020820190508181036000830152613e8e81613e52565b9050919050565b6000606082019050613eaa6000830186613789565b8181036020830152613ebc8185613a13565b90508181036040830152613ed08184613a13565b9050949350505050565b60008160601b9050919050565b6000613ef282613eda565b9050919050565b6000613f0482613ee7565b9050919050565b613f1c613f17826131b2565b613ef9565b82525050565b600081905092915050565b6000613f398385613f22565b9350613f46838584613312565b82840190509392505050565b6000613f5e8286613f0b565b601482019150613f6f828486613f2d565b9150819050949350505050565b7f46756e6374696f6e206973207265737472696374656420746f2074686520636f60008201527f6e7472616374206f776e657220616e6420656469746f72730000000000000000602082015250565b6000613fd8603883613418565b9150613fe382613f7c565b604082019050919050565b6000602082019050818103600083015261400781613fcb565b9050919050565b7f46756e6374696f6e2063616e6e6f742062652063616c6c6564206f6e2061207260008201527f6574726163746564207075626c69636174696f6e000000000000000000000000602082015250565b600061406a603483613418565b91506140758261400e565b604082019050919050565b600060208201905081810360008301526140998161405d565b9050919050565b7f46756e6374696f6e2063616e6e6f742062652063616c6c65642062792074686560008201527f20636f6e7472616374206f776e65720000000000000000000000000000000000602082015250565b60006140fc602f83613418565b9150614107826140a0565b604082019050919050565b6000602082019050818103600083015261412b816140ef565b9050919050565b7f46756e6374696f6e2063616e6e6f742062652063616c6c656420627920616e2060008201527f656e646f72736572000000000000000000000000000000000000000000000000602082015250565b600061418e602883613418565b915061419982614132565b604082019050919050565b600060208201905081810360008301526141bd81614181565b9050919050565b6141cd816134e4565b81146141d857600080fd5b50565b6000815190506141ea816141c4565b92915050565b600060208284031215614206576142056130d6565b5b6000614214848285016141db565b91505092915050565b7f4964656e7469747920636f756c64206e6f742062652073746f72656420696e2060008201527f4964656e7469747920636f6e7472616374000000000000000000000000000000602082015250565b6000614279603183613418565b91506142848261421d565b604082019050919050565b600060208201905081810360008301526142a88161426c565b9050919050565b60006060820190506142c46000830187613789565b81810360208301526142d68186613a13565b905081810360408301526142eb818486613a93565b905095945050505050565b60006143018261340d565b61430b8185613f22565b935061431b818560208601613429565b80840191505092915050565b600061433382866142f6565b9150614340828486613f2d565b9150819050949350505050565b7f496e70757420666f7220646f63756d656e742063616e6e6f7420626520656d7060008201527f7479000000000000000000000000000000000000000000000000000000000000602082015250565b60006143a9602283613418565b91506143b48261434d565b604082019050919050565b600060208201905081810360008301526143d88161439c565b9050919050565b60006080820190506143f46000830188613789565b8181036020830152614406818761345c565b9050818103604083015261441a8186613a13565b9050818103606083015261442f818486613a93565b90509695505050505050565b7f496e70757420666f72206d657461646174612063616e6e6f7420626520656d7060008201527f7479000000000000000000000000000000000000000000000000000000000000602082015250565b6000614497602283613418565b91506144a28261443b565b604082019050919050565b600060208201905081810360008301526144c68161448a565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000614503602083613418565b915061450e826144cd565b602082019050919050565b60006020820190508181036000830152614532816144f6565b9050919050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b6000614595602e83613418565b91506145a082614539565b604082019050919050565b600060208201905081810360008301526145c481614588565b9050919050565b7f496e70757420666f7220646f63756d656e742c206964656e746974792c206f7260008201527f206d657461646174612063616e6e6f7420626520656d70747900000000000000602082015250565b6000614627603983613418565b9150614632826145cb565b604082019050919050565b600060208201905081810360008301526146568161461a565b9050919050565b60008160e01c9050919050565b600060033d11156146895760046000803e61468660005161465d565b90505b90565b600060443d101561469c5761471f565b6146a46130cc565b60043d036004823e80513d602482011167ffffffffffffffff821117156146cc57505061471f565b808201805167ffffffffffffffff8111156146ea575050505061471f565b80602083010160043d03850181111561470757505050505061471f565b61471682602001850186613295565b82955050505050505b90565b60006080820190506147376000830187613789565b8181036020830152614749818661345c565b9050818103604083015261475d818561345c565b905061476c60608301846138cb565b95945050505050565b60008160f81b9050919050565b600061478d82614775565b9050919050565b6147a56147a082613555565b614782565b82525050565b60006147b78285613f0b565b6014820191506147c78284614794565b6001820191508190509392505050565b7f496e76616c696420656e646f7273657220726f6c650000000000000000000000600082015250565b600061480d601583613418565b9150614818826147d7565b602082019050919050565b6000602082019050818103600083015261483c81614800565b9050919050565b600060a0820190506148586000830188613789565b6148656020830187613789565b8181036040830152614877818661345c565b90506148866060830185613567565b6148936080830184613567565b9695505050505050565b60006148aa828486613f2d565b91508190509392505050565b60006040820190506148cb6000830186613789565b81810360208301526148de818486613a93565b9050949350505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000614944602683613418565b915061494f826148e8565b604082019050919050565b6000602082019050818103600083015261497381614937565b9050919050565b600060808201905061498f6000830187613789565b61499c6020830186613789565b81810360408301526149ae818561345c565b905081810360608301526149c28184613a13565b905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b614a43614a3e826149fc565b614a28565b82525050565b6000819050919050565b6000819050919050565b614a6e614a6982614a49565b614a53565b82525050565b6000614a808285614a32565b600482019150614a908284614a5d565b6020820191508190509392505050565b614aa981614a49565b82525050565b6000602082019050614ac46000830184614aa0565b92915050565b6000608082019050614adf6000830188613789565b614aec6020830187613789565b8181036040830152614afe818661345c565b90508181036060830152614b13818486613a93565b90509695505050505050565b7f556e6f7264657265644b65795365742831303029202d204b65792063616e6e6f60008201527f7420626520307830000000000000000000000000000000000000000000000000602082015250565b6000614b7b602883613418565b9150614b8682614b1f565b604082019050919050565b60006020820190508181036000830152614baa81614b6e565b9050919050565b7f556e6f726465726564416464726573735365742831303129202d20416464726560008201527f737320286b65792920616c72656164792065786973747320696e20746865207360208201527f65742e0000000000000000000000000000000000000000000000000000000000604082015250565b6000614c33604383613418565b9150614c3e82614bb1565b606082019050919050565b60006020820190508181036000830152614c6281614c26565b9050919050565b6000614c7482613db0565b9150614c7f83613db0565b925082821015614c9257614c91613d81565b5b828203905092915050565b7f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960008201527f6e697469616c697a696e67000000000000000000000000000000000000000000602082015250565b6000614cf9602b83613418565b9150614d0482614c9d565b604082019050919050565b60006020820190508181036000830152614d2881614cec565b9050919050565b7f556e6f7264657265644b65795365742831303229202d2041646472657373202860008201527f6b65792920646f6573206e6f7420657869737420696e20746865207365742e00602082015250565b6000614d8b603f83613418565b9150614d9682614d2f565b604082019050919050565b60006020820190508181036000830152614dba81614d7e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212209395d8e862e542016a5cdae742f818cde31f67b9312dec1a9bd524a134b9ad7b64736f6c634300080c0033

Deployed ByteCode

0x608060405234801561001057600080fd5b506004361061014d5760003560e01c8063715018a6116100c3578063c19d93fb1161007c578063c19d93fb1461032c578063c27e3e991461034a578063f16fce2014610368578063f2fde38b14610384578063f3458b19146103a0578063fafc1de5146103aa5761014d565b8063715018a6146102925780637c0380341461029c578063868db57c146102b85780638da5cb5b146102d457806391e57554146102f2578063bf8ad0f0146103105761014d565b80633515a20b116101155780633515a20b146101ce578063392f37e9146102005780634d300e0c1461021e57806354fd4d501461023a57806356ce0e6c1461025857806361471425146102745761014d565b8063072ca49014610152578063075d47821461016e578063137d8e9b146101785780631ddddb18146101945780631f4339d8146101b0575b600080fd5b61016c60048036038101906101679190613145565b6103c6565b005b61017661049f565b005b610192600480360381019061018d91906131f0565b6108aa565b005b6101ae60048036038101906101a99190613391565b6109c0565b005b6101b8610e79565b6040516101c59190613495565b60405180910390f35b6101e860048036038101906101e391906134b7565b610f07565b6040516101f793929190613576565b60405180910390f35b610208610fd3565b6040516102159190613495565b60405180910390f35b61023860048036038101906102339190613391565b611061565b005b6102426112b8565b60405161024f91906135d0565b60405180910390f35b610272600480360381019061026d9190613391565b6112bd565b005b61027c611514565b60405161028991906135d0565b60405180910390f35b61029a611527565b005b6102b660048036038101906102b19190613145565b6115af565b005b6102d260048036038101906102cd9190613693565b611613565b005b6102dc611ae3565b6040516102e99190613798565b60405180910390f35b6102fa611b0d565b6040516103079190613812565b60405180910390f35b61032a60048036038101906103259190613852565b611b33565b005b610334611f07565b60405161034191906138da565b60405180910390f35b610352611f1a565b60405161035f9190613916565b60405180910390f35b610382600480360381019061037d9190613145565b611f40565b005b61039e600480360381019061039991906134b7565b6121c1565b005b6103a86122b9565b005b6103c460048036038101906103bf91906131f0565b61247a565b005b336103db8160666125c890919063ffffffff16565b61041a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104119061397d565b60405180910390fd5b7f434679b17d9cd53f23bfca42fae8a2054170516a440ff32561a15400cff4763e3333606560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018686604051610492959493929190613ac0565b60405180910390a1505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4706104c98161269b565b610508576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ff90613b87565b60405180910390fd5b6001600381111561051c5761051b6134ff565b5b606b60009054906101000a900460ff16600381111561053e5761053d6134ff565b5b1461057e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161057590613c19565b60405180910390fd5b60006069805461058d906139cc565b90501180156105aa57506000606a80546105a6906139cc565b9050115b6105e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105e090613cab565b60405180910390fd5b6000805b6105f7606661279b565b8110156107f9576000606560006106188460666127ac90919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900460ff16151515158152602001600182018054610688906139cc565b80601f01602080910402602001604051908101604052809291908181526020018280546106b4906139cc565b80156107015780601f106106d657610100808354040283529160200191610701565b820191906000526020600020905b8154815290600101906020018083116106e457829003601f168201915b505050505081526020016002820160009054906101000a900460ff16600381111561072f5761072e6134ff565b5b6003811115610741576107406134ff565b5b8152505090506002600381111561075b5761075a6134ff565b5b81604001516003811115610772576107716134ff565b5b14806107a5575060038081111561078c5761078b6134ff565b5b816040015160038111156107a3576107a26134ff565b5b145b80156107d1575060696040516107bb9190613d6a565b6040518091039020816020015180519060200120145b156107e55782806107e190613dba565b9350505b5080806107f190613dba565b9150506105ed565b50600181101561083e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161083590613e75565b60405180910390fd5b6002606b60006101000a81548160ff02191690836003811115610864576108636134ff565b5b02179055507fc0f0a609e353b791e4d3d6234d43ac4ab40f4406257a427e3661ffa39f651614336069606a60405161089e93929190613e95565b60405180910390a15050565b8282826040516020016108bf93929190613f52565b604051602081830303815290604052805190602001206108dd611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061091b575061091a8161269b565b5b61095a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161095190613fee565b60405180910390fd5b8361096f8160666125c890919063ffffffff16565b6109ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a59061397d565b60405180910390fd5b6109b98585856127f7565b5050505050565b6003808111156109d3576109d26134ff565b5b606b60009054906101000a900460ff1660038111156109f5576109f46134ff565b5b1415610a36576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a2d90614080565b60405180910390fd5b610a3e611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610aac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aa390614112565b60405180910390fd5b610ac03360666125c890919063ffffffff16565b15610b00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af7906141a4565b60405180910390fd5b606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663237f1a21336040518263ffffffff1660e01b8152600401610b5b9190613798565b602060405180830381865afa925050508015610b9557506040513d601f19601f82011682018060405250810190610b9291906141f0565b60015b610bdf576000610bda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bd19061428f565b60405180910390fd5b610cb8565b80610cb657606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633ce65e1f856040518263ffffffff1660e01b8152600401610c3f9190613495565b600060405180830381600087803b158015610c5957600080fd5b505af1925050508015610c6a575060015b610cb4576000610caf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca69061428f565b60405180910390fd5b610cb5565b5b5b505b610ccc33606661299990919063ffffffff16565b604051806060016040528060011515815260200160698054610ced906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054610d19906139cc565b8015610d665780601f10610d3b57610100808354040283529160200191610d66565b820191906000526020600020905b815481529060010190602001808311610d4957829003601f168201915b5050505050815260200160016003811115610d8457610d836134ff565b5b815250606560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001019080519060200190610e02929190612f3b565b5060408201518160020160006101000a81548160ff02191690836003811115610e2e57610e2d6134ff565b5b02179055509050507f4b9cb2b363a5ee858fb0cc2bd085673d8dd76f7e593577e376442e1fc5a8e7de3360698484604051610e6c94939291906142af565b60405180910390a1505050565b60698054610e86906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054610eb2906139cc565b8015610eff5780601f10610ed457610100808354040283529160200191610eff565b820191906000526020600020905b815481529060010190602001808311610ee257829003601f168201915b505050505081565b60656020528060005260406000206000915090508060000160009054906101000a900460ff1690806001018054610f3d906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054610f69906139cc565b8015610fb65780601f10610f8b57610100808354040283529160200191610fb6565b820191906000526020600020905b815481529060010190602001808311610f9957829003601f168201915b5050505050908060020160009054906101000a900460ff16905083565b606a8054610fe0906139cc565b80601f016020809104026020016040519081016040528092919081815260200182805461100c906139cc565b80156110595780601f1061102e57610100808354040283529160200191611059565b820191906000526020600020905b81548152906001019060200180831161103c57829003601f168201915b505050505081565b82828260405160200161107693929190614327565b60405160208183030381529060405280519060200120611094611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806110d257506110d18161269b565b5b611111576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161110890613fee565b60405180910390fd5b600380811115611124576111236134ff565b5b606b60009054906101000a900460ff166003811115611146576111456134ff565b5b1415611187576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161117e90614080565b60405180910390fd5b60008451116111cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111c2906143bf565b60405180910390fd5b6000606980546111da906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054611206906139cc565b80156112535780601f1061122857610100808354040283529160200191611253565b820191906000526020600020905b81548152906001019060200180831161123657829003601f168201915b505050505090508460699080519060200190611270929190612f3b565b507f485b8b5d49d7e96530987bf1396564ae0ea49128c95cbbbfcd0ea512f4a4c23f3382606987876040516112a99594939291906143df565b60405180910390a15050505050565b600181565b8282826040516020016112d293929190614327565b604051602081830303815290604052805190602001206112f0611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061132e575061132d8161269b565b5b61136d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161136490613fee565b60405180910390fd5b6003808111156113805761137f6134ff565b5b606b60009054906101000a900460ff1660038111156113a2576113a16134ff565b5b14156113e3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113da90614080565b60405180910390fd5b6000845111611427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161141e906144ad565b60405180910390fd5b6000606a8054611436906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054611462906139cc565b80156114af5780601f10611484576101008083540402835291602001916114af565b820191906000526020600020905b81548152906001019060200180831161149257829003601f168201915b5050505050905084606a90805190602001906114cc929190612f3b565b507f0227bf25436408f256b28c9940609926c6075e64036bbb8b91f45c40b283c6b63382606a87876040516115059594939291906143df565b60405180910390a15050505050565b606860009054906101000a900460ff1681565b61152f612b15565b73ffffffffffffffffffffffffffffffffffffffff1661154d611ae3565b73ffffffffffffffffffffffffffffffffffffffff16146115a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161159a90614519565b60405180910390fd5b6115ad6000612b1d565b565b336115c48160666125c890919063ffffffff16565b611603576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115fa9061397d565b60405180910390fd5b61160e3384846127f7565b505050565b600060019054906101000a900460ff1661163b5760008054906101000a900460ff1615611644565b611643612be3565b5b611683576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161167a906145ab565b60405180910390fd5b60008060019054906101000a900460ff1615905080156116d3576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b600087511180156116e5575060008651115b80156116f2575060008551115b611731576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117289061463d565b60405180910390fd5b82606c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663237f1a21326040518263ffffffff1660e01b81526004016117cd9190613798565b602060405180830381865afa92505050801561180757506040513d601f19601f8201168201806040525081019061180491906141f0565b60015b61188f5761181361466a565b806308c379a0141561187e575061182861468c565b806118335750611880565b60008190611877576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186e9190613495565b60405180910390fd5b505061188a565b505b3d6000803e3d6000fd5b6119a6565b806119a457606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633ce65e1f876040518263ffffffff1660e01b81526004016118ef9190613495565b600060405180830381600087803b15801561190957600080fd5b505af192505050801561191a575060015b6119a25761192661466a565b806308c379a01415611991575061193b61468c565b806119465750611993565b6000819061198a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119819190613495565b60405180910390fd5b505061199d565b505b3d6000803e3d6000fd5b6119a3565b5b5b505b83606b60016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081606860006101000a81548160ff021916908360ff1602179055508660699080519060200190611a18929190612f3b565b5085606a9080519060200190611a2f929190612f3b565b506001606b60006101000a81548160ff02191690836003811115611a5657611a556134ff565b5b02179055507f6e6e8aadd6568bf7641708904cac7c1c943f46f4dc249646de39cbd4156f8c6c328888606b60009054906101000a900460ff16604051611a9f9493929190614722565b60405180910390a1611aaf612bf4565b611ab8886121c1565b8015611ad95760008060016101000a81548160ff0219169083151502179055505b5050505050505050565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606b60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b8181604051602001611b469291906147ab565b60405160208183030381529060405280519060200120611b64611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611ba25750611ba18161269b565b5b611be1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bd890613fee565b60405180910390fd5b82611bf68160666125c890919063ffffffff16565b611c35576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2c9061397d565b60405180910390fd5b60006003811115611c4957611c486134ff565b5b836003811115611c5c57611c5b6134ff565b5b1415611c9d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c9490614823565b60405180910390fd5b6000606560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900460ff16151515158152602001600182018054611d14906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054611d40906139cc565b8015611d8d5780601f10611d6257610100808354040283529160200191611d8d565b820191906000526020600020905b815481529060010190602001808311611d7057829003601f168201915b505050505081526020016002820160009054906101000a900460ff166003811115611dbb57611dba6134ff565b5b6003811115611dcd57611dcc6134ff565b5b8152505090506000816040015190508482604001906003811115611df457611df36134ff565b5b90816003811115611e0857611e076134ff565b5b8152505081606560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001019080519060200190611e88929190612f3b565b5060408201518160020160006101000a81548160ff02191690836003811115611eb457611eb36134ff565b5b02179055509050507f6a7d00b353117270b48f660782a3ce72fec3209c5400b6eea672a09134068815338784602001518489604051611ef7959493929190614843565b60405180910390a1505050505050565b606b60009054906101000a900460ff1681565b606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b8181604051602001611f5392919061489d565b60405160208183030381529060405280519060200120611f71611ae3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611faf5750611fae8161269b565b5b611fee576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fe590613fee565b60405180910390fd5b600380811115612001576120006134ff565b5b606b60009054906101000a900460ff166003811115612023576120226134ff565b5b1415612064576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161205b90614080565b60405180910390fd5b6003606b60006101000a81548160ff0219169083600381111561208a576120896134ff565b5b02179055506069600061209d9190612fc1565b606a60006120ab9190612fc1565b5b60006120b8606661279b565b111561216b5760006120d5600060666127ac90919063ffffffff16565b9050606560008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160006101000a81549060ff021916905560018201600061213b9190612fc1565b6002820160006101000a81549060ff02191690555050612165816066612c5590919063ffffffff16565b506120ac565b6066600060018201600061217f9190613001565b50507f9379a610ba2120f051e2a8333e1011c463a0006ec61a37e171538871b19a4c973384846040516121b4939291906148b6565b60405180910390a1505050565b6121c9612b15565b73ffffffffffffffffffffffffffffffffffffffff166121e7611ae3565b73ffffffffffffffffffffffffffffffffffffffff161461223d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161223490614519565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156122ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122a49061495a565b60405180910390fd5b6122b681612b1d565b50565b336122ce8160666125c890919063ffffffff16565b61230d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123049061397d565b60405180910390fd5b6000606560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101805461235c906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054612388906139cc565b80156123d55780601f106123aa576101008083540402835291602001916123d5565b820191906000526020600020905b8154815290600101906020018083116123b857829003601f168201915b505050505090506069606560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010190805461242c906139cc565b612437929190613022565b507f324ad7caca7f94ae22e76fe579057d163b9db28c4c267335946f9b5b1f0c4ed2333383606960405161246e949392919061497a565b60405180910390a15050565b82828260405160200161248f93929190613f52565b604051602081830303815290604052805190602001206124ae8161269b565b6124ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124e490613b87565b60405180910390fd5b836125028160666125c890919063ffffffff16565b612541576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125389061397d565b60405180910390fd5b7f434679b17d9cd53f23bfca42fae8a2054170516a440ff32561a15400cff4763e3386606560008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010187876040516125b9959493929190613ac0565b60405180910390a15050505050565b600080836001018054905014156125e25760009050612695565b8173ffffffffffffffffffffffffffffffffffffffff16836001018460000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054815481106126505761264f6149cd565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161490505b92915050565b6000806000357fffffffff0000000000000000000000000000000000000000000000000000000016836040516020016126d5929190614a74565b604051602081830303815290604052805190602001209050606b60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fc45c05d826040518263ffffffff1660e01b81526004016127489190614aaf565b602060405180830381865afa92505050801561278257506040513d601f19601f8201168201806040525081019061277f91906141f0565b60015b612790576000915050612796565b80925050505b919050565b600081600101805490509050919050565b60008260010182815481106127c4576127c36149cd565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905092915050565b61280b836066612c5590919063ffffffff16565b6000606560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101805461285a906139cc565b80601f0160208091040260200160405190810160405280929190818152602001828054612886906139cc565b80156128d35780601f106128a8576101008083540402835291602001916128d3565b820191906000526020600020905b8154815290600101906020018083116128b657829003601f168201915b50505050509050606560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160006101000a81549060ff021916905560018201600061293e9190612fc1565b6002820160006101000a81549060ff021916905550507feeac29556e3934bb9013dbc6bfb03c354307b574ef88c920c1c580233327bf80338583868660405161298b959493929190614aca565b60405180910390a150505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612a09576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a0090614b91565b60405180910390fd5b612a1382826125c8565b15612a53576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a4a90614c49565b60405180910390fd5b81600101819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060018260010180549050612acc9190614c69565b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050565b600033905090565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081603360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000612bee30612e76565b15905090565b600060019054906101000a900460ff16612c43576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c3a90614d0f565b60405180910390fd5b612c4b612e89565b612c53612eda565b565b612c5f82826125c8565b612c9e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c9590614da1565b60405180910390fd5b6000826001016001612caf8561279b565b612cb99190614c69565b81548110612cca57612cc96149cd565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050808460000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081846001018281548110612d9a57612d996149cd565b5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000905583600101805480612e3b57612e3a614dc1565b5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055905550505050565b600080823b905060008111915050919050565b600060019054906101000a900460ff16612ed8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ecf90614d0f565b60405180910390fd5b565b600060019054906101000a900460ff16612f29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f2090614d0f565b60405180910390fd5b612f39612f34612b15565b612b1d565b565b828054612f47906139cc565b90600052602060002090601f016020900481019282612f695760008555612fb0565b82601f10612f8257805160ff1916838001178555612fb0565b82800160010185558215612fb0579182015b82811115612faf578251825591602001919060010190612f94565b5b509050612fbd91906130af565b5090565b508054612fcd906139cc565b6000825580601f10612fdf5750612ffe565b601f016020900490600052602060002090810190612ffd91906130af565b5b50565b508054600082559060005260206000209081019061301f91906130af565b50565b82805461302e906139cc565b90600052602060002090601f016020900481019282613050576000855561309e565b82601f10613061578054855561309e565b8280016001018555821561309e57600052602060002091601f016020900482015b8281111561309d578254825591600101919060010190613082565b5b5090506130ab91906130af565b5090565b5b808211156130c85760008160009055506001016130b0565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112613105576131046130e0565b5b8235905067ffffffffffffffff811115613122576131216130e5565b5b60208301915083600182028301111561313e5761313d6130ea565b5b9250929050565b6000806020838503121561315c5761315b6130d6565b5b600083013567ffffffffffffffff81111561317a576131796130db565b5b613186858286016130ef565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006131bd82613192565b9050919050565b6131cd816131b2565b81146131d857600080fd5b50565b6000813590506131ea816131c4565b92915050565b600080600060408486031215613209576132086130d6565b5b6000613217868287016131db565b935050602084013567ffffffffffffffff811115613238576132376130db565b5b613244868287016130ef565b92509250509250925092565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61329e82613255565b810181811067ffffffffffffffff821117156132bd576132bc613266565b5b80604052505050565b60006132d06130cc565b90506132dc8282613295565b919050565b600067ffffffffffffffff8211156132fc576132fb613266565b5b61330582613255565b9050602081019050919050565b82818337600083830152505050565b600061333461332f846132e1565b6132c6565b9050828152602081018484840111156133505761334f613250565b5b61335b848285613312565b509392505050565b600082601f830112613378576133776130e0565b5b8135613388848260208601613321565b91505092915050565b6000806000604084860312156133aa576133a96130d6565b5b600084013567ffffffffffffffff8111156133c8576133c76130db565b5b6133d486828701613363565b935050602084013567ffffffffffffffff8111156133f5576133f46130db565b5b613401868287016130ef565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b60005b8381101561344757808201518184015260208101905061342c565b83811115613456576000848401525b50505050565b60006134678261340d565b6134718185613418565b9350613481818560208601613429565b61348a81613255565b840191505092915050565b600060208201905081810360008301526134af818461345c565b905092915050565b6000602082840312156134cd576134cc6130d6565b5b60006134db848285016131db565b91505092915050565b60008115159050919050565b6134f9816134e4565b82525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6004811061353f5761353e6134ff565b5b50565b60008190506135508261352e565b919050565b600061356082613542565b9050919050565b61357081613555565b82525050565b600060608201905061358b60008301866134f0565b818103602083015261359d818561345c565b90506135ac6040830184613567565b949350505050565b600060ff82169050919050565b6135ca816135b4565b82525050565b60006020820190506135e560008301846135c1565b92915050565b60006135f6826131b2565b9050919050565b613606816135eb565b811461361157600080fd5b50565b600081359050613623816135fd565b92915050565b6000613634826131b2565b9050919050565b61364481613629565b811461364f57600080fd5b50565b6000813590506136618161363b565b92915050565b613670816135b4565b811461367b57600080fd5b50565b60008135905061368d81613667565b92915050565b600080600080600080600060e0888a0312156136b2576136b16130d6565b5b60006136c08a828b016131db565b975050602088013567ffffffffffffffff8111156136e1576136e06130db565b5b6136ed8a828b01613363565b965050604088013567ffffffffffffffff81111561370e5761370d6130db565b5b61371a8a828b01613363565b955050606088013567ffffffffffffffff81111561373b5761373a6130db565b5b6137478a828b01613363565b94505060806137588a828b01613614565b93505060a06137698a828b01613652565b92505060c061377a8a828b0161367e565b91505092959891949750929550565b613792816131b2565b82525050565b60006020820190506137ad6000830184613789565b92915050565b6000819050919050565b60006137d86137d36137ce84613192565b6137b3565b613192565b9050919050565b60006137ea826137bd565b9050919050565b60006137fc826137df565b9050919050565b61380c816137f1565b82525050565b60006020820190506138276000830184613803565b92915050565b6004811061383a57600080fd5b50565b60008135905061384c8161382d565b92915050565b60008060408385031215613869576138686130d6565b5b6000613877858286016131db565b92505060206138888582860161383d565b9150509250929050565b600481106138a3576138a26134ff565b5b50565b60008190506138b482613892565b919050565b60006138c4826138a6565b9050919050565b6138d4816138b9565b82525050565b60006020820190506138ef60008301846138cb565b92915050565b6000613900826137df565b9050919050565b613910816138f5565b82525050565b600060208201905061392b6000830184613907565b92915050565b7f4e6f206d61746368696e6720656e646f7273656d656e7420666f756e64000000600082015250565b6000613967601d83613418565b915061397282613931565b602082019050919050565b600060208201905081810360008301526139968161395a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806139e457607f821691505b602082108114156139f8576139f761399d565b5b50919050565b60008190508160005260206000209050919050565b60008154613a20816139cc565b613a2a8186613418565b94506001821660008114613a455760018114613a5757613a8a565b60ff1983168652602086019350613a8a565b613a60856139fe565b60005b83811015613a8257815481890152600182019150602081019050613a63565b808801955050505b50505092915050565b6000613a9f8385613418565b9350613aac838584613312565b613ab583613255565b840190509392505050565b6000608082019050613ad56000830188613789565b613ae26020830187613789565b8181036040830152613af48186613a13565b90508181036060830152613b09818486613a93565b90509695505050505050565b7f46756e6374696f6e2063616e206f6e6c792062652063616c6c6564207769746860008201527f20656469746f7269616c20616363657373207269676874730000000000000000602082015250565b6000613b71603883613418565b9150613b7c82613b15565b604082019050919050565b60006020820190508181036000830152613ba081613b64565b9050919050565b7f46756e6374696f6e20726571756972657320636f6e747261637420737461746560008201527f3a207375626d6974746564000000000000000000000000000000000000000000602082015250565b6000613c03602b83613418565b9150613c0e82613ba7565b604082019050919050565b60006020820190508181036000830152613c3281613bf6565b9050919050565b7f496e70757420666f7220646f63756d656e74206f72206d65746164617461206360008201527f616e6e6f7420626520656d707479000000000000000000000000000000000000602082015250565b6000613c95602e83613418565b9150613ca082613c39565b604082019050919050565b60006020820190508181036000830152613cc481613c88565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b60008154613cf8816139cc565b613d028186613ccb565b94506001821660008114613d1d5760018114613d2e57613d61565b60ff19831686528186019350613d61565b613d3785613cd6565b60005b83811015613d5957815481890152600182019150602081019050613d3a565b838801955050505b50505092915050565b6000613d768284613ceb565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000819050919050565b6000613dc582613db0565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613df857613df7613d81565b5b600182019050919050565b7f496e73756666696369656e74206e756d626572206f662070726976696c65676560008201527f6420656e646f7273656d656e7473000000000000000000000000000000000000602082015250565b6000613e5f602e83613418565b9150613e6a82613e03565b604082019050919050565b60006020820190508181036000830152613e8e81613e52565b9050919050565b6000606082019050613eaa6000830186613789565b8181036020830152613ebc8185613a13565b90508181036040830152613ed08184613a13565b9050949350505050565b60008160601b9050919050565b6000613ef282613eda565b9050919050565b6000613f0482613ee7565b9050919050565b613f1c613f17826131b2565b613ef9565b82525050565b600081905092915050565b6000613f398385613f22565b9350613f46838584613312565b82840190509392505050565b6000613f5e8286613f0b565b601482019150613f6f828486613f2d565b9150819050949350505050565b7f46756e6374696f6e206973207265737472696374656420746f2074686520636f60008201527f6e7472616374206f776e657220616e6420656469746f72730000000000000000602082015250565b6000613fd8603883613418565b9150613fe382613f7c565b604082019050919050565b6000602082019050818103600083015261400781613fcb565b9050919050565b7f46756e6374696f6e2063616e6e6f742062652063616c6c6564206f6e2061207260008201527f6574726163746564207075626c69636174696f6e000000000000000000000000602082015250565b600061406a603483613418565b91506140758261400e565b604082019050919050565b600060208201905081810360008301526140998161405d565b9050919050565b7f46756e6374696f6e2063616e6e6f742062652063616c6c65642062792074686560008201527f20636f6e7472616374206f776e65720000000000000000000000000000000000602082015250565b60006140fc602f83613418565b9150614107826140a0565b604082019050919050565b6000602082019050818103600083015261412b816140ef565b9050919050565b7f46756e6374696f6e2063616e6e6f742062652063616c6c656420627920616e2060008201527f656e646f72736572000000000000000000000000000000000000000000000000602082015250565b600061418e602883613418565b915061419982614132565b604082019050919050565b600060208201905081810360008301526141bd81614181565b9050919050565b6141cd816134e4565b81146141d857600080fd5b50565b6000815190506141ea816141c4565b92915050565b600060208284031215614206576142056130d6565b5b6000614214848285016141db565b91505092915050565b7f4964656e7469747920636f756c64206e6f742062652073746f72656420696e2060008201527f4964656e7469747920636f6e7472616374000000000000000000000000000000602082015250565b6000614279603183613418565b91506142848261421d565b604082019050919050565b600060208201905081810360008301526142a88161426c565b9050919050565b60006060820190506142c46000830187613789565b81810360208301526142d68186613a13565b905081810360408301526142eb818486613a93565b905095945050505050565b60006143018261340d565b61430b8185613f22565b935061431b818560208601613429565b80840191505092915050565b600061433382866142f6565b9150614340828486613f2d565b9150819050949350505050565b7f496e70757420666f7220646f63756d656e742063616e6e6f7420626520656d7060008201527f7479000000000000000000000000000000000000000000000000000000000000602082015250565b60006143a9602283613418565b91506143b48261434d565b604082019050919050565b600060208201905081810360008301526143d88161439c565b9050919050565b60006080820190506143f46000830188613789565b8181036020830152614406818761345c565b9050818103604083015261441a8186613a13565b9050818103606083015261442f818486613a93565b90509695505050505050565b7f496e70757420666f72206d657461646174612063616e6e6f7420626520656d7060008201527f7479000000000000000000000000000000000000000000000000000000000000602082015250565b6000614497602283613418565b91506144a28261443b565b604082019050919050565b600060208201905081810360008301526144c68161448a565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000614503602083613418565b915061450e826144cd565b602082019050919050565b60006020820190508181036000830152614532816144f6565b9050919050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b6000614595602e83613418565b91506145a082614539565b604082019050919050565b600060208201905081810360008301526145c481614588565b9050919050565b7f496e70757420666f7220646f63756d656e742c206964656e746974792c206f7260008201527f206d657461646174612063616e6e6f7420626520656d70747900000000000000602082015250565b6000614627603983613418565b9150614632826145cb565b604082019050919050565b600060208201905081810360008301526146568161461a565b9050919050565b60008160e01c9050919050565b600060033d11156146895760046000803e61468660005161465d565b90505b90565b600060443d101561469c5761471f565b6146a46130cc565b60043d036004823e80513d602482011167ffffffffffffffff821117156146cc57505061471f565b808201805167ffffffffffffffff8111156146ea575050505061471f565b80602083010160043d03850181111561470757505050505061471f565b61471682602001850186613295565b82955050505050505b90565b60006080820190506147376000830187613789565b8181036020830152614749818661345c565b9050818103604083015261475d818561345c565b905061476c60608301846138cb565b95945050505050565b60008160f81b9050919050565b600061478d82614775565b9050919050565b6147a56147a082613555565b614782565b82525050565b60006147b78285613f0b565b6014820191506147c78284614794565b6001820191508190509392505050565b7f496e76616c696420656e646f7273657220726f6c650000000000000000000000600082015250565b600061480d601583613418565b9150614818826147d7565b602082019050919050565b6000602082019050818103600083015261483c81614800565b9050919050565b600060a0820190506148586000830188613789565b6148656020830187613789565b8181036040830152614877818661345c565b90506148866060830185613567565b6148936080830184613567565b9695505050505050565b60006148aa828486613f2d565b91508190509392505050565b60006040820190506148cb6000830186613789565b81810360208301526148de818486613a93565b9050949350505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000614944602683613418565b915061494f826148e8565b604082019050919050565b6000602082019050818103600083015261497381614937565b9050919050565b600060808201905061498f6000830187613789565b61499c6020830186613789565b81810360408301526149ae818561345c565b905081810360608301526149c28184613a13565b905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b614a43614a3e826149fc565b614a28565b82525050565b6000819050919050565b6000819050919050565b614a6e614a6982614a49565b614a53565b82525050565b6000614a808285614a32565b600482019150614a908284614a5d565b6020820191508190509392505050565b614aa981614a49565b82525050565b6000602082019050614ac46000830184614aa0565b92915050565b6000608082019050614adf6000830188613789565b614aec6020830187613789565b8181036040830152614afe818661345c565b90508181036060830152614b13818486613a93565b90509695505050505050565b7f556e6f7264657265644b65795365742831303029202d204b65792063616e6e6f60008201527f7420626520307830000000000000000000000000000000000000000000000000602082015250565b6000614b7b602883613418565b9150614b8682614b1f565b604082019050919050565b60006020820190508181036000830152614baa81614b6e565b9050919050565b7f556e6f726465726564416464726573735365742831303129202d20416464726560008201527f737320286b65792920616c72656164792065786973747320696e20746865207360208201527f65742e0000000000000000000000000000000000000000000000000000000000604082015250565b6000614c33604383613418565b9150614c3e82614bb1565b606082019050919050565b60006020820190508181036000830152614c6281614c26565b9050919050565b6000614c7482613db0565b9150614c7f83613db0565b925082821015614c9257614c91613d81565b5b828203905092915050565b7f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960008201527f6e697469616c697a696e67000000000000000000000000000000000000000000602082015250565b6000614cf9602b83613418565b9150614d0482614c9d565b604082019050919050565b60006020820190508181036000830152614d2881614cec565b9050919050565b7f556e6f7264657265644b65795365742831303229202d2041646472657373202860008201527f6b65792920646f6573206e6f7420657869737420696e20746865207365742e00602082015250565b6000614d8b603f83613418565b9150614d9682614d2f565b604082019050919050565b60006020820190508181036000830152614dba81614d7e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212209395d8e862e542016a5cdae742f818cde31f67b9312dec1a9bd524a134b9ad7b64736f6c634300080c0033