ETH Price: $3,112.28 (-0.89%)

Contract

0xce37b9cA1604A30013fd540e13d793d13075B57E
 

Overview

ETH Balance

5 wei

Eth Value

Less Than $0.01 (@ $3,112.28/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Renounce Ownersh...197452652024-04-27 7:44:47205 days ago1714203887IN
0xce37b9cA...13075B57E
0 ETH0.00012025.19584593
Set Render Contr...197440382024-04-27 3:37:23205 days ago1714189043IN
0xce37b9cA...13075B57E
0 ETH0.000155695.3692722
Transfer Ownersh...197140262024-04-22 22:49:59209 days ago1713826199IN
0xce37b9cA...13075B57E
0 ETH0.000189356.64003252
Set Render Contr...197126342024-04-22 18:09:59209 days ago1713809399IN
0xce37b9cA...13075B57E
0 ETH0.0006226513.50757638
Set Token Contra...197126332024-04-22 18:09:47209 days ago1713809387IN
0xce37b9cA...13075B57E
0 ETH0.0006305213.67857924
0x60806040197126302024-04-22 18:09:11209 days ago1713809351IN
 Create: HonestWorkLogic
0 ETH0.0644129312.0687276

Latest 5 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
208326942024-09-26 5:28:1153 days ago1727328491
0xce37b9cA...13075B57E
1 wei
200247932024-06-05 9:40:59165 days ago1717580459
0xce37b9cA...13075B57E
1 wei
200142202024-06-03 22:17:23167 days ago1717453043
0xce37b9cA...13075B57E
1 wei
197310302024-04-25 7:56:23207 days ago1714031783
0xce37b9cA...13075B57E
1 wei
197135132024-04-22 21:06:47209 days ago1713820007
0xce37b9cA...13075B57E
1 wei
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
HonestWorkLogic

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 2000000 runs

Other Settings:
cancun EvmVersion
File 1 of 5 : HonestWorkLogic.sol
// SPDX-License-Identifier: UNLICENSE
pragma solidity 0.8.25;

import "solady/src/utils/DateTimeLib.sol";
import "./IHonestWorkRender.sol";
import "./TodoVariables.sol";
import "./3rd/Ownable.sol";

uint256 constant SEED = 0xbeef;

contract HonestWorkLogic is Ownable {
    event TodoCompleted(uint256 tokenId, uint256 todoId, address from, address to);
    event TodoCreated(uint256 tokenId, uint256 todoIndex, uint256 todoId);

    address public tokenContract;
    address public renderContract;

    struct Token {
        uint8 open; // how many todos are open
        uint8 max; // how many todos can be open at the same time
        bool repeater; // if the token is a repeater
        uint24 todoCount; // total number of todos (including active)
        uint24[3] activeTodosIndices; // indices of active todos
        uint16[3] activeTodos; // ids of active todos
        uint48 lastTransferTime; // last transfer block.timestamp, uint48 ~= 8.9 million years
    }
    mapping(uint256 => Token) public tokenData; // token data
    mapping(uint256 => uint256[]) public tokenTodos; // all todos; we push the newest todos into this array
    struct TransferTracker {
        uint8 left;
        uint8 right;
        bytes4[7] data;
    }
    mapping(uint256 => mapping(uint256 => TransferTracker)) transferTrackers;
    mapping(uint256 => mapping(uint256 => uint32)) public todoCounters; // counter trackers

    constructor() {
        _initializeOwner(msg.sender);
    }

    function setRenderContract(address _contract) external onlyOwner {
        renderContract = _contract;
    }

    function setTokenContract(address _contract) external onlyOwner {
        tokenContract = _contract;
    }

    modifier onlyTokenContract() {
        require(msg.sender == tokenContract);
        _;
    }

    /*//////////////////////////////////////////////////////////////
                                VIEW
    //////////////////////////////////////////////////////////////*/

    function getTodoState(
        uint256 tokenId
    )
        external
        view
        returns (
            uint8 open,
            uint8 max,
            bool repeater,
            uint24 todoCount,
            uint24[3] memory activeTodosIndices,
            uint16[3] memory activeTodos,
            uint48 lastTransferTime,
            uint256[] memory todos
        )
    {
        Token memory token = tokenData[tokenId];
        uint256[] memory todosMem = tokenTodos[tokenId];
        return (
            token.open,
            token.max,
            token.repeater,
            token.todoCount,
            token.activeTodosIndices,
            token.activeTodos,
            token.lastTransferTime,
            todosMem
        );
    }

    function resolveTask(uint256 taskId) external view returns (string memory) {
        return IHonestWorkRender(renderContract).resolveTask(taskId);
    }

    /*//////////////////////////////////////////////////////////////
                                HOOK
    //////////////////////////////////////////////////////////////*/

    function beforeTokenTransfer(
        address from,
        address to,
        address sender,
        uint256 tokenId,
        uint256 balanceOfFrom,
        bytes calldata data
    ) external payable onlyTokenContract {
        Token memory token = tokenData[tokenId];
        uint256 fullfilledTodos = 0;

        // iterate over active todos
        for (uint256 index = token.open; index > 0; index--) {
            uint256 todo = token.activeTodos[index - 1];
            // attempt to fullfill the todo
            if (
                _fulfillTodo(
                    tokenId,
                    todo,
                    token.activeTodosIndices[index - 1], // todoIndex
                    from,
                    to,
                    sender,
                    balanceOfFrom,
                    data
                )
            ) {
                emit TodoCompleted(tokenId, todo, from, to);

                // shift the last "open" todo to the current position
                if (index - 1 < token.open - 1) {
                    token.activeTodosIndices[index - 1] = token.activeTodosIndices[token.open - 1];
                    token.activeTodos[index - 1] = token.activeTodos[token.open - 1];
                }
                token.open--;
                fullfilledTodos++;
            }
        }

        // add new todos if we have completed some
        if (fullfilledTodos > 0) {
            token = _addTodos(tokenId, token, fullfilledTodos);
            // save token data to storage if we have new todos
            token.lastTransferTime = uint48(block.timestamp);
            tokenData[tokenId] = token;
        } else {
            // if we have no new todos, we update the transfer time
            tokenData[tokenId].lastTransferTime = uint48(block.timestamp);
        }
    }

    function _addTodos(uint256 tokenId, Token memory token, uint256 todosToReplace) internal returns (Token memory) {
        uint256 todosToCreate = todosToReplace > 0 ? todosToReplace : 1;
        // Decision: Replace n todos or add n+1 for multi-taskers 1 in 3 times
        if (
            token.open + todosToReplace < token.max &&
            uint256(keccak256(abi.encodePacked(tokenId, SEED, token.max))) % 3 == 0
        ) {
            todosToCreate += 1;
        }

        uint256 seed = uint256(keccak256(abi.encodePacked(tokenId, SEED)));

        // Here be scary nested loops (but max n is 3)
        for (uint256 i = 0; i < todosToCreate; i++) {
            uint16 cut = 0;
            uint16 offset = 0;
            for (uint256 j = 0; j < token.open; j++) {
                // Rule 1: Only ever 1 passive (cut END range)
                if (token.activeTodos[j] >= DO_WHAT_YOU_WANT && token.activeTodos[j] <= DONT_THINK) {
                    cut = uint16(DONT_THINK - DO_WHAT_YOU_WANT + 1);
                }

                // Rule 2: Only ever 1 of GET X THINGS done (cut start range)
                // AND never show if max todos is 1
                // AND never show if list can still grow
                if (token.max == 1 || token.activeTodos[j] <= GET_10_DONE || (token.open + 1) < token.max) {
                    offset = uint16(GET_10_DONE);
                }
            }

            // Rule 3: Only ever 1 of the same todo (within reason: try to avoid duplicates ~e.g. 5 iterations)
            uint16 todoId;
            bool doContinue;
            for (uint256 j = 0; j < 5; j++) {
                todoId =
                    uint16(
                        uint256(keccak256(abi.encodePacked(seed, token.todoCount + j * type(uint16).max))) %
                            (TOTAL_TODO_COUNT - cut - offset)
                    ) +
                    offset +
                    1; // 1-indexed
                for (uint256 k = 0; j < 5 - 1 && k < token.open; k++) {
                    if (token.activeTodos[k] == todoId) {
                        doContinue = true;
                    }
                }
                if (!doContinue) break;
            }

            token.activeTodosIndices[token.open] = uint24(token.todoCount);
            token.activeTodos[token.open] = todoId;
            token.todoCount++;
            token.open++;

            tokenTodos[tokenId].push(todoId);

            emit TodoCreated(tokenId, token.todoCount - 1, todoId);
        }

        return token;
    }

    /*//////////////////////////////////////////////////////////////
                                MINT
    //////////////////////////////////////////////////////////////*/

    function createTodo(uint256 tokenId) external onlyTokenContract {
        // Generate the token with initial todo (1 - 3)
        uint256 seed = uint256(keccak256(abi.encodePacked(tokenId, SEED)));
        bool repeater = tokenId == 1 || tokenId == 25 || tokenId == 50 || tokenId == 100;
        uint8 max = repeater ? 1 : uint8(uint256(seed) % 3) + 1;
        uint16 cut = 0;
        uint16 offset = uint16(GET_10_DONE);
        uint16 todoId;

        if (!repeater) {
            todoId =
                uint16(
                    uint256(keccak256(abi.encodePacked(seed, uint32(0 /*first*/)))) % (TOTAL_TODO_COUNT - offset - cut)
                ) +
                offset +
                1; // 1-indexed
        } else if (tokenId == 1) {
            todoId = uint16(DO_NOTHING_FOR_A_YEAR);
        } else if (tokenId == 25) {
            todoId = uint16(DO_NOTHING_FOR_A_MONTH);
        } else if (tokenId == 50) {
            todoId = uint16(DO_NOTHING_FOR_A_WEEK);
        } else {
            todoId = uint16(DO_NOTHING_FOR_A_DAY);
        }

        tokenTodos[tokenId].push(todoId);
        Token memory token = Token({
            open: 1,
            max: max,
            repeater: repeater,
            todoCount: 1,
            activeTodosIndices: [uint24(0 /*first*/), 0, 0],
            activeTodos: [todoId, 0, 0],
            lastTransferTime: uint48(block.timestamp)
        });

        // save to storage
        tokenData[tokenId] = token;

        emit TodoCreated(tokenId, 0, todoId);
    }

    /*//////////////////////////////////////////////////////////////
                                TODO
    //////////////////////////////////////////////////////////////*/

    function _fulfillTodo(
        uint256 tokenId,
        uint256 todo, // id
        uint256 todoIndex, // id
        address from,
        address to,
        address sender,
        uint256 balanceOfFrom,
        bytes calldata data
    ) internal returns (bool) {
        // Just transfer: Do what you want / Don't think / etc
        if (DO_WHAT_YOU_WANT <= todo && todo <= DONT_THINK) {
            return true;
        }

        // Low Gas
        if (todo == LOW_GAS) {
            return tx.gasprice < 20 gwei;
        }

        // Origin is not the sender
        if (todo == ORIGIN_NOT_SENDER || todo == ORIGIN_NOT_SENDER_2) {
            return tx.origin != sender;
        }

        // Send to beef
        if (todo == BEEF || todo == BEEF_2 || todo == BEEF_ONLY) {
            bytes20 addr = bytes20(to);
            return (addr[0] == 0xbe && addr[1] == 0xef) || (addr[18] == 0xbe && addr[19] == 0xef);
        }

        // Avoid the beef
        if (todo == AVOID_THE_BEEF) {
            bytes20 addr = bytes20(to);
            return !(addr[0] == 0xbe && addr[1] == 0xef) || (addr[18] == 0xbe && addr[19] == 0xef);
        }

        // Send to dead
        if (todo == DEAD || todo == DEAD_2) {
            bytes20 addr = bytes20(to);
            return (addr[0] == 0xde && addr[1] == 0xad) || (addr[18] == 0xde && addr[19] == 0xad);
        }

        // Send to babe
        if (todo == BABE || todo == BABE_2) {
            bytes20 addr = bytes20(to);
            return (addr[0] == 0xba && addr[1] == 0xbe) || (addr[18] == 0xba && addr[19] == 0xbe);
        }

        // Send to deaf
        if (todo == DEAF) {
            bytes20 addr = bytes20(to);
            return (addr[0] == 0xde && addr[1] == 0xaf) || (addr[18] == 0xde && addr[19] == 0xaf);
        }

        // Send to feed
        if (todo == FEED) {
            bytes20 addr = bytes20(to);
            return (addr[0] == 0xfe && addr[1] == 0xed) || (addr[18] == 0xfe && addr[19] == 0xed);
        }

        // Send to fed
        if (todo == FED) {
            bytes20 addr = bytes20(to);
            return
                (addr[0] == 0xfe && addr[1] & hex"f0" == hex"d0") ||
                (addr[18] & hex"0f" == hex"0f" && addr[19] == 0xed);
        }

        // Send to face
        if (todo == FACE || todo == FACE_2) {
            bytes20 addr = bytes20(to);
            return (addr[0] == 0xfa && addr[1] == 0xce) || (addr[18] == 0xfa && addr[19] == 0xce);
        }

        // Send to bad
        if (todo == BAD || todo == BAD_2 || todo == BAD_3) {
            bytes20 addr = bytes20(to);
            return
                (addr[0] == 0xba && addr[1] & hex"f0" == hex"d0") ||
                (addr[18] & hex"0f" == hex"0b" && addr[19] == 0xad);
        }

        // Pay 1 wei
        if (todo == PAY_1_WEI) {
            return msg.value == 1 wei;
        }

        // Send to an empty address
        if (todo == TO_ZERO_ETH) {
            return to.balance == 0;
        }

        // Have 0 ETH when sending it
        if (todo == ZERO_ETH) {
            return from.balance == 0;
        }

        // Have 1 ETH when sending it
        if (todo == ONE_ETH) {
            return from.balance >= 1 ether;
        }

        // Have an even balance
        if (todo == EVEN_BALANCE) {
            return from.balance % 2 == 0;
        }

        // Have an odd balance
        if (todo == ODD_BALANCE) {
            return from.balance % 2 == 1;
        }

        // Make me jealous
        if (todo == MAKE_ME_JEALOUS) {
            return from.balance < to.balance;
        }

        // Happy New Year
        if (todo == HAPPY_NEW_YEAR) {
            (, uint month, uint day) = DateTimeLib.timestampToDate(block.timestamp);
            return month == 1 && day == 1;
        }

        // At midnight
        if (todo == AT_MIDNIGHT) {
            // +/- 5 minute around midnight
            return block.timestamp % 1 days < 5 minutes || block.timestamp % 1 days > 1 days - 5 minutes;
        }

        // Opening Hours
        if (todo == OPENING_HOURS) {
            uint hour = (block.timestamp / 1 hours) % 24;
            return hour >= 9 && hour < 17;
        }

        // Outside Opening Hours
        if (todo == OUTSIDE_OPENING_HOURS) {
            uint hour = (block.timestamp / 1 hours) % 24;
            return hour < 9 || hour >= 17;
        }

        // 7/11
        if (todo == SEVEN_ELEVEN) {
            uint hour = (block.timestamp / 1 hours) % 24;
            return hour >= 7 && hour < 23;
        }

        // Send to yourself
        if (
            todo == TO_SELF || todo == TREAT_YOURSELF || todo == A_A || todo == YOU_ARE_HERE || todo == YOU_ARE_ENOUGH
        ) {
            return from == to;
        }

        // Send to someone else
        if (todo == TO_SOMEONE_ELSE || todo == AWAY || todo == OFF_YOU_GO) {
            return from != to;
        }

        // Transfer on a Monday
        if (todo == MONDAY) {
            return DateTimeLib.weekday(block.timestamp) == 1;
        }

        // Transfer on a Tuesday
        if (todo == TUESDAY) {
            return DateTimeLib.weekday(block.timestamp) == 2;
        }

        // Transfer on a Wednesday
        if (todo == WEDNESDAY) {
            return DateTimeLib.weekday(block.timestamp) == 3;
        }

        // Transfer on a Thursday
        if (todo == THURSDAY) {
            return DateTimeLib.weekday(block.timestamp) == 4;
        }

        // Transfer on a Friday
        if (todo == FRIDAY) {
            return DateTimeLib.weekday(block.timestamp) == 5;
        }

        // Transfer on a Saturday
        if (todo == SATURDAY) {
            return DateTimeLib.weekday(block.timestamp) == 6;
        }

        // Transfer on a Sunday
        if (todo == SUNDAY) {
            return DateTimeLib.weekday(block.timestamp) == 7;
        }

        // Do nothing for 5 minutes
        if (todo == DO_NOTHING_FOR_5_MINUTES || todo == TAKE_A_MOMENT || todo == NOT_NOW) {
            return tokenData[tokenId].lastTransferTime + 5 minutes <= block.timestamp;
        }

        // Do nothing for 10 minutes (aka snooze)
        if (todo == SNOOZE) {
            return tokenData[tokenId].lastTransferTime + 10 minutes <= block.timestamp;
        }

        // Do nothing for an hour
        if (todo == DO_NOTHING_FOR_AN_HOUR || todo == TIME_FOR_LUNCH || todo == GO_LOOK_AT_THE_SKY) {
            return tokenData[tokenId].lastTransferTime + 1 hours <= block.timestamp;
        }

        // Do nothing for twelve hours
        if (todo == DO_NOTHING_FOR_TWELVE_HOURS) {
            return tokenData[tokenId].lastTransferTime + 12 hours <= block.timestamp;
        }

        // Do nothing for a day
        if (
            todo == DO_NOTHING_FOR_A_DAY ||
            todo == TOMORROW_IS_ANOTHER_DAY ||
            todo == SLEEP_ON_IT ||
            todo == TAKE_TODAY_OFF ||
            todo == COME_BACK_TOMORROW ||
            todo == TOUCH_GRASS ||
            todo == PROCRASTINATE
        ) {
            return tokenData[tokenId].lastTransferTime + 1 days <= block.timestamp;
        }

        // Do nothing for 48 hours
        if (todo == DO_NOTHING_FOR_48_HOURS) {
            return tokenData[tokenId].lastTransferTime + 2 days <= block.timestamp;
        }

        // Do nothing for a week
        if (todo == DO_NOTHING_FOR_A_WEEK || todo == TAKE_A_WEEK_OFF || todo == HOLIDAY_TIME) {
            return tokenData[tokenId].lastTransferTime + 1 weeks <= block.timestamp;
        }

        // Do nothing for 1 month
        if (todo == DO_NOTHING_FOR_A_MONTH || todo == WAIT_A_MONTH) {
            return tokenData[tokenId].lastTransferTime + 4 weeks <= block.timestamp;
        }

        // Do nothing for 1 year
        if (todo == DO_NOTHING_FOR_A_YEAR || todo == NEXT_YEAR_WILL_BE_GREAT) {
            return tokenData[tokenId].lastTransferTime + 52 weeks <= block.timestamp;
        }

        // Send ETH with it
        if (todo == SEND_ETH_WITH_IT) {
            return msg.value > 0;
        }

        // Don't send ETH with it
        if (todo == DONT_SEND_ETH_WITH_IT) {
            return msg.value == 0;
        }

        // 50 percent chance
        if (todo == FIFTY_FIFTY || todo == TRY_IT_USUALLY_WORKS) {
            return succeedWithProbability(50);
        }

        // 33 percent chance
        if (todo == ITS_ABOUT_THE_JOURNEY || todo == TRUST_THE_PROCESS || todo == KEEP_TRYING) {
            return succeedWithProbability(33);
        }

        // 60 percent chance
        if (todo == TAKE_A_CHANCE || todo == TRY_IT_USUALLY_WORKS) {
            return succeedWithProbability(60);
        }

        // 10 percent chance
        if (todo == BE_PERSISTENT || todo == BE_LUCKY) {
            return succeedWithProbability(10);
        }

        // 20 percent chance
        if (todo == HARD_WORK || todo == KEEP_ON_KEEPING_ON) {
            return succeedWithProbability(20);
        }

        // 75 percent chance
        if (todo == EASY_WORK) {
            return succeedWithProbability(75);
        }

        // Have multiple lists
        if (todo == HAVE_MULTIPLE_LISTS) {
            return balanceOfFrom > 1;
        }

        // Transfer to a contract
        if (todo == TO_CONTRACT) {
            return to.code.length > 0;
        }

        // To someone foreign
        if (todo == TO_SOMEONE_FOREIGN) {
            // We iterate over the address and make sure we have no matching digits
            bytes20 fromAddr = bytes20(from);
            bytes20 toAddr = bytes20(to);
            for (uint i = 0; i < 20; i++) {
                if (fromAddr[i] & hex"f0" == toAddr[i] & hex"f0" || fromAddr[i] & hex"0f" == toAddr[i] & hex"0f") {
                    return false;
                }
            }

            return true;
        }

        // Summer
        if (todo == SUMMER) {
            (, uint month, ) = DateTimeLib.timestampToDate(block.timestamp);
            return month >= 6 && month <= 8;
        }

        // Not Summer
        if (todo == NOT_SUMMER) {
            (, uint month, ) = DateTimeLib.timestampToDate(block.timestamp);
            return month < 6 || month > 8;
        }

        // Winter
        if (todo == WINTER) {
            (, uint month, ) = DateTimeLib.timestampToDate(block.timestamp);
            return month >= 12 || month <= 2;
        }

        // Not Winter
        if (todo == NOT_WINTER) {
            (, uint month, ) = DateTimeLib.timestampToDate(block.timestamp);
            return month > 2 && month < 12;
        }

        // Spring
        if (todo == SPRING) {
            (, uint month, ) = DateTimeLib.timestampToDate(block.timestamp);
            return month >= 3 && month <= 5;
        }

        // Not Spring
        if (todo == NOT_SPRING) {
            (, uint month, ) = DateTimeLib.timestampToDate(block.timestamp);
            return month < 3 || month > 5;
        }

        // Autumn
        if (todo == AUTUMN) {
            (, uint month, ) = DateTimeLib.timestampToDate(block.timestamp);
            return month >= 9 && month <= 11;
        }

        // Not Autumn
        if (todo == NOT_AUTUMN) {
            (, uint month, ) = DateTimeLib.timestampToDate(block.timestamp);
            return month < 9 || month > 11;
        }

        // In any season
        if (todo == IN_ANY_SEASON) {
            return true;
        }

        // Weekend, Not week
        if (todo == WEEKEND || todo == NOT_WEEK) {
            uint weekday = DateTimeLib.weekday(block.timestamp);
            return weekday == 6 || weekday == 7;
        }

        // Week, Not weekend
        if (todo == WEEK || todo == NOT_WEEKEND) {
            uint weekday = DateTimeLib.weekday(block.timestamp);
            return weekday >= 1 && weekday <= 5;
        }

        // Not Monday
        if (todo == NOT_MONDAY) {
            return DateTimeLib.weekday(block.timestamp) != 1;
        }

        // Not Tuesday
        if (todo == NOT_TUESDAY) {
            return DateTimeLib.weekday(block.timestamp) != 2;
        }

        // Not Wednesday
        if (todo == NOT_WEDNESDAY) {
            return DateTimeLib.weekday(block.timestamp) != 3;
        }

        // Not Thursday
        if (todo == NOT_THURSDAY) {
            return DateTimeLib.weekday(block.timestamp) != 4;
        }

        // Not Friday
        if (todo == NOT_FRIDAY) {
            return DateTimeLib.weekday(block.timestamp) != 5;
        }

        // Not Saturday
        if (todo == NOT_SATURDAY) {
            return DateTimeLib.weekday(block.timestamp) != 6;
        }

        // Not Sunday
        if (todo == NOT_SUNDAY) {
            return DateTimeLib.weekday(block.timestamp) != 7;
        }

        // Visit 7 addresses, A B C D E F G A
        if (todo == RING_OF_7) {
            // here we need to track 7 distinct addresses/transfers
            return trackDistinctAddressesInARow({todo: todo, tokenId: tokenId, from: from, to: to, length: 7});
        }

        // Visit 5 addresses, A B C D E A
        if (todo == RING_OF_5) {
            // here we need to track 5 distinct addresses/transfers
            return trackDistinctAddressesInARow({todo: todo, tokenId: tokenId, from: from, to: to, length: 5});
        }

        // Visit 3 addresses, Love triangle, A B C
        if (todo == LOVE_TRIANGLE || todo == RING_OF_3 || todo == ALICE_BOB_AND_EVE || todo == A_B_C) {
            return trackDistinctAddressesInARow({todo: todo, tokenId: tokenId, from: from, to: to, length: 3});
        }

        // Visit 2 addresses, A B A
        if (todo == ALICE_AND_BOB || todo == RETURN_TO_SENDER || todo == ASK_FOR_HELP || todo == A_B_A) {
            return trackDistinctAddressesInARow({todo: todo, tokenId: tokenId, from: from, to: to, length: 2});
        }

        // Two in two
        if (todo == TWO_IN_TWO) {
            // Checking if the last two transfers were within 2 minutes
            return
                trackLastNTransfersWithinTimeWindow({todo: todo, tokenId: tokenId, length: 2, timeWindow: 2 minutes});
        }

        // Three in three
        if (todo == THREE_IN_THREE) {
            // Checking if the last three transfers were within 3 minutes
            return
                trackLastNTransfersWithinTimeWindow({todo: todo, tokenId: tokenId, length: 3, timeWindow: 3 minutes});
        }

        // Five in five
        if (todo == FIVE_IN_FIVE) {
            // Checking if the last five transfers were within 5 minutes
            return
                trackLastNTransfersWithinTimeWindow({todo: todo, tokenId: tokenId, length: 5, timeWindow: 5 minutes});
        }

        // Every 10 minutes for an hour
        if (todo == EVERY_10_MINUTES_FOR_AN_HOUR) {
            // We are only tracking the last time the token was transferred and check if it's within 10 and 11
            if (
                tokenData[tokenId].lastTransferTime + 10 minutes <= block.timestamp &&
                tokenData[tokenId].lastTransferTime + 11 minutes > block.timestamp
            ) {
                tokenData[tokenId].lastTransferTime = uint48(block.timestamp);
                todoCounters[tokenId][todo]++;

                if (todoCounters[tokenId][todo] == 5) {
                    todoCounters[tokenId][todo] = 0;
                    return true;
                }
            } else {
                tokenData[tokenId].lastTransferTime = uint48(block.timestamp);
                todoCounters[tokenId][todo] = 0;
            }
            return false;
        }

        // Every day for a week
        if (todo == EVERY_DAY_FOR_A_WEEK) {
            return trackEveryDay({todo: todo, tokenId: tokenId, period: 7});
        }

        // Steady job (transfer every day monday to friday)
        if (todo == STEADY_JOB) {
            if (DateTimeLib.weekday(block.timestamp) == 1) {
                // We always start counting on a Monday
                todoCounters[tokenId][todo] = 1;
            } else if (block.timestamp / 1 days == tokenData[tokenId].lastTransferTime / 1 days + 1) {
                // If the previous transfer was yesterday, we increment the counter
                todoCounters[tokenId][todo]++;
            } else {
                // If there was a gap in the transfers, we reset the counter
                todoCounters[tokenId][todo] = 0;
            }
            return todoCounters[tokenId][todo] == 5;
        }

        // Every week for a month
        if (todo == EVERY_WEEK_FOR_A_MONTH) {
            return trackEveryWeek({todo: todo, tokenId: tokenId, period: 4});
        }

        // Every month for a year
        if (todo == EVERY_MONTH_FOR_A_YEAR) {
            // We need to check if the previous transfer was last month
            uint256 currMonth = calculateMonthsSinceEpoch(block.timestamp);
            uint256 prevMonth = calculateMonthsSinceEpoch(tokenData[tokenId].lastTransferTime);

            if (prevMonth + 1 == currMonth) {
                todoCounters[tokenId][todo]++;
            } else {
                // If we have a gap of not one month, we reset the counter
                todoCounters[tokenId][todo] = 0;
                return false;
            }

            if (todoCounters[tokenId][todo] == 11) {
                todoCounters[tokenId][todo] = 0;
                return true;
            }
            return false;
        }

        // Every season
        if (todo == EVERY_SEASON) {
            return trackEverySeason({todo: todo, tokenId: tokenId});
        }

        // Twice within the same block
        if (todo == TWICE_WITHIN_A_BLOCK) {
            return tokenData[tokenId].lastTransferTime == block.timestamp;
        }

        // Transfer 3 times
        if (todo == TRANSFER_3_TIMES) {
            return trackLastNTransfers(todo, tokenId, 3);
        }

        // Transfer 5 times
        if (todo == TRANSFER_5_TIMES) {
            return trackLastNTransfers(todo, tokenId, 5);
        }

        // Transfer 7 times
        if (todo == TRANSFER_7_TIMES) {
            return trackLastNTransfers(todo, tokenId, 7);
        }

        // Transfer 10 times
        if (todo == TRANSFER_10_TIMES) {
            return trackLastNTransfers(todo, tokenId, 10);
        }

        // Get 1 things done
        if (todo == GET_1_DONE) {
            return tokenData[tokenId].todoCount - (todoIndex + 1) >= 1;
        }

        // Get 5 things done
        if (todo == GET_5_DONE) {
            return tokenData[tokenId].todoCount - (todoIndex + 1) >= 5;
        }

        // Get 10 things done
        if (todo == GET_10_DONE) {
            return tokenData[tokenId].todoCount - (todoIndex + 1) >= 10;
        }

        // Even blocks
        if (todo == EVEN_BLOCKS) {
            return block.number % 2 == 0;
        }

        // Odd blocks
        if (todo == ODD_BLOCKS) {
            return block.number % 2 == 1;
        }

        // Password
        if (todo == WITH_PASSWORD) {
            return keccak256(data) == keccak256(abi.encodePacked("password"));
        }

        // Safty first
        if (todo == SAFETY_FIRST) {
            return data.length > 0;
        }

        // Fuck safety
        if (todo == FCK_SAFETY) {
            return data.length == 0;
        }

        // Stay the weekend
        if (todo == STAY_THE_WEEKEND) {
            TransferTracker memory tracker = transferTrackers[tokenId][todo];

            // Check if previous holder was the same as the "to" address.
            // Check if the previous transfer was on a Friday and the current transfer is on the following Monday.
            if (
                tracker.data[0] == bytes4(bytes20(to)) &&
                DateTimeLib.weekday(tokenData[tokenId].lastTransferTime) == 5 &&
                DateTimeLib.weekday(block.timestamp) == 1 &&
                block.timestamp - tokenData[tokenId].lastTransferTime < 7 days
            ) {
                delete transferTrackers[tokenId][todo];
                return true;
            }

            // Update tracker with the new 'from' address only if needed
            if (tracker.data[0] != bytes4(bytes20(from))) {
                tracker.data[0] = bytes4(bytes20(from));

                // save to storage
                transferTrackers[tokenId][todo] = tracker;
            }

            return false;
        }

        // Stay the night
        if (todo == STAY_THE_NIGHT || todo == WHERE_WHERE_YOU) {
            TransferTracker memory tracker = transferTrackers[tokenId][todo];

            // Normalize to epoch days (Days since 1970-01-01)
            uint curDay = block.timestamp / 1 days;
            uint prevDay = tokenData[tokenId].lastTransferTime / 1 days;

            // Check if previous holder was the same as the "to" address.
            // Check if the first transfer was on a previous day and if this transfer is after 6 am.
            if (
                tracker.data[0] == bytes4(bytes20(to)) && prevDay + 1 == curDay && block.timestamp % 1 days >= 6 hours
            ) {
                delete transferTrackers[tokenId][todo];
                return true;
            }

            // Update tracker with the new 'from' address only if needed
            if (tracker.data[0] != bytes4(bytes20(from))) {
                tracker.data[0] = bytes4(bytes20(from));

                // save to storage
                transferTrackers[tokenId][todo] = tracker;
            }

            return false;
        }

        // Stay on a contract for 2 days
        if (todo == ON_A_CONTRACT_2_DAYS) {
            TransferTracker memory tracker = transferTrackers[tokenId][todo];

            // Normalize to epoch days (Days since 1970-01-01)
            uint curDay = block.timestamp / 1 days;
            uint prevDay = tokenData[tokenId].lastTransferTime / 1 days;

            // Check if previous holder was the same as the "to" address.
            // Check if the first transfer was two days ago and if this
            // transfer is coming from a contract.
            if (tracker.data[0] == bytes4(bytes20(to)) && prevDay + 2 == curDay && from.code.length > 0) {
                delete transferTrackers[tokenId][todo];
                return true;
            }

            // Update tracker with the new 'from' address only if needed
            if (tracker.data[0] != bytes4(bytes20(from))) {
                tracker.data[0] = bytes4(bytes20(from));

                // save to storage
                transferTrackers[tokenId][todo] = tracker;
            }

            return false;
        }

        if (todo == VISIT_A_NEW_PLACE_TOMORROW) {
            // Check if the previous transfer was yesterday and the "to" address is different.
            return tokenData[tokenId].lastTransferTime + 1 days <= block.timestamp && from != to;
        }

        if (todo == TAKE_A_SABBATICAL) {
            // Stay 3 months on another address, then come back
            TransferTracker memory tracker = transferTrackers[tokenId][todo];

            // Normalize to epoch months
            uint256 currMonth = calculateMonthsSinceEpoch(block.timestamp);
            uint256 prevMonth = calculateMonthsSinceEpoch(tokenData[tokenId].lastTransferTime);

            // Check if the 'to' address is the same as the previously recorded address
            // and check if the difference in months is exactly three.
            if (tracker.data[0] == bytes4(bytes20(to)) && (prevMonth + 3 == currMonth)) {
                delete transferTrackers[tokenId][todo];
                return true;
            }

            // Update tracker with the new 'from' address only if needed
            if (tracker.data[0] != bytes4(bytes20(from))) {
                tracker.data[0] = bytes4(bytes20(from));

                // save to storage
                transferTrackers[tokenId][todo] = tracker;
            }

            return false;
        }

        // Be bad for a week
        if (todo == BE_BAD_FOR_A_WEEK) {
            // Get this weeks Monday 00:00:00 in epoch days
            uint curWeekStart = block.timestamp / 1 days - DateTimeLib.weekday(block.timestamp) + 1;

            // Get the previous weeks Monday 00:00:00 in epoch days
            uint prevTimestamp = tokenData[tokenId].lastTransferTime;
            uint prevWeekStart = prevTimestamp / 1 days - DateTimeLib.weekday(prevTimestamp) + 1;

            bytes20 addr = bytes20(from);

            // Check if the previous transfer was a week ago and the "from" address is bad.
            return
                prevWeekStart + 7 == curWeekStart &&
                ((addr[0] == 0xba && addr[1] & hex"f0" == hex"d0") ||
                    (addr[18] & hex"0f" == hex"0b" && addr[19] == 0xad));
        }

        // Play dead for a week
        if (todo == PLAY_DEAD_FOR_A_WEEK) {
            // Get this weeks Monday 00:00:00 in epoch days
            uint curWeekStart = block.timestamp / 1 days - DateTimeLib.weekday(block.timestamp) + 1;

            // Get the previous weeks Monday 00:00:00 in epoch days
            uint prevTimestamp = tokenData[tokenId].lastTransferTime;
            uint prevWeekStart = prevTimestamp / 1 days - DateTimeLib.weekday(prevTimestamp) + 1;

            bytes20 addr = bytes20(from);

            // Check if the previous transfer was a week ago and the "from" address is dead.
            return
                (prevWeekStart + 7 == curWeekStart && (addr[0] == 0xde && addr[1] == 0xad)) ||
                (addr[18] == 0xde && addr[19] == 0xad);
        }

        // A new place every day, Road trip
        if (todo == A_NEW_PLACE_EVERY_DAY || todo == ROAD_TRIP) {
            return
                trackLastNTransfersWithInterval({
                    todo: todo,
                    tokenId: tokenId,
                    length: 7,
                    from: from,
                    to: to,
                    interval: 1 days
                });
        }

        // Go sightseeing
        if (todo == GO_SIGHTSEEING) {
            return
                trackLastNTransfersWithInterval({
                    todo: todo,
                    tokenId: tokenId,
                    length: 4,
                    from: from,
                    to: to,
                    interval: 1 hours
                });
        }

        // Do 3 in a row, Do 3
        if (todo == DO_3) {
            return trackLastNTransfers(todo, tokenId, 3);
        }

        // Do 5
        if (todo == DO_5) {
            return trackLastNTransfers(todo, tokenId, 5);
        }

        // Do 5
        if (todo == DO_5 || todo == GIVE_ME_5) {
            return trackLastNTransfers(todo, tokenId, 5);
        }

        // Do 7
        if (todo == DO_7) {
            return trackLastNTransfers(todo, tokenId, 7);
        }

        // Do 10
        if (todo == DO_10) {
            return trackLastNTransfers(todo, tokenId, 10);
        }

        // Date
        if (todo == A_DATE) {
            uint256 detRand = uint256(keccak256(abi.encodePacked(tokenId, todoIndex)));
            (, uint month, uint day) = DateTimeLib.epochDayToDate((detRand % 365) + 1);
            (, uint curMonth, uint curDay) = DateTimeLib.timestampToDate(block.timestamp);
            return (month == curMonth && day == curDay);
        }

        // If we don't know the todo, we can't fullfill it
        return false;
    }

    /*//////////////////////////////////////////////////////////////
                            LOGIC HELPERS
    //////////////////////////////////////////////////////////////*/

    function succeedWithProbability(uint256 probability) internal view returns (bool) {
        return uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao))) % 100 <= probability;
    }

    function trackEveryDay(uint todo, uint tokenId, uint period) internal returns (bool) {
        // Normalize to epoch days (Days since 1970-01-01)
        uint curDay = block.timestamp / 1 days;
        uint prevDay = tokenData[tokenId].lastTransferTime / 1 days;

        // We check if the previous day was yesterday
        if (prevDay + 1 == curDay) {
            todoCounters[tokenId][todo]++;
        } else if (prevDay + 1 < curDay) {
            // If we have a gap of more than one day, we reset the counter
            todoCounters[tokenId][todo] = 0;
        }

        // Period - 1 because we start counting from 0 (this is how the todoCounter is initialized)
        if (todoCounters[tokenId][todo] == period - 1) {
            todoCounters[tokenId][todo] = 0;
            return true;
        }

        return false;
    }

    function calculateMonthsSinceEpoch(uint timestamp) internal pure returns (uint) {
        (uint year, uint month, ) = DateTimeLib.timestampToDate(timestamp);
        return year * 12 + month;
    }

    function trackEveryWeek(uint todo, uint tokenId, uint period) internal returns (bool) {
        // Get this weeks Monday 00:00:00 in epoch days
        uint curWeekStart = block.timestamp / 1 days - DateTimeLib.weekday(block.timestamp) + 1;

        // Get the previous weeks Monday 00:00:00 in epoch days
        uint prevTimestamp = tokenData[tokenId].lastTransferTime;
        uint prevWeekStart = prevTimestamp / 1 days - DateTimeLib.weekday(prevTimestamp) + 1;

        // We check if the transactions were in continuous weeks
        if (prevWeekStart + 7 == curWeekStart) {
            todoCounters[tokenId][todo]++;
        } else if (prevWeekStart + 1 < curWeekStart) {
            // If we have a gap of more than one week, we reset the counter
            todoCounters[tokenId][todo] = 0;
        }

        // Period - 1 because we start counting from 0 (this is how the todoCounter is initialized)
        if (todoCounters[tokenId][todo] == period - 1) {
            todoCounters[tokenId][todo] = 0;
            return true;
        }

        return false;
    }

    function trackEverySeason(uint todo, uint tokenId) internal returns (bool) {
        // Track the last transfers and check if they were in consecutive seasons.
        // Winter: Dec-Feb, Spring: Mar-May, Summer: Jun-Aug, Autumn: Sep-Nov
        // Transfers can start in any season to be valid.

        (, uint curMonth, ) = DateTimeLib.timestampToDate(block.timestamp);
        (, uint prevMonth, ) = DateTimeLib.timestampToDate(tokenData[tokenId].lastTransferTime);

        // Normalize to season
        uint curSeason = (curMonth % 12) / 3;
        uint prevSeason = (prevMonth % 12) / 3;

        if ((prevSeason + 1) % 4 == curSeason) {
            todoCounters[tokenId][todo]++;
        } else {
            // If we have a gap of not exactly one season, we reset the counter
            todoCounters[tokenId][todo] = 0;
            return false;
        }

        if (todoCounters[tokenId][todo] == 3) {
            todoCounters[tokenId][todo] = 0;
            return true;
        }

        return false;
    }

    function trackLastNTransfersWithinTimeWindow(
        uint todo,
        uint tokenId,
        uint8 length,
        uint timeWindow
    ) internal returns (bool) {
        TransferTracker memory tracker = transferTrackers[tokenId][todo];

        // typecast timestamp to bytes4 , this results in a resolution of 136 years
        bytes4 currentTimeStamp = bytes4(uint32(block.timestamp % type(uint32).max));
        bytes4 earliestTime = bytes4(uint32((block.timestamp - timeWindow) % type(uint32).max));

        // add the new timestamp to the tracker on the right
        tracker.data[tracker.right] = currentTimeStamp;

        // increment right pointer
        tracker.right = (tracker.right + 1) % length;

        // end condition: left pointer is equal to right (but we also need to exclude the initial state)
        if (tracker.left == tracker.right && tracker.data[0] != 0x0) {
            // Check if left timestamp is within the timeWindow
            if (tracker.data[tracker.left] >= earliestTime) {
                delete transferTrackers[tokenId][todo];
                return true;
            }
        }

        // if left timestamp is not within timeWindow, we pop-left (adjust the left pointer)
        // we loop from the left pointer to the right pointer
        while (tracker.left != tracker.right) {
            if (tracker.data[tracker.left] < earliestTime) {
                tracker.left = (tracker.left + 1) % length;
            } else {
                break;
            }
        }

        // save to storage
        transferTrackers[tokenId][todo] = tracker;

        return false;
    }

    function trackLastNTransfersWithInterval(
        uint todo,
        uint tokenId,
        uint8 length,
        address from,
        address to,
        uint interval
    ) internal returns (bool) {
        TransferTracker memory tracker = transferTrackers[tokenId][todo];

        // normalize time to interval
        uint curTime = block.timestamp / interval;
        uint prevTime = tokenData[tokenId].lastTransferTime / interval;

        // if the previous transfer was not within the interval, we reset the tracker
        if (prevTime + 1 != curTime) {
            tracker.left = tracker.right;
        }

        // add the new address to the tracker
        tracker.data[tracker.right] = bytes4(bytes20(from));

        // increment right pointer
        tracker.right = (tracker.right + 1) % length;

        // end condition: left pointer is equal to right (but we also need to exclude the initial state)
        if (tracker.left == tracker.right && tracker.data[0] != 0x0) {
            if (tracker.data[tracker.left] == bytes4(bytes20(to))) {
                delete transferTrackers[tokenId][todo];
                return true;
            }
        }

        // If new address is a duplicate, we adjust the left pointer.
        // We loop from the left pointer to the right pointer.
        uint8 left = tracker.left;
        while (left != tracker.right) {
            if (tracker.data[left] == bytes4(bytes20(to))) {
                tracker.left = (left + 1) % length;
                break;
            }
            left = (left + 1) % length;
        }

        // save to storage
        transferTrackers[tokenId][todo] = tracker;

        return false;
    }

    function trackLastNTransfers(uint todo, uint tokenId, uint8 n) internal returns (bool) {
        todoCounters[tokenId][todo]++;

        if (todoCounters[tokenId][todo] == n) {
            delete todoCounters[tokenId][todo];
            return true;
        }

        return false;
    }

    function trackDistinctAddressesInARow(
        uint todo,
        uint tokenId,
        address from,
        address to,
        uint8 length
    ) internal returns (bool) {
        TransferTracker memory tracker = transferTrackers[tokenId][todo];

        // add the new address to the tracker
        tracker.data[tracker.right] = bytes4(bytes20(from));

        // adjust right pointer
        tracker.right = (tracker.right + 1) % length;

        // end condition: left pointer is equal to right (but we also need exclude the initial state)
        if (tracker.left == tracker.right && tracker.data[0] != 0x0) {
            if (tracker.data[tracker.left] == bytes4(bytes20(to))) {
                delete transferTrackers[tokenId][todo];
                return true;
            }
        }

        // If new address is a duplicate, we adjust the left pointer.
        // We loop from the left pointer to the right pointer.
        uint8 left = tracker.left;
        while (left != tracker.right) {
            if (tracker.data[left] == bytes4(bytes20(to))) {
                tracker.left = (left + 1) % length;
                break;
            }
            left = (left + 1) % length;
        }

        // save to storage
        transferTrackers[tokenId][todo] = tracker;

        return false;
    }

    /*//////////////////////////////////////////////////////////////
                               tokenURI
    //////////////////////////////////////////////////////////////*/

    function tokenURI(uint256 tokenId) external view returns (string memory) {
        Token memory token = tokenData[tokenId];
        return
            IHonestWorkRender(renderContract).tokenURI(
                tokenId,
                tokenTodos[tokenId],
                token.activeTodosIndices,
                token.open,
                token.max,
                token.repeater
            );
    }

    function renderSVG(uint256 tokenId) external view returns (string memory) {
        Token memory token = tokenData[tokenId];
        return
            IHonestWorkRender(renderContract).renderSVG(
                tokenId,
                tokenTodos[tokenId],
                token.activeTodosIndices,
                token.open
            );
    }

    function renderSVGBase64(uint256 tokenId) external view returns (string memory) {
        Token memory token = tokenData[tokenId];
        return
            IHonestWorkRender(renderContract).renderSVGBase64(
                tokenId,
                tokenTodos[tokenId],
                token.activeTodosIndices,
                token.open
            );
    }
}

