MATIC Price: $0.645832 (+2.70%)
Gas: 39 GWei
 

Overview

MATIC Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 MATIC

MATIC Value

$0.00

Token Holdings

More Info

Private Name Tags

TokenTracker

CACHE Gold (CGT) (@$36.66)

Sponsored

Transaction Hash
Method
Block
From
To
Value
Approve551107032024-03-26 19:15:0277 days ago1711480502IN
CACHE Gold: CGT Token
0 MATIC0.00632721172.22536686
Approve551106992024-03-26 19:14:5477 days ago1711480494IN
CACHE Gold: CGT Token
0 MATIC0.00988676172.22536686
Approve477232652023-09-19 8:20:02267 days ago1695111602IN
CACHE Gold: CGT Token
0 MATIC0.0046836281.67307124
Approve455243402023-07-26 2:56:42322 days ago1690340202IN
CACHE Gold: CGT Token
0 MATIC0.0024679443
Approve403308622023-03-14 9:30:10456 days ago1678786210IN
CACHE Gold: CGT Token
0 MATIC0.0078686137.0694092
Approve403285342023-03-14 8:03:31456 days ago1678781011IN
CACHE Gold: CGT Token
0 MATIC0.01616294281.43729099
Approve383259162023-01-20 22:33:13508 days ago1674253993IN
CACHE Gold: CGT Token
0 MATIC0.0028658949.67403794
Transfer379249622023-01-11 2:04:30518 days ago1673402670IN
CACHE Gold: CGT Token
0 MATIC0.01985049124.21541831
Approve378933592023-01-10 7:35:47519 days ago1673336147IN
CACHE Gold: CGT Token
0 MATIC0.0029327251.07674495
Approve367781922022-12-13 11:12:59547 days ago1670929979IN
CACHE Gold: CGT Token
0 MATIC0.0020644651.20460242
Approve361377282022-11-27 16:13:26562 days ago1669565606IN
CACHE Gold: CGT Token
0 MATIC0.002455142.50977833
Transfer351062302022-11-02 11:08:29588 days ago1667387309IN
CACHE Gold: CGT Token
0 MATIC0.0036420140.69015219
Approve343030482022-10-13 18:39:04607 days ago1665686344IN
CACHE Gold: CGT Token
0 MATIC0.0044495977.51104033
Transfer339281132022-10-04 17:08:50616 days ago1664903330IN
CACHE Gold: CGT Token
0 MATIC0.0051658631.04970001
Revoke Role339165222022-10-04 10:27:46617 days ago1664879266IN
CACHE Gold: CGT Token
0 MATIC0.000832230.00000001
Approve320813552022-08-19 18:29:10662 days ago1660933750IN
CACHE Gold: CGT Token
0 MATIC0.0021736237.63600002
Set Fee Exempt319114292022-08-15 7:11:17667 days ago1660547477IN
CACHE Gold: CGT Token
0 MATIC0.00757202109.75695141
Set Fee Exempt317247112022-08-10 7:52:08672 days ago1660117928IN
CACHE Gold: CGT Token
0 MATIC0.0023325233.81006908
Set Fee Exempt317247002022-08-10 7:51:24672 days ago1660117884IN
CACHE Gold: CGT Token
0 MATIC0.0023180333.60007619
Approve316845702022-08-09 5:42:57673 days ago1660023777IN
CACHE Gold: CGT Token
0 MATIC0.0027450547.53021359
Approve316845512022-08-09 5:41:03673 days ago1660023663IN
CACHE Gold: CGT Token
0 MATIC0.0028626949.56700659
Approve316844842022-08-09 5:32:19673 days ago1660023139IN
CACHE Gold: CGT Token
0 MATIC0.0017225430.00000002
Approve316642192022-08-08 16:15:04673 days ago1659975304IN
CACHE Gold: CGT Token
0 MATIC0.0034868760.37456354
Approve315802852022-08-06 8:03:32676 days ago1659773012IN
CACHE Gold: CGT Token
0 MATIC0.0017820631.04970002
Transfer315802162022-08-06 8:01:10676 days ago1659772870IN
CACHE Gold: CGT Token
0 MATIC0.0056483933.95000001
View all transactions

Parent Transaction Hash Block From To Value
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CacheGoldChild

Compiler Version
v0.8.11+commit.d7f03943

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 9 : CacheGoldChild.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

import {IFxERC20} from "./IFxERC20.sol";
import "../lib/AccessControl.sol";

