ETH Price: $3,281.48 (+0.34%)

Token

DOG (D)
 

Overview

Max Total Supply

1,000 D

Holders

48

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 9 Decimals)

Filtered by Token Holder
dancho6.eth
Balance
10.023804901 D

Value
$0.00
0xb80128d5bf716dd6fe5e7b6895d08ef3cb92e3f1
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Dog

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 22 : Dog.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.21;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./Token.sol";
import "./Breed.sol";

contract HoldersList {
    mapping(uint index => address holder) _holders;
    mapping(address holder => uint index) _holder_index;
    uint public holders_count;

    function get_holders_list(
        uint index,
        uint count
    ) external view returns (uint page_count, address[] memory accounts) {
        if (index >= holders_count) return (0, new address[](0));

        uint end = index + count;
        if (end > holders_count) {
            end = holders_count;
        }
        page_count = end - index;

        accounts = new address[](page_count);
        uint i;
        for (i = index; i < page_count; ++i) {
            accounts[i] = _holders[index + i];
        }
    }

    function add_holder(address value) internal {
        uint index = holders_count++;
        _holders[index] = value;
        _holder_index[value] = index;
    }

    function remove_holder(address value) internal {
        if (holders_count == 0) return;

        uint removingIndex = _holder_index[value];
        if (removingIndex != holders_count - 1) {
            address lastHolder = _holders[holders_count - 1];
            _holders[removingIndex] = lastHolder;
            _holder_index[lastHolder] = removingIndex;
        }

        --holders_count;
        delete _holder_index[value];
        delete _holders[holders_count];
    }
}

contract Dog is Token, ReentrancyGuard, HoldersList {
    uint constant MAX_GENS_START = 1000;
    uint public constant GEN_MIN = 1;
    uint public constant gen_max = MAX_GENS_START;
    uint public gen = MAX_GENS_START;
    uint public constant max_breed = 1000;
    mapping(address owner => mapping(uint index => Breed)) public breeds;
    mapping(address owner => uint) public counts;
    uint public breed_total_count;
    uint breed_id;

    constructor() Token("DOG", "D") {}

    function _add_breed_to_owner(address account, Breed memory breed) private {
        if (account == _pair) return;
        if (++counts[account] == 1) add_holder(account);
        ++breed_total_count;
        uint index = counts[account] - 1;
        breeds[account][index] = breed;
    }

    function _remove_breed_from_owner_by_index(
        address account,
        uint index
    ) private {
        if (account == _pair) return;
        if (--counts[account] == 0) remove_holder(account);
        --breed_total_count;
        uint last_index = counts[account];
        if (index != last_index) {
            Breed memory last_breed = breeds[account][last_index];
            breeds[account][index] = last_breed;
        }
        delete breeds[account][last_index];
    }

    function _transfer_breed_from_to_by_index(
        address account,
        uint index,
        address to
    ) private {
        Breed memory breed = breeds[account][index];
        super.transfer_internal(account, to, 10 ** DECIMALS);
        _remove_breed_from_owner_by_index(account, index);
        _add_breed_to_owner(to, breed);
    }

    function transfer_breed_from_to_by_index(uint index, address to) external {
        require(index < counts[msg.sender], "incorrect index");
        _transfer_breed_from_to_by_index(msg.sender, index, to);
    }

    function gen_mode(uint value) private returns (uint) {
        value = (value * gen) / gen_max;
        if (value == 0) value = 1;
        if (gen > GEN_MIN) --gen;
        return value;
    }

    function buy(
        address to,
        uint256 amount
    ) internal virtual override nonReentrant {
        uint last_balance = balanceOf(to);
        uint balance = last_balance + amount;
        uint count = balance /
            (10 ** decimals()) -
            last_balance /
            (10 ** decimals());
        uint i;
        for (i = 0; i < count; ++i) {
            Breed memory breed = Breed(++breed_id, gen_mode(max_breed));
            _add_breed_to_owner(to, breed);
        }
        super.buy(to, amount);
    }

    function sell(
        address from,
        uint256 amount
    ) internal virtual override lockFee nonReentrant {
        uint last_balance = balanceOf(from);
        uint balance = last_balance - amount;
        uint count = last_balance /
            (10 ** decimals()) -
            balance /
            (10 ** decimals());
        uint i;
        uint owner_count = counts[from];
        for (i = 0; i < count; ++i) {
            if (gen < gen_max) ++gen;
            if (owner_count > 0)
                _remove_breed_from_owner_by_index(from, --owner_count);
        }
        super._transfer(from, _pair, amount);
    }

    function transfer_internal(
        address from,
        address to,
        uint256 amount
    ) internal virtual override nonReentrant {
        uint last_balance_from = balanceOf(from);
        uint balance_from = last_balance_from - amount;
        uint last_balance_to = balanceOf(to);
        uint balance_to = last_balance_to + amount;
        if (to == address(0) || to == DEAD_ADDRESS) {
            last_balance_to = 0;
            balance_to = 0;
        }

        uint count_from = last_balance_from /
            (10 ** decimals()) -
            balance_from /
            (10 ** decimals());
        uint count_to = balance_to /
            (10 ** decimals()) -
            last_balance_to /
            (10 ** decimals());
        // calculate transfer count
        uint transfer_count = count_from;

        if (transfer_count > count_to) transfer_count = count_to;
        // transfer
        uint i;
        uint owner_count = counts[from];
        for (i = 0; i < transfer_count; ++i) {
            if (owner_count == 0) break;
            uint from_index = --owner_count;
            Breed memory breed = breeds[from][from_index];
            _remove_breed_from_owner_by_index(from, from_index);
            _add_breed_to_owner(to, breed);
        }
        uint transfered = i;

        // remove from
        for (i = transfer_count; i < count_from; ++i) {
            uint from_index = --owner_count;
            _remove_breed_from_owner_by_index(from, from_index);
        }

        // generate to
        for (i = transfered; i < count_to; ++i) {
            Breed memory breed = Breed(++breed_id, gen_mode(max_breed));
            _add_breed_to_owner(to, breed);
        }

        super.transfer_internal(from, to, amount);
    }

    function get_item_acc_index(
        address account,
        uint index
    ) external view returns (ItemData memory) {
        return this.get_item(breeds[account][index]);
    }

    function get_svg_acc_index(
        address account,
        uint index
    ) external view returns (string memory) {
        return toSvg(this.get_item_acc_index(account, index));
    }

    function get_account_breeds(
        address account,
        uint index,
        uint count
    ) external view returns (uint page_count, Breed[] memory accounts) {
        uint account_count = counts[account];
        if (index >= account_count) return (0, new Breed[](0));

        uint end = index + count;
        if (end > account_count) {
            end = account_count;
        }
        page_count = end - index;

        accounts = new Breed[](page_count);
        uint i;
        for (i = 0; i < page_count; ++i) {
            accounts[i] = breeds[account][index + i];
        }
    }

    function get_account_items(
        address account,
        uint index,
        uint count
    ) external view returns (uint page_count, ItemData[] memory accounts) {
        uint account_count = counts[account];
        if (index >= account_count) return (0, new ItemData[](0));

        uint end = index + count;
        if (end > account_count) {
            end = account_count;
        }
        page_count = end - index;

        accounts = new ItemData[](page_count);
        uint i;
        for (i = 0; i < page_count; ++i) {
            accounts[i] = this.get_item(breeds[account][index + i]);
        }
    }

    function get_account_svgs(
        address account,
        uint index,
        uint count
    ) external view returns (uint page_count, string[] memory accounts) {
        uint account_count = counts[account];
        if (index >= account_count) return (0, new string[](0));

        uint end = index + count;
        if (end > account_count) {
            end = account_count;
            page_count = index - end;
        }

        accounts = new string[](page_count);
        uint i;
        uint n = 0;
        for (i = index; i < end; ++i) {
            accounts[n++] = toSvg(this.get_item(breeds[account][i]));
        }
    }
}

File 2 of 22 : Breed.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

struct Breed {
    uint serial_number; // serial number
    uint breed2; // value breed
}

File 3 of 22 : Token.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import "./ERC20Token.sol";
import "./Generator.sol";

address constant DEAD_ADDRESS = 0x000000000000000000000000000000000000dEaD;