File 2 of 5 : DateTimeLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for date time operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/DateTimeLib.sol)
/// @author Modified from BokkyPooBahsDateTimeLibrary (https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary)
/// @dev
/// Conventions:
/// --------------------------------------------------------------------+
/// Unit      | Range                | Notes                            |
/// --------------------------------------------------------------------|
/// timestamp | 0..0x1e18549868c76ff | Unix timestamp.                  |
/// epochDay  | 0..0x16d3e098039     | Days since 1970-01-01.           |
/// year      | 1970..0xffffffff     | Gregorian calendar year.         |
/// month     | 1..12                | Gregorian calendar month.        |
/// day       | 1..31                | Gregorian calendar day of month. |
/// weekday   | 1..7                 | The day of the week (1-indexed). |
/// --------------------------------------------------------------------+
/// All timestamps of days are rounded down to 00:00:00 UTC.
library DateTimeLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Weekdays are 1-indexed, adhering to ISO 8601.

    uint256 internal constant MON = 1;
    uint256 internal constant TUE = 2;
    uint256 internal constant WED = 3;
    uint256 internal constant THU = 4;
    uint256 internal constant FRI = 5;
    uint256 internal constant SAT = 6;
    uint256 internal constant SUN = 7;

    // Months and days of months are 1-indexed, adhering to ISO 8601.

    uint256 internal constant JAN = 1;
    uint256 internal constant FEB = 2;
    uint256 internal constant MAR = 3;
    uint256 internal constant APR = 4;
    uint256 internal constant MAY = 5;
    uint256 internal constant JUN = 6;
    uint256 internal constant JUL = 7;
    uint256 internal constant AUG = 8;
    uint256 internal constant SEP = 9;
    uint256 internal constant OCT = 10;
    uint256 internal constant NOV = 11;
    uint256 internal constant DEC = 12;

    // These limits are large enough for most practical purposes.
    // Inputs that exceed these limits result in undefined behavior.

    uint256 internal constant MAX_SUPPORTED_YEAR = 0xffffffff;
    uint256 internal constant MAX_SUPPORTED_EPOCH_DAY = 0x16d3e098039;
    uint256 internal constant MAX_SUPPORTED_TIMESTAMP = 0x1e18549868c76ff;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    DATE TIME OPERATIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the number of days since 1970-01-01 from (`year`,`month`,`day`).
    /// See: https://howardhinnant.github.io/date_algorithms.html
    /// Note: Inputs outside the supported ranges result in undefined behavior.
    /// Use {isSupportedDate} to check if the inputs are supported.
    function dateToEpochDay(uint256 year, uint256 month, uint256 day)
        internal
        pure
        returns (uint256 epochDay)
    {
        /// @solidity memory-safe-assembly
        assembly {
            year := sub(year, lt(month, 3))
            let doy := add(shr(11, add(mul(62719, mod(add(month, 9), 12)), 769)), day)
            let yoe := mod(year, 400)
            let doe := sub(add(add(mul(yoe, 365), shr(2, yoe)), doy), div(yoe, 100))
            epochDay := sub(add(mul(div(year, 400), 146097), doe), 719469)
        }
    }

    /// @dev Returns (`year`,`month`,`day`) from the number of days since 1970-01-01.
    /// Note: Inputs outside the supported ranges result in undefined behavior.
    /// Use {isSupportedDays} to check if the inputs is supported.
    function epochDayToDate(uint256 epochDay)
        internal
        pure
        returns (uint256 year, uint256 month, uint256 day)
    {
        /// @solidity memory-safe-assembly
        assembly {
            epochDay := add(epochDay, 719468)
            let doe := mod(epochDay, 146097)
            let yoe :=
                div(sub(sub(add(doe, div(doe, 36524)), div(doe, 1460)), eq(doe, 146096)), 365)
            let doy := sub(doe, sub(add(mul(365, yoe), shr(2, yoe)), div(yoe, 100)))
            let mp := div(add(mul(5, doy), 2), 153)
            day := add(sub(doy, shr(11, add(mul(mp, 62719), 769))), 1)
            month := byte(mp, shl(160, 0x030405060708090a0b0c0102))
            year := add(add(yoe, mul(div(epochDay, 146097), 400)), lt(month, 3))
        }
    }

    /// @dev Returns the unix timestamp from (`year`,`month`,`day`).
    /// Note: Inputs outside the supported ranges result in undefined behavior.
    /// Use {isSupportedDate} to check if the inputs are supported.
    function dateToTimestamp(uint256 year, uint256 month, uint256 day)
        internal
        pure
        returns (uint256 result)
    {
        unchecked {
            result = dateToEpochDay(year, month, day) * 86400;
        }
    }

    /// @dev Returns (`year`,`month`,`day`) from the given unix timestamp.
    /// Note: Inputs outside the supported ranges result in undefined behavior.
    /// Use {isSupportedTimestamp} to check if the inputs are supported.
    function timestampToDate(uint256 timestamp)
        internal
        pure
        returns (uint256 year, uint256 month, uint256 day)
    {
        (year, month, day) = epochDayToDate(timestamp / 86400);
    }

    /// @dev Returns the unix timestamp from
    /// (`year`,`month`,`day`,`hour`,`minute`,`second`).
    /// Note: Inputs outside the supported ranges result in undefined behavior.
    /// Use {isSupportedDateTime} to check if the inputs are supported.
    function dateTimeToTimestamp(
        uint256 year,
        uint256 month,
        uint256 day,
        uint256 hour,
        uint256 minute,
        uint256 second
    ) internal pure returns (uint256 result) {
        unchecked {
            result = dateToEpochDay(year, month, day) * 86400 + hour * 3600 + minute * 60 + second;
        }
    }

    /// @dev Returns (`year`,`month`,`day`,`hour`,`minute`,`second`)
    /// from the given unix timestamp.
    /// Note: Inputs outside the supported ranges result in undefined behavior.
    /// Use {isSupportedTimestamp} to check if the inputs are supported.
    function timestampToDateTime(uint256 timestamp)
        internal
        pure
        returns (
            uint256 year,
            uint256 month,
            uint256 day,
            uint256 hour,
            uint256 minute,
            uint256 second
        )
    {
        unchecked {
            (year, month, day) = epochDayToDate(timestamp / 86400);
            uint256 secs = timestamp % 86400;
            hour = secs / 3600;
            secs = secs % 3600;
            minute = secs / 60;
            second = secs % 60;
        }
    }

    /// @dev Returns if the `year` is leap.
    function isLeapYear(uint256 year) internal pure returns (bool leap) {
        /// @solidity memory-safe-assembly
        assembly {
            leap := iszero(and(add(mul(iszero(mod(year, 25)), 12), 3), year))
        }
    }

    /// @dev Returns number of days in given `month` of `year`.
    function daysInMonth(uint256 year, uint256 month) internal pure returns (uint256 result) {
        bool flag = isLeapYear(year);
        /// @solidity memory-safe-assembly
        assembly {
            // `daysInMonths = [31,28,31,30,31,30,31,31,30,31,30,31]`.
            // `result = daysInMonths[month - 1] + isLeapYear(year)`.
            result :=
                add(byte(month, shl(152, 0x1f1c1f1e1f1e1f1f1e1f1e1f)), and(eq(month, 2), flag))
        }
    }

    /// @dev Returns the weekday from the unix timestamp.
    /// Monday: 1, Tuesday: 2, ....., Sunday: 7.
    function weekday(uint256 timestamp) internal pure returns (uint256 result) {
        unchecked {
            result = ((timestamp / 86400 + 3) % 7) + 1;
        }
    }

    /// @dev Returns if (`year`,`month`,`day`) is a supported date.
    /// - `1970 <= year <= MAX_SUPPORTED_YEAR`.
    /// - `1 <= month <= 12`.
    /// - `1 <= day <= daysInMonth(year, month)`.
    function isSupportedDate(uint256 year, uint256 month, uint256 day)
        internal
        pure
        returns (bool result)
    {
        uint256 md = daysInMonth(year, month);
        /// @solidity memory-safe-assembly
        assembly {
            result :=
                and(
                    lt(sub(year, 1970), sub(MAX_SUPPORTED_YEAR, 1969)),
                    and(lt(sub(month, 1), 12), lt(sub(day, 1), md))
                )
        }
    }

    /// @dev Returns if (`year`,`month`,`day`,`hour`,`minute`,`second`) is a supported date time.
    /// - `1970 <= year <= MAX_SUPPORTED_YEAR`.
    /// - `1 <= month <= 12`.
    /// - `1 <= day <= daysInMonth(year, month)`.
    /// - `hour < 24`.
    /// - `minute < 60`.
    /// - `second < 60`.
    function isSupportedDateTime(
        uint256 year,
        uint256 month,
        uint256 day,
        uint256 hour,
        uint256 minute,
        uint256 second
    ) internal pure returns (bool result) {
        if (isSupportedDate(year, month, day)) {
            /// @solidity memory-safe-assembly
            assembly {
                result := and(lt(hour, 24), and(lt(minute, 60), lt(second, 60)))
            }
        }
    }

    /// @dev Returns if `epochDay` is a supported unix epoch day.
    function isSupportedEpochDay(uint256 epochDay) internal pure returns (bool result) {
        unchecked {
            result = epochDay < MAX_SUPPORTED_EPOCH_DAY + 1;
        }
    }

    /// @dev Returns if `timestamp` is a supported unix timestamp.
    function isSupportedTimestamp(uint256 timestamp) internal pure returns (bool result) {
        unchecked {
            result = timestamp < MAX_SUPPORTED_TIMESTAMP + 1;
        }
    }

    /// @dev Returns the unix timestamp of the given `n`th weekday `wd`, in `month` of `year`.
    /// Example: 3rd Friday of Feb 2022 is `nthWeekdayInMonthOfYearTimestamp(2022, 2, 3, 5)`
    /// Note: `n` is 1-indexed for traditional consistency.
    /// Invalid weekdays (i.e. `wd == 0 || wd > 7`) result in undefined behavior.
    function nthWeekdayInMonthOfYearTimestamp(uint256 year, uint256 month, uint256 n, uint256 wd)
        internal
        pure
        returns (uint256 result)
    {
        uint256 d = dateToEpochDay(year, month, 1);
        uint256 md = daysInMonth(year, month);
        /// @solidity memory-safe-assembly
        assembly {
            let diff := sub(wd, add(mod(add(d, 3), 7), 1))
            let date := add(mul(sub(n, 1), 7), add(mul(gt(diff, 6), 7), diff))
            result := mul(mul(86400, add(date, d)), and(lt(date, md), iszero(iszero(n))))
        }
    }

    /// @dev Returns the unix timestamp of the most recent Monday.
    function mondayTimestamp(uint256 timestamp) internal pure returns (uint256 result) {
        uint256 t = timestamp;
        /// @solidity memory-safe-assembly
        assembly {
            let day := div(t, 86400)
            result := mul(mul(sub(day, mod(add(day, 3), 7)), 86400), gt(t, 345599))
        }
    }

    /// @dev Returns whether the unix timestamp falls on a Saturday or Sunday.
    /// To check whether it is a week day, just take the negation of the result.
    function isWeekEnd(uint256 timestamp) internal pure returns (bool result) {
        result = weekday(timestamp) > FRI;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*              DATE TIME ARITHMETIC OPERATIONS               */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Adds `numYears` to the unix timestamp, and returns the result.
    /// Note: The result will share the same Gregorian calendar month,
    /// but different Gregorian calendar years for non-zero `numYears`.
    /// If the Gregorian calendar month of the result has less days
    /// than the Gregorian calendar month day of the `timestamp`,
    /// the result's month day will be the maximum possible value for the month.
    /// (e.g. from 29th Feb to 28th Feb)
    function addYears(uint256 timestamp, uint256 numYears) internal pure returns (uint256 result) {
        (uint256 year, uint256 month, uint256 day) = epochDayToDate(timestamp / 86400);
        result = _offsetted(year + numYears, month, day, timestamp);
    }

    /// @dev Adds `numMonths` to the unix timestamp, and returns the result.
    /// Note: If the Gregorian calendar month of the result has less days
    /// than the Gregorian calendar month day of the `timestamp`,
    /// the result's month day will be the maximum possible value for the month.
    /// (e.g. from 29th Feb to 28th Feb)
    function addMonths(uint256 timestamp, uint256 numMonths)
        internal
        pure
        returns (uint256 result)
    {
        (uint256 year, uint256 month, uint256 day) = epochDayToDate(timestamp / 86400);
        month = _sub(month + numMonths, 1);
        result = _offsetted(year + month / 12, _add(month % 12, 1), day, timestamp);
    }

    /// @dev Adds `numDays` to the unix timestamp, and returns the result.
    function addDays(uint256 timestamp, uint256 numDays) internal pure returns (uint256 result) {
        result = timestamp + numDays * 86400;
    }

    /// @dev Adds `numHours` to the unix timestamp, and returns the result.
    function addHours(uint256 timestamp, uint256 numHours) internal pure returns (uint256 result) {
        result = timestamp + numHours * 3600;
    }

    /// @dev Adds `numMinutes` to the unix timestamp, and returns the result.
    function addMinutes(uint256 timestamp, uint256 numMinutes)
        internal
        pure
        returns (uint256 result)
    {
        result = timestamp + numMinutes * 60;
    }

    /// @dev Adds `numSeconds` to the unix timestamp, and returns the result.
    function addSeconds(uint256 timestamp, uint256 numSeconds)
        internal
        pure
        returns (uint256 result)
    {
        result = timestamp + numSeconds;
    }

    /// @dev Subtracts `numYears` from the unix timestamp, and returns the result.
    /// Note: The result will share the same Gregorian calendar month,
    /// but different Gregorian calendar years for non-zero `numYears`.
    /// If the Gregorian calendar month of the result has less days
    /// than the Gregorian calendar month day of the `timestamp`,
    /// the result's month day will be the maximum possible value for the month.
    /// (e.g. from 29th Feb to 28th Feb)
    function subYears(uint256 timestamp, uint256 numYears) internal pure returns (uint256 result) {
        (uint256 year, uint256 month, uint256 day) = epochDayToDate(timestamp / 86400);
        result = _offsetted(year - numYears, month, day, timestamp);
    }

    /// @dev Subtracts `numYears` from the unix timestamp, and returns the result.
    /// Note: If the Gregorian calendar month of the result has less days
    /// than the Gregorian calendar month day of the `timestamp`,
    /// the result's month day will be the maximum possible value for the month.
    /// (e.g. from 29th Feb to 28th Feb)
    function subMonths(uint256 timestamp, uint256 numMonths)
        internal
        pure
        returns (uint256 result)
    {
        (uint256 year, uint256 month, uint256 day) = epochDayToDate(timestamp / 86400);
        uint256 yearMonth = _totalMonths(year, month) - _add(numMonths, 1);
        result = _offsetted(yearMonth / 12, _add(yearMonth % 12, 1), day, timestamp);
    }

    /// @dev Subtracts `numDays` from the unix timestamp, and returns the result.
    function subDays(uint256 timestamp, uint256 numDays) internal pure returns (uint256 result) {
        result = timestamp - numDays * 86400;
    }

    /// @dev Subtracts `numHours` from the unix timestamp, and returns the result.
    function subHours(uint256 timestamp, uint256 numHours) internal pure returns (uint256 result) {
        result = timestamp - numHours * 3600;
    }

    /// @dev Subtracts `numMinutes` from the unix timestamp, and returns the result.
    function subMinutes(uint256 timestamp, uint256 numMinutes)
        internal
        pure
        returns (uint256 result)
    {
        result = timestamp - numMinutes * 60;
    }

    /// @dev Subtracts `numSeconds` from the unix timestamp, and returns the result.
    function subSeconds(uint256 timestamp, uint256 numSeconds)
        internal
        pure
        returns (uint256 result)
    {
        result = timestamp - numSeconds;
    }

    /// @dev Returns the difference in Gregorian calendar years
    /// between `fromTimestamp` and `toTimestamp`.
    /// Note: Even if the true time difference is less than a year,
    /// the difference can be non-zero is the timestamps are
    /// from different Gregorian calendar years
    function diffYears(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 result)
    {
        toTimestamp - fromTimestamp;
        (uint256 fromYear,,) = epochDayToDate(fromTimestamp / 86400);
        (uint256 toYear,,) = epochDayToDate(toTimestamp / 86400);
        result = _sub(toYear, fromYear);
    }

    /// @dev Returns the difference in Gregorian calendar months
    /// between `fromTimestamp` and `toTimestamp`.
    /// Note: Even if the true time difference is less than a month,
    /// the difference can be non-zero is the timestamps are
    /// from different Gregorian calendar months.
    function diffMonths(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 result)
    {
        toTimestamp - fromTimestamp;
        (uint256 fromYear, uint256 fromMonth,) = epochDayToDate(fromTimestamp / 86400);
        (uint256 toYear, uint256 toMonth,) = epochDayToDate(toTimestamp / 86400);
        result = _sub(_totalMonths(toYear, toMonth), _totalMonths(fromYear, fromMonth));
    }

    /// @dev Returns the difference in days between `fromTimestamp` and `toTimestamp`.
    function diffDays(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 result)
    {
        result = (toTimestamp - fromTimestamp) / 86400;
    }

    /// @dev Returns the difference in hours between `fromTimestamp` and `toTimestamp`.
    function diffHours(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 result)
    {
        result = (toTimestamp - fromTimestamp) / 3600;
    }

    /// @dev Returns the difference in minutes between `fromTimestamp` and `toTimestamp`.
    function diffMinutes(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 result)
    {
        result = (toTimestamp - fromTimestamp) / 60;
    }

    /// @dev Returns the difference in seconds between `fromTimestamp` and `toTimestamp`.
    function diffSeconds(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 result)
    {
        result = toTimestamp - fromTimestamp;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unchecked arithmetic for computing the total number of months.
    function _totalMonths(uint256 numYears, uint256 numMonths)
        private
        pure
        returns (uint256 total)
    {
        unchecked {
            total = numYears * 12 + numMonths;
        }
    }

    /// @dev Unchecked arithmetic for adding two numbers.
    function _add(uint256 a, uint256 b) private pure returns (uint256 c) {
        unchecked {
            c = a + b;
        }
    }

    /// @dev Unchecked arithmetic for subtracting two numbers.
    function _sub(uint256 a, uint256 b) private pure returns (uint256 c) {
        unchecked {
            c = a - b;
        }
    }

    /// @dev Returns the offsetted timestamp.
    function _offsetted(uint256 year, uint256 month, uint256 day, uint256 timestamp)
        private
        pure
        returns (uint256 result)
    {
        uint256 dm = daysInMonth(year, month);
        if (day >= dm) {
            day = dm;
        }
        result = dateToEpochDay(year, month, day) * 86400 + (timestamp % 86400);
    }
}

File 3 of 5 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
/// @dev While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;


    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits.
            newOwner := shr(96, shl(96, newOwner))
            // Store the new value.
            sstore(not(_OWNER_SLOT_NOT), newOwner)
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            let ownerSlot := not(_OWNER_SLOT_NOT)
            // Clean the upper 96 bits.
            newOwner := shr(96, shl(96, newOwner))
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
            // Store the new value.
            sstore(ownerSlot, newOwner)
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(not(_OWNER_SLOT_NOT))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         MODIFIERS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}

