Address Details
contract

0x438d727b434b6126aF6a91AcBf7Ce9e2a1A967c8

Contract Name
CeloEduMarketplace
Creator
0x92ed65–55ad42 at 0xff9b35–53d573
Balance
0 CELO ( )
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
17 Transactions
Transfers
0 Transfers
Gas Used
2,027,794
Last Balance Update
11536199
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
CeloEduMarketplace




Optimization enabled
false
Compiler version
v0.8.7+commit.e28d00a7




EVM Version
london




Verified at
2022-05-20T03:13:52.008197Z

CeloEduMarketplace.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract CeloEduMarketplace {
    using Counters for Counters.Counter;

    address internal cUSDTokenAddress = 0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1;

    struct Course {
        address payable owner;
        string title;
        string description;
        string author;
        string image;
        uint price;
        uint sold;
    }

    struct Learner {
        address owner;
        bool isComplete;
    }

    mapping(uint256 => Course) internal courses;
    mapping(uint256 => Learner[]) internal learners;
    Counters.Counter public totalCourses;

    function addCourse(
        string memory _title, 
        string memory _description,
        string memory _author,
        string memory _image,
        uint _price
    ) public {
        uint256 courseIndex = totalCourses.current();
        totalCourses.increment();
        uint _sold = 0;

        courses[courseIndex] = Course(
            payable(msg.sender), 
            _title, 
            _description, 
            _author, 
            _image, 
            _price, 
            _sold
        );
    }

    function getCourse(uint _index) public view returns (
        address payable,
        string memory,
        string memory,
        string memory,
        string memory,
        uint,
        uint
    ) {
        Course storage c = courses[_index];

        return (
            c.owner, 
            c.title, 
            c.description, 
            c.author, 
            c.image, 
            c.price, 
            c.sold
        );
    }

    function buyCourse(uint _index) public payable {
        IERC20 cUSD = IERC20(cUSDTokenAddress);
        Course storage c = courses[_index];

        require(!isBoughtCourse(_index), "Course has already been bought");
        require(cUSD.balanceOf(msg.sender) > c.price, "Not enough cUSD");

        require(
            cUSD.transferFrom(
                msg.sender, 
                c.owner, 
                c.price
            ), 
            "Failed to transfer funds"
        );

        c.sold++;
        learners[_index].push(Learner(msg.sender, false));
    }

    function completeCourse(uint _index) public payable {
        require(isBoughtCourse(_index), "Need to buy course first");
        require(!isCompleteCourse(_index), "Course is already complete");

        Learner[] storage _learners = learners[_index];

        for (uint i = 0; i < _learners.length; i++) {
            if (_learners[i].owner == msg.sender) {
                _learners[i].isComplete = true;
                break;
            }
        }
    }

    function isBoughtCourse(uint _index) public view returns (bool) {
        Learner[] memory _learners = getCourseLearners(_index);

        for (uint i = 0; i < _learners.length; i++) {
            if (_learners[i].owner == msg.sender) {
                return true;
            }
        }

        return false;
    }

    function isCompleteCourse(uint _index) public view returns (bool) {
        Learner[] memory _learners = getCourseLearners(_index);

        for (uint i = 0; i < _learners.length; i++) {
            if (_learners[i].isComplete) {
                return true;
            }
        }

        return false;
    }

    function getCourseLearners(uint _index) public view returns (Learner[] memory) {
        Learner[] memory _learners = learners[_index];
        return _learners;
    }
}
        

/_openzeppelin/contracts/token/ERC20/IERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}
          

/_openzeppelin/contracts/utils/Counters.sol

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

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}
          

Contract ABI

[{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addCourse","inputs":[{"type":"string","name":"_title","internalType":"string"},{"type":"string","name":"_description","internalType":"string"},{"type":"string","name":"_author","internalType":"string"},{"type":"string","name":"_image","internalType":"string"},{"type":"uint256","name":"_price","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"buyCourse","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"completeCourse","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address payable"},{"type":"string","name":"","internalType":"string"},{"type":"string","name":"","internalType":"string"},{"type":"string","name":"","internalType":"string"},{"type":"string","name":"","internalType":"string"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCourse","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct CeloEduMarketplace.Learner[]","components":[{"type":"address","name":"owner","internalType":"address"},{"type":"bool","name":"isComplete","internalType":"bool"}]}],"name":"getCourseLearners","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isBoughtCourse","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isCompleteCourse","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_value","internalType":"uint256"}],"name":"totalCourses","inputs":[]}]
              