contract Token is ERC20Token, Generator {
    uint8 constant DECIMALS = 9;

    uint256 constant _startTotalSupply = 1000 * (10 ** DECIMALS);
    uint256 constant _startMaxBuyCount = (_startTotalSupply * 5) / 10000;
    uint256 constant _addMaxBuyPercentPerSec = 1; // 100%=_addMaxBuyPrecesion add 0.005%/second
    uint256 constant _addMaxBuyPrecesion = 10000;
    uint256 constant _taxPrecesion = 1000;
    uint256 constant _transferZeroTaxSeconds = 1000; // zero tax transfer time
    address internal _pair;
    address immutable _deployer;
    bool internal _feeLocked;
    uint256 internal _startTime;

    constructor(
        string memory name_,
        string memory symbol_
    ) ERC20Token(name_, symbol_) {
        _deployer = msg.sender;
        _mint(msg.sender, _startTotalSupply);
    }

    modifier maxBuyLimit(uint256 amount) {
        require(amount <= maxBuy(), "max buy");
        _;
    }
    modifier lockFee() {
        _feeLocked = true;
        _;
        _feeLocked = false;
    }

    function decimals() public pure override returns (uint8) {
        return DECIMALS;
    }

    function start(address pair) external onlyOwner {
        _pair = pair;
        _startTime = block.timestamp;
    }

    function isStarted() public view returns (bool) {
        return _pair != address(0);
    }

    receive() external payable {
        bool sent;
        (sent, ) = payable(_deployer).call{value: msg.value}("");
        require(sent, "can not get ether");
    }

    function maxBuy() public view returns (uint256) {
        if (!isStarted()) return _startTotalSupply;
        uint256 count = _startMaxBuyCount +
            (_startTotalSupply *
                (block.timestamp - _startTime) *
                _addMaxBuyPercentPerSec) /
            _addMaxBuyPrecesion;
        if (count > _startTotalSupply) count = _startTotalSupply;
        return count;
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal override {
        // allow burning
        if (to == address(0) || to == DEAD_ADDRESS) {
            transfer_internal(from, to, amount);
            return;
        }

        // system transfers
        if (
            !isStarted() &&
            (from == address(0) ||
                from == address(this) ||
                from == _deployer ||
                to == _deployer)
        ) {
            super._transfer(from, to, amount);
            return;
        }

        // transfers with fee
        if (_feeLocked) {
            super._transfer(from, to, amount);
            return;
        } else {
            if (from == _pair) {
                buy(to, amount);
                return;
            } else if (to == _pair) {
                sell(from, amount);
                return;
            } else transfer_internal(from, to, amount);
        }
    }

    function buy(
        address to,
        uint256 amount
    ) internal virtual maxBuyLimit(amount) lockFee {
        super._transfer(_pair, to, amount);
    }

    function sell(address from, uint256 amount) internal virtual lockFee {
        super._transfer(from, _pair, amount);
    }

    function transfer_internal(
        address from,
        address to,
        uint256 amount
    ) internal virtual lockFee {
        if (to == address(0) || to == DEAD_ADDRESS) {
            _burn(from, amount);
            return;
        }
        super._transfer(from, to, amount);
    }
}

File 4 of 22 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

File 5 of 22 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     * ```
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

File 6 of 22 : Generator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "./Path.sol";
import "./String.sol";
import "./Files.sol";
import "./Colors.sol";
import "./IGenerator.sol";
import "./Breed.sol";
import "./Random.sol";
import "./Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

uint8 constant PIXELS_COUNT = 10;

contract Generator is Ownable {
    using FilesLib for mapping(uint => Path[]);
    using PathLib for Path;
    using PathLib for Path[];
    using RandLib for Rand;
    using RandLib for string[];

    
    string[] public fur_colors = ["#D2B48C", "#A52A2A", "#000000", "#FFFFFF", "#708090"]; 
    string[] public eye_colors = ["#6A5ACD", "#4682B4", "#2F4F4F"]; 
    string[] public nose_colors = ["#000000", "#696969", "#A9A9A9"]; 
    string[] public tongue_colors = ["#FF6347", "#FF4500"]; 
    string[] public ear_colors = ["#FFD700", "#ADFF2F", "#FF6347", "#00BFFF", "#FF69B4"];

    string[] public background_colors = [
        "#20a826", "#f4910a", "#003cff", "#f8e424", "#a0301d", 
        "#4bcadd", "#ff2a2a", "#7400a4", "#78c59b", "#f8Bac7"
    ];


    uint color_step_base = 1000;
    uint MAX = 1000;

    function set_max_base(uint max) external onlyOwner {
        MAX = max;
    }

    function set_color_step_base(uint step_base) external onlyOwner {
        color_step_base = step_base;
    }

    function pick_color(string[] storage colors, uint random_value) private view returns (string memory) {
        uint index = random_value % colors.length;
        return colors[index];
    }

    function get_item(Breed calldata breed) external view returns (ItemData memory) {
    Rand memory rnd = Rand(breed, 0);
    return ItemData({
        furColor: pick_color(fur_colors, rnd.next()),
        eyeColor: pick_color(eye_colors, rnd.next()),
        noseColor: pick_color(nose_colors, rnd.next()),
        tongueColor: pick_color(tongue_colors, rnd.next()),
        earColor: pick_color(ear_colors, rnd.next()),        
        backgroundColor: pick_color(background_colors, rnd.next())
    });
}


    function getSvg(Breed calldata breed) external view returns (string memory) {
        return toSvg(this.get_item(breed));
    }

   function toSvg(ItemData memory data) internal pure returns (string memory) {
    return string(abi.encodePacked(
        "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>",
        "<rect width='100' height='100' fill='", data.backgroundColor, "'/>", 
        
        "<polygon points='50,20 70,35 70,65 50,80 30,65 30,35' fill='", data.furColor, "' />",
        "<rect x='25' y='30' width='10' height='10' fill='", data.earColor, "' />",    
        "<rect x='65' y='30' width='10' height='10' fill='", data.earColor, "' />",    
        "<circle cx='40' cy='50' r='5' fill='", data.eyeColor, "' />",      
        "<circle cx='60' cy='50' r='5' fill='", data.eyeColor, "' />",      
        "<circle cx='50' cy='60' r='5' fill='", data.noseColor, "' />",     
        "<ellipse cx='50' cy='70' rx='10' ry='5' fill='", data.tongueColor, "' />",   
        "</svg>"
    ));
}




}

File 7 of 22 : ERC20Token.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 */
abstract contract ERC20Token is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     * ```
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

File 8 of 22 : draft-IERC6093.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

File 9 of 22 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 10 of 22 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 11 of 22 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` 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 value) external returns (bool);
}

File 12 of 22 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

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

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

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

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

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

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

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

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

File 13 of 22 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Ownable {
    address _owner;

    event RenounceOwnership();

    constructor() {
        _owner = msg.sender;
    }

    modifier onlyOwner() {
        require(_owner == msg.sender, "only owner");
        _;
    }

    function owner() external view virtual returns (address) {
        return _owner;
    }

    function ownerRenounce() public onlyOwner {
        _owner = address(0);
        emit RenounceOwnership();
    }

    function transferOwnership(address newOwner) external onlyOwner {
        _owner = newOwner;
    }
}

File 14 of 22 : Random.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "./Breed.sol";

struct Rand {
    Breed breed;
    uint nonce;
}

library RandLib {
    function next(Rand memory rnd) internal pure returns (uint) {
        return
            uint(
                keccak256(
                    abi.encodePacked(
                        rnd.breed.serial_number,
                        rnd.breed.breed2,
                        rnd.nonce++
                    )
                )
            );
    }

    function next_breed2_clamped(Rand memory rnd) internal pure returns (uint) {
        return next(rnd) % rnd.breed.breed2;
    }
}

File 15 of 22 : IGenerator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./Breed.sol";
import "./ItemData.sol";

interface IGenerator {
    function get_item(
        Breed calldata seed_data
    ) external view returns (ItemData memory);

    function getSvg(
        Breed calldata seed_data
    ) external view returns (string memory);
}

File 16 of 22 : Colors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

library ColorConvert {
    function toSvgColor(uint24 value) internal pure returns (string memory) {
        return string(abi.encodePacked("#", toHex(value)));
    }

    function toHex(uint24 value) internal pure returns (bytes memory) {
        bytes memory buffer = new bytes(6);
        for (uint i = 0; i < 3; ++i) {
            buffer[5 - i * 2] = hexChar(uint8(value) & 0x0f);
            buffer[4 - i * 2] = hexChar((uint8(value) >> 4) & 0x0f);
            value >>= 8;
        }
        return buffer;
    }

    function hexChar(uint8 value) internal pure returns (bytes1) {
        if (value < 10) return bytes1(uint8(48 + (uint(value) % 10)));
        return bytes1(uint8(65 + uint256((value - 10) % 6)));
    }
}

File 17 of 22 : Files.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import './Path.sol';

struct FileData {
    uint file;
    Path[] paths;
}

library FilesLib {
    function set_file(
        mapping(uint => Path[]) storage paths,
        FileData calldata input,
        uint8 count
    ) internal returns (uint8) {
        Path[] storage storageFile = paths[input.file];
        if (storageFile.length > 0) delete paths[input.file - 1];
        else ++count;
        for (uint i = 0; i < input.paths.length; ++i) {
            storageFile.push(input.paths[i]);
        }
        return count;
    }

    function set_files(
        mapping(uint => Path[]) storage paths,
        FileData[] calldata input,
        uint8 count
    ) internal returns (uint8) {
        if (input.length == 0) return count;
        uint i;
        for (i = 0; i < input.length; ++i)
            count = set_file(paths, input[i], count);
        return count;
    }
}

File 18 of 22 : String.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

library StringLib {
    function equals(
        string memory s1,
        string memory s2
    ) internal pure returns (bool) {
        return (keccak256(abi.encodePacked((s1))) ==
            keccak256(abi.encodePacked((s2))));
    }
}

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

File 19 of 22 : Path.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "./Path.sol";
import "./String.sol";
import "./Colors.sol";
import "./Random.sol";

struct Path {
    string fill;
    string data;
}

library PathLib {
    using PathLib for Path;
    using RandLib for Rand;
    using RandLib for string[];
    using StringConverter for uint8;
    using ColorConvert for uint24;
    using StringLib for string;

    function toSvg(Path memory p) internal pure returns (string memory) {
        return
            string(
                abi.encodePacked("<path fill='", p.fill, "' d='", p.data, "'/>")
            );
    }

    function toSvg(
        Path memory p,
        string memory color
    ) internal pure returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "<path fill='",
                    color,
                    "' d='",
                    p.data,
                    color,
                    "'/>"
                )
            );
    }

    function toSvg(
        Path[] storage paths,
        string memory color
    ) internal view returns (string memory) {
        string memory res;
        for (uint i = 0; i < paths.length; ++i) {
            res = string(abi.encodePacked(res, paths[i].toSvg(color)));
        }
        return res;
    }

    function toSvg(Path[] storage paths) internal view returns (string memory) {
        string memory res;
        for (uint i = 0; i < paths.length; ++i) {
            res = string(abi.encodePacked(res, paths[i].toSvg()));
        }
        return res;
    }
}

File 20 of 22 : ItemData.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

struct ItemData {
    string furColor;
    string eyeColor;
    string noseColor;
    string tongueColor;
    string earColor;        
    string backgroundColor;
}

File 21 of 22 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

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

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

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

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

File 22 of 22 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

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

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

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

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

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

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

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

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

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

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

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

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[],"name":"RenounceOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"GEN_MIN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"background_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"breed_total_count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"breeds","outputs":[{"internalType":"uint256","name":"serial_number","type":"uint256"},{"internalType":"uint256","name":"breed2","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"counts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ear_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"eye_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fur_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gen","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gen_max","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"serial_number","type":"uint256"},{"internalType":"uint256","name":"breed2","type":"uint256"}],"internalType":"struct Breed","name":"breed","type":"tuple"}],"name":"getSvg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"get_account_breeds","outputs":[{"internalType":"uint256","name":"page_count","type":"uint256"},{"components":[{"internalType":"uint256","name":"serial_number","type":"uint256"},{"internalType":"uint256","name":"breed2","type":"uint256"}],"internalType":"struct Breed[]","name":"accounts","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"get_account_items","outputs":[{"internalType":"uint256","name":"page_count","type":"uint256"},{"components":[{"internalType":"string","name":"furColor","type":"string"},{"internalType":"string","name":"eyeColor","type":"string"},{"internalType":"string","name":"noseColor","type":"string"},{"internalType":"string","name":"tongueColor","type":"string"},{"internalType":"string","name":"earColor","type":"string"},{"internalType":"string","name":"backgroundColor","type":"string"}],"internalType":"struct ItemData[]","name":"accounts","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"get_account_svgs","outputs":[{"internalType":"uint256","name":"page_count","type":"uint256"},{"internalType":"string[]","name":"accounts","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"get_holders_list","outputs":[{"internalType":"uint256","name":"page_count","type":"uint256"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"serial_number","type":"uint256"},{"internalType":"uint256","name":"breed2","type":"uint256"}],"internalType":"struct Breed","name":"breed","type":"tuple"}],"name":"get_item","outputs":[{"components":[{"internalType":"string","name":"furColor","type":"string"},{"internalType":"string","name":"eyeColor","type":"string"},{"internalType":"string","name":"noseColor","type":"string"},{"internalType":"string","name":"tongueColor","type":"string"},{"internalType":"string","name":"earColor","type":"string"},{"internalType":"string","name":"backgroundColor","type":"string"}],"internalType":"struct ItemData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"get_item_acc_index","outputs":[{"components":[{"internalType":"string","name":"furColor","type":"string"},{"internalType":"string","name":"eyeColor","type":"string"},{"internalType":"string","name":"noseColor","type":"string"},{"internalType":"string","name":"tongueColor","type":"string"},{"internalType":"string","name":"earColor","type":"string"},{"internalType":"string","name":"backgroundColor","type":"string"}],"internalType":"struct ItemData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"get_svg_acc_index","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"holders_count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBuy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"max_breed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nose_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownerRenounce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"step_base","type":"uint256"}],"name":"set_color_step_base","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"name":"set_max_base","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"start","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tongue_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"transfer_breed_from_to_by_index","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a06040526040518060a001604052806040518060400160405280600781526020017f234432423438430000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f234135324132410000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f233030303030300000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f234646464646460000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f23373038303930000000000000000000000000000000000000000000000000008152508152506006906005610144929190610b0e565b5060405180606001604052806040518060400160405280600781526020017f233641354143440000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f233436383242340000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f2332463446344600000000000000000000000000000000000000000000000000815250815250600790600361020f929190610b65565b5060405180606001604052806040518060400160405280600781526020017f233030303030300000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f233639363936390000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f234139413941390000000000000000000000000000000000000000000000000081525081525060089060036102da929190610b65565b5060405180604001604052806040518060400160405280600781526020017f234646363334370000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f2346463435303000000000000000000000000000000000000000000000000000815250815250600990600261036a929190610bbc565b506040518060a001604052806040518060400160405280600781526020017f234646443730300000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f234144464632460000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f234646363334370000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f233030424646460000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f2346463639423400000000000000000000000000000000000000000000000000815250815250600a9060056104ab929190610b0e565b506040518061014001604052806040518060400160405280600781526020017f233230613832360000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f236634393130610000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f233030336366660000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f236638653432340000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f236130333031640000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f233462636164640000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f236666326132610000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f233734303061340000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f233738633539620000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600781526020017f2366384261633700000000000000000000000000000000000000000000000000815250815250600b90600a610714929190610c13565b506103e8600c556103e8600d556103e8601455348015610732575f80fd5b506040518060400160405280600381526020017f444f4700000000000000000000000000000000000000000000000000000000008152506040518060400160405280600181526020017f4400000000000000000000000000000000000000000000000000000000000000815250818181600390816107b09190610f1f565b5080600490816107c09190610f1f565b5050503360055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050610861336009600a6108499190611156565b6103e861085691906111a0565b61087060201b60201c565b505060016010819055506112c9565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036108e0575f6040517fec442f050000000000000000000000000000000000000000000000000000000081526004016108d79190611220565b60405180910390fd5b6108f15f83836108f560201b60201c565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610945578060025f8282546109399190611239565b92505081905550610a13565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050818110156109ce578381836040517fe450d38c0000000000000000000000000000000000000000000000000000000081526004016109c59392919061127b565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a5a578060025f8282540392505081905550610aa4565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610b0191906112b0565b60405180910390a3505050565b828054828255905f5260205f20908101928215610b54579160200282015b82811115610b53578251829081610b439190610f1f565b5091602001919060010190610b2c565b5b509050610b619190610c6a565b5090565b828054828255905f5260205f20908101928215610bab579160200282015b82811115610baa578251829081610b9a9190610f1f565b5091602001919060010190610b83565b5b509050610bb89190610c6a565b5090565b828054828255905f5260205f20908101928215610c02579160200282015b82811115610c01578251829081610bf19190610f1f565b5091602001919060010190610bda565b5b509050610c0f9190610c6a565b5090565b828054828255905f5260205f20908101928215610c59579160200282015b82811115610c58578251829081610c489190610f1f565b5091602001919060010190610c31565b5b509050610c669190610c6a565b5090565b5b80821115610c89575f8181610c809190610c8d565b50600101610c6b565b5090565b508054610c9990610d49565b5f825580601f10610caa5750610cc7565b601f0160209004905f5260205f2090810190610cc69190610cca565b5b50565b5b80821115610ce1575f815f905550600101610ccb565b5090565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680610d6057607f821691505b602082108103610d7357610d72610d1c565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302610dd57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610d9a565b610ddf8683610d9a565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f610e23610e1e610e1984610df7565b610e00565b610df7565b9050919050565b5f819050919050565b610e3c83610e09565b610e50610e4882610e2a565b848454610da6565b825550505050565b5f90565b610e64610e58565b610e6f818484610e33565b505050565b5b81811015610e9257610e875f82610e5c565b600181019050610e75565b5050565b601f821115610ed757610ea881610d79565b610eb184610d8b565b81016020851015610ec0578190505b610ed4610ecc85610d8b565b830182610e74565b50505b505050565b5f82821c905092915050565b5f610ef75f1984600802610edc565b1980831691505092915050565b5f610f0f8383610ee8565b9150826002028217905092915050565b610f2882610ce5565b67ffffffffffffffff811115610f4157610f40610cef565b5b610f4b8254610d49565b610f56828285610e96565b5f60209050601f831160018114610f87575f8415610f75578287015190505b610f7f8582610f04565b865550610fe6565b601f198416610f9586610d79565b5f5b82811015610fbc57848901518255600182019150602085019450602081019050610f97565b86831015610fd95784890151610fd5601f891682610ee8565b8355505b6001600288020188555050505b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f8160011c9050919050565b5f808291508390505b60018511156110705780860481111561104c5761104b610fee565b5b600185161561105b5780820291505b80810290506110698561101b565b9450611030565b94509492505050565b5f826110885760019050611143565b81611095575f9050611143565b81600181146110ab57600281146110b5576110e4565b6001915050611143565b60ff8411156110c7576110c6610fee565b5b8360020a9150848211156110de576110dd610fee565b5b50611143565b5060208310610133831016604e8410600b84101617156111195782820a90508381111561111457611113610fee565b5b611143565b6111268484846001611027565b9250905081840481111561113d5761113c610fee565b5b81810290505b9392505050565b5f60ff82169050919050565b5f61116082610df7565b915061116b8361114a565b92506111987fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484611079565b905092915050565b5f6111aa82610df7565b91506111b583610df7565b92508282026111c381610df7565b915082820484148315176111da576111d9610fee565b5b5092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61120a826111e1565b9050919050565b61121a81611200565b82525050565b5f6020820190506112335f830184611211565b92915050565b5f61124382610df7565b915061124e83610df7565b925082820190508082111561126657611265610fee565b5b92915050565b61127581610df7565b82525050565b5f60608201905061128e5f830186611211565b61129b602083018561126c565b6112a8604083018461126c565b949350505050565b5f6020820190506112c35f83018461126c565b92915050565b6080516155a86112ef5f395f8181610246015281816123dc015261243201526155a85ff3fe60806040526004361061023e575f3560e01c8063750e8d101161012d578063af504def116100aa578063d5a426061161006e578063d5a4260614610a11578063dd0b281e14610a4e578063dd62ed3e14610a76578063dde415fa14610ab2578063f2fde38b14610adc5761030f565b8063af504def14610931578063b42781ee1461095b578063b42dfa0d14610983578063b4377a3e146109ad578063b4f243a4146109d55761030f565b80638fdada4a116100f15780638fdada4a1461082857806395d89b411461085257806398bafaa31461087c578063a9059cbb146108b9578063ad48f495146108f55761030f565b8063750e8d101461070d5780637673bfa41461074a57806377f23990146107865780637c3b3b87146107c25780638da5cb5b146107fe5761030f565b80633860a393116101bb578063544736e61161017f578063544736e6146106185780635e927ceb146106425780636a29f5e51461066a57806370a08231146106a757806370db69d6146106e35761030f565b80633860a393146104eb578063392475b7146105285780633fc0fdcb14610564578063422b9e23146105a057806353c55061146105dc5761030f565b806323b872dd1161020257806323b872dd146104095780632a4b02e6146104455780632d12d34b14610481578063313ce567146104ab578063333a0072146104d55761030f565b8063018a3741146103135780630568e65e1461033d57806306fdde0314610379578063095ea7b3146103a357806318160ddd146103df5761030f565b3661030f575f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163460405161028890613b0a565b5f6040518083038185875af1925050503d805f81146102c2576040519150601f19603f3d011682016040523d82523d5f602084013e6102c7565b606091505b5050809150508061030d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161030490613b78565b60405180910390fd5b005b5f80fd5b34801561031e575f80fd5b50610327610b04565b6040516103349190613bae565b60405180910390f35b348015610348575f80fd5b50610363600480360381019061035e9190613c32565b610b0a565b6040516103709190613bae565b60405180910390f35b348015610384575f80fd5b5061038d610b1f565b60405161039a9190613cbd565b60405180910390f35b3480156103ae575f80fd5b506103c960048036038101906103c49190613d07565b610baf565b6040516103d69190613d5f565b60405180910390f35b3480156103ea575f80fd5b506103f3610bd1565b6040516104009190613bae565b60405180910390f35b348015610414575f80fd5b5061042f600480360381019061042a9190613d78565b610bda565b60405161043c9190613d5f565b60405180910390f35b348015610450575f80fd5b5061046b60048036038101906104669190613dc8565b610c08565b6040516104789190613cbd565b60405180910390f35b34801561048c575f80fd5b50610495610cae565b6040516104a29190613bae565b60405180910390f35b3480156104b6575f80fd5b506104bf610cb3565b6040516104cc9190613e0e565b60405180910390f35b3480156104e0575f80fd5b506104e9610cbb565b005b3480156104f6575f80fd5b50610511600480360381019061050c9190613e27565b610db8565b60405161051f929190613f1c565b60405180910390f35b348015610533575f80fd5b5061054e60048036038101906105499190613dc8565b610f3a565b60405161055b9190613cbd565b60405180910390f35b34801561056f575f80fd5b5061058a60048036038101906105859190613d07565b610fe0565b604051610597919061403b565b60405180910390f35b3480156105ab575f80fd5b506105c660048036038101906105c1919061407d565b6110b6565b6040516105d39190613cbd565b60405180910390f35b3480156105e7575f80fd5b5061060260048036038101906105fd9190613dc8565b611142565b60405161060f9190613cbd565b60405180910390f35b348015610623575f80fd5b5061062c6111e8565b6040516106399190613d5f565b60405180910390f35b34801561064d575f80fd5b5061066860048036038101906106639190613dc8565b61123f565b005b348015610675575f80fd5b50610690600480360381019061068b9190613d07565b6112d8565b60405161069e9291906140a8565b60405180910390f35b3480156106b2575f80fd5b506106cd60048036038101906106c89190613c32565b611303565b6040516106da9190613bae565b60405180910390f35b3480156106ee575f80fd5b506106f7611348565b6040516107049190613bae565b60405180910390f35b348015610718575f80fd5b50610733600480360381019061072e91906140cf565b61144c565b604051610741929190614283565b60405180910390f35b348015610755575f80fd5b50610770600480360381019061076b9190613dc8565b611685565b60405161077d9190613cbd565b60405180910390f35b348015610791575f80fd5b506107ac60048036038101906107a79190613dc8565b61172b565b6040516107b99190613cbd565b60405180910390f35b3480156107cd575f80fd5b506107e860048036038101906107e3919061407d565b6117d1565b6040516107f5919061403b565b60405180910390f35b348015610809575f80fd5b506108126118a2565b60405161081f91906142c0565b60405180910390f35b348015610833575f80fd5b5061083c6118ca565b6040516108499190613bae565b60405180910390f35b34801561085d575f80fd5b506108666118d0565b6040516108739190613cbd565b60405180910390f35b348015610887575f80fd5b506108a2600480360381019061089d91906140cf565b611960565b6040516108b09291906143bd565b60405180910390f35b3480156108c4575f80fd5b506108df60048036038101906108da9190613d07565b611b3d565b6040516108ec9190613d5f565b60405180910390f35b348015610900575f80fd5b5061091b60048036038101906109169190613dc8565b611b5f565b6040516109289190613cbd565b60405180910390f35b34801561093c575f80fd5b50610945611c05565b6040516109529190613bae565b60405180910390f35b348015610966575f80fd5b50610981600480360381019061097c9190613dc8565b611c0b565b005b34801561098e575f80fd5b50610997611ca4565b6040516109a49190613bae565b60405180910390f35b3480156109b8575f80fd5b506109d360048036038101906109ce91906143eb565b611caa565b005b3480156109e0575f80fd5b506109fb60048036038101906109f69190613d07565b611d38565b604051610a089190613cbd565b60405180910390f35b348015610a1c575f80fd5b50610a376004803603810190610a3291906140cf565b611dc7565b604051610a459291906144e4565b60405180910390f35b348015610a59575f80fd5b50610a746004803603810190610a6f9190613c32565b612005565b005b348015610a81575f80fd5b50610a9c6004803603810190610a979190614512565b6120de565b604051610aa99190613bae565b60405180910390f35b348015610abd575f80fd5b50610ac6612160565b604051610ad39190613bae565b60405180910390f35b348015610ae7575f80fd5b50610b026004803603810190610afd9190613c32565b612166565b005b60135481565b6016602052805f5260405f205f915090505481565b606060038054610b2e9061457d565b80601f0160208091040260200160405190810160405280929190818152602001828054610b5a9061457d565b8015610ba55780601f10610b7c57610100808354040283529160200191610ba5565b820191905f5260205f20905b815481529060010190602001808311610b8857829003601f168201915b5050505050905090565b5f80610bb9612238565b9050610bc681858561223f565b600191505092915050565b5f600254905090565b5f80610be4612238565b9050610bf1858285612251565b610bfc8585856122e3565b60019150509392505050565b600a8181548110610c17575f80fd5b905f5260205f20015f915090508054610c2f9061457d565b80601f0160208091040260200160405190810160405280929190818152602001828054610c5b9061457d565b8015610ca65780601f10610c7d57610100808354040283529160200191610ca6565b820191905f5260205f20905b815481529060010190602001808311610c8957829003601f168201915b505050505081565b600181565b5f6009905090565b3373ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610d4a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d41906145f7565b60405180910390fd5b5f60055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f6e4ee811a17215345b89e3506064ff2d62f4feedff3566e9d09219cda7e8cadb60405160405180910390a1565b5f60606013548410610e17575f8067ffffffffffffffff811115610ddf57610dde614615565b5b604051908082528060200260200182016040528015610e0d5781602001602082028036833780820191505090505b5091509150610f33565b5f8385610e24919061466f565b9050601354811115610e365760135490505b8481610e4291906146a2565b92508267ffffffffffffffff811115610e5e57610e5d614615565b5b604051908082528060200260200182016040528015610e8c5781602001602082028036833780820191505090505b5091505f8590505b83811015610f305760115f8288610eab919061466f565b81526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16838281518110610eeb57610eea6146d5565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050806001019050610e94565b50505b9250929050565b60098181548110610f49575f80fd5b905f5260205f20015f915090508054610f619061457d565b80601f0160208091040260200160405190810160405280929190818152602001828054610f8d9061457d565b8015610fd85780601f10610faf57610100808354040283529160200191610fd8565b820191905f5260205f20905b815481529060010190602001808311610fbb57829003601f168201915b505050505081565b610fe8613a8f565b3073ffffffffffffffffffffffffffffffffffffffff16637c3b3b8760155f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f206040518263ffffffff1660e01b815260040161106c9190614774565b5f60405180830381865afa158015611086573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906110ae91906149cb565b905092915050565b606061113b3073ffffffffffffffffffffffffffffffffffffffff16637c3b3b87846040518263ffffffff1660e01b81526004016110f49190614a65565b5f60405180830381865afa15801561110e573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061113691906149cb565b612592565b9050919050565b60088181548110611151575f80fd5b905f5260205f20015f9150905080546111699061457d565b80601f01602080910402602001604051908101604052809291908181526020018280546111959061457d565b80156111e05780601f106111b7576101008083540402835291602001916111e0565b820191905f5260205f20905b8154815290600101906020018083116111c357829003601f168201915b505050505081565b5f8073ffffffffffffffffffffffffffffffffffffffff16600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415905090565b3373ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146112ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112c5906145f7565b60405180910390fd5b80600d8190555050565b6015602052815f5260405f20602052805f5260405f205f9150915050805f0154908060010154905082565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b5f6113516111e8565b611377576009600a6113639190614bad565b6103e86113709190614bf7565b9050611449565b5f6127106001600f544261138b91906146a2565b6009600a6113999190614bad565b6103e86113a69190614bf7565b6113b09190614bf7565b6113ba9190614bf7565b6113c49190614c65565b61271060056009600a6113d79190614bad565b6103e86113e49190614bf7565b6113ee9190614bf7565b6113f89190614c65565b611402919061466f565b90506009600a6114129190614bad565b6103e861141f9190614bf7565b811115611444576009600a6114349190614bad565b6103e86114419190614bf7565b90505b809150505b90565b5f60605f60165f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490508085106114f6575f8067ffffffffffffffff8111156114b2576114b1614615565b5b6040519080825280602002602001820160405280156114eb57816020015b6114d8613a8f565b8152602001906001900390816114d05790505b50925092505061167d565b5f8486611503919061466f565b905081811115611511578190505b858161151d91906146a2565b93508367ffffffffffffffff81111561153957611538614615565b5b60405190808252806020026020018201604052801561157257816020015b61155f613a8f565b8152602001906001900390816115575790505b5092505f5b84811015611679573073ffffffffffffffffffffffffffffffffffffffff16637c3b3b8760155f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f848b6115e5919061466f565b81526020019081526020015f206040518263ffffffff1660e01b815260040161160e9190614774565b5f60405180830381865afa158015611628573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061165091906149cb565b848281518110611663576116626146d5565b5b6020026020010181905250806001019050611577565b5050505b935093915050565b600b8181548110611694575f80fd5b905f5260205f20015f9150905080546116ac9061457d565b80601f01602080910402602001604051908101604052809291908181526020018280546116d89061457d565b80156117235780601f106116fa57610100808354040283529160200191611723565b820191905f5260205f20905b81548152906001019060200180831161170657829003601f168201915b505050505081565b6007818154811061173a575f80fd5b905f5260205f20015f9150905080546117529061457d565b80601f016020809104026020016040519081016040528092919081815260200182805461177e9061457d565b80156117c95780601f106117a0576101008083540402835291602001916117c9565b820191905f5260205f20905b8154815290600101906020018083116117ac57829003601f168201915b505050505081565b6117d9613a8f565b5f6040518060400160405280848036038101906117f69190614ce2565b81526020015f81525090506040518060c0016040528061181f600661181a856125e8565b61263e565b81526020016118376007611832856125e8565b61263e565b815260200161184f600861184a856125e8565b61263e565b81526020016118676009611862856125e8565b61263e565b815260200161187f600a61187a856125e8565b61263e565b8152602001611897600b611892856125e8565b61263e565b815250915050919050565b5f60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6103e881565b6060600480546118df9061457d565b80601f016020809104026020016040519081016040528092919081815260200182805461190b9061457d565b80156119565780601f1061192d57610100808354040283529160200191611956565b820191905f5260205f20905b81548152906001019060200180831161193957829003601f168201915b5050505050905090565b5f60605f60165f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050808510611a0a575f8067ffffffffffffffff8111156119c6576119c5614615565b5b6040519080825280602002602001820160405280156119ff57816020015b6119ec613ac5565b8152602001906001900390816119e45790505b509250925050611b35565b5f8486611a17919061466f565b905081811115611a25578190505b8581611a3191906146a2565b93508367ffffffffffffffff811115611a4d57611a4c614615565b5b604051908082528060200260200182016040528015611a8657816020015b611a73613ac5565b815260200190600190039081611a6b5790505b5092505f5b84811015611b315760155f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8289611add919061466f565b81526020019081526020015f206040518060400160405290815f8201548152602001600182015481525050848281518110611b1b57611b1a6146d5565b5b6020026020010181905250806001019050611a8b565b5050505b935093915050565b5f80611b47612238565b9050611b548185856122e3565b600191505092915050565b60068181548110611b6e575f80fd5b905f5260205f20015f915090508054611b869061457d565b80601f0160208091040260200160405190810160405280929190818152602001828054611bb29061457d565b8015611bfd5780601f10611bd457610100808354040283529160200191611bfd565b820191905f5260205f20905b815481529060010190602001808311611be057829003601f168201915b505050505081565b60175481565b3373ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611c9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c91906145f7565b60405180910390fd5b80600c8190555050565b60145481565b60165f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20548210611d29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d2090614d57565b60405180910390fd5b611d343383836126fe565b5050565b6060611dbf3073ffffffffffffffffffffffffffffffffffffffff16633fc0fdcb85856040518363ffffffff1660e01b8152600401611d78929190614d75565b5f60405180830381865afa158015611d92573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611dba91906149cb565b612592565b905092915050565b5f60605f60165f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050808510611e6b575f8067ffffffffffffffff811115611e2d57611e2c614615565b5b604051908082528060200260200182016040528015611e6057816020015b6060815260200190600190039081611e4b5790505b509250925050611ffd565b5f8486611e78919061466f565b905081811115611e94578190508086611e9191906146a2565b93505b8367ffffffffffffffff811115611eae57611ead614615565b5b604051908082528060200260200182016040528015611ee157816020015b6060815260200190600190039081611ecc5790505b5092505f805f90508791505b82821015611ff857611fc33073ffffffffffffffffffffffffffffffffffffffff16637c3b3b8760155f8d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f206040518263ffffffff1660e01b8152600401611f7c9190614774565b5f60405180830381865afa158015611f96573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611fbe91906149cb565b612592565b858280611fcf90614d9c565b935081518110611fe257611fe16146d5565b5b6020026020010181905250816001019150611eed565b505050505b935093915050565b3373ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612094576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161208b906145f7565b60405180910390fd5b80600e5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555042600f8190555050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b6103e881565b3373ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146121f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121ec906145f7565b60405180910390fd5b8060055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b5f33905090565b61224c838383600161279d565b505050565b5f61225c84846120de565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146122dd57818110156122ce578281836040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526004016122c593929190614de3565b60405180910390fd5b6122dc84848484035f61279d565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16148061234a575061dead73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b1561235f5761235a83838361296c565b61258d565b6123676111e8565b15801561248157505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614806123d457503073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b8061242a57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b8061248057507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b5b1561249657612491838383612c66565b61258d565b600e60149054906101000a900460ff16156124bb576124b6838383612c66565b61258d565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361251e576125198282612d56565b61258d565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036125815761257c8382612e33565b61258d565b61258c83838361296c565b5b505050565b60608160a00151825f01518360800151846080015185602001518660200151876040015188606001516040516020016125d2989796959493929190615320565b6040516020818303038152906040529050919050565b5f815f01515f0151825f01516020015183602001805180919061260a90614d9c565b81525060405160200161261f93929190615477565b604051602081830303815290604052805190602001205f1c9050919050565b60605f83805490508361265191906154b3565b9050838181548110612666576126656146d5565b5b905f5260205f200180546126799061457d565b80601f01602080910402602001604051908101604052809291908181526020018280546126a59061457d565b80156126f05780601f106126c7576101008083540402835291602001916126f0565b820191905f5260205f20905b8154815290600101906020018083116126d357829003601f168201915b505050505091505092915050565b5f60155f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8481526020019081526020015f206040518060400160405290815f8201548152602001600182015481525050905061278384836009600a61277e9190614bad565b612fad565b61278d848461306e565b61279782826132b2565b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361280d575f6040517fe602df0500000000000000000000000000000000000000000000000000000000815260040161280491906142c0565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361287d575f6040517f94280d6200000000000000000000000000000000000000000000000000000000815260040161287491906142c0565b60405180910390fd5b8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508015612966578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161295d9190613bae565b60405180910390a35b50505050565b612974613431565b5f61297e84611303565b90505f828261298d91906146a2565b90505f61299985611303565b90505f84826129a8919061466f565b90505f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161480612a11575061dead73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16145b15612a1d575f91505f90505b5f612a26610cb3565b600a612a329190614bad565b84612a3d9190614c65565b612a45610cb3565b600a612a519190614bad565b86612a5c9190614c65565b612a6691906146a2565b90505f612a71610cb3565b600a612a7d9190614bad565b84612a889190614c65565b612a90610cb3565b600a612a9c9190614bad565b84612aa79190614c65565b612ab191906146a2565b90505f82905081811115612ac3578190505b5f8060165f8d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f91505b82821015612bb7575f810315612bb7575f81612b24906154e3565b91508190505f60155f8f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f206040518060400160405290815f82015481526020016001820154815250509050612ba08e8361306e565b612baa8d826132b2565b5050816001019150612b09565b5f8290508392505b85831015612bed575f82612bd2906154e3565b9250829050612be18e8261306e565b50826001019250612bbf565b8092505b84831015612c44575f604051806040016040528060185f8154612c1390614d9c565b9190508190558152602001612c296103e8613477565b8152509050612c388d826132b2565b50826001019250612bf1565b612c4f8d8d8d612fad565b50505050505050505050612c616134ca565b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612cd6575f6040517f96c6fd1e000000000000000000000000000000000000000000000000000000008152600401612ccd91906142c0565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612d46575f6040517fec442f05000000000000000000000000000000000000000000000000000000008152600401612d3d91906142c0565b60405180910390fd5b612d518383836134d4565b505050565b612d5e613431565b5f612d6883611303565b90505f8282612d77919061466f565b90505f612d82610cb3565b600a612d8e9190614bad565b83612d999190614c65565b612da1610cb3565b600a612dad9190614bad565b83612db89190614c65565b612dc291906146a2565b90505f5b81811015612e19575f604051806040016040528060185f8154612de890614d9c565b9190508190558152602001612dfe6103e8613477565b8152509050612e0d87826132b2565b50806001019050612dc6565b612e2386866136ed565b50505050612e2f6134ca565b5050565b6001600e60146101000a81548160ff021916908315150217905550612e56613431565b5f612e6083611303565b90505f8282612e6f91906146a2565b90505f612e7a610cb3565b600a612e869190614bad565b82612e919190614c65565b612e99610cb3565b600a612ea59190614bad565b84612eb09190614c65565b612eba91906146a2565b90505f8060165f8873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f91505b82821015612f56576103e86014541015612f2c5760145f8154612f2490614d9c565b919050819055505b5f811115612f4b57612f4a8782612f42906154e3565b92508261306e565b5b816001019150612f02565b612f8287600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16886122e3565b5050505050612f8f6134ca565b5f600e60146101000a81548160ff0219169083151502179055505050565b6001600e60146101000a81548160ff0219169083151502179055505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16148061302f575061dead73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b156130435761303e838261379e565b61304f565b61304e838383612c66565b5b5f600e60146101000a81548160ff021916908315150217905550505050565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603156132ae575f60165f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f815461310d906154e3565b91905081905503613122576131218261381d565b5b60175f8154613130906154e3565b919050819055505f60165f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050808214613250575f60155f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f206040518060400160405290815f820154815260200160018201548152505090508060155f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f820151815f015560208201518160010155905050505b60155f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8281526020019081526020015f205f8082015f9055600182015f90555050505b5050565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16031561342d57600160165f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f815461335290614d9c565b9190508190550361336757613366826139e1565b5b60175f815461337590614d9c565b919050819055505f600160165f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20546133c791906146a2565b90508160155f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f205f820151815f015560208201518160010155905050505b5050565b60026010540361346d576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002601081905550565b5f6103e8601454836134899190614bf7565b6134939190614c65565b91505f82036134a157600191505b600160145411156134c25760145f81546134ba906154e3565b919050819055505b819050919050565b6001601081905550565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603613524578060025f828254613518919061466f565b925050819055506135f2565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050818110156135ad578381836040517fe450d38c0000000000000000000000000000000000000000000000000000000081526004016135a493929190614de3565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603613639578060025f8282540392505081905550613683565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516136e09190613bae565b60405180910390a3505050565b806136f6611348565b811115613738576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161372f90615554565b60405180910390fd5b6001600e60146101000a81548160ff02191690831515021790555061377f600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff168484612c66565b5f600e60146101000a81548160ff021916908315150217905550505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361380e575f6040517f96c6fd1e00000000000000000000000000000000000000000000000000000000815260040161380591906142c0565b60405180910390fd5b613819825f836134d4565b5050565b5f60135403156139de575f60125f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050600160135461387791906146a2565b8114613952575f60115f600160135461389091906146a2565b81526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508060115f8481526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160125f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b60135f8154613960906154e3565b9190508190555060125f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f905560115f60135481526020019081526020015f205f6101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055505b50565b5f60135f8154809291906139f490614d9c565b9190505590508160115f8381526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060125f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055505050565b6040518060c001604052806060815260200160608152602001606081526020016060815260200160608152602001606081525090565b60405180604001604052805f81526020015f81525090565b5f81905092915050565b50565b5f613af55f83613add565b9150613b0082613ae7565b5f82019050919050565b5f613b1482613aea565b9150819050919050565b5f82825260208201905092915050565b7f63616e206e6f74206765742065746865720000000000000000000000000000005f82015250565b5f613b62601183613b1e565b9150613b6d82613b2e565b602082019050919050565b5f6020820190508181035f830152613b8f81613b56565b9050919050565b5f819050919050565b613ba881613b96565b82525050565b5f602082019050613bc15f830184613b9f565b92915050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613c0182613bd8565b9050919050565b613c1181613bf7565b8114613c1b575f80fd5b50565b5f81359050613c2c81613c08565b92915050565b5f60208284031215613c4757613c46613bd0565b5b5f613c5484828501613c1e565b91505092915050565b5f81519050919050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f613c8f82613c5d565b613c998185613b1e565b9350613ca9818560208601613c67565b613cb281613c75565b840191505092915050565b5f6020820190508181035f830152613cd58184613c85565b905092915050565b613ce681613b96565b8114613cf0575f80fd5b50565b5f81359050613d0181613cdd565b92915050565b5f8060408385031215613d1d57613d1c613bd0565b5b5f613d2a85828601613c1e565b9250506020613d3b85828601613cf3565b9150509250929050565b5f8115159050919050565b613d5981613d45565b82525050565b5f602082019050613d725f830184613d50565b92915050565b5f805f60608486031215613d8f57613d8e613bd0565b5b5f613d9c86828701613c1e565b9350506020613dad86828701613c1e565b9250506040613dbe86828701613cf3565b9150509250925092565b5f60208284031215613ddd57613ddc613bd0565b5b5f613dea84828501613cf3565b91505092915050565b5f60ff82169050919050565b613e0881613df3565b82525050565b5f602082019050613e215f830184613dff565b92915050565b5f8060408385031215613e3d57613e3c613bd0565b5b5f613e4a85828601613cf3565b9250506020613e5b85828601613cf3565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b613e9781613bf7565b82525050565b5f613ea88383613e8e565b60208301905092915050565b5f602082019050919050565b5f613eca82613e65565b613ed48185613e6f565b9350613edf83613e7f565b805f5b83811015613f0f578151613ef68882613e9d565b9750613f0183613eb4565b925050600181019050613ee2565b5085935050505092915050565b5f604082019050613f2f5f830185613b9f565b8181036020830152613f418184613ec0565b90509392505050565b5f82825260208201905092915050565b5f613f6482613c5d565b613f6e8185613f4a565b9350613f7e818560208601613c67565b613f8781613c75565b840191505092915050565b5f60c083015f8301518482035f860152613fac8282613f5a565b91505060208301518482036020860152613fc68282613f5a565b91505060408301518482036040860152613fe08282613f5a565b91505060608301518482036060860152613ffa8282613f5a565b915050608083015184820360808601526140148282613f5a565b91505060a083015184820360a086015261402e8282613f5a565b9150508091505092915050565b5f6020820190508181035f8301526140538184613f92565b905092915050565b5f80fd5b5f604082840312156140745761407361405b565b5b81905092915050565b5f6040828403121561409257614091613bd0565b5b5f61409f8482850161405f565b91505092915050565b5f6040820190506140bb5f830185613b9f565b6140c86020830184613b9f565b9392505050565b5f805f606084860312156140e6576140e5613bd0565b5b5f6140f386828701613c1e565b935050602061410486828701613cf3565b925050604061411586828701613cf3565b9150509250925092565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f60c083015f8301518482035f8601526141628282613f5a565b9150506020830151848203602086015261417c8282613f5a565b915050604083015184820360408601526141968282613f5a565b915050606083015184820360608601526141b08282613f5a565b915050608083015184820360808601526141ca8282613f5a565b91505060a083015184820360a08601526141e48282613f5a565b9150508091505092915050565b5f6141fc8383614148565b905092915050565b5f602082019050919050565b5f61421a8261411f565b6142248185614129565b93508360208202850161423685614139565b805f5b85811015614271578484038952815161425285826141f1565b945061425d83614204565b925060208a01995050600181019050614239565b50829750879550505050505092915050565b5f6040820190506142965f830185613b9f565b81810360208301526142a88184614210565b90509392505050565b6142ba81613bf7565b82525050565b5f6020820190506142d35f8301846142b1565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61430b81613b96565b82525050565b604082015f8201516143255f850182614302565b5060208201516143386020850182614302565b50505050565b5f6143498383614311565b60408301905092915050565b5f602082019050919050565b5f61436b826142d9565b61437581856142e3565b9350614380836142f3565b805f5b838110156143b0578151614397888261433e565b97506143a283614355565b925050600181019050614383565b5085935050505092915050565b5f6040820190506143d05f830185613b9f565b81810360208301526143e28184614361565b90509392505050565b5f806040838503121561440157614400613bd0565b5b5f61440e85828601613cf3565b925050602061441f85828601613c1e565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f61445d8383613f5a565b905092915050565b5f602082019050919050565b5f61447b82614429565b6144858185614433565b93508360208202850161449785614443565b805f5b858110156144d257848403895281516144b38582614452565b94506144be83614465565b925060208a0199505060018101905061449a565b50829750879550505050505092915050565b5f6040820190506144f75f830185613b9f565b81810360208301526145098184614471565b90509392505050565b5f806040838503121561452857614527613bd0565b5b5f61453585828601613c1e565b925050602061454685828601613c1e565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061459457607f821691505b6020821081036145a7576145a6614550565b5b50919050565b7f6f6e6c79206f776e6572000000000000000000000000000000000000000000005f82015250565b5f6145e1600a83613b1e565b91506145ec826145ad565b602082019050919050565b5f6020820190508181035f83015261460e816145d5565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61467982613b96565b915061468483613b96565b925082820190508082111561469c5761469b614642565b5b92915050565b5f6146ac82613b96565b91506146b783613b96565b92508282039050818111156146cf576146ce614642565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f815f1c9050919050565b5f819050919050565b5f61472861472383614702565b61470d565b9050919050565b604082015f80830154905061474381614716565b61474f5f860182614302565b506001830154905061476081614716565b61476d6020860182614302565b5050505050565b5f6040820190506147875f83018461472f565b92915050565b5f80fd5b61479a82613c75565b810181811067ffffffffffffffff821117156147b9576147b8614615565b5b80604052505050565b5f6147cb613bc7565b90506147d78282614791565b919050565b5f80fd5b5f80fd5b5f80fd5b5f67ffffffffffffffff82111561480257614801614615565b5b61480b82613c75565b9050602081019050919050565b5f61482a614825846147e8565b6147c2565b905082815260208101848484011115614846576148456147e4565b5b614851848285613c67565b509392505050565b5f82601f83011261486d5761486c6147e0565b5b815161487d848260208601614818565b91505092915050565b5f60c0828403121561489b5761489a61478d565b5b6148a560c06147c2565b90505f82015167ffffffffffffffff8111156148c4576148c36147dc565b5b6148d084828501614859565b5f83015250602082015167ffffffffffffffff8111156148f3576148f26147dc565b5b6148ff84828501614859565b602083015250604082015167ffffffffffffffff811115614923576149226147dc565b5b61492f84828501614859565b604083015250606082015167ffffffffffffffff811115614953576149526147dc565b5b61495f84828501614859565b606083015250608082015167ffffffffffffffff811115614983576149826147dc565b5b61498f84828501614859565b60808301525060a082015167ffffffffffffffff8111156149b3576149b26147dc565b5b6149bf84828501614859565b60a08301525092915050565b5f602082840312156149e0576149df613bd0565b5b5f82015167ffffffffffffffff8111156149fd576149fc613bd4565b5b614a0984828501614886565b91505092915050565b5f614a206020840184613cf3565b905092915050565b60408201614a385f830183614a12565b614a445f850182614302565b50614a526020830183614a12565b614a5f6020850182614302565b50505050565b5f604082019050614a785f830184614a28565b92915050565b5f8160011c9050919050565b5f808291508390505b6001851115614ad357808604811115614aaf57614aae614642565b5b6001851615614abe5780820291505b8081029050614acc85614a7e565b9450614a93565b94509492505050565b5f82614aeb5760019050614ba6565b81614af8575f9050614ba6565b8160018114614b0e5760028114614b1857614b47565b6001915050614ba6565b60ff841115614b2a57614b29614642565b5b8360020a915084821115614b4157614b40614642565b5b50614ba6565b5060208310610133831016604e8410600b8410161715614b7c5782820a905083811115614b7757614b76614642565b5b614ba6565b614b898484846001614a8a565b92509050818404811115614ba057614b9f614642565b5b81810290505b9392505050565b5f614bb782613b96565b9150614bc283613df3565b9250614bef7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484614adc565b905092915050565b5f614c0182613b96565b9150614c0c83613b96565b9250828202614c1a81613b96565b91508282048414831517614c3157614c30614642565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f614c6f82613b96565b9150614c7a83613b96565b925082614c8a57614c89614c38565b5b828204905092915050565b5f60408284031215614caa57614ca961478d565b5b614cb460406147c2565b90505f614cc384828501613cf3565b5f830152506020614cd684828501613cf3565b60208301525092915050565b5f60408284031215614cf757614cf6613bd0565b5b5f614d0484828501614c95565b91505092915050565b7f696e636f727265637420696e64657800000000000000000000000000000000005f82015250565b5f614d41600f83613b1e565b9150614d4c82614d0d565b602082019050919050565b5f6020820190508181035f830152614d6e81614d35565b9050919050565b5f604082019050614d885f8301856142b1565b614d956020830184613b9f565b9392505050565b5f614da682613b96565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614dd857614dd7614642565b5b600182019050919050565b5f606082019050614df65f8301866142b1565b614e036020830185613b9f565b614e106040830184613b9f565b949350505050565b5f81905092915050565b7f3c73766720786d6c6e733d27687474703a2f2f7777772e77332e6f72672f32305f8201527f30302f737667272076696577426f783d273020302031303020313030273e0000602082015250565b5f614e7c603e83614e18565b9150614e8782614e22565b603e82019050919050565b7f3c726563742077696474683d2731303027206865696768743d273130302720665f8201527f696c6c3d27000000000000000000000000000000000000000000000000000000602082015250565b5f614eec602583614e18565b9150614ef782614e92565b602582019050919050565b5f614f0c82613c5d565b614f168185614e18565b9350614f26818560208601613c67565b80840191505092915050565b7f272f3e00000000000000000000000000000000000000000000000000000000005f82015250565b5f614f66600383614e18565b9150614f7182614f32565b600382019050919050565b7f3c706f6c79676f6e20706f696e74733d2735302c32302037302c33352037302c5f8201527f36352035302c38302033302c36352033302c3335272066696c6c3d2700000000602082015250565b5f614fd6603c83614e18565b9150614fe182614f7c565b603c82019050919050565b7f27202f3e000000000000000000000000000000000000000000000000000000005f82015250565b5f615020600483614e18565b915061502b82614fec565b600482019050919050565b7f3c7265637420783d2732352720793d273330272077696474683d2731302720685f8201527f65696768743d273130272066696c6c3d27000000000000000000000000000000602082015250565b5f615090603183614e18565b915061509b82615036565b603182019050919050565b7f3c7265637420783d2736352720793d273330272077696474683d2731302720685f8201527f65696768743d273130272066696c6c3d27000000000000000000000000000000602082015250565b5f615100603183614e18565b915061510b826150a6565b603182019050919050565b7f3c636972636c652063783d273430272063793d2735302720723d2735272066695f8201527f6c6c3d2700000000000000000000000000000000000000000000000000000000602082015250565b5f615170602483614e18565b915061517b82615116565b602482019050919050565b7f3c636972636c652063783d273630272063793d2735302720723d2735272066695f8201527f6c6c3d2700000000000000000000000000000000000000000000000000000000602082015250565b5f6151e0602483614e18565b91506151eb82615186565b602482019050919050565b7f3c636972636c652063783d273530272063793d2736302720723d2735272066695f8201527f6c6c3d2700000000000000000000000000000000000000000000000000000000602082015250565b5f615250602483614e18565b915061525b826151f6565b602482019050919050565b7f3c656c6c697073652063783d273530272063793d273730272072783d273130275f8201527f2072793d2735272066696c6c3d27000000000000000000000000000000000000602082015250565b5f6152c0602e83614e18565b91506152cb82615266565b602e82019050919050565b7f3c2f7376673e00000000000000000000000000000000000000000000000000005f82015250565b5f61530a600683614e18565b9150615315826152d6565b600682019050919050565b5f61532a82614e70565b915061533582614ee0565b9150615341828b614f02565b915061534c82614f5a565b915061535782614fca565b9150615363828a614f02565b915061536e82615014565b915061537982615084565b91506153858289614f02565b915061539082615014565b915061539b826150f4565b91506153a78288614f02565b91506153b282615014565b91506153bd82615164565b91506153c98287614f02565b91506153d482615014565b91506153df826151d4565b91506153eb8286614f02565b91506153f682615014565b915061540182615244565b915061540d8285614f02565b915061541882615014565b9150615423826152b4565b915061542f8284614f02565b915061543a82615014565b9150615445826152fe565b91508190509998505050505050505050565b5f819050919050565b61547161546c82613b96565b615457565b82525050565b5f6154828286615460565b6020820191506154928285615460565b6020820191506154a28284615460565b602082019150819050949350505050565b5f6154bd82613b96565b91506154c883613b96565b9250826154d8576154d7614c38565b5b828206905092915050565b5f6154ed82613b96565b91505f82036154ff576154fe614642565b5b600182039050919050565b7f6d617820627579000000000000000000000000000000000000000000000000005f82015250565b5f61553e600783613b1e565b91506155498261550a565b602082019050919050565b5f6020820190508181035f83015261556b81615532565b905091905056fea264697066735822122035bed1a76b6a273fecbd6e3ff537f49cc705d6aa29662033b4f4c3ba49baa46564736f6c63430008190033

Deployed Bytecode

0x60806040526004361061023e575f3560e01c8063750e8d101161012d578063af504def116100aa578063d5a426061161006e578063d5a4260614610a11578063dd0b281e14610a4e578063dd62ed3e14610a76578063dde415fa14610ab2578063f2fde38b14610adc5761030f565b8063af504def14610931578063b42781ee1461095b578063b42dfa0d14610983578063b4377a3e146109ad578063b4f243a4146109d55761030f565b80638fdada4a116100f15780638fdada4a1461082857806395d89b411461085257806398bafaa31461087c578063a9059cbb146108b9578063ad48f495146108f55761030f565b8063750e8d101461070d5780637673bfa41461074a57806377f23990146107865780637c3b3b87146107c25780638da5cb5b146107fe5761030f565b80633860a393116101bb578063544736e61161017f578063544736e6146106185780635e927ceb146106425780636a29f5e51461066a57806370a08231146106a757806370db69d6146106e35761030f565b80633860a393146104eb578063392475b7146105285780633fc0fdcb14610564578063422b9e23146105a057806353c55061146105dc5761030f565b806323b872dd1161020257806323b872dd146104095780632a4b02e6146104455780632d12d34b14610481578063313ce567146104ab578063333a0072146104d55761030f565b8063018a3741146103135780630568e65e1461033d57806306fdde0314610379578063095ea7b3146103a357806318160ddd146103df5761030f565b3661030f575f7f000000000000000000000000498d0590999ab4718292902df368a417fc15f96173ffffffffffffffffffffffffffffffffffffffff163460405161028890613b0a565b5f6040518083038185875af1925050503d805f81146102c2576040519150601f19603f3d011682016040523d82523d5f602084013e6102c7565b606091505b5050809150508061030d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161030490613b78565b60405180910390fd5b005b5f80fd5b34801561031e575f80fd5b50610327610b04565b6040516103349190613bae565b60405180910390f35b348015610348575f80fd5b50610363600480360381019061035e9190613c32565b610b0a565b6040516103709190613bae565b60405180910390f35b348015610384575f80fd5b5061038d610b1f565b60405161039a9190613cbd565b60405180910390f35b3480156103ae575f80fd5b506103c960048036038101906103c49190613d07565b610baf565b6040516103d69190613d5f565b60405180910390f35b3480156103ea575f80fd5b506103f3610bd1565b6040516104009190613bae565b60405180910390f35b348015610414575f80fd5b5061042f600480360381019061042a9190613d78565b610bda565b60405161043c9190613d5f565b60405180910390f35b348015610450575f80fd5b5061046b60048036038101906104669190613dc8565b610c08565b6040516104789190613cbd565b60405180910390f35b34801561048c575f80fd5b50610495610cae565b6040516104a29190613bae565b60405180910390f35b3480156104b6575f80fd5b506104bf610cb3565b6040516104cc9190613e0e565b60405180910390f35b3480156104e0575f80fd5b506104e9610cbb565b005b3480156104f6575f80fd5b50610511600480360381019061050c9190613e27565b610db8565b60405161051f929190613f1c565b60405180910390f35b348015610533575f80fd5b5061054e60048036038101906105499190613dc8565b610f3a565b60405161055b9190613cbd565b60405180910390f35b34801561056f575f80fd5b5061058a60048036038101906105859190613d07565b610fe0565b604051610597919061403b565b60405180910390f35b3480156105ab575f80fd5b506105c660048036038101906105c1919061407d565b6110b6565b6040516105d39190613cbd565b60405180910390f35b3480156105e7575f80fd5b5061060260048036038101906105fd9190613dc8565b611142565b60405161060f9190613cbd565b60405180910390f35b348015610623575f80fd5b5061062c6111e8565b6040516106399190613d5f565b60405180910390f35b34801561064d575f80fd5b5061066860048036038101906106639190613dc8565b61123f565b005b348015610675575f80fd5b50610690600480360381019061068b9190613d07565b6112d8565b60405161069e9291906140a8565b60405180910390f35b3480156106b2575f80fd5b506106cd60048036038101906106c89190613c32565b611303565b6040516106da9190613bae565b60405180910390f35b3480156106ee575f80fd5b506106f7611348565b6040516107049190613bae565b60405180910390f35b348015610718575f80fd5b50610733600480360381019061072e91906140cf565b61144c565b604051610741929190614283565b60405180910390f35b348015610755575f80fd5b50610770600480360381019061076b9190613dc8565b611685565b60405161077d9190613cbd565b60405180910390f35b348015610791575f80fd5b506107ac60048036038101906107a79190613dc8565b61172b565b6040516107b99190613cbd565b60405180910390f35b3480156107cd575f80fd5b506107e860048036038101906107e3919061407d565b6117d1565b6040516107f5919061403b565b60405180910390f35b348015610809575f80fd5b506108126118a2565b60405161081f91906142c0565b60405180910390f35b348015610833575f80fd5b5061083c6118ca565b6040516108499190613bae565b60405180910390f35b34801561085d575f80fd5b506108666118d0565b6040516108739190613cbd565b60405180910390f35b348015610887575f80fd5b506108a2600480360381019061089d91906140cf565b611960565b6040516108b09291906143bd565b60405180910390f35b3480156108c4575f80fd5b506108df60048036038101906108da9190613d07565b611b3d565b6040516108ec9190613d5f565b60405180910390f35b348015610900575f80fd5b5061091b60048036038101906109169190613dc8565b611b5f565b6040516109289190613cbd565b60405180910390f35b34801561093c575f80fd5b50610945611c05565b6040516109529190613bae565b60405180910390f35b348015610966575f80fd5b50610981600480360381019061097c9190613dc8565b611c0b565b005b34801561098e575f80fd5b50610997611ca4565b6040516109a49190613bae565b60405180910390f35b3480156109b8575f80fd5b506109d360048036038101906109ce91906143eb565b611caa565b005b3480156109e0575f80fd5b506109fb60048036038101906109f69190613d07565b611d38565b604051610a089190613cbd565b60405180910390f35b348015610a1c575f80fd5b50610a376004803603810190610a3291906140cf565b611dc7565b604051610a459291906144e4565b60405180910390f35b348015610a59575f80fd5b50610a746004803603810190610a6f9190613c32565b612005565b005b348015610a81575f80fd5b50610a9c6004803603810190610a979190614512565b6120de565b604051610aa99190613bae565b60405180910390f35b348015610abd575f80fd5b50610ac6612160565b604051610ad39190613bae565b60405180910390f35b348015610ae7575f80fd5b50610b026004803603810190610afd9190613c32565b612166565b005b60135481565b6016602052805f5260405f205f915090505481565b606060038054610b2e9061457d565b80601f0160208091040260200160405190810160405280929190818152602001828054610b5a9061457d565b8015610ba55780601f10610b7c57610100808354040283529160200191610ba5565b820191905f5260205f20905b815481529060010190602001808311610b8857829003601f168201915b5050505050905090565b5f80610bb9612238565b9050610bc681858561223f565b600191505092915050565b5f600254905090565b5f80610be4612238565b9050610bf1858285612251565b610bfc8585856122e3565b60019150509392505050565b600a8181548110610c17575f80fd5b905f5260205f20015f915090508054610c2f9061457d565b80601f0160208091040260200160405190810160405280929190818152602001828054610c5b9061457d565b8015610ca65780601f10610c7d57610100808354040283529160200191610ca6565b820191905f5260205f20905b815481529060010190602001808311610c8957829003601f168201915b505050505081565b600181565b5f6009905090565b3373ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610d4a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d41906145f7565b60405180910390fd5b5f60055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f6e4ee811a17215345b89e3506064ff2d62f4feedff3566e9d09219cda7e8cadb60405160405180910390a1565b5f60606013548410610e17575f8067ffffffffffffffff811115610ddf57610dde614615565b5b604051908082528060200260200182016040528015610e0d5781602001602082028036833780820191505090505b5091509150610f33565b5f8385610e24919061466f565b9050601354811115610e365760135490505b8481610e4291906146a2565b92508267ffffffffffffffff811115610e5e57610e5d614615565b5b604051908082528060200260200182016040528015610e8c5781602001602082028036833780820191505090505b5091505f8590505b83811015610f305760115f8288610eab919061466f565b81526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16838281518110610eeb57610eea6146d5565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050806001019050610e94565b50505b9250929050565b60098181548110610f49575f80fd5b905f5260205f20015f915090508054610f619061457d565b80601f0160208091040260200160405190810160405280929190818152602001828054610f8d9061457d565b8015610fd85780601f10610faf57610100808354040283529160200191610fd8565b820191905f5260205f20905b815481529060010190602001808311610fbb57829003601f168201915b505050505081565b610fe8613a8f565b3073ffffffffffffffffffffffffffffffffffffffff16637c3b3b8760155f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f206040518263ffffffff1660e01b815260040161106c9190614774565b5f60405180830381865afa158015611086573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906110ae91906149cb565b905092915050565b606061113b3073ffffffffffffffffffffffffffffffffffffffff16637c3b3b87846040518263ffffffff1660e01b81526004016110f49190614a65565b5f60405180830381865afa15801561110e573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061113691906149cb565b612592565b9050919050565b60088181548110611151575f80fd5b905f5260205f20015f9150905080546111699061457d565b80601f01602080910402602001604051908101604052809291908181526020018280546111959061457d565b80156111e05780601f106111b7576101008083540402835291602001916111e0565b820191905f5260205f20905b8154815290600101906020018083116111c357829003601f168201915b505050505081565b5f8073ffffffffffffffffffffffffffffffffffffffff16600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415905090565b3373ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146112ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112c5906145f7565b60405180910390fd5b80600d8190555050565b6015602052815f5260405f20602052805f5260405f205f9150915050805f0154908060010154905082565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b5f6113516111e8565b611377576009600a6113639190614bad565b6103e86113709190614bf7565b9050611449565b5f6127106001600f544261138b91906146a2565b6009600a6113999190614bad565b6103e86113a69190614bf7565b6113b09190614bf7565b6113ba9190614bf7565b6113c49190614c65565b61271060056009600a6113d79190614bad565b6103e86113e49190614bf7565b6113ee9190614bf7565b6113f89190614c65565b611402919061466f565b90506009600a6114129190614bad565b6103e861141f9190614bf7565b811115611444576009600a6114349190614bad565b6103e86114419190614bf7565b90505b809150505b90565b5f60605f60165f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490508085106114f6575f8067ffffffffffffffff8111156114b2576114b1614615565b5b6040519080825280602002602001820160405280156114eb57816020015b6114d8613a8f565b8152602001906001900390816114d05790505b50925092505061167d565b5f8486611503919061466f565b905081811115611511578190505b858161151d91906146a2565b93508367ffffffffffffffff81111561153957611538614615565b5b60405190808252806020026020018201604052801561157257816020015b61155f613a8f565b8152602001906001900390816115575790505b5092505f5b84811015611679573073ffffffffffffffffffffffffffffffffffffffff16637c3b3b8760155f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f848b6115e5919061466f565b81526020019081526020015f206040518263ffffffff1660e01b815260040161160e9190614774565b5f60405180830381865afa158015611628573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061165091906149cb565b848281518110611663576116626146d5565b5b6020026020010181905250806001019050611577565b5050505b935093915050565b600b8181548110611694575f80fd5b905f5260205f20015f9150905080546116ac9061457d565b80601f01602080910402602001604051908101604052809291908181526020018280546116d89061457d565b80156117235780601f106116fa57610100808354040283529160200191611723565b820191905f5260205f20905b81548152906001019060200180831161170657829003601f168201915b505050505081565b6007818154811061173a575f80fd5b905f5260205f20015f9150905080546117529061457d565b80601f016020809104026020016040519081016040528092919081815260200182805461177e9061457d565b80156117c95780601f106117a0576101008083540402835291602001916117c9565b820191905f5260205f20905b8154815290600101906020018083116117ac57829003601f168201915b505050505081565b6117d9613a8f565b5f6040518060400160405280848036038101906117f69190614ce2565b81526020015f81525090506040518060c0016040528061181f600661181a856125e8565b61263e565b81526020016118376007611832856125e8565b61263e565b815260200161184f600861184a856125e8565b61263e565b81526020016118676009611862856125e8565b61263e565b815260200161187f600a61187a856125e8565b61263e565b8152602001611897600b611892856125e8565b61263e565b815250915050919050565b5f60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6103e881565b6060600480546118df9061457d565b80601f016020809104026020016040519081016040528092919081815260200182805461190b9061457d565b80156119565780601f1061192d57610100808354040283529160200191611956565b820191905f5260205f20905b81548152906001019060200180831161193957829003601f168201915b5050505050905090565b5f60605f60165f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050808510611a0a575f8067ffffffffffffffff8111156119c6576119c5614615565b5b6040519080825280602002602001820160405280156119ff57816020015b6119ec613ac5565b8152602001906001900390816119e45790505b509250925050611b35565b5f8486611a17919061466f565b905081811115611a25578190505b8581611a3191906146a2565b93508367ffffffffffffffff811115611a4d57611a4c614615565b5b604051908082528060200260200182016040528015611a8657816020015b611a73613ac5565b815260200190600190039081611a6b5790505b5092505f5b84811015611b315760155f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8289611add919061466f565b81526020019081526020015f206040518060400160405290815f8201548152602001600182015481525050848281518110611b1b57611b1a6146d5565b5b6020026020010181905250806001019050611a8b565b5050505b935093915050565b5f80611b47612238565b9050611b548185856122e3565b600191505092915050565b60068181548110611b6e575f80fd5b905f5260205f20015f915090508054611b869061457d565b80601f0160208091040260200160405190810160405280929190818152602001828054611bb29061457d565b8015611bfd5780601f10611bd457610100808354040283529160200191611bfd565b820191905f5260205f20905b815481529060010190602001808311611be057829003601f168201915b505050505081565b60175481565b3373ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611c9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c91906145f7565b60405180910390fd5b80600c8190555050565b60145481565b60165f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20548210611d29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d2090614d57565b60405180910390fd5b611d343383836126fe565b5050565b6060611dbf3073ffffffffffffffffffffffffffffffffffffffff16633fc0fdcb85856040518363ffffffff1660e01b8152600401611d78929190614d75565b5f60405180830381865afa158015611d92573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611dba91906149cb565b612592565b905092915050565b5f60605f60165f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050808510611e6b575f8067ffffffffffffffff811115611e2d57611e2c614615565b5b604051908082528060200260200182016040528015611e6057816020015b6060815260200190600190039081611e4b5790505b509250925050611ffd565b5f8486611e78919061466f565b905081811115611e94578190508086611e9191906146a2565b93505b8367ffffffffffffffff811115611eae57611ead614615565b5b604051908082528060200260200182016040528015611ee157816020015b6060815260200190600190039081611ecc5790505b5092505f805f90508791505b82821015611ff857611fc33073ffffffffffffffffffffffffffffffffffffffff16637c3b3b8760155f8d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f206040518263ffffffff1660e01b8152600401611f7c9190614774565b5f60405180830381865afa158015611f96573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611fbe91906149cb565b612592565b858280611fcf90614d9c565b935081518110611fe257611fe16146d5565b5b6020026020010181905250816001019150611eed565b505050505b935093915050565b3373ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612094576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161208b906145f7565b60405180910390fd5b80600e5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555042600f8190555050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b6103e881565b3373ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146121f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121ec906145f7565b60405180910390fd5b8060055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b5f33905090565b61224c838383600161279d565b505050565b5f61225c84846120de565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146122dd57818110156122ce578281836040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526004016122c593929190614de3565b60405180910390fd5b6122dc84848484035f61279d565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16148061234a575061dead73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b1561235f5761235a83838361296c565b61258d565b6123676111e8565b15801561248157505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614806123d457503073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b8061242a57507f000000000000000000000000498d0590999ab4718292902df368a417fc15f96173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b8061248057507f000000000000000000000000498d0590999ab4718292902df368a417fc15f96173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b5b1561249657612491838383612c66565b61258d565b600e60149054906101000a900460ff16156124bb576124b6838383612c66565b61258d565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361251e576125198282612d56565b61258d565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036125815761257c8382612e33565b61258d565b61258c83838361296c565b5b505050565b60608160a00151825f01518360800151846080015185602001518660200151876040015188606001516040516020016125d2989796959493929190615320565b6040516020818303038152906040529050919050565b5f815f01515f0151825f01516020015183602001805180919061260a90614d9c565b81525060405160200161261f93929190615477565b604051602081830303815290604052805190602001205f1c9050919050565b60605f83805490508361265191906154b3565b9050838181548110612666576126656146d5565b5b905f5260205f200180546126799061457d565b80601f01602080910402602001604051908101604052809291908181526020018280546126a59061457d565b80156126f05780601f106126c7576101008083540402835291602001916126f0565b820191905f5260205f20905b8154815290600101906020018083116126d357829003601f168201915b505050505091505092915050565b5f60155f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8481526020019081526020015f206040518060400160405290815f8201548152602001600182015481525050905061278384836009600a61277e9190614bad565b612fad565b61278d848461306e565b61279782826132b2565b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361280d575f6040517fe602df0500000000000000000000000000000000000000000000000000000000815260040161280491906142c0565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361287d575f6040517f94280d6200000000000000000000000000000000000000000000000000000000815260040161287491906142c0565b60405180910390fd5b8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508015612966578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161295d9190613bae565b60405180910390a35b50505050565b612974613431565b5f61297e84611303565b90505f828261298d91906146a2565b90505f61299985611303565b90505f84826129a8919061466f565b90505f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161480612a11575061dead73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16145b15612a1d575f91505f90505b5f612a26610cb3565b600a612a329190614bad565b84612a3d9190614c65565b612a45610cb3565b600a612a519190614bad565b86612a5c9190614c65565b612a6691906146a2565b90505f612a71610cb3565b600a612a7d9190614bad565b84612a889190614c65565b612a90610cb3565b600a612a9c9190614bad565b84612aa79190614c65565b612ab191906146a2565b90505f82905081811115612ac3578190505b5f8060165f8d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f91505b82821015612bb7575f810315612bb7575f81612b24906154e3565b91508190505f60155f8f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f206040518060400160405290815f82015481526020016001820154815250509050612ba08e8361306e565b612baa8d826132b2565b5050816001019150612b09565b5f8290508392505b85831015612bed575f82612bd2906154e3565b9250829050612be18e8261306e565b50826001019250612bbf565b8092505b84831015612c44575f604051806040016040528060185f8154612c1390614d9c565b9190508190558152602001612c296103e8613477565b8152509050612c388d826132b2565b50826001019250612bf1565b612c4f8d8d8d612fad565b50505050505050505050612c616134ca565b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612cd6575f6040517f96c6fd1e000000000000000000000000000000000000000000000000000000008152600401612ccd91906142c0565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612d46575f6040517fec442f05000000000000000000000000000000000000000000000000000000008152600401612d3d91906142c0565b60405180910390fd5b612d518383836134d4565b505050565b612d5e613431565b5f612d6883611303565b90505f8282612d77919061466f565b90505f612d82610cb3565b600a612d8e9190614bad565b83612d999190614c65565b612da1610cb3565b600a612dad9190614bad565b83612db89190614c65565b612dc291906146a2565b90505f5b81811015612e19575f604051806040016040528060185f8154612de890614d9c565b9190508190558152602001612dfe6103e8613477565b8152509050612e0d87826132b2565b50806001019050612dc6565b612e2386866136ed565b50505050612e2f6134ca565b5050565b6001600e60146101000a81548160ff021916908315150217905550612e56613431565b5f612e6083611303565b90505f8282612e6f91906146a2565b90505f612e7a610cb3565b600a612e869190614bad565b82612e919190614c65565b612e99610cb3565b600a612ea59190614bad565b84612eb09190614c65565b612eba91906146a2565b90505f8060165f8873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f91505b82821015612f56576103e86014541015612f2c5760145f8154612f2490614d9c565b919050819055505b5f811115612f4b57612f4a8782612f42906154e3565b92508261306e565b5b816001019150612f02565b612f8287600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16886122e3565b5050505050612f8f6134ca565b5f600e60146101000a81548160ff0219169083151502179055505050565b6001600e60146101000a81548160ff0219169083151502179055505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16148061302f575061dead73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b156130435761303e838261379e565b61304f565b61304e838383612c66565b5b5f600e60146101000a81548160ff021916908315150217905550505050565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603156132ae575f60165f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f815461310d906154e3565b91905081905503613122576131218261381d565b5b60175f8154613130906154e3565b919050819055505f60165f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050808214613250575f60155f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f206040518060400160405290815f820154815260200160018201548152505090508060155f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f820151815f015560208201518160010155905050505b60155f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8281526020019081526020015f205f8082015f9055600182015f90555050505b5050565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16031561342d57600160165f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f815461335290614d9c565b9190508190550361336757613366826139e1565b5b60175f815461337590614d9c565b919050819055505f600160165f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20546133c791906146a2565b90508160155f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f205f820151815f015560208201518160010155905050505b5050565b60026010540361346d576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002601081905550565b5f6103e8601454836134899190614bf7565b6134939190614c65565b91505f82036134a157600191505b600160145411156134c25760145f81546134ba906154e3565b919050819055505b819050919050565b6001601081905550565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603613524578060025f828254613518919061466f565b925050819055506135f2565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050818110156135ad578381836040517fe450d38c0000000000000000000000000000000000000000000000000000000081526004016135a493929190614de3565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603613639578060025f8282540392505081905550613683565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516136e09190613bae565b60405180910390a3505050565b806136f6611348565b811115613738576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161372f90615554565b60405180910390fd5b6001600e60146101000a81548160ff02191690831515021790555061377f600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff168484612c66565b5f600e60146101000a81548160ff021916908315150217905550505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361380e575f6040517f96c6fd1e00000000000000000000000000000000000000000000000000000000815260040161380591906142c0565b60405180910390fd5b613819825f836134d4565b5050565b5f60135403156139de575f60125f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050600160135461387791906146a2565b8114613952575f60115f600160135461389091906146a2565b81526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508060115f8481526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160125f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b60135f8154613960906154e3565b9190508190555060125f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f905560115f60135481526020019081526020015f205f6101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055505b50565b5f60135f8154809291906139f490614d9c565b9190505590508160115f8381526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060125f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055505050565b6040518060c001604052806060815260200160608152602001606081526020016060815260200160608152602001606081525090565b60405180604001604052805f81526020015f81525090565b5f81905092915050565b50565b5f613af55f83613add565b9150613b0082613ae7565b5f82019050919050565b5f613b1482613aea565b9150819050919050565b5f82825260208201905092915050565b7f63616e206e6f74206765742065746865720000000000000000000000000000005f82015250565b5f613b62601183613b1e565b9150613b6d82613b2e565b602082019050919050565b5f6020820190508181035f830152613b8f81613b56565b9050919050565b5f819050919050565b613ba881613b96565b82525050565b5f602082019050613bc15f830184613b9f565b92915050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613c0182613bd8565b9050919050565b613c1181613bf7565b8114613c1b575f80fd5b50565b5f81359050613c2c81613c08565b92915050565b5f60208284031215613c4757613c46613bd0565b5b5f613c5484828501613c1e565b91505092915050565b5f81519050919050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f613c8f82613c5d565b613c998185613b1e565b9350613ca9818560208601613c67565b613cb281613c75565b840191505092915050565b5f6020820190508181035f830152613cd58184613c85565b905092915050565b613ce681613b96565b8114613cf0575f80fd5b50565b5f81359050613d0181613cdd565b92915050565b5f8060408385031215613d1d57613d1c613bd0565b5b5f613d2a85828601613c1e565b9250506020613d3b85828601613cf3565b9150509250929050565b5f8115159050919050565b613d5981613d45565b82525050565b5f602082019050613d725f830184613d50565b92915050565b5f805f60608486031215613d8f57613d8e613bd0565b5b5f613d9c86828701613c1e565b9350506020613dad86828701613c1e565b9250506040613dbe86828701613cf3565b9150509250925092565b5f60208284031215613ddd57613ddc613bd0565b5b5f613dea84828501613cf3565b91505092915050565b5f60ff82169050919050565b613e0881613df3565b82525050565b5f602082019050613e215f830184613dff565b92915050565b5f8060408385031215613e3d57613e3c613bd0565b5b5f613e4a85828601613cf3565b9250506020613e5b85828601613cf3565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b613e9781613bf7565b82525050565b5f613ea88383613e8e565b60208301905092915050565b5f602082019050919050565b5f613eca82613e65565b613ed48185613e6f565b9350613edf83613e7f565b805f5b83811015613f0f578151613ef68882613e9d565b9750613f0183613eb4565b925050600181019050613ee2565b5085935050505092915050565b5f604082019050613f2f5f830185613b9f565b8181036020830152613f418184613ec0565b90509392505050565b5f82825260208201905092915050565b5f613f6482613c5d565b613f6e8185613f4a565b9350613f7e818560208601613c67565b613f8781613c75565b840191505092915050565b5f60c083015f8301518482035f860152613fac8282613f5a565b91505060208301518482036020860152613fc68282613f5a565b91505060408301518482036040860152613fe08282613f5a565b91505060608301518482036060860152613ffa8282613f5a565b915050608083015184820360808601526140148282613f5a565b91505060a083015184820360a086015261402e8282613f5a565b9150508091505092915050565b5f6020820190508181035f8301526140538184613f92565b905092915050565b5f80fd5b5f604082840312156140745761407361405b565b5b81905092915050565b5f6040828403121561409257614091613bd0565b5b5f61409f8482850161405f565b91505092915050565b5f6040820190506140bb5f830185613b9f565b6140c86020830184613b9f565b9392505050565b5f805f606084860312156140e6576140e5613bd0565b5b5f6140f386828701613c1e565b935050602061410486828701613cf3565b925050604061411586828701613cf3565b9150509250925092565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f60c083015f8301518482035f8601526141628282613f5a565b9150506020830151848203602086015261417c8282613f5a565b915050604083015184820360408601526141968282613f5a565b915050606083015184820360608601526141b08282613f5a565b915050608083015184820360808601526141ca8282613f5a565b91505060a083015184820360a08601526141e48282613f5a565b9150508091505092915050565b5f6141fc8383614148565b905092915050565b5f602082019050919050565b5f61421a8261411f565b6142248185614129565b93508360208202850161423685614139565b805f5b85811015614271578484038952815161425285826141f1565b945061425d83614204565b925060208a01995050600181019050614239565b50829750879550505050505092915050565b5f6040820190506142965f830185613b9f565b81810360208301526142a88184614210565b90509392505050565b6142ba81613bf7565b82525050565b5f6020820190506142d35f8301846142b1565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61430b81613b96565b82525050565b604082015f8201516143255f850182614302565b5060208201516143386020850182614302565b50505050565b5f6143498383614311565b60408301905092915050565b5f602082019050919050565b5f61436b826142d9565b61437581856142e3565b9350614380836142f3565b805f5b838110156143b0578151614397888261433e565b97506143a283614355565b925050600181019050614383565b5085935050505092915050565b5f6040820190506143d05f830185613b9f565b81810360208301526143e28184614361565b90509392505050565b5f806040838503121561440157614400613bd0565b5b5f61440e85828601613cf3565b925050602061441f85828601613c1e565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f61445d8383613f5a565b905092915050565b5f602082019050919050565b5f61447b82614429565b6144858185614433565b93508360208202850161449785614443565b805f5b858110156144d257848403895281516144b38582614452565b94506144be83614465565b925060208a0199505060018101905061449a565b50829750879550505050505092915050565b5f6040820190506144f75f830185613b9f565b81810360208301526145098184614471565b90509392505050565b5f806040838503121561452857614527613bd0565b5b5f61453585828601613c1e565b925050602061454685828601613c1e565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061459457607f821691505b6020821081036145a7576145a6614550565b5b50919050565b7f6f6e6c79206f776e6572000000000000000000000000000000000000000000005f82015250565b5f6145e1600a83613b1e565b91506145ec826145ad565b602082019050919050565b5f6020820190508181035f83015261460e816145d5565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61467982613b96565b915061468483613b96565b925082820190508082111561469c5761469b614642565b5b92915050565b5f6146ac82613b96565b91506146b783613b96565b92508282039050818111156146cf576146ce614642565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f815f1c9050919050565b5f819050919050565b5f61472861472383614702565b61470d565b9050919050565b604082015f80830154905061474381614716565b61474f5f860182614302565b506001830154905061476081614716565b61476d6020860182614302565b5050505050565b5f6040820190506147875f83018461472f565b92915050565b5f80fd5b61479a82613c75565b810181811067ffffffffffffffff821117156147b9576147b8614615565b5b80604052505050565b5f6147cb613bc7565b90506147d78282614791565b919050565b5f80fd5b5f80fd5b5f80fd5b5f67ffffffffffffffff82111561480257614801614615565b5b61480b82613c75565b9050602081019050919050565b5f61482a614825846147e8565b6147c2565b905082815260208101848484011115614846576148456147e4565b5b614851848285613c67565b509392505050565b5f82601f83011261486d5761486c6147e0565b5b815161487d848260208601614818565b91505092915050565b5f60c0828403121561489b5761489a61478d565b5b6148a560c06147c2565b90505f82015167ffffffffffffffff8111156148c4576148c36147dc565b5b6148d084828501614859565b5f83015250602082015167ffffffffffffffff8111156148f3576148f26147dc565b5b6148ff84828501614859565b602083015250604082015167ffffffffffffffff811115614923576149226147dc565b5b61492f84828501614859565b604083015250606082015167ffffffffffffffff811115614953576149526147dc565b5b61495f84828501614859565b606083015250608082015167ffffffffffffffff811115614983576149826147dc565b5b61498f84828501614859565b60808301525060a082015167ffffffffffffffff8111156149b3576149b26147dc565b5b6149bf84828501614859565b60a08301525092915050565b5f602082840312156149e0576149df613bd0565b5b5f82015167ffffffffffffffff8111156149fd576149fc613bd4565b5b614a0984828501614886565b91505092915050565b5f614a206020840184613cf3565b905092915050565b60408201614a385f830183614a12565b614a445f850182614302565b50614a526020830183614a12565b614a5f6020850182614302565b50505050565b5f604082019050614a785f830184614a28565b92915050565b5f8160011c9050919050565b5f808291508390505b6001851115614ad357808604811115614aaf57614aae614642565b5b6001851615614abe5780820291505b8081029050614acc85614a7e565b9450614a93565b94509492505050565b5f82614aeb5760019050614ba6565b81614af8575f9050614ba6565b8160018114614b0e5760028114614b1857614b47565b6001915050614ba6565b60ff841115614b2a57614b29614642565b5b8360020a915084821115614b4157614b40614642565b5b50614ba6565b5060208310610133831016604e8410600b8410161715614b7c5782820a905083811115614b7757614b76614642565b5b614ba6565b614b898484846001614a8a565b92509050818404811115614ba057614b9f614642565b5b81810290505b9392505050565b5f614bb782613b96565b9150614bc283613df3565b9250614bef7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484614adc565b905092915050565b5f614c0182613b96565b9150614c0c83613b96565b9250828202614c1a81613b96565b91508282048414831517614c3157614c30614642565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f614c6f82613b96565b9150614c7a83613b96565b925082614c8a57614c89614c38565b5b828204905092915050565b5f60408284031215614caa57614ca961478d565b5b614cb460406147c2565b90505f614cc384828501613cf3565b5f830152506020614cd684828501613cf3565b60208301525092915050565b5f60408284031215614cf757614cf6613bd0565b5b5f614d0484828501614c95565b91505092915050565b7f696e636f727265637420696e64657800000000000000000000000000000000005f82015250565b5f614d41600f83613b1e565b9150614d4c82614d0d565b602082019050919050565b5f6020820190508181035f830152614d6e81614d35565b9050919050565b5f604082019050614d885f8301856142b1565b614d956020830184613b9f565b9392505050565b5f614da682613b96565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614dd857614dd7614642565b5b600182019050919050565b5f606082019050614df65f8301866142b1565b614e036020830185613b9f565b614e106040830184613b9f565b949350505050565b5f81905092915050565b7f3c73766720786d6c6e733d27687474703a2f2f7777772e77332e6f72672f32305f8201527f30302f737667272076696577426f783d273020302031303020313030273e0000602082015250565b5f614e7c603e83614e18565b9150614e8782614e22565b603e82019050919050565b7f3c726563742077696474683d2731303027206865696768743d273130302720665f8201527f696c6c3d27000000000000000000000000000000000000000000000000000000602082015250565b5f614eec602583614e18565b9150614ef782614e92565b602582019050919050565b5f614f0c82613c5d565b614f168185614e18565b9350614f26818560208601613c67565b80840191505092915050565b7f272f3e00000000000000000000000000000000000000000000000000000000005f82015250565b5f614f66600383614e18565b9150614f7182614f32565b600382019050919050565b7f3c706f6c79676f6e20706f696e74733d2735302c32302037302c33352037302c5f8201527f36352035302c38302033302c36352033302c3335272066696c6c3d2700000000602082015250565b5f614fd6603c83614e18565b9150614fe182614f7c565b603c82019050919050565b7f27202f3e000000000000000000000000000000000000000000000000000000005f82015250565b5f615020600483614e18565b915061502b82614fec565b600482019050919050565b7f3c7265637420783d2732352720793d273330272077696474683d2731302720685f8201527f65696768743d273130272066696c6c3d27000000000000000000000000000000602082015250565b5f615090603183614e18565b915061509b82615036565b603182019050919050565b7f3c7265637420783d2736352720793d273330272077696474683d2731302720685f8201527f65696768743d273130272066696c6c3d27000000000000000000000000000000602082015250565b5f615100603183614e18565b915061510b826150a6565b603182019050919050565b7f3c636972636c652063783d273430272063793d2735302720723d2735272066695f8201527f6c6c3d2700000000000000000000000000000000000000000000000000000000602082015250565b5f615170602483614e18565b915061517b82615116565b602482019050919050565b7f3c636972636c652063783d273630272063793d2735302720723d2735272066695f8201527f6c6c3d2700000000000000000000000000000000000000000000000000000000602082015250565b5f6151e0602483614e18565b91506151eb82615186565b602482019050919050565b7f3c636972636c652063783d273530272063793d2736302720723d2735272066695f8201527f6c6c3d2700000000000000000000000000000000000000000000000000000000602082015250565b5f615250602483614e18565b915061525b826151f6565b602482019050919050565b7f3c656c6c697073652063783d273530272063793d273730272072783d273130275f8201527f2072793d2735272066696c6c3d27000000000000000000000000000000000000602082015250565b5f6152c0602e83614e18565b91506152cb82615266565b602e82019050919050565b7f3c2f7376673e00000000000000000000000000000000000000000000000000005f82015250565b5f61530a600683614e18565b9150615315826152d6565b600682019050919050565b5f61532a82614e70565b915061533582614ee0565b9150615341828b614f02565b915061534c82614f5a565b915061535782614fca565b9150615363828a614f02565b915061536e82615014565b915061537982615084565b91506153858289614f02565b915061539082615014565b915061539b826150f4565b91506153a78288614f02565b91506153b282615014565b91506153bd82615164565b91506153c98287614f02565b91506153d482615014565b91506153df826151d4565b91506153eb8286614f02565b91506153f682615014565b915061540182615244565b915061540d8285614f02565b915061541882615014565b9150615423826152b4565b915061542f8284614f02565b915061543a82615014565b9150615445826152fe565b91508190509998505050505050505050565b5f819050919050565b61547161546c82613b96565b615457565b82525050565b5f6154828286615460565b6020820191506154928285615460565b6020820191506154a28284615460565b602082019150819050949350505050565b5f6154bd82613b96565b91506154c883613b96565b9250826154d8576154d7614c38565b5b828206905092915050565b5f6154ed82613b96565b91505f82036154ff576154fe614642565b5b600182039050919050565b7f6d617820627579000000000000000000000000000000000000000000000000005f82015250565b5f61553e600783613b1e565b91506155498261550a565b602082019050919050565b5f6020820190508181035f83015261556b81615532565b905091905056fea264697066735822122035bed1a76b6a273fecbd6e3ff537f49cc705d6aa29662033b4f4c3ba49baa46564736f6c63430008190033

Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.