File 4 of 5 : IHonestWorkRender.sol
// SPDX-License-Identifier: UNLICENSE
pragma solidity 0.8.25;

interface IHonestWorkRender {
    function tokenURI(
        uint256 tokenId,
        uint256[] calldata tokenTodos,
        uint24[3] calldata activeTodoIndices,
        uint8 open,
        uint8 max,
        bool repeater
    ) external view returns (string memory);

    function renderSVG(
        uint256 tokenId,
        uint256[] calldata tokenTodos,
        uint24[3] calldata activeTodoIndices,
        uint8 open
    ) external view returns (string memory);

    function renderSVGBase64(
        uint256 tokenId,
        uint256[] calldata tokenTodos,
        uint24[3] calldata activeTodoIndices,
        uint8 open
    ) external view returns (string memory);

    function resolveTask(uint256 taskId) external view returns (string memory);
}

File 5 of 5 : TodoVariables.sol
// SPDX-License-Identifier: UNLICENSE
pragma solidity 0.8.25;

uint256 constant GET_1_DONE = 1;
uint256 constant GET_5_DONE = 2;
uint256 constant GET_10_DONE = 3;
uint256 constant LOW_GAS = 4;
uint256 constant EVEN_BLOCKS = 5;
uint256 constant ODD_BLOCKS = 6;
uint256 constant SEND_ETH_WITH_IT = 7;
uint256 constant DONT_SEND_ETH_WITH_IT = 8;
uint256 constant PAY_1_WEI = 9;
uint256 constant SAFETY_FIRST = 10;
uint256 constant FCK_SAFETY = 11;
uint256 constant WITH_PASSWORD = 12;
uint256 constant BE_LUCKY = 13;
uint256 constant ITS_ABOUT_THE_JOURNEY = 14;
uint256 constant TAKE_A_CHANCE = 15;
uint256 constant TRUST_THE_PROCESS = 16;
uint256 constant BE_PERSISTENT = 17;
uint256 constant KEEP_TRYING = 18;
uint256 constant KEEP_ON_KEEPING_ON = 19;
uint256 constant FIFTY_FIFTY = 20;
uint256 constant TRY_IT_USUALLY_WORKS = 21;
uint256 constant EASY_WORK = 22;
uint256 constant HARD_WORK = 23;
uint256 constant YOU_ARE_HERE = 24;
uint256 constant YOU_ARE_ENOUGH = 25;
uint256 constant BEEF = 26;
uint256 constant BEEF_2 = 27;
uint256 constant BEEF_ONLY = 28;
uint256 constant AVOID_THE_BEEF = 29;
uint256 constant DEAD = 30;
uint256 constant DEAD_2 = 31;
uint256 constant BABE = 32;
uint256 constant BABE_2 = 33;
uint256 constant DEAF = 34;
uint256 constant FEED = 35;
uint256 constant FED = 36;
uint256 constant BAD = 37;
uint256 constant BAD_2 = 38;
uint256 constant BAD_3 = 39;
uint256 constant FACE = 40;
uint256 constant FACE_2 = 41;
uint256 constant TO_SELF = 42;
uint256 constant TREAT_YOURSELF = 43;
uint256 constant A_A = 44;
uint256 constant TO_SOMEONE_ELSE = 45;
uint256 constant AWAY = 46;
uint256 constant OFF_YOU_GO = 47;
uint256 constant TO_SOMEONE_FOREIGN = 48;
uint256 constant TO_CONTRACT = 49;
uint256 constant ORIGIN_NOT_SENDER = 50;
uint256 constant ORIGIN_NOT_SENDER_2 = 51;
uint256 constant TO_ZERO_ETH = 52;
uint256 constant ZERO_ETH = 53;
uint256 constant ONE_ETH = 54;
uint256 constant MAKE_ME_JEALOUS = 55;
uint256 constant EVEN_BALANCE = 56;
uint256 constant ODD_BALANCE = 57;
uint256 constant HAVE_MULTIPLE_LISTS = 58;
uint256 constant OPENING_HOURS = 59;
uint256 constant OUTSIDE_OPENING_HOURS = 60;
uint256 constant MONDAY = 61;
uint256 constant NOT_MONDAY = 62;
uint256 constant TUESDAY = 63;
uint256 constant NOT_TUESDAY = 64;
uint256 constant WEDNESDAY = 65;
uint256 constant NOT_WEDNESDAY = 66;
uint256 constant THURSDAY = 67;
uint256 constant NOT_THURSDAY = 68;
uint256 constant FRIDAY = 69;
uint256 constant NOT_FRIDAY = 70;
uint256 constant SATURDAY = 71;
uint256 constant NOT_SATURDAY = 72;
uint256 constant SUNDAY = 73;
uint256 constant NOT_SUNDAY = 74;
uint256 constant WEEKEND = 75;
uint256 constant NOT_WEEKEND = 76;
uint256 constant WEEK = 77;
uint256 constant NOT_WEEK = 78;
uint256 constant SUMMER = 79;
uint256 constant NOT_SUMMER = 80;
uint256 constant WINTER = 81;
uint256 constant NOT_WINTER = 82;
uint256 constant SPRING = 83;
uint256 constant NOT_SPRING = 84;
uint256 constant AUTUMN = 85;
uint256 constant NOT_AUTUMN = 86;
uint256 constant IN_ANY_SEASON = 87;
uint256 constant SEVEN_ELEVEN = 88;
uint256 constant AT_MIDNIGHT = 89;
uint256 constant HAPPY_NEW_YEAR = 90;
uint256 constant A_DATE = 91;
uint256 constant DO_NOTHING_FOR_5_MINUTES = 92;
uint256 constant TAKE_A_MOMENT = 93;
uint256 constant NOT_NOW = 94;
uint256 constant SNOOZE = 95;
uint256 constant DO_NOTHING_FOR_AN_HOUR = 96;
uint256 constant GO_LOOK_AT_THE_SKY = 97;
uint256 constant TIME_FOR_LUNCH = 98;
uint256 constant DO_NOTHING_FOR_TWELVE_HOURS = 99;
uint256 constant DO_NOTHING_FOR_A_DAY = 100;
uint256 constant TOMORROW_IS_ANOTHER_DAY = 101;
uint256 constant SLEEP_ON_IT = 102;
uint256 constant TAKE_TODAY_OFF = 103;
uint256 constant COME_BACK_TOMORROW = 104;
uint256 constant TOUCH_GRASS = 105;
uint256 constant PROCRASTINATE = 106;
uint256 constant DO_NOTHING_FOR_48_HOURS = 107;
uint256 constant DO_NOTHING_FOR_A_WEEK = 108;
uint256 constant TAKE_A_WEEK_OFF = 109;
uint256 constant HOLIDAY_TIME = 110;
uint256 constant DO_NOTHING_FOR_A_MONTH = 111;
uint256 constant WAIT_A_MONTH = 112;
uint256 constant DO_NOTHING_FOR_A_YEAR = 113;
uint256 constant NEXT_YEAR_WILL_BE_GREAT = 114;
uint256 constant TWO_IN_TWO = 115;
uint256 constant THREE_IN_THREE = 116;
uint256 constant FIVE_IN_FIVE = 117;
uint256 constant EVERY_10_MINUTES_FOR_AN_HOUR = 118;
uint256 constant EVERY_DAY_FOR_A_WEEK = 119;
uint256 constant STEADY_JOB = 120;
uint256 constant EVERY_WEEK_FOR_A_MONTH = 121;
uint256 constant EVERY_MONTH_FOR_A_YEAR = 122;
uint256 constant EVERY_SEASON = 123;
uint256 constant TWICE_WITHIN_A_BLOCK = 124;
uint256 constant STAY_THE_WEEKEND = 125;
uint256 constant STAY_THE_NIGHT = 126;
uint256 constant ON_A_CONTRACT_2_DAYS = 127;
uint256 constant VISIT_A_NEW_PLACE_TOMORROW = 128;
uint256 constant TAKE_A_SABBATICAL = 129;
uint256 constant BE_BAD_FOR_A_WEEK = 130;
uint256 constant PLAY_DEAD_FOR_A_WEEK = 131;
uint256 constant A_NEW_PLACE_EVERY_DAY = 132;
uint256 constant ROAD_TRIP = 133;
uint256 constant GO_SIGHTSEEING = 134;
uint256 constant WHERE_WHERE_YOU = 135;
uint256 constant TRANSFER_3_TIMES = 136;
uint256 constant TRANSFER_5_TIMES = 137;
uint256 constant TRANSFER_7_TIMES = 138;
uint256 constant TRANSFER_10_TIMES = 139;
uint256 constant DO_3 = 140;
uint256 constant DO_5 = 141;
uint256 constant DO_7 = 142;
uint256 constant DO_10 = 143;
uint256 constant GIVE_ME_5 = 144;
uint256 constant RING_OF_3 = 145;
uint256 constant RING_OF_5 = 146;
uint256 constant RING_OF_7 = 147;
uint256 constant LOVE_TRIANGLE = 148;
uint256 constant ALICE_AND_BOB = 149;
uint256 constant ALICE_BOB_AND_EVE = 150;
uint256 constant A_B_C = 151;
uint256 constant A_B_A = 152;
uint256 constant ASK_FOR_HELP = 153;
uint256 constant RETURN_TO_SENDER = 154;
uint256 constant DO_WHAT_YOU_WANT = 155;
uint256 constant ITS_NOT_MUCH = 156;
uint256 constant HONEST_WORK = 157;
uint256 constant ALL_PLAY_AND_NO_WORK = 158;
uint256 constant SEND_IT = 159;
uint256 constant JUST_TRANSFER = 160;
uint256 constant TRANSFER = 161;
uint256 constant DO_WHAT_YOU_LOVE = 162;
uint256 constant TRANSFER_AND_MAKE_A_WISH = 163;
uint256 constant TRANSFER_AND_CALL_YOUR_MOM = 164;
uint256 constant TAKE_A_DEEP_BREATH = 165;
uint256 constant WITH_YOUR_EYES_CLOSED = 166;
uint256 constant SUCCESS = 167;
uint256 constant YES = 168;
uint256 constant TO_YOUR_CRUSH = 169;
uint256 constant TO_SOMEONE_YOU_LIKE = 170;
uint256 constant TO_SOMEONE_YOU_DONT_LIKE = 171;
uint256 constant TO_SOMEONE_YOU_LOVE = 172;
uint256 constant TO_SOMEONE_YOU_HATE = 173;
uint256 constant SMILE = 174;
uint256 constant BE_CALM = 175;
uint256 constant GO_FOR_IT = 176;
uint256 constant ACT_NOW = 177;
uint256 constant DO_IT = 178;
uint256 constant START_A_RUMOR = 179;
uint256 constant DONT_DO_IT = 180;
uint256 constant REFUSE = 181;
uint256 constant FEELS_GOOD_TO = 182;
uint256 constant DONT_THINK = 183;