Contract Creation Code

0x608060405273874069fa1eb16d44d622f2e0ca25eea172369bc16000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561006457600080fd5b50611798806100746000396000f3fe60806040526004361061007b5760003560e01c806337f66bb71161004e57806337f66bb71461013857806372bc10021461017557806387ac18601461019e578063e3a62c32146101c95761007b565b80630b91e28d146100805780630d3b4292146100c357806315876d43146100df578063194d73a21461011c575b600080fd5b34801561008c57600080fd5b506100a760048036038101906100a29190610f38565b610206565b6040516100ba97969594939291906111a3565b60405180910390f35b6100dd60048036038101906100d89190610f38565b6104b1565b005b3480156100eb57600080fd5b5061010660048036038101906101019190610f38565b610632565b6040516101139190611287565b60405180910390f35b61013660048036038101906101319190610f38565b6106c8565b005b34801561014457600080fd5b5061015f600480360381019061015a9190610f38565b610a00565b60405161016c9190611287565b60405180910390f35b34801561018157600080fd5b5061019c60048036038101906101979190610e4d565b610a68565b005b3480156101aa57600080fd5b506101b3610bb9565b6040516101c09190611342565b60405180910390f35b3480156101d557600080fd5b506101f060048036038101906101eb9190610f38565b610bc5565b6040516101fd9190611265565b60405180910390f35b60006060806060806000806000600160008a815260200190815260200160002090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160010182600201836003018460040185600501548660060154858054610273906114da565b80601f016020809104026020016040519081016040528092919081815260200182805461029f906114da565b80156102ec5780601f106102c1576101008083540402835291602001916102ec565b820191906000526020600020905b8154815290600101906020018083116102cf57829003601f168201915b505050505095508480546102ff906114da565b80601f016020809104026020016040519081016040528092919081815260200182805461032b906114da565b80156103785780601f1061034d57610100808354040283529160200191610378565b820191906000526020600020905b81548152906001019060200180831161035b57829003601f168201915b5050505050945083805461038b906114da565b80601f01602080910402602001604051908101604052809291908181526020018280546103b7906114da565b80156104045780601f106103d957610100808354040283529160200191610404565b820191906000526020600020905b8154815290600101906020018083116103e757829003601f168201915b50505050509350828054610417906114da565b80601f0160208091040260200160405190810160405280929190818152602001828054610443906114da565b80156104905780601f1061046557610100808354040283529160200191610490565b820191906000526020600020905b81548152906001019060200180831161047357829003601f168201915b50505050509250975097509750975097509750975050919395979092949650565b6104ba81610632565b6104f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104f090611302565b60405180910390fd5b61050281610a00565b15610542576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161053990611322565b60405180910390fd5b600060026000838152602001908152602001600020905060005b818054905081101561062d573373ffffffffffffffffffffffffffffffffffffffff16828281548110610592576105916115e4565b5b9060005260206000200160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561061a5760018282815481106105f1576105f06115e4565b5b9060005260206000200160000160146101000a81548160ff02191690831515021790555061062d565b80806106259061153d565b91505061055c565b505050565b60008061063e83610bc5565b905060005b81518110156106bc573373ffffffffffffffffffffffffffffffffffffffff16828281518110610676576106756115e4565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614156106a9576001925050506106c3565b80806106b49061153d565b915050610643565b5060009150505b919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600060016000848152602001908152602001600020905061070e83610632565b1561074e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610745906112c2565b60405180910390fd5b80600501548273ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b815260040161078c9190611188565b60206040518083038186803b1580156107a457600080fd5b505afa1580156107b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107dc9190610f65565b1161081c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610813906112e2565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166323b872dd338360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684600501546040518463ffffffff1660e01b81526004016108819392919061122e565b602060405180830381600087803b15801561089b57600080fd5b505af11580156108af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d39190610e20565b610912576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610909906112a2565b60405180910390fd5b8060060160008154809291906109279061153d565b91905055506002600084815260200190815260200160002060405180604001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001600015158152509080600181540180825580915050600190039060005260206000200160009091909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff0219169083151502179055505050505050565b600080610a0c83610bc5565b905060005b8151811015610a5c57818181518110610a2d57610a2c6115e4565b5b60200260200101516020015115610a4957600192505050610a63565b8080610a549061153d565b915050610a11565b5060009150505b919050565b6000610a746003610caa565b9050610a806003610cb8565b60006040518060e001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001888152602001878152602001868152602001858152602001848152602001828152506001600084815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151816001019080519060200190610b41929190610cce565b506040820151816002019080519060200190610b5e929190610cce565b506060820151816003019080519060200190610b7b929190610cce565b506080820151816004019080519060200190610b98929190610cce565b5060a0820151816005015560c0820151816006015590505050505050505050565b60038060000154905081565b6060600060026000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610c9b578382906000526020600020016040518060400160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff16151515158152505081526020019060010190610bfc565b50505050905080915050919050565b600081600001549050919050565b6001816000016000828254019250508190555050565b828054610cda906114da565b90600052602060002090601f016020900481019282610cfc5760008555610d43565b82601f10610d1557805160ff1916838001178555610d43565b82800160010185558215610d43579182015b82811115610d42578251825591602001919060010190610d27565b5b509050610d509190610d54565b5090565b5b80821115610d6d576000816000905550600101610d55565b5090565b6000610d84610d7f84611382565b61135d565b905082815260208101848484011115610da057610d9f611647565b5b610dab848285611498565b509392505050565b600081519050610dc281611734565b92915050565b600082601f830112610ddd57610ddc611642565b5b8135610ded848260208601610d71565b91505092915050565b600081359050610e058161174b565b92915050565b600081519050610e1a8161174b565b92915050565b600060208284031215610e3657610e35611651565b5b6000610e4484828501610db3565b91505092915050565b600080600080600060a08688031215610e6957610e68611651565b5b600086013567ffffffffffffffff811115610e8757610e8661164c565b5b610e9388828901610dc8565b955050602086013567ffffffffffffffff811115610eb457610eb361164c565b5b610ec088828901610dc8565b945050604086013567ffffffffffffffff811115610ee157610ee061164c565b5b610eed88828901610dc8565b935050606086013567ffffffffffffffff811115610f0e57610f0d61164c565b5b610f1a88828901610dc8565b9250506080610f2b88828901610df6565b9150509295509295909350565b600060208284031215610f4e57610f4d611651565b5b6000610f5c84828501610df6565b91505092915050565b600060208284031215610f7b57610f7a611651565b5b6000610f8984828501610e0b565b91505092915050565b6000610f9e838361114a565b60408301905092915050565b610fb381611462565b82525050565b610fc28161141a565b82525050565b610fd181611408565b82525050565b610fe081611408565b82525050565b6000610ff1826113c3565b610ffb81856113e6565b9350611006836113b3565b8060005b8381101561103757815161101e8882610f92565b9750611029836113d9565b92505060018101905061100a565b5085935050505092915050565b61104d8161142c565b82525050565b61105c8161142c565b82525050565b600061106d826113ce565b61107781856113f7565b93506110878185602086016114a7565b61109081611656565b840191505092915050565b60006110a86018836113f7565b91506110b382611667565b602082019050919050565b60006110cb601e836113f7565b91506110d682611690565b602082019050919050565b60006110ee600f836113f7565b91506110f9826116b9565b602082019050919050565b60006111116018836113f7565b915061111c826116e2565b602082019050919050565b6000611134601a836113f7565b915061113f8261170b565b602082019050919050565b6040820160008201516111606000850182610fc8565b5060208201516111736020850182611044565b50505050565b61118281611458565b82525050565b600060208201905061119d6000830184610fd7565b92915050565b600060e0820190506111b8600083018a610fb9565b81810360208301526111ca8189611062565b905081810360408301526111de8188611062565b905081810360608301526111f28187611062565b905081810360808301526112068186611062565b905061121560a0830185611179565b61122260c0830184611179565b98975050505050505050565b60006060820190506112436000830186610fd7565b6112506020830185610faa565b61125d6040830184611179565b949350505050565b6000602082019050818103600083015261127f8184610fe6565b905092915050565b600060208201905061129c6000830184611053565b92915050565b600060208201905081810360008301526112bb8161109b565b9050919050565b600060208201905081810360008301526112db816110be565b9050919050565b600060208201905081810360008301526112fb816110e1565b9050919050565b6000602082019050818103600083015261131b81611104565b9050919050565b6000602082019050818103600083015261133b81611127565b9050919050565b60006020820190506113576000830184611179565b92915050565b6000611367611378565b9050611373828261150c565b919050565b6000604051905090565b600067ffffffffffffffff82111561139d5761139c611613565b5b6113a682611656565b9050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600061141382611438565b9050919050565b600061142582611438565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061146d82611474565b9050919050565b600061147f82611486565b9050919050565b600061149182611438565b9050919050565b82818337600083830152505050565b60005b838110156114c55780820151818401526020810190506114aa565b838111156114d4576000848401525b50505050565b600060028204905060018216806114f257607f821691505b60208210811415611506576115056115b5565b5b50919050565b61151582611656565b810181811067ffffffffffffffff8211171561153457611533611613565b5b80604052505050565b600061154882611458565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561157b5761157a611586565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4661696c656420746f207472616e736665722066756e64730000000000000000600082015250565b7f436f757273652068617320616c7265616479206265656e20626f756768740000600082015250565b7f4e6f7420656e6f75676820635553440000000000000000000000000000000000600082015250565b7f4e65656420746f2062757920636f757273652066697273740000000000000000600082015250565b7f436f7572736520697320616c726561647920636f6d706c657465000000000000600082015250565b61173d8161142c565b811461174857600080fd5b50565b61175481611458565b811461175f57600080fd5b5056fea2646970667358221220711c4f3a410270f24afe22146328ae1be30d41cdab26bcebaf64c970e7efb1b664736f6c63430008070033

