ETH Price: $3,026.95 (+2.28%)
Gas: 2 Gwei

Token

War Riders Gun (WRG)
 

Overview

Max Total Supply

4,903 WRG

Holders

155

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A

Other Info

Balance
4 WRG
0xaec539a116fa75e8bdcf016d3c146a25bc1af93b
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

War Riders Gun token contract has migrated to 0x2d6e10561b320c4f31a903bf0fa92a1ed58637c0.

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
GunToken

Compiler Version
v0.5.11+commit.c082d0b4

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2019-10-18
*/

pragma solidity ^0.5.5;

library strings {
    struct slice {
        uint _len;
        uint _ptr;
    }

    function memcpy(uint dest, uint src, uint len) private pure {
        // Copy word-length chunks while possible
        for(; len >= 32; len -= 32) {
            assembly {
                mstore(dest, mload(src))
            }
            dest += 32;
            src += 32;
        }

        // Copy remaining bytes
        uint mask = 256 ** (32 - len) - 1;
        assembly {
            let srcpart := and(mload(src), not(mask))
            let destpart := and(mload(dest), mask)
            mstore(dest, or(destpart, srcpart))
        }
    }

    /*
     * @dev Returns a slice containing the entire string.
     * @param self The string to make a slice from.
     * @return A newly allocated slice containing the entire string.
     */
    function toSlice(string memory self) internal pure returns (slice memory) {
        uint ptr;
        assembly {
            ptr := add(self, 0x20)
        }
        return slice(bytes(self).length, ptr);
    }

    /*
     * @dev Returns the length of a null-terminated bytes32 string.
     * @param self The value to find the length of.
     * @return The length of the string, from 0 to 32.
     */
    function len(bytes32 self) internal pure returns (uint) {
        uint ret;
        if (self == 0)
            return 0;
        if (uint(self) & 0xffffffffffffffffffffffffffffffff == 0) {
            ret += 16;
            self = bytes32(uint(self) / 0x100000000000000000000000000000000);
        }
        if (uint(self) & 0xffffffffffffffff == 0) {
            ret += 8;
            self = bytes32(uint(self) / 0x10000000000000000);
        }
        if (uint(self) & 0xffffffff == 0) {
            ret += 4;
            self = bytes32(uint(self) / 0x100000000);
        }
        if (uint(self) & 0xffff == 0) {
            ret += 2;
            self = bytes32(uint(self) / 0x10000);
        }
        if (uint(self) & 0xff == 0) {
            ret += 1;
        }
        return 32 - ret;
    }

    /*
     * @dev Returns a slice containing the entire bytes32, interpreted as a
     *      null-terminated utf-8 string.
     * @param self The bytes32 value to convert to a slice.
     * @return A new slice containing the value of the input argument up to the
     *         first null.
     */
    function toSliceB32(bytes32 self) internal pure returns (slice memory ret) {
        // Allocate space for `self` in memory, copy it there, and point ret at it
        assembly {
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x20))
            mstore(ptr, self)
            mstore(add(ret, 0x20), ptr)
        }
        ret._len = len(self);
    }

    /*
     * @dev Returns a new slice containing the same data as the current slice.
     * @param self The slice to copy.
     * @return A new slice containing the same data as `self`.
     */
    function copy(slice memory self) internal pure returns (slice memory) {
        return slice(self._len, self._ptr);
    }

    /*
     * @dev Copies a slice to a new string.
     * @param self The slice to copy.
     * @return A newly allocated string containing the slice's text.
     */
    function toString(slice memory self) internal pure returns (string memory) {
        string memory ret = new string(self._len);
        uint retptr;
        assembly { retptr := add(ret, 32) }

        memcpy(retptr, self._ptr, self._len);
        return ret;
    }

    /*
     * @dev Returns the length in runes of the slice. Note that this operation
     *      takes time proportional to the length of the slice; avoid using it
     *      in loops, and call `slice.empty()` if you only need to know whether
     *      the slice is empty or not.
     * @param self The slice to operate on.
     * @return The length of the slice in runes.
     */
    function len(slice memory self) internal pure returns (uint l) {
        // Starting at ptr-31 means the LSB will be the byte we care about
        uint ptr = self._ptr - 31;
        uint end = ptr + self._len;
        for (l = 0; ptr < end; l++) {
            uint8 b;
            assembly { b := and(mload(ptr), 0xFF) }
            if (b < 0x80) {
                ptr += 1;
            } else if(b < 0xE0) {
                ptr += 2;
            } else if(b < 0xF0) {
                ptr += 3;
            } else if(b < 0xF8) {
                ptr += 4;
            } else if(b < 0xFC) {
                ptr += 5;
            } else {
                ptr += 6;
            }
        }
    }

    /*
     * @dev Returns true if the slice is empty (has a length of 0).
     * @param self The slice to operate on.
     * @return True if the slice is empty, False otherwise.
     */
    function empty(slice memory self) internal pure returns (bool) {
        return self._len == 0;
    }

    /*
     * @dev Returns a positive number if `other` comes lexicographically after
     *      `self`, a negative number if it comes before, or zero if the
     *      contents of the two slices are equal. Comparison is done per-rune,
     *      on unicode codepoints.
     * @param self The first slice to compare.
     * @param other The second slice to compare.
     * @return The result of the comparison.
     */
    function compare(slice memory self, slice memory other) internal pure returns (int) {
        uint shortest = self._len;
        if (other._len < self._len)
            shortest = other._len;

        uint selfptr = self._ptr;
        uint otherptr = other._ptr;
        for (uint idx = 0; idx < shortest; idx += 32) {
            uint a;
            uint b;
            assembly {
                a := mload(selfptr)
                b := mload(otherptr)
            }
            if (a != b) {
                // Mask out irrelevant bytes and check again
                uint256 mask = uint256(-1); // 0xffff...
                if(shortest < 32) {
                  mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
                }
                uint256 diff = (a & mask) - (b & mask);
                if (diff != 0)
                    return int(diff);
            }
            selfptr += 32;
            otherptr += 32;
        }
        return int(self._len) - int(other._len);
    }

    /*
     * @dev Returns true if the two slices contain the same text.
     * @param self The first slice to compare.
     * @param self The second slice to compare.
     * @return True if the slices are equal, false otherwise.
     */
    function equals(slice memory self, slice memory other) internal pure returns (bool) {
        return compare(self, other) == 0;
    }

    /*
     * @dev Extracts the first rune in the slice into `rune`, advancing the
     *      slice to point to the next rune and returning `self`.
     * @param self The slice to operate on.
     * @param rune The slice that will contain the first rune.
     * @return `rune`.
     */
    function nextRune(slice memory self, slice memory rune) internal pure returns (slice memory) {
        rune._ptr = self._ptr;

        if (self._len == 0) {
            rune._len = 0;
            return rune;
        }

        uint l;
        uint b;
        // Load the first byte of the rune into the LSBs of b
        assembly { b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF) }
        if (b < 0x80) {
            l = 1;
        } else if(b < 0xE0) {
            l = 2;
        } else if(b < 0xF0) {
            l = 3;
        } else {
            l = 4;
        }

        // Check for truncated codepoints
        if (l > self._len) {
            rune._len = self._len;
            self._ptr += self._len;
            self._len = 0;
            return rune;
        }

        self._ptr += l;
        self._len -= l;
        rune._len = l;
        return rune;
    }

    /*
     * @dev Returns the first rune in the slice, advancing the slice to point
     *      to the next rune.
     * @param self The slice to operate on.
     * @return A slice containing only the first rune from `self`.
     */
    function nextRune(slice memory self) internal pure returns (slice memory ret) {
        nextRune(self, ret);
    }

    /*
     * @dev Returns the number of the first codepoint in the slice.
     * @param self The slice to operate on.
     * @return The number of the first codepoint in the slice.
     */
    function ord(slice memory self) internal pure returns (uint ret) {
        if (self._len == 0) {
            return 0;
        }

        uint word;
        uint length;
        uint divisor = 2 ** 248;

        // Load the rune into the MSBs of b
        assembly { word:= mload(mload(add(self, 32))) }
        uint b = word / divisor;
        if (b < 0x80) {
            ret = b;
            length = 1;
        } else if(b < 0xE0) {
            ret = b & 0x1F;
            length = 2;
        } else if(b < 0xF0) {
            ret = b & 0x0F;
            length = 3;
        } else {
            ret = b & 0x07;
            length = 4;
        }

        // Check for truncated codepoints
        if (length > self._len) {
            return 0;
        }

        for (uint i = 1; i < length; i++) {
            divisor = divisor / 256;
            b = (word / divisor) & 0xFF;
            if (b & 0xC0 != 0x80) {
                // Invalid UTF-8 sequence
                return 0;
            }
            ret = (ret * 64) | (b & 0x3F);
        }

        return ret;
    }

    /*
     * @dev Returns the keccak-256 hash of the slice.
     * @param self The slice to hash.
     * @return The hash of the slice.
     */
    function keccak(slice memory self) internal pure returns (bytes32 ret) {
        assembly {
            ret := keccak256(mload(add(self, 32)), mload(self))
        }
    }

    /*
     * @dev Returns true if `self` starts with `needle`.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return True if the slice starts with the provided text, false otherwise.
     */
    function startsWith(slice memory self, slice memory needle) internal pure returns (bool) {
        if (self._len < needle._len) {
            return false;
        }

        if (self._ptr == needle._ptr) {
            return true;
        }

        bool equal;
        assembly {
            let length := mload(needle)
            let selfptr := mload(add(self, 0x20))
            let needleptr := mload(add(needle, 0x20))
            equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
        }
        return equal;
    }

    /*
     * @dev If `self` starts with `needle`, `needle` is removed from the
     *      beginning of `self`. Otherwise, `self` is unmodified.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return `self`
     */
    function beyond(slice memory self, slice memory needle) internal pure returns (slice memory) {
        if (self._len < needle._len) {
            return self;
        }

        bool equal = true;
        if (self._ptr != needle._ptr) {
            assembly {
                let length := mload(needle)
                let selfptr := mload(add(self, 0x20))
                let needleptr := mload(add(needle, 0x20))
                equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
            }
        }

        if (equal) {
            self._len -= needle._len;
            self._ptr += needle._len;
        }

        return self;
    }

    /*
     * @dev Returns true if the slice ends with `needle`.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return True if the slice starts with the provided text, false otherwise.
     */
    function endsWith(slice memory self, slice memory needle) internal pure returns (bool) {
        if (self._len < needle._len) {
            return false;
        }

        uint selfptr = self._ptr + self._len - needle._len;

        if (selfptr == needle._ptr) {
            return true;
        }

        bool equal;
        assembly {
            let length := mload(needle)
            let needleptr := mload(add(needle, 0x20))
            equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
        }

        return equal;
    }

    /*
     * @dev If `self` ends with `needle`, `needle` is removed from the
     *      end of `self`. Otherwise, `self` is unmodified.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return `self`
     */
    function until(slice memory self, slice memory needle) internal pure returns (slice memory) {
        if (self._len < needle._len) {
            return self;
        }

        uint selfptr = self._ptr + self._len - needle._len;
        bool equal = true;
        if (selfptr != needle._ptr) {
            assembly {
                let length := mload(needle)
                let needleptr := mload(add(needle, 0x20))
                equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
            }
        }

        if (equal) {
            self._len -= needle._len;
        }

        return self;
    }

    // Returns the memory address of the first byte of the first occurrence of
    // `needle` in `self`, or the first byte after `self` if not found.
    function findPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) {
        uint ptr = selfptr;
        uint idx;

        if (needlelen <= selflen) {
            if (needlelen <= 32) {
                bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1));

                bytes32 needledata;
                assembly { needledata := and(mload(needleptr), mask) }

                uint end = selfptr + selflen - needlelen;
                bytes32 ptrdata;
                assembly { ptrdata := and(mload(ptr), mask) }

                while (ptrdata != needledata) {
                    if (ptr >= end)
                        return selfptr + selflen;
                    ptr++;
                    assembly { ptrdata := and(mload(ptr), mask) }
                }
                return ptr;
            } else {
                // For long needles, use hashing
                bytes32 hash;
                assembly { hash := keccak256(needleptr, needlelen) }

                for (idx = 0; idx <= selflen - needlelen; idx++) {
                    bytes32 testHash;
                    assembly { testHash := keccak256(ptr, needlelen) }
                    if (hash == testHash)
                        return ptr;
                    ptr += 1;
                }
            }
        }
        return selfptr + selflen;
    }

    // Returns the memory address of the first byte after the last occurrence of
    // `needle` in `self`, or the address of `self` if not found.
    function rfindPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) {
        uint ptr;

        if (needlelen <= selflen) {
            if (needlelen <= 32) {
                bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1));

                bytes32 needledata;
                assembly { needledata := and(mload(needleptr), mask) }

                ptr = selfptr + selflen - needlelen;
                bytes32 ptrdata;
                assembly { ptrdata := and(mload(ptr), mask) }

                while (ptrdata != needledata) {
                    if (ptr <= selfptr)
                        return selfptr;
                    ptr--;
                    assembly { ptrdata := and(mload(ptr), mask) }
                }
                return ptr + needlelen;
            } else {
                // For long needles, use hashing
                bytes32 hash;
                assembly { hash := keccak256(needleptr, needlelen) }
                ptr = selfptr + (selflen - needlelen);
                while (ptr >= selfptr) {
                    bytes32 testHash;
                    assembly { testHash := keccak256(ptr, needlelen) }
                    if (hash == testHash)
                        return ptr + needlelen;
                    ptr -= 1;
                }
            }
        }
        return selfptr;
    }

    /*
     * @dev Modifies `self` to contain everything from the first occurrence of
     *      `needle` to the end of the slice. `self` is set to the empty slice
     *      if `needle` is not found.
     * @param self The slice to search and modify.
     * @param needle The text to search for.
     * @return `self`.
     */
    function find(slice memory self, slice memory needle) internal pure returns (slice memory) {
        uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
        self._len -= ptr - self._ptr;
        self._ptr = ptr;
        return self;
    }

    /*
     * @dev Modifies `self` to contain the part of the string from the start of
     *      `self` to the end of the first occurrence of `needle`. If `needle`
     *      is not found, `self` is set to the empty slice.
     * @param self The slice to search and modify.
     * @param needle The text to search for.
     * @return `self`.
     */
    function rfind(slice memory self, slice memory needle) internal pure returns (slice memory) {
        uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
        self._len = ptr - self._ptr;
        return self;
    }

    /*
     * @dev Splits the slice, setting `self` to everything after the first
     *      occurrence of `needle`, and `token` to everything before it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and `token` is set to the entirety of `self`.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @param token An output parameter to which the first token is written.
     * @return `token`.
     */
    function split(slice memory self, slice memory needle, slice memory token) internal pure returns (slice memory) {
        uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
        token._ptr = self._ptr;
        token._len = ptr - self._ptr;
        if (ptr == self._ptr + self._len) {
            // Not found
            self._len = 0;
        } else {
            self._len -= token._len + needle._len;
            self._ptr = ptr + needle._len;
        }
        return token;
    }

    /*
     * @dev Splits the slice, setting `self` to everything after the first
     *      occurrence of `needle`, and returning everything before it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and the entirety of `self` is returned.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @return The part of `self` up to the first occurrence of `delim`.
     */
    function split(slice memory self, slice memory needle) internal pure returns (slice memory token) {
        split(self, needle, token);
    }

    /*
     * @dev Splits the slice, setting `self` to everything before the last
     *      occurrence of `needle`, and `token` to everything after it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and `token` is set to the entirety of `self`.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @param token An output parameter to which the first token is written.
     * @return `token`.
     */
    function rsplit(slice memory self, slice memory needle, slice memory token) internal pure returns (slice memory) {
        uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
        token._ptr = ptr;
        token._len = self._len - (ptr - self._ptr);
        if (ptr == self._ptr) {
            // Not found
            self._len = 0;
        } else {
            self._len -= token._len + needle._len;
        }
        return token;
    }

    /*
     * @dev Splits the slice, setting `self` to everything before the last
     *      occurrence of `needle`, and returning everything after it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and the entirety of `self` is returned.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @return The part of `self` after the last occurrence of `delim`.
     */
    function rsplit(slice memory self, slice memory needle) internal pure returns (slice memory token) {
        rsplit(self, needle, token);
    }

    /*
     * @dev Counts the number of nonoverlapping occurrences of `needle` in `self`.
     * @param self The slice to search.
     * @param needle The text to search for in `self`.
     * @return The number of occurrences of `needle` found in `self`.
     */
    function count(slice memory self, slice memory needle) internal pure returns (uint cnt) {
        uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr) + needle._len;
        while (ptr <= self._ptr + self._len) {
            cnt++;
            ptr = findPtr(self._len - (ptr - self._ptr), ptr, needle._len, needle._ptr) + needle._len;
        }
    }

    /*
     * @dev Returns True if `self` contains `needle`.
     * @param self The slice to search.
     * @param needle The text to search for in `self`.
     * @return True if `needle` is found in `self`, false otherwise.
     */
    function contains(slice memory self, slice memory needle) internal pure returns (bool) {
        return rfindPtr(self._len, self._ptr, needle._len, needle._ptr) != self._ptr;
    }

    /*
     * @dev Returns a newly allocated string containing the concatenation of
     *      `self` and `other`.
     * @param self The first slice to concatenate.
     * @param other The second slice to concatenate.
     * @return The concatenation of the two strings.
     */
    function concat(slice memory self, slice memory other) internal pure returns (string memory) {
        string memory ret = new string(self._len + other._len);
        uint retptr;
        assembly { retptr := add(ret, 32) }
        memcpy(retptr, self._ptr, self._len);
        memcpy(retptr + self._len, other._ptr, other._len);
        return ret;
    }

    /*
     * @dev Joins an array of slices, using `self` as a delimiter, returning a
     *      newly allocated string.
     * @param self The delimiter to use.
     * @param parts A list of slices to join.
     * @return A newly allocated string containing all the slices in `parts`,
     *         joined with `self`.
     */
    function join(slice memory self, slice[] memory parts) internal pure returns (string memory) {
        if (parts.length == 0)
            return "";

        uint length = self._len * (parts.length - 1);
        for(uint i = 0; i < parts.length; i++)
            length += parts[i]._len;

        string memory ret = new string(length);
        uint retptr;
        assembly { retptr := add(ret, 32) }

        for(uint i = 0; i < parts.length; i++) {
            memcpy(retptr, parts[i]._ptr, parts[i]._len);
            retptr += parts[i]._len;
            if (i < parts.length - 1) {
                memcpy(retptr, self._ptr, self._len);
                retptr += self._len;
            }
        }

        return ret;
    }
}

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


/**
 * @dev Required interface of an ERC721 compliant contract.
 */
contract IERC721 is IERC165 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of NFTs in `owner`'s account.
     */
    function balanceOf(address owner) public view returns (uint256 balance);

    /**
     * @dev Returns the owner of the NFT specified by `tokenId`.
     */
    function ownerOf(uint256 tokenId) public view returns (address owner);

    /**
     * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
     * another (`to`).
     *
     *
     *
     * Requirements:
     * - `from`, `to` cannot be zero.
     * - `tokenId` must be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this
     * NFT by either {approve} or {setApprovalForAll}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public;
    /**
     * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
     * another (`to`).
     *
     * Requirements:
     * - If the caller is not `from`, it must be approved to move this NFT by
     * either {approve} or {setApprovalForAll}.
     */
    function transferFrom(address from, address to, uint256 tokenId) public;
    function approve(address to, uint256 tokenId) public;
    function getApproved(uint256 tokenId) public view returns (address operator);

    function setApprovalForAll(address operator, bool _approved) public;
    function isApprovedForAll(address owner, address operator) public view returns (bool);


    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
}