uint256 constant TOTAL_TODO_COUNT = 183;

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 2000000
  },
  "evmVersion": "cancun",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"todoId","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"TodoCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"todoIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"todoId","type":"uint256"}],"name":"TodoCreated","type":"event"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"balanceOfFrom","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"beforeTokenTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"createTodo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getTodoState","outputs":[{"internalType":"uint8","name":"open","type":"uint8"},{"internalType":"uint8","name":"max","type":"uint8"},{"internalType":"bool","name":"repeater","type":"bool"},{"internalType":"uint24","name":"todoCount","type":"uint24"},{"internalType":"uint24[3]","name":"activeTodosIndices","type":"uint24[3]"},{"internalType":"uint16[3]","name":"activeTodos","type":"uint16[3]"},{"internalType":"uint48","name":"lastTransferTime","type":"uint48"},{"internalType":"uint256[]","name":"todos","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renderContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"renderSVG","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"renderSVGBase64","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"taskId","type":"uint256"}],"name":"resolveTask","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"}],"name":"setRenderContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"}],"name":"setTokenContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"todoCounters","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenData","outputs":[{"internalType":"uint8","name":"open","type":"uint8"},{"internalType":"uint8","name":"max","type":"uint8"},{"internalType":"bool","name":"repeater","type":"bool"},{"internalType":"uint24","name":"todoCount","type":"uint24"},{"internalType":"uint48","name":"lastTransferTime","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenTodos","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"}]