Deployed ByteCode

0x60806040526004361061007b5760003560e01c806337f66bb71161004e57806337f66bb71461013857806372bc10021461017557806387ac18601461019e578063e3a62c32146101c95761007b565b80630b91e28d146100805780630d3b4292146100c357806315876d43146100df578063194d73a21461011c575b600080fd5b34801561008c57600080fd5b506100a760048036038101906100a29190610f38565b610206565b6040516100ba97969594939291906111a3565b60405180910390f35b6100dd60048036038101906100d89190610f38565b6104b1565b005b3480156100eb57600080fd5b5061010660048036038101906101019190610f38565b610632565b6040516101139190611287565b60405180910390f35b61013660048036038101906101319190610f38565b6106c8565b005b34801561014457600080fd5b5061015f600480360381019061015a9190610f38565b610a00565b60405161016c9190611287565b60405180910390f35b34801561018157600080fd5b5061019c60048036038101906101979190610e4d565b610a68565b005b3480156101aa57600080fd5b506101b3610bb9565b6040516101c09190611342565b60405180910390f35b3480156101d557600080fd5b506101f060048036038101906101eb9190610f38565b610bc5565b6040516101fd9190611265565b60405180910390f35b60006060806060806000806000600160008a815260200190815260200160002090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160010182600201836003018460040185600501548660060154858054610273906114da565b80601f016020809104026020016040519081016040528092919081815260200182805461029f906114da565b80156102ec5780601f106102c1576101008083540402835291602001916102ec565b820191906000526020600020905b8154815290600101906020018083116102cf57829003601f168201915b505050505095508480546102ff906114da565b80601f016020809104026020016040519081016040528092919081815260200182805461032b906114da565b80156103785780601f1061034d57610100808354040283529160200191610378565b820191906000526020600020905b81548152906001019060200180831161035b57829003601f168201915b5050505050945083805461038b906114da565b80601f01602080910402602001604051908101604052809291908181526020018280546103b7906114da565b80156104045780601f106103d957610100808354040283529160200191610404565b820191906000526020600020905b8154815290600101906020018083116103e757829003601f168201915b50505050509350828054610417906114da565b80601f0160208091040260200160405190810160405280929190818152602001828054610443906114da565b80156104905780601f1061046557610100808354040283529160200191610490565b820191906000526020600020905b81548152906001019060200180831161047357829003601f168201915b50505050509250975097509750975097509750975050919395979092949650565b6104ba81610632565b6104f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104f090611302565b60405180910390fd5b61050281610a00565b15610542576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161053990611322565b60405180910390fd5b600060026000838152602001908152602001600020905060005b818054905081101561062d573373ffffffffffffffffffffffffffffffffffffffff16828281548110610592576105916115e4565b5b9060005260206000200160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561061a5760018282815481106105f1576105f06115e4565b5b9060005260206000200160000160146101000a81548160ff02191690831515021790555061062d565b80806106259061153d565b91505061055c565b505050565b60008061063e83610bc5565b905060005b81518110156106bc573373ffffffffffffffffffffffffffffffffffffffff16828281518110610676576106756115e4565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614156106a9576001925050506106c3565b80806106b49061153d565b915050610643565b5060009150505b919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600060016000848152602001908152602001600020905061070e83610632565b1561074e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610745906112c2565b60405180910390fd5b80600501548273ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b815260040161078c9190611188565b60206040518083038186803b1580156107a457600080fd5b505afa1580156107b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107dc9190610f65565b1161081c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610813906112e2565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166323b872dd338360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684600501546040518463ffffffff1660e01b81526004016108819392919061122e565b602060405180830381600087803b15801561089b57600080fd5b505af11580156108af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d39190610e20565b610912576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610909906112a2565b60405180910390fd5b8060060160008154809291906109279061153d565b91905055506002600084815260200190815260200160002060405180604001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001600015158152509080600181540180825580915050600190039060005260206000200160009091909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff0219169083151502179055505050505050565b600080610a0c83610bc5565b905060005b8151811015610a5c57818181518110610a2d57610a2c6115e4565b5b60200260200101516020015115610a4957600192505050610a63565b8080610a549061153d565b915050610a11565b5060009150505b919050565b6000610a746003610caa565b9050610a806003610cb8565b60006040518060e001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001888152602001878152602001868152602001858152602001848152602001828152506001600084815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151816001019080519060200190610b41929190610cce565b506040820151816002019080519060200190610b5e929190610cce565b506060820151816003019080519060200190610b7b929190610cce565b506080820151816004019080519060200190610b98929190610cce565b5060a0820151816005015560c0820151816006015590505050505050505050565b60038060000154905081565b6060600060026000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610c9b578382906000526020600020016040518060400160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff16151515158152505081526020019060010190610bfc565b50505050905080915050919050565b600081600001549050919050565b6001816000016000828254019250508190555050565b828054610cda906114da565b90600052602060002090601f016020900481019282610cfc5760008555610d43565b82601f10610d1557805160ff1916838001178555610d43565b82800160010185558215610d43579182015b82811115610d42578251825591602001919060010190610d27565b5b509050610d509190610d54565b5090565b5b80821115610d6d576000816000905550600101610d55565b5090565b6000610d84610d7f84611382565b61135d565b905082815260208101848484011115610da057610d9f611647565b5b610dab848285611498565b509392505050565b600081519050610dc281611734565b92915050565b600082601f830112610ddd57610ddc611642565b5b8135610ded848260208601610d71565b91505092915050565b600081359050610e058161174b565b92915050565b600081519050610e1a8161174b565b92915050565b600060208284031215610e3657610e35611651565b5b6000610e4484828501610db3565b91505092915050565b600080600080600060a08688031215610e6957610e68611651565b5b600086013567ffffffffffffffff811115610e8757610e8661164c565b5b610e9388828901610dc8565b955050602086013567ffffffffffffffff811115610eb457610eb361164c565b5b610ec088828901610dc8565b945050604086013567ffffffffffffffff811115610ee157610ee061164c565b5b610eed88828901610dc8565b935050606086013567ffffffffffffffff811115610f0e57610f0d61164c565b5b610f1a88828901610dc8565b9250506080610f2b88828901610df6565b9150509295509295909350565b600060208284031215610f4e57610f4d611651565b5b6000610f5c84828501610df6565b91505092915050565b600060208284031215610f7b57610f7a611651565b5b6000610f8984828501610e0b565b91505092915050565b6000610f9e838361114a565b60408301905092915050565b610fb381611462565b82525050565b610fc28161141a565b82525050565b610fd181611408565b82525050565b610fe081611408565b82525050565b6000610ff1826113c3565b610ffb81856113e6565b9350611006836113b3565b8060005b8381101561103757815161101e8882610f92565b9750611029836113d9565b92505060018101905061100a565b5085935050505092915050565b61104d8161142c565b82525050565b61105c8161142c565b82525050565b600061106d826113ce565b61107781856113f7565b93506110878185602086016114a7565b61109081611656565b840191505092915050565b60006110a86018836113f7565b91506110b382611667565b602082019050919050565b60006110cb601e836113f7565b91506110d682611690565b602082019050919050565b60006110ee600f836113f7565b91506110f9826116b9565b602082019050919050565b60006111116018836113f7565b915061111c826116e2565b602082019050919050565b6000611134601a836113f7565b915061113f8261170b565b602082019050919050565b6040820160008201516111606000850182610fc8565b5060208201516111736020850182611044565b50505050565b61118281611458565b82525050565b600060208201905061119d6000830184610fd7565b92915050565b600060e0820190506111b8600083018a610fb9565b81810360208301526111ca8189611062565b905081810360408301526111de8188611062565b905081810360608301526111f28187611062565b905081810360808301526112068186611062565b905061121560a0830185611179565b61122260c0830184611179565b98975050505050505050565b60006060820190506112436000830186610fd7565b6112506020830185610faa565b61125d6040830184611179565b949350505050565b6000602082019050818103600083015261127f8184610fe6565b905092915050565b600060208201905061129c6000830184611053565b92915050565b600060208201905081810360008301526112bb8161109b565b9050919050565b600060208201905081810360008301526112db816110be565b9050919050565b600060208201905081810360008301526112fb816110e1565b9050919050565b6000602082019050818103600083015261131b81611104565b9050919050565b6000602082019050818103600083015261133b81611127565b9050919050565b60006020820190506113576000830184611179565b92915050565b6000611367611378565b9050611373828261150c565b919050565b6000604051905090565b600067ffffffffffffffff82111561139d5761139c611613565b5b6113a682611656565b9050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600061141382611438565b9050919050565b600061142582611438565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061146d82611474565b9050919050565b600061147f82611486565b9050919050565b600061149182611438565b9050919050565b82818337600083830152505050565b60005b838110156114c55780820151818401526020810190506114aa565b838111156114d4576000848401525b50505050565b600060028204905060018216806114f257607f821691505b60208210811415611506576115056115b5565b5b50919050565b61151582611656565b810181811067ffffffffffffffff8211171561153457611533611613565b5b80604052505050565b600061154882611458565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561157b5761157a611586565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4661696c656420746f207472616e736665722066756e64730000000000000000600082015250565b7f436f757273652068617320616c7265616479206265656e20626f756768740000600082015250565b7f4e6f7420656e6f75676820635553440000000000000000000000000000000000600082015250565b7f4e65656420746f2062757920636f757273652066697273740000000000000000600082015250565b7f436f7572736520697320616c726561647920636f6d706c657465000000000000600082015250565b61173d8161142c565b811461174857600080fd5b50565b61175481611458565b811461175f57600080fd5b5056fea2646970667358221220711c4f3a410270f24afe22146328ae1be30d41cdab26bcebaf64c970e7efb1b664736f6c63430008070033