/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
contract IERC721Metadata is IERC721 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
contract IERC721Enumerable is IERC721 {
    function totalSupply() public view returns (uint256);
    function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId);

    function tokenByIndex(uint256 index) public view returns (uint256);
}

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
contract IERC721Receiver {
    /**
     * @notice Handle the receipt of an NFT
     * @dev The ERC721 smart contract calls this function on the recipient
     * after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
     * otherwise the caller will revert the transaction. The selector to be
     * returned can be obtained as `this.onERC721Received.selector`. This
     * function MAY throw to revert and reject the transfer.
     * Note: the ERC721 contract address is always the message sender.
     * @param operator The address which called `safeTransferFrom` function
     * @param from The address which previously owned the token
     * @param tokenId The NFT identifier which is being transferred
     * @param data Additional data with no specified format
     * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
    public returns (bytes4);
}

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * NOTE: This is a feature of the next version of OpenZeppelin Contracts.
     * @dev Get it via `npm install @openzeppelin/contracts@next`.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.

     * NOTE: This is a feature of the next version of OpenZeppelin Contracts.
     * @dev Get it via `npm install @openzeppelin/contracts@next`.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * NOTE: This is a feature of the next version of OpenZeppelin Contracts.
     * @dev Get it via `npm install @openzeppelin/contracts@next`.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * This test is non-exhaustive, and there may be false-negatives: during the
     * execution of a contract's constructor, its address will be reported as
     * not containing a contract.
     *
     * IMPORTANT: It is unsafe to assume that an address for which this
     * function returns false is an externally-owned account (EOA) and not a
     * contract.
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies in extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != 0x0 && codehash != accountHash);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * NOTE: This is a feature of the next version of OpenZeppelin Contracts.
     * @dev Get it via `npm install @openzeppelin/contracts@next`.
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }
}

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
 * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
 * directly accessed.
 */
library Counters {
    using SafeMath for uint256;

    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

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

    function increment(Counter storage counter) internal {
        // The {SafeMath} overflow check can be skipped here, see the comment at the top
        counter._value += 1;
    }

    function decrement(Counter storage counter) internal {
        counter._value = counter._value.sub(1);
    }
}

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    /**
     * @dev Mapping of interface ids to whether or not it's supported.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () internal {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721 is Context, ERC165, IERC721 {
    using SafeMath for uint256;
    using Address for address;
    using Counters for Counters.Counter;

    // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    // Mapping from token ID to owner
    mapping (uint256 => address) private _tokenOwner;

    // Mapping from token ID to approved address
    mapping (uint256 => address) private _tokenApprovals;

    // Mapping from owner to number of owned token
    mapping (address => Counters.Counter) private _ownedTokensCount;

    // Mapping from owner to operator approvals
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
     *        0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    constructor () public {
        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
    }

    /**
     * @dev Gets the balance of the specified address.
     * @param owner address to query the balance of
     * @return uint256 representing the amount owned by the passed address
     */
    function balanceOf(address owner) public view returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");

        return _ownedTokensCount[owner].current();
    }

    /**
     * @dev Gets the owner of the specified token ID.
     * @param tokenId uint256 ID of the token to query the owner of
     * @return address currently marked as the owner of the given token ID
     */
    function ownerOf(uint256 tokenId) public view returns (address) {
        address owner = _tokenOwner[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");

        return owner;
    }

    /**
     * @dev Approves another address to transfer the given token ID
     * The zero address indicates there is no approved address.
     * There can only be one approved address per token at a given time.
     * Can only be called by the token owner or an approved operator.
     * @param to address to be approved for the given token ID
     * @param tokenId uint256 ID of the token to be approved
     */
    function approve(address to, uint256 tokenId) public {
        address owner = ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Gets the approved address for a token ID, or zero if no address set
     * Reverts if the token ID does not exist.
     * @param tokenId uint256 ID of the token to query the approval of
     * @return address currently approved for the given token ID
     */
    function getApproved(uint256 tokenId) public view returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev Sets or unsets the approval of a given operator
     * An operator is allowed to transfer all tokens of the sender on their behalf.
     * @param to operator address to set the approval
     * @param approved representing the status of the approval to be set
     */
    function setApprovalForAll(address to, bool approved) public {
        require(to != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][to] = approved;
        emit ApprovalForAll(_msgSender(), to, approved);
    }

    /**
     * @dev Tells whether an operator is approved by a given owner.
     * @param owner owner address which you want to query the approval of
     * @param operator operator address which you want to query the approval of
     * @return bool whether the given operator is approved by the given owner
     */
    function isApprovedForAll(address owner, address operator) public view returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev Transfers the ownership of a given token ID to another address.
     * Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     * Requires the msg.sender to be the owner, approved, or operator.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function transferFrom(address from, address to, uint256 tokenId) public {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transferFrom(from, to, tokenId);
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the msg.sender to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the _msgSender() to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes data to send along with a safe transfer check
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransferFrom(from, to, tokenId, _data);
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement `onERC721Received`,
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the msg.sender to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes data to send along with a safe transfer check
     */
    function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal {
        _transferFrom(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether the specified token exists.
     * @param tokenId uint256 ID of the token to query the existence of
     * @return bool whether the token exists
     */
    function _exists(uint256 tokenId) internal view returns (bool) {
        address owner = _tokenOwner[tokenId];
        return owner != address(0);
    }

    /**
     * @dev Returns whether the given spender can transfer a given token ID.
     * @param spender address of the spender to query
     * @param tokenId uint256 ID of the token to be transferred
     * @return bool whether the msg.sender is approved for the given token ID,
     * is an operator of the owner, or is the owner of the token
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Internal function to safely mint a new token.
     * Reverts if the given token ID already exists.
     * If the target address is a contract, it must implement `onERC721Received`,
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * @param to The address that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     */
    function _safeMint(address to, uint256 tokenId) internal {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Internal function to safely mint a new token.
     * Reverts if the given token ID already exists.
     * If the target address is a contract, it must implement `onERC721Received`,
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * @param to The address that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     * @param _data bytes data to send along with a safe transfer check
     */
    function _safeMint(address to, uint256 tokenId, bytes memory _data) internal {
        _mint(to, tokenId);
        require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Internal function to mint a new token.
     * Reverts if the given token ID already exists.
     * @param to The address that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     */
    function _mint(address to, uint256 tokenId) internal {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _tokenOwner[tokenId] = to;
        _ownedTokensCount[to].increment();

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

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * Deprecated, use {_burn} instead.
     * @param owner owner of the token to burn
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(address owner, uint256 tokenId) internal {
        require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own");

        _clearApproval(tokenId);

        _ownedTokensCount[owner].decrement();
        _tokenOwner[tokenId] = address(0);

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

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(uint256 tokenId) internal {
        _burn(ownerOf(tokenId), tokenId);
    }

    /**
     * @dev Internal function to transfer ownership of a given token ID to another address.
     * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _transferFrom(address from, address to, uint256 tokenId) internal {
        require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _clearApproval(tokenId);

        _ownedTokensCount[from].decrement();
        _ownedTokensCount[to].increment();

        _tokenOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * This function is deprecated.
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        internal returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }

        bytes4 retval = IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data);
        return (retval == _ERC721_RECEIVED);
    }

    /**
     * @dev Private function to clear current approval of a given token ID.
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _clearApproval(uint256 tokenId) private {
        if (_tokenApprovals[tokenId] != address(0)) {
            _tokenApprovals[tokenId] = address(0);
        }
    }
}

/**
 * @title ERC-721 Non-Fungible Token with optional enumeration extension logic
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable {
    // Mapping from owner to list of owned token IDs
    mapping(address => 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;

    /*
     *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
     *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
     *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
     *
     *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
     */
    bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;

    /**
     * @dev Constructor function.
     */
    constructor () public {
        // register the supported interface to conform to ERC721Enumerable via ERC165
        _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
    }

    /**
     * @dev Gets the token ID at a given index of the tokens list of the requested owner.
     * @param owner address owning the tokens list to be accessed
     * @param index uint256 representing the index to be accessed of the requested tokens list
     * @return uint256 token ID at the given index of the tokens list owned by the requested address
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
        require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }

    /**
     * @dev Gets the total amount of tokens stored by the contract.
     * @return uint256 representing the total amount of tokens
     */
    function totalSupply() public view returns (uint256) {
        return _allTokens.length;
    }

    /**
     * @dev Gets the token ID at a given index of all the tokens in this contract
     * Reverts if the index is greater or equal to the total number of tokens.
     * @param index uint256 representing the index to be accessed of the tokens list
     * @return uint256 token ID at the given index of the tokens list
     */
    function tokenByIndex(uint256 index) public view returns (uint256) {
        require(index < totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }

    /**
     * @dev Internal function to transfer ownership of a given token ID to another address.
     * As opposed to transferFrom, this imposes no restrictions on msg.sender.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _transferFrom(address from, address to, uint256 tokenId) internal {
        super._transferFrom(from, to, tokenId);

        _removeTokenFromOwnerEnumeration(from, tokenId);

        _addTokenToOwnerEnumeration(to, tokenId);
    }

    /**
     * @dev Internal function to mint a new token.
     * Reverts if the given token ID already exists.
     * @param to address the beneficiary that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     */
    function _mint(address to, uint256 tokenId) internal {
        super._mint(to, tokenId);

        _addTokenToOwnerEnumeration(to, tokenId);

        _addTokenToAllTokensEnumeration(tokenId);
    }

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * Deprecated, use {ERC721-_burn} instead.
     * @param owner owner of the token to burn
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(address owner, uint256 tokenId) internal {
        super._burn(owner, tokenId);

        _removeTokenFromOwnerEnumeration(owner, tokenId);
        // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund
        _ownedTokensIndex[tokenId] = 0;

        _removeTokenFromAllTokensEnumeration(tokenId);
    }

    /**
     * @dev Gets the list of token IDs of the requested owner.
     * @param owner address owning the tokens
     * @return uint256[] List of token IDs owned by the requested address
     */
    function _tokensOfOwner(address owner) internal view returns (uint256[] storage) {
        return _ownedTokens[owner];
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        _ownedTokensIndex[tokenId] = _ownedTokens[to].length;
        _ownedTokens[to].push(tokenId);
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _ownedTokens[from].length.sub(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
        _ownedTokens[from].length--;

        // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by
        // lastTokenId, or just over the end of the array if the token was the last one).
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length.sub(1);
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        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

        // This also deletes the contents at the last position of the array
        _allTokens.length--;
        _allTokensIndex[tokenId] = 0;
    }
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * Modified to remove the mint function and to replace it
 * with the _addTokenTo function.
 * This function is very similar to the _mint function, but it
 * does not emit a Transfer event
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
contract NoMintERC721 is Context, ERC165, IERC721 {
    using SafeMath for uint256;
    using Address for address;
    using Counters for Counters.Counter;

    // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    // Mapping from token ID to owner
    mapping (uint256 => address) private _tokenOwner;

    // Mapping from token ID to approved address
    mapping (uint256 => address) private _tokenApprovals;

    // Mapping from owner to number of owned token
    mapping (address => Counters.Counter) private _ownedTokensCount;

    // Mapping from owner to operator approvals
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
     *        0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    constructor () public {
        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
    }

    /**
     * @dev Gets the balance of the specified address.
     * @param owner address to query the balance of
     * @return uint256 representing the amount owned by the passed address
     */
    function balanceOf(address owner) public view returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");

        return _ownedTokensCount[owner].current();
    }

    /**
     * @dev Gets the owner of the specified token ID.
     * @param tokenId uint256 ID of the token to query the owner of
     * @return address currently marked as the owner of the given token ID
     */
    function ownerOf(uint256 tokenId) public view returns (address) {
        address owner = _tokenOwner[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");

        return owner;
    }

    /**
     * @dev Approves another address to transfer the given token ID
     * The zero address indicates there is no approved address.
     * There can only be one approved address per token at a given time.
     * Can only be called by the token owner or an approved operator.
     * @param to address to be approved for the given token ID
     * @param tokenId uint256 ID of the token to be approved
     */
    function approve(address to, uint256 tokenId) public {
        address owner = ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Gets the approved address for a token ID, or zero if no address set
     * Reverts if the token ID does not exist.
     * @param tokenId uint256 ID of the token to query the approval of
     * @return address currently approved for the given token ID
     */
    function getApproved(uint256 tokenId) public view returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev Sets or unsets the approval of a given operator
     * An operator is allowed to transfer all tokens of the sender on their behalf.
     * @param to operator address to set the approval
     * @param approved representing the status of the approval to be set
     */
    function setApprovalForAll(address to, bool approved) public {
        require(to != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][to] = approved;
        emit ApprovalForAll(_msgSender(), to, approved);
    }

    /**
     * @dev Tells whether an operator is approved by a given owner.
     * @param owner owner address which you want to query the approval of
     * @param operator operator address which you want to query the approval of
     * @return bool whether the given operator is approved by the given owner
     */
    function isApprovedForAll(address owner, address operator) public view returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev Transfers the ownership of a given token ID to another address.
     * Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     * Requires the msg.sender to be the owner, approved, or operator.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function transferFrom(address from, address to, uint256 tokenId) public {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transferFrom(from, to, tokenId);
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the msg.sender to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the _msgSender() to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes data to send along with a safe transfer check
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransferFrom(from, to, tokenId, _data);
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement `onERC721Received`,
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the msg.sender to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes data to send along with a safe transfer check
     */
    function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal {
        _transferFrom(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether the specified token exists.
     * @param tokenId uint256 ID of the token to query the existence of
     * @return bool whether the token exists
     */
    function _exists(uint256 tokenId) internal view returns (bool) {
        address owner = _tokenOwner[tokenId];
        return owner != address(0);
    }

    /**
     * @dev Returns whether the given spender can transfer a given token ID.
     * @param spender address of the spender to query
     * @param tokenId uint256 ID of the token to be transferred
     * @return bool whether the msg.sender is approved for the given token ID,
     * is an operator of the owner, or is the owner of the token
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Internal function to mint a new token.
     * Reverts if the given token ID already exists.
     * @param to The address that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     */
    function _addTokenTo(address to, uint256 tokenId) internal {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _tokenOwner[tokenId] = to;
        _ownedTokensCount[to].increment();
    }

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * Deprecated, use {_burn} instead.
     * @param owner owner of the token to burn
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(address owner, uint256 tokenId) internal {
        require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own");

        _clearApproval(tokenId);

        _ownedTokensCount[owner].decrement();
        _tokenOwner[tokenId] = address(0);

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

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(uint256 tokenId) internal {
        _burn(ownerOf(tokenId), tokenId);
    }

    /**
     * @dev Internal function to transfer ownership of a given token ID to another address.
     * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _transferFrom(address from, address to, uint256 tokenId) internal {
        require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _clearApproval(tokenId);

        _ownedTokensCount[from].decrement();
        _ownedTokensCount[to].increment();

        _tokenOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * This function is deprecated.
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        internal returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }

        bytes4 retval = IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data);
        return (retval == _ERC721_RECEIVED);
    }

    /**
     * @dev Private function to clear current approval of a given token ID.
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _clearApproval(uint256 tokenId) private {
        if (_tokenApprovals[tokenId] != address(0)) {
            _tokenApprovals[tokenId] = address(0);
        }
    }
}

/**
 * @title ERC-721 Non-Fungible Token with optional enumeration extension logic
 * Modified to work with the NoMintERC721 contract
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
contract NoMintERC721Enumerable is Context, ERC165, NoMintERC721, IERC721Enumerable {
    // Mapping from owner to list of owned token IDs
    mapping(address => 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;

    /*
     *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
     *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
     *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
     *
     *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
     */
    bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;

    /**
     * @dev Constructor function.
     */
    constructor () public {
        // register the supported interface to conform to ERC721Enumerable via ERC165
        _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
    }

    /**
     * @dev Gets the token ID at a given index of the tokens list of the requested owner.
     * @param owner address owning the tokens list to be accessed
     * @param index uint256 representing the index to be accessed of the requested tokens list
     * @return uint256 token ID at the given index of the tokens list owned by the requested address
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
        require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }

    /**
     * @dev Gets the total amount of tokens stored by the contract.
     * @return uint256 representing the total amount of tokens
     */
    function totalSupply() public view returns (uint256) {
        return _allTokens.length;
    }

    /**
     * @dev Gets the token ID at a given index of all the tokens in this contract
     * Reverts if the index is greater or equal to the total number of tokens.
     * @param index uint256 representing the index to be accessed of the tokens list
     * @return uint256 token ID at the given index of the tokens list
     */
    function tokenByIndex(uint256 index) public view returns (uint256) {
        require(index < totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }

    /**
     * @dev Internal function to transfer ownership of a given token ID to another address.
     * As opposed to transferFrom, this imposes no restrictions on msg.sender.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _transferFrom(address from, address to, uint256 tokenId) internal {
        super._transferFrom(from, to, tokenId);

        _removeTokenFromOwnerEnumeration(from, tokenId);

        _addTokenToOwnerEnumeration(to, tokenId);
    }

    /**
     * @dev Internal function to mint a new token.
     * Reverts if the given token ID already exists.
     * @param to address the beneficiary that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     */
    function _addTokenTo(address to, uint256 tokenId) internal {
        super._addTokenTo(to, tokenId);

        _addTokenToOwnerEnumeration(to, tokenId);

        _addTokenToAllTokensEnumeration(tokenId);
    }

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * Deprecated, use {ERC721-_burn} instead.
     * @param owner owner of the token to burn
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(address owner, uint256 tokenId) internal {
        super._burn(owner, tokenId);

        _removeTokenFromOwnerEnumeration(owner, tokenId);
        // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund
        _ownedTokensIndex[tokenId] = 0;

        _removeTokenFromAllTokensEnumeration(tokenId);
    }

    /**
     * @dev Gets the list of token IDs of the requested owner.
     * @param owner address owning the tokens
     * @return uint256[] List of token IDs owned by the requested address
     */
    function _tokensOfOwner(address owner) internal view returns (uint256[] storage) {
        return _ownedTokens[owner];
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        _ownedTokensIndex[tokenId] = _ownedTokens[to].length;
        _ownedTokens[to].push(tokenId);
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _ownedTokens[from].length.sub(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
        _ownedTokens[from].length--;

        // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by
        // lastTokenId, or just over the end of the array if the token was the last one).
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length.sub(1);
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        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

        // This also deletes the contents at the last position of the array
        _allTokens.length--;
        _allTokensIndex[tokenId] = 0;
    }
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * Modified to change
 * function tokenURI(uint256 tokenId) external view returns (string memory);
 * to
 * function tokenURI(uint256 tokenId) public view returns (string memory);
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
contract OveridableERC721Metadata is Context, ERC165, NoMintERC721, IERC721Metadata {
    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Optional mapping for token URIs
    mapping(uint256 => string) private _tokenURIs;

    /*
     *     bytes4(keccak256('name()')) == 0x06fdde03
     *     bytes4(keccak256('symbol()')) == 0x95d89b41
     *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
     *
     *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
     */
    bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;

    /**
     * @dev Constructor function
     */
    constructor (string memory name, string memory symbol) public {
        _name = name;
        _symbol = symbol;

        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721_METADATA);
    }

    /**
     * @dev Gets the token name.
     * @return string representing the token name
     */
    function name() external view returns (string memory) {
        return _name;
    }

    /**
     * @dev Gets the token symbol.
     * @return string representing the token symbol
     */
    function symbol() external view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns an URI for a given token ID.
     * Throws if the token ID does not exist. May return an empty string.
     * @param tokenId uint256 ID of the token to query
     */
    function tokenURI(uint256 tokenId) public view returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        return _tokenURIs[tokenId];
    }

    /**
     * @dev Internal function to set the token URI for a given token.
     * Reverts if the token ID does not exist.
     * @param tokenId uint256 ID of the token to set its URI
     * @param uri string URI to assign
     */
    function _setTokenURI(uint256 tokenId, string memory uri) internal {
        require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
        _tokenURIs[tokenId] = uri;
    }

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * Deprecated, use _burn(uint256) instead.
     * @param owner owner of the token to burn
     * @param tokenId uint256 ID of the token being burned by the msg.sender
     */
    function _burn(address owner, uint256 tokenId) internal {
        super._burn(owner, tokenId);

        // Clear metadata (if any)
        if (bytes(_tokenURIs[tokenId]).length != 0) {
            delete _tokenURIs[tokenId];
        }
    }
}

/**
 * ERC-721 implementation that allows 
 * tokens (of the same category) to be minted in batches. Each batch
 * contains enough data to generate all
 * token ids inside the batch, and to
 * generate the tokenURI in the batch
 */
contract GunToken is NoMintERC721, NoMintERC721Enumerable, OveridableERC721Metadata, Ownable {
    using strings for *;
    
    address internal factory;
    address internal oldToken;
    uint256 internal migrateCursor = 0;
    
    uint16 public constant maxAllocation = 4000;
    uint256 public lastAllocation = 0;
    
    event BatchTransfer(address indexed from, address indexed to, uint256 indexed batchIndex);
    
    struct Batch {
        address owner;
        uint16 size;
        uint8 category;
        uint256 startId;
        uint256 startTokenId;
    }
    
    Batch[] public allBatches;
    mapping(address => uint256) unactivatedBalance;
    mapping(uint256 => bool) isActivated;
    
    //Used for enumeration
    mapping(address => Batch[]) public batchesOwned;
    //Batch index to owner batch index
    mapping(uint256 => uint256) public ownedBatchIndex;
    
    mapping(uint8 => uint256) internal totalGunsMintedByCategory;
    uint256 internal _totalSupply;

    modifier onlyFactory {
        require(msg.sender == factory, "Not authorized");
        _;
    }

    constructor(address factoryAddress, address oldGunToken) public OveridableERC721Metadata("War Riders Gun", "WRG") {
        factory = factoryAddress;
        oldToken = oldGunToken;
    }
    
    function categoryTypeToId(uint8 category, uint256 categoryId) public view returns (uint256) {
        for (uint i = 0; i < allBatches.length; i++) {
            Batch memory a = allBatches[i];
            if (a.category != category)
                continue;
            
            uint256 endId = a.startId + a.size;
            if (categoryId >= a.startId && categoryId < endId) {
                uint256 dif = categoryId - a.startId;
                
                return a.startTokenId + dif;
            }
        }
        
        revert();
    }
    
    /**
     * @dev Gets the token ID at a given index of the tokens list of the requested owner.
     * @param owner address owning the tokens list to be accessed
     * @param index uint256 representing the index to be accessed of the requested tokens list
     * @return uint256 token ID at the given index of the tokens list owned by the requested address
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
        return tokenOfOwner(owner)[index];
    }
    
    function getBatchCount(address owner) public view returns(uint256) {
        return batchesOwned[owner].length;
    }
    
    function getTokensInBatch(address owner, uint256 index) public view returns (uint256[] memory) {
        Batch memory a = batchesOwned[owner][index];
        uint256[] memory result = new uint256[](a.size);
        
        uint256 pos = 0;
        uint end = a.startTokenId + a.size;
        for (uint i = a.startTokenId; i < end; i++) {
            if (isActivated[i] && super.ownerOf(i) != owner) {
                continue;
            }
            
            result[pos] = i;
            pos++;
        }
        
        require(pos > 0);
        
        uint256 subAmount = a.size - pos;
        
        assembly { mstore(result, sub(mload(result), subAmount)) }
        
        return result;
    }
    
    function tokenByIndex(uint256 index) public view returns (uint256) {
        return allTokens()[index];
    }
    
    function allTokens() public view returns (uint256[] memory) {
        uint256[] memory result = new uint256[](totalSupply());
        
        uint pos = 0;
        for (uint i = 0; i < allBatches.length; i++) {
            Batch memory a = allBatches[i];
            uint end = a.startTokenId + a.size;
            for (uint j = a.startTokenId; j < end; j++) {
                result[pos] = j;
                pos++;
            }
        }
        
        return result;
    }
    
    function tokenOfOwner(address owner) public view returns (uint256[] memory) {
        uint256[] memory result = new uint256[](balanceOf(owner));
        
        uint pos = 0;
        for (uint i = 0; i < batchesOwned[owner].length; i++) {
            Batch memory a = batchesOwned[owner][i];
            uint end = a.startTokenId + a.size;
            for (uint j = a.startTokenId; j < end; j++) {
                if (isActivated[j] && super.ownerOf(j) != owner) {
                    continue;
                }
                
                result[pos] = j;
                pos++;
            }
        }
        
        uint256[] memory fallbackOwned = _tokensOfOwner(owner);
        for (uint i = 0; i < fallbackOwned.length; i++) {
            result[pos] = fallbackOwned[i];
            pos++;
        }
        
        return result;
    }
    
    function balanceOf(address owner) public view returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");

        return super.balanceOf(owner) + unactivatedBalance[owner];
    }
    
     function ownerOf(uint256 tokenId) public view returns (address) {
         require(exists(tokenId), "Token doesn't exist!");
         
         if (isActivated[tokenId]) {
             return super.ownerOf(tokenId);
         }
         uint256 index = getBatchIndex(tokenId);
         require(index < allBatches.length, "Token batch doesn't exist");
         Batch memory a = allBatches[index];
         require(tokenId < a.startTokenId + a.size);
         return a.owner;
     }
    
    function exists(uint256 _tokenId) public view returns (bool) {
        if (isActivated[_tokenId]) {
            return super._exists(_tokenId);
        } else {
            uint256 index = getBatchIndex(_tokenId);
            if (index < allBatches.length) {
                Batch memory a = allBatches[index];
                uint end = a.startTokenId + a.size;
                
                return _tokenId < end;
            }
            return false;
        }
    }
    
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }
    
    function claimAllocation(address to, uint16 size, uint8 category) public onlyFactory returns (uint) {
        require(size < maxAllocation, "Size must be smaller than maxAllocation");
        
        allBatches.push(Batch({
            owner: to,
            size: size,
            category: category,
            startId: totalGunsMintedByCategory[category],
            startTokenId: lastAllocation
        }));
        
        uint end = lastAllocation + size;
        for (uint i = lastAllocation; i < end; i++) {
            emit Transfer(address(0), to, i);
        }
        
        lastAllocation += maxAllocation;
        
        unactivatedBalance[to] += size;
        totalGunsMintedByCategory[category] += size;
        
        _addBatchToOwner(to, allBatches[allBatches.length - 1]);
        
        _totalSupply += size;
        return lastAllocation;
    }
    
    function migrate(uint256 count) public onlyOwner returns (uint256) {
        GunToken oldGuns = GunToken(oldToken);
        
        for (uint256 i = 0; i < count; i++) {
            uint256 index = migrateCursor + i;
            
            (address to, uint16 size, uint8 category, uint256 startId, uint256 startTokenId) = oldGuns.allBatches(index);
            allBatches.push(Batch({
                owner: to,
                size: size,
                category: category,
                startId: startId,
                startTokenId: startTokenId
            }));
            
            uint end = lastAllocation + size;
            uint256 ubalance = size;
            for (uint z = lastAllocation; z < end; z++) {
                address owner = oldGuns.ownerOf(z);
                if (owner != to) {
                    isActivated[z] = true;
                    addTokenTo(owner, z);
                    ubalance--;
                } else {
                    emit Transfer(address(0), to, z);
                }
                
                
            }
            
            lastAllocation += maxAllocation;
            unactivatedBalance[to] += ubalance;
            totalGunsMintedByCategory[category] += size;
            
            _addBatchToOwner(to, allBatches[allBatches.length - 1]);
            
            _totalSupply += size;
        }
        
        migrateCursor += count;
        
        return lastAllocation;
    }
    
    function transferFrom(address from, address to, uint256 tokenId) public {
        if (!isActivated[tokenId]) {
            activate(tokenId);
        }
        super.transferFrom(from, to, tokenId);
    }
    
    function activate(uint256 tokenId) public {
        require(!isActivated[tokenId], "Token already activated");
        uint256 index = getBatchIndex(tokenId);
        require(index < allBatches.length, "Token batch doesn't exist");
        Batch memory a = allBatches[index];
        require(tokenId < a.startTokenId + a.size);
        isActivated[tokenId] = true;
        addTokenTo(a.owner, tokenId);
        unactivatedBalance[a.owner]--;
    }
    
    function getBatchIndex(uint256 tokenId) public pure returns (uint256) {
        uint256 index = (tokenId / maxAllocation);
        
        return index;
    }
    
    function categoryForToken(uint256 tokenId) public view returns (uint8) {
        uint256 index = getBatchIndex(tokenId);
        require(index < allBatches.length, "Token batch doesn't exist");
        
        Batch memory a = allBatches[index];
        
        return a.category;
    }
    
    function categoryIdForToken(uint256 tokenId) public view returns (uint256) {
        uint256 index = getBatchIndex(tokenId);
        require(index < allBatches.length, "Token batch doesn't exist");
        
        Batch memory a = allBatches[index];
        
        uint256 categoryId = (tokenId % maxAllocation) + a.startId;
        
        return categoryId;
    }
    
    function uintToString(uint v) internal pure returns (string memory) {
        if (v == 0) {
            return "0";
        }
        uint j = v;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (v != 0) {
            bstr[k--] = byte(uint8(48 + v % 10));
            v /= 10;
        }
        
        return string(bstr);
    }
    
    function tokenURI(uint256 tokenId) public view returns (string memory) {
        require(exists(tokenId), "Token doesn't exist!");
        if (isActivated[tokenId]) {
            return super.tokenURI(tokenId);
        } else {
            //Predict the token URI
            uint8 category = categoryForToken(tokenId);
            uint256 _categoryId = categoryIdForToken(tokenId);
            
            string memory id = uintToString(category).toSlice().concat("/".toSlice()).toSlice().concat(uintToString(_categoryId).toSlice().concat(".json".toSlice()).toSlice());
            string memory _base = "https://vault.warriders.com/guns/";
            
            //Final URL: https://vault.warriders.com/guns/<category>/<category_id>.json
            string memory _metadata = _base.toSlice().concat(id.toSlice());
            
            return _metadata;
        }
    }
    
    function addTokenTo(address _to, uint256 _tokenId) internal {
        //Predict the token URI
        uint8 category = categoryForToken(_tokenId);
        uint256 _categoryId = categoryIdForToken(_tokenId);
            
        string memory id = uintToString(category).toSlice().concat("/".toSlice()).toSlice().concat(uintToString(_categoryId).toSlice().concat(".json".toSlice()).toSlice());
        string memory _base = "https://vault.warriders.com/guns/";
            
        //Final URL: https://vault.warriders.com/guns/<category>/<category_id>.json
        string memory _metadata = _base.toSlice().concat(id.toSlice());
        
        super._addTokenTo(_to, _tokenId);
        super._setTokenURI(_tokenId, _metadata);
    }
    
    function ceil(uint a, uint m) internal pure returns (uint ) {
        return ((a + m - 1) / m) * m;
    }
    
    function _removeBatchFromOwner(address from, Batch memory batch) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).
        
        uint256 globalIndex = getBatchIndex(batch.startTokenId);

        uint256 lastBatchIndex = batchesOwned[from].length.sub(1);
        uint256 batchIndex = ownedBatchIndex[globalIndex];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (batchIndex != lastBatchIndex) {
            Batch memory lastBatch = batchesOwned[from][lastBatchIndex];
            uint256 lastGlobalIndex = getBatchIndex(lastBatch.startTokenId);

            batchesOwned[from][batchIndex] = lastBatch; // Move the last batch to the slot of the to-delete batch
            ownedBatchIndex[lastGlobalIndex] = batchIndex; // Update the moved batch's index
        }

        // This also deletes the contents at the last position of the array
        batchesOwned[from].length--;

        // Note that ownedBatchIndex[batch] hasn't been cleared: it still points to the old slot (now occupied by
        // lastBatch, or just over the end of the array if the batch was the last one).
    }
    
    function _addBatchToOwner(address to, Batch memory batch) private {
        uint256 globalIndex = getBatchIndex(batch.startTokenId);
        
        ownedBatchIndex[globalIndex] = batchesOwned[to].length;
        batchesOwned[to].push(batch);
    }
    
    function batchTransfer(uint256 batchIndex, address to) public {
        Batch storage a = allBatches[batchIndex];
        
        address previousOwner = a.owner;
        
        require(a.owner == msg.sender);
        
        _removeBatchFromOwner(previousOwner, a);
        
        a.owner = to;
        
        _addBatchToOwner(to, a);
        
        emit BatchTransfer(previousOwner, to, batchIndex);
        
        //Now to need to emit a bunch of transfer events
        uint end = a.startTokenId + a.size;
        uint256 unActivated = 0;
        for (uint i = a.startTokenId; i < end; i++) {
            if (isActivated[i]) {
                if (ownerOf(i) != previousOwner)
                    continue; //The previous owner didn't own this token, don't emit an event
            } else {
                unActivated++;
            }
            emit Transfer(previousOwner, to, i);
        }
        
        unactivatedBalance[to] += unActivated;
        unactivatedBalance[previousOwner] -= unActivated;
    }
}

contract ApproveAndCallFallBack {
    function receiveApproval(address from, uint256 tokens, address token, bytes memory data) public payable returns (bool);
}

/**
 * @title ERC20Basic
 * @dev Simpler version of ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/179
 */
contract ERC20Basic {
  function totalSupply() public view returns (uint256);
  function balanceOf(address who) public view returns (uint256);
  function transfer(address to, uint256 value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}

contract ERC20 is ERC20Basic {
  function allowance(address owner, address spender)
    public view returns (uint256);

  function transferFrom(address from, address to, uint256 value)
    public returns (bool);

  function approve(address spender, uint256 value) public returns (bool);
  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 value
  );
}

contract BurnableToken is ERC20 {
  event Burn(address indexed burner, uint256 value);
  function burn(uint256 _value) public;
}

contract StandardBurnableToken is BurnableToken {
  function burnFrom(address _from, uint256 _value) public;
}

interface BZNFeed {
    /**
     * Returns the converted BZN value
     */
    function convert(uint256 usd) external view returns (uint256);
}

contract SimpleBZNFeed is BZNFeed, Ownable {
    
    uint256 private conversion;
    
    function updateConversion(uint256 conversionRate) public onlyOwner {
        conversion = conversionRate;
    }
    
    function convert(uint256 usd) external view returns (uint256) {
        return usd * conversion;
    }
}

interface IDSValue {
   
    function peek() external view returns (bytes32, bool);
    function read() external view returns (bytes32);
    function poke(bytes32 wut) external;
    function void() external;
}

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,
        uint _start,
        uint _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_bytes.length >= (_start + _length));

        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)

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

        return tempBytes;
    }

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

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

        return tempAddress;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint _start) internal  pure returns (bytes32) {
        require(_bytes.length >= (_start + 32));
        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(uint(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(uint(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;
    }
}

contract GunPreOrder is Ownable, ApproveAndCallFallBack {
    using BytesLib for bytes;
    using SafeMath for uint256;
    
    //Event for when a bulk buy order has been placed
    event consumerBulkBuy(uint8 category, uint256 quanity, address reserver);
    //Event for when a gun has been bought
    event GunsBought(uint256 gunId, address owner, uint8 category);
    //Event for when ether is taken out of this contract
    event Withdrawal(uint256 amount);

    //Default referal commision percent
    uint256 public constant COMMISSION_PERCENT = 5;
    
    //Whether category is open
    mapping(uint8 => bool) public categoryExists;
    mapping(uint8 => bool) public categoryOpen;
    mapping(uint8 => bool) public categoryKilled;
    
    //The additional referal commision percent for any given referal address (default is 0)
    mapping(address => uint256) internal commissionRate;
    
    //How many guns in a given category an address has reserved
    mapping(uint8 => mapping(address => uint256)) public categoryReserveAmount;
    
    //Opensea buy address
    address internal constant OPENSEA = 0x5b3256965e7C3cF26E11FCAf296DfC8807C01073;

    //The percent increase and percent base for a given category
    mapping(uint8 => uint256) public categoryPercentIncrease;
    mapping(uint8 => uint256) public categoryPercentBase;

    //Price of a givevn category in USD WEI
    mapping(uint8 => uint256) public categoryPrice;
    
    //The percent of ether required for buying in BZN
    mapping(uint8 => uint256) public requiredEtherPercent;
    mapping(uint8 => uint256) public requiredEtherPercentBase;
    bool public allowCreateCategory = true;

    //The gun token contract
    GunToken public token;
    //The gun factory contract
    GunFactory internal factory;
    //The BZN contract
    StandardBurnableToken internal bzn;
    //The Maker ETH/USD price feed
    IDSValue public ethFeed;
    BZNFeed public bznFeed;
    //The gamepool address
    address internal gamePool;
    
    //Require the skinned/regular shop to be opened
    modifier ensureShopOpen(uint8 category) {
        require(categoryExists[category], "Category doesn't exist!");
        require(categoryOpen[category], "Category is not open!");
        _;
    }
    
    //Allow a function to accept ETH payment
    modifier payInETH(address referal, uint8 category, address new_owner, uint16 quanity) {
        uint256 usdPrice;
        uint256 totalPrice;
        (usdPrice, totalPrice) = priceFor(category, quanity);
        require(usdPrice > 0, "Price not yet set");
        
        categoryPrice[category] = usdPrice; //Save last price
        
        uint256 price = convert(totalPrice, false);
        
        require(msg.value >= price, "Not enough Ether sent!");
        
        _;
        
        if (msg.value > price) {
            uint256 change = msg.value - price;

            msg.sender.transfer(change);
        }
        
        if (referal != address(0)) {
            require(referal != msg.sender, "The referal cannot be the sender");
            require(referal != tx.origin, "The referal cannot be the tranaction origin");
            require(referal != new_owner, "The referal cannot be the new owner");

            //The commissionRate map adds any partner bonuses, or 0 if a normal user referral
            uint256 totalCommision = COMMISSION_PERCENT + commissionRate[referal];

            uint256 commision = (price * totalCommision) / 100;
            
            address payable _referal = address(uint160(referal));

            _referal.transfer(commision);
        }

    }
    
    //Allow function to accept BZN payment
    modifier payInBZN(address referal, uint8 category, address payable new_owner, uint16 quanity) {
        uint256[] memory prices = new uint256[](4); //Hack to work around local var limit (usdPrice, bznPrice, commision, totalPrice)
        (prices[0], prices[3]) = priceFor(category, quanity);
        require(prices[0] > 0, "Price not yet set");
            
        categoryPrice[category] = prices[0];
        
        prices[1] = convert(prices[3], true); //Convert the totalPrice to BZN

        //The commissionRate map adds any partner bonuses, or 0 if a normal user referral
        if (referal != address(0)) {
            prices[2] = (prices[1] * (COMMISSION_PERCENT + commissionRate[referal])) / 100;
        }
        
        uint256 requiredEther = (convert(prices[3], false) * requiredEtherPercent[category]) / requiredEtherPercentBase[category];
        
        require(msg.value >= requiredEther, "Buying with BZN requires some Ether!");
        
        bzn.burnFrom(new_owner, (((prices[1] - prices[2]) * 30) / 100));
        bzn.transferFrom(new_owner, gamePool, prices[1] - prices[2] - (((prices[1] - prices[2]) * 30) / 100));
        
        _;
        
        if (msg.value > requiredEther) {
            new_owner.transfer(msg.value - requiredEther);
        }
        
        if (referal != address(0)) {
            require(referal != msg.sender, "The referal cannot be the sender");
            require(referal != tx.origin, "The referal cannot be the tranaction origin");
            require(referal != new_owner, "The referal cannot be the new owner");
            
            bzn.transferFrom(new_owner, referal, prices[2]);
            
            prices[2] = (requiredEther * (COMMISSION_PERCENT + commissionRate[referal])) / 100;
            
            address payable _referal = address(uint160(referal));

            _referal.transfer(prices[2]);
        }
    }

    //Constructor
    constructor(
        address tokenAddress,
        address tokenFactory,
        address gp,
        address isd,
        address bzn_address
    ) public {
        token = GunToken(tokenAddress);

        factory = GunFactory(tokenFactory);
        
        ethFeed = IDSValue(isd);
        bzn = StandardBurnableToken(bzn_address);

        gamePool = gp;

        //Set percent increases
        categoryPercentIncrease[1] = 100035;
        categoryPercentBase[1] = 100000;
        
        categoryPercentIncrease[2] = 100025;
        categoryPercentBase[2] = 100000;
        
        categoryPercentIncrease[3] = 100015;
        categoryPercentBase[3] = 100000;
        
        commissionRate[OPENSEA] = 10;
    }
    
    function createCategory(uint8 category) public onlyOwner {
        require(allowCreateCategory);
        
        categoryExists[category] = true;
    }
    
    function disableCreateCategories() public onlyOwner {
        allowCreateCategory = false;
    }
    
    //Set the referal commision rate for an address
    function setCommission(address referral, uint256 percent) public onlyOwner {
        require(percent > COMMISSION_PERCENT);
        require(percent < 95);
        percent = percent - COMMISSION_PERCENT;
        
        commissionRate[referral] = percent;
    }
    
    //Set the price increase/base for skinned or regular guns
    function setPercentIncrease(uint256 increase, uint256 base, uint8 category) public onlyOwner {
        require(increase > base);
        
        categoryPercentIncrease[category] = increase;
        categoryPercentBase[category] = base;
    }
    
    function setEtherPercent(uint256 percent, uint256 base, uint8 category) public onlyOwner {
        requiredEtherPercent[category] = percent;
        requiredEtherPercentBase[category] = base;
    }
    
    function killCategory(uint8 category) public onlyOwner {
        require(!categoryKilled[category]);
        
        categoryOpen[category] = false;
        categoryKilled[category] = true;
    }

    //Open/Close the skinned or regular guns shop
    function setShopState(uint8 category, bool open) public onlyOwner {
        require(category == 1 || category == 2 || category == 3);
        require(!categoryKilled[category]);
        require(categoryExists[category]);
        
        categoryOpen[category] = open;
    }

    /**
     * Set the price for any given category in USD.
     */
    function setPrice(uint8 category, uint256 price, bool inWei) public onlyOwner {
        uint256 multiply = 1e18;
        if (inWei) {
            multiply = 1;
        }
        
        categoryPrice[category] = price * multiply;
    }

    /**
    Withdraw the amount from the contract's balance. Only the contract owner can execute this function
    */
    function withdraw(uint256 amount) public onlyOwner {
        uint256 balance = address(this).balance;

        require(amount <= balance, "Requested to much");
        
        address payable _owner = address(uint160(owner()));
        
        _owner.transfer(amount);

        emit Withdrawal(amount);
    }
    
    function setBZNFeedContract(address new_bzn_feed) public onlyOwner {
        bznFeed = BZNFeed(new_bzn_feed);
    }
    
    //Buy many skinned or regular guns with BZN. This will reserve the amount of guns and allows the new_owner to invoke claimGuns for free
    function buyWithBZN(address referal, uint8 category, address payable new_owner, uint16 quanity) ensureShopOpen(category) payInBZN(referal, category, new_owner, quanity) public payable returns (bool) {
        factory.mintFor(new_owner, quanity, category);
            
        return true;
    }
    
    //Buy many skinned or regular guns with ETH. This will reserve the amount of guns and allows the new_owner to invoke claimGuns for free
    function buyWithEther(address referal, uint8 category, address new_owner, uint16 quanity) ensureShopOpen(category) payInETH(referal, category, new_owner, quanity) public payable returns (bool) {
        factory.mintFor(new_owner, quanity, category);
        
        return true;
    }
    
    function convert(uint256 usdValue, bool isBZN) public view returns (uint256) {
        if (isBZN) {
            return bznFeed.convert(usdValue);
        } else {
            bool temp;
            bytes32 aaa;
            (aaa, temp) = ethFeed.peek();
                
            uint256 priceForEtherInUsdWei = uint256(aaa);
            
            return usdValue / (priceForEtherInUsdWei / 1e18);
        }
    }
    
    /**
    Get the price for skinned or regular guns in USD (wei)
    */
    function priceFor(uint8 category, uint16 quanity) public view returns (uint256, uint256) {
        require(quanity > 0);
        uint256 percent = categoryPercentIncrease[category];
        uint256 base = categoryPercentBase[category];

        uint256 currentPrice = categoryPrice[category];
        uint256 nextPrice = currentPrice;
        uint256 totalPrice = 0;
        //We can't use exponents because we'll overflow quickly
        //Only for loop :(
        for (uint i = 0; i < quanity; i++) {
            nextPrice = (currentPrice * percent) / base;
            
            currentPrice = nextPrice;
            
            totalPrice += nextPrice;
        }

        //Return the next price, as this is the true price
        return (nextPrice, totalPrice);
    }

    //Determine if a tokenId exists (has been sold)
    function sold(uint256 _tokenId) public view returns (bool) {
        return token.exists(_tokenId);
    }
    
    function receiveApproval(address from, uint256 tokenAmount, address tokenContract, bytes memory data) public payable returns (bool) {
        address referal;
        uint8 category;
        uint16 quanity;
        
        (referal, category, quanity) = abi.decode(data, (address, uint8, uint16));
        
        require(quanity >= 1);
        
        address payable _from = address(uint160(from)); 
        
        buyWithBZN(referal, category, _from, quanity);
        
        return true;
    }
}

contract GunFactory is Ownable {
    using strings for *;
    
    uint8 public constant PREMIUM_CATEGORY = 1;
    uint8 public constant MIDGRADE_CATEGORY = 2;
    uint8 public constant REGULAR_CATEGORY = 3;
    uint256 public constant ONE_MONTH = 2628000;
    
    uint256 public mintedGuns = 0;
    address preOrderAddress;
    GunToken token;
    
    mapping(uint8 => uint256) internal gunsMintedByCategory;
    mapping(uint8 => uint256) internal totalGunsMintedByCategory;
    
    mapping(uint8 => uint256) internal firstMonthLimit;
    mapping(uint8 => uint256) internal secondMonthLimit;
    mapping(uint8 => uint256) internal thirdMonthLimit;
    
    uint256 internal startTime;
    mapping(uint8 => uint256) internal currentMonthEnd;
    uint256 internal monthOneEnd;
    uint256 internal monthTwoEnd;

    modifier onlyPreOrder {
        require(msg.sender == preOrderAddress, "Not authorized");
        _;
    }

    modifier isInitialized {
        require(preOrderAddress != address(0), "No linked preorder");
        require(address(token) != address(0), "No linked token");
        _;
    }
    
    constructor() public {
        firstMonthLimit[PREMIUM_CATEGORY] = 5000;
        firstMonthLimit[MIDGRADE_CATEGORY] = 20000;
        firstMonthLimit[REGULAR_CATEGORY] = 30000;
        
        secondMonthLimit[PREMIUM_CATEGORY] = 2500;
        secondMonthLimit[MIDGRADE_CATEGORY] = 10000;
        secondMonthLimit[REGULAR_CATEGORY] = 15000;
        
        thirdMonthLimit[PREMIUM_CATEGORY] = 600;
        thirdMonthLimit[MIDGRADE_CATEGORY] = 3000;
        thirdMonthLimit[REGULAR_CATEGORY] = 6000;
        
        startTime = block.timestamp;
        monthOneEnd = startTime + ONE_MONTH;
        monthTwoEnd = startTime + ONE_MONTH + ONE_MONTH;
        
        currentMonthEnd[PREMIUM_CATEGORY] = monthOneEnd;
        currentMonthEnd[MIDGRADE_CATEGORY] = monthOneEnd;
        currentMonthEnd[REGULAR_CATEGORY] = monthOneEnd;
    }

    function uintToString(uint v) internal pure returns (string memory) {
        if (v == 0) {
            return "0";
        }
        uint j = v;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (v != 0) {
            bstr[k--] = byte(uint8(48 + v % 10));
            v /= 10;
        }
        
        return string(bstr);
    }

    function mintFor(address newOwner, uint16 size, uint8 category) public onlyPreOrder isInitialized returns (uint256) {
        GunPreOrder preOrder = GunPreOrder(preOrderAddress);
        require(preOrder.categoryExists(category), "Invalid category");
        
        require(!hasReachedLimit(category), "The monthly limit has been reached");
        
        token.claimAllocation(newOwner, size, category);
        
        mintedGuns++;
        
        gunsMintedByCategory[category] = gunsMintedByCategory[category] + 1;
        totalGunsMintedByCategory[category] = totalGunsMintedByCategory[category] + 1;
    }
    
    function hasReachedLimit(uint8 category) internal returns (bool) {
        uint256 currentTime = block.timestamp;
        uint256 limit = currentLimit(category);
        
        uint256 monthEnd = currentMonthEnd[category];
        
        //If the current block time is greater than or equal to the end of the month
        if (currentTime >= monthEnd) {
            //It's a new month, reset all limits
            //gunsMintedByCategory[PREMIUM_CATEGORY] = 0;
            //gunsMintedByCategory[MIDGRADE_CATEGORY] = 0;
            //gunsMintedByCategory[REGULAR_CATEGORY] = 0;
            gunsMintedByCategory[category] = 0;
            
            //Set next month end to be equal one month in advance
            //do this while the current time is greater than the next month end
            while (currentTime >= monthEnd) {
                monthEnd = monthEnd + ONE_MONTH;
            }
            
            //Finally, update the limit
            limit = currentLimit(category);
            currentMonthEnd[category] = monthEnd;
        }
        
        //Check if the limit has been reached
        return gunsMintedByCategory[category] >= limit;
    }
    
    function reachedLimit(uint8 category) public view returns (bool) {
        uint256 limit = currentLimit(category);
        
        return gunsMintedByCategory[category] >= limit;
    }
    
    function currentLimit(uint8 category) public view returns (uint256) {
        uint256 currentTime = block.timestamp;
        uint256 limit;
        if (currentTime < monthOneEnd) {
            limit = firstMonthLimit[category];
        } else if (currentTime < monthTwoEnd) {
            limit = secondMonthLimit[category];
        } else {
            limit = thirdMonthLimit[category];
        }
        
        return limit;
    }
    
    function setCategoryLimit(uint8 category, uint256 firstLimit, uint256 secondLimit, uint256 thirdLimit) public onlyOwner {
        require(firstMonthLimit[category] == 0);
        require(secondMonthLimit[category] == 0);
        require(thirdMonthLimit[category] == 0);
        
        firstMonthLimit[category] = firstLimit;
        secondMonthLimit[category] = secondLimit;
        thirdMonthLimit[category] = thirdLimit;
    }
    
    /**
    Attach the preOrder that will be receiving tokens being marked for sale by the
    sellCar function
    */
    function attachPreOrder(address dst) public onlyOwner {
        //Enforce that address is indeed a preorder
        GunPreOrder preOrder = GunPreOrder(dst);

        preOrderAddress = address(preOrder);
    }

    /**
    Attach the token being used for things
    */
    function attachToken(address dst) public onlyOwner {
        require(address(token) == address(0));
        require(dst != address(0));

        //Enforce that address is indeed a preorder
        GunToken ct = GunToken(dst);

        token = ct;
    }
}

Contract Security Audit

Contract ABI

[{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ownedBatchIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint8","name":"category","type":"uint8"},{"internalType":"uint256","name":"categoryId","type":"uint256"}],"name":"categoryTypeToId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"batchesOwned","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint16","name":"size","type":"uint16"},{"internalType":"uint8","name":"category","type":"uint8"},{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"startTokenId","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokenOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"categoryIdForToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getBatchIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"name":"migrate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint16","name":"size","type":"uint16"},{"internalType":"uint8","name":"category","type":"uint8"}],"name":"claimAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allTokens","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"categoryForToken","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxAllocation","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"batchIndex","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"batchTransfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"activate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"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":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allBatches","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint16","name":"size","type":"uint16"},{"internalType":"uint8","name":"category","type":"uint8"},{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"startTokenId","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getTokensInBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getBatchCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"factoryAddress","type":"address"},{"internalType":"address","name":"oldGunToken","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"batchIndex","type":"uint256"}],"name":"BatchTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","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"}]

60806040526000600f5560006010553480156200001b57600080fd5b506040516200629a3803806200629a833981810160405260408110156200004157600080fd5b8101908080519060200190929190805190602001909291905050506040518060400160405280600e81526020017f576172205269646572732047756e0000000000000000000000000000000000008152506040518060400160405280600381526020017f5752470000000000000000000000000000000000000000000000000000000000815250620000e06301ffc9a760e01b6200029760201b60201c565b620000f86380ac58cd60e01b6200029760201b60201c565b6200011063780e9d6360e01b6200029760201b60201c565b816009908051906020019062000128929190620003a8565b5080600a908051906020019062000141929190620003a8565b506200015a635b5e139f60e01b6200029760201b60201c565b505060006200016e620003a060201b60201c565b905080600c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35081600d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600e60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505062000457565b63ffffffff60e01b817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141562000334576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4552433136353a20696e76616c696420696e746572666163652069640000000081525060200191505060405180910390fd5b6001600080837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b600033905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620003eb57805160ff19168380011785556200041c565b828001600101855582156200041c579182015b828111156200041b578251825591602001919060010190620003fe565b5b5090506200042b91906200042f565b5090565b6200045491905b808211156200045057600081600090555060010162000436565b5090565b90565b615e3380620004676000396000f3fe608060405234801561001057600080fd5b50600436106102315760003560e01c80636ff97f1d11610130578063a51d6be0116100b8578063d3204c0c1161007c578063d3204c0c14610e75578063e985e9c514610f18578063e9a04ce014610f94578063f2fde38b14610fb2578063f8d39a3614610ff657610231565b8063a51d6be014610bb5578063b260c42a14610c03578063b88d4fde14610c31578063bfe6d41714610d36578063c87b56dd14610dce57610231565b80638f32d59b116100ff5780638f32d59b14610a52578063956accf914610a7457806395d89b4114610abc5780639b3ba79f14610b3f578063a22cb46514610b6557610231565b80636ff97f1d1461094757806370a08231146109a6578063715018a6146109fe5780638da5cb5b14610a0857610231565b8063294cdf0d116101be578063454b060811610182578063454b06081461079c5780634f558e79146107de5780634f6ccce714610824578063519861a7146108665780636352211e146108d957610231565b8063294cdf0d146105af5780632a9d74bb146106485780632f745c591461068a57806342842e0e146106ec57806344ec3c071461075a57610231565b806308fff1461161020557806308fff146146103ce578063095ea7b31461041d578063141321621461046b57806318160ddd1461052357806323b872dd1461054157610231565b80622b557d1461023657806301ffc9a71461027857806306fdde03146102dd578063081812fc14610360575b600080fd5b6102626004803603602081101561024c57600080fd5b810190808035906020019092919050505061104e565b6040518082815260200191505060405180910390f35b6102c36004803603602081101561028e57600080fd5b8101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169060200190929190505050611066565b604051808215151515815260200191505060405180910390f35b6102e56110cd565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561032557808201518184015260208101905061030a565b50505050905090810190601f1680156103525780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61038c6004803603602081101561037657600080fd5b810190808035906020019092919050505061116f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610407600480360360408110156103e457600080fd5b81019080803560ff1690602001909291908035906020019092919050505061120a565b6040518082815260200191505060405180910390f35b6104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611371565b005b6104b76004803603604081101561048157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611558565b604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018561ffff1661ffff1681526020018460ff1660ff1681526020018381526020018281526020019550505050505060405180910390f35b61052b6115e3565b6040518082815260200191505060405180910390f35b6105ad6004803603606081101561055757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115ed565b005b6105f1600480360360208110156105c557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061162c565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610634578082015181840152602081019050610619565b505050509050019250505060405180910390f35b6106746004803603602081101561065e57600080fd5b810190808035906020019092919050505061195a565b6040518082815260200191505060405180910390f35b6106d6600480360360408110156106a057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611ade565b6040518082815260200191505060405180910390f35b6107586004803603606081101561070257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611b04565b005b6107866004803603602081101561077057600080fd5b8101908080359060200190929190505050611b24565b6040518082815260200191505060405180910390f35b6107c8600480360360208110156107b257600080fd5b8101908080359060200190929190505050611b42565b6040518082815260200191505060405180910390f35b61080a600480360360208110156107f457600080fd5b810190808035906020019092919050505061211f565b604051808215151515815260200191505060405180910390f35b6108506004803603602081101561083a57600080fd5b8101908080359060200190929190505050612273565b6040518082815260200191505060405180910390f35b6108c36004803603606081101561087c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803561ffff169060200190929190803560ff169060200190929190505050612297565b6040518082815260200191505060405180910390f35b610905600480360360208110156108ef57600080fd5b8101908080359060200190929190505050612704565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61094f61293e565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610992578082015181840152602081019050610977565b505050509050019250505060405180910390f35b6109e8600480360360208110156109bc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612ad5565b6040518082815260200191505060405180910390f35b610a06612bad565b005b610a10612ce8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610a5a612d12565b604051808215151515815260200191505060405180910390f35b610aa060048036036020811015610a8a57600080fd5b8101908080359060200190929190505050612d71565b604051808260ff1660ff16815260200191505060405180910390f35b610ac4612ede565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610b04578082015181840152602081019050610ae9565b50505050905090810190601f168015610b315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610b47612f80565b604051808261ffff1661ffff16815260200191505060405180910390f35b610bb360048036036040811015610b7b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803515159060200190929190505050612f86565b005b610c0160048036036040811015610bcb57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061313e565b005b610c2f60048036036020811015610c1957600080fd5b81019080803590602001909291905050506135b0565b005b610d3460048036036080811015610c4757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190640100000000811115610cae57600080fd5b820183602082011115610cc057600080fd5b80359060200191846001830284011164010000000083111715610ce257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061384f565b005b610d6260048036036020811015610d4c57600080fd5b81019080803590602001909291905050506138c7565b604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018561ffff1661ffff1681526020018460ff1660ff1681526020018381526020018281526020019550505050505060405180910390f35b610dfa60048036036020811015610de457600080fd5b8101908080359060200190929190505050613945565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610e3a578082015181840152602081019050610e1f565b50505050905090810190601f168015610e675780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610ec160048036036040811015610e8b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613b4c565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610f04578082015181840152602081019050610ee9565b505050509050019250505060405180910390f35b610f7a60048036036040811015610f2e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613d93565b604051808215151515815260200191505060405180910390f35b610f9c613e27565b6040518082815260200191505060405180910390f35b610ff460048036036020811015610fc857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613e2d565b005b6110386004803603602081101561100c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613eb3565b6040518082815260200191505060405180910390f35b60156020528060005260406000206000915090505481565b6000806000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900460ff169050919050565b606060098054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156111655780601f1061113a57610100808354040283529160200191611165565b820191906000526020600020905b81548152906001019060200180831161114857829003601f168201915b5050505050905090565b600061117a82613eff565b6111cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615cfd602c913960400191505060405180910390fd5b6002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b600080600090505b60118054905081101561136557611227615999565b6011828154811061123457fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff1681526020016001820154815260200160028201548152505090508460ff16816040015160ff161461130d5750611358565b6000816020015161ffff1682606001510190508160600151851015801561133357508085105b156113555760008260600151860390508083608001510194505050505061136b565b50505b8080600101915050611212565b50600080fd5b92915050565b600061137c82612704565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611403576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180615dad6021913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16611422613f71565b73ffffffffffffffffffffffffffffffffffffffff16148061145157506114508161144b613f71565b613d93565b5b6114a6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526038815260200180615c726038913960400191505060405180910390fd5b826002600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b6014602052816000526040600020818154811061157157fe5b9060005260206000209060030201600091509150508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900461ffff16908060000160169054906101000a900460ff16908060010154908060020154905085565b6000601754905090565b6013600082815260200190815260200160002060009054906101000a900460ff1661161c5761161b816135b0565b5b611627838383613f79565b505050565b60608061163883612ad5565b6040519080825280602002602001820160405280156116665781602001602082028038833980820191505090505b509050600080905060008090505b601460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490508110156118a1576116c6615999565b601460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811061171057fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff1681526020016001820154815260200160028201548152505090506000816020015161ffff1682608001510190506000826080015190505b81811015611891576013600082815260200190815260200160002060009054906101000a900460ff16801561185857508773ffffffffffffffffffffffffffffffffffffffff1661183f82613fef565b73ffffffffffffffffffffffffffffffffffffffff1614155b1561186257611884565b8086868151811061186f57fe5b60200260200101818152505084806001019550505b80806001019150506117ef565b5050508080600101915050611674565b5060606118ad856140b7565b8054806020026020016040519081016040528092919081815260200182805480156118f757602002820191906000526020600020905b8154815260200190600101908083116118e3575b5050505050905060008090505b815181101561194e5781818151811061191957fe5b602002602001015184848151811061192d57fe5b60200260200101818152505082806001019350508080600101915050611904565b50829350505050919050565b60008061196683611b24565b905060118054905081106119e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f546f6b656e20626174636820646f65736e27742065786973740000000000000081525060200191505060405180910390fd5b6119ea615999565b601182815481106119f757fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff16815260200160018201548152602001600282015481525050905060008160600151610fa061ffff168681611acf57fe5b06019050809350505050919050565b6000611ae98361162c565b8281518110611af457fe5b6020026020010151905092915050565b611b1f8383836040518060200160405280600081525061384f565b505050565b600080610fa061ffff168381611b3657fe5b04905080915050919050565b6000611b4c612d12565b611bbe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6000600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008090505b8381101561210357600081600f5401905060008060008060008773ffffffffffffffffffffffffffffffffffffffff1663bfe6d417876040518263ffffffff1660e01b81526004018082815260200191505060a06040518083038186803b158015611c5557600080fd5b505afa158015611c69573d6000803e3d6000fd5b505050506040513d60a0811015611c7f57600080fd5b8101908080519060200190929190805190602001909291908051906020019092919080519060200190929190805190602001909291905050509450945094509450945060116040518060a001604052808773ffffffffffffffffffffffffffffffffffffffff1681526020018661ffff1681526020018560ff168152602001848152602001838152509080600181540180825580915050906001820390600052602060002090600302016000909192909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548160ff021916908360ff160217905550606082015181600101556080820151816002015550505060008461ffff1660105401905060008561ffff169050600060105490505b82811015611f6d5760008b73ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611e4e57600080fd5b505afa158015611e62573d6000803e3d6000fd5b505050506040513d6020811015611e7857600080fd5b810190808051906020019092919050505090508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611f025760016013600084815260200190815260200160002060006101000a81548160ff021916908315150217905550611ef481836140ff565b828060019003935050611f5f565b818973ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45b508080600101915050611df3565b50610fa061ffff1660106000828254019250508190555080601260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508561ffff16601660008760ff1660ff168152602001908152602001600020600082825401925050819055506120da8760116001601180549050038154811061201557fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff16815260200160018201548152602001600282015481525050614262565b8561ffff1660176000828254019250508190555050505050505050508080600101915050611beb565b5082600f60008282540192505081905550601054915050919050565b60006013600083815260200190815260200160002060009054906101000a900460ff16156121575761215082613eff565b905061226e565b600061216283611b24565b905060118054905081101561226857612179615999565b6011828154811061218657fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff1681526020016001820154815260200160028201548152505090506000816020015161ffff168260800151019050808510935050505061226e565b60009150505b919050565b600061227d61293e565b828151811061228857fe5b60200260200101519050919050565b6000600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461235c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f4e6f7420617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b610fa061ffff168361ffff16106123be576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180615b826027913960400191505060405180910390fd5b60116040518060a001604052808673ffffffffffffffffffffffffffffffffffffffff1681526020018561ffff1681526020018460ff168152602001601660008660ff1660ff1681526020019081526020016000205481526020016010548152509080600181540180825580915050906001820390600052602060002090600302016000909192909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548160ff021916908360ff160217905550606082015181600101556080820151816002015550505060008361ffff16601054019050600060105490505b8181101561257257808673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a48080600101915050612501565b50610fa061ffff166010600082825401925050819055508361ffff16601260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508361ffff16601660008560ff1660ff168152602001908152602001600020600082825401925050819055506126e38560116001601180549050038154811061261e57fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff16815260200160018201548152602001600282015481525050614262565b8361ffff166017600082825401925050819055506010549150509392505050565b600061270f8261211f565b612781576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f546f6b656e20646f65736e27742065786973742100000000000000000000000081525060200191505060405180910390fd5b6013600083815260200190815260200160002060009054906101000a900460ff16156127b7576127b082613fef565b9050612939565b60006127c283611b24565b9050601180549050811061283e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f546f6b656e20626174636820646f65736e27742065786973740000000000000081525060200191505060405180910390fd5b612846615999565b6011828154811061285357fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff168152602001600182015481526020016002820154815250509050806020015161ffff16816080015101841061292f57600080fd5b8060000151925050505b919050565b6060806129496115e3565b6040519080825280602002602001820160405280156129775781602001602082028038833980820191505090505b509050600080905060008090505b601180549050811015612acc5761299a615999565b601182815481106129a757fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff1681526020016001820154815260200160028201548152505090506000816020015161ffff1682608001510190506000826080015190505b81811015612abc5780868681518110612a9b57fe5b60200260200101818152505084806001019550508080600101915050612a86565b5050508080600101915050612985565b50819250505090565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612b5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180615caa602a913960400191505060405180910390fd5b601260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ba5836143df565b019050919050565b612bb5612d12565b612c27576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000600c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612d55613f71565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b600080612d7d83611b24565b90506011805490508110612df9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f546f6b656e20626174636820646f65736e27742065786973740000000000000081525060200191505060405180910390fd5b612e01615999565b60118281548110612e0e57fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff168152602001600182015481526020016002820154815250509050806040015192505050919050565b6060600a8054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015612f765780601f10612f4b57610100808354040283529160200191612f76565b820191906000526020600020905b815481529060010190602001808311612f5957829003601f168201915b5050505050905090565b610fa081565b612f8e613f71565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561302f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4552433732313a20617070726f766520746f2063616c6c65720000000000000081525060200191505060405180910390fd5b806004600061303c613f71565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff166130e9613f71565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051808215151515815260200191505060405180910390a35050565b60006011838154811061314d57fe5b9060005260206000209060030201905060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690503373ffffffffffffffffffffffffffffffffffffffff168260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146131e257600080fd5b61329e81836040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff168152602001600182015481526020016002820154815250506144b4565b828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061339d83836040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff16815260200160018201548152602001600282015481525050614262565b838373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fc42fa155158786a1dd6ccc3a785f35845467353c3cc700e0e31a79f90e22227d60405160405180910390a460008260000160149054906101000a900461ffff1661ffff16836002015401905060008090506000846002015490505b8281101561350d576013600082815260200190815260200160002060009054906101000a900460ff161561349b578373ffffffffffffffffffffffffffffffffffffffff1661347682612704565b73ffffffffffffffffffffffffffffffffffffffff161461349657613500565b6134a4565b81806001019250505b808673ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45b8080600101915050613428565b5080601260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555080601260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550505050505050565b6013600082815260200190815260200160002060009054906101000a900460ff1615613644576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f546f6b656e20616c72656164792061637469766174656400000000000000000081525060200191505060405180910390fd5b600061364f82611b24565b905060118054905081106136cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f546f6b656e20626174636820646f65736e27742065786973740000000000000081525060200191505060405180910390fd5b6136d3615999565b601182815481106136e057fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff168152602001600182015481526020016002820154815250509050806020015161ffff1681608001510183106137bc57600080fd5b60016013600085815260200190815260200160002060006101000a81548160ff0219169083151502179055506137f68160000151846140ff565b60126000826000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600190039190505550505050565b61386061385a613f71565b836147d3565b6138b5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526031815260200180615dce6031913960400191505060405180910390fd5b6138c1848484846148c7565b50505050565b601181815481106138d457fe5b90600052602060002090600302016000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900461ffff16908060000160169054906101000a900460ff16908060010154908060020154905085565b60606139508261211f565b6139c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f546f6b656e20646f65736e27742065786973742100000000000000000000000081525060200191505060405180910390fd5b6013600083815260200190815260200160002060009054906101000a900460ff16156139f8576139f182614939565b9050613b47565b6000613a0383612d71565b90506000613a108461195a565b90506060613af8613a7f613a7a613a5b6040518060400160405280600581526020017f2e6a736f6e000000000000000000000000000000000000000000000000000000815250614a4c565b613a6c613a6787614a7a565b614a4c565b614ba790919063ffffffff16565b614a4c565b613aea613ae5613ac36040518060400160405280600181526020017f2f00000000000000000000000000000000000000000000000000000000000000815250614a4c565b613ad7613ad28960ff16614a7a565b614a4c565b614ba790919063ffffffff16565b614a4c565b614ba790919063ffffffff16565b90506060604051806060016040528060218152602001615c016021913990506060613b3c613b2584614a4c565b613b2e84614a4c565b614ba790919063ffffffff16565b905080955050505050505b919050565b6060613b56615999565b601460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208381548110613ba057fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff1681526020016001820154815260200160028201548152505090506060816020015161ffff16604051908082528060200260200182016040528015613c9b5781602001602082028038833980820191505090505b50905060008090506000836020015161ffff1684608001510190506000846080015190505b81811015613d62576013600082815260200190815260200160002060009054906101000a900460ff168015613d2957508773ffffffffffffffffffffffffffffffffffffffff16613d1082613fef565b73ffffffffffffffffffffffffffffffffffffffff1614155b15613d3357613d55565b80848481518110613d4057fe5b60200260200101818152505082806001019350505b8080600101915050613cc0565b5060008211613d7057600080fd5b600082856020015161ffff16039050808451038452839550505050505092915050565b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b60105481565b613e35612d12565b613ea7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b613eb081614c29565b50565b6000601460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b6000806001600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415915050919050565b600033905090565b613f8a613f84613f71565b826147d3565b613fdf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526031815260200180615dce6031913960400191505060405180910390fd5b613fea838383614d6f565b505050565b6000806001600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156140ae576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526029815260200180615cd46029913960400191505060405180910390fd5b80915050919050565b6000600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050919050565b600061410a82612d71565b905060006141178361195a565b905060606141ff6141866141816141626040518060400160405280600581526020017f2e6a736f6e000000000000000000000000000000000000000000000000000000815250614a4c565b61417361416e87614a7a565b614a4c565b614ba790919063ffffffff16565b614a4c565b6141f16141ec6141ca6040518060400160405280600181526020017f2f00000000000000000000000000000000000000000000000000000000000000815250614a4c565b6141de6141d98960ff16614a7a565b614a4c565b614ba790919063ffffffff16565b614a4c565b614ba790919063ffffffff16565b90506060604051806060016040528060218152602001615c01602191399050606061424361422c84614a4c565b61423584614a4c565b614ba790919063ffffffff16565b905061424f8787614d93565b6142598682614db4565b50505050505050565b60006142718260800151611b24565b9050601460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506015600083815260200190815260200160002081905550601460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020829080600181540180825580915050906001820390600052602060002090600302016000909192909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548160ff021916908360ff1602179055506060820151816001015560808201518160020155505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415614466576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180615caa602a913960400191505060405180910390fd5b6144ad600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020614e3e565b9050919050565b60006144c38260800151611b24565b9050600061451d6001601460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050614e4c90919063ffffffff16565b905060006015600084815260200190815260200160002054905081811461477957614546615999565b601460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020838154811061459057fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff16815260200160018201548152602001600282015481525050905060006146618260800151611b24565b905081601460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002084815481106146ae57fe5b906000526020600020906003020160008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548160ff021916908360ff160217905550606082015181600101556080820151816002015590505082601560008381526020019081526020016000208190555050505b601460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054809190600190036147cb91906159e5565b505050505050565b60006147de82613eff565b614833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615c46602c913960400191505060405180910390fd5b600061483e83612704565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806148ad57508373ffffffffffffffffffffffffffffffffffffffff166148958461116f565b73ffffffffffffffffffffffffffffffffffffffff16145b806148be57506148bd8185613d93565b5b91505092915050565b6148d2848484614d6f565b6148de84848484614e96565b614933576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526032815260200180615ba96032913960400191505060405180910390fd5b50505050565b606061494482613eff565b614999576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f815260200180615d7e602f913960400191505060405180910390fd5b600b60008381526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015614a405780601f10614a1557610100808354040283529160200191614a40565b820191906000526020600020905b815481529060010190602001808311614a2357829003601f168201915b50505050509050919050565b614a54615a17565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606000821415614ac2576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050614ba2565b600082905060005b60008214614aec578080600101915050600a8281614ae457fe5b049150614aca565b6060816040519080825280601f01601f191660200182016040528015614b215781602001600182028038833980820191505090505b50905060006001830390505b60008614614b9a57600a8681614b3f57fe5b0660300160f81b82828060019003935081518110614b5957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a8681614b9257fe5b049550614b2d565b819450505050505b919050565b60608082600001518460000151016040519080825280601f01601f191660200182016040528015614be75781602001600182028038833980820191505090505b5090506000602082019050614c058186602001518760000151615086565b614c1e8560000151820185602001518660000151615086565b819250505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415614caf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180615bdb6026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a380600c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b614d7a8383836150cf565b614d84838261532a565b614d8e82826154c8565b505050565b614d9d828261558f565b614da782826154c8565b614db08161574b565b5050565b614dbd82613eff565b614e12576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615d29602c913960400191505060405180910390fd5b80600b60008481526020019081526020016000209080519060200190614e39929190615a31565b505050565b600081600001549050919050565b6000614e8e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250615797565b905092915050565b6000614eb78473ffffffffffffffffffffffffffffffffffffffff16615857565b614ec4576001905061507e565b60008473ffffffffffffffffffffffffffffffffffffffff1663150b7a02614eea613f71565b8887876040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614fa6578082015181840152602081019050614f8b565b50505050905090810190601f168015614fd35780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015614ff557600080fd5b505af1158015615009573d6000803e3d6000fd5b505050506040513d602081101561501f57600080fd5b8101908080519060200190929190505050905063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149150505b949350505050565b5b602081106150aa5781518352602083019250602082019150602081039050615087565b60006001826020036101000a0390508019835116818551168181178652505050505050565b8273ffffffffffffffffffffffffffffffffffffffff166150ef82612704565b73ffffffffffffffffffffffffffffffffffffffff161461515b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526029815260200180615d556029913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156151e1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180615c226024913960400191505060405180910390fd5b6151ea816158a2565b615231600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020615960565b615278600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020615983565b816001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b60006153826001600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050614e4c90919063ffffffff16565b905060006006600084815260200190815260200160002054905081811461546f576000600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002083815481106153ef57fe5b9060005260206000200154905080600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020838154811061544757fe5b9060005260206000200181905550816006600083815260200190815260200160002081905550505b600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054809190600190036154c19190615ab1565b5050505050565b600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506006600083815260200190815260200160002081905550600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150509060018203906000526020600020016000909192909190915055505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415615632576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4552433732313a206d696e7420746f20746865207a65726f206164647265737381525060200191505060405180910390fd5b61563b81613eff565b156156ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000081525060200191505060405180910390fd5b816001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550615747600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020615983565b5050565b6007805490506008600083815260200190815260200160002081905550600781908060018154018082558091505090600182039060005260206000200160009091929091909150555050565b6000838311158290615844576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156158095780820151818401526020810190506157ee565b50505050905090810190601f1680156158365780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b60008060007fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060001b9050833f91506000801b82141580156158995750808214155b92505050919050565b600073ffffffffffffffffffffffffffffffffffffffff166002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461595d5760006002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50565b61597860018260000154614e4c90919063ffffffff16565b816000018190555050565b6001816000016000828254019250508190555050565b6040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600061ffff168152602001600060ff16815260200160008152602001600081525090565b815481835581811115615a1257600302816003028360005260206000209182019101615a119190615add565b5b505050565b604051806040016040528060008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615a7257805160ff1916838001178555615aa0565b82800160010185558215615aa0579182015b82811115615a9f578251825591602001919060010190615a84565b5b509050615aad9190615b5c565b5090565b815481835581811115615ad857818360005260206000209182019101615ad79190615b5c565b5b505050565b615b5991905b80821115615b5557600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a81549061ffff02191690556000820160166101000a81549060ff02191690556001820160009055600282016000905550600301615ae3565b5090565b90565b615b7e91905b80821115615b7a576000816000905550600101615b62565b5090565b9056fe53697a65206d75737420626520736d616c6c6572207468616e206d6178416c6c6f636174696f6e4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737368747470733a2f2f7661756c742e7761727269646572732e636f6d2f67756e732f4552433732313a207472616e7366657220746f20746865207a65726f20616464726573734552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656420666f7220616c6c4552433732313a2062616c616e636520717565727920666f7220746865207a65726f20616464726573734552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76656420717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732314d657461646174613a2055524920736574206f66206e6f6e6578697374656e7420746f6b656e4552433732313a207472616e73666572206f6620746f6b656e2074686174206973206e6f74206f776e4552433732314d657461646174613a2055524920717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76616c20746f2063757272656e74206f776e65724552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564a265627a7a72315820876931c215f7956d3a852fd29294df62b37bd1b5c267f0ba3dfa8814f2f4f2e064736f6c634300050b003200000000000000000000000062d981aea59c6c768dff55ffb7f745cb79eeaa3600000000000000000000000018f64687e77c012d062bce0396fbbf7f21e11b77

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102315760003560e01c80636ff97f1d11610130578063a51d6be0116100b8578063d3204c0c1161007c578063d3204c0c14610e75578063e985e9c514610f18578063e9a04ce014610f94578063f2fde38b14610fb2578063f8d39a3614610ff657610231565b8063a51d6be014610bb5578063b260c42a14610c03578063b88d4fde14610c31578063bfe6d41714610d36578063c87b56dd14610dce57610231565b80638f32d59b116100ff5780638f32d59b14610a52578063956accf914610a7457806395d89b4114610abc5780639b3ba79f14610b3f578063a22cb46514610b6557610231565b80636ff97f1d1461094757806370a08231146109a6578063715018a6146109fe5780638da5cb5b14610a0857610231565b8063294cdf0d116101be578063454b060811610182578063454b06081461079c5780634f558e79146107de5780634f6ccce714610824578063519861a7146108665780636352211e146108d957610231565b8063294cdf0d146105af5780632a9d74bb146106485780632f745c591461068a57806342842e0e146106ec57806344ec3c071461075a57610231565b806308fff1461161020557806308fff146146103ce578063095ea7b31461041d578063141321621461046b57806318160ddd1461052357806323b872dd1461054157610231565b80622b557d1461023657806301ffc9a71461027857806306fdde03146102dd578063081812fc14610360575b600080fd5b6102626004803603602081101561024c57600080fd5b810190808035906020019092919050505061104e565b6040518082815260200191505060405180910390f35b6102c36004803603602081101561028e57600080fd5b8101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169060200190929190505050611066565b604051808215151515815260200191505060405180910390f35b6102e56110cd565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561032557808201518184015260208101905061030a565b50505050905090810190601f1680156103525780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61038c6004803603602081101561037657600080fd5b810190808035906020019092919050505061116f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610407600480360360408110156103e457600080fd5b81019080803560ff1690602001909291908035906020019092919050505061120a565b6040518082815260200191505060405180910390f35b6104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611371565b005b6104b76004803603604081101561048157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611558565b604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018561ffff1661ffff1681526020018460ff1660ff1681526020018381526020018281526020019550505050505060405180910390f35b61052b6115e3565b6040518082815260200191505060405180910390f35b6105ad6004803603606081101561055757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115ed565b005b6105f1600480360360208110156105c557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061162c565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610634578082015181840152602081019050610619565b505050509050019250505060405180910390f35b6106746004803603602081101561065e57600080fd5b810190808035906020019092919050505061195a565b6040518082815260200191505060405180910390f35b6106d6600480360360408110156106a057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611ade565b6040518082815260200191505060405180910390f35b6107586004803603606081101561070257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611b04565b005b6107866004803603602081101561077057600080fd5b8101908080359060200190929190505050611b24565b6040518082815260200191505060405180910390f35b6107c8600480360360208110156107b257600080fd5b8101908080359060200190929190505050611b42565b6040518082815260200191505060405180910390f35b61080a600480360360208110156107f457600080fd5b810190808035906020019092919050505061211f565b604051808215151515815260200191505060405180910390f35b6108506004803603602081101561083a57600080fd5b8101908080359060200190929190505050612273565b6040518082815260200191505060405180910390f35b6108c36004803603606081101561087c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803561ffff169060200190929190803560ff169060200190929190505050612297565b6040518082815260200191505060405180910390f35b610905600480360360208110156108ef57600080fd5b8101908080359060200190929190505050612704565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61094f61293e565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610992578082015181840152602081019050610977565b505050509050019250505060405180910390f35b6109e8600480360360208110156109bc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612ad5565b6040518082815260200191505060405180910390f35b610a06612bad565b005b610a10612ce8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610a5a612d12565b604051808215151515815260200191505060405180910390f35b610aa060048036036020811015610a8a57600080fd5b8101908080359060200190929190505050612d71565b604051808260ff1660ff16815260200191505060405180910390f35b610ac4612ede565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610b04578082015181840152602081019050610ae9565b50505050905090810190601f168015610b315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610b47612f80565b604051808261ffff1661ffff16815260200191505060405180910390f35b610bb360048036036040811015610b7b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803515159060200190929190505050612f86565b005b610c0160048036036040811015610bcb57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061313e565b005b610c2f60048036036020811015610c1957600080fd5b81019080803590602001909291905050506135b0565b005b610d3460048036036080811015610c4757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190640100000000811115610cae57600080fd5b820183602082011115610cc057600080fd5b80359060200191846001830284011164010000000083111715610ce257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061384f565b005b610d6260048036036020811015610d4c57600080fd5b81019080803590602001909291905050506138c7565b604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018561ffff1661ffff1681526020018460ff1660ff1681526020018381526020018281526020019550505050505060405180910390f35b610dfa60048036036020811015610de457600080fd5b8101908080359060200190929190505050613945565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610e3a578082015181840152602081019050610e1f565b50505050905090810190601f168015610e675780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610ec160048036036040811015610e8b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613b4c565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610f04578082015181840152602081019050610ee9565b505050509050019250505060405180910390f35b610f7a60048036036040811015610f2e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613d93565b604051808215151515815260200191505060405180910390f35b610f9c613e27565b6040518082815260200191505060405180910390f35b610ff460048036036020811015610fc857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613e2d565b005b6110386004803603602081101561100c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613eb3565b6040518082815260200191505060405180910390f35b60156020528060005260406000206000915090505481565b6000806000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900460ff169050919050565b606060098054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156111655780601f1061113a57610100808354040283529160200191611165565b820191906000526020600020905b81548152906001019060200180831161114857829003601f168201915b5050505050905090565b600061117a82613eff565b6111cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615cfd602c913960400191505060405180910390fd5b6002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b600080600090505b60118054905081101561136557611227615999565b6011828154811061123457fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff1681526020016001820154815260200160028201548152505090508460ff16816040015160ff161461130d5750611358565b6000816020015161ffff1682606001510190508160600151851015801561133357508085105b156113555760008260600151860390508083608001510194505050505061136b565b50505b8080600101915050611212565b50600080fd5b92915050565b600061137c82612704565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611403576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180615dad6021913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16611422613f71565b73ffffffffffffffffffffffffffffffffffffffff16148061145157506114508161144b613f71565b613d93565b5b6114a6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526038815260200180615c726038913960400191505060405180910390fd5b826002600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b6014602052816000526040600020818154811061157157fe5b9060005260206000209060030201600091509150508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900461ffff16908060000160169054906101000a900460ff16908060010154908060020154905085565b6000601754905090565b6013600082815260200190815260200160002060009054906101000a900460ff1661161c5761161b816135b0565b5b611627838383613f79565b505050565b60608061163883612ad5565b6040519080825280602002602001820160405280156116665781602001602082028038833980820191505090505b509050600080905060008090505b601460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490508110156118a1576116c6615999565b601460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811061171057fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff1681526020016001820154815260200160028201548152505090506000816020015161ffff1682608001510190506000826080015190505b81811015611891576013600082815260200190815260200160002060009054906101000a900460ff16801561185857508773ffffffffffffffffffffffffffffffffffffffff1661183f82613fef565b73ffffffffffffffffffffffffffffffffffffffff1614155b1561186257611884565b8086868151811061186f57fe5b60200260200101818152505084806001019550505b80806001019150506117ef565b5050508080600101915050611674565b5060606118ad856140b7565b8054806020026020016040519081016040528092919081815260200182805480156118f757602002820191906000526020600020905b8154815260200190600101908083116118e3575b5050505050905060008090505b815181101561194e5781818151811061191957fe5b602002602001015184848151811061192d57fe5b60200260200101818152505082806001019350508080600101915050611904565b50829350505050919050565b60008061196683611b24565b905060118054905081106119e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f546f6b656e20626174636820646f65736e27742065786973740000000000000081525060200191505060405180910390fd5b6119ea615999565b601182815481106119f757fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff16815260200160018201548152602001600282015481525050905060008160600151610fa061ffff168681611acf57fe5b06019050809350505050919050565b6000611ae98361162c565b8281518110611af457fe5b6020026020010151905092915050565b611b1f8383836040518060200160405280600081525061384f565b505050565b600080610fa061ffff168381611b3657fe5b04905080915050919050565b6000611b4c612d12565b611bbe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6000600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008090505b8381101561210357600081600f5401905060008060008060008773ffffffffffffffffffffffffffffffffffffffff1663bfe6d417876040518263ffffffff1660e01b81526004018082815260200191505060a06040518083038186803b158015611c5557600080fd5b505afa158015611c69573d6000803e3d6000fd5b505050506040513d60a0811015611c7f57600080fd5b8101908080519060200190929190805190602001909291908051906020019092919080519060200190929190805190602001909291905050509450945094509450945060116040518060a001604052808773ffffffffffffffffffffffffffffffffffffffff1681526020018661ffff1681526020018560ff168152602001848152602001838152509080600181540180825580915050906001820390600052602060002090600302016000909192909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548160ff021916908360ff160217905550606082015181600101556080820151816002015550505060008461ffff1660105401905060008561ffff169050600060105490505b82811015611f6d5760008b73ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611e4e57600080fd5b505afa158015611e62573d6000803e3d6000fd5b505050506040513d6020811015611e7857600080fd5b810190808051906020019092919050505090508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611f025760016013600084815260200190815260200160002060006101000a81548160ff021916908315150217905550611ef481836140ff565b828060019003935050611f5f565b818973ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45b508080600101915050611df3565b50610fa061ffff1660106000828254019250508190555080601260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508561ffff16601660008760ff1660ff168152602001908152602001600020600082825401925050819055506120da8760116001601180549050038154811061201557fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff16815260200160018201548152602001600282015481525050614262565b8561ffff1660176000828254019250508190555050505050505050508080600101915050611beb565b5082600f60008282540192505081905550601054915050919050565b60006013600083815260200190815260200160002060009054906101000a900460ff16156121575761215082613eff565b905061226e565b600061216283611b24565b905060118054905081101561226857612179615999565b6011828154811061218657fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff1681526020016001820154815260200160028201548152505090506000816020015161ffff168260800151019050808510935050505061226e565b60009150505b919050565b600061227d61293e565b828151811061228857fe5b60200260200101519050919050565b6000600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461235c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f4e6f7420617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b610fa061ffff168361ffff16106123be576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180615b826027913960400191505060405180910390fd5b60116040518060a001604052808673ffffffffffffffffffffffffffffffffffffffff1681526020018561ffff1681526020018460ff168152602001601660008660ff1660ff1681526020019081526020016000205481526020016010548152509080600181540180825580915050906001820390600052602060002090600302016000909192909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548160ff021916908360ff160217905550606082015181600101556080820151816002015550505060008361ffff16601054019050600060105490505b8181101561257257808673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a48080600101915050612501565b50610fa061ffff166010600082825401925050819055508361ffff16601260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508361ffff16601660008560ff1660ff168152602001908152602001600020600082825401925050819055506126e38560116001601180549050038154811061261e57fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff16815260200160018201548152602001600282015481525050614262565b8361ffff166017600082825401925050819055506010549150509392505050565b600061270f8261211f565b612781576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f546f6b656e20646f65736e27742065786973742100000000000000000000000081525060200191505060405180910390fd5b6013600083815260200190815260200160002060009054906101000a900460ff16156127b7576127b082613fef565b9050612939565b60006127c283611b24565b9050601180549050811061283e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f546f6b656e20626174636820646f65736e27742065786973740000000000000081525060200191505060405180910390fd5b612846615999565b6011828154811061285357fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff168152602001600182015481526020016002820154815250509050806020015161ffff16816080015101841061292f57600080fd5b8060000151925050505b919050565b6060806129496115e3565b6040519080825280602002602001820160405280156129775781602001602082028038833980820191505090505b509050600080905060008090505b601180549050811015612acc5761299a615999565b601182815481106129a757fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff1681526020016001820154815260200160028201548152505090506000816020015161ffff1682608001510190506000826080015190505b81811015612abc5780868681518110612a9b57fe5b60200260200101818152505084806001019550508080600101915050612a86565b5050508080600101915050612985565b50819250505090565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612b5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180615caa602a913960400191505060405180910390fd5b601260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ba5836143df565b019050919050565b612bb5612d12565b612c27576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000600c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612d55613f71565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b600080612d7d83611b24565b90506011805490508110612df9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f546f6b656e20626174636820646f65736e27742065786973740000000000000081525060200191505060405180910390fd5b612e01615999565b60118281548110612e0e57fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff168152602001600182015481526020016002820154815250509050806040015192505050919050565b6060600a8054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015612f765780601f10612f4b57610100808354040283529160200191612f76565b820191906000526020600020905b815481529060010190602001808311612f5957829003601f168201915b5050505050905090565b610fa081565b612f8e613f71565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561302f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4552433732313a20617070726f766520746f2063616c6c65720000000000000081525060200191505060405180910390fd5b806004600061303c613f71565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff166130e9613f71565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051808215151515815260200191505060405180910390a35050565b60006011838154811061314d57fe5b9060005260206000209060030201905060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690503373ffffffffffffffffffffffffffffffffffffffff168260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146131e257600080fd5b61329e81836040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff168152602001600182015481526020016002820154815250506144b4565b828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061339d83836040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff16815260200160018201548152602001600282015481525050614262565b838373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fc42fa155158786a1dd6ccc3a785f35845467353c3cc700e0e31a79f90e22227d60405160405180910390a460008260000160149054906101000a900461ffff1661ffff16836002015401905060008090506000846002015490505b8281101561350d576013600082815260200190815260200160002060009054906101000a900460ff161561349b578373ffffffffffffffffffffffffffffffffffffffff1661347682612704565b73ffffffffffffffffffffffffffffffffffffffff161461349657613500565b6134a4565b81806001019250505b808673ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45b8080600101915050613428565b5080601260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555080601260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550505050505050565b6013600082815260200190815260200160002060009054906101000a900460ff1615613644576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f546f6b656e20616c72656164792061637469766174656400000000000000000081525060200191505060405180910390fd5b600061364f82611b24565b905060118054905081106136cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f546f6b656e20626174636820646f65736e27742065786973740000000000000081525060200191505060405180910390fd5b6136d3615999565b601182815481106136e057fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff168152602001600182015481526020016002820154815250509050806020015161ffff1681608001510183106137bc57600080fd5b60016013600085815260200190815260200160002060006101000a81548160ff0219169083151502179055506137f68160000151846140ff565b60126000826000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600190039190505550505050565b61386061385a613f71565b836147d3565b6138b5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526031815260200180615dce6031913960400191505060405180910390fd5b6138c1848484846148c7565b50505050565b601181815481106138d457fe5b90600052602060002090600302016000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900461ffff16908060000160169054906101000a900460ff16908060010154908060020154905085565b60606139508261211f565b6139c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f546f6b656e20646f65736e27742065786973742100000000000000000000000081525060200191505060405180910390fd5b6013600083815260200190815260200160002060009054906101000a900460ff16156139f8576139f182614939565b9050613b47565b6000613a0383612d71565b90506000613a108461195a565b90506060613af8613a7f613a7a613a5b6040518060400160405280600581526020017f2e6a736f6e000000000000000000000000000000000000000000000000000000815250614a4c565b613a6c613a6787614a7a565b614a4c565b614ba790919063ffffffff16565b614a4c565b613aea613ae5613ac36040518060400160405280600181526020017f2f00000000000000000000000000000000000000000000000000000000000000815250614a4c565b613ad7613ad28960ff16614a7a565b614a4c565b614ba790919063ffffffff16565b614a4c565b614ba790919063ffffffff16565b90506060604051806060016040528060218152602001615c016021913990506060613b3c613b2584614a4c565b613b2e84614a4c565b614ba790919063ffffffff16565b905080955050505050505b919050565b6060613b56615999565b601460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208381548110613ba057fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff1681526020016001820154815260200160028201548152505090506060816020015161ffff16604051908082528060200260200182016040528015613c9b5781602001602082028038833980820191505090505b50905060008090506000836020015161ffff1684608001510190506000846080015190505b81811015613d62576013600082815260200190815260200160002060009054906101000a900460ff168015613d2957508773ffffffffffffffffffffffffffffffffffffffff16613d1082613fef565b73ffffffffffffffffffffffffffffffffffffffff1614155b15613d3357613d55565b80848481518110613d4057fe5b60200260200101818152505082806001019350505b8080600101915050613cc0565b5060008211613d7057600080fd5b600082856020015161ffff16039050808451038452839550505050505092915050565b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b60105481565b613e35612d12565b613ea7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b613eb081614c29565b50565b6000601460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b6000806001600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415915050919050565b600033905090565b613f8a613f84613f71565b826147d3565b613fdf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526031815260200180615dce6031913960400191505060405180910390fd5b613fea838383614d6f565b505050565b6000806001600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156140ae576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526029815260200180615cd46029913960400191505060405180910390fd5b80915050919050565b6000600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050919050565b600061410a82612d71565b905060006141178361195a565b905060606141ff6141866141816141626040518060400160405280600581526020017f2e6a736f6e000000000000000000000000000000000000000000000000000000815250614a4c565b61417361416e87614a7a565b614a4c565b614ba790919063ffffffff16565b614a4c565b6141f16141ec6141ca6040518060400160405280600181526020017f2f00000000000000000000000000000000000000000000000000000000000000815250614a4c565b6141de6141d98960ff16614a7a565b614a4c565b614ba790919063ffffffff16565b614a4c565b614ba790919063ffffffff16565b90506060604051806060016040528060218152602001615c01602191399050606061424361422c84614a4c565b61423584614a4c565b614ba790919063ffffffff16565b905061424f8787614d93565b6142598682614db4565b50505050505050565b60006142718260800151611b24565b9050601460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506015600083815260200190815260200160002081905550601460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020829080600181540180825580915050906001820390600052602060002090600302016000909192909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548160ff021916908360ff1602179055506060820151816001015560808201518160020155505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415614466576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180615caa602a913960400191505060405180910390fd5b6144ad600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020614e3e565b9050919050565b60006144c38260800151611b24565b9050600061451d6001601460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050614e4c90919063ffffffff16565b905060006015600084815260200190815260200160002054905081811461477957614546615999565b601460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020838154811061459057fe5b90600052602060002090600302016040518060a00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900461ffff1661ffff1661ffff1681526020016000820160169054906101000a900460ff1660ff1660ff16815260200160018201548152602001600282015481525050905060006146618260800151611b24565b905081601460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002084815481106146ae57fe5b906000526020600020906003020160008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548160ff021916908360ff160217905550606082015181600101556080820151816002015590505082601560008381526020019081526020016000208190555050505b601460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054809190600190036147cb91906159e5565b505050505050565b60006147de82613eff565b614833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615c46602c913960400191505060405180910390fd5b600061483e83612704565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806148ad57508373ffffffffffffffffffffffffffffffffffffffff166148958461116f565b73ffffffffffffffffffffffffffffffffffffffff16145b806148be57506148bd8185613d93565b5b91505092915050565b6148d2848484614d6f565b6148de84848484614e96565b614933576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526032815260200180615ba96032913960400191505060405180910390fd5b50505050565b606061494482613eff565b614999576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f815260200180615d7e602f913960400191505060405180910390fd5b600b60008381526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015614a405780601f10614a1557610100808354040283529160200191614a40565b820191906000526020600020905b815481529060010190602001808311614a2357829003601f168201915b50505050509050919050565b614a54615a17565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606000821415614ac2576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050614ba2565b600082905060005b60008214614aec578080600101915050600a8281614ae457fe5b049150614aca565b6060816040519080825280601f01601f191660200182016040528015614b215781602001600182028038833980820191505090505b50905060006001830390505b60008614614b9a57600a8681614b3f57fe5b0660300160f81b82828060019003935081518110614b5957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a8681614b9257fe5b049550614b2d565b819450505050505b919050565b60608082600001518460000151016040519080825280601f01601f191660200182016040528015614be75781602001600182028038833980820191505090505b5090506000602082019050614c058186602001518760000151615086565b614c1e8560000151820185602001518660000151615086565b819250505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415614caf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180615bdb6026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a380600c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b614d7a8383836150cf565b614d84838261532a565b614d8e82826154c8565b505050565b614d9d828261558f565b614da782826154c8565b614db08161574b565b5050565b614dbd82613eff565b614e12576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615d29602c913960400191505060405180910390fd5b80600b60008481526020019081526020016000209080519060200190614e39929190615a31565b505050565b600081600001549050919050565b6000614e8e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250615797565b905092915050565b6000614eb78473ffffffffffffffffffffffffffffffffffffffff16615857565b614ec4576001905061507e565b60008473ffffffffffffffffffffffffffffffffffffffff1663150b7a02614eea613f71565b8887876040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614fa6578082015181840152602081019050614f8b565b50505050905090810190601f168015614fd35780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015614ff557600080fd5b505af1158015615009573d6000803e3d6000fd5b505050506040513d602081101561501f57600080fd5b8101908080519060200190929190505050905063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149150505b949350505050565b5b602081106150aa5781518352602083019250602082019150602081039050615087565b60006001826020036101000a0390508019835116818551168181178652505050505050565b8273ffffffffffffffffffffffffffffffffffffffff166150ef82612704565b73ffffffffffffffffffffffffffffffffffffffff161461515b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526029815260200180615d556029913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156151e1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180615c226024913960400191505060405180910390fd5b6151ea816158a2565b615231600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020615960565b615278600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020615983565b816001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b60006153826001600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050614e4c90919063ffffffff16565b905060006006600084815260200190815260200160002054905081811461546f576000600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002083815481106153ef57fe5b9060005260206000200154905080600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020838154811061544757fe5b9060005260206000200181905550816006600083815260200190815260200160002081905550505b600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054809190600190036154c19190615ab1565b5050505050565b600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506006600083815260200190815260200160002081905550600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150509060018203906000526020600020016000909192909190915055505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415615632576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4552433732313a206d696e7420746f20746865207a65726f206164647265737381525060200191505060405180910390fd5b61563b81613eff565b156156ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000081525060200191505060405180910390fd5b816001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550615747600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020615983565b5050565b6007805490506008600083815260200190815260200160002081905550600781908060018154018082558091505090600182039060005260206000200160009091929091909150555050565b6000838311158290615844576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156158095780820151818401526020810190506157ee565b50505050905090810190601f1680156158365780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b60008060007fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060001b9050833f91506000801b82141580156158995750808214155b92505050919050565b600073ffffffffffffffffffffffffffffffffffffffff166002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461595d5760006002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50565b61597860018260000154614e4c90919063ffffffff16565b816000018190555050565b6001816000016000828254019250508190555050565b6040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600061ffff168152602001600060ff16815260200160008152602001600081525090565b815481835581811115615a1257600302816003028360005260206000209182019101615a119190615add565b5b505050565b604051806040016040528060008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615a7257805160ff1916838001178555615aa0565b82800160010185558215615aa0579182015b82811115615a9f578251825591602001919060010190615a84565b5b509050615aad9190615b5c565b5090565b815481835581811115615ad857818360005260206000209182019101615ad79190615b5c565b5b505050565b615b5991905b80821115615b5557600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a81549061ffff02191690556000820160166101000a81549060ff02191690556001820160009055600282016000905550600301615ae3565b5090565b90565b615b7e91905b80821115615b7a576000816000905550600101615b62565b5090565b9056fe53697a65206d75737420626520736d616c6c6572207468616e206d6178416c6c6f636174696f6e4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737368747470733a2f2f7661756c742e7761727269646572732e636f6d2f67756e732f4552433732313a207472616e7366657220746f20746865207a65726f20616464726573734552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656420666f7220616c6c4552433732313a2062616c616e636520717565727920666f7220746865207a65726f20616464726573734552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76656420717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732314d657461646174613a2055524920736574206f66206e6f6e6578697374656e7420746f6b656e4552433732313a207472616e73666572206f6620746f6b656e2074686174206973206e6f74206f776e4552433732314d657461646174613a2055524920717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76616c20746f2063757272656e74206f776e65724552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564a265627a7a72315820876931c215f7956d3a852fd29294df62b37bd1b5c267f0ba3dfa8814f2f4f2e064736f6c634300050b0032

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000062d981aea59c6c768dff55ffb7f745cb79eeaa3600000000000000000000000018f64687e77c012d062bce0396fbbf7f21e11b77

-----Decoded View---------------
Arg [0] : factoryAddress (address): 0x62d981aea59C6c768dfF55ffB7F745cb79eEAA36
Arg [1] : oldGunToken (address): 0x18F64687E77C012D062BCe0396FBbF7f21e11B77

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000062d981aea59c6c768dff55ffb7f745cb79eeaa36
Arg [1] : 00000000000000000000000018f64687e77c012d062bce0396fbbf7f21e11b77


Deployed Bytecode Sourcemap

92844:15086:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;92844:15086:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;93701:50;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;93701:50:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;39860:135;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;39860:135:0;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;90908:85;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;90908:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71236:204;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;71236:204:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;94179:572;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;94179:572:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;70518:425;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;70518:425:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;93607:47;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;93607:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;98924:91;;;:::i;:::-;;;;;;;;;;;;;;;;;;;101461:209;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;101461:209:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;96795:876;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;96795:876:0;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;96795:876:0;;;;;;;;;;;;;;;;;102632:378;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;102632:378:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;95137:141;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;95137:141:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;73873:134;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;73873:134:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;102150:163;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;102150:163:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;99942:1507;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;99942:1507:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;98425:487;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;98425:487:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;96167:111;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;96167:111:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;99027:903;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;99027:903:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;97923:490;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;97923:490:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;96290:493;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;96290:493:0;;;;;;;;;;;;;;;;;97683:227;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;97683:227:0;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;66172:140;;;:::i;:::-;;65361:79;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;65727:94;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;102325:295;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;102325:295:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;91108:89;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;91108:89:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;93086:43;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;71741:254;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;71741:254:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;106867:1060;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;106867:1060:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;101682:456;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;101682:456:0;;;;;;;;;;;;;;;;;:::i;:::-;;74744:272;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;74744:272:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21:11:-1;8;5:28;2:2;;;46:1;43;36:12;2:2;74744:272:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;74744:272:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;74744:272:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;93:3;85:6;81:16;74:27;137:4;133:9;126:4;121:3;117:14;113:30;106:37;;169:3;161:6;157:16;147:26;;74744:272:0;;;;;;;;;;;;;;;:::i;:::-;;93445:25;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;93445:25:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;103510:896;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;103510:896:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;103510:896:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;95421:734;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;95421:734:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;95421:734:0;;;;;;;;;;;;;;;;;72325:147;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;72325:147:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;93136:33;;;:::i;:::-;;;;;;;;;;;;;;;;;;;66467:109;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;66467:109:0;;;;;;;;;;;;;;;;;;;:::i;:::-;;95290:119;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;95290:119:0;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;93701:50;;;;;;;;;;;;;;;;;:::o;39860:135::-;39930:4;39954:20;:33;39975:11;39954:33;;;;;;;;;;;;;;;;;;;;;;;;;;;39947:40;;39860:135;;;:::o;90908:85::-;90947:13;90980:5;90973:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90908:85;:::o;71236:204::-;71295:7;71323:16;71331:7;71323;:16::i;:::-;71315:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71408:15;:24;71424:7;71408:24;;;;;;;;;;;;;;;;;;;;;71401:31;;71236:204;;;:::o;94179:572::-;94262:7;94287:6;94296:1;94287:10;;94282:433;94303:10;:17;;;;94299:1;:21;94282:433;;;94342:14;;:::i;:::-;94359:10;94370:1;94359:13;;;;;;;;;;;;;;;;;;94342:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94405:8;94391:22;;:1;:10;;;:22;;;94387:53;;94432:8;;;94387:53;94469:13;94497:1;:6;;;94485:18;;:1;:9;;;:18;94469:34;;94536:1;:9;;;94522:10;:23;;:45;;;;;94562:5;94549:10;:18;94522:45;94518:186;;;94588:11;94615:1;:9;;;94602:10;:22;94588:36;;94685:3;94668:1;:14;;;:20;94661:27;;;;;;;;94518:186;94282:433;;;94322:3;;;;;;;94282:433;;;;94735:8;;;94179:572;;;;;:::o;70518:425::-;70582:13;70598:16;70606:7;70598;:16::i;:::-;70582:32;;70639:5;70633:11;;:2;:11;;;;70625:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;70719:5;70703:21;;:12;:10;:12::i;:::-;:21;;;:62;;;;70728:37;70745:5;70752:12;:10;:12::i;:::-;70728:16;:37::i;:::-;70703:62;70695:154;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;70889:2;70862:15;:24;70878:7;70862:24;;;;;;;;;;;;:29;;;;;;;;;;;;;;;;;;70927:7;70923:2;70907:28;;70916:5;70907:28;;;;;;;;;;;;70518:425;;;:::o;93607:47::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;98924:91::-;98968:7;98995:12;;98988:19;;98924:91;:::o;101461:209::-;101549:11;:20;101561:7;101549:20;;;;;;;;;;;;;;;;;;;;;101544:71;;101586:17;101595:7;101586:8;:17::i;:::-;101544:71;101625:37;101644:4;101650:2;101654:7;101625:18;:37::i;:::-;101461:209;;;:::o;96795:876::-;96853:16;96882:23;96922:16;96932:5;96922:9;:16::i;:::-;96908:31;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;148:4;140:6;136:17;126:27;;0:157;96908:31:0;;;;96882:57;;96960:8;96971:1;96960:12;;96988:6;96997:1;96988:10;;96983:437;97004:12;:19;97017:5;97004:19;;;;;;;;;;;;;;;:26;;;;97000:1;:30;96983:437;;;97052:14;;:::i;:::-;97069:12;:19;97082:5;97069:19;;;;;;;;;;;;;;;97089:1;97069:22;;;;;;;;;;;;;;;;;;97052:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97106:8;97134:1;:6;;;97117:23;;:1;:14;;;:23;97106:34;;97160:6;97169:1;:14;;;97160:23;;97155:254;97189:3;97185:1;:7;97155:254;;;97222:11;:14;97234:1;97222:14;;;;;;;;;;;;;;;;;;;;;:43;;;;;97260:5;97240:25;;:16;97254:1;97240:13;:16::i;:::-;:25;;;;97222:43;97218:100;;;97290:8;;97218:100;97368:1;97354:6;97361:3;97354:11;;;;;;;;;;;;;:15;;;;;97388:5;;;;;;;97155:254;97194:3;;;;;;;97155:254;;;;96983:437;;97032:3;;;;;;;96983:437;;;;97440:30;97473:21;97488:5;97473:14;:21::i;:::-;97440:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97510:6;97519:1;97510:10;;97505:125;97526:13;:20;97522:1;:24;97505:125;;;97582:13;97596:1;97582:16;;;;;;;;;;;;;;97568:6;97575:3;97568:11;;;;;;;;;;;;;:30;;;;;97613:5;;;;;;;97548:3;;;;;;;97505:125;;;;97657:6;97650:13;;;;;96795:876;;;:::o;102632:378::-;102698:7;102718:13;102734:22;102748:7;102734:13;:22::i;:::-;102718:38;;102783:10;:17;;;;102775:5;:25;102767:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;102851:14;;:::i;:::-;102868:10;102879:5;102868:17;;;;;;;;;;;;;;;;;;102851:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;102906:18;102955:1;:9;;;93125:4;102928:23;;:7;:23;;;;;;102927:37;102906:58;;102992:10;102985:17;;;;;102632:378;;;:::o;95137:141::-;95217:7;95244:19;95257:5;95244:12;:19::i;:::-;95264:5;95244:26;;;;;;;;;;;;;;95237:33;;95137:141;;;;:::o;73873:134::-;73960:39;73977:4;73983:2;73987:7;73960:39;;;;;;;;;;;;:16;:39::i;:::-;73873:134;;;:::o;102150:163::-;102211:7;102231:13;93125:4;102248:23;;:7;:23;;;;;;102231:41;;102300:5;102293:12;;;102150:163;;;:::o;99942:1507::-;100000:7;65573:9;:7;:9::i;:::-;65565:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;100020:16;100048:8;;;;;;;;;;;100020:37;;100083:9;100095:1;100083:13;;100078:1279;100102:5;100098:1;:9;100078:1279;;;100129:13;100161:1;100145:13;;:17;100129:33;;100192:10;100204:11;100217:14;100233:15;100250:20;100274:7;:18;;;100293:5;100274:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;100274:25:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;100274:25:0;;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;100274:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;100191:108;;;;;;;;;;100314:10;100330:196;;;;;;;;100362:2;100330:196;;;;;;100389:4;100330:196;;;;;;100422:8;100330:196;;;;;;100458:7;100330:196;;;;100498:12;100330:196;;;100314:213;;39:1:-1;33:3;27:10;23:18;57:10;52:3;45:23;79:10;72:17;;0:93;100314:213:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;100556:8;100584:4;100567:21;;:14;;:21;100556:32;;100603:16;100622:4;100603:23;;;;100646:6;100655:14;;100646:23;;100641:405;100675:3;100671:1;:7;100641:405;;;100704:13;100720:7;:15;;;100736:1;100720:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;100720:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;100720:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;100720:18:0;;;;;;;;;;;;;;;;100704:34;;100770:2;100761:11;;:5;:11;;;100757:238;;100814:4;100797:11;:14;100809:1;100797:14;;;;;;;;;;;;:21;;;;;;;;;;;;;;;;;;100841:20;100852:5;100859:1;100841:10;:20::i;:::-;100884:10;;;;;;;;100757:238;;;100973:1;100969:2;100948:27;;100965:1;100948:27;;;;;;;;;;;;100757:238;100641:405;100680:3;;;;;;;100641:405;;;;93125:4;101074:31;;:14;;:31;;;;;;;;;;;101146:8;101120:18;:22;101139:2;101120:22;;;;;;;;;;;;;;;;:34;;;;;;;;;;;101208:4;101169:43;;:25;:35;101195:8;101169:35;;;;;;;;;;;;;;;;:43;;;;;;;;;;;101241:55;101258:2;101262:10;101293:1;101273:10;:17;;;;:21;101262:33;;;;;;;;;;;;;;;;;;101241:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:16;:55::i;:::-;101341:4;101325:20;;:12;;:20;;;;;;;;;;;100078:1279;;;;;;;;100109:3;;;;;;;100078:1279;;;;101394:5;101377:13;;:22;;;;;;;;;;;101427:14;;101420:21;;;99942:1507;;;:::o;98425:487::-;98480:4;98501:11;:21;98513:8;98501:21;;;;;;;;;;;;;;;;;;;;;98497:408;;;98546:23;98560:8;98546:13;:23::i;:::-;98539:30;;;;98497:408;98602:13;98618:23;98632:8;98618:13;:23::i;:::-;98602:39;;98668:10;:17;;;;98660:5;:25;98656:211;;;98706:14;;:::i;:::-;98723:10;98734:5;98723:17;;;;;;;;;;;;;;;;;;98706:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;98759:8;98787:1;:6;;;98770:23;;:1;:14;;;:23;98759:34;;98848:3;98837:8;:14;98830:21;;;;;;;98656:211;98888:5;98881:12;;;98425:487;;;;:::o;96167:111::-;96225:7;96252:11;:9;:11::i;:::-;96264:5;96252:18;;;;;;;;;;;;;;96245:25;;96167:111;;;:::o;99027:903::-;99121:4;93923:7;;;;;;;;;;;93909:21;;:10;:21;;;93901:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;93125:4;99146:20;;:4;:20;;;99138:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;99231:10;99247:202;;;;;;;;99275:2;99247:202;;;;;;99298:4;99247:202;;;;;;99327:8;99247:202;;;;;;99359:25;:35;99385:8;99359:35;;;;;;;;;;;;;;;;99247:202;;;;99423:14;;99247:202;;;99231:219;;39:1:-1;33:3;27:10;23:18;57:10;52:3;45:23;79:10;72:17;;0:93;99231:219:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;99471:8;99499:4;99482:21;;:14;;:21;99471:32;;99519:6;99528:14;;99519:23;;99514:103;99548:3;99544:1;:7;99514:103;;;99603:1;99599:2;99578:27;;99595:1;99578:27;;;;;;;;;;;;99553:3;;;;;;;99514:103;;;;93125:4;99637:31;;:14;;:31;;;;;;;;;;;99715:4;99689:30;;:18;:22;99708:2;99689:22;;;;;;;;;;;;;;;;:30;;;;;;;;;;;99769:4;99730:43;;:25;:35;99756:8;99730:35;;;;;;;;;;;;;;;;:43;;;;;;;;;;;99794:55;99811:2;99815:10;99846:1;99826:10;:17;;;;:21;99815:33;;;;;;;;;;;;;;;;;;99794:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:16;:55::i;:::-;99886:4;99870:20;;:12;;:20;;;;;;;;;;;99908:14;;99901:21;;;99027:903;;;;;:::o;97923:490::-;97978:7;98007:15;98014:7;98007:6;:15::i;:::-;97999:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;98074:11;:20;98086:7;98074:20;;;;;;;;;;;;;;;;;;;;;98070:84;;;98119:22;98133:7;98119:13;:22::i;:::-;98112:29;;;;98070:84;98165:13;98181:22;98195:7;98181:13;:22::i;:::-;98165:38;;98231:10;:17;;;;98223:5;:25;98215:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;98290:14;;:::i;:::-;98307:10;98318:5;98307:17;;;;;;;;;;;;;;;;;;98290:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;98371:1;:6;;;98354:23;;:1;:14;;;:23;98344:7;:33;98336:42;;;;;;98397:1;:7;;;98390:14;;;;97923:490;;;;:::o;96290:493::-;96332:16;96361:23;96401:13;:11;:13::i;:::-;96387:28;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;148:4;140:6;136:17;126:27;;0:157;96387:28:0;;;;96361:54;;96436:8;96447:1;96436:12;;96464:6;96473:1;96464:10;;96459:283;96480:10;:17;;;;96476:1;:21;96459:283;;;96519:14;;:::i;:::-;96536:10;96547:1;96536:13;;;;;;;;;;;;;;;;;;96519:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;96564:8;96592:1;:6;;;96575:23;;:1;:14;;;:23;96564:34;;96618:6;96627:1;:14;;;96618:23;;96613:118;96647:3;96643:1;:7;96613:118;;;96690:1;96676:6;96683:3;96676:11;;;;;;;;;;;;;:15;;;;;96710:5;;;;;;;96652:3;;;;;;;96613:118;;;;96459:283;;96499:3;;;;;;;96459:283;;;;96769:6;96762:13;;;;96290:493;:::o;97683:227::-;97738:7;97783:1;97766:19;;:5;:19;;;;97758:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97877:18;:25;97896:5;97877:25;;;;;;;;;;;;;;;;97852:22;97868:5;97852:15;:22::i;:::-;:50;97845:57;;97683:227;;;:::o;66172:140::-;65573:9;:7;:9::i;:::-;65565:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66271:1;66234:40;;66255:6;;;;;;;;;;;66234:40;;;;;;;;;;;;66302:1;66285:6;;:19;;;;;;;;;;;;;;;;;;66172:140::o;65361:79::-;65399:7;65426:6;;;;;;;;;;;65419:13;;65361:79;:::o;65727:94::-;65767:4;65807:6;;;;;;;;;;;65791:22;;:12;:10;:12::i;:::-;:22;;;65784:29;;65727:94;:::o;102325:295::-;102389:5;102407:13;102423:22;102437:7;102423:13;:22::i;:::-;102407:38;;102472:10;:17;;;;102464:5;:25;102456:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;102540:14;;:::i;:::-;102557:10;102568:5;102557:17;;;;;;;;;;;;;;;;;;102540:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;102602:1;:10;;;102595:17;;;;102325:295;;;:::o;91108:89::-;91149:13;91182:7;91175:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91108:89;:::o;93086:43::-;93125:4;93086:43;:::o;71741:254::-;71827:12;:10;:12::i;:::-;71821:18;;:2;:18;;;;71813:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71921:8;71882:18;:32;71901:12;:10;:12::i;:::-;71882:32;;;;;;;;;;;;;;;:36;71915:2;71882:36;;;;;;;;;;;;;;;;:47;;;;;;;;;;;;;;;;;;71974:2;71945:42;;71960:12;:10;:12::i;:::-;71945:42;;;71978:8;71945:42;;;;;;;;;;;;;;;;;;;;;;71741:254;;:::o;106867:1060::-;106940:15;106958:10;106969;106958:22;;;;;;;;;;;;;;;;;;106940:40;;107001:21;107025:1;:7;;;;;;;;;;;;107001:31;;107072:10;107061:21;;:1;:7;;;;;;;;;;;;:21;;;107053:30;;;;;;107104:39;107126:13;107141:1;107104:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:21;:39::i;:::-;107174:2;107164:1;:7;;;:12;;;;;;;;;;;;;;;;;;107197:23;107214:2;107218:1;107197:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:16;:23::i;:::-;107279:10;107275:2;107246:44;;107260:13;107246:44;;;;;;;;;;;;107369:8;107397:1;:6;;;;;;;;;;;;107380:23;;:1;:14;;;:23;107369:34;;107414:19;107436:1;107414:23;;107453:6;107462:1;:14;;;107453:23;;107448:355;107482:3;107478:1;:7;107448:355;;;107511:11;:14;107523:1;107511:14;;;;;;;;;;;;;;;;;;;;;107507:235;;;107564:13;107550:27;;:10;107558:1;107550:7;:10::i;:::-;:27;;;107546:62;;107600:8;;107546:62;107507:235;;;107713:13;;;;;;;107507:235;107789:1;107785:2;107761:30;;107770:13;107761:30;;;;;;;;;;;;107448:355;107487:3;;;;;;;107448:355;;;;107849:11;107823:18;:22;107842:2;107823:22;;;;;;;;;;;;;;;;:37;;;;;;;;;;;107908:11;107871:18;:33;107890:13;107871:33;;;;;;;;;;;;;;;;:48;;;;;;;;;;;106867:1060;;;;;;:::o;101682:456::-;101744:11;:20;101756:7;101744:20;;;;;;;;;;;;;;;;;;;;;101743:21;101735:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;101803:13;101819:22;101833:7;101819:13;:22::i;:::-;101803:38;;101868:10;:17;;;;101860:5;:25;101852:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;101926:14;;:::i;:::-;101943:10;101954:5;101943:17;;;;;;;;;;;;;;;;;;101926:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;102006:1;:6;;;101989:23;;:1;:14;;;:23;101979:7;:33;101971:42;;;;;;102047:4;102024:11;:20;102036:7;102024:20;;;;;;;;;;;;:27;;;;;;;;;;;;;;;;;;102062:28;102073:1;:7;;;102082;102062:10;:28::i;:::-;102101:18;:27;102120:1;:7;;;102101:27;;;;;;;;;;;;;;;;:29;;;;;;;;;;;;;;101682:456;;;:::o;74744:272::-;74859:41;74878:12;:10;:12::i;:::-;74892:7;74859:18;:41::i;:::-;74851:103;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74965:43;74983:4;74989:2;74993:7;75002:5;74965:17;:43::i;:::-;74744:272;;;;:::o;93445:25::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;103510:896::-;103566:13;103600:15;103607:7;103600:6;:15::i;:::-;103592:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;103655:11;:20;103667:7;103655:20;;;;;;;;;;;;;;;;;;;;;103651:748;;;103699:23;103714:7;103699:14;:23::i;:::-;103692:30;;;;103651:748;103792:14;103809:25;103826:7;103809:16;:25::i;:::-;103792:42;;103849:19;103871:27;103890:7;103871:18;:27::i;:::-;103849:49;;103927:16;103946:144;104018:71;:61;104061:17;:15;;;;;;;;;;;;;;;;;;:17::i;:::-;104018:35;:25;104031:11;104018:12;:25::i;:::-;:33;:35::i;:::-;:42;;:61;;;;:::i;:::-;:69;:71::i;:::-;103946:64;:54;103986:13;:11;;;;;;;;;;;;;;;;;;:13::i;:::-;103946:32;:22;103959:8;103946:22;;:12;:22::i;:::-;:30;:32::i;:::-;:39;;:54;;;;:::i;:::-;:62;:64::i;:::-;:71;;:144;;;;:::i;:::-;103927:163;;104105:19;:57;;;;;;;;;;;;;;;;;;;104280:23;104306:36;104329:12;:2;:10;:12::i;:::-;104306:15;:5;:13;:15::i;:::-;:22;;:36;;;;:::i;:::-;104280:62;;104378:9;104371:16;;;;;;;103510:896;;;;:::o;95421:734::-;95498:16;95527:14;;:::i;:::-;95544:12;:19;95557:5;95544:19;;;;;;;;;;;;;;;95564:5;95544:26;;;;;;;;;;;;;;;;;;95527:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;95581:23;95621:1;:6;;;95607:21;;;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;148:4;140:6;136:17;126:27;;0:157;95607:21:0;;;;95581:47;;95649:11;95663:1;95649:15;;95675:8;95703:1;:6;;;95686:23;;:1;:14;;;:23;95675:34;;95725:6;95734:1;:14;;;95725:23;;95720:226;95754:3;95750:1;:7;95720:226;;;95783:11;:14;95795:1;95783:14;;;;;;;;;;;;;;;;;;;;;:43;;;;;95821:5;95801:25;;:16;95815:1;95801:13;:16::i;:::-;:25;;;;95783:43;95779:92;;;95847:8;;95779:92;95913:1;95899:6;95906:3;95899:11;;;;;;;;;;;;;:15;;;;;95929:5;;;;;;;95720:226;95759:3;;;;;;;95720:226;;;;95980:1;95974:3;:7;95966:16;;;;;;96003:17;96032:3;96023:1;:6;;;:12;;;96003:32;;96101:9;96092:6;96086:13;96082:29;96074:6;96067:45;96141:6;96134:13;;;;;;;95421:734;;;;:::o;72325:147::-;72405:4;72429:18;:25;72448:5;72429:25;;;;;;;;;;;;;;;:35;72455:8;72429:35;;;;;;;;;;;;;;;;;;;;;;;;;72422:42;;72325:147;;;;:::o;93136:33::-;;;;:::o;66467:109::-;65573:9;:7;:9::i;:::-;65565:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66540:28;66559:8;66540:18;:28::i;:::-;66467:109;:::o;95290:119::-;95348:7;95375:12;:19;95388:5;95375:19;;;;;;;;;;;;;;;:26;;;;95368:33;;95290:119;;;:::o;76209:155::-;76266:4;76283:13;76299:11;:20;76311:7;76299:20;;;;;;;;;;;;;;;;;;;;;76283:36;;76354:1;76337:19;;:5;:19;;;;76330:26;;;76209:155;;;:::o;27961:98::-;28006:15;28041:10;28034:17;;27961:98;:::o;72919:292::-;73063:41;73082:12;:10;:12::i;:::-;73096:7;73063:18;:41::i;:::-;73055:103;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73171:32;73185:4;73191:2;73195:7;73171:13;:32::i;:::-;72919:292;;;:::o;69859:228::-;69914:7;69934:13;69950:11;:20;69962:7;69950:20;;;;;;;;;;;;;;;;;;;;;69934:36;;70006:1;69989:19;;:5;:19;;;;69981:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;70074:5;70067:12;;;69859:228;;;:::o;85400:126::-;85462:17;85499:12;:19;85512:5;85499:19;;;;;;;;;;;;;;;85492:26;;85400:126;;;:::o;104418:747::-;104522:14;104539:26;104556:8;104539:16;:26::i;:::-;104522:43;;104576:19;104598:28;104617:8;104598:18;:28::i;:::-;104576:50;;104651:16;104670:144;104742:71;:61;104785:17;:15;;;;;;;;;;;;;;;;;;:17::i;:::-;104742:35;:25;104755:11;104742:12;:25::i;:::-;:33;:35::i;:::-;:42;;:61;;;;:::i;:::-;:69;:71::i;:::-;104670:64;:54;104710:13;:11;;;;;;;;;;;;;;;;;;:13::i;:::-;104670:32;:22;104683:8;104670:22;;:12;:22::i;:::-;:30;:32::i;:::-;:39;;:54;;;;:::i;:::-;:62;:64::i;:::-;:71;;:144;;;;:::i;:::-;104651:163;;104825:19;:57;;;;;;;;;;;;;;;;;;;104992:23;105018:36;105041:12;:2;:10;:12::i;:::-;105018:15;:5;:13;:15::i;:::-;:22;;:36;;;;:::i;:::-;104992:62;;105075:32;105093:3;105098:8;105075:17;:32::i;:::-;105118:39;105137:8;105147:9;105118:18;:39::i;:::-;104418:747;;;;;;;:::o;106601:254::-;106678:19;106700:33;106714:5;:18;;;106700:13;:33::i;:::-;106678:55;;106785:12;:16;106798:2;106785:16;;;;;;;;;;;;;;;:23;;;;106754:15;:28;106770:11;106754:28;;;;;;;;;;;:54;;;;106819:12;:16;106832:2;106819:16;;;;;;;;;;;;;;;106841:5;106819:28;;39:1:-1;33:3;27:10;23:18;57:10;52:3;45:23;79:10;72:17;;0:93;106819:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;106601:254;;;:::o;69422:211::-;69477:7;69522:1;69505:19;;:5;:19;;;;69497:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69591:34;:17;:24;69609:5;69591:24;;;;;;;;;;;;;;;:32;:34::i;:::-;69584:41;;69422:211;;;:::o;105296:1293::-;105562:19;105584:33;105598:5;:18;;;105584:13;:33::i;:::-;105562:55;;105630:22;105655:32;105685:1;105655:12;:18;105668:4;105655:18;;;;;;;;;;;;;;;:25;;;;:29;;:32;;;;:::i;:::-;105630:57;;105698:18;105719:15;:28;105735:11;105719:28;;;;;;;;;;;;105698:49;;105868:14;105854:10;:28;105850:409;;105899:22;;:::i;:::-;105924:12;:18;105937:4;105924:18;;;;;;;;;;;;;;;105943:14;105924:34;;;;;;;;;;;;;;;;;;105899:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;105973:23;105999:37;106013:9;:22;;;105999:13;:37::i;:::-;105973:63;;106086:9;106053:12;:18;106066:4;106053:18;;;;;;;;;;;;;;;106072:10;106053:30;;;;;;;;;;;;;;;;;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;106203:10;106168:15;:32;106184:15;106168:32;;;;;;;;;;;:45;;;;105850:409;;;106348:12;:18;106361:4;106348:18;;;;;;;;;;;;;;;:27;;;;;;;;;;;;:::i;:::-;;105296:1293;;;;;:::o;76734:333::-;76819:4;76844:16;76852:7;76844;:16::i;:::-;76836:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;76920:13;76936:16;76944:7;76936;:16::i;:::-;76920:32;;76982:5;76971:16;;:7;:16;;;:51;;;;77015:7;76991:31;;:20;77003:7;76991:11;:20::i;:::-;:31;;;76971:51;:87;;;;77026:32;77043:5;77050:7;77026:16;:32::i;:::-;76971:87;76963:96;;;76734:333;;;;:::o;75735:272::-;75845:32;75859:4;75865:2;75869:7;75845:13;:32::i;:::-;75896:48;75919:4;75925:2;75929:7;75938:5;75896:22;:48::i;:::-;75888:111;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;75735:272;;;;:::o;91404:203::-;91460:13;91494:16;91502:7;91494;:16::i;:::-;91486:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91580:10;:19;91591:7;91580:19;;;;;;;;;;;91573:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91404:203;;;:::o;891:216::-;951:12;;:::i;:::-;976:8;1036:4;1030;1026:15;1019:22;;1069:30;;;;;;;;1081:4;1075:18;1069:30;;;;1095:3;1069:30;;;1062:37;;;891:216;;;:::o;103022:476::-;103075:13;103110:1;103105;:6;103101:49;;;103128:10;;;;;;;;;;;;;;;;;;;;;103101:49;103160:6;103169:1;103160:10;;103181:8;103200:69;103212:1;103207;:6;103200:69;;103230:5;;;;;;;103255:2;103250:7;;;;;;;;;103200:69;;;103279:17;103309:3;103299:14;;;;;;;;;;;;;;;;;;;;;;;;;29:1:-1;21:6;17:14;116:4;104:10;96:6;87:34;147:4;139:6;135:17;125:27;;0:156;103299:14:0;;;;103279:34;;103324:6;103339:1;103333:3;:7;103324:16;;103351:100;103363:1;103358;:6;103351:100;;103413:2;103409:1;:6;;;;;;103404:2;:11;103393:24;;103381:4;103386:3;;;;;;;103381:9;;;;;;;;;;;:36;;;;;;;;;;;103437:2;103432:7;;;;;;;;;103351:100;;;103485:4;103471:19;;;;;;103022:476;;;;:::o;22633:362::-;22711:13;22737:17;22780:5;:10;;;22768:4;:9;;;:22;22757:34;;;;;;;;;;;;;;;;;;;;;;;;;29:1:-1;21:6;17:14;116:4;104:10;96:6;87:34;147:4;139:6;135:17;125:27;;0:156;22757:34:0;;;;22737:54;;22802:11;22854:2;22849:3;22845:12;22835:22;;22869:36;22876:6;22884:4;:9;;;22895:4;:9;;;22869:6;:36::i;:::-;22916:50;22932:4;:9;;;22923:6;:18;22943:5;:10;;;22955:5;:10;;;22916:6;:50::i;:::-;22984:3;22977:10;;;;22633:362;;;;:::o;66682:229::-;66776:1;66756:22;;:8;:22;;;;66748:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66866:8;66837:38;;66858:6;;;;;;;;;;;66837:38;;;;;;;;;;;;66895:8;66886:6;;:17;;;;;;;;;;;;;;;;;;66682:229;:::o;83808:245::-;83894:38;83914:4;83920:2;83924:7;83894:19;:38::i;:::-;83945:47;83978:4;83984:7;83945:32;:47::i;:::-;84005:40;84033:2;84037:7;84005:27;:40::i;:::-;83808:245;;;:::o;84318:214::-;84388:30;84406:2;84410:7;84388:17;:30::i;:::-;84431:40;84459:2;84463:7;84431:27;:40::i;:::-;84484;84516:7;84484:31;:40::i;:::-;84318:214;;:::o;91854:195::-;91940:16;91948:7;91940;:16::i;:::-;91932:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92038:3;92016:10;:19;92027:7;92016:19;;;;;;;;;;;:25;;;;;;;;;;;;:::i;:::-;;91854:195;;:::o;38539:114::-;38604:7;38631;:14;;;38624:21;;38539:114;;;:::o;31215:136::-;31273:7;31300:43;31304:1;31307;31300:43;;;;;;;;;;;;;;;;;:3;:43::i;:::-;31293:50;;31215:136;;;;:::o;79947:358::-;80069:4;80096:15;:2;:13;;;:15::i;:::-;80091:60;;80135:4;80128:11;;;;80091:60;80163:13;80195:2;80179:36;;;80216:12;:10;:12::i;:::-;80230:4;80236:7;80245:5;80179:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;80179:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;80179:72:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;80179:72:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;80179:72:0;;;;;;;;;;;;;;;;80163:88;;67623:10;80280:16;;80270:26;;;:6;:26;;;;80262:35;;;79947:358;;;;;;;:::o;119:565::-;241:170;254:2;247:3;:9;241:170;;331:3;325:10;319:4;312:24;373:2;365:10;;;;397:2;390:9;;;;265:2;258:9;;;;241:170;;;456:9;488:1;481:3;476:2;:8;468:3;:17;:21;456:33;;559:4;555:9;549:3;543:10;539:26;612:4;605;599:11;595:22;657:7;647:8;644:21;638:4;631:35;509:168;;;;;;:::o;78886:459::-;79000:4;78980:24;;:16;78988:7;78980;:16::i;:::-;:24;;;78972:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79083:1;79069:16;;:2;:16;;;;79061:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79139:23;79154:7;79139:14;:23::i;:::-;79175:35;:17;:23;79193:4;79175:23;;;;;;;;;;;;;;;:33;:35::i;:::-;79221:33;:17;:21;79239:2;79221:21;;;;;;;;;;;;;;;:31;:33::i;:::-;79290:2;79267:11;:20;79279:7;79267:20;;;;;;;;;;;;:25;;;;;;;;;;;;;;;;;;79329:7;79325:2;79310:27;;79319:4;79310:27;;;;;;;;;;;;78886:459;;;:::o;87005:1148::-;87271:22;87296:32;87326:1;87296:12;:18;87309:4;87296:18;;;;;;;;;;;;;;;:25;;;;:29;;:32;;;;:::i;:::-;87271:57;;87339:18;87360:17;:26;87378:7;87360:26;;;;;;;;;;;;87339:47;;87507:14;87493:10;:28;87489:328;;87538:19;87560:12;:18;87573:4;87560:18;;;;;;;;;;;;;;;87579:14;87560:34;;;;;;;;;;;;;;;;87538:56;;87644:11;87611:12;:18;87624:4;87611:18;;;;;;;;;;;;;;;87630:10;87611:30;;;;;;;;;;;;;;;:44;;;;87761:10;87728:17;:30;87746:11;87728:30;;;;;;;;;;;:43;;;;87489:328;;87906:12;:18;87919:4;87906:18;;;;;;;;;;;;;;;:27;;;;;;;;;;;;:::i;:::-;;87005:1148;;;;:::o;85827:186::-;85941:12;:16;85954:2;85941:16;;;;;;;;;;;;;;;:23;;;;85912:17;:26;85930:7;85912:26;;;;;;;;;;;:52;;;;85975:12;:16;85988:2;85975:16;;;;;;;;;;;;;;;85997:7;85975:30;;39:1:-1;33:3;27:10;23:18;57:10;52:3;45:23;79:10;72:17;;0:93;85975:30:0;;;;;;;;;;;;;;;;;;;;;;85827:186;;:::o;77320:290::-;77412:1;77398:16;;:2;:16;;;;77390:61;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77471:16;77479:7;77471;:16::i;:::-;77470:17;77462:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77556:2;77533:11;:20;77545:7;77533:20;;;;;;;;;;;;:25;;;;;;;;;;;;;;;;;;77569:33;:17;:21;77587:2;77569:21;;;;;;;;;;;;;;;:31;:33::i;:::-;77320:290;;:::o;86214:164::-;86318:10;:17;;;;86291:15;:24;86307:7;86291:24;;;;;;;;;;;:44;;;;86346:10;86362:7;86346:24;;39:1:-1;33:3;27:10;23:18;57:10;52:3;45:23;79:10;72:17;;0:93;86346:24:0;;;;;;;;;;;;;;;;;;;;;;86214:164;:::o;31801:192::-;31887:7;31920:1;31915;:6;;31923:12;31907:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;31907:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31947:9;31963:1;31959;:5;31947:17;;31984:1;31977:8;;;31801:192;;;;;:::o;36236:810::-;36296:4;36749:16;36776:19;36798:66;36776:88;;;;36967:7;36955:20;36943:32;;37007:3;36995:15;;:8;:15;;:42;;;;;37026:11;37014:8;:23;;36995:42;36987:51;;;;36236:810;;;:::o;80473:175::-;80573:1;80537:38;;:15;:24;80553:7;80537:24;;;;;;;;;;;;;;;;;;;;;:38;;;80533:108;;80627:1;80592:15;:24;80608:7;80592:24;;;;;;;;;;;;:37;;;;;;;;;;;;;;;;;;80533:108;80473:175;:::o;38850:110::-;38931:21;38950:1;38931:7;:14;;;:18;;:21;;;;:::i;:::-;38914:7;:14;;:38;;;;38850:110;:::o;38661:181::-;38833:1;38815:7;:14;;;:19;;;;;;;;;;;38661:181;:::o;92844:15086::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o

Swarm Source

bzzr://876931c215f7956d3a852fd29294df62b37bd1b5c267f0ba3dfa8814f2f4f2e0
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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