ETH Price: $3,189.21 (-6.63%)

Contract

0x9a6b280D9dE461c16e9D47fB7996aCbe36Eac50B
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

TokenTracker

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Approval For...235407602025-10-09 14:25:3535 days ago1760019935IN
0x9a6b280D...e36Eac50B
0 ETH0.000122732.63945101
Set Approval For...234825572025-10-01 11:08:3543 days ago1759316915IN
0x9a6b280D...e36Eac50B
0 ETH0.00005931.27549541
Set Approval For...234825162025-10-01 10:59:5943 days ago1759316399IN
0x9a6b280D...e36Eac50B
0 ETH0.000057331.23300544
Move Turmite228600142025-07-06 11:58:35130 days ago1751803115IN
0x9a6b280D...e36Eac50B
0 ETH0.022327192.25839233
Reprogramm Turmi...228600052025-07-06 11:56:35130 days ago1751802995IN
0x9a6b280D...e36Eac50B
0 ETH0.000072192.24380578
Reprogramm Turmi...228599872025-07-06 11:52:59130 days ago1751802779IN
0x9a6b280D...e36Eac50B
0 ETH0.000072582.2448631
Set Approval For...225509272025-05-24 6:29:47173 days ago1748068187IN
0x9a6b280D...e36Eac50B
0 ETH0.000046050.99040661
Move Turmite223728612025-04-29 6:15:23198 days ago1745907323IN
0x9a6b280D...e36Eac50B
0 ETH0.001935520.87709193
Move Turmite223728492025-04-29 6:12:59198 days ago1745907179IN
0x9a6b280D...e36Eac50B
0 ETH0.007717980.87730854
Reprogramm Turmi...223728362025-04-29 6:10:23198 days ago1745907023IN
0x9a6b280D...e36Eac50B
0 ETH0.000027230.84540627
Set Approval For...219591922025-03-02 12:29:35256 days ago1740918575IN
0x9a6b280D...e36Eac50B
0 ETH0.000030640.65913967
Set Approval For...217744952025-02-04 17:01:35282 days ago1738688495IN
0x9a6b280D...e36Eac50B
0 ETH0.000133412.86922129
Move Turmite204718612024-08-06 20:17:11464 days ago1722975431IN
0x9a6b280D...e36Eac50B
0 ETH0.006561495.33958688
Safe Transfer Fr...204718302024-08-06 20:10:59464 days ago1722975059IN
0x9a6b280D...e36Eac50B
0 ETH0.000661856.19807008
Set Approval For...200332922024-06-06 14:10:23525 days ago1717683023IN
0x9a6b280D...e36Eac50B
0 ETH0.0016272634.93258152
Set Approval For...197349352024-04-25 21:01:59566 days ago1714078919IN
0x9a6b280D...e36Eac50B
0 ETH0.000413828.89962095
Set Approval For...193952482024-03-09 4:46:59614 days ago1709959619IN
0x9a6b280D...e36Eac50B
0 ETH0.0017765538.20640885
Set Approval For...192576772024-02-18 22:35:35633 days ago1708295735IN
0x9a6b280D...e36Eac50B
0 ETH0.0010055121.58548856
Set Approval For...191624952024-02-05 13:53:59647 days ago1707141239IN
0x9a6b280D...e36Eac50B
0 ETH0.0009859821.16617534
Set Approval For...187282932023-12-06 15:52:23708 days ago1701877943IN
0x9a6b280D...e36Eac50B
0 ETH0.0031138366.96565129
Set Approval For...187134502023-12-04 13:58:59710 days ago1701698339IN
0x9a6b280D...e36Eac50B
0 ETH0.0023063749.60059114
Set Approval For...178495952023-08-05 15:14:59831 days ago1691248499IN
0x9a6b280D...e36Eac50B
0 ETH0.0017771938.2201712
Set Approval For...177051372023-07-16 10:03:47851 days ago1689501827IN
0x9a6b280D...e36Eac50B
0 ETH0.0007244715.55229156
Reprogramm Turmi...176015302023-07-01 20:19:35866 days ago1688242775IN
0x9a6b280D...e36Eac50B
0 ETH0.0004557414.17043589
Set Approval For...175546882023-06-25 6:22:11872 days ago1687674131IN
0x9a6b280D...e36Eac50B
0 ETH0.00065114.00042062
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xD30A18Cd...36F4Cc41d
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Straylight

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "./metadata.sol";
import "./EnumerableMate.sol";

//                           STRAYLIGHT PROTOCOL v.01
//
//                                .         .
//                                  ., ... .,
//                                  \%%&%%&./
//                         ,,.      /@&&%&&&\     ,,
//                            *,   (##%&&%##)  .*.
//                              (,  (#%%%%.)   %,
//                               ,% (#(##(%.(/
//                                 %((#%%%##*
//                 ..**,*/***///*,..,#%%%%*..,*\\\***\*,**..
//                                   /%#%%
//                              /###(/%&%/(##%(,
//                           ,/    (%###%%&%,   **
//                         .#.    *@&%###%%&)     \\
//                        /       *&&%###%&@#       *.
//                      ,*         (%#%###%#?)       .*.
//                                 ./%%###%%#,
//                                  .,(((##,.
//
//

/// @title Straylight
/// @notice The main point of interaction for Straylight - relies on Gamboard, Metadata, Turmitesv4 and EnumerableMate
/// @author @brachlandberlin / plsdlr.net
/// @dev facilitates minting, moving of individual turmites, reprogramming and even external logic of turmites and overwrites tokenUri()

contract Straylight is EnumerableMate, Metadata {
    event TurmiteReprogramm(uint256 indexed tokenId, bytes12 indexed newrule);
    event TurmiteMint(uint256 indexed tokenId, bytes12 indexed rule, uint256 boardId);

    uint256 public boardcounter = 0;
    uint256 private turmitecounter = 0;
    uint256 public maxnumbturmites;
    uint256[4] startx = [36, 72, 72, 108];
    uint256[4] starty = [72, 36, 108, 72];
    address minterContract;
    address haecceityContract;
    address admin;
    mapping(uint256 => bool) public haecceity;

    constructor(
        address _minterContract,
        uint256 maxAmount,
        string memory network
    ) Metadata(network) EnumerableMate("Straylight", "STR") {
        minterContract = _minterContract;
        maxnumbturmites = maxAmount;
        admin = msg.sender;
    }

    /// @dev public Mint function should only be called from external Minter Contract
    /// @param mintTo the address the token should be minted to
    /// @param rule the inital rule the turmite is minted with
    /// @param moves the inital number of rules the turmite is minted with
    function publicmint(
        address mintTo,
        bytes12 rule,
        uint256 moves
    ) external {
        require(turmitecounter < maxnumbturmites, "MINT_OVER");
        require(validateNewRule(rule) == true, "INVALID_RULE");
        require(msg.sender == minterContract, "ONLY_MINTABLE_FROM_MINT_CONTRACT");

        boardcounter = (turmitecounter / 4) + 1;
        uint256 startposx = startx[turmitecounter % 4];
        uint256 startposy = starty[turmitecounter % 4];
        _addTokenToOwnerEnumeration(mintTo, turmitecounter);
        _addTokenToAllTokensEnumeration(turmitecounter);
        _mint(mintTo, turmitecounter);
        createTurmite(turmitecounter, uint8(startposx), uint8(startposy), 1, uint8(boardcounter), rule);
        emit TurmiteMint(turmitecounter, rule, boardcounter);
        if (moves > 0) {
            calculateTurmiteMove(turmitecounter, moves);
        }
        haecceity[turmitecounter] = false;
        turmitecounter = turmitecounter + 1;
    }

    /// @dev overwrites the tokenURI function from ERC721 Solmate
    /// @param id the id of the NFT
    function tokenURI(uint256 id) public view override returns (string memory) {
        return
            fullMetadata(
                id,
                turmites[id].boardnumber,
                turmites[id].rule,
                turmites[id].state,
                turmites[id].turposx,
                turmites[id].turposy,
                turmites[id].orientation
            );
    }

    /// @dev helper Function to render board without turmites
    /// @param number Board number
    function renderBoard(uint8 number) public view returns (string memory) {
        return getSvg(number, 0, 0, false);
    }

    function moveTurmite(uint256[2] calldata idmoves) external {
        require(msg.sender == ownerOf(idmoves[0]), "NOT_AUTHORIZED");
        if (idmoves[1] > 0) {
            calculateTurmiteMove(idmoves[0], idmoves[1]);
        }
    }

    /// @dev function to validate that an new input from user is in the "gramma" of the rules
    /// @param rule a bytes12 rule - to understand the specific gramma of rules take a look at turmitev4 contract
    function validateNewRule(bytes12 rule) public pure returns (bool allowed) {
        //Normal Format Example: 0xff0801ff0201ff0000000001
        //we dont test against direction bc direction never writes
        //bool firstbit = (rule[0] == 0xFF || rule[0] == 0x00);
        //bool secondbit = (rule[3] == 0xFF || rule[3] == 0x00);
        bool colorfieldbit = ((rule[0] == 0xFF || rule[0] == 0x00) &&
            (rule[3] == 0xFF || rule[3] == 0x00) &&
            (rule[6] == 0xFF || rule[6] == 0x00) &&
            (rule[9] == 0xFF || rule[9] == 0x00));
        bool statebit = ((rule[2] == 0x01 || rule[2] == 0x00) &&
            (rule[5] == 0x01 || rule[5] == 0x00) &&
            (rule[8] == 0x01 || rule[8] == 0x00) &&
            (rule[11] == 0x01 || rule[11] == 0x00));
        return bool(statebit && colorfieldbit);
    }

    /// @notice WE EXPECT THAT YOU KNOW WHAT YOU ARE DOING BEFORE CALLING THIS FUNCTION MANUALY
    /// @notice PLEASE CONSULT THE DOCUMENTATION
    /// @dev function to reprogramm your turmite | DANGERZONE | if you don't use the interface consult the documentation before wasting gas
    /// @param id ID of the turmite
    /// @param rule a bytes12 rule - to understand the specific gramma of rules take a look at turmitev4 contract
    function reprogrammTurmite(uint256 id, bytes12 rule) external {
        require(msg.sender == ownerOf(id), "NOT_AUTHORIZED");
        require(validateNewRule(rule) == true, "INVALID_RULE");
        turmites[id].rule = rule;
        emit TurmiteReprogramm(id, rule);
    }

    /// @dev function for the admin to set external HA Contract
    /// @param _haecceityContract address of contract
    function setHaecceityContract(address _haecceityContract) external {
        require(msg.sender == admin, "NOT_AUTHORIZED");
        haecceityContract = _haecceityContract;
    }

    /// @dev get the position(x and y values) and the state of the current field for a turmite (all handy encoded)
    /// @param id the id of the token / turmite
    function getPosField(uint256 id) public view returns (bytes memory encodedData) {
        bytes32 sour;
        uint8 _x;
        uint8 _y;
        bytes memory data = new bytes(32);
        turmite storage dataTurmite = turmites[id];
        assembly {
            sour := sload(dataTurmite.slot)
            _x := and(sour, 0xFF)
            _y := and(shr(8, sour), 0xFF)
        }
        bytes1 stateOfField = getByte(_x, _y, (id / 4) + 1);
        assembly {
            mstore8(add(data, 32), _x)
            mstore8(add(data, 33), _y)
            mstore(add(data, 34), stateOfField)
        }
        return (data);
    }

    //  _   _   _____          _   _  _____ ______ _____   __________  _   _ ______   _   _
    // | | | | |  __ \   /\   | \ | |/ ____|  ____|  __ \ |___  / __ \| \ | |  ____| | | | |
    // | | | | | |  | | /  \  |  \| | |  __| |__  | |__) |   / / |  | |  \| | |__    | | | |
    // | | | | | |  | |/ /\ \ | . ` | | |_ |  __| |  _  /   / /| |  | | . ` |  __|   | | | |
    // |_| |_| | |__| / ____ \| |\  | |__| | |____| | \ \  / /_| |__| | |\  | |____  |_| |_|
    // (_) (_) |_____/_/    \_\_| \_|\_____|______|_|  \_\/_____\____/|_| \_|______| (_) (_)

    /// @notice WE EXPECT THAT YOU KNOW WHAT YOU ARE DOING BEFORE CALLING THIS FUNCTION
    /// @notice PLEASE CONSULT THE DOCUMENTATION
    /// @dev should be called by user to unlock external control
    /// @param id the id of the token / turmite the user what to hand logic control over to external smart contract
    function setHaecceityMode(uint256 id) external {
        require(haecceityContract != address(0), "CONTRACT_IS_ZEROADDRESS");
        require(msg.sender == ownerOf(id), "NOT_AUTHORIZED");
        haecceity[id] = true;
    }

    /// @dev internal deocde function
    ///  @param data data to decode
    function decode(bytes memory data)
        internal
        pure
        returns (
            uint8 x,
            uint8 y,
            bytes1 field
        )
    {
        assembly {
            x := mload(add(data, 1))
            y := mload(add(data, 2))
            field := mload(add(data, 34))
        }
    }

    /// @notice WE EXPECT THAT YOU KNOW WHAT YOU ARE DOING BEFORE CALLING THIS FUNCTION
    /// @notice PLEASE CONSULT THE DOCUMENTATION
    /// @dev function should be called by external haecceity Contract which allows external control of turmites by user deployed smart contracts
    /// @dev this function sets the field
    /// @param id the id of the turmite
    /// @param data the encoded data of the next step
    function setByteHaMode(uint256 id, bytes calldata data) external {
        require(haecceityContract != address(0), "CONTRACT_IS_ZEROADDRESS");
        require(haecceity[id] == true, "CONTRACT_NOT_INITALIZED_BY_NFT_OWNER");
        require(msg.sender == haecceityContract, "CALL_ONLY_FROM_HACONTRACT");
        (uint8 x, uint8 y, bytes1 stateOfField) = decode(data);
        setByte(x, y, stateOfField, turmites[id].boardnumber);
    }

    /// @notice WE EXPECT THAT YOU KNOW WHAT YOU ARE DOING BEFORE CALLING THIS FUNCTION
    /// @notice PLEASE CONSULT THE DOCUMENTATION
    /// @dev function should be called by external haecceity Contract which allows external control of turmites by user deployed smart contracts
    /// @dev this function sets the end position after moving
    /// @param id the id of the turmite
    /// @param data the encoded data of the position
    function setPositionHaMode(uint256 id, bytes calldata data) external {
        require(haecceityContract != address(0), "CONTRACT_IS_ZEROADDRESS");
        require(haecceity[id] == true, "CONTRACT_NOT_INITALIZED_BY_NFT_OWNER");
        require(msg.sender == haecceityContract, "CALL_ONLY_FROM_HACONTRACT");
        (uint8 x, uint8 y, ) = decode(data);
        turmites[id].turposx = x;
        turmites[id].turposy = y;
    }

    /// @dev overwriting transfer functions to add extension from here

    /// @notice after every transfer we reset the permission for external control
    /// @dev resets permission after every transfer
    function _transferResetHAMode(uint256 tokenId) internal {
        if (haecceity[tokenId] == true) {
            haecceity[tokenId] = false;
        }
    }

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        _transferResetHAMode(tokenId);
        _removeTokenFromOwnerEnumeration(from, tokenId);
        _addTokenToOwnerEnumeration(to, tokenId);
        super.transferFrom(from, to, tokenId);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        _transferResetHAMode(tokenId);
        _removeTokenFromOwnerEnumeration(from, tokenId);
        _addTokenToOwnerEnumeration(to, tokenId);
        super.safeTransferFrom(from, to, tokenId);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) public virtual override {
        _transferResetHAMode(tokenId);
        _removeTokenFromOwnerEnumeration(from, tokenId);
        _addTokenToOwnerEnumeration(to, tokenId);
        super.safeTransferFrom(from, to, tokenId, data);
    }
}

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "./turmitev4.sol";
import "solady/src/utils/LibString.sol";

/// @title Metadata
/// @notice Renders the dynamic metadata of every NFT via the Turmite v4.
/// @author @brachlandberlin / plsdlr.net
/// @dev Generates the metadata as JSON String and encodes it with base64 and data:application/json;base64,

contract Metadata is Turmite {
    string private network;

    constructor(string memory _network) {
        network = _network;
    }

    /// @dev generates the dynamic metadata
    /// @param tokenId the tokenId of the Turmite
    /// @param boardNumber the Board Number
    /// @param rule the rule of the turmite
    /// @param state current state
    /// @param turposx x position of the turmite
    /// @param turposy y position of the turmite
    /// @param orientation orientation of the turmite
    function fullMetadata(
        uint256 tokenId,
        uint8 boardNumber,
        bytes12 rule,
        bytes1 state,
        uint8 turposx,
        uint8 turposy,
        uint8 orientation
    ) internal view returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "data:application/json;base64,",
                    Base64.encode(
                        abi.encodePacked(
                            '{"name":"',
                            generateName(tokenId, boardNumber),
                            '", "description":"',
                            "Onchain Mutiplayer Art",
                            '", "image": "',
                            getSvg(boardNumber, turposx, turposy, true),
                            '",',
                            '"attributes": ',
                            generateAttributes(boardNumber, rule, state, turposx, turposy, orientation),
                            "}"
                        )
                    )
                )
            );
    }

    /// @dev generates the Name of the turmite as a string
    /// @param tokenId the tokenId of the Turmite
    /// @param boardNumber the Board Number
    function generateName(uint256 tokenId, uint8 boardNumber) internal pure returns (string memory) {
        return
            string(
                abi.encodePacked("Turmite ", LibString.toString(tokenId), " World ", LibString.toString(boardNumber))
            );
    }

    /// @dev generates the dynamic attributes as JSON String, for param see fullMetadata()
    function generateAttributes(
        uint8 boardNumber,
        bytes12 rule,
        bytes1 state,
        uint8 turposx,
        uint8 turposy,
        uint8 orientation
    ) internal view returns (string memory) {
        return
            string(
                abi.encodePacked(
                    '[{"trait_type":"World","value":"',
                    LibString.toString(boardNumber),
                    '"},',
                    '{"trait_type":"Rule",',
                    '"value":"',
                    bytes12ToString(rule),
                    '"},',
                    '{"trait_type":"State",',
                    '"value":"',
                    LibString.toString(uint8(state)),
                    '"},',
                    '{"trait_type":"POS X",',
                    '"value":"',
                    LibString.toString(turposx),
                    '"},',
                    '{"trait_type":"POS Y",',
                    '"value":"',
                    LibString.toString(turposy),
                    '"},',
                    '{"trait_type":"Direction",',
                    '"value":"',
                    LibString.toString(orientation),
                    '"},{"trait_type":"Network","value":"',
                    network,
                    '"}]'
                )
            );
    }

    /// @dev helper function to create a String from a byte12
    /// @param _bytes12 the input value
    function bytes12ToString(bytes12 _bytes12) internal pure returns (string memory) {
        uint8 i = 0;
        bytes memory bytesArray = new bytes(24);
        for (i = 0; i < bytesArray.length; i++) {
            uint8 _f = uint8(_bytes12[i / 2] & 0x0f);
            uint8 _l = uint8(_bytes12[i / 2] >> 4);

            bytesArray[i] = toByte(_l);
            i = i + 1;
            bytesArray[i] = toByte(_f);
        }
        return string(bytesArray);
    }

    /// @dev helper function to convert from uint8 to byte1
    /// @param _uint8 the input value
    function toByte(uint8 _uint8) internal pure returns (bytes1) {
        if (_uint8 < 10) {
            return bytes1(_uint8 + 48);
        } else {
            return bytes1(_uint8 + 87);
        }
    }
}

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