/// @title The CacheGold Token Contract for L2/Sidechains
/// @author CACHE TEAM
contract CacheGoldChild is IFxERC20, AccessControl {
    bytes32 public constant FEE_ENFORCER_ROLE = keccak256("FEE_ENFORCER_ROLE");
    // 10^8 shortcut
    uint256 private constant TOKEN = 10**8;

    string public constant name = "CACHE Gold";
    string public constant symbol = "CGT";
    uint8 public constant decimals = 8;

    // Seconds in a day
    uint256 private constant DAY = 86400;

    // Days in a year
    uint256 private constant YEAR = 365;

    // The maximum transfer fee is 10 basis points
    uint256 private constant MAX_TRANSFER_FEE_BASIS_POINTS = 10;

    // Basis points means divide by 10,000 to get decimal
    uint256 private constant BASIS_POINTS_MULTIPLIER = 10000;

    // The storage fee of 0.25%
    uint256 private constant STORAGE_FEE_DENOMINATOR = 4e10;

    // The inactive fee of 0.50%
    uint256 private constant INACTIVE_FEE_DENOMINATOR = 2e10;

    // The minimum balance that would accrue a storage fee after 1 day
    uint256 private constant MIN_BALANCE_FOR_FEES = 146000;

    // Initial basis points for transfer fee
    uint256 private _transferFeeBasisPoints = 10;

    // How many days need to pass before late fees can be collected (3 years)
    uint256 public constant INACTIVE_THRESHOLD_DAYS = 1095;

    // Token balance of each address
    mapping(address => uint256) private _balances;

    // Allowed transfer from address
    mapping(address => mapping(address => uint256)) private _allowances;

    // Last time storage fee was paid
    mapping(address => uint256) private _timeStorageFeePaid;

    // Last time the address produced a transaction on this contract
    mapping(address => uint256) private _timeLastActivity;

    // Amount of inactive fees already paid
    mapping(address => uint256) private _inactiveFeePaid;

    // If address doesn't have any activity for INACTIVE_THRESHOLD_DAYS
    // we can start deducting chunks off the address so that
    // full balance can be recouped after 200 years. This is likely
    // to happen if the user loses their private key.
    mapping(address => uint256) private _inactiveFeePerYear;

    // Addresses not subject to transfer fees
    mapping(address => bool) private _transferFeeExempt;

    // Address is not subject to storage fees
    mapping(address => bool) private _storageFeeExempt;

    // Save grace period on storage fees for an address
    mapping(address => uint256) private _storageFeeGracePeriod;
    // Current total number of tokens created
    uint256 private _totalSupply;

    // Address where storage and transfer fees are collected
    address private _feeAddress;

    // A fee-exempt address that can be used to collect gold tokens in exchange
    // for redemption of physical gold
    address private _redeemAddress;

    //addresses related to the fxManager
    address internal _fxManager;
    address internal _connectedToken;


    // Grace period before storage fees kick in
    uint256 private _storageFeeGracePeriodDays = 0;

    // When gold bars are minted on child chain
    event Mint(uint256 amount, address user);
    
    // When a user burns tokens in child for withdrawal to mainnet
    event withdrawBurn(address _from, uint256 _amount);

    // When an account has no activity for INACTIVE_THRESHOLD_DAYS
    // it will be flagged as inactive
    event AccountInactive(address indexed account, uint256 feePerYear);

    // If an previoulsy dormant account is reactivated
    event AccountReActive(address indexed account);
    
    // Emit if the Operator address is changed
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    // Emit if the critical addresses are changed
    event AddressChange(string addressType, address indexed account);

    // Emit if a critical fee is changed
    event FeeChange(string feeType, uint fee);

    constructor() {
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        setFeeExempt(msg.sender);
    }

    function initialize(
        address __feeAddress,
        address __feeEnforcer,
        address __fxManager_,
        address __connectedToken,
        address __redeemAddress
    ) external onlyRole(DEFAULT_ADMIN_ROLE) override  {
        require(__fxManager_ != address(0x0) && __connectedToken != address(0x0), "Zero address inputted");
        require(_fxManager == address(0x0) && _connectedToken == address(0x0), "Token is already initialized");
        _fxManager = __fxManager_;
        _connectedToken = __connectedToken;
        _redeemAddress = __redeemAddress;
        _feeAddress = __feeAddress;
        _grantRole(FEE_ENFORCER_ROLE, __feeEnforcer);
        setFeeExempt(_feeAddress);
        setFeeExempt(_fxManager);
    }

    // fxManager returns fx manager
    function fxManager() external view override returns (address) {
        return _fxManager;
    }

    // connectedToken returns root token
    function connectedToken() external view override returns (address) {
        return _connectedToken;
    }

    function setFxManager(address __fxManager) external onlyRole(DEFAULT_ADMIN_ROLE) {
        _fxManager = __fxManager;
        setFeeExempt(_fxManager);
    }


    /**
     * @dev Transfer token for a specified address
     * @param to The address to transfer to.
     * @param value The amount to be transferred.
     */
    function transfer(address to, uint256 value)
        external
        override
        returns (bool)
    {
        require(_balances[msg.sender] >= value, "Insufficient Balance To Make This Transfer");

        // Update activity for the sender
        _updateActivity(msg.sender);

        // Can opportunistically mark an account inactive if someone
        // sends money to it
        if (_shouldMarkInactive(to)) {
            _setInactive(to);
        }

        _transfer(msg.sender, to, value);
        return true;
    }
    
    /**
     * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
     * 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
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     */
    function approve(address spender, uint256 value)
        external
        override
        returns (bool)
    {
        _updateActivity(msg.sender);
        _approve(msg.sender, spender, value);
        return true;
    }

    /**
     * @dev Transfer tokens from one address to another.
     * Note that while this function emits an Approval event, this is not required as per the specification,
     * and other compliant implementations may not emit the event.
     * Also note that even though balance requirements are not explicitly checked,
     * any transfer attempt over the approved amount will automatically fail due to
     * SafeMath revert when trying to subtract approval to a negative balance
     * @param from address The address which you want to send tokens from
     * @param to address The address which you want to transfer to
     * @param value uint256 the amount of tokens to be transferred
     */
    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external override returns (bool) {
        _updateActivity(msg.sender);
        _transfer(from, to, value);
        _approve(from, msg.sender, (_allowances[from][msg.sender] - (value)));
        return true;
    }

    /**
     * @dev Increase the amount of tokens that an owner allowed to a spender.
     * approve should be called when allowed_[_spender] == 0. To increment
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * Emits an Approval event.
     * @param spender The address which will spend the funds.
     * @param addedValue The amount of tokens to increase the allowance by.
     */
    function increaseAllowance(address spender, uint256 addedValue)
        external
        returns (bool)
    {
        _updateActivity(msg.sender);
        _approve(
            msg.sender,
            spender,
            (_allowances[msg.sender][spender] + (addedValue))
        );
        return true;
    }

    /**
     * @dev Decrease the amount of tokens that an owner allowed to a spender.
     * approve should be called when allowed_[_spender] == 0. To decrement
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * Emits an Approval event.
     * @param spender The address which will spend the funds.
     * @param subtractedValue The amount of tokens to decrease the allowance by.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue)
        external
        returns (bool)
    {
        _updateActivity(msg.sender);
        _approve(
            msg.sender,
            spender,
            (_allowances[msg.sender][spender] - (subtractedValue))
        );
        return true;
    }

    /**
     * @dev Manually pay storage fees on senders address. Exchanges may want to
     * periodically call this function to pay owed storage fees. This is a
     * cheaper option than 'send to self', which would also trigger paying
     * storage fees
     *
     * @return A boolean that indicates if the operation was successful.
     */
    function payStorageFee() external returns (bool) {
        _updateActivity(msg.sender);
        _payStorageFee(msg.sender);
        return true;
    }

    function setAccountInactive(address account)
        external
        onlyRole(FEE_ENFORCER_ROLE)
        returns (bool)
    {
        require(
            _shouldMarkInactive(account),
            "Account not eligible to be marked inactive"
        );
        _setInactive(account);
        return true;
    }

    /**
     * @dev Contract allows the forcible collection of storage fees on an address
     * if it is has been more than than 365 days since the last time storage fees
     * were paid on this address.
     *
     * Alternatively inactive fees may also be collected periodically on a prorated
     * basis if the account is currently marked as inactive.
     *
     * @param account The address to pay storage fees on
     * @return A boolean that indicates if the operation was successful.
     */
    function forcePayFees(address account)
        external
        onlyRole(FEE_ENFORCER_ROLE)
        returns (bool)
    {
        require(account != address(0), "Zero address used");
        require(
            _balances[account] > 0,
            "Account has no balance, cannot force paying fees"
        );

        // If account is inactive, pay inactive fees
        if (isInactive(account)) {
            uint256 paid = _payInactiveFee(account);
            require(paid > 0, "Error no fees paid!");
        } else if (_shouldMarkInactive(account)) {
            // If it meets inactive threshold, but hasn't been set yet, set it.
            // This will also trigger automatic payment of owed storage fees
            // before starting inactive fees
            _setInactive(account);
        } else {
            // Otherwise just force paying owed storage fees, which can only
            // be called if they are more than 365 days overdue
            require(
                daysSincePaidStorageFee(account) >= YEAR,
                "Account has paid storage fees more recently than 365 days"
            );
            uint256 paid = _payStorageFee(account);
            require(
                paid > 0,
                "No appreciable storage fees due, will refund gas"
            );
        }
        return true;
    }

    /**
     * @dev Set the address to collect fees
     * @param newFeeAddress The address to collect storage and transfer fees
     * @return An bool representing successfully changing fee address
     */
    function setFeeAddress(address newFeeAddress)
        external
        onlyRole(DEFAULT_ADMIN_ROLE)
        returns (bool)
    {
        require(newFeeAddress != address(0), "Zero address used");
        _feeAddress = newFeeAddress;
        setFeeExempt(_feeAddress);
        emit AddressChange("Fee Address", newFeeAddress);
        return true;
    }

    /**
    * @dev Set the address to deposit tokens when redeeming for physical locked bars.
    * @param newRedeemAddress The address to redeem tokens for bars
    * @return An bool representing successfully changing redeem address
    */
    function setRedeemAddress(address newRedeemAddress) external onlyRole(DEFAULT_ADMIN_ROLE) returns(bool) {
        require(newRedeemAddress != address(0), "Zero address used");
        _redeemAddress = newRedeemAddress;
        setFeeExempt(_redeemAddress);
        emit AddressChange("Redeem Address", newRedeemAddress);
        return true;
    }

    /**
     * @dev Set the number of days before storage fees begin accruing.
     * @param daysGracePeriod The global setting for the grace period before storage
     * fees begin accruing. Note that calling this will not change the grace period
     * for addresses already actively inside a grace period
     */
    function setStorageFeeGracePeriodDays(uint256 daysGracePeriod)
        external
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        _storageFeeGracePeriodDays = daysGracePeriod;
        emit FeeChange("Storage Fee Grace Period Days", daysGracePeriod);
    }

    /**
     * @dev Set this account as being exempt from transfer fees. This may be used
     * in special circumstance for cold storage addresses owed by Cache, exchanges, etc.
     * @param account The account to exempt from transfer fees
     */
    function setTransferFeeExempt(address account) external onlyRole(DEFAULT_ADMIN_ROLE) {
        _transferFeeExempt[account] = true;
    }

    /**
     * @dev Set this account as being exempt from storage fees. This may be used
     * in special circumstance for cold storage addresses owed by Cache, exchanges, etc.
     * @param account The account to exempt from storage fees
     */
    function setStorageFeeExempt(address account) external onlyRole(DEFAULT_ADMIN_ROLE) {
        _storageFeeExempt[account] = true;
    }

    /**
     * @dev Set a new transfer fee in basis points, must be less than or equal to 10 basis points
     * @param fee The new transfer fee in basis points
     */
    function setTransferFeeBasisPoints(uint256 fee) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(
            fee <= MAX_TRANSFER_FEE_BASIS_POINTS,
            "Transfer fee basis points must be an integer between 0 and 10"
        );
        emit FeeChange("Transfer Fee Basis Points", fee);
        _transferFeeBasisPoints = fee;
    }

    /**
     * @dev Gets the balance of the specified address deducting owed fees and
     * accounting for the maximum amount that could be sent including transfer fee
     * @param owner The address to query the balance of.
     * @return An uint256 representing the amount sendable by the passed address
     * including transaction and storage fees
     */
    function balanceOf(address owner) external view override returns (uint256) {
        return maximumTransferAmount(owner);
    }

    /**
     * @dev Gets the balance of the specified address not deducting owed fees.
     * this returns the 'traditional' ERC-20 balance that represents the balance
     * currently stored in contract storage.
     * @param owner The address to query the balance of.
     * @return An uint256 representing the amount stored in passed address
     */
    function balanceOfNoFees(address owner) external view returns (uint256) {
        return _balances[owner];
    }

    /**
    * @return address for redeeming tokens for gold bars
    */
    function redeemAddress() external view returns(address) {
        return _redeemAddress;
    }

    /**
     * @return address where fees are collected
     */
    function getFeeAddress() external view returns (address) {
        return _feeAddress;
    }    

    /**
     * @return the current number of days and address is exempt
     * from storage fees upon receiving tokens
     */
    function storageFeeGracePeriodDays() external view returns (uint256) {
        return _storageFeeGracePeriodDays;
    }

    /**
     * @return the current transfer fee in basis points [0-10]
     */
    function transferFeeBasisPoints() external view returns (uint256) {
        return _transferFeeBasisPoints;
    }

    /**
     * @dev Function to mint certain amount of tokens in the child chain
     * @param user The user to whom the minted tokens have to be sent to
     * @param amount The amount of tokens to add to the supply and pass to the user
     */
    function mint(address user, uint256 amount)
        external
        override
    {
        require(msg.sender == _fxManager, "Invalid sender");
        _totalSupply = _totalSupply + amount;
        uint storageFeeTo = calcStorageFee(user);// automatically deduct any pending storage fee
        _balances[user] = _balances[user] + amount - storageFeeTo;
        emit Mint(amount,user);
        if(_timeStorageFeePaid[user] == 0){ 
            //checks if it is the first time the user is depositing gold into the account
            _storageFeeGracePeriod[user] = _storageFeeGracePeriodDays;
            _timeLastActivity[user] = block.timestamp;
            _timeStorageFeePaid[user] = block.timestamp;
        }
    }
    
    /**
     * @dev Function to burn certain amount of tokens in the child chain
     * @param account The account from whom the tokens have to be removed from
     * @param amount The amount of tokens to remove from the supply and burn
     */
    function burn(address account, uint256 amount) 
        external
        override
    {
        require(msg.sender == _fxManager, "Invalid sender");
        uint256 currentAllowance = allowance(account, msg.sender);
        require(
            currentAllowance >= amount,
            "ERC20: burn amount exceeds allowance"
        );
        _approve(account, msg.sender, currentAllowance - amount);
        unchecked
        {
            _balances[account] = _balances[account] - amount;
        }
        
        _totalSupply = _totalSupply - amount;//reduce the total supply
        emit withdrawBurn(account, amount);
        emit Transfer(account, address(0), amount);// Fx Tunnel expects an event denoting a burn to withdraw on mainnet
    }

    function totalCirculation() external view returns (uint256) {
        return _totalSupply;
    }
    
    function totalSupply() external view override returns (uint256) {
         return _totalSupply;
     }

    /**
     * @dev Function to check the amount of tokens that an owner allowed to a spender.
     * @param owner address The address which owns the funds.
     * @param spender address The address which will spend the funds.
     * @return A uint256 specifying the amount of tokens still available for the spender.
     */
    function allowance(address owner, address spender)
        public
        view
        override
        returns (uint256)
    {
        return _allowances[owner][spender];
    }
    
    /**
     * @dev Set account is no longer exempt from all fees
     * @param account The account to reactivate fees
     */
    function unsetFeeExempt(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _transferFeeExempt[account] = false;
        _storageFeeExempt[account] = false;
    }
    /**
     * @dev Set this account as being exempt from all fees. This may be used
     * in special circumstance for cold storage addresses owed by Cache, exchanges, etc.
     * @param account The account to exempt from storage and transfer fees
     */
    function setFeeExempt(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _transferFeeExempt[account] = true;
        _storageFeeExempt[account] = true;
    }

    /**
     * @dev Check if the address given is exempt from storage fees
     * @param account The address to check
     * @return A boolean if the address passed is exempt from storage fees
     */
    function isStorageFeeExempt(address account) public view returns (bool) {
        return _storageFeeExempt[account];
    }

    /**
     * @dev Check if the address given is exempt from transfer fees
     * @param account The address to check
     * @return A boolean if the address passed is exempt from transfer fees
     */
    function isTransferFeeExempt(address account) public view returns (bool) {
        return _transferFeeExempt[account];
    }

    /**
     * @dev Check if the address given is exempt from transfer fees
     * @param account The address to check
     * @return A boolean if the address passed is exempt from transfer fees
     */
    function isAllFeeExempt(address account) public view returns (bool) {
        return _transferFeeExempt[account] && _storageFeeExempt[account];
    }


    function isInactive(address account) public view returns (bool) {
        return _inactiveFeePerYear[account] > 0;
    }

    /**
     * @dev Get the number of days since the account last paid storage fees
     * @param account The address to check
     * @return A uint256 representing the number of days since storage fees where last paid
     */
    function daysSincePaidStorageFee(address account)
        public
        view
        returns (uint256)
    {
        if (isInactive(account) || _timeStorageFeePaid[account] == 0) {
            return 0;
        }
        return (block.timestamp - _timeStorageFeePaid[account]) / (DAY);
    }

    /**
     * @dev Get the days since the account last sent a transaction to the contract (activity)
     * @param account The address to check
     * @return A uint256 representing the number of days since the address last had activity
     * with the contract
     */
    function daysSinceActivity(address account) public view returns (uint256) {
        if (_timeLastActivity[account] == 0) {
            return 0;
        }
        return (block.timestamp - (_timeLastActivity[account])) / (DAY);
    }

    /**
     * @dev Returns the total number of fees owed on a particular address
     * @param account The address to check
     * @return The total storage and inactive fees owed on the address
     */
    function calcOwedFees(address account) public view returns (uint256) {
        return calcStorageFee(account) + (calcInactiveFee(account));
    }

    /**
     * @dev Calculate the current storage fee owed for a given address
     * @param account The address to check
     * @return A uint256 representing current storage fees for the address
     */
    function calcStorageFee(address account) public view returns (uint256) {
        // If an account is in an inactive state those fees take over and
        // storage fees are effectively paused
        uint256 balance = _balances[account];
        if (
            isInactive(account) || isStorageFeeExempt(account) || balance == 0
        ) {
            return 0;
        }

        uint256 daysSinceStoragePaid = daysSincePaidStorageFee(account);
        uint256 daysInactive = daysSinceActivity(account);
        uint256 gracePeriod = _storageFeeGracePeriod[account];

        // If there is a grace period, we can deduct it from the daysSinceStoragePaid
        if (gracePeriod > 0) {
            if (daysSinceStoragePaid > gracePeriod) {
                daysSinceStoragePaid = daysSinceStoragePaid - (gracePeriod);
            } else {
                daysSinceStoragePaid = 0;
            }
        }

        if (daysSinceStoragePaid == 0) {
            return 0;
        }

        // This is an edge case where the account has not yet been marked inactive, but
        // will be marked inactive whenever there is a transaction allowing it to be marked.
        // Therefore we know storage fees will only be valid up to a point, and inactive
        // fees will take over.
        if (daysInactive >= INACTIVE_THRESHOLD_DAYS) {
            // This should not be at risk of being negative, because its impossible to force paying
            // storage fees without also setting the account to inactive, so if we are here it means
            // the last time storage fees were paid was BEFORE the account became eligible to be inactive
            // and it's always the case that daysSinceStoragePaid > daysInactive - (INACTIVE_THRESHOLD_DAYS)
            daysSinceStoragePaid =
                daysSinceStoragePaid -
                (daysInactive - (INACTIVE_THRESHOLD_DAYS));
        }
        // The normal case with normal storage fees
        return storageFee(balance, daysSinceStoragePaid);
    }

    /**
     * @dev Calculate the current inactive fee for a given address
     * @param account The address to check
     * @return A uint256 representing current inactive fees for the address
     */
    function calcInactiveFee(address account) public view returns (uint256) {
        uint256 balance = _balances[account];
        uint256 daysInactive = daysSinceActivity(account);

        // if the account is marked inactive already, can use the snapshot balance
        if (isInactive(account)) {
            return
                _calcInactiveFee(
                    balance,
                    daysInactive,
                    _inactiveFeePerYear[account],
                    _inactiveFeePaid[account]
                );
        } else if (_shouldMarkInactive(account)) {
            // Account has not yet been marked inactive in contract, but the inactive fees will still be due.
            // Just assume snapshotBalance will be current balance after fees
            uint256 snapshotBalance = balance - (calcStorageFee(account));
            return
                _calcInactiveFee(
                    snapshotBalance, // current balance
                    daysInactive, // number of days inactive
                    _calcInactiveFeePerYear(snapshotBalance), // the inactive fee per year based on balance
                    0
                ); // fees paid already
        }
        return 0;
    }

    /**
     * @dev Calculate the amount that would clear the balance from the address
     * accounting for owed storage and transfer fees
     * accounting for storage and transfer fees
     * @param account The address to check
     * @return A uint256 representing total amount an address has available to send
     */
    function maximumTransferAmount(address account) public view returns (uint256) {
        require(account != address(0), "Zero address used");

        // Internal addresses pay no fees, so they can send their entire balance
        uint256 balanceAfterStorage = _balances[account] -
            (calcOwedFees(account));
        if (_transferFeeBasisPoints == 0 || isTransferFeeExempt(account)) {
            return balanceAfterStorage;
        }

        // Edge cases where remaining balance is 0.00000001, but is effectively 0
        if (balanceAfterStorage <= 1) {
            return 0;
        }

        // Calculate the send all amount including storage fee
        // Send All = Balance / 1.001
        // and round up 0.00000001
        uint256 divisor = TOKEN +
            (_transferFeeBasisPoints * BASIS_POINTS_MULTIPLIER);
        uint256 sendAllAmount = (((balanceAfterStorage * TOKEN) /
            divisor) +
            1);

        // Calc transfer fee on send all amount
        uint256 transFee = (sendAllAmount * (_transferFeeBasisPoints)) /
            (BASIS_POINTS_MULTIPLIER);

        // Fix to include rounding errors
        if ((sendAllAmount + transFee) > balanceAfterStorage) {
            return sendAllAmount - (1);
        }

        return sendAllAmount;
    }

    /*
     * @dev Calculate the transfer fee on an amount
     * @param value The value being sent
     * @return A uint256 representing the transfer fee on sending the value given
     */
    function calcTransferFee(address account, uint256 value)
        public
        view
        returns (uint256)
    {
        if (isTransferFeeExempt(account)) {
            return 0;
        }
        // Basis points -> decimal multiplier:
        // f(x) = x / 10,0000 (10 basis points is 0.001)
        // So transfer fee working with integers =
        // f(balance, basis) = (balance * TOKEN) / (10,000 * TOKEN / basis)
        return (value * (_transferFeeBasisPoints)) / (BASIS_POINTS_MULTIPLIER);
    }

    /*
     * @dev Calculate the storage fee for a given balance after a certain number of
     * days have passed since the last time fees were paid.
     * @param balance The current balance of the address
     * @param daysSinceStoragePaid The number days that have passed since fees where last paid
     * @return A uint256 representing the storage fee owed
     */
    function storageFee(uint256 balance, uint256 daysSinceStoragePaid)
        public
        pure
        returns (uint256)
    {
        uint256 fee = (balance * TOKEN * daysSinceStoragePaid /
            YEAR) /
            STORAGE_FEE_DENOMINATOR;
        if (fee > balance) {
            return balance;
        }
        return fee;
    }

    /**
     * @dev Approve an address to spend another addresses' tokens.
     * @param owner The address that owns the tokens.
     * @param spender The address that will spend the tokens.
     * @param value The number of tokens that can be spent.
     */
    function _approve(
        address owner,
        address spender,
        uint256 value
    ) internal {
        require(spender != address(0), "Zero address used");
        require(owner != address(0), "Zero address used");

        _allowances[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    /**
     * @dev Transfer token for a specified addresses. Transfer is modified from a
     * standard ERC20 contract in that it must also process transfer and storage fees
     * for the token itself. Additionally there are certain internal addresses that
     * are not subject to fees.
     * @param from The address to transfer from.
     * @param to The address to transfer to.
     * @param value The amount to be transferred.
     */
    function _transfer(
        address from,
        address to,
        uint256 value
    ) internal {
        require(from != address(0), "Zero address used");
        require(to != address(0), "Zero address used");
        require(to != address(this), "Cannot transfer tokens to the contract");

        // redeem address can only call burn
        require(from != _redeemAddress,
                "Redeem address can only transfer to mainnet by burning");
        // If the account was previously inactive and initiated the transfer, the
        // inactive fees and storage fees have already been paid by the time we get here
        // via the _updateActivity() call
        uint256 storageFeeFrom = calcStorageFee(from);
        uint256 storageFeeTo = 0;
        uint256 allFeeFrom = storageFeeFrom;
        uint256 balanceFromBefore = _balances[from];
        uint256 balanceToBefore = _balances[to];

        // If not sending to self can pay storage and transfer fee
        if (from != to) {
            // Need transfer fee and storage fee for receiver if not sending to self
            allFeeFrom = allFeeFrom + (calcTransferFee(from, value));
            storageFeeTo = calcStorageFee(to);
            _balances[from] = balanceFromBefore - (value) - (allFeeFrom);
            _balances[to] = balanceToBefore + (value) - (storageFeeTo);
            _balances[_feeAddress] =
                _balances[_feeAddress] +
                (allFeeFrom) +
                (storageFeeTo);
        } else {
            // Only storage fee if sending to self
            _balances[from] = balanceFromBefore - (storageFeeFrom);
            _balances[_feeAddress] = _balances[_feeAddress] + (storageFeeFrom);
        }

        // Regular Transfer
        emit Transfer(from, to, value);

        // Fee transfer on `from` address
        if (allFeeFrom > 0) {
            emit Transfer(from, _feeAddress, allFeeFrom);
            if (storageFeeFrom > 0) {
                _timeStorageFeePaid[from] = block.timestamp;
                _endGracePeriod(from);
            }
        }

        // If first time receiving coins, set the grace period
        // and start the the activity clock and storage fee clock
        if (_timeStorageFeePaid[to] == 0) {
            // We may change the grace period in the future so we want to
            // preserve it per address so there is no retroactive deduction
            _storageFeeGracePeriod[to] = _storageFeeGracePeriodDays;
            _timeLastActivity[to] = block.timestamp;
            _timeStorageFeePaid[to] = block.timestamp;
        }

        // Fee transfer on `to` address
        if (storageFeeTo > 0) {
            emit Transfer(to, _feeAddress, storageFeeTo);
            _timeStorageFeePaid[to] = block.timestamp;
            _endGracePeriod(to);
        } else if (balanceToBefore < MIN_BALANCE_FOR_FEES) {
            // MIN_BALANCE_FOR_FEES is the minimum amount in which a storage fee
            // would be due after a sigle day, so if the balance is above that,
            // the storage fee would always be greater than 0.
            //
            // This avoids the following condition:
            // 1. User receives tokens
            // 2. Users sends all but a tiny amount to another address
            // 3. A year later, the user receives more tokens. Because
            // their previous balance was super small, there were no appreciable
            // storage fee, therefore the storage fee clock was not reset
            // 4. User now owes storage fees on entire balance, as if they
            // held tokens for 1 year, instead of resetting the clock to now.
            _timeStorageFeePaid[to] = block.timestamp;
        }
    }

    /**
     * @dev Apply storage fee deduction
     * @param account The account to pay storage fees
     * @return A uint256 representing the storage fee paid
     */
    function _payStorageFee(address account) internal returns (uint256) {
        uint256 storeFee = calcStorageFee(account);
        if (storeFee == 0) {
            return 0;
        }

        // Reduce account balance and add to fee address
        _balances[account] = _balances[account] - (storeFee);
        _balances[_feeAddress] = _balances[_feeAddress] + (storeFee);
        emit Transfer(account, _feeAddress, storeFee);
        _timeStorageFeePaid[account] = block.timestamp;
        _endGracePeriod(account);
        return storeFee;
    }

    /**
     * @dev Apply inactive fee deduction
     * @param account The account to pay inactive fees
     * @return A uint256 representing the inactive fee paid
     */
    function _payInactiveFee(address account) internal returns (uint256) {
        uint256 fee = _calcInactiveFee(
            _balances[account],
            daysSinceActivity(account),
            _inactiveFeePerYear[account],
            _inactiveFeePaid[account]
        );

        if (fee == 0) {
            return 0;
        }

        _balances[account] = _balances[account] - (fee);
        _balances[_feeAddress] = _balances[_feeAddress] + (fee);
        _inactiveFeePaid[account] = _inactiveFeePaid[account] + (fee);
        emit Transfer(account, _feeAddress, fee);
        return fee;
    }

    function _shouldMarkInactive(address account) internal view returns (bool) {
        // Can only mark an account as inactive if
        //
        // 1. it's not fee exempt
        // 2. it has a balance
        // 3. it's been over INACTIVE_THRESHOLD_DAYS since last activity
        // 4. it's not already marked inactive
        // 5. the storage fees owed already consume entire balance
        if (
            account != address(0) &&
            _balances[account] > 0 &&
            daysSinceActivity(account) >= INACTIVE_THRESHOLD_DAYS &&
            !isInactive(account) &&
            !isAllFeeExempt(account) &&
            (_balances[account] - calcStorageFee(account)) > 0
        ) {
            return true;
        }
        return false;
    }

    /**
     * @dev Mark an account as inactive. The function will automatically deduct
     * owed storage fees and inactive fees in one go.
     *
     * @param account The account to mark inactive
     */
    function _setInactive(address account) internal {
        // First get owed storage fees
        uint256 storeFee = calcStorageFee(account);
        uint256 snapshotBalance = _balances[account] - (storeFee);

        // all _setInactive calls are wrapped in _shouldMarkInactive, which
        // already checks this, so we shouldn't hit this condition
        assert(snapshotBalance > 0);

        // Set the account inactive on deducted balance
        _inactiveFeePerYear[account] = _calcInactiveFeePerYear(snapshotBalance);
        emit AccountInactive(account, _inactiveFeePerYear[account]);
        uint256 inactiveFees = _calcInactiveFee(
            snapshotBalance,
            daysSinceActivity(account),
            _inactiveFeePerYear[account],
            0
        );

        // Deduct owed storage and inactive fees
        uint256 fees = storeFee + (inactiveFees);
        _balances[account] = _balances[account] - (fees);
        _balances[_feeAddress] = _balances[_feeAddress] + (fees);
        _inactiveFeePaid[account] = _inactiveFeePaid[account] + (inactiveFees);
        emit Transfer(account, _feeAddress, fees);

        // Reset storage fee clock if storage fees paid
        if (storeFee > 0) {
            _timeStorageFeePaid[account] = block.timestamp;
            _endGracePeriod(account);
        }
    }

    /**
     * @dev Update the activity clock on an account thats originated a transaction.
     * If the account has previously been marked inactive or should have been
     * marked inactive, it will opportunistically collect those owed fees.
     *
     * @param account The account to update activity
     */
    function _updateActivity(address account) internal {
        // Cache has the ability to force collecting storage and inactivity fees,
        // but in the event an address was missed, can we still detect if the
        // account was inactive when they next transact
        //
        // Here we simply set the account as being inactive, collect the previous
        // storage and inactive fees that were owed, and then reactivate the account
        if (_shouldMarkInactive(account)) {
            // Call will pay existing storage fees before marking inactive
            _setInactive(account);
        }

        // Pay remaining fees and reset fee clocks
        if (isInactive(account)) {
            _payInactiveFee(account);
            _inactiveFeePerYear[account] = 0;
            _timeStorageFeePaid[account] = block.timestamp;
            emit AccountReActive(account);
        }

        // The normal case will just hit this and update
        // the activity clock for the account
        _timeLastActivity[account] = block.timestamp;
    }

    /**
     * @dev Turn off storage fee grace period for an address the first
     * time storage fees are paid (after grace period has ended)
     * @param account The account to turn off storage fee grace period
     */
    function _endGracePeriod(address account) internal {
        _storageFeeGracePeriod[account] = 0;
    }

    /**
     * @dev Simulate the transfer from one address to another see final balances and associated fees
     * @param from address The address which you want to send tokens from
     * @param to address The address which you want to transfer to
     * @return a uint256 array of 5 values representing the
     * [0] storage fees `from`
     * [1] storage fees `to`
     * [2] transfer fee `from`
     * [3] final `from` balance
     * [4] final `to` balance
     */
    

    /**
     * @dev Calculate the amount of inactive fees due per year on the snapshot balance.
     * Should return 50 basis points or 1 token minimum.
     *
     * @param snapshotBalance The balance of the account when marked inactive
     * @return uint256 the inactive fees due each year
     */
    function _calcInactiveFeePerYear(uint256 snapshotBalance)
        internal
        pure
        returns (uint256)
    {
        uint256 inactiveFeePerYear = (snapshotBalance * (TOKEN)) /
            (INACTIVE_FEE_DENOMINATOR);
        if (inactiveFeePerYear < TOKEN) {
            return TOKEN;
        }
        return inactiveFeePerYear;
    }
    
    /**
     * @dev Calculate inactive fees due on an account
     * @param balance The current account balance
     * @param daysInactive The number of days the account has been inactive
     * @param feePerYear The inactive fee per year based on snapshot balance
     * @param paidAlready The amount of inactive fees that have been paid already
     * @return uint256 for inactive fees due
     */
    function _calcInactiveFee(
        uint256 balance,
        uint256 daysInactive,
        uint256 feePerYear,
        uint256 paidAlready
    ) internal pure returns (uint256) {
        uint256 daysDue = daysInactive - (INACTIVE_THRESHOLD_DAYS);
        uint256 totalDue = (feePerYear * (TOKEN) * (daysDue)) /
            (YEAR) /
            (TOKEN) -
            (paidAlready);

        // The fee per year can be off by 0.00000001 so we can collect
        // the final dust after 200 years
        if (totalDue > balance || balance - (totalDue) <= 200) {
            return balance;
        }
        return totalDue;
    }
}

File 2 of 9 : IFxERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
import {IERC20} from "../lib/IERC20.sol";
interface IFxERC20 is IERC20 {
    function fxManager() external returns (address);

    function connectedToken() external returns (address);

    function initialize(
        address __feeAddress,
        address __owner,
        address __fxManager_,
        address __connectedToken,
        address __redeemAddress
    ) external;

    function mint(address user, uint256 amount) external;

    function burn(address user, uint256 amount) external;
}

File 3 of 9 : AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "./Context.sol";
import "./Strings.sol";
import "./ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role, _msgSender());
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(uint160(account), 20),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 4 of 9 : IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

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

File 5 of 9 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity 0.8.11;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 6 of 9 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.11;

/*
 * @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) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 7 of 9 : Strings.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.11;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant alphabet = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

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

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

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

File 8 of 9 : ERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.11;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 9 of 9 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.11;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"feePerYear","type":"uint256"}],"name":"AccountInactive","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AccountReActive","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"addressType","type":"string"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddressChange","type":"event"},{"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":[{"indexed":false,"internalType":"string","name":"feeType","type":"string"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"FeeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawBurn","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_ENFORCER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INACTIVE_THRESHOLD_DAYS","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":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfNoFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"calcInactiveFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"calcOwedFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"calcStorageFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"calcTransferFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"connectedToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"daysSinceActivity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"daysSincePaidStorageFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"forcePayFees","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fxManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"__feeAddress","type":"address"},{"internalType":"address","name":"__feeEnforcer","type":"address"},{"internalType":"address","name":"__fxManager_","type":"address"},{"internalType":"address","name":"__connectedToken","type":"address"},{"internalType":"address","name":"__redeemAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isAllFeeExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isInactive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isStorageFeeExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isTransferFeeExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"maximumTransferAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payStorageFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"setAccountInactive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeAddress","type":"address"}],"name":"setFeeAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"setFeeExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"__fxManager","type":"address"}],"name":"setFxManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRedeemAddress","type":"address"}],"name":"setRedeemAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"setStorageFeeExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"daysGracePeriod","type":"uint256"}],"name":"setStorageFeeGracePeriodDays","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"setTransferFeeBasisPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"setTransferFeeExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"daysSinceStoragePaid","type":"uint256"}],"name":"storageFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"storageFeeGracePeriodDays","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCirculation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[],"name":"transferFeeBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"account","type":"address"}],"name":"unsetFeeExempt","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052600a60015560006010553480156200001b57600080fd5b50620000316000801b336200004860201b60201c565b62000042336200013960201b60201c565b62000985565b6200005a82826200021260201b60201c565b6200013557600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550620000da6200027c60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000801b6200015e81620001526200027c60201b60201c565b6200028460201b60201c565b6001600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b600033905090565b6200029682826200021260201b60201c565b6200034457620002c98173ffffffffffffffffffffffffffffffffffffffff1660146200034860201b62002c391760201c565b620002e48360001c60206200034860201b62002c391760201c565b604051602001620002f7929190620006c6565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200033b91906200076b565b60405180910390fd5b5050565b6060600060028360026200035d9190620007c8565b62000369919062000829565b67ffffffffffffffff81111562000385576200038462000886565b5b6040519080825280601f01601f191660200182016040528015620003b85781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110620003f357620003f2620008b5565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106200045a5762000459620008b5565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600060018460026200049c9190620007c8565b620004a8919062000829565b90505b600181111562000552577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110620004ee57620004ed620008b5565b5b1a60f81b828281518110620005085762000507620008b5565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c9450806200054a90620008e4565b9050620004ab565b506000841462000599576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620005909062000963565b60405180910390fd5b8091505092915050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000620005e6601783620005a3565b9150620005f382620005ae565b601782019050919050565b600081519050919050565b60005b83811015620006295780820151818401526020810190506200060c565b8381111562000639576000848401525b50505050565b60006200064c82620005fe565b620006588185620005a3565b93506200066a81856020860162000609565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b6000620006ae601183620005a3565b9150620006bb8262000676565b601182019050919050565b6000620006d382620005d7565b9150620006e182856200063f565b9150620006ee826200069f565b9150620006fc82846200063f565b91508190509392505050565b600082825260208201905092915050565b6000601f19601f8301169050919050565b60006200073782620005fe565b62000743818562000708565b93506200075581856020860162000609565b620007608162000719565b840191505092915050565b600060208201905081810360008301526200078781846200072a565b905092915050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000620007d5826200078f565b9150620007e2836200078f565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156200081e576200081d62000799565b5b828202905092915050565b600062000836826200078f565b915062000843836200078f565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156200087b576200087a62000799565b5b828201905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000620008f1826200078f565b9150600082141562000908576200090762000799565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b60006200094b60208362000708565b9150620009588262000913565b602082019050919050565b600060208201905081810360008301526200097e816200093c565b9050919050565b615d2980620009956000396000f3fe608060405234801561001057600080fd5b506004361061035d5760003560e01c80635aa34921116101d35780639dc29fac11610104578063d547741f116100a2578063e34611191161007c578063e346111914610af4578063e8337a2714610b24578063edd496fa14610b54578063fd1c1ae014610b705761035d565b8063d547741f14610a8c578063da40390314610aa8578063dd62ed3e14610ac45761035d565b8063a4791315116100de578063a4791315146109e0578063a9059cbb14610a10578063c344250814610a40578063cbabd8d814610a705761035d565b80639dc29fac14610976578063a217fddf14610992578063a457c2d7146109b05761035d565b80637c37080e116101715780638f9e4cf21161014b5780638f9e4cf2146108ec57806391d148541461090a57806395d89b411461093a5780639b779153146109585761035d565b80637c37080e1461088257806380a78ac7146108a05780638705fcd4146108bc5761035d565b80636a5de0f3116101ad5780636a5de0f3146107ea5780636f9423f61461081a57806370a0823114610836578063749796a5146108665761035d565b80635aa349211461076c5780635dcf8d2b1461079c5780635fcbc896146107ba5761035d565b80632a533239116102ad578063395093511161024b5780634d1e090a116102255780634d1e090a146106be5780634e7ceacb146106ee5780634fcf262c1461070c578063549b47291461073c5761035d565b806339509351146106425780633c6d47741461067257806340c10f19146106a25761035d565b8063313ce56711610287578063313ce567146105ba578063348287e7146105d857806335dd4403146105f657806336568abe146106265761035d565b80632a533239146105505780632ec3fc8e1461056e5780632f2ff15d1461059e5761035d565b806318160ddd1161031a57806323b872dd116102f457806323b872dd146104a2578063248a9ca3146104d2578063265b51501461050257806329c25d39146105205761035d565b806318160ddd14610436578063183767da146104545780631a222ac7146104725761035d565b806301ffc9a71461036257806306fdde0314610392578063095ea7b3146103b05780630a8a4914146103e0578063115a4689146103fe5780631459457a1461041a575b600080fd5b61037c60048036038101906103779190614a6f565b610ba0565b6040516103899190614ab7565b60405180910390f35b61039a610c1a565b6040516103a79190614b6b565b60405180910390f35b6103ca60048036038101906103c59190614c21565b610c53565b6040516103d79190614ab7565b60405180910390f35b6103e8610c73565b6040516103f59190614c70565b60405180910390f35b61041860048036038101906104139190614c8b565b610c9d565b005b610434600480360381019061042f9190614cb8565b610d22565b005b61043e611057565b60405161044b9190614d42565b60405180910390f35b61045c611061565b6040516104699190614d42565b60405180910390f35b61048c60048036038101906104879190614c8b565b61106b565b6040516104999190614d42565b60405180910390f35b6104bc60048036038101906104b79190614d5d565b6111af565b6040516104c99190614ab7565b60405180910390f35b6104ec60048036038101906104e79190614de6565b611262565b6040516104f99190614e22565b60405180910390f35b61050a611281565b6040516105179190614c70565b60405180910390f35b61053a60048036038101906105359190614c8b565b6112ab565b6040516105479190614d42565b60405180910390f35b61055861135e565b6040516105659190614d42565b60405180910390f35b61058860048036038101906105839190614c8b565b611368565b6040516105959190614ab7565b60405180910390f35b6105b860048036038101906105b39190614e3d565b6115b8565b005b6105c26115e1565b6040516105cf9190614e99565b60405180910390f35b6105e06115e6565b6040516105ed9190614e22565b60405180910390f35b610610600480360381019061060b9190614c8b565b61160a565b60405161061d9190614d42565b60405180910390f35b610640600480360381019061063b9190614e3d565b6116ce565b005b61065c60048036038101906106579190614c21565b611751565b6040516106699190614ab7565b60405180910390f35b61068c60048036038101906106879190614c21565b6117f8565b6040516106999190614d42565b60405180910390f35b6106bc60048036038101906106b79190614c21565b611835565b005b6106d860048036038101906106d39190614eb4565b611ad4565b6040516106e59190614d42565b60405180910390f35b6106f6611b2d565b6040516107039190614c70565b60405180910390f35b61072660048036038101906107219190614c8b565b611b57565b6040516107339190614d42565b60405180910390f35b61075660048036038101906107519190614c8b565b611ba0565b6040516107639190614ab7565b60405180910390f35b61078660048036038101906107819190614c8b565b611bf6565b6040516107939190614d42565b60405180910390f35b6107a4611c1b565b6040516107b19190614d42565b60405180910390f35b6107d460048036038101906107cf9190614c8b565b611c25565b6040516107e19190614ab7565b60405180910390f35b61080460048036038101906107ff9190614c8b565b611c70565b6040516108119190614ab7565b60405180910390f35b610834600480360381019061082f9190614c8b565b611cff565b005b610850600480360381019061084b9190614c8b565b611d70565b60405161085d9190614d42565b60405180910390f35b610880600480360381019061087b9190614c8b565b611d82565b005b61088a611e4b565b6040516108979190614d42565b60405180910390f35b6108ba60048036038101906108b59190614ef4565b611e51565b005b6108d660048036038101906108d19190614c8b565b611ea8565b6040516108e39190614ab7565b60405180910390f35b6108f4611ff1565b6040516109019190614ab7565b60405180910390f35b610924600480360381019061091f9190614e3d565b61200d565b6040516109319190614ab7565b60405180910390f35b610942612077565b60405161094f9190614b6b565b60405180910390f35b6109606120b0565b60405161096d9190614c70565b60405180910390f35b610990600480360381019061098b9190614c21565b6120da565b005b61099a61230e565b6040516109a79190614e22565b60405180910390f35b6109ca60048036038101906109c59190614c21565b612315565b6040516109d79190614ab7565b60405180910390f35b6109fa60048036038101906109f59190614c8b565b6123bc565b604051610a079190614ab7565b60405180910390f35b610a2a6004803603810190610a259190614c21565b612467565b604051610a379190614ab7565b60405180910390f35b610a5a6004803603810190610a559190614c8b565b612521565b604051610a679190614d42565b60405180910390f35b610a8a6004803603810190610a859190614c8b565b6126c4565b005b610aa66004803603810190610aa19190614e3d565b61278d565b005b610ac26004803603810190610abd9190614ef4565b6127b6565b005b610ade6004803603810190610ad99190614f21565b612851565b604051610aeb9190614d42565b60405180910390f35b610b0e6004803603810190610b099190614c8b565b6128d8565b604051610b1b9190614ab7565b60405180910390f35b610b3e6004803603810190610b399190614c8b565b612a21565b604051610b4b9190614ab7565b60405180910390f35b610b6e6004803603810190610b699190614c8b565b612a77565b005b610b8a6004803603810190610b859190614c8b565b612ae8565b604051610b979190614d42565b60405180910390f35b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610c135750610c1282612e75565b5b9050919050565b6040518060400160405280600a81526020017f434143484520476f6c640000000000000000000000000000000000000000000081525081565b6000610c5e33612edf565b610c69338484613023565b6001905092915050565b6000600f60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000801b610cb281610cad6131ee565b6131f6565b81600e60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610d1e600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611d82565b5050565b6000801b610d3781610d326131ee565b6131f6565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614158015610da15750600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614155b610de0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dd790614fad565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148015610e8c5750600073ffffffffffffffffffffffffffffffffffffffff16600f60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b610ecb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ec290615019565b60405180910390fd5b83600e60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600f60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555085600c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610ff97f28bf9dc89136e09e32491ee8523d449c14e9c2f5c4fb97b2669bafb5e1434b2986613293565b611024600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611d82565b61104f600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611d82565b505050505050565b6000600b54905090565b6000600154905090565b600080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060006110bb846112ab565b90506110c684611c25565b1561115e576111558282600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600660008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054613373565b925050506111aa565b61116784613403565b156111a357600061117785612ae8565b836111829190615068565b9050611199818361119284613530565b6000613373565b93505050506111aa565b6000925050505b919050565b60006111ba33612edf565b6111c5848484613578565b611257843384600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546112529190615068565b613023565b600190509392505050565b6000806000838152602001908152602001600020600101549050919050565b6000600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414156112fd5760009050611359565b62015180600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020544261134c9190615068565b61135691906150cb565b90505b919050565b6000601054905090565b60007f28bf9dc89136e09e32491ee8523d449c14e9c2f5c4fb97b2669bafb5e1434b2961139c816113976131ee565b6131f6565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561140c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161140390615148565b60405180910390fd5b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541161148e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611485906151da565b60405180910390fd5b61149783611c25565b156114f25760006114a784613ea1565b9050600081116114ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e390615246565b60405180910390fd5b506115ae565b6114fb83613403565b1561150e5761150983614209565b6115ad565b61016d61151a8461160a565b101561155b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611552906152d8565b60405180910390fd5b60006115668461468a565b9050600081116115ab576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115a29061536a565b60405180910390fd5b505b5b6001915050919050565b6115c182611262565b6115d2816115cd6131ee565b6131f6565b6115dc8383613293565b505050565b600881565b7f28bf9dc89136e09e32491ee8523d449c14e9c2f5c4fb97b2669bafb5e1434b2981565b600061161582611c25565b8061165f57506000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054145b1561166d57600090506116c9565b62015180600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054426116bc9190615068565b6116c691906150cb565b90505b919050565b6116d66131ee565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161173a906153fc565b60405180910390fd5b61174d82826148e9565b5050565b600061175c33612edf565b6117ee338484600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546117e9919061541c565b613023565b6001905092915050565b600061180383611ba0565b15611811576000905061182f565b612710600154836118229190615472565b61182c91906150cb565b90505b92915050565b600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146118c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118bc90615518565b60405180910390fd5b80600b546118d3919061541c565b600b8190555060006118e483612ae8565b90508082600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611932919061541c565b61193c9190615068565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507ff3cea5493d790af0133817606f7350a91d7f154ea52eaa79d179d4d231e5010282846040516119b0929190615538565b60405180910390a16000600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541415611acf57601054600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555042600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555042600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b505050565b6000806409502f900061016d846305f5e10087611af19190615472565b611afb9190615472565b611b0591906150cb565b611b0f91906150cb565b905083811115611b225783915050611b27565b809150505b92915050565b6000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000611c018261106b565b611c0a83612ae8565b611c14919061541c565b9050919050565b6000600b54905090565b600080600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054119050919050565b60007f28bf9dc89136e09e32491ee8523d449c14e9c2f5c4fb97b2669bafb5e1434b29611ca481611c9f6131ee565b6131f6565b611cad83613403565b611cec576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ce3906155d3565b60405180910390fd5b611cf583614209565b6001915050919050565b6000801b611d1481611d0f6131ee565b6131f6565b6001600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6000611d7b82612521565b9050919050565b6000801b611d9781611d926131ee565b6131f6565b6001600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b61044781565b6000801b611e6681611e616131ee565b6131f6565b816010819055507f9ce010994eb307d3d21dc4d32471b192947a8e6b07f597325e8ed94d53685a6982604051611e9c919061563f565b60405180910390a15050565b60008060001b611ebf81611eba6131ee565b6131f6565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611f2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f2690615148565b60405180910390fd5b82600c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611f9b600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611d82565b8273ffffffffffffffffffffffffffffffffffffffff167ff01df6097899c4c56c975ef84404392d5cf3d3664ba387b392c13e5e2974527b604051611fdf906156b9565b60405180910390a26001915050919050565b6000611ffc33612edf565b6120053361468a565b506001905090565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6040518060400160405280600381526020017f434754000000000000000000000000000000000000000000000000000000000081525081565b6000600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461216a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161216190615518565b60405180910390fd5b60006121768333612851565b9050818110156121bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121b29061574b565b60405180910390fd5b6121d1833384846121cc9190615068565b613023565b81600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600b546122649190615068565b600b819055507ff602ae17994c0ad90feed837a60f3d393186af2c99ea73dfb1fb0924ebf04e01838360405161229b92919061576b565b60405180910390a1600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516123019190614d42565b60405180910390a3505050565b6000801b81565b600061232033612edf565b6123b2338484600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546123ad9190615068565b613023565b6001905092915050565b6000600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1680156124605750600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b9050919050565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156124eb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124e290615806565b60405180910390fd5b6124f433612edf565b6124fd83613403565b1561250c5761250b83614209565b5b612517338484613578565b6001905092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612592576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161258990615148565b60405180910390fd5b600061259d83611bf6565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546125e79190615068565b9050600060015414806125ff57506125fe83611ba0565b5b1561260d57809150506126bf565b6001811161261f5760009150506126bf565b60006127106001546126319190615472565b6305f5e100612640919061541c565b905060006001826305f5e100856126579190615472565b61266191906150cb565b61266b919061541c565b90506000612710600154836126809190615472565b61268a91906150cb565b9050838183612699919061541c565b11156126b7576001826126ac9190615068565b9450505050506126bf565b819450505050505b919050565b6000801b6126d9816126d46131ee565b6131f6565b6000600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b61279682611262565b6127a7816127a26131ee565b6131f6565b6127b183836148e9565b505050565b6000801b6127cb816127c66131ee565b6131f6565b600a82111561280f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161280690615898565b60405180910390fd5b7f9ce010994eb307d3d21dc4d32471b192947a8e6b07f597325e8ed94d53685a698260405161283e9190615904565b60405180910390a1816001819055505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b60008060001b6128ef816128ea6131ee565b6131f6565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561295f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161295690615148565b60405180910390fd5b82600d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506129cb600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611d82565b8273ffffffffffffffffffffffffffffffffffffffff167ff01df6097899c4c56c975ef84404392d5cf3d3664ba387b392c13e5e2974527b604051612a0f9061597e565b60405180910390a26001915050919050565b6000600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000801b612a8c81612a876131ee565b6131f6565b6001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b600080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050612b3683611c25565b80612b465750612b4583612a21565b5b80612b515750600081145b15612b60576000915050612c34565b6000612b6b8461160a565b90506000612b78856112ab565b90506000600a60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000811115612be85780831115612be2578083612bdb9190615068565b9250612be7565b600092505b5b6000831415612bfe576000945050505050612c34565b6104478210612c235761044782612c159190615068565b83612c209190615068565b92505b612c2d8484611ad4565b9450505050505b919050565b606060006002836002612c4c9190615472565b612c56919061541c565b67ffffffffffffffff811115612c6f57612c6e61599e565b5b6040519080825280601f01601f191660200182016040528015612ca15781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612cd957612cd86159cd565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612d3d57612d3c6159cd565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002612d7d9190615472565b612d87919061541c565b90505b6001811115612e27577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110612dc957612dc86159cd565b5b1a60f81b828281518110612de057612ddf6159cd565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c945080612e20906159fc565b9050612d8a565b5060008414612e6b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e6290615a72565b60405180910390fd5b8091505092915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b612ee881613403565b15612ef757612ef681614209565b5b612f0081611c25565b15612fdc57612f0e81613ea1565b506000600760008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555042600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508073ffffffffffffffffffffffffffffffffffffffff167f96cc51e6ab9b6970cc6fc055179c755849347faa4f703098b52724f2a76ad95660405160405180910390a25b42600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613093576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161308a90615148565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415613103576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130fa90615148565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516131e19190614d42565b60405180910390a3505050565b600033905090565b613200828261200d565b61328f576132258173ffffffffffffffffffffffffffffffffffffffff166014612c39565b6132338360001c6020612c39565b604051602001613244929190615b66565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016132869190614b6b565b60405180910390fd5b5050565b61329d828261200d565b61336f57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506133146131ee565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600080610447856133849190615068565b90506000836305f5e10061016d846305f5e100896133a29190615472565b6133ac9190615472565b6133b691906150cb565b6133c091906150cb565b6133ca9190615068565b9050868111806133e6575060c881886133e39190615068565b11155b156133f55786925050506133fb565b80925050505b949350505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561348057506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054115b80156134965750610447613493836112ab565b10155b80156134a857506134a682611c25565b155b80156134ba57506134b8826123bc565b155b8015613518575060006134cc83612ae8565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546135169190615068565b115b15613526576001905061352b565b600090505b919050565b6000806404a817c8006305f5e100846135499190615472565b61355391906150cb565b90506305f5e10081101561356e576305f5e100915050613573565b809150505b919050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156135e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016135df90615148565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161364f90615148565b60405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156136c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016136be90615c12565b60405180910390fd5b600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415613758576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161374f90615ca4565b60405180910390fd5b600061376384612ae8565b90506000808290506000600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16146139de5761383088876117f8565b8361383b919061541c565b925061384687612ae8565b93508286836138559190615068565b61385f9190615068565b600260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508386826138af919061541c565b6138b99190615068565b600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550838360026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461396a919061541c565b613974919061541c565b60026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550613b00565b84826139ea9190615068565b600260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508460026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054613a9a919061541c565b60026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88604051613b5d9190614d42565b60405180910390a36000831115613c4d57600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051613bed9190614d42565b60405180910390a36000851115613c4c5742600460008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550613c4b886149ca565b5b5b6000600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541415613d6457601054600a60008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555042600560008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555042600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b6000841115613e4657600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef86604051613dec9190614d42565b60405180910390a342600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550613e41876149ca565b613e97565b62023a50811015613e965742600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5b5050505050505050565b600080613f75600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054613ef0856112ab565b600760008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600660008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054613373565b90506000811415613f8a576000915050614204565b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054613fd59190615068565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054614085919061541c565b60026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054614135919061541c565b600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516141f79190614d42565b60405180910390a3809150505b919050565b600061421482612ae8565b9050600081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546142639190615068565b90506000811161427657614275615cc4565b5b61427f81613530565b600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff167f481010afe95c4aad3901e4d3948ca845e8772b11b72f77bf2dd74a9940e21a21600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040516143479190614d42565b60405180910390a260006143a58261435e866112ab565b600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546000613373565b9050600081846143b5919061541c565b905080600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546144029190615068565b600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546144b2919061541c565b60026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054614562919061541c565b600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516146249190614d42565b60405180910390a360008411156146835742600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550614682856149ca565b5b5050505050565b60008061469683612ae8565b905060008114156146ab5760009150506148e4565b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546146f69190615068565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546147a6919061541c565b60026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161488a9190614d42565b60405180910390a342600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506148df836149ca565b809150505b919050565b6148f3828261200d565b156149c657600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555061496b6131ee565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000600a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b614a4c81614a17565b8114614a5757600080fd5b50565b600081359050614a6981614a43565b92915050565b600060208284031215614a8557614a84614a12565b5b6000614a9384828501614a5a565b91505092915050565b60008115159050919050565b614ab181614a9c565b82525050565b6000602082019050614acc6000830184614aa8565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015614b0c578082015181840152602081019050614af1565b83811115614b1b576000848401525b50505050565b6000601f19601f8301169050919050565b6000614b3d82614ad2565b614b478185614add565b9350614b57818560208601614aee565b614b6081614b21565b840191505092915050565b60006020820190508181036000830152614b858184614b32565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000614bb882614b8d565b9050919050565b614bc881614bad565b8114614bd357600080fd5b50565b600081359050614be581614bbf565b92915050565b6000819050919050565b614bfe81614beb565b8114614c0957600080fd5b50565b600081359050614c1b81614bf5565b92915050565b60008060408385031215614c3857614c37614a12565b5b6000614c4685828601614bd6565b9250506020614c5785828601614c0c565b9150509250929050565b614c6a81614bad565b82525050565b6000602082019050614c856000830184614c61565b92915050565b600060208284031215614ca157614ca0614a12565b5b6000614caf84828501614bd6565b91505092915050565b600080600080600060a08688031215614cd457614cd3614a12565b5b6000614ce288828901614bd6565b9550506020614cf388828901614bd6565b9450506040614d0488828901614bd6565b9350506060614d1588828901614bd6565b9250506080614d2688828901614bd6565b9150509295509295909350565b614d3c81614beb565b82525050565b6000602082019050614d576000830184614d33565b92915050565b600080600060608486031215614d7657614d75614a12565b5b6000614d8486828701614bd6565b9350506020614d9586828701614bd6565b9250506040614da686828701614c0c565b9150509250925092565b6000819050919050565b614dc381614db0565b8114614dce57600080fd5b50565b600081359050614de081614dba565b92915050565b600060208284031215614dfc57614dfb614a12565b5b6000614e0a84828501614dd1565b91505092915050565b614e1c81614db0565b82525050565b6000602082019050614e376000830184614e13565b92915050565b60008060408385031215614e5457614e53614a12565b5b6000614e6285828601614dd1565b9250506020614e7385828601614bd6565b9150509250929050565b600060ff82169050919050565b614e9381614e7d565b82525050565b6000602082019050614eae6000830184614e8a565b92915050565b60008060408385031215614ecb57614eca614a12565b5b6000614ed985828601614c0c565b9250506020614eea85828601614c0c565b9150509250929050565b600060208284031215614f0a57614f09614a12565b5b6000614f1884828501614c0c565b91505092915050565b60008060408385031215614f3857614f37614a12565b5b6000614f4685828601614bd6565b9250506020614f5785828601614bd6565b9150509250929050565b7f5a65726f206164647265737320696e7075747465640000000000000000000000600082015250565b6000614f97601583614add565b9150614fa282614f61565b602082019050919050565b60006020820190508181036000830152614fc681614f8a565b9050919050565b7f546f6b656e20697320616c726561647920696e697469616c697a656400000000600082015250565b6000615003601c83614add565b915061500e82614fcd565b602082019050919050565b6000602082019050818103600083015261503281614ff6565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061507382614beb565b915061507e83614beb565b92508282101561509157615090615039565b5b828203905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006150d682614beb565b91506150e183614beb565b9250826150f1576150f061509c565b5b828204905092915050565b7f5a65726f20616464726573732075736564000000000000000000000000000000600082015250565b6000615132601183614add565b915061513d826150fc565b602082019050919050565b6000602082019050818103600083015261516181615125565b9050919050565b7f4163636f756e7420686173206e6f2062616c616e63652c2063616e6e6f74206660008201527f6f72636520706179696e67206665657300000000000000000000000000000000602082015250565b60006151c4603083614add565b91506151cf82615168565b604082019050919050565b600060208201905081810360008301526151f3816151b7565b9050919050565b7f4572726f72206e6f206665657320706169642100000000000000000000000000600082015250565b6000615230601383614add565b915061523b826151fa565b602082019050919050565b6000602082019050818103600083015261525f81615223565b9050919050565b7f4163636f756e742068617320706169642073746f726167652066656573206d6f60008201527f726520726563656e746c79207468616e20333635206461797300000000000000602082015250565b60006152c2603983614add565b91506152cd82615266565b604082019050919050565b600060208201905081810360008301526152f1816152b5565b9050919050565b7f4e6f206170707265636961626c652073746f726167652066656573206475652c60008201527f2077696c6c20726566756e642067617300000000000000000000000000000000602082015250565b6000615354603083614add565b915061535f826152f8565b604082019050919050565b6000602082019050818103600083015261538381615347565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b60006153e6602f83614add565b91506153f18261538a565b604082019050919050565b60006020820190508181036000830152615415816153d9565b9050919050565b600061542782614beb565b915061543283614beb565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561546757615466615039565b5b828201905092915050565b600061547d82614beb565b915061548883614beb565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156154c1576154c0615039565b5b828202905092915050565b7f496e76616c69642073656e646572000000000000000000000000000000000000600082015250565b6000615502600e83614add565b915061550d826154cc565b602082019050919050565b60006020820190508181036000830152615531816154f5565b9050919050565b600060408201905061554d6000830185614d33565b61555a6020830184614c61565b9392505050565b7f4163636f756e74206e6f7420656c696769626c6520746f206265206d61726b6560008201527f6420696e61637469766500000000000000000000000000000000000000000000602082015250565b60006155bd602a83614add565b91506155c882615561565b604082019050919050565b600060208201905081810360008301526155ec816155b0565b9050919050565b7f53746f726167652046656520477261636520506572696f642044617973000000600082015250565b6000615629601d83614add565b9150615634826155f3565b602082019050919050565b600060408201905081810360008301526156588161561c565b90506156676020830184614d33565b92915050565b7f4665652041646472657373000000000000000000000000000000000000000000600082015250565b60006156a3600b83614add565b91506156ae8261566d565b602082019050919050565b600060208201905081810360008301526156d281615696565b9050919050565b7f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f7760008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000615735602483614add565b9150615740826156d9565b604082019050919050565b6000602082019050818103600083015261576481615728565b9050919050565b60006040820190506157806000830185614c61565b61578d6020830184614d33565b9392505050565b7f496e73756666696369656e742042616c616e636520546f204d616b652054686960008201527f73205472616e7366657200000000000000000000000000000000000000000000602082015250565b60006157f0602a83614add565b91506157fb82615794565b604082019050919050565b6000602082019050818103600083015261581f816157e3565b9050919050565b7f5472616e736665722066656520626173697320706f696e7473206d757374206260008201527f6520616e20696e7465676572206265747765656e203020616e64203130000000602082015250565b6000615882603d83614add565b915061588d82615826565b604082019050919050565b600060208201905081810360008301526158b181615875565b9050919050565b7f5472616e736665722046656520426173697320506f696e747300000000000000600082015250565b60006158ee601983614add565b91506158f9826158b8565b602082019050919050565b6000604082019050818103600083015261591d816158e1565b905061592c6020830184614d33565b92915050565b7f52656465656d2041646472657373000000000000000000000000000000000000600082015250565b6000615968600e83614add565b915061597382615932565b602082019050919050565b600060208201905081810360008301526159978161595b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000615a0782614beb565b91506000821415615a1b57615a1a615039565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b6000615a5c602083614add565b9150615a6782615a26565b602082019050919050565b60006020820190508181036000830152615a8b81615a4f565b9050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000615ad3601783615a92565b9150615ade82615a9d565b601782019050919050565b6000615af482614ad2565b615afe8185615a92565b9350615b0e818560208601614aee565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b6000615b50601183615a92565b9150615b5b82615b1a565b601182019050919050565b6000615b7182615ac6565b9150615b7d8285615ae9565b9150615b8882615b43565b9150615b948284615ae9565b91508190509392505050565b7f43616e6e6f74207472616e7366657220746f6b656e7320746f2074686520636f60008201527f6e74726163740000000000000000000000000000000000000000000000000000602082015250565b6000615bfc602683614add565b9150615c0782615ba0565b604082019050919050565b60006020820190508181036000830152615c2b81615bef565b9050919050565b7f52656465656d20616464726573732063616e206f6e6c79207472616e7366657260008201527f20746f206d61696e6e6574206279206275726e696e6700000000000000000000602082015250565b6000615c8e603683614add565b9150615c9982615c32565b604082019050919050565b60006020820190508181036000830152615cbd81615c81565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fdfea2646970667358221220f45ab8c4546b6e66a1a84059dc3e65fd6f414e2d06b3715f94791dc2c7e77c9c64736f6c634300080b0033

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061035d5760003560e01c80635aa34921116101d35780639dc29fac11610104578063d547741f116100a2578063e34611191161007c578063e346111914610af4578063e8337a2714610b24578063edd496fa14610b54578063fd1c1ae014610b705761035d565b8063d547741f14610a8c578063da40390314610aa8578063dd62ed3e14610ac45761035d565b8063a4791315116100de578063a4791315146109e0578063a9059cbb14610a10578063c344250814610a40578063cbabd8d814610a705761035d565b80639dc29fac14610976578063a217fddf14610992578063a457c2d7146109b05761035d565b80637c37080e116101715780638f9e4cf21161014b5780638f9e4cf2146108ec57806391d148541461090a57806395d89b411461093a5780639b779153146109585761035d565b80637c37080e1461088257806380a78ac7146108a05780638705fcd4146108bc5761035d565b80636a5de0f3116101ad5780636a5de0f3146107ea5780636f9423f61461081a57806370a0823114610836578063749796a5146108665761035d565b80635aa349211461076c5780635dcf8d2b1461079c5780635fcbc896146107ba5761035d565b80632a533239116102ad578063395093511161024b5780634d1e090a116102255780634d1e090a146106be5780634e7ceacb146106ee5780634fcf262c1461070c578063549b47291461073c5761035d565b806339509351146106425780633c6d47741461067257806340c10f19146106a25761035d565b8063313ce56711610287578063313ce567146105ba578063348287e7146105d857806335dd4403146105f657806336568abe146106265761035d565b80632a533239146105505780632ec3fc8e1461056e5780632f2ff15d1461059e5761035d565b806318160ddd1161031a57806323b872dd116102f457806323b872dd146104a2578063248a9ca3146104d2578063265b51501461050257806329c25d39146105205761035d565b806318160ddd14610436578063183767da146104545780631a222ac7146104725761035d565b806301ffc9a71461036257806306fdde0314610392578063095ea7b3146103b05780630a8a4914146103e0578063115a4689146103fe5780631459457a1461041a575b600080fd5b61037c60048036038101906103779190614a6f565b610ba0565b6040516103899190614ab7565b60405180910390f35b61039a610c1a565b6040516103a79190614b6b565b60405180910390f35b6103ca60048036038101906103c59190614c21565b610c53565b6040516103d79190614ab7565b60405180910390f35b6103e8610c73565b6040516103f59190614c70565b60405180910390f35b61041860048036038101906104139190614c8b565b610c9d565b005b610434600480360381019061042f9190614cb8565b610d22565b005b61043e611057565b60405161044b9190614d42565b60405180910390f35b61045c611061565b6040516104699190614d42565b60405180910390f35b61048c60048036038101906104879190614c8b565b61106b565b6040516104999190614d42565b60405180910390f35b6104bc60048036038101906104b79190614d5d565b6111af565b6040516104c99190614ab7565b60405180910390f35b6104ec60048036038101906104e79190614de6565b611262565b6040516104f99190614e22565b60405180910390f35b61050a611281565b6040516105179190614c70565b60405180910390f35b61053a60048036038101906105359190614c8b565b6112ab565b6040516105479190614d42565b60405180910390f35b61055861135e565b6040516105659190614d42565b60405180910390f35b61058860048036038101906105839190614c8b565b611368565b6040516105959190614ab7565b60405180910390f35b6105b860048036038101906105b39190614e3d565b6115b8565b005b6105c26115e1565b6040516105cf9190614e99565b60405180910390f35b6105e06115e6565b6040516105ed9190614e22565b60405180910390f35b610610600480360381019061060b9190614c8b565b61160a565b60405161061d9190614d42565b60405180910390f35b610640600480360381019061063b9190614e3d565b6116ce565b005b61065c60048036038101906106579190614c21565b611751565b6040516106699190614ab7565b60405180910390f35b61068c60048036038101906106879190614c21565b6117f8565b6040516106999190614d42565b60405180910390f35b6106bc60048036038101906106b79190614c21565b611835565b005b6106d860048036038101906106d39190614eb4565b611ad4565b6040516106e59190614d42565b60405180910390f35b6106f6611b2d565b6040516107039190614c70565b60405180910390f35b61072660048036038101906107219190614c8b565b611b57565b6040516107339190614d42565b60405180910390f35b61075660048036038101906107519190614c8b565b611ba0565b6040516107639190614ab7565b60405180910390f35b61078660048036038101906107819190614c8b565b611bf6565b6040516107939190614d42565b60405180910390f35b6107a4611c1b565b6040516107b19190614d42565b60405180910390f35b6107d460048036038101906107cf9190614c8b565b611c25565b6040516107e19190614ab7565b60405180910390f35b61080460048036038101906107ff9190614c8b565b611c70565b6040516108119190614ab7565b60405180910390f35b610834600480360381019061082f9190614c8b565b611cff565b005b610850600480360381019061084b9190614c8b565b611d70565b60405161085d9190614d42565b60405180910390f35b610880600480360381019061087b9190614c8b565b611d82565b005b61088a611e4b565b6040516108979190614d42565b60405180910390f35b6108ba60048036038101906108b59190614ef4565b611e51565b005b6108d660048036038101906108d19190614c8b565b611ea8565b6040516108e39190614ab7565b60405180910390f35b6108f4611ff1565b6040516109019190614ab7565b60405180910390f35b610924600480360381019061091f9190614e3d565b61200d565b6040516109319190614ab7565b60405180910390f35b610942612077565b60405161094f9190614b6b565b60405180910390f35b6109606120b0565b60405161096d9190614c70565b60405180910390f35b610990600480360381019061098b9190614c21565b6120da565b005b61099a61230e565b6040516109a79190614e22565b60405180910390f35b6109ca60048036038101906109c59190614c21565b612315565b6040516109d79190614ab7565b60405180910390f35b6109fa60048036038101906109f59190614c8b565b6123bc565b604051610a079190614ab7565b60405180910390f35b610a2a6004803603810190610a259190614c21565b612467565b604051610a379190614ab7565b60405180910390f35b610a5a6004803603810190610a559190614c8b565b612521565b604051610a679190614d42565b60405180910390f35b610a8a6004803603810190610a859190614c8b565b6126c4565b005b610aa66004803603810190610aa19190614e3d565b61278d565b005b610ac26004803603810190610abd9190614ef4565b6127b6565b005b610ade6004803603810190610ad99190614f21565b612851565b604051610aeb9190614d42565b60405180910390f35b610b0e6004803603810190610b099190614c8b565b6128d8565b604051610b1b9190614ab7565b60405180910390f35b610b3e6004803603810190610b399190614c8b565b612a21565b604051610b4b9190614ab7565b60405180910390f35b610b6e6004803603810190610b699190614c8b565b612a77565b005b610b8a6004803603810190610b859190614c8b565b612ae8565b604051610b979190614d42565b60405180910390f35b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610c135750610c1282612e75565b5b9050919050565b6040518060400160405280600a81526020017f434143484520476f6c640000000000000000000000000000000000000000000081525081565b6000610c5e33612edf565b610c69338484613023565b6001905092915050565b6000600f60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000801b610cb281610cad6131ee565b6131f6565b81600e60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610d1e600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611d82565b5050565b6000801b610d3781610d326131ee565b6131f6565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614158015610da15750600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614155b610de0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dd790614fad565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148015610e8c5750600073ffffffffffffffffffffffffffffffffffffffff16600f60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b610ecb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ec290615019565b60405180910390fd5b83600e60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600f60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555085600c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610ff97f28bf9dc89136e09e32491ee8523d449c14e9c2f5c4fb97b2669bafb5e1434b2986613293565b611024600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611d82565b61104f600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611d82565b505050505050565b6000600b54905090565b6000600154905090565b600080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060006110bb846112ab565b90506110c684611c25565b1561115e576111558282600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600660008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054613373565b925050506111aa565b61116784613403565b156111a357600061117785612ae8565b836111829190615068565b9050611199818361119284613530565b6000613373565b93505050506111aa565b6000925050505b919050565b60006111ba33612edf565b6111c5848484613578565b611257843384600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546112529190615068565b613023565b600190509392505050565b6000806000838152602001908152602001600020600101549050919050565b6000600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414156112fd5760009050611359565b62015180600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020544261134c9190615068565b61135691906150cb565b90505b919050565b6000601054905090565b60007f28bf9dc89136e09e32491ee8523d449c14e9c2f5c4fb97b2669bafb5e1434b2961139c816113976131ee565b6131f6565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561140c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161140390615148565b60405180910390fd5b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541161148e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611485906151da565b60405180910390fd5b61149783611c25565b156114f25760006114a784613ea1565b9050600081116114ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e390615246565b60405180910390fd5b506115ae565b6114fb83613403565b1561150e5761150983614209565b6115ad565b61016d61151a8461160a565b101561155b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611552906152d8565b60405180910390fd5b60006115668461468a565b9050600081116115ab576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115a29061536a565b60405180910390fd5b505b5b6001915050919050565b6115c182611262565b6115d2816115cd6131ee565b6131f6565b6115dc8383613293565b505050565b600881565b7f28bf9dc89136e09e32491ee8523d449c14e9c2f5c4fb97b2669bafb5e1434b2981565b600061161582611c25565b8061165f57506000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054145b1561166d57600090506116c9565b62015180600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054426116bc9190615068565b6116c691906150cb565b90505b919050565b6116d66131ee565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161173a906153fc565b60405180910390fd5b61174d82826148e9565b5050565b600061175c33612edf565b6117ee338484600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546117e9919061541c565b613023565b6001905092915050565b600061180383611ba0565b15611811576000905061182f565b612710600154836118229190615472565b61182c91906150cb565b90505b92915050565b600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146118c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118bc90615518565b60405180910390fd5b80600b546118d3919061541c565b600b8190555060006118e483612ae8565b90508082600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611932919061541c565b61193c9190615068565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507ff3cea5493d790af0133817606f7350a91d7f154ea52eaa79d179d4d231e5010282846040516119b0929190615538565b60405180910390a16000600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541415611acf57601054600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555042600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555042600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b505050565b6000806409502f900061016d846305f5e10087611af19190615472565b611afb9190615472565b611b0591906150cb565b611b0f91906150cb565b905083811115611b225783915050611b27565b809150505b92915050565b6000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000611c018261106b565b611c0a83612ae8565b611c14919061541c565b9050919050565b6000600b54905090565b600080600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054119050919050565b60007f28bf9dc89136e09e32491ee8523d449c14e9c2f5c4fb97b2669bafb5e1434b29611ca481611c9f6131ee565b6131f6565b611cad83613403565b611cec576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ce3906155d3565b60405180910390fd5b611cf583614209565b6001915050919050565b6000801b611d1481611d0f6131ee565b6131f6565b6001600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6000611d7b82612521565b9050919050565b6000801b611d9781611d926131ee565b6131f6565b6001600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b61044781565b6000801b611e6681611e616131ee565b6131f6565b816010819055507f9ce010994eb307d3d21dc4d32471b192947a8e6b07f597325e8ed94d53685a6982604051611e9c919061563f565b60405180910390a15050565b60008060001b611ebf81611eba6131ee565b6131f6565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611f2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f2690615148565b60405180910390fd5b82600c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611f9b600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611d82565b8273ffffffffffffffffffffffffffffffffffffffff167ff01df6097899c4c56c975ef84404392d5cf3d3664ba387b392c13e5e2974527b604051611fdf906156b9565b60405180910390a26001915050919050565b6000611ffc33612edf565b6120053361468a565b506001905090565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6040518060400160405280600381526020017f434754000000000000000000000000000000000000000000000000000000000081525081565b6000600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461216a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161216190615518565b60405180910390fd5b60006121768333612851565b9050818110156121bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121b29061574b565b60405180910390fd5b6121d1833384846121cc9190615068565b613023565b81600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600b546122649190615068565b600b819055507ff602ae17994c0ad90feed837a60f3d393186af2c99ea73dfb1fb0924ebf04e01838360405161229b92919061576b565b60405180910390a1600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516123019190614d42565b60405180910390a3505050565b6000801b81565b600061232033612edf565b6123b2338484600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546123ad9190615068565b613023565b6001905092915050565b6000600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1680156124605750600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b9050919050565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156124eb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124e290615806565b60405180910390fd5b6124f433612edf565b6124fd83613403565b1561250c5761250b83614209565b5b612517338484613578565b6001905092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612592576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161258990615148565b60405180910390fd5b600061259d83611bf6565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546125e79190615068565b9050600060015414806125ff57506125fe83611ba0565b5b1561260d57809150506126bf565b6001811161261f5760009150506126bf565b60006127106001546126319190615472565b6305f5e100612640919061541c565b905060006001826305f5e100856126579190615472565b61266191906150cb565b61266b919061541c565b90506000612710600154836126809190615472565b61268a91906150cb565b9050838183612699919061541c565b11156126b7576001826126ac9190615068565b9450505050506126bf565b819450505050505b919050565b6000801b6126d9816126d46131ee565b6131f6565b6000600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b61279682611262565b6127a7816127a26131ee565b6131f6565b6127b183836148e9565b505050565b6000801b6127cb816127c66131ee565b6131f6565b600a82111561280f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161280690615898565b60405180910390fd5b7f9ce010994eb307d3d21dc4d32471b192947a8e6b07f597325e8ed94d53685a698260405161283e9190615904565b60405180910390a1816001819055505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b60008060001b6128ef816128ea6131ee565b6131f6565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561295f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161295690615148565b60405180910390fd5b82600d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506129cb600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611d82565b8273ffffffffffffffffffffffffffffffffffffffff167ff01df6097899c4c56c975ef84404392d5cf3d3664ba387b392c13e5e2974527b604051612a0f9061597e565b60405180910390a26001915050919050565b6000600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000801b612a8c81612a876131ee565b6131f6565b6001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b600080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050612b3683611c25565b80612b465750612b4583612a21565b5b80612b515750600081145b15612b60576000915050612c34565b6000612b6b8461160a565b90506000612b78856112ab565b90506000600a60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000811115612be85780831115612be2578083612bdb9190615068565b9250612be7565b600092505b5b6000831415612bfe576000945050505050612c34565b6104478210612c235761044782612c159190615068565b83612c209190615068565b92505b612c2d8484611ad4565b9450505050505b919050565b606060006002836002612c4c9190615472565b612c56919061541c565b67ffffffffffffffff811115612c6f57612c6e61599e565b5b6040519080825280601f01601f191660200182016040528015612ca15781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612cd957612cd86159cd565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612d3d57612d3c6159cd565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002612d7d9190615472565b612d87919061541c565b90505b6001811115612e27577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110612dc957612dc86159cd565b5b1a60f81b828281518110612de057612ddf6159cd565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c945080612e20906159fc565b9050612d8a565b5060008414612e6b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e6290615a72565b60405180910390fd5b8091505092915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b612ee881613403565b15612ef757612ef681614209565b5b612f0081611c25565b15612fdc57612f0e81613ea1565b506000600760008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555042600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508073ffffffffffffffffffffffffffffffffffffffff167f96cc51e6ab9b6970cc6fc055179c755849347faa4f703098b52724f2a76ad95660405160405180910390a25b42600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613093576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161308a90615148565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415613103576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130fa90615148565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516131e19190614d42565b60405180910390a3505050565b600033905090565b613200828261200d565b61328f576132258173ffffffffffffffffffffffffffffffffffffffff166014612c39565b6132338360001c6020612c39565b604051602001613244929190615b66565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016132869190614b6b565b60405180910390fd5b5050565b61329d828261200d565b61336f57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506133146131ee565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600080610447856133849190615068565b90506000836305f5e10061016d846305f5e100896133a29190615472565b6133ac9190615472565b6133b691906150cb565b6133c091906150cb565b6133ca9190615068565b9050868111806133e6575060c881886133e39190615068565b11155b156133f55786925050506133fb565b80925050505b949350505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561348057506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054115b80156134965750610447613493836112ab565b10155b80156134a857506134a682611c25565b155b80156134ba57506134b8826123bc565b155b8015613518575060006134cc83612ae8565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546135169190615068565b115b15613526576001905061352b565b600090505b919050565b6000806404a817c8006305f5e100846135499190615472565b61355391906150cb565b90506305f5e10081101561356e576305f5e100915050613573565b809150505b919050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156135e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016135df90615148565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161364f90615148565b60405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156136c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016136be90615c12565b60405180910390fd5b600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415613758576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161374f90615ca4565b60405180910390fd5b600061376384612ae8565b90506000808290506000600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16146139de5761383088876117f8565b8361383b919061541c565b925061384687612ae8565b93508286836138559190615068565b61385f9190615068565b600260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508386826138af919061541c565b6138b99190615068565b600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550838360026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461396a919061541c565b613974919061541c565b60026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550613b00565b84826139ea9190615068565b600260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508460026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054613a9a919061541c565b60026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88604051613b5d9190614d42565b60405180910390a36000831115613c4d57600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051613bed9190614d42565b60405180910390a36000851115613c4c5742600460008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550613c4b886149ca565b5b5b6000600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541415613d6457601054600a60008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555042600560008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555042600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b6000841115613e4657600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef86604051613dec9190614d42565b60405180910390a342600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550613e41876149ca565b613e97565b62023a50811015613e965742600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5b5050505050505050565b600080613f75600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054613ef0856112ab565b600760008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600660008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054613373565b90506000811415613f8a576000915050614204565b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054613fd59190615068565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054614085919061541c565b60026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054614135919061541c565b600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516141f79190614d42565b60405180910390a3809150505b919050565b600061421482612ae8565b9050600081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546142639190615068565b90506000811161427657614275615cc4565b5b61427f81613530565b600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff167f481010afe95c4aad3901e4d3948ca845e8772b11b72f77bf2dd74a9940e21a21600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040516143479190614d42565b60405180910390a260006143a58261435e866112ab565b600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546000613373565b9050600081846143b5919061541c565b905080600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546144029190615068565b600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546144b2919061541c565b60026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054614562919061541c565b600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516146249190614d42565b60405180910390a360008411156146835742600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550614682856149ca565b5b5050505050565b60008061469683612ae8565b905060008114156146ab5760009150506148e4565b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546146f69190615068565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546147a6919061541c565b60026000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161488a9190614d42565b60405180910390a342600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506148df836149ca565b809150505b919050565b6148f3828261200d565b156149c657600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555061496b6131ee565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000600a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b614a4c81614a17565b8114614a5757600080fd5b50565b600081359050614a6981614a43565b92915050565b600060208284031215614a8557614a84614a12565b5b6000614a9384828501614a5a565b91505092915050565b60008115159050919050565b614ab181614a9c565b82525050565b6000602082019050614acc6000830184614aa8565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015614b0c578082015181840152602081019050614af1565b83811115614b1b576000848401525b50505050565b6000601f19601f8301169050919050565b6000614b3d82614ad2565b614b478185614add565b9350614b57818560208601614aee565b614b6081614b21565b840191505092915050565b60006020820190508181036000830152614b858184614b32565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000614bb882614b8d565b9050919050565b614bc881614bad565b8114614bd357600080fd5b50565b600081359050614be581614bbf565b92915050565b6000819050919050565b614bfe81614beb565b8114614c0957600080fd5b50565b600081359050614c1b81614bf5565b92915050565b60008060408385031215614c3857614c37614a12565b5b6000614c4685828601614bd6565b9250506020614c5785828601614c0c565b9150509250929050565b614c6a81614bad565b82525050565b6000602082019050614c856000830184614c61565b92915050565b600060208284031215614ca157614ca0614a12565b5b6000614caf84828501614bd6565b91505092915050565b600080600080600060a08688031215614cd457614cd3614a12565b5b6000614ce288828901614bd6565b9550506020614cf388828901614bd6565b9450506040614d0488828901614bd6565b9350506060614d1588828901614bd6565b9250506080614d2688828901614bd6565b9150509295509295909350565b614d3c81614beb565b82525050565b6000602082019050614d576000830184614d33565b92915050565b600080600060608486031215614d7657614d75614a12565b5b6000614d8486828701614bd6565b9350506020614d9586828701614bd6565b9250506040614da686828701614c0c565b9150509250925092565b6000819050919050565b614dc381614db0565b8114614dce57600080fd5b50565b600081359050614de081614dba565b92915050565b600060208284031215614dfc57614dfb614a12565b5b6000614e0a84828501614dd1565b91505092915050565b614e1c81614db0565b82525050565b6000602082019050614e376000830184614e13565b92915050565b60008060408385031215614e5457614e53614a12565b5b6000614e6285828601614dd1565b9250506020614e7385828601614bd6565b9150509250929050565b600060ff82169050919050565b614e9381614e7d565b82525050565b6000602082019050614eae6000830184614e8a565b92915050565b60008060408385031215614ecb57614eca614a12565b5b6000614ed985828601614c0c565b9250506020614eea85828601614c0c565b9150509250929050565b600060208284031215614f0a57614f09614a12565b5b6000614f1884828501614c0c565b91505092915050565b60008060408385031215614f3857614f37614a12565b5b6000614f4685828601614bd6565b9250506020614f5785828601614bd6565b9150509250929050565b7f5a65726f206164647265737320696e7075747465640000000000000000000000600082015250565b6000614f97601583614add565b9150614fa282614f61565b602082019050919050565b60006020820190508181036000830152614fc681614f8a565b9050919050565b7f546f6b656e20697320616c726561647920696e697469616c697a656400000000600082015250565b6000615003601c83614add565b915061500e82614fcd565b602082019050919050565b6000602082019050818103600083015261503281614ff6565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061507382614beb565b915061507e83614beb565b92508282101561509157615090615039565b5b828203905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006150d682614beb565b91506150e183614beb565b9250826150f1576150f061509c565b5b828204905092915050565b7f5a65726f20616464726573732075736564000000000000000000000000000000600082015250565b6000615132601183614add565b915061513d826150fc565b602082019050919050565b6000602082019050818103600083015261516181615125565b9050919050565b7f4163636f756e7420686173206e6f2062616c616e63652c2063616e6e6f74206660008201527f6f72636520706179696e67206665657300000000000000000000000000000000602082015250565b60006151c4603083614add565b91506151cf82615168565b604082019050919050565b600060208201905081810360008301526151f3816151b7565b9050919050565b7f4572726f72206e6f206665657320706169642100000000000000000000000000600082015250565b6000615230601383614add565b915061523b826151fa565b602082019050919050565b6000602082019050818103600083015261525f81615223565b9050919050565b7f4163636f756e742068617320706169642073746f726167652066656573206d6f60008201527f726520726563656e746c79207468616e20333635206461797300000000000000602082015250565b60006152c2603983614add565b91506152cd82615266565b604082019050919050565b600060208201905081810360008301526152f1816152b5565b9050919050565b7f4e6f206170707265636961626c652073746f726167652066656573206475652c60008201527f2077696c6c20726566756e642067617300000000000000000000000000000000602082015250565b6000615354603083614add565b915061535f826152f8565b604082019050919050565b6000602082019050818103600083015261538381615347565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b60006153e6602f83614add565b91506153f18261538a565b604082019050919050565b60006020820190508181036000830152615415816153d9565b9050919050565b600061542782614beb565b915061543283614beb565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561546757615466615039565b5b828201905092915050565b600061547d82614beb565b915061548883614beb565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156154c1576154c0615039565b5b828202905092915050565b7f496e76616c69642073656e646572000000000000000000000000000000000000600082015250565b6000615502600e83614add565b915061550d826154cc565b602082019050919050565b60006020820190508181036000830152615531816154f5565b9050919050565b600060408201905061554d6000830185614d33565b61555a6020830184614c61565b9392505050565b7f4163636f756e74206e6f7420656c696769626c6520746f206265206d61726b6560008201527f6420696e61637469766500000000000000000000000000000000000000000000602082015250565b60006155bd602a83614add565b91506155c882615561565b604082019050919050565b600060208201905081810360008301526155ec816155b0565b9050919050565b7f53746f726167652046656520477261636520506572696f642044617973000000600082015250565b6000615629601d83614add565b9150615634826155f3565b602082019050919050565b600060408201905081810360008301526156588161561c565b90506156676020830184614d33565b92915050565b7f4665652041646472657373000000000000000000000000000000000000000000600082015250565b60006156a3600b83614add565b91506156ae8261566d565b602082019050919050565b600060208201905081810360008301526156d281615696565b9050919050565b7f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f7760008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000615735602483614add565b9150615740826156d9565b604082019050919050565b6000602082019050818103600083015261576481615728565b9050919050565b60006040820190506157806000830185614c61565b61578d6020830184614d33565b9392505050565b7f496e73756666696369656e742042616c616e636520546f204d616b652054686960008201527f73205472616e7366657200000000000000000000000000000000000000000000602082015250565b60006157f0602a83614add565b91506157fb82615794565b604082019050919050565b6000602082019050818103600083015261581f816157e3565b9050919050565b7f5472616e736665722066656520626173697320706f696e7473206d757374206260008201527f6520616e20696e7465676572206265747765656e203020616e64203130000000602082015250565b6000615882603d83614add565b915061588d82615826565b604082019050919050565b600060208201905081810360008301526158b181615875565b9050919050565b7f5472616e736665722046656520426173697320506f696e747300000000000000600082015250565b60006158ee601983614add565b91506158f9826158b8565b602082019050919050565b6000604082019050818103600083015261591d816158e1565b905061592c6020830184614d33565b92915050565b7f52656465656d2041646472657373000000000000000000000000000000000000600082015250565b6000615968600e83614add565b915061597382615932565b602082019050919050565b600060208201905081810360008301526159978161595b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000615a0782614beb565b91506000821415615a1b57615a1a615039565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b6000615a5c602083614add565b9150615a6782615a26565b602082019050919050565b60006020820190508181036000830152615a8b81615a4f565b9050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000615ad3601783615a92565b9150615ade82615a9d565b601782019050919050565b6000615af482614ad2565b615afe8185615a92565b9350615b0e818560208601614aee565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b6000615b50601183615a92565b9150615b5b82615b1a565b601182019050919050565b6000615b7182615ac6565b9150615b7d8285615ae9565b9150615b8882615b43565b9150615b948284615ae9565b91508190509392505050565b7f43616e6e6f74207472616e7366657220746f6b656e7320746f2074686520636f60008201527f6e74726163740000000000000000000000000000000000000000000000000000602082015250565b6000615bfc602683614add565b9150615c0782615ba0565b604082019050919050565b60006020820190508181036000830152615c2b81615bef565b9050919050565b7f52656465656d20616464726573732063616e206f6e6c79207472616e7366657260008201527f20746f206d61696e6e6574206279206275726e696e6700000000000000000000602082015250565b6000615c8e603683614add565b9150615c9982615c32565b604082019050919050565b60006020820190508181036000830152615cbd81615c81565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fdfea2646970667358221220f45ab8c4546b6e66a1a84059dc3e65fd6f414e2d06b3715f94791dc2c7e77c9c64736f6c634300080b0033

Block Transaction Gas Used Reward
view all blocks produced

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

OVERVIEW

CACHE Gold tokens each represent one gram of pure gold stored in vaults around the world. CACHE Gold tokens are redeemable for delivery of physical gold or can be sold for fiat currency.

Loading...
Loading

Validator Index Block Amount
View All Withdrawals

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

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