6080604052348015600e575f80fd5b50601633601a565b6055565b6001600160a01b0316638b78c6d819819055805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b615fad806100625f395ff3fe608060405260043610610109575f3560e01c80638da5cb5b116100a1578063c321f9b411610071578063c87b56dd11610057578063c87b56dd146103d6578063d12a4c98146103f5578063f2fde38b14610414575f80fd5b8063c321f9b414610372578063c3c3a2f0146103c3575f80fd5b80638da5cb5b14610254578063adb3ca6714610287578063b4b5b48f146102b4578063bbcd5bbe14610353575f80fd5b80635ca2ddf1116100dc5780635ca2ddf1146101db578063715018a6146101fa57806372efa29f146102025780638415d21314610235575f80fd5b8063173db2e51461010d578063456d908e1461016357806348d8afd51461018f57806355a373d6146101b0575b5f80fd5b348015610118575f80fd5b506001546101399073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561016e575f80fd5b5061018261017d36600461588c565b610427565b60405161015a91906158a3565b34801561019a575f80fd5b506101ae6101a936600461588c565b6104df565b005b3480156101bb575f80fd5b505f546101399073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101e6575f80fd5b506101826101f536600461588c565b610860565b6101ae610a5d565b34801561020d575f80fd5b5061022161021c36600461588c565b610a70565b60405161015a98979695949392919061595d565b348015610240575f80fd5b506101ae61024f366004615a17565b610c45565b34801561025f575f80fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754610139565b348015610292575f80fd5b506102a66102a1366004615a30565b610c94565b60405190815260200161015a565b3480156102bf575f80fd5b506103146102ce36600461588c565b60026020525f90815260409020805460039091015460ff80831692610100810482169262010000820490921691630100000090910462ffffff169065ffffffffffff1685565b6040805160ff96871681529590941660208601529115159284019290925262ffffff909116606083015265ffffffffffff16608082015260a00161015a565b34801561035e575f80fd5b506101ae61036d366004615a17565b610cbf565b34801561037d575f80fd5b506103ae61038c366004615a30565b600560209081525f928352604080842090915290825290205463ffffffff1681565b60405163ffffffff909116815260200161015a565b6101ae6103d1366004615a50565b610d0d565b3480156103e1575f80fd5b506101826103f036600461588c565b6111d7565b348015610400575f80fd5b5061018261040f36600461588c565b611376565b6101ae610422366004615a17565b61150d565b6001546040517f456d908e0000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063456d908e906024015f60405180830381865afa158015610494573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104d99190810190615b2c565b92915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610501575f80fd5b5f8161beef604051602001610520929190918252602082015260400190565b604051602081830303815290604052805190602001205f1c90505f826001148061054a5750826019145b806105555750826032145b806105605750826064145b90505f8161058357610573600384615c22565b61057e906001615c62565b610586565b60015b90505f6003818461060057818361ffff168361ffff1660b76105a89190615c7b565b6105b29190615c7b565b6040805160208082018b90525f8284015282516024818403018152604490920190925280519101206105e49190615c22565b6105ee9190615c8e565b6105f9906001615c8e565b9050610634565b8660010361061057506071610634565b866019036106205750606f610634565b866032036106305750606c610634565b5060645b60035f8881526020019081526020015f2081908060018154018082558091505060019003905f5260205f20015f909161ffff169091909150555f6040518060e00160405280600160ff1681526020018660ff1681526020018715158152602001600162ffffff16815260200160405180606001604052805f62ffffff1662ffffff1681526020015f62ffffff1681526020015f62ffffff16815250815260200160405180606001604052808561ffff1661ffff1681526020015f61ffff1681526020015f61ffff1681525081526020014265ffffffffffff1681525090508060025f8a81526020019081526020015f205f820151815f015f6101000a81548160ff021916908360ff1602179055506020820151815f0160016101000a81548160ff021916908360ff1602179055506040820151815f0160026101000a81548160ff0219169083151502179055506060820151815f0160036101000a81548162ffffff021916908362ffffff1602179055506080820151816001019060036107bc929190615671565b5060a08201516107d29060028301906003615709565b5060c09190910151600390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001665ffffffffffff909216919091179055604080518981525f602082015261ffff84168183015290517fa2c76bc2f53d218db7b73da5593a6f3b09c71e0d92aca376720d10369814f0d5916060908290030190a15050505050505050565b5f818152600260209081526040808320815160e081018352815460ff80821683526101008204811695830195909552620100008104909416151581840152630100000090930462ffffff166060808501919091528251808201938490529094939260808401919060018401906003908288855b82829054906101000a900462ffffff1662ffffff16815260200190600301906020826002010492830192600103820291508084116108d357505050928452505060408051606081019182905260209093019291506002840190600390825f855b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116109335750505092845250505060039182015465ffffffffffff166020918201526001545f878152929091526040918290206080840151845193517f9416c65a00000000000000000000000000000000000000000000000000000000815294955073ffffffffffffffffffffffffffffffffffffffff90921693639416c65a936109f793899392909190600401615ce2565b5f60405180830381865afa158015610a11573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610a569190810190615b2c565b9392505050565b610a65611536565b610a6e5f61156b565b565b5f805f80610a7c61578c565b610a8461578c565b5f878152600260209081526040808320815160e081018352815460ff80821683526101008204811695830195909552620100008104909416151581840152630100000090930462ffffff1660608085019190915282518082019384905290938593909291608084019160018401906003908288855b82829054906101000a900462ffffff1662ffffff1681526020019060030190602082600201049283019260010382029150808411610af957505050928452505060408051606081019182905260209093019291506002840190600390825f855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610b595750505092845250505060039182015465ffffffffffff166020918201525f8d8152918152604080832080548251818502810185019093528083529495509293909291830182828015610bfe57602002820191905f5260205f20905b815481526020019060010190808311610bea575b50505050509050815f015182602001518360400151846060015185608001518660a001518760c0015187995099509950995099509950995099505050919395975091939597565b610c4d611536565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6003602052815f5260405f208181548110610cad575f80fd5b905f5260205f20015f91509150505481565b610cc7611536565b5f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610d2f575f80fd5b5f848152600260209081526040808320815160e081018352815460ff80821683526101008204811695830195909552620100008104909416151581840152630100000090930462ffffff16606080850191909152825190810192839052909160808401919060018401906003908288855b82829054906101000a900462ffffff1662ffffff1681526020019060030190602082600201049283019260010382029150808411610da057505050928452505060408051606081019182905260209093019291506002840190600390825f855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610e00575050509284525050506003919091015465ffffffffffff1660209091015280519091505f9060ff165b80156110395760a08301515f90610e77600184615c7b565b60038110610e8757610e87615d1b565b602002015161ffff169050610ece88828660800151600186610ea99190615c7b565b60038110610eb957610eb9615d1b565b602002015162ffffff168e8e8e8d8d8d6115d0565b1561102657604080518981526020810183905273ffffffffffffffffffffffffffffffffffffffff8d8116828401528c16606082015290517f573c13d5af72038238ea235fec819de220e307e6ee81ca9a7d9ad8de329f938f9181900360800190a18351610f3e90600190615d48565b60ff16610f4c600184615c7b565b10156110065760808401518451610f6590600190615d48565b60ff1660038110610f7857610f78615d1b565b60200201516080850151610f8d600185615c7b565b60038110610f9d57610f9d615d1b565b62ffffff909216602092909202015260a08401518451610fbf90600190615d48565b60ff1660038110610fd257610fd2615d1b565b602002015160a0850151610fe7600185615c7b565b60038110610ff757610ff7615d1b565b61ffff90921660209290920201525b83518461101282615d61565b60ff169052508261102281615d9b565b9350505b508061103181615dd2565b915050610e5f565b50801561118b5761104b8683836141e0565b65ffffffffffff421660c08201525f87815260026020908152604091829020835181549285015193850151606086015162ffffff166301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff9115156201000002919091167fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff60ff968716610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090961696909316959095179390931716929092171781556080820151919350839161112f9060018301906003615671565b5060a08201516111459060028301906003615709565b5060c09190910151600390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001665ffffffffffff9092169190911790556111cc565b5f86815260026020526040902060030180547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000164265ffffffffffff161790555b505050505050505050565b5f818152600260209081526040808320815160e081018352815460ff80821683526101008204811695830195909552620100008104909416151581840152630100000090930462ffffff166060808501919091528251808201938490529094939260808401919060018401906003908288855b82829054906101000a900462ffffff1662ffffff168152602001906003019060208260020104928301926001038202915080841161124a57505050928452505060408051606081019182905260209093019291506002840190600390825f855b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116112aa5750505092845250505060039182015465ffffffffffff166020918201526001545f87815292825260409283902060808501518551938601518686015195517ff78cd33900000000000000000000000000000000000000000000000000000000815296975073ffffffffffffffffffffffffffffffffffffffff9093169563f78cd339956109f7958b959092909190600401615e06565b5f818152600260209081526040808320815160e081018352815460ff80821683526101008204811695830195909552620100008104909416151581840152630100000090930462ffffff166060808501919091528251808201938490529094939260808401919060018401906003908288855b82829054906101000a900462ffffff1662ffffff16815260200190600301906020826002010492830192600103820291508084116113e957505050928452505060408051606081019182905260209093019291506002840190600390825f855b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116114495750505092845250505060039182015465ffffffffffff166020918201526001545f878152929091526040918290206080840151845193517fd099110e00000000000000000000000000000000000000000000000000000000815294955073ffffffffffffffffffffffffffffffffffffffff9092169363d099110e936109f793899392909190600401615ce2565b611515611536565b8060601b61152a57637448fbae5f526004601cfd5b6115338161156b565b50565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314610a6e576382b429005f526004601cfd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f88609b111580156115e3575060b78911155b156115f0575060016141d3565b6004890361160657506404a817c8003a106141d3565b60328914806116155750603389145b1561163a57503273ffffffffffffffffffffffffffffffffffffffff851614156141d3565b601a8914806116495750601b89145b806116545750601c89145b1561179057606086901b7fbe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b161480156116fe57507fef000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857508060125b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660be60f81b14801561178857507fef000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601383901a60f81b16145b9150506141d3565b601d890361184c57606086901b7fbe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b1614801561183d57507fef000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b15806117885750806012611708565b601e89148061185b5750601f89145b1561199657606086901b7fde000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b1614801561190557507fad000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507fde000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b1614801561178857508060135b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660ad60f81b149150506141d3565b60208914806119a55750602189145b15611adf57606086901b7fba000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b16148015611a4f57507fbe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507fba000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b1614801561178857508060131a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660be60f81b149150506141d3565b60228903611c1c57606086901b7fde000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b16148015611b8c57507faf000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507fde000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b1614801561178857508060131a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660af60f81b149150506141d3565b60238903611d5a57606086901b7ffe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b16148015611cc957507fed000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507ffe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b1614801561178857508060135b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660ed60f81b149150506141d3565b60248903611e4857606086901b7ffe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b16148015611e0757507fd0000000000000000000000000000000000000000000000000000000000000007ff000000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857508060121a60f81b7f0f000000000000000000000000000000000000000000000000000000000000009081161480156117885750806013611d26565b6028891480611e575750602989145b15611f9157606086901b7ffa000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b16148015611f0157507fce000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507ffa000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b1614801561178857508060131a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660ce60f81b149150506141d3565b6025891480611fa05750602689145b80611fab5750602789145b156120b657606086901b7fba000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b1614801561205557507fd0000000000000000000000000000000000000000000000000000000000000007ff000000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507f0b000000000000000000000000000000000000000000000000000000000000007f0f00000000000000000000000000000000000000000000000000000000000000601283901a60f81b161480156117885750806013611962565b600989036120c85750600134146141d3565b603489036120ef575073ffffffffffffffffffffffffffffffffffffffff851631156141d3565b60358903612116575073ffffffffffffffffffffffffffffffffffffffff861631156141d3565b603689036121475750670de0b6b3a764000073ffffffffffffffffffffffffffffffffffffffff87163110156141d3565b6038890361217957612171600273ffffffffffffffffffffffffffffffffffffffff891631615c22565b1590506141d3565b603989036121ad576121a3600273ffffffffffffffffffffffffffffffffffffffff891631615c22565b60011490506141d3565b603789036121ed578573ffffffffffffffffffffffffffffffffffffffff16318773ffffffffffffffffffffffffffffffffffffffff16311090506141d3565b605a890361221e575f80612200426145e9565b92509250508160011480156122155750806001145b925050506141d3565b605989036122575761012c6122366201518042615c22565b108061225057506201505461224e6201518042615c22565b115b90506141d3565b603b8903612290575f601861226e610e1042615e54565b6122789190615c22565b905060098110158015611788575060111190506141d3565b603c89036122c8575f60186122a7610e1042615e54565b6122b19190615c22565b9050600981108061178857506011111590506141d3565b60588903612301575f60186122df610e1042615e54565b6122e99190615c22565b905060078110158015611788575060171190506141d3565b602a8914806123105750602b89145b8061231b5750602c89145b806123265750601889145b806123315750601989145b1561236c578573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff161490506141d3565b602d89148061237b5750602e89145b806123865750602f89145b156123c2578573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16141590506141d3565b603d89036123de576007600362015180420401066001016121a3565b603f89036123fe57506002600160076201518042046003010601146141d3565b6041890361241f5760076003620151804204010660010160031490506141d3565b6043890361243f57506004600160076201518042046003010601146141d3565b6045890361245f57506005600160076201518042046003010601146141d3565b6047890361247f57506006600160076201518042046003010601146141d3565b604989036124a05760076003620151804204010660010160071490506141d3565b605c8914806124af5750605d89145b806124ba5750605e89145b156124f7575f8a81526002602052604090206003015442906124e69065ffffffffffff1661012c615e67565b65ffffffffffff16111590506141d3565b605f8903612526575f8a81526002602052604090206003015442906124e69065ffffffffffff16610258615e67565b60608914806125355750606289145b806125405750606189145b1561256c575f8a81526002602052604090206003015442906124e69065ffffffffffff16610e10615e67565b6063890361259b575f8a81526002602052604090206003015442906124e69065ffffffffffff1661a8c0615e67565b60648914806125aa5750606589145b806125b55750606689145b806125c05750606789145b806125cb5750606889145b806125d65750606989145b806125e15750606a89145b1561260e575f8a81526002602052604090206003015442906124e69065ffffffffffff1662015180615e67565b606b890361263e575f8a81526002602052604090206003015442906124e69065ffffffffffff166202a300615e67565b606c89148061264d5750606d89145b806126585750606e89145b15612685575f8a81526002602052604090206003015442906124e69065ffffffffffff1662093a80615e67565b606f8914806126945750607089145b156126c1575f8a81526002602052604090206003015442906124e69065ffffffffffff166224ea00615e67565b60718914806126d05750607289145b156126fe575f8a81526002602052604090206003015442906124e69065ffffffffffff166301dfe200615e67565b6007890361270f57503415156141d3565b6008890361271f575034156141d3565b601489148061272e5750601589145b1561273d576122506032614609565b600e89148061274c5750601089145b806127575750601289145b15612766576122506021614609565b600f8914806127755750601589145b1561278457612250603c614609565b60118914806127935750600d89145b156127a257612250600a614609565b60178914806127b15750601389145b156127c0576122506014614609565b601689036127d257612250604b614609565b603a89036127e45750600183116141d3565b6031890361280c575073ffffffffffffffffffffffffffffffffffffffff85163b15156141d3565b6030890361293557606087811b9087901b5f5b60148110156129295781816014811061283a5761283a615d1b565b1a60f81b7ff0000000000000000000000000000000000000000000000000000000000000001683826014811061287257612872615d1b565b1a60f81b7ff00000000000000000000000000000000000000000000000000000000000000016148061291157508181601481106128b1576128b1615d1b565b1a60f81b7f0f00000000000000000000000000000000000000000000000000000000000000168382601481106128e9576128e9615d1b565b1a60f81b7f0f0000000000000000000000000000000000000000000000000000000000000016145b15612921575f93505050506141d3565b60010161281f565b506001925050506141d3565b604f8903612962575f612947426145e9565b509150506006811015801561178857506008101590506141d3565b6050890361298c575f612974426145e9565b509150506006811080611788575060081090506141d3565b605189036129b8575f61299e426145e9565b50915050600c8110158061178857506002101590506141d3565b605289036129e3575f6129ca426145e9565b509150506002811180156117885750600c1190506141d3565b60538903612a10575f6129f5426145e9565b509150506003811015801561178857506005101590506141d3565b60548903612a3a575f612a22426145e9565b509150506003811080611788575060051090506141d3565b60558903612a67575f612a4c426145e9565b50915050600981101580156117885750600b101590506141d3565b60568903612a91575f612a79426145e9565b5091505060098110806117885750600b1090506141d3565b60578903612aa1575060016141d3565b604b891480612ab05750604e89145b15612ad8576001600762015180420460030106016006811480611788575060071490506141d3565b604d891480612ae75750604c89145b15612b12576001600762015180420460030106810190811080159061178857506005101590506141d3565b603e8903612b3257506001600762015180420460030106810114156141d3565b60408903612b535750600260016007620151804204600301060114156141d3565b60428903612b75576007600362015180420401066001016003141590506141d3565b60448903612b965750600460016007620151804204600301060114156141d3565b60468903612bb75750600560016007620151804204600301060114156141d3565b60488903612bd85750600660016007620151804204600301060114156141d3565b604a8903612bfa576007600362015180420401066001016007141590506141d3565b60938903612c1057612250898b89896007614653565b60928903612c2657612250898b89896005614653565b6094891480612c355750609189145b80612c405750609689145b80612c4b5750609789145b15612c5e57612250898b89896003614653565b6095891480612c6d5750609a89145b80612c785750609989145b80612c835750609889145b15612c9657612250898b89896002614653565b60738903612cac57612250898b600260786149a7565b60748903612cc257612250898b600360b46149a7565b60758903612cd957612250898b600561012c6149a7565b60768903612ec0575f8a8152600260205260409020600301544290612d089065ffffffffffff16610258615e67565b65ffffffffffff1611158015612d4a57505f8a8152600260205260409020600301544290612d409065ffffffffffff16610294615e67565b65ffffffffffff16115b15612e40575f8a815260026020908152604080832060030180547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000164265ffffffffffff16179055600582528083208c84529091528120805463ffffffff1691612db383615e86565b82546101009290920a63ffffffff8181021990931691831602179091555f8c81526005602081815260408084208f85529091529091205490911690039050612e3b57505f8981526005602090815260408083208b8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016905560016141d3565b612eb9565b5f8a815260026020908152604080832060030180547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000164265ffffffffffff16179055600582528083208c8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690555b505f6141d3565b60778903612ed457612250898b6007614d1c565b6078890361303857600760036201518042040106600101600103612f38575f8a81526005602090815260408083208c8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000166001179055613011565b5f8a815260026020526040902060030154612f5f90620151809065ffffffffffff16615ea8565b612f6a906001615e67565b65ffffffffffff16612f7f6201518042615e54565b03612fd2575f8a81526005602090815260408083208c84529091528120805463ffffffff1691612fae83615e86565b91906101000a81548163ffffffff021916908363ffffffff16021790555050613011565b5f8a81526005602090815260408083208c8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690555b505f8981526005602081815260408084208c85529091529091205463ffffffff16146141d3565b6079890361304c57612250898b6004614e92565b607a89036131a3575f61305e4261504d565b5f8c815260026020526040812060030154919250906130849065ffffffffffff1661504d565b905081613092826001615ecc565b036130e5575f8c81526005602090815260408083208e84529091528120805463ffffffff16916130c183615e86565b91906101000a81548163ffffffff021916908363ffffffff1602179055505061312b565b5050505f8981526005602090815260408083208b8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690556141d3565b5f8c81526005602090815260408083208e845290915290205463ffffffff16600b03613199575050505f8981526005602090815260408083208b8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016905560016141d3565b5f925050506141d3565b607b89036131b557612250898b615075565b607c89036131de57505f8981526002602052604090206003015465ffffffffffff1642146141d3565b608889036131f257612250898b6003615207565b6089890361320657612250898b6005615207565b608a890361321a57612250898b6007615207565b608b890361322e57612250898b600a615207565b6001890361326f5760016132428982615ecc565b5f8c81526002602052604090205461326691906301000000900462ffffff16615c7b565b101590506141d3565b60028903613284576005613242896001615ecc565b6003890361329957600a613242896001615ecc565b600589036132ac57612171600243615c22565b600689036132bf576121a3600243615c22565b600c8903613329576040517f70617373776f72640000000000000000000000000000000000000000000000006020820152602801604051602081830303815290604052805190602001208383604051613319929190615edf565b60405180910390201490506141d3565b600a890361333a57508015156141d3565b600b890361334a575080156141d3565b607d89036135ea575f8a81526004602090815260408083208c845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e08101808452919284019160018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190600401906020826003010492830192600103820291508084116133a3575050509290935250505050604081015151909150606088901b7fffffffff00000000000000000000000000000000000000000000000000000000908116911614801561347157505f8b81526002602052604090206003015461346d9065ffffffffffff166001600762015180909204600301919091060190565b6005145b801561348b57506007600362015180420401066001016001145b80156134bc57505f8b81526002602052604090206003015462093a80906134ba9065ffffffffffff1642615c7b565b105b1561350f5750505f8981526004602090815260408083208b8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001681556001908101919091556141d3565b604081015151606089901b7fffffffff000000000000000000000000000000000000000000000000000000009081169116146135e1576040818101805160608b901b7fffffffff000000000000000000000000000000000000000000000000000000001690525f8d8152600460209081528382208e83528152929020835181549385015160ff908116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909516911617929092178255518291906135dd90600183019060076157aa565b5050505b5f9150506141d3565b607e8914806135f95750608789145b156138c4575f8a81526004602090815260408083208c845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e08101808452919284019160018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001906004019060208260030104928301926001038202915080841161364f57905050505050508152505090505f62015180426136bc9190615e54565b5f8d815260026020526040812060030154919250906136e790620151809065ffffffffffff16615ea8565b65ffffffffffff1690508860601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191683604001515f6007811061372a5761372a615d1b565b60200201517fffffffff0000000000000000000000000000000000000000000000000000000016148015613767575081613765826001615ecc565b145b8015613781575061546061377e6201518042615c22565b10155b156137db575f8d81526004602090815260408083208f8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016815560018101829055905b5050600193505050506141d3565b60408301515160608b901b7fffffffff000000000000000000000000000000000000000000000000000000009081169116146138b957604083015160608b901b905f7fffffffff00000000000000000000000000000000000000000000000000000000909216602092830291909101525f8e81526004825260408082208f8352835290819020855181549387015160ff908116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009095169116179290921782558401518491906138b590600183019060076157aa565b5050505b5f93505050506141d3565b607f8903613aa4575f8a81526004602090815260408083208c845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e08101808452919284019160018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001906004019060208260030104928301926001038202915080841161391d57905050505050508152505090505f620151804261398a9190615e54565b5f8d815260026020526040812060030154919250906139b590620151809065ffffffffffff16615ea8565b65ffffffffffff1690508860601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191683604001515f600781106139f8576139f8615d1b565b60200201517fffffffff0000000000000000000000000000000000000000000000000000000016148015613a35575081613a33826002615ecc565b145b8015613781575073ffffffffffffffffffffffffffffffffffffffff8a163b156137db575f8d81526004602090815260408083208f8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016815560018101829055906137cd565b60808903613b1c575f8a8152600260205260409020600301544290613ad49065ffffffffffff1662015180615e67565b65ffffffffffff161115801561225057508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16141590506141d3565b60818903613c9a575f8a81526004602090815260408083208c845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e08101808452919284019160018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019060040190602082600301049283019260010382029150808411613b7557905050505050508152505090505f613bdc4261504d565b5f8d81526002602052604081206003015491925090613c029065ffffffffffff1661504d565b60408401515190915060608a901b7fffffffff000000000000000000000000000000000000000000000000000000009081169116148015613781575081613c4a826003615ecc565b036137db575f8d81526004602090815260408083208f8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016815560018101829055906137cd565b60828903613e75575f600760036201518042040106600101613cbf6201518042615e54565b613cc99190615c7b565b613cd4906001615ecc565b5f8c815260026020526040812060039081015492935065ffffffffffff90921691600762015180840490910106600101613d116201518084615e54565b613d1b9190615c7b565b613d26906001615ecc565b905060608a901b83613d39836007615ecc565b148015613e6a57507fba000000000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000005f83901a60f81b16148015613de057507fd0000000000000000000000000000000000000000000000000000000000000007ff000000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b80613e6a57507f0b000000000000000000000000000000000000000000000000000000000000007f0f00000000000000000000000000000000000000000000000000000000000000601283901a60f81b16148015613e6a57508060135b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660ad60f81b145b9450505050506141d3565b6083890361401c575f600760036201518042040106600101613e9a6201518042615e54565b613ea49190615c7b565b613eaf906001615ecc565b5f8c815260026020526040812060039081015492935065ffffffffffff90921691600762015180840490910106600101613eec6201518084615e54565b613ef69190615c7b565b613f01906001615ecc565b905060608a901b83613f14836007615ecc565b148015613fbb57507fde000000000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000005f83901a60f81b16148015613fbb57507fad000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b80613e6a57507fde000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b16148015613e6a5750806013613e3d565b608489148061402b5750608589145b1561404257612250898b60078a8a620151806152c4565b6086890361405b57612250898b60048a8a610e106152c4565b608c890361406f57612250898b6003615207565b608d890361408357612250898b6005615207565b608d8914806140925750609089145b156140a357612250898b6005615207565b608e89036140b757612250898b6007615207565b608f89036140cb57612250898b600a615207565b605b89036141d0576040805160208082018d90528183018b9052825180830384018152606090920190925280519101205f806141a161410c61016d85615c22565b614117906001615ecc565b5f805f620afa6c8401935062023ab1840661016d62023ab082146105b48304618eac84048401030304606481048160021c8261016d0201038203915060996002836005020104600161030161f4ff830201600b1c84030193506b030405060708090a0b0c010260a01b811a9450506003841061019062023ab1880402820101945050509193909250565b92509250505f806141b1426145e9565b925092505081841480156141c457508083145b955050505050506141d3565b505f5b9998505050505050505050565b6141e8615830565b5f8083116141f75760016141f9565b825b9050836020015160ff1683855f015160ff166142159190615ecc565b10801561428857506020848101516040805192830188905261beef9083015260f81b7fff00000000000000000000000000000000000000000000000000000000000000166060820152600390606101604051602081830303815290604052805190602001205f1c6142869190615c22565b155b1561429b57614298600182615ecc565b90505b5f8561beef6040516020016142ba929190918252602082015260400190565b604051602081830303815290604052805190602001205f1c90505f5b828110156145de575f805f5b885160ff168110156143c557609b8960a00151826003811061430657614306615d1b565b602002015161ffff161015801561433c575060b78960a00151826003811061433057614330615d1b565b602002015161ffff1611155b1561435b5761434d609b60b7615c7b565b614358906001615ecc565b92505b886020015160ff1660011480614390575060038960a00151826003811061438457614384615d1b565b602002015161ffff1611155b806143b35750886020015160ff16895f015160016143ae9190615c62565b60ff16105b156143bd57600391505b6001016142e2565b505f805f5b60058110156144c957838461ffff168661ffff1660b76143ea9190615c7b565b6143f49190615c7b565b8861440161ffff85615eee565b8e6060015162ffffff166144159190615ecc565b604080516020810193909352820152606001604051602081830303815290604052805190602001205f1c6144499190615c22565b6144539190615c8e565b61445e906001615c8e565b92505f5b60048210801561447557508b5160ff1681105b156144ba578361ffff168c60a00151826003811061449557614495615d1b565b602002015161ffff16036144a857600192505b806144b281615d9b565b915050614462565b5081156144c9576001016143ca565b5060608a015160808b01518b5160ff16600381106144e9576144e9615d1b565b62ffffff909216602092909202015260a08a01518a5183919060ff166003811061451557614515615d1b565b61ffff909216602092909202015260608a0180519061453382615f05565b62ffffff1690525089518a61454782615f1c565b60ff169052505f8b815260036020908152604082208054600181810183559184529190922061ffff851691015560608b01517fa2c76bc2f53d218db7b73da5593a6f3b09c71e0d92aca376720d10369814f0d5918d916145a79190615f3a565b6040805192835262ffffff909116602083015261ffff85169082015260600160405180910390a15050600190920191506142d69050565b509395945050505050565b5f80806145fc6141176201518086615e54565b9196909550909350915050565b5f8160644244604051602001614629929190918252602082015260400190565b604051602081830303815290604052805190602001205f1c61464b9190615c22565b111592915050565b5f84815260046020908152604080832088845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e081018084528594938401919060018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190600401906020826003010492830192600103820291508084116146a657905050505050508152505090508460601b8160400151826020015160ff166007811061472457614724615d1b565b7fffffffff00000000000000000000000000000000000000000000000000000000909216602092830291909101528101518390614762906001615c62565b61476c9190615f56565b60ff9081166020830181905282519091161480156147b057506040810151517fffffffff000000000000000000000000000000000000000000000000000000001615155b1561486e578360601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168160400151825f015160ff16600781106147f4576147f4615d1b565b60200201517fffffffff00000000000000000000000000000000000000000000000000000000160361486e5750505f848152600460209081526040808320888452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016815560019081019190915561499e565b80515b816020015160ff168160ff1614614927578460601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191682604001518260ff16600781106148be576148be615d1b565b60200201517fffffffff00000000000000000000000000000000000000000000000000000000160361490a57836148f6826001615c62565b6149009190615f56565b60ff168252614927565b83614916826001615c62565b6149209190615f56565b9050614871565b5f8781526004602090815260408083208b8452825291829020845181549286015160ff908116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009094169116179190911781559083015183919061499590600183019060076157aa565b505f9450505050505b95945050505050565b5f83815260046020908152604080832087845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e081018084528594938401919060018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190600401906020826003010492830192600103820291508084116149fa57905050505050508152505090505f63ffffffff801642614a6a9190615c22565b60e01b90505f63ffffffff614a7f8642615c7b565b614a899190615c22565b60e01b9050818360400151846020015160ff1660078110614aac57614aac615d1b565b7fffffffff00000000000000000000000000000000000000000000000000000000909216602092830291909101528301518690614aea906001615c62565b614af49190615f56565b60ff908116602085018190528451909116148015614b3857506040830151517fffffffff000000000000000000000000000000000000000000000000000000001615155b15614bf957604083015183517fffffffff000000000000000000000000000000000000000000000000000000008316919060ff1660078110614b7c57614b7c615d1b565b60200201517fffffffff000000000000000000000000000000000000000000000000000000001610614bf9575050505f848152600460209081526040808320888452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001681556001908101919091559050614d14565b826020015160ff16835f015160ff1614614c9c57604083015183517fffffffff000000000000000000000000000000000000000000000000000000008316919060ff1660078110614c4c57614c4c615d1b565b60200201517fffffffff00000000000000000000000000000000000000000000000000000000161015614c9c5782518690614c88906001615c62565b614c929190615f56565b60ff168352614bf9565b5f8781526004602090815260408083208b8452825291829020855181549287015160ff908116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090941691161791909117815590840151849190614d0a90600183019060076157aa565b505f955050505050505b949350505050565b5f80614d2b6201518042615e54565b5f8581526002602052604081206003015491925090614d5690620151809065ffffffffffff16615ea8565b65ffffffffffff16905081614d6c826001615ecc565b03614dbf575f8581526005602090815260408083208984529091528120805463ffffffff1691614d9b83615e86565b91906101000a81548163ffffffff021916908363ffffffff16021790555050614e10565b81614dcb826001615ecc565b1015614e10575f858152600560209081526040808320898452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690555b614e1b600185615c7b565b5f8681526005602090815260408083208a845290915290205463ffffffff1603614e87575050505f828152600560209081526040808320868452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690556001610a56565b505f95945050505050565b5f80600760036201518042040106600101614eb06201518042615e54565b614eba9190615c7b565b614ec5906001615ecc565b5f85815260026020526040812060039081015492935065ffffffffffff90921691600762015180840490910106600101614f026201518084615e54565b614f0c9190615c7b565b614f17906001615ecc565b905082614f25826007615ecc565b03614f78575f8681526005602090815260408083208a84529091528120805463ffffffff1691614f5483615e86565b91906101000a81548163ffffffff021916908363ffffffff16021790555050614fc9565b82614f84826001615ecc565b1015614fc9575f8681526005602090815260408083208a8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690555b614fd4600186615c7b565b5f8781526005602090815260408083208b845290915290205463ffffffff1603615041575050505f838152600560209081526040808320878452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000169055506001610a56565b505f9695505050505050565b5f805f615059846145e9565b5090925090508061506b83600c615eee565b614d149190615ecc565b5f80615080426145e9565b505f8581526002602052604081206003015491935091506150a89065ffffffffffff166145e9565b5091505f905060036150bb600c85615c22565b6150c59190615e54565b90505f60036150d5600c85615c22565b6150df9190615e54565b90508160046150ef836001615ecc565b6150f99190615c22565b0361514c575f8681526005602090815260408083208a84529091528120805463ffffffff169161512883615e86565b91906101000a81548163ffffffff021916908363ffffffff16021790555050615196565b5050505f838152600560209081526040808320878452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016905591506104d99050565b5f8681526005602090815260408083208a845290915290205463ffffffff16600303615041575050505f838152600560209081526040808320878452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016905550600190506104d9565b5f8281526005602090815260408083208684529091528120805463ffffffff16908261523283615e86565b82546101009290920a63ffffffff8181021990931691831602179091555f85815260056020908152604080832089845290915290205460ff851691160390506152bb57505f828152600560209081526040808320868452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690556001610a56565b505f9392505050565b5f85815260046020908152604080832089845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e081018084528594938401919060018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001906004019060208260030104928301926001038202915080841161531757905050505050508152505090505f83426153819190615e54565b5f89815260026020526040812060030154919250906153a990869065ffffffffffff16615e54565b9050816153b7826001615ecc565b146153c757602083015160ff1683525b8660601b8360400151846020015160ff16600781106153e8576153e8615d1b565b7fffffffff00000000000000000000000000000000000000000000000000000000909216602092830291909101528301518890615426906001615c62565b6154309190615f56565b60ff90811660208501819052845190911614801561547457506040830151517fffffffff000000000000000000000000000000000000000000000000000000001615155b15615535578560601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168360400151845f015160ff16600781106154b8576154b8615d1b565b60200201517fffffffff000000000000000000000000000000000000000000000000000000001603615535575050505f8681526004602090815260408083208a8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001681556001908101919091559050615667565b82515b836020015160ff168160ff16146155ee578660601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191684604001518260ff166007811061558557615585615d1b565b60200201517fffffffff0000000000000000000000000000000000000000000000000000000016036155d157886155bd826001615c62565b6155c79190615f56565b60ff1684526155ee565b886155dd826001615c62565b6155e79190615f56565b9050615538565b5f8a81526004602090815260408083208e8452825291829020865181549288015160ff908116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009094169116179190911781559085015185919061565c90600183019060076157aa565b505f96505050505050505b9695505050505050565b6001830191839082156156f9579160200282015f5b838211156156c857835183826101000a81548162ffffff021916908362ffffff1602179055509260200192600301602081600201049283019260010302615686565b80156156f75782816101000a81549062ffffff02191690556003016020816002010492830192600103026156c8565b505b50615705929150615878565b5090565b6001830191839082156156f9579160200282015f5b8382111561575e57835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030261571e565b80156156f75782816101000a81549061ffff021916905560020160208160010104928301926001030261575e565b60405180606001604052806003906020820280368337509192915050565b6001830191839082156156f9579160200282015f5b8382111561580057835183826101000a81548163ffffffff021916908360e01c021790555092602001926004016020816003010492830192600103026157bf565b80156156f75782816101000a81549063ffffffff0219169055600401602081600301049283019260010302615800565b6040805160e0810182525f8082526020820181905291810182905260608101919091526080810161585f61578c565b815260200161586c61578c565b81525f60209091015290565b5b80821115615705575f8155600101615879565b5f6020828403121561589c575f80fd5b5035919050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b805f5b600381101561591d57815162ffffff168452602093840193909101906001016158f9565b50505050565b5f815180845260208085019450602084015f5b8381101561595257815187529582019590820190600101615936565b509495945050505050565b5f61018060ff8b168352602060ff8b166020850152891515604085015262ffffff8916606085015261599260808501896158f6565b60e08401875f5b60038110156159ba57815161ffff1683529183019190830190600101615999565b50505065ffffffffffff861661014085015250806101608401526159e081840185615923565b9b9a5050505050505050505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114615a12575f80fd5b919050565b5f60208284031215615a27575f80fd5b610a56826159ef565b5f8060408385031215615a41575f80fd5b50508035926020909101359150565b5f805f805f805f60c0888a031215615a66575f80fd5b615a6f886159ef565b9650615a7d602089016159ef565b9550615a8b604089016159ef565b9450606088013593506080880135925060a088013567ffffffffffffffff80821115615ab5575f80fd5b818a0191508a601f830112615ac8575f80fd5b813581811115615ad6575f80fd5b8b6020828501011115615ae7575f80fd5b60208301945080935050505092959891949750929550565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60208284031215615b3c575f80fd5b815167ffffffffffffffff80821115615b53575f80fd5b818401915084601f830112615b66575f80fd5b815181811115615b7857615b78615aff565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715615bbe57615bbe615aff565b81604052828152876020848701011115615bd6575f80fd5b8260208601602083015e5f928101602001929092525095945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82615c3057615c30615bf5565b500690565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60ff81811683821601908111156104d9576104d9615c35565b818103818111156104d9576104d9615c35565b61ffff818116838216019080821115615ca957615ca9615c35565b5092915050565b5f815480845260208085019450835f5260205f205f5b8381101561595257815487529582019560019182019101615cc6565b84815260c060208201525f615cfa60c0830186615cb0565b9050615d0960408301856158f6565b60ff831660a083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60ff82811682821603908111156104d9576104d9615c35565b5f60ff821680615d7357615d73615c35565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615dcb57615dcb615c35565b5060010190565b5f81615de057615de0615c35565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b5f610100888352806020840152615e1f81840189615cb0565b915050615e2f60408301876158f6565b60ff851660a083015260ff841660c083015282151560e0830152979650505050505050565b5f82615e6257615e62615bf5565b500490565b65ffffffffffff818116838216019080821115615ca957615ca9615c35565b5f63ffffffff808316818103615e9e57615e9e615c35565b6001019392505050565b5f65ffffffffffff80841680615ec057615ec0615bf5565b92169190910492915050565b808201808211156104d9576104d9615c35565b818382375f9101908152919050565b80820281158282048414176104d9576104d9615c35565b5f62ffffff808316818103615e9e57615e9e615c35565b5f60ff821660ff8103615f3157615f31615c35565b60010192915050565b62ffffff828116828216039080821115615ca957615ca9615c35565b5f60ff831680615f6857615f68615bf5565b8060ff8416069150509291505056fea26469706673582212205740219e7c6d6df2e30f8644dc6b5e1005c5f0a4d53c0784dc4795042801ff7864736f6c63430008190033