import "@rari-capital/solmate/src/tokens/ERC721.sol";

/// @title EnumerableMate
/// @notice slightly reduced version of ERC721Enumerable.sol - mainly optimizing the transfer function
/// @author @brachlandberlin / plsdlr.net
/// @author OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
/// @dev Comments are mostly taken over from OpenZeppelin

abstract contract EnumerableMate is ERC721 {
    // Mapping from owner to list of owned token IDs
    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint256 => uint256) private _ownedTokensIndex;

    // Array with all token ids, used for enumeration
    uint256[] private _allTokens;

    // Mapping from token id to position in the allTokens array
    mapping(uint256 => uint256) private _allTokensIndex;

    constructor(string memory name, string memory s) ERC721(name, s) {}

    /// getter
    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
        require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }

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

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual returns (uint256) {
        require(index < EnumerableMate.totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }

    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) internal {
        uint256 length = ERC721.balanceOf(to);
        _ownedTokens[to][length] = tokenId;
        _ownedTokensIndex[tokenId] = length;
    }

    function _addTokenToAllTokensEnumeration(uint256 tokenId) internal {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) internal {
        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }

    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) internal {
        uint256 lastTokenIndex = _allTokens.length - 1;
        uint256 tokenIndex = _allTokensIndex[tokenId];
        uint256 lastTokenId = _allTokens[lastTokenIndex];
        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        delete _allTokensIndex[tokenId];
        _allTokens.pop();
    }
}

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "./gameboard.sol";

/// @title Turmite v4
/// @notice Implementation of Turmite logic for Straylight Protocoll.
/// @author @brachlandberlin / plsdlr.net
/// @dev Every Turmite rule is for simplicity represented as 12 Bytes. For easy acess by render functions all individual turmite data is safed in an struct.

contract Turmite is Gameboard {
    // using Base64 for string;    //note what is this used for?

    mapping(uint256 => turmite) public turmites;

    event TurmiteMove(uint256 indexed tokenId, uint8 indexed boardnumber, uint256 indexed moves);

    /// @dev individual slot for every turmite
    // Layout from Example:
    // _____________________________________________________________________________________________________
    // Empty Space :)                   Rule                     State  Boardnumber  Orientation   Y     X
    // _____________________________________________________________________________________________________
    // 0x000000000000000000000000000000 ff0801ff0201ff0000000001 01     01           01            32    3a
    // _____________________________________________________________________________________________________
    //
    struct turmite {
        uint8 turposx;
        uint8 turposy;
        uint8 orientation;
        uint8 boardnumber;
        bytes1 state;
        bytes12 rule;
    }

    /// @dev grammar for the rules
    // Layout from example rule
    // Rule:
    // _________________________________________________
    // ff0801ff0201ff0000000001                            2 states / 4 rulessegments
    // _________________________________________________
    // | ff0801 | ff0201 | ff0000 | 000001 |               4 * 3 Bytes
    // _________________________________________________
    // | c d s  |  c d s |  ...                            c = color, d = direction, s = state
    // _________________________________________________
    // | c = ff  ,  d = 08  ,  s = 01 | ...
    // _________________________________________________
    //
    // written as context-sensitive grammar, with start symbol S:
    //
    //     S    	→       a  a  a
    //     a        →       c  d  s
    //     c        →       ff | 00
    //     d        →       02 | 08 | 04
    //     s        →       01 | 00

    /// @dev creates an Turmite Struct and mapping to id, every turmite gets initalized with state 0
    /// @param posx the x position of the turmite on the board
    /// @param posy the y position on the turmite on the board
    /// @param startdirection the startdirection of the turmite
    /// @param boardNumber the boardNumber number
    /// @param rule 12 Byte rule which defines behavior of the turmite
    function createTurmite(
        uint256 id,
        uint8 posx,
        uint8 posy,
        uint8 startdirection,
        uint8 boardNumber,
        bytes12 rule
    ) internal {
        bytes1 state = hex"00";
        turmites[id] = turmite(posx, posy, startdirection, boardNumber, state, rule);
    }

    /// @dev main computational logic of turmite
    /// @dev this function is internal because there should be a check to validate ownership of the turmite
    /// @param id the id of the turmite to move
    /// @param moves the number of moves
    function calculateTurmiteMove(uint256 id, uint256 moves) internal {
        bytes1 colorField;
        uint8 _x;
        uint8 _y;
        uint8 _boardNumber;
        bytes32 sour;

        turmite storage data = turmites[id];
        assembly {
            sour := sload(data.slot)
        }
        for (uint256 z = 0; z < moves; ) {
            assembly {
                _x := and(sour, 0xFF)
                _y := and(shr(8, sour), 0xFF)
                _boardNumber := shr(24, sour)
            }
            bytes1 stateOfField = getByte(_x, _y, _boardNumber);
            assembly {
                let maskedRule := and(sour, 0x000000000000000000000000000000ffffffffffffffffffffffff0000000000)

                let _orientation := and(
                    shr(16, sour),
                    0x00000000000000000000000000000000000000000000000000000000000000ff
                )

                let newState
                let newDirection

                if and(
                    eq(shr(248, stateOfField), 0x00),
                    eq(shr(32, and(sour, 0x000000000000000000000000000000000000000000000000000000ff00000000)), 0x00)
                ) {
                    colorField := shl(120, maskedRule)
                    newDirection := and(shr(120, maskedRule), 0xFF)
                    newState := and(shr(112, maskedRule), 0xFF)
                }
                if and(
                    eq(shr(248, stateOfField), 0xff),
                    eq(shr(32, and(sour, 0x000000000000000000000000000000000000000000000000000000ff00000000)), 0x00)
                ) {
                    colorField := shl(144, maskedRule)
                    newDirection := and(shr(96, maskedRule), 0xFF)
                    newState := and(shr(88, maskedRule), 0xFF)
                }
                if and(
                    eq(shr(248, stateOfField), 0x00),
                    eq(shr(32, and(sour, 0x000000000000000000000000000000000000000000000000000000ff00000000)), 0x01)
                ) {
                    colorField := shl(168, maskedRule)
                    newDirection := and(shr(72, maskedRule), 0xFF)
                    newState := and(shr(64, maskedRule), 0xFF)
                }
                if and(
                    eq(shr(248, stateOfField), 0xff),
                    eq(shr(32, and(sour, 0x000000000000000000000000000000000000000000000000000000ff00000000)), 0x01)
                ) {
                    colorField := shl(192, maskedRule)
                    newDirection := and(shr(48, maskedRule), 0xFF)
                    newState := and(shr(40, maskedRule), 0xFF)
                }

                let newOrientation
                switch newDirection
                case 0x02 {
                    newOrientation := addmod(_orientation, 1, 4)
                }
                case 0x08 {
                    switch _orientation
                    case 0 {
                        newOrientation := 3
                    }
                    default {
                        newOrientation := mod(sub(_orientation, 1), 4)
                    }
                }
                case 0x04 {
                    newOrientation := mod(add(_orientation, 2), 4)
                }
                default {
                    newOrientation := _orientation
                }

                let buffer := mload(0x40)

                switch newOrientation
                case 0x00 {
                    mstore8(add(buffer, 31), addmod(_x, 1, 144))
                    mstore8(add(buffer, 30), _y)
                }
                case 0x02 {
                    switch _x
                    case 0 {
                        mstore8(add(buffer, 31), 143)
                        mstore8(add(buffer, 30), _y)
                    }
                    default {
                        mstore8(add(buffer, 31), sub(_x, 1))
                        mstore8(add(buffer, 30), _y)
                    }
                }
                case 0x03 {
                    mstore8(add(buffer, 31), _x)
                    mstore8(add(buffer, 30), addmod(_y, 1, 144))
                }
                case 0x01 {
                    switch _y
                    case 0 {
                        mstore8(add(buffer, 31), _x)
                        mstore8(add(buffer, 30), 143)
                    }
                    default {
                        mstore8(add(buffer, 31), _x)
                        mstore8(add(buffer, 30), sub(_y, 1))
                    }
                }

                //  128   120  112  104   96   88   80   72   64   56   48  40
                // 0xff    08   01   ff   02   01   ff   00   00   00   44  21

                mstore8(add(buffer, 29), newOrientation)
                mstore8(add(buffer, 28), _boardNumber)
                mstore8(add(buffer, 27), newState)
                sour := or(mload(buffer), maskedRule)
            }

            // note that we pass here the "old" x & y
            setByte(_x, _y, colorField, _boardNumber);
            unchecked {
                z += 1;
            }
        }
        assembly {
            sstore(data.slot, sour)
        }
        emit TurmiteMove(id, _boardNumber, moves);
    }
}

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

/// @notice Library for converting numbers into strings and other string operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
library LibString {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The `length` of the output is too small to contain all the hex digits.
    error HexLengthInsufficient();

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

    /// @dev The constant returned when the `search` is not found in the string.
    uint256 internal constant NOT_FOUND = type(uint256).max;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     DECIMAL OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(uint256 value) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
            // We will need 1 word for the trailing zeros padding, 1 word for the length,
            // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
            let m := add(mload(0x40), 0xa0)
            // Update the free memory pointer to allocate.
            mstore(0x40, m)
            // Assign the `str` to the end.
            str := sub(m, 0x20)
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end of the memory to calculate the length later.
            let end := str

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for { let temp := value } 1 {} {
                str := sub(str, 1)
                // Write the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(str, add(48, mod(temp, 10)))
                // Keep dividing `temp` until zero.
                temp := div(temp, 10)
                // prettier-ignore
                if iszero(temp) { break }
            }

            let length := sub(end, str)
            // Move the pointer 32 bytes leftwards to make room for the length.
            str := sub(str, 0x20)
            // Store the length.
            mstore(str, length)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   HEXADECIMAL OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `length` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2 + 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value, length);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `length` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            let start := mload(0x40)
            // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes
            // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
            // We add 0x20 to the total and round down to a multiple of 0x20.
            // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
            let m := add(start, and(add(shl(1, length), 0x62), not(0x1f)))
            // Allocate the memory.
            mstore(0x40, m)
            // Assign the `str` to the end.
            str := sub(m, 0x20)
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let temp := value
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for {} 1 {} {
                str := sub(str, 2)
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                length := sub(length, 1)
                // prettier-ignore
                if iszero(length) { break }
            }

            if temp {
                // Store the function selector of `HexLengthInsufficient()`.
                mstore(0x00, 0x2194895a)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Compute the string's length.
            let strLength := sub(end, str)
            // Move the pointer and write the length.
            str := sub(str, 0x20)
            mstore(str, strLength)
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
    /// As address are 20 bytes long, the output will left-padded to have
    /// a length of `20 * 2 + 2` bytes.
    function toHexString(uint256 value) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is encoded using 2 hexadecimal digits per byte.
    /// As address are 20 bytes long, the output will left-padded to have
    /// a length of `20 * 2` bytes.
    function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            let start := mload(0x40)
            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
            // 0x02 bytes for the prefix, and 0x40 bytes for the digits.
            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
            let m := add(start, 0xa0)
            // Allocate the memory.
            mstore(0x40, m)
            // Assign the `str` to the end.
            str := sub(m, 0x20)
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for { let temp := value } 1 {} {
                str := sub(str, 2)
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                // prettier-ignore
                if iszero(temp) { break }
            }

            // Compute the string's length.
            let strLength := sub(end, str)
            // Move the pointer and write the length.
            str := sub(str, 0x20)
            mstore(str, strLength)
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
    /// and the alphabets are capitalized conditionally according to
    /// https://eips.ethereum.org/EIPS/eip-55
    function toHexStringChecksumed(address value) internal pure returns (string memory str) {
        str = toHexString(value);
        /// @solidity memory-safe-assembly
        assembly {
            let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
            let o := add(str, 0x22)
            let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
            let t := shl(240, 136) // `0b10001000 << 240`
            // prettier-ignore
            for { let i := 0 } 1 {} {
                mstore(add(i, i), mul(t, byte(i, hashed)))
                i := add(i, 1)
                // prettier-ignore
                if eq(i, 20) { break }
            }
            mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
            o := add(o, 0x20)
            mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
    function toHexString(address value) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is encoded using 2 hexadecimal digits per byte.
    function toHexStringNoPrefix(address value) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            str := mload(0x40)

            // Allocate the memory.
            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
            // 0x02 bytes for the prefix, and 0x28 bytes for the digits.
            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
            mstore(0x40, add(str, 0x80))

            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            str := add(str, 2)
            mstore(str, 40)

            let o := add(str, 0x20)
            mstore(add(o, 40), 0)

            value := shl(96, value)

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for { let i := 0 } 1 {} {
                let p := add(o, add(i, i))
                let temp := byte(i, value)
                mstore8(add(p, 1), mload(and(temp, 15)))
                mstore8(p, mload(shr(4, temp)))
                i := add(i, 1)
                // prettier-ignore
                if eq(i, 20) { break }
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   RUNE STRING OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the number of UTF characters in the string.
    function runeCount(string memory s) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            if mload(s) {
                mstore(0x00, div(not(0), 255))
                mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
                let o := add(s, 0x20)
                let end := add(o, mload(s))
                // prettier-ignore
                for { result := 1 } 1 { result := add(result, 1) } {
                    o := add(o, byte(0, mload(shr(250, mload(o)))))
                    // prettier-ignore
                    if iszero(lt(o, end)) { break }
                }
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   BYTE STRING OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // For performance and bytecode compactness, all indices of the following operations
    // are byte (ASCII) offsets, not UTF character offsets.

    /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.
    function replace(
        string memory subject,
        string memory search,
        string memory replacement
    ) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)
            let replacementLength := mload(replacement)

            subject := add(subject, 0x20)
            search := add(search, 0x20)
            replacement := add(replacement, 0x20)
            result := add(mload(0x40), 0x20)

            let subjectEnd := add(subject, subjectLength)
            if iszero(gt(searchLength, subjectLength)) {
                let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 32)) {
                    h := keccak256(search, searchLength)
                }
                let m := shl(3, sub(32, and(searchLength, 31)))
                let s := mload(search)
                // prettier-ignore
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of 
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                mstore(result, t)
                                result := add(result, 1)
                                subject := add(subject, 1)
                                // prettier-ignore
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Copy the `replacement` one word at a time.
                        // prettier-ignore
                        for { let o := 0 } 1 {} {
                            mstore(add(result, o), mload(add(replacement, o)))
                            o := add(o, 0x20)
                            // prettier-ignore
                            if iszero(lt(o, replacementLength)) { break }
                        }
                        result := add(result, replacementLength)
                        subject := add(subject, searchLength)
                        if searchLength {
                            // prettier-ignore
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    mstore(result, t)
                    result := add(result, 1)
                    subject := add(subject, 1)
                    // prettier-ignore
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
            }

            let resultRemainder := result
            result := add(mload(0x40), 0x20)
            let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))
            // Copy the rest of the string one word at a time.
            // prettier-ignore
            for {} lt(subject, subjectEnd) {} {
                mstore(resultRemainder, mload(subject))
                resultRemainder := add(resultRemainder, 0x20)
                subject := add(subject, 0x20)
            }
            result := sub(result, 0x20)
            // Zeroize the slot after the string.
            let last := add(add(result, 0x20), k)
            mstore(last, 0)
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 31), not(31)))
            // Store the length of the result.
            mstore(result, k)
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from left to right, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(
        string memory subject,
        string memory search,
        uint256 from
    ) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // prettier-ignore
            for { let subjectLength := mload(subject) } 1 {} {
                if iszero(mload(search)) {
                    // `result = min(from, subjectLength)`.
                    result := xor(from, mul(xor(from, subjectLength), lt(subjectLength, from)))
                    break
                }
                let searchLength := mload(search)
                let subjectStart := add(subject, 0x20)    
                
                result := not(0) // Initialize to `NOT_FOUND`.

                subject := add(subjectStart, from)
                let subjectSearchEnd := add(sub(add(subjectStart, subjectLength), searchLength), 1)

                let m := shl(3, sub(32, and(searchLength, 31)))
                let s := mload(add(search, 0x20))

                // prettier-ignore
                if iszero(lt(subject, subjectSearchEnd)) { break }

                if iszero(lt(searchLength, 32)) {
                    // prettier-ignore
                    for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
                        if iszero(shr(m, xor(mload(subject), s))) {
                            if eq(keccak256(subject, searchLength), h) {
                                result := sub(subject, subjectStart)
                                break
                            }
                        }
                        subject := add(subject, 1)
                        // prettier-ignore
                        if iszero(lt(subject, subjectSearchEnd)) { break }
                    }
                    break
                }
                // prettier-ignore
                for {} 1 {} {
                    if iszero(shr(m, xor(mload(subject), s))) {
                        result := sub(subject, subjectStart)
                        break
                    }
                    subject := add(subject, 1)
                    // prettier-ignore
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from left to right.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) {
        result = indexOf(subject, search, 0);
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from right to left, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(
        string memory subject,
        string memory search,
        uint256 from
    ) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // prettier-ignore
            for {} 1 {} {
                let searchLength := mload(search)
                let fromMax := sub(mload(subject), searchLength)
                if iszero(gt(fromMax, from)) {
                    from := fromMax
                }
                if iszero(mload(search)) {
                    result := from
                    break
                }
                result := not(0) // Initialize to `NOT_FOUND`.

                let subjectSearchEnd := sub(add(subject, 0x20), 1)

                subject := add(add(subject, 0x20), from)
                // prettier-ignore
                if iszero(gt(subject, subjectSearchEnd)) { break }
                // As this function is not too often used,
                // we shall simply use keccak256 for smaller bytecode size.
                // prettier-ignore
                for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
                    if eq(keccak256(subject, searchLength), h) {
                        result := sub(subject, add(subjectSearchEnd, 1))
                        break
                    }
                    subject := sub(subject, 1)
                    // prettier-ignore
                    if iszero(gt(subject, subjectSearchEnd)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from right to left.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) {
        result = lastIndexOf(subject, search, uint256(int256(-1)));
    }

    /// @dev Returns whether `subject` starts with `search`.
    function startsWith(string memory subject, string memory search) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLength := mload(search)
            // Just using keccak256 directly is actually cheaper.
            result := and(
                iszero(gt(searchLength, mload(subject))),
                eq(keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength))
            )
        }
    }

    /// @dev Returns whether `subject` ends with `search`.
    function endsWith(string memory subject, string memory search) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLength := mload(search)
            let subjectLength := mload(subject)
            // Whether `search` is not longer than `subject`.
            let withinRange := iszero(gt(searchLength, subjectLength))
            // Just using keccak256 directly is actually cheaper.
            result := and(
                withinRange,
                eq(
                    keccak256(
                        // `subject + 0x20 + max(subjectLength - searchLength, 0)`.
                        add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),
                        searchLength
                    ),
                    keccak256(add(search, 0x20), searchLength)
                )
            )
        }
    }

    /// @dev Returns `subject` repeated `times`.
    function repeat(string memory subject, uint256 times) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            if iszero(or(iszero(times), iszero(subjectLength))) {
                subject := add(subject, 0x20)
                result := mload(0x40)
                let output := add(result, 0x20)
                // prettier-ignore
                for {} 1 {} {
                    // Copy the `subject` one word at a time.
                    // prettier-ignore
                    for { let o := 0 } 1 {} {
                        mstore(add(output, o), mload(add(subject, o)))
                        o := add(o, 0x20)
                        // prettier-ignore
                        if iszero(lt(o, subjectLength)) { break }
                    }
                    output := add(output, subjectLength)
                    times := sub(times, 1)
                    // prettier-ignore
                    if iszero(times) { break }
                }
                // Zeroize the slot after the string.
                mstore(output, 0)
                // Store the length.
                let resultLength := sub(output, add(result, 0x20))
                mstore(result, resultLength)
                // Allocate memory for the length and the bytes,
                // rounded up to a multiple of 32.
                mstore(0x40, add(result, and(add(resultLength, 63), not(31))))
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function slice(
        string memory subject,
        uint256 start,
        uint256 end
    ) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            if iszero(gt(subjectLength, end)) {
                end := subjectLength
            }
            if iszero(gt(subjectLength, start)) {
                start := subjectLength
            }
            if lt(start, end) {
                result := mload(0x40)
                let resultLength := sub(end, start)
                mstore(result, resultLength)
                subject := add(subject, start)
                let w := not(31)
                // Copy the `subject` one word at a time, backwards.
                // prettier-ignore
                for { let o := and(add(resultLength, 31), w) } 1 {} {
                    mstore(add(result, o), mload(add(subject, o)))
                    o := add(o, w) // `sub(o, 0x20)`.
                    // prettier-ignore
                    if iszero(o) { break }
                }
                // Zeroize the slot after the string.
                mstore(add(add(result, 0x20), resultLength), 0)
                // Allocate memory for the length and the bytes,
                // rounded up to a multiple of 32.
                mstore(0x40, add(result, and(add(resultLength, 63), w)))
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
    /// `start` is a byte offset.
    function slice(string memory subject, uint256 start) internal pure returns (string memory result) {
        result = slice(subject, start, uint256(int256(-1)));
    }

    /// @dev Returns all the indices of `search` in `subject`.
    /// The indices are byte offsets.
    function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)

            if iszero(gt(searchLength, subjectLength)) {
                subject := add(subject, 0x20)
                search := add(search, 0x20)
                result := add(mload(0x40), 0x20)

                let subjectStart := subject
                let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 32)) {
                    h := keccak256(search, searchLength)
                }
                let m := shl(3, sub(32, and(searchLength, 31)))
                let s := mload(search)
                // prettier-ignore
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of 
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                subject := add(subject, 1)
                                // prettier-ignore
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Append to `result`.
                        mstore(result, sub(subject, subjectStart))
                        result := add(result, 0x20)
                        // Advance `subject` by `searchLength`.
                        subject := add(subject, searchLength)
                        if searchLength {
                            // prettier-ignore
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    subject := add(subject, 1)
                    // prettier-ignore
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
                let resultEnd := result
                // Assign `result` to the free memory pointer.
                result := mload(0x40)
                // Store the length of `result`.
                mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
                // Allocate memory for result.
                // We allocate one more word, so this array can be recycled for {split}.
                mstore(0x40, add(resultEnd, 0x20))
            }
        }
    }

    /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
    function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) {
        uint256[] memory indices = indicesOf(subject, delimiter);
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(31)
            let indexPtr := add(indices, 0x20)
            let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
            mstore(add(indicesEnd, w), mload(subject))
            mstore(indices, add(mload(indices), 1))
            let prevIndex := 0
            // prettier-ignore
            for {} 1 {} {
                let index := mload(indexPtr)
                mstore(indexPtr, 0x60)                        
                if iszero(eq(index, prevIndex)) {
                    let element := mload(0x40)
                    let elementLength := sub(index, prevIndex)
                    mstore(element, elementLength)
                    // Copy the `subject` one word at a time, backwards.
                    // prettier-ignore
                    for { let o := and(add(elementLength, 31), w) } 1 {} {
                        mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
                        o := add(o, w) // `sub(o, 0x20)`.
                        // prettier-ignore
                        if iszero(o) { break }
                    }
                    // Zeroize the slot after the string.
                    mstore(add(add(element, 0x20), elementLength), 0)
                    // Allocate memory for the length and the bytes,
                    // rounded up to a multiple of 32.
                    mstore(0x40, add(element, and(add(elementLength, 63), w)))
                    // Store the `element` into the array.
                    mstore(indexPtr, element)                        
                }
                prevIndex := add(index, mload(delimiter))
                indexPtr := add(indexPtr, 0x20)
                // prettier-ignore
                if iszero(lt(indexPtr, indicesEnd)) { break }
            }
            result := indices
            if iszero(mload(delimiter)) {
                result := add(indices, 0x20)
                mstore(result, sub(mload(indices), 2))
            }
        }
    }

    /// @dev Returns a concatenated string of `a` and `b`.
    /// Cheaper than `string.concat()` and does not de-align the free memory pointer.
    function concat(string memory a, string memory b) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(31)
            result := mload(0x40)
            let aLength := mload(a)
            // Copy `a` one word at a time, backwards.
            // prettier-ignore
            for { let o := and(add(mload(a), 32), w) } 1 {} {
                mstore(add(result, o), mload(add(a, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                // prettier-ignore
                if iszero(o) { break }
            }
            let bLength := mload(b)
            let output := add(result, mload(a))
            // Copy `b` one word at a time, backwards.
            // prettier-ignore
            for { let o := and(add(bLength, 32), w) } 1 {} {
                mstore(add(output, o), mload(add(b, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                // prettier-ignore
                if iszero(o) { break }
            }
            let totalLength := add(aLength, bLength)
            let last := add(add(result, 0x20), totalLength)
            // Zeroize the slot after the string.
            mstore(last, 0)
            // Stores the length.
            mstore(result, totalLength)
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 31), w))
        }
    }

    /// @dev Returns a copy of the string in either lowercase or UPPERCASE.
    function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let length := mload(subject)
            if length {
                result := add(mload(0x40), 0x20)
                subject := add(subject, 1)
                let flags := shl(add(70, shl(5, toUpper)), 67108863)
                let w := not(0)
                // prettier-ignore
                for { let o := length } 1 {} {
                    o := add(o, w)
                    let b := and(0xff, mload(add(subject, o)))
                    mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
                    // prettier-ignore
                    if iszero(o) { break }
                }
                // Restore the result.
                result := mload(0x40)
                // Stores the string length.
                mstore(result, length)
                // Zeroize the slot after the string.
                let last := add(add(result, 0x20), length)
                mstore(last, 0)
                // Allocate memory for the length and the bytes,
                // rounded up to a multiple of 32.
                mstore(0x40, and(add(last, 31), not(31)))
            }
        }
    }

    /// @dev Returns a lowercased copy of the string.
    function lower(string memory subject) internal pure returns (string memory result) {
        result = toCase(subject, false);
    }

    /// @dev Returns an UPPERCASED copy of the string.
    function upper(string memory subject) internal pure returns (string memory result) {
        result = toCase(subject, true);
    }

    /// @dev Escapes the string to be used within HTML tags.
    function escapeHTML(string memory s) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            // prettier-ignore
            for {
                let end := add(s, mload(s))
                result := add(mload(0x40), 0x20)
                // Store the bytes of the packed offsets and strides into the scratch space.
                // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
                mstore(0x1f, 0x900094)
                mstore(0x08, 0xc0000000a6ab)
                // Store "&quot;&amp;&#39;&lt;&gt;" into the scratch space.
                mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
            } iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                // Not in `["\"","'","&","<",">"]`.
                if iszero(and(shl(c, 1), 0x500000c400000000)) { 
                    mstore8(result, c)
                    result := add(result, 1)
                    continue    
                }
                let t := shr(248, mload(c))
                mstore(result, mload(and(t, 31)))
                result := add(result, shr(5, t))
            }
            let last := result
            // Zeroize the slot after the string.
            mstore(last, 0)
            // Restore the result to the start of the free memory.
            result := mload(0x40)
            // Store the length of the result.
            mstore(result, sub(last, add(result, 0x20)))
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 31), not(31)))
        }
    }

    /// @dev Escapes the string to be used within double-quotes in a JSON.
    function escapeJSON(string memory s) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            // prettier-ignore
            for {
                let end := add(s, mload(s))
                result := add(mload(0x40), 0x20)
                // Store "\\u0000" in scratch space.
                // Store "0123456789abcdef" in scratch space.
                // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
                // into the scratch space.
                mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
                // Bitmask for detecting `["\"","\\"]`.
                let e := or(shl(0x22, 1), shl(0x5c, 1))
            } iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                if iszero(lt(c, 0x20)) {
                    if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`.
                        mstore8(result, c)
                        result := add(result, 1)
                        continue    
                    }
                    mstore8(result, 0x5c) // "\\".
                    mstore8(add(result, 1), c) 
                    result := add(result, 2)
                    continue
                }
                if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`.
                    mstore8(0x1d, mload(shr(4, c))) // Hex value.
                    mstore8(0x1e, mload(and(c, 15))) // Hex value.
                    mstore(result, mload(0x19)) // "\\u00XX".
                    result := add(result, 6)    
                    continue
                }
                mstore8(result, 0x5c) // "\\".
                mstore8(add(result, 1), mload(add(c, 8)))
                result := add(result, 2)
            }
            let last := result
            // Zeroize the slot after the string.
            mstore(last, 0)
            // Restore the result to the start of the free memory.
            result := mload(0x40)
            // Store the length of the result.
            mstore(result, sub(last, add(result, 0x20)))
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 31), not(31)))
        }
    }

    /// @dev Returns whether `a` equals `b`.
    function eq(string memory a, string memory b) internal pure returns (bool result) {
        assembly {
            result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
        }
    }

    /// @dev Packs a single string with its length into a single word.
    /// Returns `bytes32(0)` if the length is zero or greater than 31.
    function packOne(string memory a) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // We don't need to zero right pad the string,
            // since this is our own custom non-standard packing scheme.
            result := mul(
                // Load the length and the bytes.
                mload(add(a, 0x1f)),
                // `length != 0 && length < 32`. Abuses underflow.
                // Assumes that the length is valid and within the block gas limit.
                lt(sub(mload(a), 1), 0x1f)
            )
        }
    }

    /// @dev Unpacks a string packed using {packOne}.
    /// Returns the empty string if `packed` is `bytes32(0)`.
    /// If `packed` is not an output of {packOne}, the output behaviour is undefined.
    function unpackOne(bytes32 packed) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the free memory pointer.
            result := mload(0x40)
            // Allocate 2 words (1 for the length, 1 for the bytes).
            mstore(0x40, add(result, 0x40))
            // Zeroize the length slot.
            mstore(result, 0)
            // Store the length and bytes.
            mstore(add(result, 0x1f), packed)
            // Right pad with zeroes.
            mstore(add(add(result, 0x20), mload(result)), 0)
        }
    }

    /// @dev Packs two strings with their lengths into a single word.
    /// Returns `bytes32(0)` if combined length is zero or greater than 30.
    function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let aLength := mload(a)
            // We don't need to zero right pad the strings,
            // since this is our own custom non-standard packing scheme.
            result := mul(
                // Load the length and the bytes of `a` and `b`.
                or(shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength))),
                // `totalLength != 0 && totalLength < 31`. Abuses underflow.
                // Assumes that the lengths are valid and within the block gas limit.
                lt(sub(add(aLength, mload(b)), 1), 0x1e)
            )
        }
    }

    /// @dev Unpacks strings packed using {packTwo}.
    /// Returns the empty strings if `packed` is `bytes32(0)`.
    /// If `packed` is not an output of {packTwo}, the output behaviour is undefined.
    function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the free memory pointer.
            resultA := mload(0x40)
            resultB := add(resultA, 0x40)
            // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
            mstore(0x40, add(resultB, 0x40))
            // Zeroize the length slots.
            mstore(resultA, 0)
            mstore(resultB, 0)
            // Store the lengths and bytes.
            mstore(add(resultA, 0x1f), packed)
            mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
            // Right pad with zeroes.
            mstore(add(add(resultA, 0x20), mload(resultA)), 0)
            mstore(add(add(resultB, 0x20), mload(resultB)), 0)
        }
    }

    /// @dev Directly returns `a` without copying.
    function directReturn(string memory a) internal pure {
        assembly {
            // Assumes that the string does not start from the scratch space.
            let retStart := sub(a, 0x20)
            let retSize := add(mload(a), 0x40)
            // Right pad with zeroes. Just in case the string is produced
            // by a method that doesn't zero right pad.
            mstore(add(retStart, retSize), 0)
            // Store the return offset.
            mstore(retStart, 0x20)
            // End the transaction, returning the string.
            return(retStart, retSize)
        }
    }
}

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "solidity-bytes-utils/contracts/BytesLib.sol";
import "base64-sol/base64.sol";

/// @title Gameboard for inchain turmites
/// @notice Implementation of an Gameboard for Straylight Protocoll.
/// @notice we are all standing on the shoulders of giants - this board is inspired by how CryptoGhost is drawing boards
/// @author @brachlandberlin / plsdlr.net
/// @dev bytesLib & base64 are required for formating

contract Gameboard {
    using BytesLib for bytes;
    mapping(uint256 => gameboard) gameboards;

    struct gameboard {
        bytes1[144][144] board;
    }

    /// @dev an explicit function to get a byte with x,y,board
    /// @param x the x position on the board
    /// @param y the y position on the board
    /// @param boardNumber the boardNumber number
    function getByte(
        uint256 x,
        uint256 y,
        uint256 boardNumber
    ) public view returns (bytes1) {
        return gameboards[boardNumber].board[x][y];
    }

    /// @dev an explicit function to set a byte with x,y,value,board
    /// @param x the x position on the board
    /// @param y the y position on the board
    /// @param value the byte1 value to set
    /// @param boardNumber the board number
    function setByte(
        uint256 x,
        uint256 y,
        bytes1 value,
        uint256 boardNumber
    ) internal {
        gameboards[boardNumber].board[x][y] = value;
    }

    /// @dev function to generate the Bitmap Base64 encoded with boardNumber, position x, position y and boolean if turmite should be rendered
    /// @param boardNumber the board number
    /// @param posx the x position of the turmite on the board
    /// @param posy the y position on the turmite on the board
    /// @param renderTurmite boolean to render turmite
    function getBitmapBase64(
        uint8 boardNumber,
        uint8 posx,
        uint8 posy,
        bool renderTurmite
    ) public view returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "data:image/bmp;base64,",
                    Base64.encode(getBitmap(boardNumber, posx, posy, renderTurmite))
                )
            );
    }

    /// @dev function to generate a SVG String with boardNumber, position x, position y and boolean if turmite should be rendered
    /// @dev same parameters as getBitmapBase64
    function getSvg(
        uint8 boardNumber,
        uint8 posx,
        uint8 posy,
        bool renderTurmite
    ) public view returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "data:image/svg+xml;base64,",
                    Base64.encode(
                        abi.encodePacked(
                            '<svg class="svgBGG" xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500"><defs id="someDefs"><style id="style1999"> .svgBGG { width: 500px;height: 500px;background-image: url(',
                            getBitmapBase64(boardNumber, posx, posy, renderTurmite),
                            "); background-repeat: no-repeat; background-size: 100%; image-rendering: -webkit-optimize-contrast; -ms-interpolation-mode: nearest-neighbor; image-rendering: -moz-crisp-edges; image-rendering: pixelated;}</style></defs></svg>"
                        )
                    )
                )
            );
    }

    /// @dev function to generate byte representation of the Board, position x, position y and boolean if turmite should be rendered
    /// @dev BMP Header is generated externaly
    /// @dev same parameters as getBitmapBase64
    function getBitmap(
        uint8 boardNumber,
        uint8 posx,
        uint8 posy,
        bool renderTurmite
    ) public view returns (bytes memory) {
        bytes
            memory headers = hex"424D385500000000000036040000280000009000000090000000010008000000000002510000120B0000120B00000000000000000000000000000101010002020200030303000404040005050500060606000707070008080800090909000A0A0A000B0B0B000C0C0C000D0D0D000E0E0E000F0F0F00101010001111110012121200131313001414140015151500161616001717170018181800191919001A1A1A001B1B1B001C1C1C001D1D1D001E1E1E001F1F1F00202020002121210022222200232323002424240025252500262626002727270028282800292929002A2A2A002B2B2B002C2C2C002D2D2D002E2E2E002F2F2F00303030003131310032323200333333003434340035353500363636003737370038383800393939003A3A3A003B3B3B003C3C3C003D3D3D003E3E3E003F3F3F00404040004141410042424200434343004444440045454500464646004747470048484800494949004A4A4A004B4B4B004C4C4C004D4D4D004E4E4E004F4F4F00505050005151510052525200535353005454540055555500565656005757570058585800595959005A5A5A005B5B5B005C5C5C005D5D5D005E5E5E005F5F5F00606060006161610062626200636363006464640065656500666666006767670068686800696969006A6A6A006B6B6B006C6C6C006D6D6D006E6E6E006F6F6F00707070007171710072727200737373007474740075757500767676007777770078787800797979007A7A7A007B7B7B007C7C7C007D7D7D007E7E7E007F7F7F00808080008181810082828200838383008484840085858500868686008787870088888800898989008A8A8A008B8B8B008C8C8C008D8D8D008E8E8E008F8F8F00909090009191910092929200939393009494940095959500969696009797970098989800999999009A9A9A009B9B9B009C9C9C009D9D9D009E9E9E009F9F9F00A0A0A000A1A1A100A2A2A200A3A3A300A4A4A400A5A5A500A6A6A600A7A7A700A8A8A800A9A9A900AAAAAA00ABABAB00ACACAC00ADADAD00AEAEAE00AFAFAF00B0B0B000B1B1B100B2B2B200B3B3B300B4B4B400B5B5B500B6B6B600B7B7B700B8B8B800B9B9B900BABABA00BBBBBB00BCBCBC00BDBDBD00BEBEBE00BFBFBF00C0C0C000C1C1C100C2C2C200C3C3C300C4C4C400C5C5C500C6C6C600C7C7C700C8C8C800C9C9C900CACACA00CBCBCB00CCCCCC00CDCDCD00CECECE00CFCFCF00D0D0D000D1D1D100D2D2D200D3D3D300D4D4D400D5D5D500D6D6D600D7D7D700D8D8D800D9D9D900DADADA00DBDBDB00DCDCDC00DDDDDD00DEDEDE00DFDFDF00E0E0E000E1E1E100E2E2E200E3E3E300E4E4E400E5E5E500E6E6E600E7E7E700E8E8E800E9E9E900EAEAEA00EBEBEB00ECECEC00EDEDED00EEEEEE00EFEFEF00F0F0F000F1F1F100F2F2F200F3F3F300F4F4F400F5F5F500F6F6F600F7F7F700F8F8F800F9F9F900FAFAFA00FBFBFB00FCFCFC00FDFDFD00FEFEFE00FFFFFF00";
        bytes memory returngameboard = new bytes(20736);
        for (uint256 xFill = 0; xFill < 144; ++xFill) {
            for (uint256 yFill = 0; yFill < 144; ++yFill) {
                uint256 index = xFill + 144 * yFill;
                returngameboard[index] = gameboards[boardNumber].board[xFill][yFill];
            }
        }
        if (renderTurmite == true) {
            uint256 index2 = uint256(posx) + 144 * uint256(posy);
            returngameboard[index2] = bytes1(uint8(165));
        }
        return headers.concat(returngameboard);
    }
}