Deployed Bytecode

0x608060405260043610610109575f3560e01c80638da5cb5b116100a1578063c321f9b411610071578063c87b56dd11610057578063c87b56dd146103d6578063d12a4c98146103f5578063f2fde38b14610414575f80fd5b8063c321f9b414610372578063c3c3a2f0146103c3575f80fd5b80638da5cb5b14610254578063adb3ca6714610287578063b4b5b48f146102b4578063bbcd5bbe14610353575f80fd5b80635ca2ddf1116100dc5780635ca2ddf1146101db578063715018a6146101fa57806372efa29f146102025780638415d21314610235575f80fd5b8063173db2e51461010d578063456d908e1461016357806348d8afd51461018f57806355a373d6146101b0575b5f80fd5b348015610118575f80fd5b506001546101399073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561016e575f80fd5b5061018261017d36600461588c565b610427565b60405161015a91906158a3565b34801561019a575f80fd5b506101ae6101a936600461588c565b6104df565b005b3480156101bb575f80fd5b505f546101399073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101e6575f80fd5b506101826101f536600461588c565b610860565b6101ae610a5d565b34801561020d575f80fd5b5061022161021c36600461588c565b610a70565b60405161015a98979695949392919061595d565b348015610240575f80fd5b506101ae61024f366004615a17565b610c45565b34801561025f575f80fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754610139565b348015610292575f80fd5b506102a66102a1366004615a30565b610c94565b60405190815260200161015a565b3480156102bf575f80fd5b506103146102ce36600461588c565b60026020525f90815260409020805460039091015460ff80831692610100810482169262010000820490921691630100000090910462ffffff169065ffffffffffff1685565b6040805160ff96871681529590941660208601529115159284019290925262ffffff909116606083015265ffffffffffff16608082015260a00161015a565b34801561035e575f80fd5b506101ae61036d366004615a17565b610cbf565b34801561037d575f80fd5b506103ae61038c366004615a30565b600560209081525f928352604080842090915290825290205463ffffffff1681565b60405163ffffffff909116815260200161015a565b6101ae6103d1366004615a50565b610d0d565b3480156103e1575f80fd5b506101826103f036600461588c565b6111d7565b348015610400575f80fd5b5061018261040f36600461588c565b611376565b6101ae610422366004615a17565b61150d565b6001546040517f456d908e0000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063456d908e906024015f60405180830381865afa158015610494573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104d99190810190615b2c565b92915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610501575f80fd5b5f8161beef604051602001610520929190918252602082015260400190565b604051602081830303815290604052805190602001205f1c90505f826001148061054a5750826019145b806105555750826032145b806105605750826064145b90505f8161058357610573600384615c22565b61057e906001615c62565b610586565b60015b90505f6003818461060057818361ffff168361ffff1660b76105a89190615c7b565b6105b29190615c7b565b6040805160208082018b90525f8284015282516024818403018152604490920190925280519101206105e49190615c22565b6105ee9190615c8e565b6105f9906001615c8e565b9050610634565b8660010361061057506071610634565b866019036106205750606f610634565b866032036106305750606c610634565b5060645b60035f8881526020019081526020015f2081908060018154018082558091505060019003905f5260205f20015f909161ffff169091909150555f6040518060e00160405280600160ff1681526020018660ff1681526020018715158152602001600162ffffff16815260200160405180606001604052805f62ffffff1662ffffff1681526020015f62ffffff1681526020015f62ffffff16815250815260200160405180606001604052808561ffff1661ffff1681526020015f61ffff1681526020015f61ffff1681525081526020014265ffffffffffff1681525090508060025f8a81526020019081526020015f205f820151815f015f6101000a81548160ff021916908360ff1602179055506020820151815f0160016101000a81548160ff021916908360ff1602179055506040820151815f0160026101000a81548160ff0219169083151502179055506060820151815f0160036101000a81548162ffffff021916908362ffffff1602179055506080820151816001019060036107bc929190615671565b5060a08201516107d29060028301906003615709565b5060c09190910151600390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001665ffffffffffff909216919091179055604080518981525f602082015261ffff84168183015290517fa2c76bc2f53d218db7b73da5593a6f3b09c71e0d92aca376720d10369814f0d5916060908290030190a15050505050505050565b5f818152600260209081526040808320815160e081018352815460ff80821683526101008204811695830195909552620100008104909416151581840152630100000090930462ffffff166060808501919091528251808201938490529094939260808401919060018401906003908288855b82829054906101000a900462ffffff1662ffffff16815260200190600301906020826002010492830192600103820291508084116108d357505050928452505060408051606081019182905260209093019291506002840190600390825f855b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116109335750505092845250505060039182015465ffffffffffff166020918201526001545f878152929091526040918290206080840151845193517f9416c65a00000000000000000000000000000000000000000000000000000000815294955073ffffffffffffffffffffffffffffffffffffffff90921693639416c65a936109f793899392909190600401615ce2565b5f60405180830381865afa158015610a11573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610a569190810190615b2c565b9392505050565b610a65611536565b610a6e5f61156b565b565b5f805f80610a7c61578c565b610a8461578c565b5f878152600260209081526040808320815160e081018352815460ff80821683526101008204811695830195909552620100008104909416151581840152630100000090930462ffffff1660608085019190915282518082019384905290938593909291608084019160018401906003908288855b82829054906101000a900462ffffff1662ffffff1681526020019060030190602082600201049283019260010382029150808411610af957505050928452505060408051606081019182905260209093019291506002840190600390825f855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610b595750505092845250505060039182015465ffffffffffff166020918201525f8d8152918152604080832080548251818502810185019093528083529495509293909291830182828015610bfe57602002820191905f5260205f20905b815481526020019060010190808311610bea575b50505050509050815f015182602001518360400151846060015185608001518660a001518760c0015187995099509950995099509950995099505050919395975091939597565b610c4d611536565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6003602052815f5260405f208181548110610cad575f80fd5b905f5260205f20015f91509150505481565b610cc7611536565b5f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610d2f575f80fd5b5f848152600260209081526040808320815160e081018352815460ff80821683526101008204811695830195909552620100008104909416151581840152630100000090930462ffffff16606080850191909152825190810192839052909160808401919060018401906003908288855b82829054906101000a900462ffffff1662ffffff1681526020019060030190602082600201049283019260010382029150808411610da057505050928452505060408051606081019182905260209093019291506002840190600390825f855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610e00575050509284525050506003919091015465ffffffffffff1660209091015280519091505f9060ff165b80156110395760a08301515f90610e77600184615c7b565b60038110610e8757610e87615d1b565b602002015161ffff169050610ece88828660800151600186610ea99190615c7b565b60038110610eb957610eb9615d1b565b602002015162ffffff168e8e8e8d8d8d6115d0565b1561102657604080518981526020810183905273ffffffffffffffffffffffffffffffffffffffff8d8116828401528c16606082015290517f573c13d5af72038238ea235fec819de220e307e6ee81ca9a7d9ad8de329f938f9181900360800190a18351610f3e90600190615d48565b60ff16610f4c600184615c7b565b10156110065760808401518451610f6590600190615d48565b60ff1660038110610f7857610f78615d1b565b60200201516080850151610f8d600185615c7b565b60038110610f9d57610f9d615d1b565b62ffffff909216602092909202015260a08401518451610fbf90600190615d48565b60ff1660038110610fd257610fd2615d1b565b602002015160a0850151610fe7600185615c7b565b60038110610ff757610ff7615d1b565b61ffff90921660209290920201525b83518461101282615d61565b60ff169052508261102281615d9b565b9350505b508061103181615dd2565b915050610e5f565b50801561118b5761104b8683836141e0565b65ffffffffffff421660c08201525f87815260026020908152604091829020835181549285015193850151606086015162ffffff166301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff9115156201000002919091167fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff60ff968716610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090961696909316959095179390931716929092171781556080820151919350839161112f9060018301906003615671565b5060a08201516111459060028301906003615709565b5060c09190910151600390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001665ffffffffffff9092169190911790556111cc565b5f86815260026020526040902060030180547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000164265ffffffffffff161790555b505050505050505050565b5f818152600260209081526040808320815160e081018352815460ff80821683526101008204811695830195909552620100008104909416151581840152630100000090930462ffffff166060808501919091528251808201938490529094939260808401919060018401906003908288855b82829054906101000a900462ffffff1662ffffff168152602001906003019060208260020104928301926001038202915080841161124a57505050928452505060408051606081019182905260209093019291506002840190600390825f855b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116112aa5750505092845250505060039182015465ffffffffffff166020918201526001545f87815292825260409283902060808501518551938601518686015195517ff78cd33900000000000000000000000000000000000000000000000000000000815296975073ffffffffffffffffffffffffffffffffffffffff9093169563f78cd339956109f7958b959092909190600401615e06565b5f818152600260209081526040808320815160e081018352815460ff80821683526101008204811695830195909552620100008104909416151581840152630100000090930462ffffff166060808501919091528251808201938490529094939260808401919060018401906003908288855b82829054906101000a900462ffffff1662ffffff16815260200190600301906020826002010492830192600103820291508084116113e957505050928452505060408051606081019182905260209093019291506002840190600390825f855b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116114495750505092845250505060039182015465ffffffffffff166020918201526001545f878152929091526040918290206080840151845193517fd099110e00000000000000000000000000000000000000000000000000000000815294955073ffffffffffffffffffffffffffffffffffffffff9092169363d099110e936109f793899392909190600401615ce2565b611515611536565b8060601b61152a57637448fbae5f526004601cfd5b6115338161156b565b50565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314610a6e576382b429005f526004601cfd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f88609b111580156115e3575060b78911155b156115f0575060016141d3565b6004890361160657506404a817c8003a106141d3565b60328914806116155750603389145b1561163a57503273ffffffffffffffffffffffffffffffffffffffff851614156141d3565b601a8914806116495750601b89145b806116545750601c89145b1561179057606086901b7fbe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b161480156116fe57507fef000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857508060125b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660be60f81b14801561178857507fef000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601383901a60f81b16145b9150506141d3565b601d890361184c57606086901b7fbe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b1614801561183d57507fef000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b15806117885750806012611708565b601e89148061185b5750601f89145b1561199657606086901b7fde000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b1614801561190557507fad000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507fde000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b1614801561178857508060135b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660ad60f81b149150506141d3565b60208914806119a55750602189145b15611adf57606086901b7fba000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b16148015611a4f57507fbe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507fba000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b1614801561178857508060131a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660be60f81b149150506141d3565b60228903611c1c57606086901b7fde000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b16148015611b8c57507faf000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507fde000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b1614801561178857508060131a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660af60f81b149150506141d3565b60238903611d5a57606086901b7ffe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b16148015611cc957507fed000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507ffe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b1614801561178857508060135b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660ed60f81b149150506141d3565b60248903611e4857606086901b7ffe000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b16148015611e0757507fd0000000000000000000000000000000000000000000000000000000000000007ff000000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857508060121a60f81b7f0f000000000000000000000000000000000000000000000000000000000000009081161480156117885750806013611d26565b6028891480611e575750602989145b15611f9157606086901b7ffa000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b16148015611f0157507fce000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507ffa000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b1614801561178857508060131a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660ce60f81b149150506141d3565b6025891480611fa05750602689145b80611fab5750602789145b156120b657606086901b7fba000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600c89901a60f81b1614801561205557507fd0000000000000000000000000000000000000000000000000000000000000007ff000000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b8061178857507f0b000000000000000000000000000000000000000000000000000000000000007f0f00000000000000000000000000000000000000000000000000000000000000601283901a60f81b161480156117885750806013611962565b600989036120c85750600134146141d3565b603489036120ef575073ffffffffffffffffffffffffffffffffffffffff851631156141d3565b60358903612116575073ffffffffffffffffffffffffffffffffffffffff861631156141d3565b603689036121475750670de0b6b3a764000073ffffffffffffffffffffffffffffffffffffffff87163110156141d3565b6038890361217957612171600273ffffffffffffffffffffffffffffffffffffffff891631615c22565b1590506141d3565b603989036121ad576121a3600273ffffffffffffffffffffffffffffffffffffffff891631615c22565b60011490506141d3565b603789036121ed578573ffffffffffffffffffffffffffffffffffffffff16318773ffffffffffffffffffffffffffffffffffffffff16311090506141d3565b605a890361221e575f80612200426145e9565b92509250508160011480156122155750806001145b925050506141d3565b605989036122575761012c6122366201518042615c22565b108061225057506201505461224e6201518042615c22565b115b90506141d3565b603b8903612290575f601861226e610e1042615e54565b6122789190615c22565b905060098110158015611788575060111190506141d3565b603c89036122c8575f60186122a7610e1042615e54565b6122b19190615c22565b9050600981108061178857506011111590506141d3565b60588903612301575f60186122df610e1042615e54565b6122e99190615c22565b905060078110158015611788575060171190506141d3565b602a8914806123105750602b89145b8061231b5750602c89145b806123265750601889145b806123315750601989145b1561236c578573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff161490506141d3565b602d89148061237b5750602e89145b806123865750602f89145b156123c2578573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16141590506141d3565b603d89036123de576007600362015180420401066001016121a3565b603f89036123fe57506002600160076201518042046003010601146141d3565b6041890361241f5760076003620151804204010660010160031490506141d3565b6043890361243f57506004600160076201518042046003010601146141d3565b6045890361245f57506005600160076201518042046003010601146141d3565b6047890361247f57506006600160076201518042046003010601146141d3565b604989036124a05760076003620151804204010660010160071490506141d3565b605c8914806124af5750605d89145b806124ba5750605e89145b156124f7575f8a81526002602052604090206003015442906124e69065ffffffffffff1661012c615e67565b65ffffffffffff16111590506141d3565b605f8903612526575f8a81526002602052604090206003015442906124e69065ffffffffffff16610258615e67565b60608914806125355750606289145b806125405750606189145b1561256c575f8a81526002602052604090206003015442906124e69065ffffffffffff16610e10615e67565b6063890361259b575f8a81526002602052604090206003015442906124e69065ffffffffffff1661a8c0615e67565b60648914806125aa5750606589145b806125b55750606689145b806125c05750606789145b806125cb5750606889145b806125d65750606989145b806125e15750606a89145b1561260e575f8a81526002602052604090206003015442906124e69065ffffffffffff1662015180615e67565b606b890361263e575f8a81526002602052604090206003015442906124e69065ffffffffffff166202a300615e67565b606c89148061264d5750606d89145b806126585750606e89145b15612685575f8a81526002602052604090206003015442906124e69065ffffffffffff1662093a80615e67565b606f8914806126945750607089145b156126c1575f8a81526002602052604090206003015442906124e69065ffffffffffff166224ea00615e67565b60718914806126d05750607289145b156126fe575f8a81526002602052604090206003015442906124e69065ffffffffffff166301dfe200615e67565b6007890361270f57503415156141d3565b6008890361271f575034156141d3565b601489148061272e5750601589145b1561273d576122506032614609565b600e89148061274c5750601089145b806127575750601289145b15612766576122506021614609565b600f8914806127755750601589145b1561278457612250603c614609565b60118914806127935750600d89145b156127a257612250600a614609565b60178914806127b15750601389145b156127c0576122506014614609565b601689036127d257612250604b614609565b603a89036127e45750600183116141d3565b6031890361280c575073ffffffffffffffffffffffffffffffffffffffff85163b15156141d3565b6030890361293557606087811b9087901b5f5b60148110156129295781816014811061283a5761283a615d1b565b1a60f81b7ff0000000000000000000000000000000000000000000000000000000000000001683826014811061287257612872615d1b565b1a60f81b7ff00000000000000000000000000000000000000000000000000000000000000016148061291157508181601481106128b1576128b1615d1b565b1a60f81b7f0f00000000000000000000000000000000000000000000000000000000000000168382601481106128e9576128e9615d1b565b1a60f81b7f0f0000000000000000000000000000000000000000000000000000000000000016145b15612921575f93505050506141d3565b60010161281f565b506001925050506141d3565b604f8903612962575f612947426145e9565b509150506006811015801561178857506008101590506141d3565b6050890361298c575f612974426145e9565b509150506006811080611788575060081090506141d3565b605189036129b8575f61299e426145e9565b50915050600c8110158061178857506002101590506141d3565b605289036129e3575f6129ca426145e9565b509150506002811180156117885750600c1190506141d3565b60538903612a10575f6129f5426145e9565b509150506003811015801561178857506005101590506141d3565b60548903612a3a575f612a22426145e9565b509150506003811080611788575060051090506141d3565b60558903612a67575f612a4c426145e9565b50915050600981101580156117885750600b101590506141d3565b60568903612a91575f612a79426145e9565b5091505060098110806117885750600b1090506141d3565b60578903612aa1575060016141d3565b604b891480612ab05750604e89145b15612ad8576001600762015180420460030106016006811480611788575060071490506141d3565b604d891480612ae75750604c89145b15612b12576001600762015180420460030106810190811080159061178857506005101590506141d3565b603e8903612b3257506001600762015180420460030106810114156141d3565b60408903612b535750600260016007620151804204600301060114156141d3565b60428903612b75576007600362015180420401066001016003141590506141d3565b60448903612b965750600460016007620151804204600301060114156141d3565b60468903612bb75750600560016007620151804204600301060114156141d3565b60488903612bd85750600660016007620151804204600301060114156141d3565b604a8903612bfa576007600362015180420401066001016007141590506141d3565b60938903612c1057612250898b89896007614653565b60928903612c2657612250898b89896005614653565b6094891480612c355750609189145b80612c405750609689145b80612c4b5750609789145b15612c5e57612250898b89896003614653565b6095891480612c6d5750609a89145b80612c785750609989145b80612c835750609889145b15612c9657612250898b89896002614653565b60738903612cac57612250898b600260786149a7565b60748903612cc257612250898b600360b46149a7565b60758903612cd957612250898b600561012c6149a7565b60768903612ec0575f8a8152600260205260409020600301544290612d089065ffffffffffff16610258615e67565b65ffffffffffff1611158015612d4a57505f8a8152600260205260409020600301544290612d409065ffffffffffff16610294615e67565b65ffffffffffff16115b15612e40575f8a815260026020908152604080832060030180547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000164265ffffffffffff16179055600582528083208c84529091528120805463ffffffff1691612db383615e86565b82546101009290920a63ffffffff8181021990931691831602179091555f8c81526005602081815260408084208f85529091529091205490911690039050612e3b57505f8981526005602090815260408083208b8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016905560016141d3565b612eb9565b5f8a815260026020908152604080832060030180547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000164265ffffffffffff16179055600582528083208c8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690555b505f6141d3565b60778903612ed457612250898b6007614d1c565b6078890361303857600760036201518042040106600101600103612f38575f8a81526005602090815260408083208c8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000166001179055613011565b5f8a815260026020526040902060030154612f5f90620151809065ffffffffffff16615ea8565b612f6a906001615e67565b65ffffffffffff16612f7f6201518042615e54565b03612fd2575f8a81526005602090815260408083208c84529091528120805463ffffffff1691612fae83615e86565b91906101000a81548163ffffffff021916908363ffffffff16021790555050613011565b5f8a81526005602090815260408083208c8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690555b505f8981526005602081815260408084208c85529091529091205463ffffffff16146141d3565b6079890361304c57612250898b6004614e92565b607a89036131a3575f61305e4261504d565b5f8c815260026020526040812060030154919250906130849065ffffffffffff1661504d565b905081613092826001615ecc565b036130e5575f8c81526005602090815260408083208e84529091528120805463ffffffff16916130c183615e86565b91906101000a81548163ffffffff021916908363ffffffff1602179055505061312b565b5050505f8981526005602090815260408083208b8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690556141d3565b5f8c81526005602090815260408083208e845290915290205463ffffffff16600b03613199575050505f8981526005602090815260408083208b8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016905560016141d3565b5f925050506141d3565b607b89036131b557612250898b615075565b607c89036131de57505f8981526002602052604090206003015465ffffffffffff1642146141d3565b608889036131f257612250898b6003615207565b6089890361320657612250898b6005615207565b608a890361321a57612250898b6007615207565b608b890361322e57612250898b600a615207565b6001890361326f5760016132428982615ecc565b5f8c81526002602052604090205461326691906301000000900462ffffff16615c7b565b101590506141d3565b60028903613284576005613242896001615ecc565b6003890361329957600a613242896001615ecc565b600589036132ac57612171600243615c22565b600689036132bf576121a3600243615c22565b600c8903613329576040517f70617373776f72640000000000000000000000000000000000000000000000006020820152602801604051602081830303815290604052805190602001208383604051613319929190615edf565b60405180910390201490506141d3565b600a890361333a57508015156141d3565b600b890361334a575080156141d3565b607d89036135ea575f8a81526004602090815260408083208c845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e08101808452919284019160018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190600401906020826003010492830192600103820291508084116133a3575050509290935250505050604081015151909150606088901b7fffffffff00000000000000000000000000000000000000000000000000000000908116911614801561347157505f8b81526002602052604090206003015461346d9065ffffffffffff166001600762015180909204600301919091060190565b6005145b801561348b57506007600362015180420401066001016001145b80156134bc57505f8b81526002602052604090206003015462093a80906134ba9065ffffffffffff1642615c7b565b105b1561350f5750505f8981526004602090815260408083208b8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001681556001908101919091556141d3565b604081015151606089901b7fffffffff000000000000000000000000000000000000000000000000000000009081169116146135e1576040818101805160608b901b7fffffffff000000000000000000000000000000000000000000000000000000001690525f8d8152600460209081528382208e83528152929020835181549385015160ff908116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909516911617929092178255518291906135dd90600183019060076157aa565b5050505b5f9150506141d3565b607e8914806135f95750608789145b156138c4575f8a81526004602090815260408083208c845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e08101808452919284019160018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001906004019060208260030104928301926001038202915080841161364f57905050505050508152505090505f62015180426136bc9190615e54565b5f8d815260026020526040812060030154919250906136e790620151809065ffffffffffff16615ea8565b65ffffffffffff1690508860601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191683604001515f6007811061372a5761372a615d1b565b60200201517fffffffff0000000000000000000000000000000000000000000000000000000016148015613767575081613765826001615ecc565b145b8015613781575061546061377e6201518042615c22565b10155b156137db575f8d81526004602090815260408083208f8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016815560018101829055905b5050600193505050506141d3565b60408301515160608b901b7fffffffff000000000000000000000000000000000000000000000000000000009081169116146138b957604083015160608b901b905f7fffffffff00000000000000000000000000000000000000000000000000000000909216602092830291909101525f8e81526004825260408082208f8352835290819020855181549387015160ff908116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009095169116179290921782558401518491906138b590600183019060076157aa565b5050505b5f93505050506141d3565b607f8903613aa4575f8a81526004602090815260408083208c845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e08101808452919284019160018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001906004019060208260030104928301926001038202915080841161391d57905050505050508152505090505f620151804261398a9190615e54565b5f8d815260026020526040812060030154919250906139b590620151809065ffffffffffff16615ea8565b65ffffffffffff1690508860601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191683604001515f600781106139f8576139f8615d1b565b60200201517fffffffff0000000000000000000000000000000000000000000000000000000016148015613a35575081613a33826002615ecc565b145b8015613781575073ffffffffffffffffffffffffffffffffffffffff8a163b156137db575f8d81526004602090815260408083208f8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016815560018101829055906137cd565b60808903613b1c575f8a8152600260205260409020600301544290613ad49065ffffffffffff1662015180615e67565b65ffffffffffff161115801561225057508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16141590506141d3565b60818903613c9a575f8a81526004602090815260408083208c845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e08101808452919284019160018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019060040190602082600301049283019260010382029150808411613b7557905050505050508152505090505f613bdc4261504d565b5f8d81526002602052604081206003015491925090613c029065ffffffffffff1661504d565b60408401515190915060608a901b7fffffffff000000000000000000000000000000000000000000000000000000009081169116148015613781575081613c4a826003615ecc565b036137db575f8d81526004602090815260408083208f8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016815560018101829055906137cd565b60828903613e75575f600760036201518042040106600101613cbf6201518042615e54565b613cc99190615c7b565b613cd4906001615ecc565b5f8c815260026020526040812060039081015492935065ffffffffffff90921691600762015180840490910106600101613d116201518084615e54565b613d1b9190615c7b565b613d26906001615ecc565b905060608a901b83613d39836007615ecc565b148015613e6a57507fba000000000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000005f83901a60f81b16148015613de057507fd0000000000000000000000000000000000000000000000000000000000000007ff000000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b80613e6a57507f0b000000000000000000000000000000000000000000000000000000000000007f0f00000000000000000000000000000000000000000000000000000000000000601283901a60f81b16148015613e6a57508060135b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660ad60f81b145b9450505050506141d3565b6083890361401c575f600760036201518042040106600101613e9a6201518042615e54565b613ea49190615c7b565b613eaf906001615ecc565b5f8c815260026020526040812060039081015492935065ffffffffffff90921691600762015180840490910106600101613eec6201518084615e54565b613ef69190615c7b565b613f01906001615ecc565b905060608a901b83613f14836007615ecc565b148015613fbb57507fde000000000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000005f83901a60f81b16148015613fbb57507fad000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000600183901a60f81b16145b80613e6a57507fde000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000601283901a60f81b16148015613e6a5750806013613e3d565b608489148061402b5750608589145b1561404257612250898b60078a8a620151806152c4565b6086890361405b57612250898b60048a8a610e106152c4565b608c890361406f57612250898b6003615207565b608d890361408357612250898b6005615207565b608d8914806140925750609089145b156140a357612250898b6005615207565b608e89036140b757612250898b6007615207565b608f89036140cb57612250898b600a615207565b605b89036141d0576040805160208082018d90528183018b9052825180830384018152606090920190925280519101205f806141a161410c61016d85615c22565b614117906001615ecc565b5f805f620afa6c8401935062023ab1840661016d62023ab082146105b48304618eac84048401030304606481048160021c8261016d0201038203915060996002836005020104600161030161f4ff830201600b1c84030193506b030405060708090a0b0c010260a01b811a9450506003841061019062023ab1880402820101945050509193909250565b92509250505f806141b1426145e9565b925092505081841480156141c457508083145b955050505050506141d3565b505f5b9998505050505050505050565b6141e8615830565b5f8083116141f75760016141f9565b825b9050836020015160ff1683855f015160ff166142159190615ecc565b10801561428857506020848101516040805192830188905261beef9083015260f81b7fff00000000000000000000000000000000000000000000000000000000000000166060820152600390606101604051602081830303815290604052805190602001205f1c6142869190615c22565b155b1561429b57614298600182615ecc565b90505b5f8561beef6040516020016142ba929190918252602082015260400190565b604051602081830303815290604052805190602001205f1c90505f5b828110156145de575f805f5b885160ff168110156143c557609b8960a00151826003811061430657614306615d1b565b602002015161ffff161015801561433c575060b78960a00151826003811061433057614330615d1b565b602002015161ffff1611155b1561435b5761434d609b60b7615c7b565b614358906001615ecc565b92505b886020015160ff1660011480614390575060038960a00151826003811061438457614384615d1b565b602002015161ffff1611155b806143b35750886020015160ff16895f015160016143ae9190615c62565b60ff16105b156143bd57600391505b6001016142e2565b505f805f5b60058110156144c957838461ffff168661ffff1660b76143ea9190615c7b565b6143f49190615c7b565b8861440161ffff85615eee565b8e6060015162ffffff166144159190615ecc565b604080516020810193909352820152606001604051602081830303815290604052805190602001205f1c6144499190615c22565b6144539190615c8e565b61445e906001615c8e565b92505f5b60048210801561447557508b5160ff1681105b156144ba578361ffff168c60a00151826003811061449557614495615d1b565b602002015161ffff16036144a857600192505b806144b281615d9b565b915050614462565b5081156144c9576001016143ca565b5060608a015160808b01518b5160ff16600381106144e9576144e9615d1b565b62ffffff909216602092909202015260a08a01518a5183919060ff166003811061451557614515615d1b565b61ffff909216602092909202015260608a0180519061453382615f05565b62ffffff1690525089518a61454782615f1c565b60ff169052505f8b815260036020908152604082208054600181810183559184529190922061ffff851691015560608b01517fa2c76bc2f53d218db7b73da5593a6f3b09c71e0d92aca376720d10369814f0d5918d916145a79190615f3a565b6040805192835262ffffff909116602083015261ffff85169082015260600160405180910390a15050600190920191506142d69050565b509395945050505050565b5f80806145fc6141176201518086615e54565b9196909550909350915050565b5f8160644244604051602001614629929190918252602082015260400190565b604051602081830303815290604052805190602001205f1c61464b9190615c22565b111592915050565b5f84815260046020908152604080832088845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e081018084528594938401919060018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190600401906020826003010492830192600103820291508084116146a657905050505050508152505090508460601b8160400151826020015160ff166007811061472457614724615d1b565b7fffffffff00000000000000000000000000000000000000000000000000000000909216602092830291909101528101518390614762906001615c62565b61476c9190615f56565b60ff9081166020830181905282519091161480156147b057506040810151517fffffffff000000000000000000000000000000000000000000000000000000001615155b1561486e578360601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168160400151825f015160ff16600781106147f4576147f4615d1b565b60200201517fffffffff00000000000000000000000000000000000000000000000000000000160361486e5750505f848152600460209081526040808320888452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016815560019081019190915561499e565b80515b816020015160ff168160ff1614614927578460601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191682604001518260ff16600781106148be576148be615d1b565b60200201517fffffffff00000000000000000000000000000000000000000000000000000000160361490a57836148f6826001615c62565b6149009190615f56565b60ff168252614927565b83614916826001615c62565b6149209190615f56565b9050614871565b5f8781526004602090815260408083208b8452825291829020845181549286015160ff908116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009094169116179190911781559083015183919061499590600183019060076157aa565b505f9450505050505b95945050505050565b5f83815260046020908152604080832087845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e081018084528594938401919060018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190600401906020826003010492830192600103820291508084116149fa57905050505050508152505090505f63ffffffff801642614a6a9190615c22565b60e01b90505f63ffffffff614a7f8642615c7b565b614a899190615c22565b60e01b9050818360400151846020015160ff1660078110614aac57614aac615d1b565b7fffffffff00000000000000000000000000000000000000000000000000000000909216602092830291909101528301518690614aea906001615c62565b614af49190615f56565b60ff908116602085018190528451909116148015614b3857506040830151517fffffffff000000000000000000000000000000000000000000000000000000001615155b15614bf957604083015183517fffffffff000000000000000000000000000000000000000000000000000000008316919060ff1660078110614b7c57614b7c615d1b565b60200201517fffffffff000000000000000000000000000000000000000000000000000000001610614bf9575050505f848152600460209081526040808320888452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001681556001908101919091559050614d14565b826020015160ff16835f015160ff1614614c9c57604083015183517fffffffff000000000000000000000000000000000000000000000000000000008316919060ff1660078110614c4c57614c4c615d1b565b60200201517fffffffff00000000000000000000000000000000000000000000000000000000161015614c9c5782518690614c88906001615c62565b614c929190615f56565b60ff168352614bf9565b5f8781526004602090815260408083208b8452825291829020855181549287015160ff908116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090941691161791909117815590840151849190614d0a90600183019060076157aa565b505f955050505050505b949350505050565b5f80614d2b6201518042615e54565b5f8581526002602052604081206003015491925090614d5690620151809065ffffffffffff16615ea8565b65ffffffffffff16905081614d6c826001615ecc565b03614dbf575f8581526005602090815260408083208984529091528120805463ffffffff1691614d9b83615e86565b91906101000a81548163ffffffff021916908363ffffffff16021790555050614e10565b81614dcb826001615ecc565b1015614e10575f858152600560209081526040808320898452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690555b614e1b600185615c7b565b5f8681526005602090815260408083208a845290915290205463ffffffff1603614e87575050505f828152600560209081526040808320868452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690556001610a56565b505f95945050505050565b5f80600760036201518042040106600101614eb06201518042615e54565b614eba9190615c7b565b614ec5906001615ecc565b5f85815260026020526040812060039081015492935065ffffffffffff90921691600762015180840490910106600101614f026201518084615e54565b614f0c9190615c7b565b614f17906001615ecc565b905082614f25826007615ecc565b03614f78575f8681526005602090815260408083208a84529091528120805463ffffffff1691614f5483615e86565b91906101000a81548163ffffffff021916908363ffffffff16021790555050614fc9565b82614f84826001615ecc565b1015614fc9575f8681526005602090815260408083208a8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690555b614fd4600186615c7b565b5f8781526005602090815260408083208b845290915290205463ffffffff1603615041575050505f838152600560209081526040808320878452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000169055506001610a56565b505f9695505050505050565b5f805f615059846145e9565b5090925090508061506b83600c615eee565b614d149190615ecc565b5f80615080426145e9565b505f8581526002602052604081206003015491935091506150a89065ffffffffffff166145e9565b5091505f905060036150bb600c85615c22565b6150c59190615e54565b90505f60036150d5600c85615c22565b6150df9190615e54565b90508160046150ef836001615ecc565b6150f99190615c22565b0361514c575f8681526005602090815260408083208a84529091528120805463ffffffff169161512883615e86565b91906101000a81548163ffffffff021916908363ffffffff16021790555050615196565b5050505f838152600560209081526040808320878452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016905591506104d99050565b5f8681526005602090815260408083208a845290915290205463ffffffff16600303615041575050505f838152600560209081526040808320878452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016905550600190506104d9565b5f8281526005602090815260408083208684529091528120805463ffffffff16908261523283615e86565b82546101009290920a63ffffffff8181021990931691831602179091555f85815260056020908152604080832089845290915290205460ff851691160390506152bb57505f828152600560209081526040808320868452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001690556001610a56565b505f9392505050565b5f85815260046020908152604080832089845282528083208151606081018352815460ff80821683526101009091041693810193909352815160e081018084528594938401919060018401906007908288855b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001906004019060208260030104928301926001038202915080841161531757905050505050508152505090505f83426153819190615e54565b5f89815260026020526040812060030154919250906153a990869065ffffffffffff16615e54565b9050816153b7826001615ecc565b146153c757602083015160ff1683525b8660601b8360400151846020015160ff16600781106153e8576153e8615d1b565b7fffffffff00000000000000000000000000000000000000000000000000000000909216602092830291909101528301518890615426906001615c62565b6154309190615f56565b60ff90811660208501819052845190911614801561547457506040830151517fffffffff000000000000000000000000000000000000000000000000000000001615155b15615535578560601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168360400151845f015160ff16600781106154b8576154b8615d1b565b60200201517fffffffff000000000000000000000000000000000000000000000000000000001603615535575050505f8681526004602090815260408083208a8452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001681556001908101919091559050615667565b82515b836020015160ff168160ff16146155ee578660601b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191684604001518260ff166007811061558557615585615d1b565b60200201517fffffffff0000000000000000000000000000000000000000000000000000000016036155d157886155bd826001615c62565b6155c79190615f56565b60ff1684526155ee565b886155dd826001615c62565b6155e79190615f56565b9050615538565b5f8a81526004602090815260408083208e8452825291829020865181549288015160ff908116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009094169116179190911781559085015185919061565c90600183019060076157aa565b505f96505050505050505b9695505050505050565b6001830191839082156156f9579160200282015f5b838211156156c857835183826101000a81548162ffffff021916908362ffffff1602179055509260200192600301602081600201049283019260010302615686565b80156156f75782816101000a81549062ffffff02191690556003016020816002010492830192600103026156c8565b505b50615705929150615878565b5090565b6001830191839082156156f9579160200282015f5b8382111561575e57835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030261571e565b80156156f75782816101000a81549061ffff021916905560020160208160010104928301926001030261575e565b60405180606001604052806003906020820280368337509192915050565b6001830191839082156156f9579160200282015f5b8382111561580057835183826101000a81548163ffffffff021916908360e01c021790555092602001926004016020816003010492830192600103026157bf565b80156156f75782816101000a81549063ffffffff0219169055600401602081600301049283019260010302615800565b6040805160e0810182525f8082526020820181905291810182905260608101919091526080810161585f61578c565b815260200161586c61578c565b81525f60209091015290565b5b80821115615705575f8155600101615879565b5f6020828403121561589c575f80fd5b5035919050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b805f5b600381101561591d57815162ffffff168452602093840193909101906001016158f9565b50505050565b5f815180845260208085019450602084015f5b8381101561595257815187529582019590820190600101615936565b509495945050505050565b5f61018060ff8b168352602060ff8b166020850152891515604085015262ffffff8916606085015261599260808501896158f6565b60e08401875f5b60038110156159ba57815161ffff1683529183019190830190600101615999565b50505065ffffffffffff861661014085015250806101608401526159e081840185615923565b9b9a5050505050505050505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114615a12575f80fd5b919050565b5f60208284031215615a27575f80fd5b610a56826159ef565b5f8060408385031215615a41575f80fd5b50508035926020909101359150565b5f805f805f805f60c0888a031215615a66575f80fd5b615a6f886159ef565b9650615a7d602089016159ef565b9550615a8b604089016159ef565b9450606088013593506080880135925060a088013567ffffffffffffffff80821115615ab5575f80fd5b818a0191508a601f830112615ac8575f80fd5b813581811115615ad6575f80fd5b8b6020828501011115615ae7575f80fd5b60208301945080935050505092959891949750929550565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60208284031215615b3c575f80fd5b815167ffffffffffffffff80821115615b53575f80fd5b818401915084601f830112615b66575f80fd5b815181811115615b7857615b78615aff565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715615bbe57615bbe615aff565b81604052828152876020848701011115615bd6575f80fd5b8260208601602083015e5f928101602001929092525095945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82615c3057615c30615bf5565b500690565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60ff81811683821601908111156104d9576104d9615c35565b818103818111156104d9576104d9615c35565b61ffff818116838216019080821115615ca957615ca9615c35565b5092915050565b5f815480845260208085019450835f5260205f205f5b8381101561595257815487529582019560019182019101615cc6565b84815260c060208201525f615cfa60c0830186615cb0565b9050615d0960408301856158f6565b60ff831660a083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60ff82811682821603908111156104d9576104d9615c35565b5f60ff821680615d7357615d73615c35565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615dcb57615dcb615c35565b5060010190565b5f81615de057615de0615c35565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b5f610100888352806020840152615e1f81840189615cb0565b915050615e2f60408301876158f6565b60ff851660a083015260ff841660c083015282151560e0830152979650505050505050565b5f82615e6257615e62615bf5565b500490565b65ffffffffffff818116838216019080821115615ca957615ca9615c35565b5f63ffffffff808316818103615e9e57615e9e615c35565b6001019392505050565b5f65ffffffffffff80841680615ec057615ec0615bf5565b92169190910492915050565b808201808211156104d9576104d9615c35565b818382375f9101908152919050565b80820281158282048414176104d9576104d9615c35565b5f62ffffff808316818103615e9e57615e9e615c35565b5f60ff821660ff8103615f3157615f31615c35565b60010192915050565b62ffffff828116828216039080821115615ca957615ca9615c35565b5f60ff831680615f6857615f68615bf5565b8060ff8416069150509291505056fea26469706673582212205740219e7c6d6df2e30f8644dc6b5e1005c5f0a4d53c0784dc4795042801ff7864736f6c63430008190033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ 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.