// SPDX-License-Identifier: Unlicense
/*
 * @title Solidity Bytes Arrays Utils
 * @author Gonçalo Sá <[email protected]>
 *
 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
 *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
 */
pragma solidity >=0.8.0 <0.9.0;


library BytesLib {
    function concat(
        bytes memory _preBytes,
        bytes memory _postBytes
    )
        internal
        pure
        returns (bytes memory)
    {
        bytes memory tempBytes;

        assembly {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
            tempBytes := mload(0x40)

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(0x40, and(
              add(add(end, iszero(add(length, mload(_preBytes)))), 31),
              not(31) // Round down to the nearest 32 bytes.
            ))
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
            // Read the first 32 bytes of _preBytes storage, which is the length
            // of the array. (We don't need to use the offset into the slot
            // because arrays use the entire slot.)
            let fslot := sload(_preBytes.slot)
            // Arrays of 31 bytes or less have an even value in their slot,
            // while longer arrays have an odd value. The actual length is
            // the slot divided by two for odd values, and the lowest order
            // byte divided by two for even values.
            // If the slot is even, bitwise and the slot with 255 and divide by
            // two to get the length. If the slot is odd, bitwise and the slot
            // with -1 and divide by two.
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
            // slength can contain both the length and contents of the array
            // if length < 32 bytes so let's prepare for that
            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
                // Since the new array still fits in the slot, we just need to
                // update the contents of the slot.
                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                sstore(
                    _preBytes.slot,
                    // all the modifications to the slot are inside this
                    // next block
                    add(
                        // we can just add to the slot contents because the
                        // bytes we want to change are the LSBs
                        fslot,
                        add(
                            mul(
                                div(
                                    // load the bytes from memory
                                    mload(add(_postBytes, 0x20)),
                                    // zero all bytes to the right
                                    exp(0x100, sub(32, mlength))
                                ),
                                // and now shift left the number of bytes to
                                // leave space for the length in the slot
                                exp(0x100, sub(32, newlength))
                            ),
                            // increase length by the double of the memory
                            // bytes length
                            mul(mlength, 2)
                        )
                    )
                )
            }
            case 1 {
                // The stored value fits in the slot, but the combined value
                // will exceed it.
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // The contents of the _postBytes array start 32 bytes into
                // the structure. Our first read should obtain the `submod`
                // bytes that can fit into the unused space in the last word
                // of the stored array. To get this, we read 32 bytes starting
                // from `submod`, so the data we read overlaps with the array
                // contents by `submod` bytes. Masking the lowest-order
                // `submod` bytes allows us to add that value directly to the
                // stored value.

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                    sc,
                    add(
                        and(
                            fslot,
                            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                        ),
                        and(mload(mc), mask)
                    )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                // Start copying to the last used word of the stored array.
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // Copy over the first `submod` bytes of the new data as in
                // case 1 above.
                let slengthmod := mod(slength, 32)
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))

                for {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

    function slice(
        bytes memory _bytes,
        uint256 _start,
        uint256 _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_length + 31 >= _length, "slice_overflow");
        require(_bytes.length >= _start + _length, "slice_outOfBounds");

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
                //zero out the 32 bytes slice we are about to return
                //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
        require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
        require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
        require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
        require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
            case 1 {
                // cb is a circuit breaker in the for loop since there's
                //  no said feature for inline assembly loops
                // cb = 1 - don't breaker
                // cb = 0 - break
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for {
                    let cc := add(_postBytes, 0x20)
                // the next line is the loop condition:
                // while(uint256(mc < end) + cb == 2)
                } eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                        // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }

    function equalStorage(
        bytes storage _preBytes,
        bytes memory _postBytes
    )
        internal
        view
        returns (bool)
    {
        bool success = true;

        assembly {
            // we know _preBytes_offset is 0
            let fslot := sload(_preBytes.slot)
            // Decode the length of the stored array like in concatStorage().
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

            // if lengths don't match the arrays are not equal
            switch eq(slength, mlength)
            case 1 {
                // slength can contain both the length and contents of the array
                // if length < 32 bytes so let's prepare for that
                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                        // blank the last byte which is the length
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                            // unsuccess:
                            success := 0
                        }
                    }
                    default {
                        // cb is a circuit breaker in the for loop since there's
                        //  no said feature for inline assembly loops
                        // cb = 1 - don't breaker
                        // cb = 0 - break
                        let cb := 1

                        // get the keccak hash to get the contents of the array
                        mstore(0x0, _preBytes.slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                        // the next line is the loop condition:
                        // while(uint256(mc < end) + cb == 2)
                        for {} eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0;

/// @title Base64
/// @author Brecht Devos - <[email protected]>
/// @notice Provides functions for encoding/decoding base64
library Base64 {
    string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    bytes  internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000"
                                            hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"
                                            hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"
                                            hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";

    function encode(bytes memory data) internal pure returns (string memory) {
        if (data.length == 0) return '';

        // load the table into memory
        string memory table = TABLE_ENCODE;

        // multiply by 4/3 rounded up
        uint256 encodedLen = 4 * ((data.length + 2) / 3);

        // add some extra buffer at the end required for the writing
        string memory result = new string(encodedLen + 32);

        assembly {
            // set the actual output length
            mstore(result, encodedLen)

            // prepare the lookup table
            let tablePtr := add(table, 1)

            // input ptr
            let dataPtr := data
            let endPtr := add(dataPtr, mload(data))

            // result ptr, jump over length
            let resultPtr := add(result, 32)

            // run over the input, 3 bytes at a time
            for {} lt(dataPtr, endPtr) {}
            {
                // read 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // write 4 characters
                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(        input,  0x3F))))
                resultPtr := add(resultPtr, 1)
            }

            // padding with '='
            switch mod(mload(data), 3)
            case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
            case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
        }

        return result;
    }

    function decode(string memory _data) internal pure returns (bytes memory) {
        bytes memory data = bytes(_data);

        if (data.length == 0) return new bytes(0);
        require(data.length % 4 == 0, "invalid base64 decoder input");

        // load the table into memory
        bytes memory table = TABLE_DECODE;

        // every 4 characters represent 3 bytes
        uint256 decodedLen = (data.length / 4) * 3;

        // add some extra buffer at the end required for the writing
        bytes memory result = new bytes(decodedLen + 32);

        assembly {
            // padding with '='
            let lastBytes := mload(add(data, mload(data)))
            if eq(and(lastBytes, 0xFF), 0x3d) {
                decodedLen := sub(decodedLen, 1)
                if eq(and(lastBytes, 0xFFFF), 0x3d3d) {
                    decodedLen := sub(decodedLen, 1)
                }
            }

            // set the actual output length
            mstore(result, decodedLen)

            // prepare the lookup table
            let tablePtr := add(table, 1)

            // input ptr
            let dataPtr := data
            let endPtr := add(dataPtr, mload(data))

            // result ptr, jump over length
            let resultPtr := add(result, 32)

            // run over the input, 4 characters at a time
            for {} lt(dataPtr, endPtr) {}
            {
               // read 4 characters
               dataPtr := add(dataPtr, 4)
               let input := mload(dataPtr)

               // write 3 bytes
               let output := add(
                   add(
                       shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)),
                       shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))),
                   add(
                       shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)),
                               and(mload(add(tablePtr, and(        input , 0xFF))), 0xFF)
                    )
                )
                mstore(resultPtr, shl(232, output))
                resultPtr := add(resultPtr, 3)
            }
        }

        return result;
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    event Approval(address indexed owner, address indexed spender, uint256 indexed id);

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /*//////////////////////////////////////////////////////////////
                         METADATA STORAGE/LOGIC
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*//////////////////////////////////////////////////////////////
                      ERC721 BALANCE/OWNER STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) internal _ownerOf;

    mapping(address => uint256) internal _balanceOf;

    function ownerOf(uint256 id) public view virtual returns (address owner) {
        require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
    }

    function balanceOf(address owner) public view virtual returns (uint256) {
        require(owner != address(0), "ZERO_ADDRESS");

        return _balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                         ERC721 APPROVAL STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*//////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = _ownerOf[id];

        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(from == _ownerOf[id], "WRONG_FROM");

        require(to != address(0), "INVALID_RECIPIENT");

        require(
            msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
            "NOT_AUTHORIZED"
        );

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            _balanceOf[from]--;

            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes calldata data
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(_ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        emit Transfer(address(0), to, id);
    }

    function _burn(uint256 id) internal virtual {
        address owner = _ownerOf[id];

        require(owner != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            _balanceOf[owner]--;
        }

        delete _ownerOf[id];

        delete getApproved[id];

        emit Transfer(owner, address(0), id);
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }
}

/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC721TokenReceiver.onERC721Received.selector;
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_minterContract","type":"address"},{"internalType":"uint256","name":"maxAmount","type":"uint256"},{"internalType":"string","name":"network","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"bytes12","name":"rule","type":"bytes12"},{"indexed":false,"internalType":"uint256","name":"boardId","type":"uint256"}],"name":"TurmiteMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"boardnumber","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"moves","type":"uint256"}],"name":"TurmiteMove","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"bytes12","name":"newrule","type":"bytes12"}],"name":"TurmiteReprogramm","type":"event"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"boardcounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"boardNumber","type":"uint8"},{"internalType":"uint8","name":"posx","type":"uint8"},{"internalType":"uint8","name":"posy","type":"uint8"},{"internalType":"bool","name":"renderTurmite","type":"bool"}],"name":"getBitmap","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"boardNumber","type":"uint8"},{"internalType":"uint8","name":"posx","type":"uint8"},{"internalType":"uint8","name":"posy","type":"uint8"},{"internalType":"bool","name":"renderTurmite","type":"bool"}],"name":"getBitmapBase64","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"uint256","name":"boardNumber","type":"uint256"}],"name":"getByte","outputs":[{"internalType":"bytes1","name":"","type":"bytes1"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getPosField","outputs":[{"internalType":"bytes","name":"encodedData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"boardNumber","type":"uint8"},{"internalType":"uint8","name":"posx","type":"uint8"},{"internalType":"uint8","name":"posy","type":"uint8"},{"internalType":"bool","name":"renderTurmite","type":"bool"}],"name":"getSvg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"haecceity","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxnumbturmites","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[2]","name":"idmoves","type":"uint256[2]"}],"name":"moveTurmite","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"mintTo","type":"address"},{"internalType":"bytes12","name":"rule","type":"bytes12"},{"internalType":"uint256","name":"moves","type":"uint256"}],"name":"publicmint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"number","type":"uint8"}],"name":"renderBoard","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes12","name":"rule","type":"bytes12"}],"name":"reprogrammTurmite","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setByteHaMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_haecceityContract","type":"address"}],"name":"setHaecceityContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"setHaecceityMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setPositionHaMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"turmites","outputs":[{"internalType":"uint8","name":"turposx","type":"uint8"},{"internalType":"uint8","name":"turposy","type":"uint8"},{"internalType":"uint8","name":"orientation","type":"uint8"},{"internalType":"uint8","name":"boardnumber","type":"uint8"},{"internalType":"bytes1","name":"state","type":"bytes1"},{"internalType":"bytes12","name":"rule","type":"bytes12"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes12","name":"rule","type":"bytes12"}],"name":"validateNewRule","outputs":[{"internalType":"bool","name":"allowed","type":"bool"}],"stateMutability":"pure","type":"function"}]

0x60806040526000600d556000600e556040518060800160405280602460ff168152602001604860ff168152602001604860ff168152602001606c60ff1681525060109060046200005192919062000205565b506040518060800160405280604860ff168152602001602460ff168152602001606c60ff168152602001604860ff1681525060149060046200009592919062000205565b50348015620000a357600080fd5b506040516200678d3803806200678d8339818101604052810190620000c99190620004ab565b806040518060400160405280600a81526020017f53747261796c69676874000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f53545200000000000000000000000000000000000000000000000000000000008152508181816000908162000149919062000767565b5080600190816200015b919062000767565b505050505080600c908162000171919062000767565b505082601860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600f8190555033601a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050506200084e565b82600481019282156200023c579160200282015b828111156200023b578251829060ff1690559160200191906001019062000219565b5b5090506200024b91906200024f565b5090565b5b808211156200026a57600081600090555060010162000250565b5090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620002af8262000282565b9050919050565b620002c181620002a2565b8114620002cd57600080fd5b50565b600081519050620002e181620002b6565b92915050565b6000819050919050565b620002fc81620002e7565b81146200030857600080fd5b50565b6000815190506200031c81620002f1565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62000377826200032c565b810181811067ffffffffffffffff821117156200039957620003986200033d565b5b80604052505050565b6000620003ae6200026e565b9050620003bc82826200036c565b919050565b600067ffffffffffffffff821115620003df57620003de6200033d565b5b620003ea826200032c565b9050602081019050919050565b60005b8381101562000417578082015181840152602081019050620003fa565b8381111562000427576000848401525b50505050565b6000620004446200043e84620003c1565b620003a2565b90508281526020810184848401111562000463576200046262000327565b5b62000470848285620003f7565b509392505050565b600082601f83011262000490576200048f62000322565b5b8151620004a28482602086016200042d565b91505092915050565b600080600060608486031215620004c757620004c662000278565b5b6000620004d786828701620002d0565b9350506020620004ea868287016200030b565b925050604084015167ffffffffffffffff8111156200050e576200050d6200027d565b5b6200051c8682870162000478565b9150509250925092565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200057957607f821691505b6020821081036200058f576200058e62000531565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620005f97fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620005ba565b620006058683620005ba565b95508019841693508086168417925050509392505050565b6000819050919050565b600062000648620006426200063c84620002e7565b6200061d565b620002e7565b9050919050565b6000819050919050565b620006648362000627565b6200067c62000673826200064f565b848454620005c7565b825550505050565b600090565b6200069362000684565b620006a081848462000659565b505050565b5b81811015620006c857620006bc60008262000689565b600181019050620006a6565b5050565b601f8211156200071757620006e18162000595565b620006ec84620005aa565b81016020851015620006fc578190505b620007146200070b85620005aa565b830182620006a5565b50505b505050565b600082821c905092915050565b60006200073c600019846008026200071c565b1980831691505092915050565b600062000757838362000729565b9150826002028217905092915050565b620007728262000526565b67ffffffffffffffff8111156200078e576200078d6200033d565b5b6200079a825462000560565b620007a7828285620006cc565b600060209050601f831160018114620007df5760008415620007ca578287015190505b620007d6858262000749565b86555062000846565b601f198416620007ef8662000595565b60005b828110156200081957848901518255600182019150602085019450602081019050620007f2565b8683101562000839578489015162000835601f89168262000729565b8355505b6001600288020188555050505b505050505050565b615f2f806200085e6000396000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c80636352211e1161011a578063c2a8d57c116100ad578063d3158b021161007c578063d3158b021461065c578063e524b3071461067a578063e8354445146106aa578063e985e9c5146106c6578063ef7af2fc146106f657610206565b8063c2a8d57c146105c4578063c61a3c84146105e0578063c87b56dd146105fc578063c966409d1461062c57610206565b806395d89b41116100e957806395d89b411461053e578063a22cb4651461055c578063b88d4fde14610578578063be76bf8f1461059457610206565b80636352211e1461049257806369dbd7d7146104c25780636c5453a6146104f257806370a082311461050e57610206565b80632cc4837f1161019d57806340cb8af91161016c57806340cb8af9146103ca57806342842e0e146103fa5780634f6ccce714610416578063518a8802146104465780635e8c32111461046257610206565b80632cc4837f146103305780632f745c591461034e57806335faee731461037e5780633aedf55c146103ae57610206565b80631034fc0d116101d95780631034fc0d146102a557806313f36fc1146102c157806318160ddd146102f657806323b872dd1461031457610206565b806301ffc9a71461020b57806306fdde031461023b578063081812fc14610259578063095ea7b314610289575b600080fd5b61022560048036038101906102209190613a09565b610726565b6040516102329190613a51565b60405180910390f35b6102436107b8565b6040516102509190613b05565b60405180910390f35b610273600480360381019061026e9190613b5d565b610846565b6040516102809190613bcb565b60405180910390f35b6102a3600480360381019061029e9190613c12565b610879565b005b6102bf60048036038101906102ba9190613caa565b610a62565b005b6102db60048036038101906102d69190613b5d565b610baa565b6040516102ed96959493929190613d50565b60405180910390f35b6102fe610c34565b60405161030b9190613dc0565b60405180910390f35b61032e60048036038101906103299190613ddb565b610c41565b005b610338610c6e565b6040516103459190613dc0565b60405180910390f35b61036860048036038101906103639190613c12565b610c74565b6040516103759190613dc0565b60405180910390f35b61039860048036038101906103939190613e2e565b610d19565b6040516103a59190613a51565b60405180910390f35b6103c860048036038101906103c39190613ec0565b61119d565b005b6103e460048036038101906103df9190613b5d565b6113bd565b6040516103f19190613a51565b60405180910390f35b610414600480360381019061040f9190613ddb565b6113dd565b005b610430600480360381019061042b9190613b5d565b61140a565b60405161043d9190613dc0565b60405180910390f35b610460600480360381019061045b9190613f20565b61147b565b005b61047c60048036038101906104779190613fa5565b61154f565b6040516104899190613b05565b60405180910390f35b6104ac60048036038101906104a79190613b5d565b61158e565b6040516104b99190613bcb565b60405180910390f35b6104dc60048036038101906104d79190613fa5565b611639565b6040516104e99190613b05565b60405180910390f35b61050c60048036038101906105079190613ec0565b611697565b005b61052860048036038101906105239190613f20565b6118d9565b6040516105359190613dc0565b60405180910390f35b610546611990565b6040516105539190613b05565b60405180910390f35b6105766004803603810190610571919061400c565b611a1e565b005b610592600480360381019061058d919061404c565b611b1b565b005b6105ae60048036038101906105a99190613fa5565b611b4c565b6040516105bb9190614129565b60405180910390f35b6105de60048036038101906105d9919061414b565b611d49565b005b6105fa60048036038101906105f59190613b5d565b611fc9565b005b61061660048036038101906106119190613b5d565b6120ff565b6040516106239190613b05565b60405180910390f35b6106466004803603810190610641919061419e565b6121e9565b6040516106539190613b05565b60405180910390f35b610664612200565b6040516106719190613dc0565b60405180910390f35b610694600480360381019061068f91906141cb565b612206565b6040516106a1919061421e565b60405180910390f35b6106c460048036038101906106bf919061425b565b612265565b005b6106e060048036038101906106db9190614288565b612352565b6040516106ed9190613a51565b60405180910390f35b610710600480360381019061070b9190613b5d565b612381565b60405161071d9190614129565b60405180910390f35b60006301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061078157506380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806107b15750635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b600080546107c5906142f7565b80601f01602080910402602001604051908101604052809291908181526020018280546107f1906142f7565b801561083e5780601f106108135761010080835404028352916020019161083e565b820191906000526020600020905b81548152906001019060200180831161082157829003601f168201915b505050505081565b60046020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806109715750600560008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b6109b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a790614374565b60405180910390fd5b826004600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b610a6b8261158e565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ad8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610acf90614374565b60405180910390fd5b60011515610ae582610d19565b151514610b27576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1e906143e0565b60405180910390fd5b80600b600084815260200190815260200160002060000160056101000a8154816bffffffffffffffffffffffff021916908360a01c02179055508073ffffffffffffffffffffffffffffffffffffffff1916827fd1464fd210d58c95f829eeb54351bb3b0f9cf4277440f5627f822489a0548cd360405160405180910390a35050565b600b6020528060005260406000206000915090508060000160009054906101000a900460ff16908060000160019054906101000a900460ff16908060000160029054906101000a900460ff16908060000160039054906101000a900460ff16908060000160049054906101000a900460f81b908060000160059054906101000a900460a01b905086565b6000600880549050905090565b610c4a81612450565b610c5483826124ac565b610c5e8282612619565b610c69838383612698565b505050565b600f5481565b6000610c7f836118d9565b8210610cc0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb790614472565b60405180910390fd5b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002054905092915050565b60008060ff60f81b836000600c8110610d3557610d34614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610da35750600060f81b836000600c8110610d7b57610d7a614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8015610e32575060ff60f81b836003600c8110610dc357610dc2614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610e315750600060f81b836003600c8110610e0957610e08614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b8015610ec1575060ff60f81b836006600c8110610e5257610e51614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610ec05750600060f81b836006600c8110610e9857610e97614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b8015610f50575060ff60f81b836009600c8110610ee157610ee0614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610f4f5750600060f81b836009600c8110610f2757610f26614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b90506000600160f81b846002600c8110610f6d57610f6c614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610fdb5750600060f81b846002600c8110610fb357610fb2614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b801561106a5750600160f81b846005600c8110610ffb57610ffa614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806110695750600060f81b846005600c811061104157611040614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b80156110f95750600160f81b846008600c811061108a57611089614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806110f85750600060f81b846008600c81106110d0576110cf614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b80156111885750600160f81b84600b600c811061111957611118614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806111875750600060f81b84600b600c811061115f5761115e614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b90508080156111945750815b92505050919050565b600073ffffffffffffffffffffffffffffffffffffffff16601960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff160361122e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112259061450d565b60405180910390fd5b60011515601b600085815260200190815260200160002060009054906101000a900460ff16151514611295576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128c9061459f565b60405180910390fd5b601960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611325576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161131c9061460b565b60405180910390fd5b600080600061137785858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a97565b9250925092506113b58360ff168360ff1683600b60008b815260200190815260200160002060000160039054906101000a900460ff1660ff16612ab8565b505050505050565b601b6020528060005260406000206000915054906101000a900460ff1681565b6113e681612450565b6113f083826124ac565b6113fa8282612619565b611405838383612b1d565b505050565b6000611414610c34565b8210611455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144c9061469d565b60405180910390fd5b6008828154811061146957611468614492565b5b90600052602060002001549050919050565b601a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461150b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161150290614374565b60405180910390fd5b80601960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b606061156561156086868686611b4c565b612c55565b6040516020016115759190614745565b6040516020818303038152906040529050949350505050565b60008073ffffffffffffffffffffffffffffffffffffffff166002600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691508173ffffffffffffffffffffffffffffffffffffffff1603611634576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161162b906147b3565b60405180910390fd5b919050565b606061166e61164a8686868661154f565b60405160200161165a9190614a59565b604051602081830303815290604052612c55565b60405160200161167e9190614ad2565b6040516020818303038152906040529050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff16601960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603611728576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161171f9061450d565b60405180910390fd5b60011515601b600085815260200190815260200160002060009054906101000a900460ff1615151461178f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117869061459f565b60405180910390fd5b601960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461181f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118169061460b565b60405180910390fd5b60008061186f84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a97565b509150915081600b600087815260200190815260200160002060000160006101000a81548160ff021916908360ff16021790555080600b600087815260200190815260200160002060000160016101000a81548160ff021916908360ff1602179055505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611949576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161194090614b40565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6001805461199d906142f7565b80601f01602080910402602001604051908101604052809291908181526020018280546119c9906142f7565b8015611a165780601f106119eb57610100808354040283529160200191611a16565b820191906000526020600020905b8154815290600101906020018083116119f957829003601f168201915b505050505081565b80600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611b0f9190613a51565b60405180910390a35050565b611b2483612450565b611b2e85846124ac565b611b388484612619565b611b458585858585612dcd565b5050505050565b606060006040518061046001604052806104368152602001615ac461043691399050600061510067ffffffffffffffff811115611b8c57611b8b614b60565b5b6040519080825280601f01601f191660200182016040528015611bbe5781602001600182028036833780820191505090505b50905060005b6090811015611cb25760005b6090811015611ca0576000816090611be89190614bbe565b83611bf39190614c18565b9050600a60008b60ff1681526020019081526020016000206000018360908110611c2057611c1f614492565b5b600502018260908110611c3657611c35614492565b5b602091828204019190069054906101000a900460f81b848281518110611c5f57611c5e614492565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505080611c9990614c6e565b9050611bd0565b5080611cab90614c6e565b9050611bc4565b506001151584151503611d2a5760008560ff166090611cd19190614bbe565b8760ff16611cdf9190614c18565b905060a560f81b828281518110611cf957611cf8614492565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350505b611d3d8183612f0b90919063ffffffff16565b92505050949350505050565b600f54600e5410611d8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d8690614d02565b60405180910390fd5b60011515611d9c83610d19565b151514611dde576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dd5906143e0565b60405180910390fd5b601860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611e6e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e6590614d6e565b60405180910390fd5b60016004600e54611e7f9190614dbd565b611e899190614c18565b600d81905550600060106004600e54611ea29190614dee565b60048110611eb357611eb2614492565b5b01549050600060146004600e54611eca9190614dee565b60048110611edb57611eda614492565b5b01549050611eeb85600e54612619565b611ef6600e54612f95565b611f0285600e54612fde565b611f15600e5483836001600d54896131f0565b8373ffffffffffffffffffffffffffffffffffffffff1916600e547f66e34e24596794eb9fbba61ddf385dbbc89563ac1f0250e6587c2ac6c039481d600d54604051611f619190613dc0565b60405180910390a36000831115611f7f57611f7e600e5484613354565b5b6000601b6000600e54815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600e54611fbc9190614c18565b600e819055505050505050565b600073ffffffffffffffffffffffffffffffffffffffff16601960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff160361205a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120519061450d565b60405180910390fd5b6120638161158e565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146120d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120c790614374565b60405180910390fd5b6001601b600083815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60606121e282600b600085815260200190815260200160002060000160039054906101000a900460ff16600b600086815260200190815260200160002060000160059054906101000a900460a01b600b600087815260200190815260200160002060000160049054906101000a900460f81b600b600088815260200190815260200160002060000160009054906101000a900460ff16600b600089815260200190815260200160002060000160019054906101000a900460ff16600b60008a815260200190815260200160002060000160029054906101000a900460ff1661362c565b9050919050565b60606121f9826000806000611639565b9050919050565b600d5481565b6000600a600083815260200190815260200160002060000184609081106122305761222f614492565b5b60050201836090811061224657612245614492565b5b602091828204019190069054906101000a900460f81b90509392505050565b6122868160006002811061227c5761227b614492565b5b602002013561158e565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122ea90614374565b60405180910390fd5b60008160016002811061230957612308614492565b5b6020020135111561234f5761234e8160006002811061232b5761232a614492565b5b60200201358260016002811061234457612343614492565b5b6020020135613354565b5b50565b60056020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b6060600080600080602067ffffffffffffffff8111156123a4576123a3614b60565b5b6040519080825280601f01601f1916602001820160405280156123d65781602001600182028036833780820191505090505b5090506000600b600088815260200190815260200160002090508054945060ff8516935060ff8560081c169250600061242e8560ff168560ff16600160048c61241f9190614dbd565b6124299190614c18565b612206565b9050846020840153836021840153806022840152829650505050505050919050565b60011515601b600083815260200190815260200160002060009054906101000a900460ff161515036124a9576000601b600083815260200190815260200160002060006101000a81548160ff0219169083151502179055505b50565b600060016124b9846118d9565b6124c39190614e1f565b90506000600760008481526020019081526020016000205490508181146125a8576000600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002054905080600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002081905550816007600083815260200190815260200160002081905550505b6007600084815260200190815260200160002060009055600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000905550505050565b6000612624836118d9565b905081600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002081905550806007600084815260200190815260200160002081905550505050565b6002600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614612739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161273090614e9f565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036127a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161279f90614f0b565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806128685750600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b806128d157506004600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b612910576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161290790614374565b60405180910390fd5b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600190039190505550600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906001019190505550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506004600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b60008060006001840151925060028401519150602284015190509193909250565b81600a60008381526020019081526020016000206000018560908110612ae157612ae0614492565b5b600502018460908110612af757612af6614492565b5b602091828204019190066101000a81548160ff021916908360f81c021790555050505050565b612b28838383610c41565b60008273ffffffffffffffffffffffffffffffffffffffff163b1480612c11575063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168273ffffffffffffffffffffffffffffffffffffffff1663150b7a023386856040518463ffffffff1660e01b8152600401612bad93929190614f51565b6020604051808303816000875af1158015612bcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf09190614fb0565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b612c50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c4790615029565b60405180910390fd5b505050565b60606000825103612c7757604051806020016040528060008152509050612dc8565b6000604051806060016040528060408152602001615a846040913990506000600360028551612ca69190614c18565b612cb09190614dbd565b6004612cbc9190614bbe565b90506000602082612ccd9190614c18565b67ffffffffffffffff811115612ce657612ce5614b60565b5b6040519080825280601f01601f191660200182016040528015612d185781602001600182028036833780820191505090505b509050818152600183018586518101602084015b81831015612d87576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f8116850151825360018201915050612d2c565b600389510660018114612da15760028114612db157612dbc565b613d3d60f01b6002830352612dbc565b603d60f81b60018303525b50505050508093505050505b919050565b612dd8858585610c41565b60008473ffffffffffffffffffffffffffffffffffffffff163b1480612ec5575063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168473ffffffffffffffffffffffffffffffffffffffff1663150b7a0233888787876040518663ffffffff1660e01b8152600401612e61959493929190615085565b6020604051808303816000875af1158015612e80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ea49190614fb0565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b612f04576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612efb90615029565b60405180910390fd5b5050505050565b6060806040519050835180825260208201818101602087015b81831015612f415780518352602083019250602081019050612f24565b50855192508351830184528091508282019050602086015b81831015612f765780518352602083019250602081019050612f59565b50601f19601f8851850115830101166040525050508091505092915050565b6008805490506009600083815260200190815260200160002081905550600881908060018154018082558091505060019003906000526020600020016000909190919091505550565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361304d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161304490614f0b565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146130ef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130e69061511f565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906001019190505550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050565b60006040518060c001604052808760ff1681526020018660ff1681526020018560ff1681526020018460ff168152602001827effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020018373ffffffffffffffffffffffffffffffffffffffff1916815250600b600089815260200190815260200160002060008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548160ff021916908360ff16021790555060408201518160000160026101000a81548160ff021916908360ff16021790555060608201518160000160036101000a81548160ff021916908360ff16021790555060808201518160000160046101000a81548160ff021916908360f81c021790555060a08201518160000160056101000a8154816bffffffffffffffffffffffff021916908360a01c021790555090505050505050505050565b600080600080600080600b600089815260200190815260200160002090508054915060005b878110156135ec5760ff8316955060ff8360081c1694508260181c935060006133ac8760ff168760ff168760ff16612206565b905070ffffffffffffffffffffffff0000000000841660ff8560101c16600080600064ff00000000891660201c1460008660f81c141615613400578360781b9b5060ff8460781c16905060ff8460701c1691505b600064ff00000000891660201c1460ff8660f81c141615613434578360901b9b5060ff8460601c16905060ff8460581c1691505b600164ff00000000891660201c1460008660f81c141615613468578360a81b9b5060ff8460481c16905060ff8460401c1691505b600164ff00000000891660201c1460ff8660f81c14161561349c578360c01b9b5060ff8460301c16905060ff8460281c1691505b600081600281146134bf57600881146134cc57600481146134ee578491506134f8565b60046001860891506134f8565b84600081146134e3576004600187030692506134e8565b600392505b506134f8565b6004600286010691505b50604051816000811461352257600281146135385760038114613569576001811461357f576135ac565b609060018f08601f8301538c601e8301536135ac565b8d600081146135555760018f03601f8401538d601e840153613563565b608f601f8401538d601e8401535b506135ac565b8d601f830153609060018e08601e8301536135ac565b8c6000811461359c578e601f84015360018e03601e8401536135aa565b8e601f840153608f601e8401535b505b5081601d8201538a601c82015383601b8201538581511799505050505050506135e08760ff168760ff168a8860ff16612ab8565b60018201915050613379565b50818155868360ff16897fbbe0aa2504840f3cabeaa7c222bc975ed888abf937945ff374653c8d57c55fbb60405160405180910390a45050505050505050565b606061367c61363b89896136a8565b6136488987876001611639565b6136568a8a8a8a8a8a6136e7565b60405160200161366893929190615353565b604051602081830303815290604052612c55565b60405160200161368c919061541d565b6040516020818303038152906040529050979650505050505050565b60606136b383613764565b6136bf8360ff16613764565b6040516020016136d09291906154d7565b604051602081830303815290604052905092915050565b60606136f58760ff16613764565b6136fe876137b4565b61370d8760f81c60ff16613764565b6137198760ff16613764565b6137258760ff16613764565b6137318760ff16613764565b600c60405160200161374997969594939291906158c7565b60405160208183030381529060405290509695505050505050565b606060a060405101806040526020810391506000825281835b60011561379f57600184039350600a81066030018453600a810490508061377d575b50828103602084039350808452505050919050565b6060600080601867ffffffffffffffff8111156137d4576137d3614b60565b5b6040519080825280601f01601f1916602001820160405280156138065781602001600182028036833780820191505090505b509050600091505b80518260ff161015613960576000600f60f81b8560028561382f91906159f2565b60ff16600c811061384357613842614492565b5b1a60f81b1660f81c9050600060048660028661385f91906159f2565b60ff16600c811061387357613872614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916901c60f81c90506138a98161396a565b838560ff16815181106138bf576138be614492565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506001846138fb9190615a23565b93506139068261396a565b838560ff168151811061391c5761391b614492565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505050818061395890615a5a565b92505061380e565b8092505050919050565b6000600a8260ff16101561398f576030826139859190615a23565b60f81b90506139a2565b60578261399c9190615a23565b60f81b90505b919050565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6139e6816139b1565b81146139f157600080fd5b50565b600081359050613a03816139dd565b92915050565b600060208284031215613a1f57613a1e6139a7565b5b6000613a2d848285016139f4565b91505092915050565b60008115159050919050565b613a4b81613a36565b82525050565b6000602082019050613a666000830184613a42565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613aa6578082015181840152602081019050613a8b565b83811115613ab5576000848401525b50505050565b6000601f19601f8301169050919050565b6000613ad782613a6c565b613ae18185613a77565b9350613af1818560208601613a88565b613afa81613abb565b840191505092915050565b60006020820190508181036000830152613b1f8184613acc565b905092915050565b6000819050919050565b613b3a81613b27565b8114613b4557600080fd5b50565b600081359050613b5781613b31565b92915050565b600060208284031215613b7357613b726139a7565b5b6000613b8184828501613b48565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613bb582613b8a565b9050919050565b613bc581613baa565b82525050565b6000602082019050613be06000830184613bbc565b92915050565b613bef81613baa565b8114613bfa57600080fd5b50565b600081359050613c0c81613be6565b92915050565b60008060408385031215613c2957613c286139a7565b5b6000613c3785828601613bfd565b9250506020613c4885828601613b48565b9150509250929050565b60007fffffffffffffffffffffffff000000000000000000000000000000000000000082169050919050565b613c8781613c52565b8114613c9257600080fd5b50565b600081359050613ca481613c7e565b92915050565b60008060408385031215613cc157613cc06139a7565b5b6000613ccf85828601613b48565b9250506020613ce085828601613c95565b9150509250929050565b600060ff82169050919050565b613d0081613cea565b82525050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b613d3b81613d06565b82525050565b613d4a81613c52565b82525050565b600060c082019050613d656000830189613cf7565b613d726020830188613cf7565b613d7f6040830187613cf7565b613d8c6060830186613cf7565b613d996080830185613d32565b613da660a0830184613d41565b979650505050505050565b613dba81613b27565b82525050565b6000602082019050613dd56000830184613db1565b92915050565b600080600060608486031215613df457613df36139a7565b5b6000613e0286828701613bfd565b9350506020613e1386828701613bfd565b9250506040613e2486828701613b48565b9150509250925092565b600060208284031215613e4457613e436139a7565b5b6000613e5284828501613c95565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112613e8057613e7f613e5b565b5b8235905067ffffffffffffffff811115613e9d57613e9c613e60565b5b602083019150836001820283011115613eb957613eb8613e65565b5b9250929050565b600080600060408486031215613ed957613ed86139a7565b5b6000613ee786828701613b48565b935050602084013567ffffffffffffffff811115613f0857613f076139ac565b5b613f1486828701613e6a565b92509250509250925092565b600060208284031215613f3657613f356139a7565b5b6000613f4484828501613bfd565b91505092915050565b613f5681613cea565b8114613f6157600080fd5b50565b600081359050613f7381613f4d565b92915050565b613f8281613a36565b8114613f8d57600080fd5b50565b600081359050613f9f81613f79565b92915050565b60008060008060808587031215613fbf57613fbe6139a7565b5b6000613fcd87828801613f64565b9450506020613fde87828801613f64565b9350506040613fef87828801613f64565b925050606061400087828801613f90565b91505092959194509250565b60008060408385031215614023576140226139a7565b5b600061403185828601613bfd565b925050602061404285828601613f90565b9150509250929050565b600080600080600060808688031215614068576140676139a7565b5b600061407688828901613bfd565b955050602061408788828901613bfd565b945050604061409888828901613b48565b935050606086013567ffffffffffffffff8111156140b9576140b86139ac565b5b6140c588828901613e6a565b92509250509295509295909350565b600081519050919050565b600082825260208201905092915050565b60006140fb826140d4565b61410581856140df565b9350614115818560208601613a88565b61411e81613abb565b840191505092915050565b6000602082019050818103600083015261414381846140f0565b905092915050565b600080600060608486031215614164576141636139a7565b5b600061417286828701613bfd565b935050602061418386828701613c95565b925050604061419486828701613b48565b9150509250925092565b6000602082840312156141b4576141b36139a7565b5b60006141c284828501613f64565b91505092915050565b6000806000606084860312156141e4576141e36139a7565b5b60006141f286828701613b48565b935050602061420386828701613b48565b925050604061421486828701613b48565b9150509250925092565b60006020820190506142336000830184613d32565b92915050565b60008190508260206002028201111561425557614254613e65565b5b92915050565b600060408284031215614271576142706139a7565b5b600061427f84828501614239565b91505092915050565b6000806040838503121561429f5761429e6139a7565b5b60006142ad85828601613bfd565b92505060206142be85828601613bfd565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061430f57607f821691505b602082108103614322576143216142c8565b5b50919050565b7f4e4f545f415554484f52495a4544000000000000000000000000000000000000600082015250565b600061435e600e83613a77565b915061436982614328565b602082019050919050565b6000602082019050818103600083015261438d81614351565b9050919050565b7f494e56414c49445f52554c450000000000000000000000000000000000000000600082015250565b60006143ca600c83613a77565b91506143d582614394565b602082019050919050565b600060208201905081810360008301526143f9816143bd565b9050919050565b7f455243373231456e756d657261626c653a206f776e657220696e646578206f7560008201527f74206f6620626f756e6473000000000000000000000000000000000000000000602082015250565b600061445c602b83613a77565b915061446782614400565b604082019050919050565b6000602082019050818103600083015261448b8161444f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f434f4e54524143545f49535f5a45524f41444452455353000000000000000000600082015250565b60006144f7601783613a77565b9150614502826144c1565b602082019050919050565b60006020820190508181036000830152614526816144ea565b9050919050565b7f434f4e54524143545f4e4f545f494e4954414c495a45445f42595f4e46545f4f60008201527f574e455200000000000000000000000000000000000000000000000000000000602082015250565b6000614589602483613a77565b91506145948261452d565b604082019050919050565b600060208201905081810360008301526145b88161457c565b9050919050565b7f43414c4c5f4f4e4c595f46524f4d5f4841434f4e545241435400000000000000600082015250565b60006145f5601983613a77565b9150614600826145bf565b602082019050919050565b60006020820190508181036000830152614624816145e8565b9050919050565b7f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60008201527f7574206f6620626f756e64730000000000000000000000000000000000000000602082015250565b6000614687602c83613a77565b91506146928261462b565b604082019050919050565b600060208201905081810360008301526146b68161467a565b9050919050565b600081905092915050565b7f646174613a696d6167652f626d703b6261736536342c00000000000000000000600082015250565b60006146fe6016836146bd565b9150614709826146c8565b601682019050919050565b600061471f82613a6c565b61472981856146bd565b9350614739818560208601613a88565b80840191505092915050565b6000614750826146f1565b915061475c8284614714565b915081905092915050565b7f4e4f545f4d494e54454400000000000000000000000000000000000000000000600082015250565b600061479d600a83613a77565b91506147a882614767565b602082019050919050565b600060208201905081810360008301526147cc81614790565b9050919050565b7f3c73766720636c6173733d227376674247472220786d6c6e733d22687474703a60008201527f2f2f7777772e77332e6f72672f323030302f737667222076657273696f6e3d2260208201527f312e31222077696474683d2235303022206865696768743d22353030223e3c6460408201527f6566732069643d22736f6d6544656673223e3c7374796c652069643d2273747960608201527f6c6531393939223e202e737667424747207b2077696474683a2035303070783b60808201527f6865696768743a2035303070783b6261636b67726f756e642d696d6167653a2060a08201527f75726c280000000000000000000000000000000000000000000000000000000060c082015250565b60006148ed60c4836146bd565b91506148f8826147d3565b60c482019050919050565b7f293b206261636b67726f756e642d7265706561743a206e6f2d7265706561743b60008201527f206261636b67726f756e642d73697a653a20313030253b20696d6167652d726560208201527f6e646572696e673a202d7765626b69742d6f7074696d697a652d636f6e74726160408201527f73743b202d6d732d696e746572706f6c6174696f6e2d6d6f64653a206e65617260608201527f6573742d6e65696768626f723b20696d6167652d72656e646572696e673a202d60808201527f6d6f7a2d63726973702d65646765733b20696d6167652d72656e646572696e6760a08201527f3a20706978656c617465643b7d3c2f7374796c653e3c2f646566733e3c2f737660c08201527f673e00000000000000000000000000000000000000000000000000000000000060e082015250565b6000614a4360e2836146bd565b9150614a4e82614903565b60e282019050919050565b6000614a64826148e0565b9150614a708284614714565b9150614a7b82614a36565b915081905092915050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000600082015250565b6000614abc601a836146bd565b9150614ac782614a86565b601a82019050919050565b6000614add82614aaf565b9150614ae98284614714565b915081905092915050565b7f5a45524f5f414444524553530000000000000000000000000000000000000000600082015250565b6000614b2a600c83613a77565b9150614b3582614af4565b602082019050919050565b60006020820190508181036000830152614b5981614b1d565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614bc982613b27565b9150614bd483613b27565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614c0d57614c0c614b8f565b5b828202905092915050565b6000614c2382613b27565b9150614c2e83613b27565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115614c6357614c62614b8f565b5b828201905092915050565b6000614c7982613b27565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614cab57614caa614b8f565b5b600182019050919050565b7f4d494e545f4f5645520000000000000000000000000000000000000000000000600082015250565b6000614cec600983613a77565b9150614cf782614cb6565b602082019050919050565b60006020820190508181036000830152614d1b81614cdf565b9050919050565b7f4f4e4c595f4d494e5441424c455f46524f4d5f4d494e545f434f4e5452414354600082015250565b6000614d58602083613a77565b9150614d6382614d22565b602082019050919050565b60006020820190508181036000830152614d8781614d4b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000614dc882613b27565b9150614dd383613b27565b925082614de357614de2614d8e565b5b828204905092915050565b6000614df982613b27565b9150614e0483613b27565b925082614e1457614e13614d8e565b5b828206905092915050565b6000614e2a82613b27565b9150614e3583613b27565b925082821015614e4857614e47614b8f565b5b828203905092915050565b7f57524f4e475f46524f4d00000000000000000000000000000000000000000000600082015250565b6000614e89600a83613a77565b9150614e9482614e53565b602082019050919050565b60006020820190508181036000830152614eb881614e7c565b9050919050565b7f494e56414c49445f524543495049454e54000000000000000000000000000000600082015250565b6000614ef5601183613a77565b9150614f0082614ebf565b602082019050919050565b60006020820190508181036000830152614f2481614ee8565b9050919050565b50565b6000614f3b6000836140df565b9150614f4682614f2b565b600082019050919050565b6000608082019050614f666000830186613bbc565b614f736020830185613bbc565b614f806040830184613db1565b8181036060830152614f9181614f2e565b9050949350505050565b600081519050614faa816139dd565b92915050565b600060208284031215614fc657614fc56139a7565b5b6000614fd484828501614f9b565b91505092915050565b7f554e534146455f524543495049454e5400000000000000000000000000000000600082015250565b6000615013601083613a77565b915061501e82614fdd565b602082019050919050565b6000602082019050818103600083015261504281615006565b9050919050565b82818337600083830152505050565b600061506483856140df565b9350615071838584615049565b61507a83613abb565b840190509392505050565b600060808201905061509a6000830188613bbc565b6150a76020830187613bbc565b6150b46040830186613db1565b81810360608301526150c7818486615058565b90509695505050505050565b7f414c52454144595f4d494e544544000000000000000000000000000000000000600082015250565b6000615109600e83613a77565b9150615114826150d3565b602082019050919050565b60006020820190508181036000830152615138816150fc565b9050919050565b7f7b226e616d65223a220000000000000000000000000000000000000000000000600082015250565b60006151756009836146bd565b91506151808261513f565b600982019050919050565b7f222c20226465736372697074696f6e223a220000000000000000000000000000600082015250565b60006151c16012836146bd565b91506151cc8261518b565b601282019050919050565b7f4f6e636861696e204d757469706c617965722041727400000000000000000000600082015250565b600061520d6016836146bd565b9150615218826151d7565b601682019050919050565b7f222c2022696d616765223a202200000000000000000000000000000000000000600082015250565b6000615259600d836146bd565b915061526482615223565b600d82019050919050565b7f222c000000000000000000000000000000000000000000000000000000000000600082015250565b60006152a56002836146bd565b91506152b08261526f565b600282019050919050565b7f2261747472696275746573223a20000000000000000000000000000000000000600082015250565b60006152f1600e836146bd565b91506152fc826152bb565b600e82019050919050565b7f7d00000000000000000000000000000000000000000000000000000000000000600082015250565b600061533d6001836146bd565b915061534882615307565b600182019050919050565b600061535e82615168565b915061536a8286614714565b9150615375826151b4565b915061538082615200565b915061538b8261524c565b91506153978285614714565b91506153a282615298565b91506153ad826152e4565b91506153b98284614714565b91506153c482615330565b9150819050949350505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000600082015250565b6000615407601d836146bd565b9150615412826153d1565b601d82019050919050565b6000615428826153fa565b91506154348284614714565b915081905092915050565b7f5475726d69746520000000000000000000000000000000000000000000000000600082015250565b60006154756008836146bd565b91506154808261543f565b600882019050919050565b7f20576f726c642000000000000000000000000000000000000000000000000000600082015250565b60006154c16007836146bd565b91506154cc8261548b565b600782019050919050565b60006154e282615468565b91506154ee8285614714565b91506154f9826154b4565b91506155058284614714565b91508190509392505050565b7f5b7b2274726169745f74797065223a22576f726c64222c2276616c7565223a22600082015250565b60006155476020836146bd565b915061555282615511565b602082019050919050565b7f227d2c0000000000000000000000000000000000000000000000000000000000600082015250565b60006155936003836146bd565b915061559e8261555d565b600382019050919050565b7f7b2274726169745f74797065223a2252756c65222c0000000000000000000000600082015250565b60006155df6015836146bd565b91506155ea826155a9565b601582019050919050565b7f2276616c7565223a220000000000000000000000000000000000000000000000600082015250565b600061562b6009836146bd565b9150615636826155f5565b600982019050919050565b7f7b2274726169745f74797065223a225374617465222c00000000000000000000600082015250565b60006156776016836146bd565b915061568282615641565b601682019050919050565b7f7b2274726169745f74797065223a22504f532058222c00000000000000000000600082015250565b60006156c36016836146bd565b91506156ce8261568d565b601682019050919050565b7f7b2274726169745f74797065223a22504f532059222c00000000000000000000600082015250565b600061570f6016836146bd565b915061571a826156d9565b601682019050919050565b7f7b2274726169745f74797065223a22446972656374696f6e222c000000000000600082015250565b600061575b601a836146bd565b915061576682615725565b601a82019050919050565b7f227d2c7b2274726169745f74797065223a224e6574776f726b222c2276616c7560008201527f65223a2200000000000000000000000000000000000000000000000000000000602082015250565b60006157cd6024836146bd565b91506157d882615771565b602482019050919050565b60008190508160005260206000209050919050565b60008154615805816142f7565b61580f81866146bd565b9450600182166000811461582a576001811461583f57615872565b60ff1983168652811515820286019350615872565b615848856157e3565b60005b8381101561586a5781548189015260018201915060208101905061584b565b838801955050505b50505092915050565b7f227d5d0000000000000000000000000000000000000000000000000000000000600082015250565b60006158b16003836146bd565b91506158bc8261587b565b600382019050919050565b60006158d28261553a565b91506158de828a614714565b91506158e982615586565b91506158f4826155d2565b91506158ff8261561e565b915061590b8289614714565b915061591682615586565b91506159218261566a565b915061592c8261561e565b91506159388288614714565b915061594382615586565b915061594e826156b6565b91506159598261561e565b91506159658287614714565b915061597082615586565b915061597b82615702565b91506159868261561e565b91506159928286614714565b915061599d82615586565b91506159a88261574e565b91506159b38261561e565b91506159bf8285614714565b91506159ca826157c0565b91506159d682846157f8565b91506159e1826158a4565b915081905098975050505050505050565b60006159fd82613cea565b9150615a0883613cea565b925082615a1857615a17614d8e565b5b828204905092915050565b6000615a2e82613cea565b9150615a3983613cea565b92508260ff03821115615a4f57615a4e614b8f565b5b828201905092915050565b6000615a6582613cea565b915060ff8203615a7857615a77614b8f565b5b60018201905091905056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f424d385500000000000036040000280000009000000090000000010008000000000002510000120b0000120b00000000000000000000000000000101010002020200030303000404040005050500060606000707070008080800090909000a0a0a000b0b0b000c0c0c000d0d0d000e0e0e000f0f0f00101010001111110012121200131313001414140015151500161616001717170018181800191919001a1a1a001b1b1b001c1c1c001d1d1d001e1e1e001f1f1f00202020002121210022222200232323002424240025252500262626002727270028282800292929002a2a2a002b2b2b002c2c2c002d2d2d002e2e2e002f2f2f00303030003131310032323200333333003434340035353500363636003737370038383800393939003a3a3a003b3b3b003c3c3c003d3d3d003e3e3e003f3f3f00404040004141410042424200434343004444440045454500464646004747470048484800494949004a4a4a004b4b4b004c4c4c004d4d4d004e4e4e004f4f4f00505050005151510052525200535353005454540055555500565656005757570058585800595959005a5a5a005b5b5b005c5c5c005d5d5d005e5e5e005f5f5f00606060006161610062626200636363006464640065656500666666006767670068686800696969006a6a6a006b6b6b006c6c6c006d6d6d006e6e6e006f6f6f00707070007171710072727200737373007474740075757500767676007777770078787800797979007a7a7a007b7b7b007c7c7c007d7d7d007e7e7e007f7f7f00808080008181810082828200838383008484840085858500868686008787870088888800898989008a8a8a008b8b8b008c8c8c008d8d8d008e8e8e008f8f8f00909090009191910092929200939393009494940095959500969696009797970098989800999999009a9a9a009b9b9b009c9c9c009d9d9d009e9e9e009f9f9f00a0a0a000a1a1a100a2a2a200a3a3a300a4a4a400a5a5a500a6a6a600a7a7a700a8a8a800a9a9a900aaaaaa00ababab00acacac00adadad00aeaeae00afafaf00b0b0b000b1b1b100b2b2b200b3b3b300b4b4b400b5b5b500b6b6b600b7b7b700b8b8b800b9b9b900bababa00bbbbbb00bcbcbc00bdbdbd00bebebe00bfbfbf00c0c0c000c1c1c100c2c2c200c3c3c300c4c4c400c5c5c500c6c6c600c7c7c700c8c8c800c9c9c900cacaca00cbcbcb00cccccc00cdcdcd00cecece00cfcfcf00d0d0d000d1d1d100d2d2d200d3d3d300d4d4d400d5d5d500d6d6d600d7d7d700d8d8d800d9d9d900dadada00dbdbdb00dcdcdc00dddddd00dedede00dfdfdf00e0e0e000e1e1e100e2e2e200e3e3e300e4e4e400e5e5e500e6e6e600e7e7e700e8e8e800e9e9e900eaeaea00ebebeb00ececec00ededed00eeeeee00efefef00f0f0f000f1f1f100f2f2f200f3f3f300f4f4f400f5f5f500f6f6f600f7f7f700f8f8f800f9f9f900fafafa00fbfbfb00fcfcfc00fdfdfd00fefefe00ffffff00a2646970667358221220792abd84e85ae7339fc7811867b48b0df27583811acd0908f337fe392af9356364736f6c634300080f0033000000000000000000000000e0b14d9412f762b6a49e7d009b62daed70212788000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102065760003560e01c80636352211e1161011a578063c2a8d57c116100ad578063d3158b021161007c578063d3158b021461065c578063e524b3071461067a578063e8354445146106aa578063e985e9c5146106c6578063ef7af2fc146106f657610206565b8063c2a8d57c146105c4578063c61a3c84146105e0578063c87b56dd146105fc578063c966409d1461062c57610206565b806395d89b41116100e957806395d89b411461053e578063a22cb4651461055c578063b88d4fde14610578578063be76bf8f1461059457610206565b80636352211e1461049257806369dbd7d7146104c25780636c5453a6146104f257806370a082311461050e57610206565b80632cc4837f1161019d57806340cb8af91161016c57806340cb8af9146103ca57806342842e0e146103fa5780634f6ccce714610416578063518a8802146104465780635e8c32111461046257610206565b80632cc4837f146103305780632f745c591461034e57806335faee731461037e5780633aedf55c146103ae57610206565b80631034fc0d116101d95780631034fc0d146102a557806313f36fc1146102c157806318160ddd146102f657806323b872dd1461031457610206565b806301ffc9a71461020b57806306fdde031461023b578063081812fc14610259578063095ea7b314610289575b600080fd5b61022560048036038101906102209190613a09565b610726565b6040516102329190613a51565b60405180910390f35b6102436107b8565b6040516102509190613b05565b60405180910390f35b610273600480360381019061026e9190613b5d565b610846565b6040516102809190613bcb565b60405180910390f35b6102a3600480360381019061029e9190613c12565b610879565b005b6102bf60048036038101906102ba9190613caa565b610a62565b005b6102db60048036038101906102d69190613b5d565b610baa565b6040516102ed96959493929190613d50565b60405180910390f35b6102fe610c34565b60405161030b9190613dc0565b60405180910390f35b61032e60048036038101906103299190613ddb565b610c41565b005b610338610c6e565b6040516103459190613dc0565b60405180910390f35b61036860048036038101906103639190613c12565b610c74565b6040516103759190613dc0565b60405180910390f35b61039860048036038101906103939190613e2e565b610d19565b6040516103a59190613a51565b60405180910390f35b6103c860048036038101906103c39190613ec0565b61119d565b005b6103e460048036038101906103df9190613b5d565b6113bd565b6040516103f19190613a51565b60405180910390f35b610414600480360381019061040f9190613ddb565b6113dd565b005b610430600480360381019061042b9190613b5d565b61140a565b60405161043d9190613dc0565b60405180910390f35b610460600480360381019061045b9190613f20565b61147b565b005b61047c60048036038101906104779190613fa5565b61154f565b6040516104899190613b05565b60405180910390f35b6104ac60048036038101906104a79190613b5d565b61158e565b6040516104b99190613bcb565b60405180910390f35b6104dc60048036038101906104d79190613fa5565b611639565b6040516104e99190613b05565b60405180910390f35b61050c60048036038101906105079190613ec0565b611697565b005b61052860048036038101906105239190613f20565b6118d9565b6040516105359190613dc0565b60405180910390f35b610546611990565b6040516105539190613b05565b60405180910390f35b6105766004803603810190610571919061400c565b611a1e565b005b610592600480360381019061058d919061404c565b611b1b565b005b6105ae60048036038101906105a99190613fa5565b611b4c565b6040516105bb9190614129565b60405180910390f35b6105de60048036038101906105d9919061414b565b611d49565b005b6105fa60048036038101906105f59190613b5d565b611fc9565b005b61061660048036038101906106119190613b5d565b6120ff565b6040516106239190613b05565b60405180910390f35b6106466004803603810190610641919061419e565b6121e9565b6040516106539190613b05565b60405180910390f35b610664612200565b6040516106719190613dc0565b60405180910390f35b610694600480360381019061068f91906141cb565b612206565b6040516106a1919061421e565b60405180910390f35b6106c460048036038101906106bf919061425b565b612265565b005b6106e060048036038101906106db9190614288565b612352565b6040516106ed9190613a51565b60405180910390f35b610710600480360381019061070b9190613b5d565b612381565b60405161071d9190614129565b60405180910390f35b60006301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061078157506380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806107b15750635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b600080546107c5906142f7565b80601f01602080910402602001604051908101604052809291908181526020018280546107f1906142f7565b801561083e5780601f106108135761010080835404028352916020019161083e565b820191906000526020600020905b81548152906001019060200180831161082157829003601f168201915b505050505081565b60046020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806109715750600560008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b6109b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a790614374565b60405180910390fd5b826004600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b610a6b8261158e565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ad8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610acf90614374565b60405180910390fd5b60011515610ae582610d19565b151514610b27576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1e906143e0565b60405180910390fd5b80600b600084815260200190815260200160002060000160056101000a8154816bffffffffffffffffffffffff021916908360a01c02179055508073ffffffffffffffffffffffffffffffffffffffff1916827fd1464fd210d58c95f829eeb54351bb3b0f9cf4277440f5627f822489a0548cd360405160405180910390a35050565b600b6020528060005260406000206000915090508060000160009054906101000a900460ff16908060000160019054906101000a900460ff16908060000160029054906101000a900460ff16908060000160039054906101000a900460ff16908060000160049054906101000a900460f81b908060000160059054906101000a900460a01b905086565b6000600880549050905090565b610c4a81612450565b610c5483826124ac565b610c5e8282612619565b610c69838383612698565b505050565b600f5481565b6000610c7f836118d9565b8210610cc0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb790614472565b60405180910390fd5b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002054905092915050565b60008060ff60f81b836000600c8110610d3557610d34614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610da35750600060f81b836000600c8110610d7b57610d7a614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8015610e32575060ff60f81b836003600c8110610dc357610dc2614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610e315750600060f81b836003600c8110610e0957610e08614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b8015610ec1575060ff60f81b836006600c8110610e5257610e51614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610ec05750600060f81b836006600c8110610e9857610e97614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b8015610f50575060ff60f81b836009600c8110610ee157610ee0614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610f4f5750600060f81b836009600c8110610f2757610f26614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b90506000600160f81b846002600c8110610f6d57610f6c614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610fdb5750600060f81b846002600c8110610fb357610fb2614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b801561106a5750600160f81b846005600c8110610ffb57610ffa614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806110695750600060f81b846005600c811061104157611040614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b80156110f95750600160f81b846008600c811061108a57611089614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806110f85750600060f81b846008600c81106110d0576110cf614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b80156111885750600160f81b84600b600c811061111957611118614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806111875750600060f81b84600b600c811061115f5761115e614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b5b90508080156111945750815b92505050919050565b600073ffffffffffffffffffffffffffffffffffffffff16601960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff160361122e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112259061450d565b60405180910390fd5b60011515601b600085815260200190815260200160002060009054906101000a900460ff16151514611295576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128c9061459f565b60405180910390fd5b601960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611325576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161131c9061460b565b60405180910390fd5b600080600061137785858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a97565b9250925092506113b58360ff168360ff1683600b60008b815260200190815260200160002060000160039054906101000a900460ff1660ff16612ab8565b505050505050565b601b6020528060005260406000206000915054906101000a900460ff1681565b6113e681612450565b6113f083826124ac565b6113fa8282612619565b611405838383612b1d565b505050565b6000611414610c34565b8210611455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144c9061469d565b60405180910390fd5b6008828154811061146957611468614492565b5b90600052602060002001549050919050565b601a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461150b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161150290614374565b60405180910390fd5b80601960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b606061156561156086868686611b4c565b612c55565b6040516020016115759190614745565b6040516020818303038152906040529050949350505050565b60008073ffffffffffffffffffffffffffffffffffffffff166002600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691508173ffffffffffffffffffffffffffffffffffffffff1603611634576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161162b906147b3565b60405180910390fd5b919050565b606061166e61164a8686868661154f565b60405160200161165a9190614a59565b604051602081830303815290604052612c55565b60405160200161167e9190614ad2565b6040516020818303038152906040529050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff16601960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603611728576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161171f9061450d565b60405180910390fd5b60011515601b600085815260200190815260200160002060009054906101000a900460ff1615151461178f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117869061459f565b60405180910390fd5b601960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461181f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118169061460b565b60405180910390fd5b60008061186f84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a97565b509150915081600b600087815260200190815260200160002060000160006101000a81548160ff021916908360ff16021790555080600b600087815260200190815260200160002060000160016101000a81548160ff021916908360ff1602179055505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611949576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161194090614b40565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6001805461199d906142f7565b80601f01602080910402602001604051908101604052809291908181526020018280546119c9906142f7565b8015611a165780601f106119eb57610100808354040283529160200191611a16565b820191906000526020600020905b8154815290600101906020018083116119f957829003601f168201915b505050505081565b80600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611b0f9190613a51565b60405180910390a35050565b611b2483612450565b611b2e85846124ac565b611b388484612619565b611b458585858585612dcd565b5050505050565b606060006040518061046001604052806104368152602001615ac461043691399050600061510067ffffffffffffffff811115611b8c57611b8b614b60565b5b6040519080825280601f01601f191660200182016040528015611bbe5781602001600182028036833780820191505090505b50905060005b6090811015611cb25760005b6090811015611ca0576000816090611be89190614bbe565b83611bf39190614c18565b9050600a60008b60ff1681526020019081526020016000206000018360908110611c2057611c1f614492565b5b600502018260908110611c3657611c35614492565b5b602091828204019190069054906101000a900460f81b848281518110611c5f57611c5e614492565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505080611c9990614c6e565b9050611bd0565b5080611cab90614c6e565b9050611bc4565b506001151584151503611d2a5760008560ff166090611cd19190614bbe565b8760ff16611cdf9190614c18565b905060a560f81b828281518110611cf957611cf8614492565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350505b611d3d8183612f0b90919063ffffffff16565b92505050949350505050565b600f54600e5410611d8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d8690614d02565b60405180910390fd5b60011515611d9c83610d19565b151514611dde576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dd5906143e0565b60405180910390fd5b601860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611e6e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e6590614d6e565b60405180910390fd5b60016004600e54611e7f9190614dbd565b611e899190614c18565b600d81905550600060106004600e54611ea29190614dee565b60048110611eb357611eb2614492565b5b01549050600060146004600e54611eca9190614dee565b60048110611edb57611eda614492565b5b01549050611eeb85600e54612619565b611ef6600e54612f95565b611f0285600e54612fde565b611f15600e5483836001600d54896131f0565b8373ffffffffffffffffffffffffffffffffffffffff1916600e547f66e34e24596794eb9fbba61ddf385dbbc89563ac1f0250e6587c2ac6c039481d600d54604051611f619190613dc0565b60405180910390a36000831115611f7f57611f7e600e5484613354565b5b6000601b6000600e54815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600e54611fbc9190614c18565b600e819055505050505050565b600073ffffffffffffffffffffffffffffffffffffffff16601960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff160361205a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120519061450d565b60405180910390fd5b6120638161158e565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146120d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120c790614374565b60405180910390fd5b6001601b600083815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60606121e282600b600085815260200190815260200160002060000160039054906101000a900460ff16600b600086815260200190815260200160002060000160059054906101000a900460a01b600b600087815260200190815260200160002060000160049054906101000a900460f81b600b600088815260200190815260200160002060000160009054906101000a900460ff16600b600089815260200190815260200160002060000160019054906101000a900460ff16600b60008a815260200190815260200160002060000160029054906101000a900460ff1661362c565b9050919050565b60606121f9826000806000611639565b9050919050565b600d5481565b6000600a600083815260200190815260200160002060000184609081106122305761222f614492565b5b60050201836090811061224657612245614492565b5b602091828204019190069054906101000a900460f81b90509392505050565b6122868160006002811061227c5761227b614492565b5b602002013561158e565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122ea90614374565b60405180910390fd5b60008160016002811061230957612308614492565b5b6020020135111561234f5761234e8160006002811061232b5761232a614492565b5b60200201358260016002811061234457612343614492565b5b6020020135613354565b5b50565b60056020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b6060600080600080602067ffffffffffffffff8111156123a4576123a3614b60565b5b6040519080825280601f01601f1916602001820160405280156123d65781602001600182028036833780820191505090505b5090506000600b600088815260200190815260200160002090508054945060ff8516935060ff8560081c169250600061242e8560ff168560ff16600160048c61241f9190614dbd565b6124299190614c18565b612206565b9050846020840153836021840153806022840152829650505050505050919050565b60011515601b600083815260200190815260200160002060009054906101000a900460ff161515036124a9576000601b600083815260200190815260200160002060006101000a81548160ff0219169083151502179055505b50565b600060016124b9846118d9565b6124c39190614e1f565b90506000600760008481526020019081526020016000205490508181146125a8576000600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002054905080600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002081905550816007600083815260200190815260200160002081905550505b6007600084815260200190815260200160002060009055600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000905550505050565b6000612624836118d9565b905081600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002081905550806007600084815260200190815260200160002081905550505050565b6002600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614612739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161273090614e9f565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036127a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161279f90614f0b565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806128685750600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b806128d157506004600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b612910576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161290790614374565b60405180910390fd5b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600190039190505550600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906001019190505550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506004600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b60008060006001840151925060028401519150602284015190509193909250565b81600a60008381526020019081526020016000206000018560908110612ae157612ae0614492565b5b600502018460908110612af757612af6614492565b5b602091828204019190066101000a81548160ff021916908360f81c021790555050505050565b612b28838383610c41565b60008273ffffffffffffffffffffffffffffffffffffffff163b1480612c11575063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168273ffffffffffffffffffffffffffffffffffffffff1663150b7a023386856040518463ffffffff1660e01b8152600401612bad93929190614f51565b6020604051808303816000875af1158015612bcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf09190614fb0565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b612c50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c4790615029565b60405180910390fd5b505050565b60606000825103612c7757604051806020016040528060008152509050612dc8565b6000604051806060016040528060408152602001615a846040913990506000600360028551612ca69190614c18565b612cb09190614dbd565b6004612cbc9190614bbe565b90506000602082612ccd9190614c18565b67ffffffffffffffff811115612ce657612ce5614b60565b5b6040519080825280601f01601f191660200182016040528015612d185781602001600182028036833780820191505090505b509050818152600183018586518101602084015b81831015612d87576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f8116850151825360018201915050612d2c565b600389510660018114612da15760028114612db157612dbc565b613d3d60f01b6002830352612dbc565b603d60f81b60018303525b50505050508093505050505b919050565b612dd8858585610c41565b60008473ffffffffffffffffffffffffffffffffffffffff163b1480612ec5575063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168473ffffffffffffffffffffffffffffffffffffffff1663150b7a0233888787876040518663ffffffff1660e01b8152600401612e61959493929190615085565b6020604051808303816000875af1158015612e80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ea49190614fb0565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b612f04576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612efb90615029565b60405180910390fd5b5050505050565b6060806040519050835180825260208201818101602087015b81831015612f415780518352602083019250602081019050612f24565b50855192508351830184528091508282019050602086015b81831015612f765780518352602083019250602081019050612f59565b50601f19601f8851850115830101166040525050508091505092915050565b6008805490506009600083815260200190815260200160002081905550600881908060018154018082558091505060019003906000526020600020016000909190919091505550565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361304d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161304490614f0b565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146130ef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130e69061511f565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906001019190505550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050565b60006040518060c001604052808760ff1681526020018660ff1681526020018560ff1681526020018460ff168152602001827effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020018373ffffffffffffffffffffffffffffffffffffffff1916815250600b600089815260200190815260200160002060008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548160ff021916908360ff16021790555060408201518160000160026101000a81548160ff021916908360ff16021790555060608201518160000160036101000a81548160ff021916908360ff16021790555060808201518160000160046101000a81548160ff021916908360f81c021790555060a08201518160000160056101000a8154816bffffffffffffffffffffffff021916908360a01c021790555090505050505050505050565b600080600080600080600b600089815260200190815260200160002090508054915060005b878110156135ec5760ff8316955060ff8360081c1694508260181c935060006133ac8760ff168760ff168760ff16612206565b905070ffffffffffffffffffffffff0000000000841660ff8560101c16600080600064ff00000000891660201c1460008660f81c141615613400578360781b9b5060ff8460781c16905060ff8460701c1691505b600064ff00000000891660201c1460ff8660f81c141615613434578360901b9b5060ff8460601c16905060ff8460581c1691505b600164ff00000000891660201c1460008660f81c141615613468578360a81b9b5060ff8460481c16905060ff8460401c1691505b600164ff00000000891660201c1460ff8660f81c14161561349c578360c01b9b5060ff8460301c16905060ff8460281c1691505b600081600281146134bf57600881146134cc57600481146134ee578491506134f8565b60046001860891506134f8565b84600081146134e3576004600187030692506134e8565b600392505b506134f8565b6004600286010691505b50604051816000811461352257600281146135385760038114613569576001811461357f576135ac565b609060018f08601f8301538c601e8301536135ac565b8d600081146135555760018f03601f8401538d601e840153613563565b608f601f8401538d601e8401535b506135ac565b8d601f830153609060018e08601e8301536135ac565b8c6000811461359c578e601f84015360018e03601e8401536135aa565b8e601f840153608f601e8401535b505b5081601d8201538a601c82015383601b8201538581511799505050505050506135e08760ff168760ff168a8860ff16612ab8565b60018201915050613379565b50818155868360ff16897fbbe0aa2504840f3cabeaa7c222bc975ed888abf937945ff374653c8d57c55fbb60405160405180910390a45050505050505050565b606061367c61363b89896136a8565b6136488987876001611639565b6136568a8a8a8a8a8a6136e7565b60405160200161366893929190615353565b604051602081830303815290604052612c55565b60405160200161368c919061541d565b6040516020818303038152906040529050979650505050505050565b60606136b383613764565b6136bf8360ff16613764565b6040516020016136d09291906154d7565b604051602081830303815290604052905092915050565b60606136f58760ff16613764565b6136fe876137b4565b61370d8760f81c60ff16613764565b6137198760ff16613764565b6137258760ff16613764565b6137318760ff16613764565b600c60405160200161374997969594939291906158c7565b60405160208183030381529060405290509695505050505050565b606060a060405101806040526020810391506000825281835b60011561379f57600184039350600a81066030018453600a810490508061377d575b50828103602084039350808452505050919050565b6060600080601867ffffffffffffffff8111156137d4576137d3614b60565b5b6040519080825280601f01601f1916602001820160405280156138065781602001600182028036833780820191505090505b509050600091505b80518260ff161015613960576000600f60f81b8560028561382f91906159f2565b60ff16600c811061384357613842614492565b5b1a60f81b1660f81c9050600060048660028661385f91906159f2565b60ff16600c811061387357613872614492565b5b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916901c60f81c90506138a98161396a565b838560ff16815181106138bf576138be614492565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506001846138fb9190615a23565b93506139068261396a565b838560ff168151811061391c5761391b614492565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505050818061395890615a5a565b92505061380e565b8092505050919050565b6000600a8260ff16101561398f576030826139859190615a23565b60f81b90506139a2565b60578261399c9190615a23565b60f81b90505b919050565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6139e6816139b1565b81146139f157600080fd5b50565b600081359050613a03816139dd565b92915050565b600060208284031215613a1f57613a1e6139a7565b5b6000613a2d848285016139f4565b91505092915050565b60008115159050919050565b613a4b81613a36565b82525050565b6000602082019050613a666000830184613a42565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613aa6578082015181840152602081019050613a8b565b83811115613ab5576000848401525b50505050565b6000601f19601f8301169050919050565b6000613ad782613a6c565b613ae18185613a77565b9350613af1818560208601613a88565b613afa81613abb565b840191505092915050565b60006020820190508181036000830152613b1f8184613acc565b905092915050565b6000819050919050565b613b3a81613b27565b8114613b4557600080fd5b50565b600081359050613b5781613b31565b92915050565b600060208284031215613b7357613b726139a7565b5b6000613b8184828501613b48565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613bb582613b8a565b9050919050565b613bc581613baa565b82525050565b6000602082019050613be06000830184613bbc565b92915050565b613bef81613baa565b8114613bfa57600080fd5b50565b600081359050613c0c81613be6565b92915050565b60008060408385031215613c2957613c286139a7565b5b6000613c3785828601613bfd565b9250506020613c4885828601613b48565b9150509250929050565b60007fffffffffffffffffffffffff000000000000000000000000000000000000000082169050919050565b613c8781613c52565b8114613c9257600080fd5b50565b600081359050613ca481613c7e565b92915050565b60008060408385031215613cc157613cc06139a7565b5b6000613ccf85828601613b48565b9250506020613ce085828601613c95565b9150509250929050565b600060ff82169050919050565b613d0081613cea565b82525050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b613d3b81613d06565b82525050565b613d4a81613c52565b82525050565b600060c082019050613d656000830189613cf7565b613d726020830188613cf7565b613d7f6040830187613cf7565b613d8c6060830186613cf7565b613d996080830185613d32565b613da660a0830184613d41565b979650505050505050565b613dba81613b27565b82525050565b6000602082019050613dd56000830184613db1565b92915050565b600080600060608486031215613df457613df36139a7565b5b6000613e0286828701613bfd565b9350506020613e1386828701613bfd565b9250506040613e2486828701613b48565b9150509250925092565b600060208284031215613e4457613e436139a7565b5b6000613e5284828501613c95565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112613e8057613e7f613e5b565b5b8235905067ffffffffffffffff811115613e9d57613e9c613e60565b5b602083019150836001820283011115613eb957613eb8613e65565b5b9250929050565b600080600060408486031215613ed957613ed86139a7565b5b6000613ee786828701613b48565b935050602084013567ffffffffffffffff811115613f0857613f076139ac565b5b613f1486828701613e6a565b92509250509250925092565b600060208284031215613f3657613f356139a7565b5b6000613f4484828501613bfd565b91505092915050565b613f5681613cea565b8114613f6157600080fd5b50565b600081359050613f7381613f4d565b92915050565b613f8281613a36565b8114613f8d57600080fd5b50565b600081359050613f9f81613f79565b92915050565b60008060008060808587031215613fbf57613fbe6139a7565b5b6000613fcd87828801613f64565b9450506020613fde87828801613f64565b9350506040613fef87828801613f64565b925050606061400087828801613f90565b91505092959194509250565b60008060408385031215614023576140226139a7565b5b600061403185828601613bfd565b925050602061404285828601613f90565b9150509250929050565b600080600080600060808688031215614068576140676139a7565b5b600061407688828901613bfd565b955050602061408788828901613bfd565b945050604061409888828901613b48565b935050606086013567ffffffffffffffff8111156140b9576140b86139ac565b5b6140c588828901613e6a565b92509250509295509295909350565b600081519050919050565b600082825260208201905092915050565b60006140fb826140d4565b61410581856140df565b9350614115818560208601613a88565b61411e81613abb565b840191505092915050565b6000602082019050818103600083015261414381846140f0565b905092915050565b600080600060608486031215614164576141636139a7565b5b600061417286828701613bfd565b935050602061418386828701613c95565b925050604061419486828701613b48565b9150509250925092565b6000602082840312156141b4576141b36139a7565b5b60006141c284828501613f64565b91505092915050565b6000806000606084860312156141e4576141e36139a7565b5b60006141f286828701613b48565b935050602061420386828701613b48565b925050604061421486828701613b48565b9150509250925092565b60006020820190506142336000830184613d32565b92915050565b60008190508260206002028201111561425557614254613e65565b5b92915050565b600060408284031215614271576142706139a7565b5b600061427f84828501614239565b91505092915050565b6000806040838503121561429f5761429e6139a7565b5b60006142ad85828601613bfd565b92505060206142be85828601613bfd565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061430f57607f821691505b602082108103614322576143216142c8565b5b50919050565b7f4e4f545f415554484f52495a4544000000000000000000000000000000000000600082015250565b600061435e600e83613a77565b915061436982614328565b602082019050919050565b6000602082019050818103600083015261438d81614351565b9050919050565b7f494e56414c49445f52554c450000000000000000000000000000000000000000600082015250565b60006143ca600c83613a77565b91506143d582614394565b602082019050919050565b600060208201905081810360008301526143f9816143bd565b9050919050565b7f455243373231456e756d657261626c653a206f776e657220696e646578206f7560008201527f74206f6620626f756e6473000000000000000000000000000000000000000000602082015250565b600061445c602b83613a77565b915061446782614400565b604082019050919050565b6000602082019050818103600083015261448b8161444f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f434f4e54524143545f49535f5a45524f41444452455353000000000000000000600082015250565b60006144f7601783613a77565b9150614502826144c1565b602082019050919050565b60006020820190508181036000830152614526816144ea565b9050919050565b7f434f4e54524143545f4e4f545f494e4954414c495a45445f42595f4e46545f4f60008201527f574e455200000000000000000000000000000000000000000000000000000000602082015250565b6000614589602483613a77565b91506145948261452d565b604082019050919050565b600060208201905081810360008301526145b88161457c565b9050919050565b7f43414c4c5f4f4e4c595f46524f4d5f4841434f4e545241435400000000000000600082015250565b60006145f5601983613a77565b9150614600826145bf565b602082019050919050565b60006020820190508181036000830152614624816145e8565b9050919050565b7f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60008201527f7574206f6620626f756e64730000000000000000000000000000000000000000602082015250565b6000614687602c83613a77565b91506146928261462b565b604082019050919050565b600060208201905081810360008301526146b68161467a565b9050919050565b600081905092915050565b7f646174613a696d6167652f626d703b6261736536342c00000000000000000000600082015250565b60006146fe6016836146bd565b9150614709826146c8565b601682019050919050565b600061471f82613a6c565b61472981856146bd565b9350614739818560208601613a88565b80840191505092915050565b6000614750826146f1565b915061475c8284614714565b915081905092915050565b7f4e4f545f4d494e54454400000000000000000000000000000000000000000000600082015250565b600061479d600a83613a77565b91506147a882614767565b602082019050919050565b600060208201905081810360008301526147cc81614790565b9050919050565b7f3c73766720636c6173733d227376674247472220786d6c6e733d22687474703a60008201527f2f2f7777772e77332e6f72672f323030302f737667222076657273696f6e3d2260208201527f312e31222077696474683d2235303022206865696768743d22353030223e3c6460408201527f6566732069643d22736f6d6544656673223e3c7374796c652069643d2273747960608201527f6c6531393939223e202e737667424747207b2077696474683a2035303070783b60808201527f6865696768743a2035303070783b6261636b67726f756e642d696d6167653a2060a08201527f75726c280000000000000000000000000000000000000000000000000000000060c082015250565b60006148ed60c4836146bd565b91506148f8826147d3565b60c482019050919050565b7f293b206261636b67726f756e642d7265706561743a206e6f2d7265706561743b60008201527f206261636b67726f756e642d73697a653a20313030253b20696d6167652d726560208201527f6e646572696e673a202d7765626b69742d6f7074696d697a652d636f6e74726160408201527f73743b202d6d732d696e746572706f6c6174696f6e2d6d6f64653a206e65617260608201527f6573742d6e65696768626f723b20696d6167652d72656e646572696e673a202d60808201527f6d6f7a2d63726973702d65646765733b20696d6167652d72656e646572696e6760a08201527f3a20706978656c617465643b7d3c2f7374796c653e3c2f646566733e3c2f737660c08201527f673e00000000000000000000000000000000000000000000000000000000000060e082015250565b6000614a4360e2836146bd565b9150614a4e82614903565b60e282019050919050565b6000614a64826148e0565b9150614a708284614714565b9150614a7b82614a36565b915081905092915050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000600082015250565b6000614abc601a836146bd565b9150614ac782614a86565b601a82019050919050565b6000614add82614aaf565b9150614ae98284614714565b915081905092915050565b7f5a45524f5f414444524553530000000000000000000000000000000000000000600082015250565b6000614b2a600c83613a77565b9150614b3582614af4565b602082019050919050565b60006020820190508181036000830152614b5981614b1d565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614bc982613b27565b9150614bd483613b27565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614c0d57614c0c614b8f565b5b828202905092915050565b6000614c2382613b27565b9150614c2e83613b27565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115614c6357614c62614b8f565b5b828201905092915050565b6000614c7982613b27565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614cab57614caa614b8f565b5b600182019050919050565b7f4d494e545f4f5645520000000000000000000000000000000000000000000000600082015250565b6000614cec600983613a77565b9150614cf782614cb6565b602082019050919050565b60006020820190508181036000830152614d1b81614cdf565b9050919050565b7f4f4e4c595f4d494e5441424c455f46524f4d5f4d494e545f434f4e5452414354600082015250565b6000614d58602083613a77565b9150614d6382614d22565b602082019050919050565b60006020820190508181036000830152614d8781614d4b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000614dc882613b27565b9150614dd383613b27565b925082614de357614de2614d8e565b5b828204905092915050565b6000614df982613b27565b9150614e0483613b27565b925082614e1457614e13614d8e565b5b828206905092915050565b6000614e2a82613b27565b9150614e3583613b27565b925082821015614e4857614e47614b8f565b5b828203905092915050565b7f57524f4e475f46524f4d00000000000000000000000000000000000000000000600082015250565b6000614e89600a83613a77565b9150614e9482614e53565b602082019050919050565b60006020820190508181036000830152614eb881614e7c565b9050919050565b7f494e56414c49445f524543495049454e54000000000000000000000000000000600082015250565b6000614ef5601183613a77565b9150614f0082614ebf565b602082019050919050565b60006020820190508181036000830152614f2481614ee8565b9050919050565b50565b6000614f3b6000836140df565b9150614f4682614f2b565b600082019050919050565b6000608082019050614f666000830186613bbc565b614f736020830185613bbc565b614f806040830184613db1565b8181036060830152614f9181614f2e565b9050949350505050565b600081519050614faa816139dd565b92915050565b600060208284031215614fc657614fc56139a7565b5b6000614fd484828501614f9b565b91505092915050565b7f554e534146455f524543495049454e5400000000000000000000000000000000600082015250565b6000615013601083613a77565b915061501e82614fdd565b602082019050919050565b6000602082019050818103600083015261504281615006565b9050919050565b82818337600083830152505050565b600061506483856140df565b9350615071838584615049565b61507a83613abb565b840190509392505050565b600060808201905061509a6000830188613bbc565b6150a76020830187613bbc565b6150b46040830186613db1565b81810360608301526150c7818486615058565b90509695505050505050565b7f414c52454144595f4d494e544544000000000000000000000000000000000000600082015250565b6000615109600e83613a77565b9150615114826150d3565b602082019050919050565b60006020820190508181036000830152615138816150fc565b9050919050565b7f7b226e616d65223a220000000000000000000000000000000000000000000000600082015250565b60006151756009836146bd565b91506151808261513f565b600982019050919050565b7f222c20226465736372697074696f6e223a220000000000000000000000000000600082015250565b60006151c16012836146bd565b91506151cc8261518b565b601282019050919050565b7f4f6e636861696e204d757469706c617965722041727400000000000000000000600082015250565b600061520d6016836146bd565b9150615218826151d7565b601682019050919050565b7f222c2022696d616765223a202200000000000000000000000000000000000000600082015250565b6000615259600d836146bd565b915061526482615223565b600d82019050919050565b7f222c000000000000000000000000000000000000000000000000000000000000600082015250565b60006152a56002836146bd565b91506152b08261526f565b600282019050919050565b7f2261747472696275746573223a20000000000000000000000000000000000000600082015250565b60006152f1600e836146bd565b91506152fc826152bb565b600e82019050919050565b7f7d00000000000000000000000000000000000000000000000000000000000000600082015250565b600061533d6001836146bd565b915061534882615307565b600182019050919050565b600061535e82615168565b915061536a8286614714565b9150615375826151b4565b915061538082615200565b915061538b8261524c565b91506153978285614714565b91506153a282615298565b91506153ad826152e4565b91506153b98284614714565b91506153c482615330565b9150819050949350505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000600082015250565b6000615407601d836146bd565b9150615412826153d1565b601d82019050919050565b6000615428826153fa565b91506154348284614714565b915081905092915050565b7f5475726d69746520000000000000000000000000000000000000000000000000600082015250565b60006154756008836146bd565b91506154808261543f565b600882019050919050565b7f20576f726c642000000000000000000000000000000000000000000000000000600082015250565b60006154c16007836146bd565b91506154cc8261548b565b600782019050919050565b60006154e282615468565b91506154ee8285614714565b91506154f9826154b4565b91506155058284614714565b91508190509392505050565b7f5b7b2274726169745f74797065223a22576f726c64222c2276616c7565223a22600082015250565b60006155476020836146bd565b915061555282615511565b602082019050919050565b7f227d2c0000000000000000000000000000000000000000000000000000000000600082015250565b60006155936003836146bd565b915061559e8261555d565b600382019050919050565b7f7b2274726169745f74797065223a2252756c65222c0000000000000000000000600082015250565b60006155df6015836146bd565b91506155ea826155a9565b601582019050919050565b7f2276616c7565223a220000000000000000000000000000000000000000000000600082015250565b600061562b6009836146bd565b9150615636826155f5565b600982019050919050565b7f7b2274726169745f74797065223a225374617465222c00000000000000000000600082015250565b60006156776016836146bd565b915061568282615641565b601682019050919050565b7f7b2274726169745f74797065223a22504f532058222c00000000000000000000600082015250565b60006156c36016836146bd565b91506156ce8261568d565b601682019050919050565b7f7b2274726169745f74797065223a22504f532059222c00000000000000000000600082015250565b600061570f6016836146bd565b915061571a826156d9565b601682019050919050565b7f7b2274726169745f74797065223a22446972656374696f6e222c000000000000600082015250565b600061575b601a836146bd565b915061576682615725565b601a82019050919050565b7f227d2c7b2274726169745f74797065223a224e6574776f726b222c2276616c7560008201527f65223a2200000000000000000000000000000000000000000000000000000000602082015250565b60006157cd6024836146bd565b91506157d882615771565b602482019050919050565b60008190508160005260206000209050919050565b60008154615805816142f7565b61580f81866146bd565b9450600182166000811461582a576001811461583f57615872565b60ff1983168652811515820286019350615872565b615848856157e3565b60005b8381101561586a5781548189015260018201915060208101905061584b565b838801955050505b50505092915050565b7f227d5d0000000000000000000000000000000000000000000000000000000000600082015250565b60006158b16003836146bd565b91506158bc8261587b565b600382019050919050565b60006158d28261553a565b91506158de828a614714565b91506158e982615586565b91506158f4826155d2565b91506158ff8261561e565b915061590b8289614714565b915061591682615586565b91506159218261566a565b915061592c8261561e565b91506159388288614714565b915061594382615586565b915061594e826156b6565b91506159598261561e565b91506159658287614714565b915061597082615586565b915061597b82615702565b91506159868261561e565b91506159928286614714565b915061599d82615586565b91506159a88261574e565b91506159b38261561e565b91506159bf8285614714565b91506159ca826157c0565b91506159d682846157f8565b91506159e1826158a4565b915081905098975050505050505050565b60006159fd82613cea565b9150615a0883613cea565b925082615a1857615a17614d8e565b5b828204905092915050565b6000615a2e82613cea565b9150615a3983613cea565b92508260ff03821115615a4f57615a4e614b8f565b5b828201905092915050565b6000615a6582613cea565b915060ff8203615a7857615a77614b8f565b5b60018201905091905056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f424d385500000000000036040000280000009000000090000000010008000000000002510000120b0000120b00000000000000000000000000000101010002020200030303000404040005050500060606000707070008080800090909000a0a0a000b0b0b000c0c0c000d0d0d000e0e0e000f0f0f00101010001111110012121200131313001414140015151500161616001717170018181800191919001a1a1a001b1b1b001c1c1c001d1d1d001e1e1e001f1f1f00202020002121210022222200232323002424240025252500262626002727270028282800292929002a2a2a002b2b2b002c2c2c002d2d2d002e2e2e002f2f2f00303030003131310032323200333333003434340035353500363636003737370038383800393939003a3a3a003b3b3b003c3c3c003d3d3d003e3e3e003f3f3f00404040004141410042424200434343004444440045454500464646004747470048484800494949004a4a4a004b4b4b004c4c4c004d4d4d004e4e4e004f4f4f00505050005151510052525200535353005454540055555500565656005757570058585800595959005a5a5a005b5b5b005c5c5c005d5d5d005e5e5e005f5f5f00606060006161610062626200636363006464640065656500666666006767670068686800696969006a6a6a006b6b6b006c6c6c006d6d6d006e6e6e006f6f6f00707070007171710072727200737373007474740075757500767676007777770078787800797979007a7a7a007b7b7b007c7c7c007d7d7d007e7e7e007f7f7f00808080008181810082828200838383008484840085858500868686008787870088888800898989008a8a8a008b8b8b008c8c8c008d8d8d008e8e8e008f8f8f00909090009191910092929200939393009494940095959500969696009797970098989800999999009a9a9a009b9b9b009c9c9c009d9d9d009e9e9e009f9f9f00a0a0a000a1a1a100a2a2a200a3a3a300a4a4a400a5a5a500a6a6a600a7a7a700a8a8a800a9a9a900aaaaaa00ababab00acacac00adadad00aeaeae00afafaf00b0b0b000b1b1b100b2b2b200b3b3b300b4b4b400b5b5b500b6b6b600b7b7b700b8b8b800b9b9b900bababa00bbbbbb00bcbcbc00bdbdbd00bebebe00bfbfbf00c0c0c000c1c1c100c2c2c200c3c3c300c4c4c400c5c5c500c6c6c600c7c7c700c8c8c800c9c9c900cacaca00cbcbcb00cccccc00cdcdcd00cecece00cfcfcf00d0d0d000d1d1d100d2d2d200d3d3d300d4d4d400d5d5d500d6d6d600d7d7d700d8d8d800d9d9d900dadada00dbdbdb00dcdcdc00dddddd00dedede00dfdfdf00e0e0e000e1e1e100e2e2e200e3e3e300e4e4e400e5e5e500e6e6e600e7e7e700e8e8e800e9e9e900eaeaea00ebebeb00ececec00ededed00eeeeee00efefef00f0f0f000f1f1f100f2f2f200f3f3f300f4f4f400f5f5f500f6f6f600f7f7f700f8f8f800f9f9f900fafafa00fbfbfb00fcfcfc00fdfdfd00fefefe00ffffff00a2646970667358221220792abd84e85ae7339fc7811867b48b0df27583811acd0908f337fe392af9356364736f6c634300080f0033

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

OVERVIEW

An on-chain, generative, multiplayer NFT-game by artist **Paul Seidler** (terra0) on Ethereum and [Optimism](https://opensea.io/collection/straylight-protocol-optimism) networks ~ presented by [folia](https://folia.app) In Straylight, players mint NFT-turmite “agents” that ...

Loading...
Loading
[ 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.