From 799dc6fce78cad61c5b6777c4bb88b97c18e8832 Mon Sep 17 00:00:00 2001 From: Ollie <69084614+olijeffers0n@users.noreply.github.com> Date: Mon, 1 Jul 2024 21:15:36 +0100 Subject: [PATCH] Delete old project --- rustplus_old/__init__.py | 26 - rustplus_old/api/__init__.py | 1 - rustplus_old/api/base_rust_api.py | 637 -------------- rustplus_old/api/icons/__init__.py | 1 - rustplus_old/api/remote/__init__.py | 8 - rustplus_old/api/remote/camera/__init__.py | 3 - .../api/remote/camera/camera_constants.py | 35 - .../api/remote/camera/camera_manager.py | 175 ---- .../api/remote/camera/camera_parser.py | 785 ----------------- rustplus_old/api/remote/camera/structures.py | 103 --- rustplus_old/api/remote/events/__init__.py | 4 - .../api/remote/events/event_handler.py | 44 - .../api/remote/events/event_loop_manager.py | 25 - rustplus_old/api/remote/events/events.py | 126 --- .../api/remote/events/handler_list.py | 63 -- .../api/remote/events/map_event_listener.py | 104 --- .../api/remote/events/registered_listener.py | 32 - rustplus_old/api/remote/fcm_listener.py | 21 - rustplus_old/api/remote/heartbeat.py | 32 - rustplus_old/api/remote/ratelimiter.py | 134 --- .../api/remote/rplus_version_handler.py | 19 - .../api/remote/rust_remote_interface.py | 256 ------ .../api/remote/rustplus_proto/__init__.py | 1 - .../api/remote/rustplus_proto/rustplus.py | 498 ----------- rustplus_old/api/remote/rustws.py | 394 --------- rustplus_old/api/remote/server_checker.py | 26 - rustplus_old/api/rust_api.py | 428 ---------- rustplus_old/api/structures/__init__.py | 10 - .../api/structures/rust_chat_message.py | 36 - rustplus_old/api/structures/rust_contents.py | 30 - .../api/structures/rust_entity_info.py | 73 -- rustplus_old/api/structures/rust_info.py | 79 -- rustplus_old/api/structures/rust_item.py | 33 - rustplus_old/api/structures/rust_map.py | 74 -- rustplus_old/api/structures/rust_marker.py | 190 ----- rustplus_old/api/structures/rust_team_info.py | 130 --- rustplus_old/api/structures/rust_time.py | 45 - rustplus_old/api/structures/serialization.py | 17 - rustplus_old/api/structures/util.py | 7 - rustplus_old/commands/__init__.py | 3 - rustplus_old/commands/command.py | 23 - rustplus_old/commands/command_data.py | 22 - rustplus_old/commands/command_handler.py | 68 -- rustplus_old/commands/command_options.py | 17 - rustplus_old/conversation/__init__.py | 3 - rustplus_old/conversation/conversation.py | 62 -- .../conversation/conversation_factory.py | 50 -- .../conversation/conversation_prompt.py | 12 - rustplus_old/exceptions/__init__.py | 12 - rustplus_old/exceptions/exceptions.py | 64 -- rustplus_old/utils/__init__.py | 6 - rustplus_old/utils/deprecated.py | 32 - rustplus_old/utils/emojis.py | 31 - rustplus_old/utils/fonts/PermanentMarker.ttf | Bin 74752 -> 0 bytes rustplus_old/utils/fonts/__init__.py | 0 rustplus_old/utils/grab_items.py | 796 ------------------ rustplus_old/utils/rust_utils.py | 297 ------- rustplus_old/utils/server_id.py | 26 - rustplus_old/utils/yielding_event.py | 27 - 59 files changed, 6256 deletions(-) delete mode 100644 rustplus_old/__init__.py delete mode 100644 rustplus_old/api/__init__.py delete mode 100644 rustplus_old/api/base_rust_api.py delete mode 100644 rustplus_old/api/icons/__init__.py delete mode 100644 rustplus_old/api/remote/__init__.py delete mode 100644 rustplus_old/api/remote/camera/__init__.py delete mode 100644 rustplus_old/api/remote/camera/camera_constants.py delete mode 100644 rustplus_old/api/remote/camera/camera_manager.py delete mode 100644 rustplus_old/api/remote/camera/camera_parser.py delete mode 100644 rustplus_old/api/remote/camera/structures.py delete mode 100644 rustplus_old/api/remote/events/__init__.py delete mode 100644 rustplus_old/api/remote/events/event_handler.py delete mode 100644 rustplus_old/api/remote/events/event_loop_manager.py delete mode 100644 rustplus_old/api/remote/events/events.py delete mode 100644 rustplus_old/api/remote/events/handler_list.py delete mode 100644 rustplus_old/api/remote/events/map_event_listener.py delete mode 100644 rustplus_old/api/remote/events/registered_listener.py delete mode 100644 rustplus_old/api/remote/fcm_listener.py delete mode 100644 rustplus_old/api/remote/heartbeat.py delete mode 100644 rustplus_old/api/remote/ratelimiter.py delete mode 100644 rustplus_old/api/remote/rplus_version_handler.py delete mode 100644 rustplus_old/api/remote/rust_remote_interface.py delete mode 100644 rustplus_old/api/remote/rustplus_proto/__init__.py delete mode 100644 rustplus_old/api/remote/rustplus_proto/rustplus.py delete mode 100644 rustplus_old/api/remote/rustws.py delete mode 100644 rustplus_old/api/remote/server_checker.py delete mode 100644 rustplus_old/api/rust_api.py delete mode 100644 rustplus_old/api/structures/__init__.py delete mode 100644 rustplus_old/api/structures/rust_chat_message.py delete mode 100644 rustplus_old/api/structures/rust_contents.py delete mode 100644 rustplus_old/api/structures/rust_entity_info.py delete mode 100644 rustplus_old/api/structures/rust_info.py delete mode 100644 rustplus_old/api/structures/rust_item.py delete mode 100644 rustplus_old/api/structures/rust_map.py delete mode 100644 rustplus_old/api/structures/rust_marker.py delete mode 100644 rustplus_old/api/structures/rust_team_info.py delete mode 100644 rustplus_old/api/structures/rust_time.py delete mode 100644 rustplus_old/api/structures/serialization.py delete mode 100644 rustplus_old/api/structures/util.py delete mode 100644 rustplus_old/commands/__init__.py delete mode 100644 rustplus_old/commands/command.py delete mode 100644 rustplus_old/commands/command_data.py delete mode 100644 rustplus_old/commands/command_handler.py delete mode 100644 rustplus_old/commands/command_options.py delete mode 100644 rustplus_old/conversation/__init__.py delete mode 100644 rustplus_old/conversation/conversation.py delete mode 100644 rustplus_old/conversation/conversation_factory.py delete mode 100644 rustplus_old/conversation/conversation_prompt.py delete mode 100644 rustplus_old/exceptions/__init__.py delete mode 100644 rustplus_old/exceptions/exceptions.py delete mode 100644 rustplus_old/utils/__init__.py delete mode 100644 rustplus_old/utils/deprecated.py delete mode 100644 rustplus_old/utils/emojis.py delete mode 100644 rustplus_old/utils/fonts/PermanentMarker.ttf delete mode 100644 rustplus_old/utils/fonts/__init__.py delete mode 100644 rustplus_old/utils/grab_items.py delete mode 100644 rustplus_old/utils/rust_utils.py delete mode 100644 rustplus_old/utils/server_id.py delete mode 100644 rustplus_old/utils/yielding_event.py diff --git a/rustplus_old/__init__.py b/rustplus_old/__init__.py deleted file mode 100644 index d7470dc..0000000 --- a/rustplus_old/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -r""" -RustPlus, An API wrapper for interfacing with the Rust+ App API -""" - -from .api import RustSocket -from .api.remote.events import ( - EntityEvent, - TeamEvent, - ChatEvent, - MarkerEvent, - ProtobufEvent, - RegisteredListener, -) -from .api.structures import RustMarker, Vector -from .api.remote.fcm_listener import FCMListener -from .api.remote.ratelimiter import RateLimiter -from .api.remote.camera import CameraManager, MovementControls, CameraMovementOptions -from .commands import CommandOptions, Command -from .exceptions import * -from .conversation import ConversationFactory, Conversation, ConversationPrompt -from .utils import * - -__name__ = "rustplus_old" -__author__ = "olijeffers0n" -__version__ = "5.6.18" -__support__ = "Discord: https://discord.gg/nQqJe8qvP8" diff --git a/rustplus_old/api/__init__.py b/rustplus_old/api/__init__.py deleted file mode 100644 index 2ac9e55..0000000 --- a/rustplus_old/api/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .rust_api import RustSocket diff --git a/rustplus_old/api/base_rust_api.py b/rustplus_old/api/base_rust_api.py deleted file mode 100644 index 17a4622..0000000 --- a/rustplus_old/api/base_rust_api.py +++ /dev/null @@ -1,637 +0,0 @@ -import asyncio -from typing import List, Union, Coroutine, Callable, Dict, Tuple -from PIL import Image - -from .remote.events.event_loop_manager import EventLoopManager -from .structures import * -from .remote.rustplus_proto import AppEmpty, AppRequest -from .remote import RustRemote, HeartBeat, MapEventListener, ServerChecker, RateLimiter -from .remote.camera import CameraManager -from ..commands import CommandOptions, CommandHandler -from ..commands.command_data import CommandData -from ..exceptions import * -from .remote.events import ( - RegisteredListener, - EntityEvent, - TeamEvent, - ChatEvent, - ProtobufEvent, -) -from ..utils import deprecated -from ..conversation import ConversationFactory -from ..utils import ServerID - - -class BaseRustSocket: - def __init__( - self, - ip: str = None, - port: str = None, - steam_id: int = None, - player_token: int = None, - command_options: CommandOptions = None, - raise_ratelimit_exception: bool = False, - ratelimit_limit: int = 25, - ratelimit_refill: int = 3, - heartbeat: HeartBeat = None, - use_proxy: bool = False, - use_test_server: bool = False, - event_loop: asyncio.AbstractEventLoop = None, - rate_limiter: RateLimiter = None, - debug: bool = False, - ) -> None: - if ip is None: - raise ValueError("Ip cannot be None") - if steam_id is None: - raise ValueError("SteamID cannot be None") - if player_token is None: - raise ValueError("PlayerToken cannot be None") - - try: - steam_id = int(steam_id) - except ValueError: - raise ValueError("SteamID must be an integer") - - try: - player_token = int(player_token) - except ValueError: - raise ValueError("PlayerToken must be an integer") - - self.server_id = ServerID(ip, port, steam_id, player_token) - self.seq = 1 - self.command_options = command_options - self.raise_ratelimit_exception = raise_ratelimit_exception - self.ratelimit_limit = ratelimit_limit - self.ratelimit_refill = ratelimit_refill - self.marker_listener = MapEventListener(self) - self.use_test_server = use_test_server - self.event_loop = event_loop - - self.remote = RustRemote( - server_id=self.server_id, - command_options=command_options, - ratelimit_limit=ratelimit_limit, - ratelimit_refill=ratelimit_refill, - use_proxy=use_proxy, - api=self, - use_test_server=use_test_server, - rate_limiter=rate_limiter, - debug=debug, - ) - - if heartbeat is None: - raise ValueError("Heartbeat cannot be None") - self.heartbeat = heartbeat - - async def _handle_ratelimit(self, amount=1) -> None: - """ - Handles the ratelimit for a specific request. Will sleep if tokens are not currently available and is set to wait - :param amount: The amount to consume - :raises RateLimitError - If the tokens are not available and is not set to wait - :return: None - """ - while True: - if await self.remote.ratelimiter.can_consume(self.server_id, amount): - await self.remote.ratelimiter.consume(self.server_id, amount) - break - - if self.raise_ratelimit_exception: - raise RateLimitError("Out of tokens") - - await asyncio.sleep( - await self.remote.ratelimiter.get_estimated_delay_time( - self.server_id, amount - ) - ) - - self.heartbeat.reset_rhythm() - - def _generate_protobuf(self) -> AppRequest: - """ - Generates the default protobuf for a request - - :return: AppRequest - The default request object - """ - app_request = AppRequest() - app_request.seq = self.seq - app_request.player_id = self.server_id.player_id - app_request.player_token = self.server_id.player_token - - self.seq += 1 - - return app_request - - async def connect( - self, - retries: int = float("inf"), - delay: int = 20, - on_failure: Union[Coroutine, Callable[[], None], None] = None, - on_success: Union[Coroutine, Callable[[], None], None] = None, - on_success_args_kwargs: Tuple[List, Dict] = ([], {}), - on_failure_args_kwargs: Tuple[List, Dict] = ([], {}), - ) -> None: - """ - Attempts to open a connection to the rust game server specified in the constructor - - :param retries: The number of times to attempt reconnecting. Defaults to infinite. - :param delay: The delay (in seconds) between reconnection attempts. - :param on_failure: Optional function to be called when connecting fails. - :param on_success: Optional function to be called when connecting succeeds. - :param on_success_args_kwargs: Optional tuple holding keyword and regular arguments - for on_success in this format (args, kwargs) - :param on_failure_args_kwargs: Optional tuple holding keyword and regular arguments - for on_failure in this format (args, kwargs) - - :return: None - """ - EventLoopManager.set_loop( - ( - self.event_loop - if self.event_loop is not None - else asyncio.get_event_loop() - ), - self.server_id, - ) - - if not self.use_test_server: - ServerChecker(self.server_id.ip, self.server_id.port).run() - - EventLoopManager.set_loop( - ( - self.event_loop - if self.event_loop is not None - else asyncio.get_event_loop() - ), - self.server_id, - ) - - try: - if self.remote.ws is None: - await self.remote.connect( - retries=retries, - delay=delay, - on_failure=on_failure, - on_success=on_success, - on_success_args_kwargs=on_success_args_kwargs, - on_failure_args_kwargs=on_failure_args_kwargs, - ) - await self.heartbeat.start_beat() - except ConnectionRefusedError: - raise ServerNotResponsiveError("Cannot Connect") - - async def close_connection(self) -> None: - """ - Disconnects from the Rust Server - - :return: None - """ - await self.remote.close() - - async def disconnect(self) -> None: - """ - Disconnects from the Rust Server - - :return: None - """ - await self.close_connection() - - async def send_wakeup_request(self) -> None: - """ - Sends a request to the server to wake up broadcast responses - - :return: None - """ - await self._handle_ratelimit() - - app_request = self._generate_protobuf() - app_request.get_time = AppEmpty() - - await self.remote.add_ignored_response(app_request.seq) - - await self.remote.send_message(app_request) - - async def switch_server( - self, - ip: str = None, - port: str = None, - steam_id: int = None, - player_token: int = None, - command_options: CommandOptions = None, - raise_ratelimit_exception: bool = True, - connect: bool = False, - use_proxy: bool = False, - ) -> None: - """ - Disconnects and replaces server params, allowing the socket to connect to a new server. - - :param raise_ratelimit_exception: Whether to raise an exception or wait - :param command_options: The command options - :param ip: IP of the server - :param port: Port of the server - :param player_token: The player Token - :param steam_id: Steam id of the player - :param connect: bool indicating if socket should automatically self.connect() - :param use_proxy: Whether to use the facepunch proxy - :return: None - """ - - if self.use_test_server: - raise ServerSwitchDisallowedError("Cannot switch server") - - if ip is None: - raise ValueError("Ip cannot be None") - if port is None: - raise ValueError("Port cannot be None") - if steam_id is None: - raise ValueError("SteamID cannot be None") - if player_token is None: - raise ValueError("PlayerToken cannot be None") - - # disconnect before redefining - await self.disconnect() - - # Reset basic credentials - self.server_id = ServerID(ip, port, steam_id, player_token) - self.seq = 1 - - # Deal with commands - - if command_options is not None: - self.command_options = command_options - self.remote.command_options = command_options - if self.remote.use_commands: - self.remote.command_handler.command_options = command_options - else: - self.remote.use_commands = True - self.remote.command_handler = CommandHandler(self.command_options, self) - - self.raise_ratelimit_exception = raise_ratelimit_exception - - self.remote.pending_entity_subscriptions = [] - self.remote.server_id = ServerID(ip, port, steam_id, player_token) - - # reset ratelimiter - self.remote.use_proxy = use_proxy - await self.remote.ratelimiter.remove(self.server_id) - self.remote.ratelimiter.add_socket( - self.server_id, - self.ratelimit_limit, - self.ratelimit_limit, - 1, - self.ratelimit_refill, - ) - self.remote.conversation_factory = ConversationFactory(self) - # remove entity events - EntityEvent.handlers.unregister_all() - # reset marker listener - self.marker_listener.persistent_ids.clear() - self.marker_listener.highest_id = 0 - - if connect: - await self.connect() - - def command( - self, - coro: Callable = None, - aliases: List[str] = None, - alias_func: Callable = None, - ) -> Union[Callable, RegisteredListener]: - """ - A coroutine decorator used to register a command executor - - :param alias_func: The function to test the aliases against - :param aliases: The aliases to register the command under - :param coro: The coroutine to call when the command is called - :return: RegisteredListener - The listener object | Callable - The callable func for the decorator - """ - - if isinstance(coro, RegisteredListener): - coro = coro.get_coro() - - if self.remote.command_handler is None: - raise CommandsNotEnabledError("Not enabled") - - if asyncio.iscoroutinefunction(coro): - cmd_data = CommandData( - coro, - aliases, - alias_func, - ) - self.remote.command_handler.register_command(cmd_data) - return RegisteredListener(coro.__name__, cmd_data.coro) - - def wrap_func(coro): - if self.command_options is None: - raise CommandsNotEnabledError("Not enabled") - - if isinstance(coro, RegisteredListener): - coro = coro.get_coro() - - cmd_data = CommandData( - coro, - aliases, - alias_func, - ) - self.remote.command_handler.register_command(cmd_data) - return RegisteredListener(coro.__name__, cmd_data.coro) - - return wrap_func - - def team_event(self, coro) -> RegisteredListener: - """ - A Decorator to register an event listener for team changes - - :param coro: The coroutine to call when a change happens - :return: RegisteredListener - The listener object - """ - - if isinstance(coro, RegisteredListener): - coro = coro.get_coro() - - listener = RegisteredListener("team_changed", coro) - TeamEvent.handlers.register(listener, self.server_id) - return listener - - def chat_event(self, coro) -> RegisteredListener: - """ - A Decorator to register an event listener for chat messages - - :param coro: The coroutine to call when a message is sent - :return: RegisteredListener - The listener object - """ - - if isinstance(coro, RegisteredListener): - coro = coro.get_coro() - - listener = RegisteredListener("chat_message", coro) - ChatEvent.handlers.register(listener, self.server_id) - return listener - - def entity_event(self, eid): - """ - Decorator to register a smart device listener - - :param eid: The entity id of the entity - :return: RegisteredListener - The listener object - :raises SmartDeviceRegistrationError - """ - - def wrap_func(coro) -> RegisteredListener: - if isinstance(coro, RegisteredListener): - coro = coro.get_coro() - - self.remote.handle_subscribing_entity(eid, coro) - - return RegisteredListener(eid, coro) - - return wrap_func - - async def start_marker_event_listener(self, delay: int = 5) -> None: - """ - Starts the marker event listener - :param delay: The delay between marker checking - :return: None - """ - self.marker_listener.start(delay) - - def marker_event(self, coro) -> RegisteredListener: - """ - A Decorator to register an event listener for new map markers - - :param coro: The coroutine to call when the command is called - :return: RegisteredListener - The listener object - """ - - if isinstance(coro, RegisteredListener): - coro = coro.get_coro() - - if not self.marker_listener: - raise ValueError("Marker listener not started") - - listener = RegisteredListener("map_marker", coro) - self.marker_listener.add_listener(listener) - return listener - - def protobuf_received(self, coro) -> RegisteredListener: - """ - A Decorator to register an event listener for protobuf being received on the websocket - - :param coro: The coroutine to call when the command is called - :return: RegisteredListener - The listener object - """ - - if isinstance(coro, RegisteredListener): - coro = coro.get_coro() - - listener = RegisteredListener("protobuf_received", coro) - ProtobufEvent.handlers.register(listener, self.server_id) - return listener - - def remove_listener(self, listener) -> bool: - """ - This will remove a listener, command or event. Takes a RegisteredListener instance - - :return: Success of removal. True = Removed. False = Not Removed - """ - if isinstance(listener, RegisteredListener): - if listener.listener_id == "map_marker": - return self.marker_listener.remove_listener(listener) - - if ChatEvent.handlers.has(listener, self.server_id): - ChatEvent.handlers.unregister(listener, self.server_id) - return True - - if TeamEvent.handlers.has(listener, self.server_id): - TeamEvent.handlers.unregister(listener, self.server_id) - return True - - if EntityEvent.handlers.has(listener, self.server_id): - EntityEvent.handlers.unregister(listener, self.server_id) - return True - - if ProtobufEvent.handlers.has(listener, self.server_id): - ProtobufEvent.handlers.unregister(listener, self.server_id) - return True - - return False - - @staticmethod - async def hang() -> None: - """ - This Will permanently put your script into a state of 'hanging' Cannot be Undone. Only do this in scripts - using commands - - :returns Nothing, This will never return - """ - - while True: - await asyncio.sleep(1) - - @deprecated("Implement this yourself. This will be removed in thed future") - def get_conversation_factory(self) -> ConversationFactory: - """ - Gets the current ConversationFactory object - - :returns ConversationFactory: the factory - """ - return self.remote.conversation_factory - - async def get_time(self) -> RustTime: - """ - Gets the current in-game time from the server. - - :returns RustTime: The Time - """ - raise NotImplementedError("Not Implemented") - - async def send_team_message(self, message: str) -> None: - """ - Sends a message to the in-game team chat - - :param message: The string message to send - """ - raise NotImplementedError("Not Implemented") - - async def get_info(self) -> RustInfo: - """ - Gets information on the Rust Server - :return: RustInfo - The info of the server - """ - raise NotImplementedError("Not Implemented") - - async def get_team_chat(self) -> List[RustChatMessage]: - """ - Gets the team chat from the server - - :return List[RustChatMessage]: The chat messages in the team chat - """ - raise NotImplementedError("Not Implemented") - - async def get_team_info(self) -> RustTeamInfo: - """ - Gets Information on the members of your team - - :return RustTeamInfo: The info of your team - """ - raise NotImplementedError("Not Implemented") - - async def get_markers(self) -> List[RustMarker]: - """ - Gets all the map markers from the server - - :return List[RustMarker]: All the markers on the map - """ - raise NotImplementedError("Not Implemented") - - async def get_map( - self, - add_icons: bool = False, - add_events: bool = False, - add_vending_machines: bool = False, - override_images: dict = None, - add_grid: bool = False, - ) -> Image.Image: - """ - Gets an image of the map from the server with the specified additions - - :param add_icons: To add the monument icons - :param add_events: To add the Event icons - :param add_vending_machines: To add the vending icons - :param override_images: To override the images pre-supplied with RustPlus.py - :param add_grid: To add the grid to the map - :return Image: PIL Image - """ - raise NotImplementedError("Not Implemented") - - async def get_raw_map_data(self) -> RustMap: - """ - Gets the raw map data from the server - - :return RustMap: The raw map of the server - """ - raise NotImplementedError("Not Implemented") - - async def get_entity_info(self, eid: int = None) -> RustEntityInfo: - """ - Gets entity info from the server - - :param eid: The Entities ID - :return RustEntityInfo: The entity Info - """ - raise NotImplementedError("Not Implemented") - - async def turn_on_smart_switch(self, eid: int = None) -> None: - """ - Turns on a given smart switch by entity ID - - :param eid: The Entities ID - :return None: - """ - raise NotImplementedError("Not Implemented") - - async def turn_off_smart_switch(self, eid: int = None) -> None: - """ - Turns off a given smart switch by entity ID - - :param eid: The Entities ID - :return None: - """ - raise NotImplementedError("Not Implemented") - - async def promote_to_team_leader(self, steamid: int = None) -> None: - """ - Promotes a given user to the team leader by their 64-bit Steam ID - - :param steamid: The SteamID of the player to promote - :return None: - """ - raise NotImplementedError("Not Implemented") - - @deprecated("Use RustSocket#get_markers") - async def get_current_events(self) -> List[RustMarker]: - """ - Returns all the map markers that are for events: - Can detect: - - Explosion - - CH47 (Chinook) - - Cargo Ship - - Locked Crate - - Attack Helicopter - - :return List[RustMarker]: All current events - """ - raise NotImplementedError("Not Implemented") - - async def get_contents( - self, eid: int = None, combine_stacks: bool = False - ) -> RustContents: - """ - Gets the contents of a storage monitor-attached container - - :param eid: The EntityID Of the storage Monitor - :param combine_stacks: Whether to combine alike stacks together - :return RustContents: The contents on the monitor - """ - raise NotImplementedError("Not Implemented") - - @deprecated("Use RustSocket#get_contents") - async def get_tc_storage_contents( - self, eid: int = None, combine_stacks: bool = False - ) -> RustContents: - """ - Gets the Information about TC Upkeep and Contents. - Do not use this for any other storage monitor than a TC - """ - raise NotImplementedError("Not Implemented") - - async def get_camera_manager(self, cam_id: str) -> CameraManager: - """ - Gets a camera manager for a given camera ID - - NOTE: This will override the current camera manager if one exists for the given ID so you cannot have multiple - - :param cam_id: The ID of the camera - :return CameraManager: The camera manager - :raises RequestError: If the camera is not found, or you cannot access it. See reason for more info - """ - raise NotImplementedError("Not Implemented") diff --git a/rustplus_old/api/icons/__init__.py b/rustplus_old/api/icons/__init__.py deleted file mode 100644 index b6e690f..0000000 --- a/rustplus_old/api/icons/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import * diff --git a/rustplus_old/api/remote/__init__.py b/rustplus_old/api/remote/__init__.py deleted file mode 100644 index 3a622b8..0000000 --- a/rustplus_old/api/remote/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from .rustplus_proto import * -from .rustws import RustWebsocket -from .ratelimiter import RateLimiter -from .rust_remote_interface import RustRemote -from .heartbeat import HeartBeat -from .server_checker import ServerChecker -from ..remote.events.event_handler import EventHandler -from ..remote.events.map_event_listener import MapEventListener diff --git a/rustplus_old/api/remote/camera/__init__.py b/rustplus_old/api/remote/camera/__init__.py deleted file mode 100644 index b39ec70..0000000 --- a/rustplus_old/api/remote/camera/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .camera_manager import CameraManager -from .camera_constants import CameraMovementOptions, MovementControls -from .structures import CameraInfo diff --git a/rustplus_old/api/remote/camera/camera_constants.py b/rustplus_old/api/remote/camera/camera_constants.py deleted file mode 100644 index 630838b..0000000 --- a/rustplus_old/api/remote/camera/camera_constants.py +++ /dev/null @@ -1,35 +0,0 @@ -class MovementControls: - """ - Possible inputs for the camera movement. - """ - - FORWARD = 2 - BACKWARD = 4 - LEFT = 8 - RIGHT = 16 - JUMP = 32 - DUCK = 64 - SPRINT = 128 - USE = 256 - FIRE_PRIMARY = 1024 - FIRE_SECONDARY = 2048 - RELOAD = 8192 - FIRE_THIRD = 134217728 - - -class CameraMovementOptions: - """ - Indicate which camera controls are active for the camera. - - """ - - NONE = 0 - MOVEMENT = 1 - MOUSE = 2 - SPRINT_AND_DUCK = 4 - FIRE = 8 - RELOAD = 16 - CROSSHAIR = 32 - - -LOOKUP_CONSTANTS = [51, 36, 143, 3, 60, 60, 144, 59, 79, 58, 157, 85, 119, 65, 134, 73, 52, 23, 90, 44, 29, 72, 122, 45, 12, 6, 136, 80, 25, 53, 8, 37, 134, 7, 76, 2, 2, 35, 43, 78, 134, 2, 98, 19, 90, 21, 125, 67, 12, 48, 43, 24, 143, 24, 83, 17, 53, 3, 82, 17, 49, 21, 4, 63, 101, 64, 151, 74, 75, 2, 62, 45, 100, 19, 86, 50, 97, 6, 138, 11, 152, 27, 132, 10, 104, 78, 8, 79, 111, 54, 72, 41, 7, 0, 102, 69, 99, 10, 145, 63, 53, 67, 13, 16, 92, 38, 51, 20, 12, 37, 41, 3, 91, 77, 83, 55, 79, 59, 139, 69, 108, 10, 115, 75, 108, 42, 0, 37, 21, 31, 82, 68, 104, 53, 145, 81, 80, 87, 128, 20, 34, 48, 123, 31, 80, 48, 83, 34, 27, 61, 146, 18, 136, 30, 65, 9, 14, 1, 150, 23, 11, 31, 129, 35, 65, 78, 47, 72, 67, 8, 41, 70, 28, 32, 54, 60, 94, 74, 155, 52, 155, 18, 71, 22, 76, 45, 112, 28, 73, 49, 124, 8, 81, 84, 45, 29, 82, 88, 38, 55, 140, 6, 11, 49, 14, 55, 144, 50, 75, 70, 10, 21, 109, 86, 48, 52, 137, 19, 74, 2, 18, 47, 51, 12, 62, 56, 77, 26, 0, 78, 8, 80, 143, 87, 92, 3, 136, 20, 128, 85, 45, 61, 102, 19, 5, 68, 153, 33, 56, 23, 35, 45, 73, 30, 29, 39, 57, 88, 17, 65, 48, 39, 124, 59, 105, 87, 148, 89, 45, 30, 57, 83, 13, 2, 105, 75, 150, 38, 143, 9, 122, 15, 29, 66, 29, 12, 87, 5, 21, 2, 106, 83, 16, 23, 50, 45, 56, 62, 142, 7, 56, 60, 136, 34, 65, 5, 70, 9, 31, 64, 2, 18, 102, 7, 159, 47, 7, 26, 67, 66, 150, 35, 2, 27, 89, 40, 81, 41, 115, 48, 155, 50, 81, 27, 133, 42, 131, 77, 142, 87, 157, 59, 129, 30, 90, 4, 39, 20, 138, 61, 150, 78, 107, 79, 115, 9, 1, 76, 45, 42, 143, 2, 24, 15, 24, 78, 119, 47, 110, 9, 12, 29, 140, 77, 31, 50, 43, 80, 127, 39, 139, 65, 79, 80, 151, 36, 34, 60, 77, 78, 110, 34, 97, 24, 132, 87, 53, 66, 27, 45, 96, 56, 56, 1, 9, 62, 12, 72, 128, 28, 108, 73, 70, 43, 88, 36, 51, 29, 119, 41, 115, 66, 17, 16, 62, 20, 110, 11, 136, 18, 5, 37, 26, 45, 16, 47, 117, 47, 38, 29, 131, 23, 13, 45, 131, 26, 112, 46, 42, 55, 147, 82, 71, 59, 145, 5, 117, 37, 92, 64, 83, 82, 102, 40, 145, 76, 120, 75, 65, 38, 74, 39, 121, 10, 105, 54, 54, 32, 133, 57, 42, 66, 59, 53, 143, 47, 16, 48, 88, 44, 46, 87, 17, 3, 65, 16, 111, 24, 4, 25, 120, 64, 68, 40, 94, 65, 74, 37, 117, 15, 23, 50, 82, 45, 148, 82, 110, 51, 49, 19, 92, 31, 3, 75, 158, 68, 62, 69, 47, 58, 159, 6, 103, 9, 157, 88, 89, 21, 76, 72, 150, 31, 10, 60, 15, 52, 93, 27, 149, 29, 3, 35, 19, 56, 74, 71, 45, 41, 120, 19, 147, 52, 35, 74, 120, 63, 26, 1, 153, 71, 85, 64, 5, 64, 4, 79, 35, 58, 152, 62, 112, 4, 38, 71, 108, 5, 93, 2, 59, 30, 111, 5, 87, 1, 149, 87, 47, 32, 156, 46, 115, 19, 127, 76, 46, 40, 109, 36, 117, 84, 20, 27, 8, 24, 101, 69, 22, 59, 60, 44, 111, 11, 18, 55, 141, 70, 104, 0, 86, 6, 146, 79, 159, 61, 67, 28, 37, 20, 50, 0, 90, 24, 31, 11, 26, 53, 98, 14, 97, 84, 99, 24, 52, 73, 89, 86, 124, 1, 19, 19, 120, 37, 37, 65, 49, 15, 81, 89, 143, 64, 75, 10, 55, 39, 117, 17, 88, 31, 130, 20, 139, 43, 106, 48, 71, 89, 126, 29, 81, 73, 23, 65, 33, 35, 58, 55, 36, 32, 93, 16, 80, 14, 157, 41, 76, 15, 17, 82, 133, 11, 2, 87, 24, 38, 140, 49, 92, 77, 66, 29, 101, 23, 152, 5, 121, 77, 85, 62, 76, 73, 46, 78, 57, 77, 61, 44, 156, 15, 84, 25, 87, 45, 66, 3, 69, 84, 92, 12, 96, 66, 155, 75, 98, 72, 28, 71, 106, 81, 100, 55, 98, 64, 65, 86, 133, 1, 28, 88, 68, 14, 116, 79, 36, 81, 129, 27, 69, 69, 141, 14, 39, 57, 72, 61, 21, 16, 112, 79, 151, 24, 133, 16, 115, 84, 19, 82, 110, 83, 108, 3, 22, 88, 140, 51, 63, 12, 23, 69, 35, 10, 90, 47, 135, 56, 120, 18, 147, 88, 104, 5, 149, 4, 16, 75, 131, 16, 109, 16, 33, 80, 21, 86, 146, 75, 128, 11, 92, 66, 12, 36, 60, 50, 106, 61, 29, 59, 18, 8, 75, 87, 148, 52, 41, 80, 36, 54, 11, 27, 158, 13, 68, 30, 96, 49, 148, 8, 70, 41, 22, 16, 74, 49, 132, 34, 16, 84, 158, 55, 93, 75, 37, 47, 117, 64, 42, 85, 35, 6, 0, 19, 104, 42, 156, 13, 88, 80, 69, 47, 61, 65, 107, 58, 25, 29, 61, 17, 137, 8, 34, 46, 74, 19, 6, 61, 38, 32, 74, 27, 47, 2, 142, 56, 26, 60, 23, 26, 68, 26, 60, 28, 130, 44, 115, 76, 139, 15, 136, 42, 119, 54, 56, 51, 120, 42, 71, 73, 123, 28, 91, 43, 124, 66, 51, 87, 141, 76, 19, 1, 19, 44, 134, 23, 102, 80, 61, 28, 73, 18, 68, 86, 150, 1, 136, 63, 74, 66, 60, 61, 92, 45, 141, 11, 122, 25, 94, 14, 69, 8, 12, 12, 58, 14, 72, 38, 98, 63, 99, 1, 15, 27, 83, 6, 122, 69, 30, 74, 58, 81, 8, 84, 36, 88, 30, 63, 159, 18, 82, 73, 40, 22, 37, 46, 112, 37, 68, 2, 157, 11, 54, 28, 149, 73, 113, 61, 18, 43, 48, 9, 104, 61, 17, 7, 73, 41, 95, 50, 69, 75, 96, 83, 103, 6, 87, 7, 18, 84, 54, 64, 3, 22, 2, 40, 50, 22, 57, 4, 111, 80, 107, 84, 22, 34, 21, 9, 45, 67, 2, 70, 84, 43, 50, 52, 49, 74, 138, 79, 103, 34, 53, 5, 41, 25, 43, 87, 157, 1, 56, 64, 57, 28, 50, 51, 113, 17, 44, 14, 21, 44, 80, 42, 35, 14, 147, 43, 3, 24, 136, 49, 35, 67, 148, 74, 159, 37, 144, 16, 32, 39, 16, 66, 82, 77, 30, 36, 2, 47, 136, 66, 61, 48, 115, 29, 109, 34, 114, 31, 19, 65, 68, 73, 132, 5, 92, 14, 17, 38, 104, 72, 23, 10, 32, 45, 11, 4, 35, 4, 159, 0, 109, 82, 2, 65, 23, 81, 94, 51, 57, 75, 59, 49, 16, 88, 35, 49, 65, 32, 124, 35, 51, 2, 2, 4, 49, 13, 111, 7, 94, 24, 68, 12, 38, 20, 13, 33, 130, 80, 130, 5, 117, 0, 89, 33, 121, 42, 9, 78, 150, 57, 79, 37, 11, 73, 0, 64, 65, 75, 140, 72, 17, 89, 128, 41, 15, 83, 75, 81, 157, 13, 118, 89, 8, 18, 102, 53, 51, 23, 22, 14, 99, 30, 81, 52, 75, 6, 15, 25, 139, 29, 70, 23, 33, 41, 128, 47, 16, 78, 54, 55, 150, 48, 21, 74, 9, 29, 6, 33, 84, 7, 17, 78, 35, 61, 99, 77, 32, 5, 83, 37, 108, 26, 140, 3, 153, 59, 61, 5, 1, 56, 135, 26, 101, 71, 145, 35, 2, 34, 122, 14, 91, 35, 11, 85, 77, 84, 71, 45, 76, 25, 41, 33, 134, 29, 139, 22, 29, 47, 46, 37, 150, 43, 128, 34, 34, 28, 53, 75, 4, 34, 113, 41, 90, 53, 153, 61, 49, 79, 90, 8, 62, 52, 98, 47, 38, 52, 17, 5, 136, 24, 100, 81, 75, 50, 13, 42, 47, 56, 6, 85, 136, 87, 10, 63, 54, 58, 104, 77, 104, 84, 153, 42, 125, 5, 123, 69, 100, 86, 77, 2, 48, 24, 24, 72, 96, 0, 73, 56, 48, 81, 128, 57, 52, 26, 76, 66, 141, 38, 89, 81, 46, 0, 42, 60, 152, 7, 21, 26, 153, 50, 156, 44, 16, 59, 54, 43, 16, 11, 10, 33, 24, 58, 22, 24, 37, 51, 142, 43, 139, 54, 105, 12, 37, 81, 98, 66, 78, 87, 83, 42, 7, 37, 78, 56, 62, 63, 158, 19, 1, 20, 133, 60, 29, 0, 65, 69, 157, 60, 62, 5, 138, 40, 29, 86, 138, 65, 74, 48, 127, 84, 41, 45, 23, 47, 153, 3, 35, 57, 33, 44, 100, 40, 20, 29, 129, 79, 119, 86, 34, 69, 6, 60, 19, 63, 149, 80, 68, 11, 66, 28, 13, 49, 99, 37, 103, 75, 84, 74, 95, 60, 19, 28, 77, 7, 74, 16, 28, 24, 19, 47, 64, 28, 12, 68, 79, 21, 18, 83, 62, 81, 142, 41, 39, 48, 78, 23, 126, 83, 14, 9, 43, 34, 79, 76, 16, 49, 87, 46, 0, 75, 125, 14, 96, 74, 58, 0, 55, 16, 125, 26, 45, 20, 62, 44, 4, 49, 28, 67, 97, 14, 29, 55, 21, 64, 20, 40, 96, 85, 148, 65, 101, 77, 126, 1, 116, 28, 40, 29, 149, 11, 99, 11, 46, 80, 78, 26, 93, 49, 19, 77, 84, 80, 12, 8, 42, 47, 127, 19, 147, 80, 39, 1, 62, 26, 95, 19, 45, 8, 32, 10, 93, 7, 148, 70, 108, 44, 89, 12, 53, 57, 76, 18, 77, 25, 101, 63, 5, 18, 38, 69, 118, 38, 145, 44, 4, 42, 57, 63, 94, 47, 92, 5, 59, 55, 46, 61, 92, 23, 134, 79, 70, 22, 124, 56, 14, 64, 96, 64, 110, 41, 147, 51, 25, 2, 117, 27, 116, 76, 123, 18, 37, 25, 59, 36, 143, 6, 138, 55, 137, 43, 70, 89, 135, 3, 53, 12, 105, 53, 146, 84, 108, 48, 65, 20, 27, 5, 158, 29, 65, 39, 94, 28, 33, 77, 123, 17, 63, 33, 36, 66, 1, 78, 0, 59, 144, 67, 132, 41, 19, 22, 95, 47, 49, 66, 105, 32, 28, 83, 152, 66, 37, 33, 110, 35, 122, 85, 65, 67, 128, 43, 90, 76, 84, 57, 23, 76, 97, 18, 33, 3, 95, 54, 155, 26, 71, 65, 90, 26, 106, 6, 141, 45, 149, 47, 91, 28, 59, 61, 99, 59, 0, 18, 92, 89, 108, 34, 62, 3, 62, 10, 92, 36, 78, 59, 106, 29, 74, 57, 112, 15, 129, 81, 141, 52, 96, 9, 30, 59, 151, 11, 81, 13, 105, 0, 17, 37, 145, 31, 141, 44, 125, 18, 62, 87, 125, 68, 99, 9, 145, 38, 45, 69, 100, 16, 60, 68, 26, 10, 2, 77, 133, 84, 22, 58, 76, 27, 122, 43, 132, 25, 32, 52, 41, 13, 33, 19, 35, 66, 116, 14, 41, 59, 112, 85, 26, 0, 130, 55, 8, 78, 141, 53, 122, 30, 153, 35, 96, 48, 15, 19, 134, 6, 16, 65, 4, 6, 133, 34, 31, 46, 0, 34, 55, 13, 65, 70, 67, 23, 45, 64, 68, 67, 76, 36, 17, 23, 40, 38, 156, 79, 30, 27, 107, 59, 28, 57, 89, 20, 147, 25, 142, 9, 128, 15, 43, 50, 70, 71, 49, 41, 47, 84, 18, 79, 84, 9, 21, 78, 47, 65, 6, 68, 79, 69, 68, 8, 70, 61, 120, 55, 3, 23, 72, 55, 60, 57, 72, 68, 37, 40, 90, 33, 129, 37, 57, 41, 80, 13, 97, 34, 47, 71, 52, 15, 153, 79, 131, 58, 65, 45, 20, 67, 70, 78, 150, 5, 154, 8, 45, 49, 136, 62, 148, 66, 103, 36, 125, 70, 6, 23, 111, 16, 151, 37, 69, 87, 10, 79, 103, 38, 156, 9, 49, 67, 95, 24, 92, 76, 72, 10, 3, 79, 48, 69, 59, 10, 14, 0, 147, 83, 134, 20, 13, 74, 30, 71, 127, 58, 11, 14, 110, 3, 5, 53, 114, 83, 129, 68, 56, 21, 83, 18, 67, 83, 76, 4, 146, 55, 127, 0, 76, 74, 141, 83, 142, 13, 64, 66, 61, 63, 55, 57, 130, 43, 149, 22, 57, 47, 104, 63, 37, 38, 77, 37, 43, 5, 30, 73, 50, 34, 18, 59, 43, 15, 44, 4, 110, 40, 43, 49, 101, 8, 111, 81, 42, 43, 124, 43, 138, 70, 74, 78, 4, 36, 43, 3, 50, 70, 53, 31, 28, 22, 151, 35, 61, 25, 113, 57, 37, 29, 64, 86, 94, 38, 65, 47, 132, 17, 54, 18, 78, 38, 31, 31, 22, 40, 156, 0, 65, 29, 110, 5, 38, 40, 107, 2, 152, 87, 11, 25, 80, 81, 50, 66, 18, 71, 86, 19, 134, 53, 79, 75, 82, 55, 24, 75, 112, 61, 102, 72, 150, 0, 148, 57, 8, 14, 36, 52, 34, 41, 126, 56, 40, 26, 17, 0, 42, 82, 60, 30, 26, 62, 16, 42, 95, 12, 18, 61, 145, 82, 89, 17, 80, 22, 30, 20, 142, 40, 35, 72, 114, 21, 151, 50, 139, 87, 106, 5, 148, 49, 140, 35, 50, 50, 78, 45, 21, 68, 14, 7, 156, 57, 39, 68, 75, 30, 94, 21, 108, 41, 52, 40, 50, 65, 100, 6, 131, 13, 3, 20, 76, 9, 156, 25, 138, 26, 138, 18, 52, 32, 10, 44, 152, 54, 130, 33, 105, 74, 1, 57, 93, 9, 107, 15, 120, 86, 80, 8, 78, 9, 100, 23, 37, 85, 102, 2, 116, 51, 96, 75, 101, 18, 97, 54, 78, 76, 143, 88, 38, 44, 109, 39, 98, 10, 100, 69, 12, 84, 92, 22, 102, 62, 7, 52, 159, 19, 124, 37, 112, 86, 65, 2, 130, 79, 3, 39, 135, 87, 101, 67, 106, 52, 113, 0, 140, 50, 49, 3, 111, 87, 98, 58, 102, 57, 48, 16, 150, 80, 9, 53, 127, 68, 125, 55, 87, 64, 91, 66, 43, 7, 81, 47, 79, 87, 146, 58, 87, 53, 28, 26, 13, 6, 96, 69, 110, 18, 4, 45, 52, 19, 15, 28, 123, 4, 92, 11, 12, 4, 34, 14, 137, 35, 145, 55, 8, 17, 78, 21, 59, 67, 42, 4, 26, 86, 136, 33, 89, 1, 47, 41, 107, 4, 149, 21, 2, 74, 77, 59, 146, 78, 129, 58, 76, 53, 8, 44, 48, 86, 114, 13, 2, 55, 29, 51, 100, 45, 148, 56, 24, 56, 106, 26, 14, 54, 94, 36, 35, 2, 110, 70, 58, 78, 19, 37, 109, 17, 30, 39, 88, 15, 144, 40, 36, 51, 49, 11, 58, 80, 149, 35, 19, 54, 99, 83, 108, 45, 151, 49, 6, 6, 34, 70, 72, 12, 87, 43, 66, 60, 132, 4, 39, 81, 145, 33, 158, 16, 107, 13, 104, 81, 13, 70, 140, 17, 151, 21, 46, 59, 157, 12, 102, 64, 110, 28, 82, 49, 4, 66, 73, 10, 22, 74, 36, 14, 51, 47, 98, 53, 54, 41, 67, 17, 126, 55, 39, 47, 7, 58, 134, 25, 140, 2, 12, 20, 159, 36, 111, 68, 36, 43, 59, 62, 98, 75, 53, 45, 80, 79, 156, 62, 126, 25, 158, 71, 94, 61, 142, 30, 33, 42, 56, 63, 0, 45, 67, 53, 106, 31, 32, 20, 24, 79, 23, 67, 152, 85, 145, 16, 138, 42, 48, 27, 131, 60, 4, 62, 110, 88, 98, 80, 56, 7, 76, 67, 77, 82, 98, 65, 43, 86, 127, 13, 154, 35, 30, 23, 48, 79, 75, 7, 68, 52, 79, 67, 152, 69, 116, 20, 140, 18, 25, 51, 95, 83, 86, 18, 86, 86, 29, 81, 63, 32, 117, 36, 7, 47, 118, 54, 110, 4, 38, 6, 126, 43, 77, 0, 114, 49, 144, 51, 86, 14, 59, 82, 131, 41, 54, 82, 36, 75, 31, 39, 126, 34, 99, 50, 145, 46, 131, 4, 13, 35, 53, 77, 35, 16, 72, 40, 22, 61, 115, 31, 60, 65, 103, 69, 121, 79, 145, 4, 44, 3, 92, 21, 157, 78, 105, 81, 128, 87, 77, 19, 70, 27, 122, 62, 146, 68, 61, 12, 156, 11, 62, 34, 93, 13, 129, 10, 27, 1, 67, 46, 123, 73, 32, 22, 78, 35, 72, 32, 80, 55, 110, 16, 64, 60, 53, 76, 157, 0, 93, 86, 1, 77, 85, 25, 50, 64, 142, 49, 141, 37, 106, 9, 158, 49, 78, 16, 90, 42, 63, 59, 121, 70, 13, 48, 42, 63, 85, 68, 32, 77, 134, 37, 122, 19, 137, 1, 131, 86, 86, 5, 116, 0, 51, 73, 142, 63, 6, 32, 151, 39, 28, 75, 11, 87, 62, 13, 19, 8, 78, 54, 108, 51, 139, 34, 84, 35, 129, 20, 70, 64, 39, 11, 10, 36, 38, 35, 4, 16, 37, 55, 45, 10, 47, 21, 4, 30, 92, 46, 153, 15, 124, 7, 89, 41, 84, 2, 157, 43, 66, 36, 137, 10, 11, 26, 33, 16, 119, 5, 128, 42, 145, 2, 120, 12, 117, 7, 98, 29, 29, 61, 116, 21, 19, 23, 24, 55, 125, 25, 15, 39, 149, 36, 89, 60, 42, 27, 63, 58, 82, 2, 153, 16, 99, 35, 34, 26, 107, 33, 150, 36, 17, 86, 40, 12, 33, 69, 61, 40, 5, 35, 61, 61, 132, 42, 52, 79, 137, 17, 126, 68, 74, 80, 66, 68, 78, 10, 71, 64, 79, 52, 74, 54, 33, 11, 125, 83, 35, 73, 124, 76, 0, 69, 29, 79, 119, 89, 92, 65, 14, 63, 40, 77, 73, 45, 112, 32, 121, 60, 9, 36, 86, 11, 21, 67, 122, 5, 65, 24, 27, 75, 92, 58, 15, 10, 6, 70, 102, 81, 39, 9, 126, 85, 133, 0, 47, 26, 19, 20, 24, 54, 97, 62, 2, 21, 40, 51, 139, 51, 1, 43, 22, 46, 2, 68, 105, 5, 119, 83, 109, 6, 19, 51, 70, 17, 33, 0, 80, 6, 111, 9, 93, 14, 79, 81, 86, 78, 64, 89, 118, 34, 70, 38, 76, 52, 46, 24, 125, 24, 2, 9, 62, 66, 73, 25, 136, 21, 88, 78, 84, 39, 150, 59, 88, 18, 38, 5, 4, 86, 111, 13, 21, 63, 45, 58, 128, 59, 16, 87, 59, 42, 96, 45, 113, 9, 155, 79, 11, 17, 115, 72, 121, 47, 112, 31, 94, 5, 155, 73, 44, 34, 16, 69, 148, 50, 5, 89, 75, 3, 53, 1, 153, 53, 146, 83, 14, 72, 15, 43, 24, 50, 150, 15, 3, 54, 149, 5, 67, 88, 114, 56, 66, 22, 144, 55, 1, 26, 14, 52, 94, 19, 72, 24, 148, 40, 72, 8, 21, 34, 134, 31, 111, 19, 118, 72, 4, 43, 58, 15, 72, 47, 109, 31, 24, 63, 14, 79, 102, 44, 101, 19, 51, 56, 121, 85, 24, 6, 33, 61, 98, 73, 128, 31, 43, 36, 77, 72, 131, 40, 137, 77, 44, 83, 122, 86, 16, 25, 107, 85, 16, 63, 97, 85, 46, 46, 148, 37, 38, 46, 155, 4, 68, 46, 49, 73, 37, 68, 19, 62, 157, 16, 144, 87, 81, 53, 64, 52, 52, 49, 87, 68, 5, 6, 86, 15, 96, 31, 151, 54, 140, 69, 135, 36, 91, 3, 130, 84, 8, 6, 54, 88, 90, 30, 153, 48, 122, 22, 60, 33, 156, 36, 46, 22, 52, 31, 83, 8, 141, 24, 24, 39, 0, 8, 139, 57, 118, 43, 135, 54, 26, 9, 76, 38, 107, 62, 59, 51, 4, 44, 87, 40, 97, 0, 90, 56, 99, 15, 73, 14, 29, 18, 135, 27, 108, 86, 80, 5, 71, 77, 131, 76, 136, 25, 10, 53, 10, 87, 100, 53, 126, 24, 58, 51, 143, 75, 29, 9, 8, 49, 37, 58, 85, 89, 80, 49, 142, 62, 57, 66, 155, 23, 56, 75, 108, 46, 75, 38, 153, 76, 143, 38, 150, 84, 137, 56, 148, 2, 42, 13, 66, 70, 34, 38, 67, 57, 155, 54, 39, 25, 86, 28, 30, 32, 114, 58, 64, 9, 128, 33, 132, 68, 0, 25, 29, 54, 159, 4, 83, 3, 131, 38, 12, 47, 83, 87, 7, 63, 102, 41, 114, 53, 153, 23, 11, 86, 74, 58, 23, 78, 132, 47, 0, 38, 88, 75, 75, 9, 146, 21, 77, 9, 58, 29, 135, 19, 101, 39, 103, 84, 158, 12, 117, 35, 72, 7, 81, 2, 13, 55, 56, 17, 147, 27, 159, 76, 94, 52, 36, 84, 134, 3, 32, 59, 98, 89, 153, 63, 154, 2, 25, 11, 90, 49, 100, 48, 41, 78, 56, 27, 99, 75, 0, 73, 18, 15, 71, 63, 66, 71, 97, 47, 29, 19, 69, 30, 138, 2, 34, 45, 18, 33, 7, 73, 104, 50, 62, 2, 85, 35, 7, 21, 32, 27, 70, 21, 0, 55, 144, 2, 93, 65, 14, 76, 87, 75, 4, 35, 137, 37, 105, 24, 55, 89, 43, 11, 39, 29, 82, 52, 80, 35, 52, 54, 56, 86, 33, 66, 25, 3, 116, 81, 59, 19, 145, 61, 14, 83, 125, 71, 34, 42, 65, 10, 149, 78, 131, 62, 81, 51, 51, 66, 60, 18, 66, 14, 58, 35, 41, 81, 140, 5, 151, 40, 32, 63, 84, 85, 144, 57, 93, 40, 116, 57, 51, 28, 56, 48, 102, 45, 151, 16, 135, 84, 9, 27, 155, 2, 0, 71, 28, 27, 27, 71, 126, 28, 130, 64, 10, 23, 34, 76, 128, 88, 95, 16, 87, 29, 82, 20, 34, 77, 43, 48, 140, 25, 86, 31, 39, 63, 139, 84, 49, 52, 126, 2, 96, 72, 4, 85, 132, 63, 141, 5, 142, 37, 82, 11, 77, 15, 40, 3, 58, 86, 133, 12, 16, 35, 55, 18, 76, 23, 130, 39, 99, 76, 153, 18, 89, 74, 128, 3, 11, 7, 58, 1, 26, 72, 15, 6, 51, 52, 20, 73, 37, 2, 115, 68, 78, 14, 70, 3, 130, 62, 81, 82, 147, 24, 80, 32, 116, 22, 146, 9, 50, 49, 44, 47, 124, 32, 71, 16, 57, 65, 103, 77, 77, 39, 155, 83, 32, 82, 46, 12, 28, 84, 29, 4, 65, 43, 135, 6, 155, 87, 17, 33, 2, 22, 106, 10, 78, 22, 29, 71, 20, 7, 133, 54, 21, 71, 30, 87, 14, 80, 122, 73, 16, 71, 137, 54, 83, 85, 82, 4, 78, 55, 63, 18, 3, 41, 30, 82, 40, 86, 153, 39, 52, 5, 79, 28, 11, 47, 123, 67, 122, 60, 123, 0, 144, 25, 59, 24, 111, 74, 153, 87, 35, 47, 51, 15, 114, 26, 28, 36, 95, 27, 61, 6, 83, 35, 159, 75, 12, 5, 30, 57, 136, 75, 52, 34, 51, 61, 116, 53, 61, 43, 103, 14, 93, 44, 8, 85, 86, 45, 9, 83, 132, 9, 121, 38, 4, 80, 71, 70, 10, 45, 111, 66, 143, 25, 75, 76, 119, 71, 135, 23, 81, 37, 0, 40, 121, 57, 49, 24, 31, 69, 52, 70, 26, 49, 54, 69, 74, 53, 89, 62, 6, 84, 77, 12, 40, 59, 46, 51, 120, 61, 93, 57, 129, 42, 122, 27, 7, 7, 61, 1, 35, 84, 19, 72, 97, 13, 53, 15, 113, 8, 116, 73, 58, 63, 57, 38, 115, 78, 113, 31, 78, 62, 115, 35, 50, 88, 57, 17, 93, 82, 70, 1, 66, 49, 87, 80, 0, 3, 74, 55, 69, 74, 47, 27, 83, 65, 143, 1, 158, 89, 25, 77, 94, 18, 114, 50, 22, 20, 20, 75, 77, 11, 14, 38, 75, 65, 15, 68, 5, 88, 60, 49, 69, 68, 155, 19, 76, 31, 64, 19, 150, 69, 127, 79, 95, 88, 144, 17, 13, 32, 115, 8, 14, 10, 46, 13, 152, 20, 27, 58, 132, 66, 80, 82, 28, 64, 39, 7, 50, 55, 97, 7, 61, 76, 27, 11, 116, 15, 153, 89, 159, 53, 141, 49, 35, 85, 37, 82, 31, 77, 9, 9, 66, 43, 9, 60, 142, 86, 11, 55, 42, 45, 51, 69, 61, 73, 34, 63, 144, 86, 90, 3, 123, 54, 128, 38, 73, 4, 126, 86, 108, 49, 67, 75, 152, 11, 22, 65, 139, 19, 89, 73, 110, 81, 15, 0, 1, 46, 91, 57, 19, 39, 59, 0, 133, 63, 49, 8, 9, 64, 124, 38, 144, 1, 20, 6, 86, 80, 46, 49, 7, 16, 113, 16, 69, 27, 153, 17, 78, 0, 134, 52, 66, 25, 59, 72, 42, 35, 150, 88, 17, 55, 54, 80, 93, 77, 86, 35, 8, 67, 122, 40, 154, 28, 114, 73, 24, 27, 125, 69, 76, 47, 74, 56, 123, 89, 48, 21, 12, 89, 84, 49, 31, 21, 106, 23, 28, 82, 68, 18, 100, 89, 42, 77, 33, 52, 133, 71, 44, 62, 67, 11, 43, 89, 20, 82, 64, 17, 61, 41, 116, 82, 99, 58, 38, 59, 15, 46, 150, 87, 127, 35, 78, 64, 64, 20, 153, 54, 94, 6, 118, 86, 55, 34, 24, 71, 63, 50, 69, 71, 56, 40, 117, 10, 55, 29, 93, 15, 53, 60, 117, 48, 103, 5, 58, 70, 4, 23, 95, 33, 14, 28, 107, 86, 11, 18, 38, 74, 39, 60, 88, 42, 71, 47, 80, 9, 31, 37, 159, 39, 111, 60, 97, 8, 44, 25, 92, 56, 81, 86, 42, 53, 40, 2, 42, 28, 80, 1, 22, 7, 122, 32, 95, 45, 41, 50, 41, 23, 139, 72, 30, 11, 7, 22, 8, 89, 3, 84, 56, 16, 19, 32, 123, 60, 138, 64, 18, 30, 147, 40, 86, 66, 45, 59, 51, 27, 97, 59, 85, 30, 9, 22, 132, 19, 66, 73, 97, 86, 76, 58, 65, 81, 20, 81, 66, 87, 13, 87, 131, 64, 123, 84, 158, 38, 99, 20, 125, 27, 90, 87, 156, 58, 88, 82, 141, 68, 94, 46, 96, 82, 89, 0, 121, 41, 17, 6, 17, 49, 159, 70, 111, 34, 157, 65, 152, 13, 51, 88, 54, 11, 121, 23, 38, 34, 46, 33, 57, 78, 1, 73, 5, 14, 110, 23, 155, 21, 142, 64, 97, 68, 3, 77, 15, 48, 36, 50, 27, 29, 130, 75, 41, 49, 145, 34, 11, 35, 55, 88, 153, 78, 23, 6, 72, 27, 17, 73, 38, 73, 9, 59, 111, 18, 79, 57, 145, 30, 93, 46, 28, 87, 152, 81, 6, 31, 27, 42, 7, 77, 88, 39, 145, 80, 89, 78, 60, 17, 93, 26, 46, 16, 26, 64, 74, 51, 97, 58, 135, 77, 74, 50, 97, 78, 123, 56, 1, 82, 18, 12, 51, 48, 15, 9, 99, 80, 7, 74, 56, 44, 106, 37, 3, 63, 89, 28, 113, 24, 75, 40, 0, 10, 151, 45, 107, 40, 41, 8, 21, 5, 120, 41, 5, 24, 118, 16, 143, 68, 101, 5, 12, 28, 50, 5, 154, 80, 145, 77, 83, 72, 115, 82, 156, 80, 132, 1, 65, 1, 27, 18, 154, 48, 70, 19, 8, 42, 99, 41, 2, 19, 8, 22, 129, 62, 85, 85, 33, 83, 79, 64, 79, 77, 149, 31, 16, 53, 21, 72, 53, 47, 149, 15, 61, 50, 18, 7, 89, 76, 159, 3, 60, 11, 12, 43, 45, 15, 5, 38, 8, 65, 145, 67, 16, 7, 79, 38, 98, 0, 60, 21, 15, 38, 97, 77, 114, 86, 49, 17, 45, 71, 73, 80, 18, 65, 111, 86, 153, 82, 49, 56, 88, 74, 96, 44, 134, 40, 137, 50, 109, 49, 42, 86, 143, 61, 156, 38, 58, 43, 77, 14, 64, 36, 140, 63, 72, 88, 31, 85, 90, 11, 75, 32, 22, 11, 23, 8, 45, 18, 114, 66, 63, 24, 12, 10, 119, 50, 15, 22, 74, 9, 96, 77, 53, 62, 79, 27, 150, 54, 142, 35, 6, 0, 17, 20, 105, 30, 129, 40, 120, 33, 64, 65, 47, 64, 132, 3, 139, 4, 152, 0, 32, 61, 129, 45, 29, 69, 86, 79, 127, 25, 21, 77, 31, 40, 8, 0, 122, 53, 146, 66, 53, 8, 151, 72, 90, 13, 49, 32, 135, 7, 9, 31, 71, 82, 151, 12, 56, 89, 95, 68, 123, 47, 42, 61, 126, 13, 134, 76, 50, 80, 120, 74, 14, 41, 136, 70, 95, 75, 105, 41, 57, 71, 4, 89, 19, 17, 51, 60, 98, 34, 93, 48, 74, 76, 86, 34, 156, 66, 116, 26, 89, 32, 151, 9, 98, 71, 49, 70, 99, 68, 32, 24, 37, 19, 58, 4, 6, 43, 143, 78, 151, 26, 73, 26, 23, 80, 19, 74, 130, 82, 130, 40, 57, 58, 29, 42, 43, 51, 134, 34, 61, 38, 24, 48, 91, 16, 73, 43, 38, 77, 136, 84, 151, 17, 6, 73, 6, 44, 146, 27, 72, 18, 45, 27, 73, 51, 132, 89, 40, 10, 6, 3, 30, 40, 141, 77, 116, 52, 40, 78, 157, 86, 67, 0, 33, 75, 108, 32, 80, 75, 155, 1, 149, 72, 13, 18, 31, 43, 90, 45, 35, 68, 129, 76, 20, 2, 44, 56, 126, 11, 124, 34, 158, 14, 0, 54, 55, 20, 63, 20, 123, 71, 29, 27, 36, 83, 60, 39, 98, 15, 88, 1, 74, 87, 64, 83, 66, 37, 18, 37, 35, 82, 77, 49, 119, 43, 154, 9, 48, 18, 117, 73, 91, 36, 115, 14, 156, 60, 155, 66, 0, 28, 56, 61, 116, 58, 151, 79, 125, 84, 18, 44, 36, 37, 155, 22, 120, 27, 127, 64, 138, 76, 71, 21, 32, 89, 113, 2, 44, 45, 52, 2, 9, 84, 82, 33, 156, 56, 77, 68, 118, 40, 148, 15, 102, 5, 19, 87, 4, 40, 21, 66, 11, 64, 69, 79, 151, 61, 124, 72, 121, 73, 35, 28, 111, 28, 104, 10, 73, 63, 1, 44, 38, 25, 135, 52, 156, 1, 131, 52, 37, 26, 86, 8, 12, 7, 114, 54, 43, 33, 145, 19, 155, 14, 44, 89, 1, 15, 97, 52, 34, 1, 62, 6, 42, 42, 42, 73, 94, 87, 1, 71, 95, 9, 56, 19, 79, 3, 138, 80, 117, 30, 28, 47, 73, 5, 16, 31, 145, 32, 133, 49, 16, 12, 70, 6, 39, 32, 153, 73, 103, 10, 124, 52, 68, 42, 119, 51, 43, 42, 58, 38, 146, 70, 117, 89, 88, 67, 137, 42, 83, 45, 37, 13, 159, 25, 85, 6, 30, 75, 72, 52, 52, 77, 149, 2, 119, 26, 115, 87, 36, 63, 44, 68, 32, 40, 17, 46, 94, 3, 62, 30, 122, 49, 10, 76, 17, 34, 50, 69, 30, 43, 64, 1, 135, 61, 92, 1, 23, 9, 138, 38, 22, 5, 136, 53, 38, 2, 28, 54, 48, 61, 84, 41, 48, 55, 132, 36, 78, 88, 159, 28, 7, 30, 129, 60, 158, 79, 0, 49, 148, 19, 140, 66, 128, 14, 30, 47, 0, 72, 48, 80, 25, 52, 91, 31, 144, 29, 55, 12, 72, 30, 115, 3, 62, 82, 87, 50, 39, 84, 95, 49, 25, 83, 151, 51, 75, 80, 98, 43, 28, 0, 72, 67, 42, 8, 21, 20, 120, 44, 101, 56, 8, 77, 40, 36, 74, 68, 18, 87, 157, 68, 109, 41, 31, 12, 15, 36, 151, 20, 105, 23, 20, 26, 110, 6, 69, 51, 142, 78, 82, 44, 145, 53, 80, 70, 113, 15, 25, 56, 153, 12, 92, 48, 150, 42, 51, 8, 19, 67, 33, 73, 72, 13, 44, 61, 140, 73, 96, 43, 96, 87, 32, 12, 110, 7, 51, 1, 19, 2, 106, 74, 146, 20, 51, 75, 10, 80, 34, 18, 104, 59, 99, 66, 74, 25, 113, 68, 157, 37, 140, 12, 60, 46, 67, 1, 11, 1, 17, 28, 15, 17, 121, 29, 44, 6, 54, 7, 116, 83, 123, 25, 130, 86, 66, 42, 81, 56, 59, 34, 46, 79, 148, 79, 129, 85, 152, 12, 129, 61, 86, 55, 7, 41, 15, 37, 98, 81, 28, 51, 41, 48, 125, 44, 57, 36, 110, 68, 94, 81, 36, 29, 83, 68, 38, 89, 122, 4, 3, 62, 22, 15, 96, 27, 77, 24, 127, 26, 34, 44, 34, 52, 75, 71, 121, 68, 48, 60, 46, 44, 77, 29, 101, 25, 116, 3, 122, 68, 37, 42, 6, 62, 118, 21, 149, 56, 157, 14, 138, 30, 19, 41, 145, 20, 52, 53, 102, 50, 6, 55, 59, 28, 89, 66, 124, 33, 106, 25, 106, 7, 97, 42, 88, 63, 79, 39, 86, 37, 133, 75, 113, 28, 17, 74, 117, 78, 3, 81, 46, 62, 61, 11, 49, 25, 55, 70, 4, 58, 0, 20, 72, 79, 90, 60, 85, 67, 9, 72, 31, 20, 71, 51, 133, 22, 140, 10, 154, 73, 93, 45, 24, 64, 134, 58, 113, 69, 157, 22, 7, 4, 23, 63, 109, 62, 86, 38, 119, 21, 126, 44, 145, 0, 2, 7, 30, 51, 127, 71, 77, 58, 15, 58, 67, 31, 38, 27, 14, 6, 84, 70, 157, 61, 18, 89, 133, 39, 120, 20, 145, 47, 63, 72, 28, 49, 56, 65, 24, 82, 84, 55, 138, 52, 95, 73, 144, 37, 55, 17, 134, 22, 57, 5, 48, 43, 107, 57, 63, 7, 3, 70, 121, 16, 120, 34, 52, 82, 64, 6, 118, 22, 128, 67, 62, 38, 90, 18, 117, 32, 14, 70, 117, 24, 59, 7, 154, 34, 158, 64, 106, 42, 0, 50, 44, 1, 154, 54, 60, 42, 14, 78, 0, 36, 143, 45, 141, 59, 146, 65, 13, 1, 84, 21, 41, 51, 97, 87, 45, 55, 84, 46, 20, 24, 126, 14, 46, 21, 17, 56, 114, 9, 102, 82, 138, 33, 62, 16, 90, 82, 86, 88, 95, 72, 94, 71, 83, 30, 6, 49, 106, 3, 65, 80, 24, 25, 28, 81, 108, 87, 131, 33, 117, 63, 123, 14, 127, 42, 53, 38, 116, 88, 76, 42, 61, 82, 41, 14, 31, 26, 34, 79, 127, 1, 152, 82, 95, 46, 40, 0, 131, 49, 29, 32, 126, 63, 98, 11, 79, 78, 41, 30, 121, 5, 123, 59, 87, 41, 83, 7, 45, 89, 11, 82, 73, 23, 73, 3, 99, 73, 29, 44, 127, 40, 98, 20, 93, 78, 54, 21, 72, 4, 94, 35, 72, 36, 59, 32, 76, 10, 96, 39, 134, 43, 24, 21, 129, 6, 50, 24, 132, 65, 50, 83, 132, 44, 148, 11, 65, 7, 50, 18, 47, 5, 75, 85, 62, 68, 136, 19, 62, 53, 136, 43, 59, 27, 11, 22, 105, 44, 50, 46, 90, 72, 14, 14, 7, 88, 142, 27, 50, 32, 28, 15, 136, 9, 112, 27, 141, 25, 108, 19, 121, 64, 72, 74, 132, 80, 3, 21, 19, 64, 2, 84, 150, 71, 133, 87, 130, 72, 66, 46, 38, 83, 63, 80, 159, 84, 155, 68, 25, 71, 55, 48, 70, 2, 67, 4, 48, 71, 41, 43, 56, 85, 24, 74, 108, 74, 92, 86, 144, 77, 77, 54, 25, 37, 76, 0, 63, 2, 37, 53, 52, 35, 129, 71, 60, 26, 74, 18, 126, 84, 44, 51, 117, 2, 80, 17, 97, 88, 135, 45, 102, 74, 88, 76, 52, 16, 85, 33, 136, 26, 150, 73, 11, 44, 3, 0, 153, 37, 55, 25, 105, 45, 87, 8, 10, 14, 58, 11, 47, 86, 114, 27, 146, 1, 59, 77, 66, 83, 92, 2, 22, 26, 81, 48, 117, 72, 19, 89, 42, 5, 7, 27, 125, 32, 17, 85, 39, 53, 83, 70, 86, 46, 45, 6, 140, 40, 65, 31, 139, 30, 105, 37, 73, 76, 147, 8, 31, 9, 91, 14, 93, 24, 81, 21, 131, 18, 44, 59, 95, 78, 2, 49, 142, 1, 119, 30, 43, 72, 71, 42, 124, 81, 113, 89, 99, 38, 74, 63, 45, 23, 32, 74, 81, 83, 135, 59, 56, 35, 71, 79, 101, 42, 141, 64, 106, 39, 95, 37, 18, 0, 59, 33, 16, 57, 2, 2, 63, 23, 130, 46, 141, 23, 54, 3, 96, 18, 112, 29, 52, 13, 5, 33, 0, 52, 132, 15, 102, 14, 128, 12, 60, 79, 55, 38, 147, 1, 9, 50, 112, 33, 0, 29, 132, 57, 120, 22, 24, 24, 3, 49, 136, 74, 88, 6, 116, 11, 104, 21, 100, 20, 138, 54, 45, 1, 131, 12, 150, 81, 7, 48, 84, 32, 19, 12, 54, 39, 131, 74, 48, 3, 148, 71, 1, 24, 18, 58, 157, 44, 20, 35, 4, 65, 128, 24, 5, 59, 119, 36, 129, 64, 121, 69, 99, 7, 26, 30, 4, 53, 133, 44, 40, 41, 67, 18, 34, 54, 123, 2, 65, 23, 82, 12, 48, 40, 17, 9, 88, 59, 90, 23, 109, 28, 140, 55, 14, 67, 124, 31, 154, 24, 64, 37, 144, 13, 71, 30, 7, 36, 38, 81, 44, 37, 74, 77, 60, 2, 84, 63, 99, 48, 154, 20, 91, 17, 94, 59, 78, 66, 108, 4, 127, 14, 32, 58, 118, 70, 129, 19, 149, 60, 115, 39, 103, 24, 118, 3, 48, 74, 145, 70, 130, 52, 31, 88, 135, 22, 158, 72, 144, 9, 79, 12, 144, 78, 78, 31, 69, 6, 58, 61, 152, 16, 43, 18, 40, 20, 93, 18, 101, 10, 157, 4, 13, 19, 114, 7, 106, 15, 85, 43, 74, 0, 47, 11, 46, 43, 37, 31, 120, 7, 48, 41, 18, 16, 36, 69, 59, 56, 77, 34, 156, 74, 151, 68, 5, 47, 152, 56, 154, 75, 15, 76, 72, 35, 85, 63, 27, 50, 88, 83, 106, 76, 66, 76, 148, 54, 95, 39, 116, 87, 71, 24, 46, 81, 41, 83, 114, 14, 148, 27, 159, 87, 82, 14, 60, 73, 71, 33, 34, 16, 105, 58, 8, 71, 111, 4, 33, 84, 76, 55, 98, 16, 33, 33, 135, 85, 28, 44, 89, 23, 1, 59, 54, 25, 67, 67, 23, 86, 101, 55, 131, 39, 104, 40, 56, 66, 87, 65, 36, 71, 103, 29, 13, 80, 152, 65, 27, 65, 58, 79, 105, 67, 87, 82, 157, 49, 119, 84, 15, 59, 5, 13, 31, 87, 79, 20, 118, 88, 53, 27, 78, 52, 82, 1, 154, 4, 79, 42, 12, 15, 39, 52, 54, 51, 15, 61, 10, 31, 54, 56, 134, 80, 138, 4, 112, 45, 5, 71, 107, 69, 33, 87, 134, 13, 119, 74, 26, 67, 73, 72, 122, 36, 20, 41, 5, 1, 41, 0, 17, 43, 120, 50, 143, 5, 87, 2, 159, 54, 4, 67, 75, 24, 113, 25, 60, 69, 55, 79, 71, 46, 54, 6, 109, 54, 45, 82, 139, 55, 57, 29, 75, 35, 80, 38, 49, 42, 39, 0, 53, 2, 104, 52, 41, 47, 143, 85, 147, 4, 46, 10, 143, 4, 68, 50, 107, 45, 149, 46, 28, 58, 61, 34, 129, 66, 158, 51, 63, 14, 75, 23, 122, 89, 73, 16, 49, 81, 58, 88, 141, 1, 63, 56, 150, 11, 69, 67, 77, 28, 43, 14, 25, 57, 73, 11, 81, 75, 61, 39, 8, 25, 72, 81, 57, 72, 33, 29, 140, 38, 17, 80, 135, 80, 138, 12, 40, 45, 135, 16, 51, 17, 74, 8, 110, 75, 80, 88, 108, 66, 60, 74, 116, 13, 121, 43, 8, 59, 158, 33, 39, 61, 32, 50, 108, 69, 115, 51, 45, 83, 80, 74, 57, 0, 64, 31, 76, 39, 39, 59, 12, 42, 95, 85, 35, 30, 154, 72, 68, 36, 99, 28, 103, 33, 147, 16, 84, 16, 123, 43, 40, 81, 34, 81, 64, 42, 74, 5, 154, 89, 126, 4, 147, 13, 35, 62, 134, 57, 127, 3, 25, 61, 35, 13, 120, 81, 20, 3, 83, 69, 104, 13, 31, 7, 132, 81, 104, 67, 144, 72, 99, 67, 121, 84, 57, 62, 138, 51, 131, 8, 122, 72, 74, 83, 140, 31, 102, 68, 29, 60, 153, 60, 76, 89, 71, 85, 27, 52, 92, 73, 95, 23, 156, 24, 104, 70, 124, 14, 9, 24, 42, 49, 109, 40, 91, 44, 101, 26, 78, 20, 90, 61, 65, 49, 155, 63, 133, 4, 71, 12, 136, 45, 65, 77, 56, 53, 67, 14, 95, 53, 33, 12, 138, 66, 114, 77, 26, 47, 9, 66, 157, 30, 128, 77, 139, 33, 27, 24, 59, 78, 84, 33, 33, 24, 46, 38, 122, 79, 98, 33, 107, 60, 91, 34, 104, 43, 154, 50, 79, 71, 69, 40, 88, 88, 103, 56, 36, 56, 46, 85, 139, 24, 98, 21, 0, 53, 153, 28, 42, 24, 40, 31, 129, 54, 93, 33, 37, 48, 129, 21, 45, 4, 151, 27, 145, 84, 115, 52, 57, 68, 34, 64, 89, 67, 26, 88, 76, 6, 7, 59, 39, 42, 80, 31, 50, 67, 147, 37, 31, 79, 21, 43, 15, 41, 47, 77, 113, 70, 39, 24, 62, 23, 36, 21, 32, 47, 153, 9, 19, 84, 78, 8, 34, 8, 108, 88, 2, 89, 107, 26, 39, 54, 16, 70, 107, 37, 3, 11, 54, 72, 39, 66, 26, 68, 95, 56, 142, 68, 88, 21, 20, 30, 117, 60, 40, 84, 86, 59, 83, 71, 124, 40, 3, 50, 128, 82, 114, 79, 159, 56, 136, 61, 58, 10, 104, 47, 155, 40, 20, 65, 143, 23, 106, 21, 36, 34, 14, 50, 66, 62, 34, 15, 11, 32, 98, 84, 10, 77, 75, 25, 150, 30, 99, 26, 2, 32, 116, 66, 106, 27, 101, 6, 25, 0, 61, 32, 136, 68, 48, 25, 19, 25, 10, 3, 156, 21, 85, 73, 21, 10, 116, 18, 63, 73, 50, 81, 138, 46, 109, 65, 54, 40, 87, 31, 108, 9, 13, 50, 80, 83, 9, 58, 140, 79, 115, 32, 14, 19, 42, 64, 58, 39, 153, 58, 123, 63, 86, 3, 53, 22, 111, 21, 103, 35, 110, 86, 114, 25, 143, 36, 56, 26, 31, 29, 127, 27, 113, 22, 132, 14, 88, 7, 126, 78, 89, 29, 76, 78, 92, 72, 49, 38, 34, 36, 77, 86, 65, 22, 53, 87, 100, 34, 143, 11, 123, 16, 158, 73, 59, 18, 121, 4, 94, 41, 21, 32, 18, 23, 47, 35, 69, 50, 119, 79, 34, 20, 12, 16, 16, 60, 56, 84, 69, 4, 23, 79, 145, 52, 153, 85, 149, 19, 50, 9, 4, 50, 85, 4, 48, 20, 57, 9, 114, 11, 43, 4, 31, 78, 57, 18, 87, 3, 62, 29, 13, 77, 15, 12, 92, 50, 145, 50, 101, 74, 103, 17, 110, 37, 54, 73, 105, 49, 93, 71, 60, 20, 140, 82, 133, 28, 156, 3, 146, 89, 72, 0, 9, 85, 28, 18, 95, 51, 32, 33, 47, 18, 9, 75, 68, 71, 86, 2, 123, 7, 99, 0, 137, 40, 23, 20, 155, 15, 34, 83, 82, 51, 125, 62, 93, 35, 150, 10, 23, 27, 43, 73, 5, 29, 18, 42, 89, 31, 31, 82, 9, 34, 156, 54, 148, 30, 72, 37, 124, 79, 41, 46, 34, 9, 141, 80, 1, 80, 158, 61, 30, 29, 118, 61, 51, 24, 128, 86, 151, 78, 126, 12, 110, 63, 54, 27, 133, 21, 64, 71, 85, 7, 102, 21, 135, 21, 119, 22, 122, 24, 57, 86, 75, 61, 138, 78, 138, 22, 150, 19, 131, 37, 121, 32, 134, 0, 24, 22, 84, 48, 70, 5, 91, 30, 28, 6, 51, 83, 157, 6, 108, 8, 93, 10, 119, 64, 63, 13, 3, 2, 54, 13, 71, 74, 118, 29, 68, 38, 109, 37, 140, 32, 115, 57, 84, 68, 118, 53, 121, 1, 130, 70, 151, 1, 144, 48, 72, 50, 55, 80, 20, 48, 59, 43, 4, 17, 107, 71, 3, 44, 138, 5, 75, 12, 129, 80, 72, 51, 71, 3, 4, 8, 33, 5, 43, 8, 86, 64, 123, 20, 14, 33, 49, 27, 55, 52, 157, 5, 3, 9, 158, 22, 118, 59, 111, 51, 126, 10, 147, 30, 34, 53, 59, 40, 59, 21, 117, 1, 98, 62, 117, 9, 27, 68, 65, 21, 103, 30, 24, 53, 88, 84, 33, 58, 154, 83, 117, 52, 108, 59, 33, 47, 12, 66, 101, 9, 150, 58, 137, 3, 86, 10, 80, 77, 140, 33, 154, 66, 142, 18, 108, 80, 89, 4, 29, 74, 92, 17, 2, 25, 69, 37, 3, 15, 131, 82, 7, 13, 56, 77, 68, 5, 2, 61, 146, 62, 26, 36, 148, 4, 11, 11, 56, 8, 14, 66, 10, 72, 141, 71, 132, 67, 97, 37, 71, 37, 91, 51, 59, 70, 32, 7, 64, 34, 89, 70, 106, 13, 131, 75, 79, 60, 48, 62, 71, 52, 50, 15, 121, 61, 1, 50, 11, 38, 98, 3, 90, 74, 106, 14, 152, 86, 127, 75, 79, 18, 47, 49, 144, 54, 142, 21, 5, 23, 141, 81, 16, 62, 51, 39, 144, 70, 101, 73, 24, 26, 40, 67, 140, 62, 47, 33, 22, 87, 36, 18, 57, 55, 62, 61, 88, 72, 121, 26, 98, 44, 131, 25, 139, 5, 44, 35, 57, 34, 5, 34, 86, 39, 40, 8, 148, 81, 21, 47, 75, 18, 6, 51, 81, 7, 81, 18, 45, 68, 129, 13, 116, 42, 82, 46, 112, 25, 82, 61, 38, 63, 54, 5, 33, 86, 131, 73, 52, 86, 24, 28, 150, 21, 123, 11, 59, 63, 91, 78, 108, 11, 71, 32, 134, 14, 64, 57, 80, 2, 118, 58, 114, 42, 82, 5, 133, 82, 31, 62, 1, 42, 21, 83, 65, 82, 152, 55, 54, 14, 157, 84, 88, 60, 124, 30, 93, 70, 41, 12, 23, 83, 12, 54, 157, 87, 17, 47, 44, 44, 40, 5, 42, 11, 155, 38, 1, 3, 118, 20, 41, 9, 103, 83, 135, 60, 83, 19, 102, 32, 123, 40, 141, 65, 81, 31, 148, 75, 155, 85, 135, 51, 118, 23, 7, 38, 98, 79, 10, 13, 74, 84, 87, 37, 35, 79, 145, 73, 96, 19, 2, 67, 132, 83, 42, 80, 74, 1, 45, 70, 107, 50, 66, 12, 87, 58, 54, 87, 2, 0, 121, 14, 108, 31, 106, 30, 8, 38, 129, 31, 152, 73, 115, 5, 148, 77, 9, 39, 101, 68, 81, 78, 118, 31, 10, 86, 41, 54, 115, 69, 53, 79, 29, 3, 15, 63, 147, 19, 54, 84, 86, 87, 148, 87, 77, 50, 42, 65, 68, 64, 66, 30, 115, 88, 48, 48, 16, 3, 148, 69, 61, 14, 45, 84, 35, 75, 107, 54, 138, 67, 113, 29, 45, 54, 80, 40, 20, 88, 57, 43, 29, 10, 150, 82, 16, 61, 13, 68, 74, 73, 69, 34, 70, 37, 25, 24, 141, 54, 151, 32, 14, 86, 140, 23, 69, 83, 152, 8, 92, 42, 154, 78, 149, 75, 55, 30, 72, 86, 155, 65, 66, 77, 45, 22, 15, 82, 5, 50, 2, 23, 19, 38, 103, 88, 52, 68, 37, 78, 111, 84, 85, 55, 106, 18, 19, 0, 33, 14, 61, 75, 84, 1, 77, 13, 81, 26, 67, 51, 157, 81, 53, 71, 98, 82, 18, 74, 39, 87, 92, 9, 18, 41, 67, 40, 137, 71, 113, 40, 48, 58, 106, 33, 145, 86, 159, 5, 109, 23, 89, 57, 96, 30, 6, 79, 117, 88, 84, 69, 14, 42, 111, 44, 126, 62, 99, 86, 16, 36, 21, 18, 127, 85, 89, 7, 12, 3, 132, 51, 52, 44, 40, 43, 114, 67, 104, 1, 40, 74, 139, 60, 129, 15, 100, 3, 136, 59, 55, 43, 96, 46, 33, 70, 122, 67, 114, 69, 7, 54, 61, 52, 54, 0, 19, 4, 95, 15, 156, 14, 44, 39, 57, 21, 144, 38, 137, 11, 150, 61, 20, 83, 95, 0, 36, 1, 117, 16, 24, 49, 68, 62, 57, 42, 28, 30, 159, 83, 107, 49, 45, 11, 55, 78, 12, 30, 45, 76, 39, 22, 159, 58, 48, 82, 18, 31, 50, 89, 87, 9, 128, 27, 64, 18, 59, 71, 24, 57, 2, 57, 107, 52, 118, 79, 35, 21, 103, 67, 37, 10, 38, 41, 152, 35, 84, 23, 67, 38, 31, 52, 104, 26, 128, 52, 142, 89, 11, 21, 41, 20, 33, 26, 1, 66, 3, 72, 107, 74, 27, 56, 30, 70, 19, 27, 97, 61, 127, 60, 110, 52, 131, 68, 27, 51, 63, 86, 39, 85, 5, 60, 141, 84, 37, 23, 63, 49, 77, 51, 29, 28, 69, 57, 56, 34, 50, 21, 36, 31, 24, 2, 11, 13, 0, 16, 10, 47, 125, 79, 47, 23, 39, 51, 126, 36, 93, 8, 133, 85, 8, 31, 111, 85, 152, 41, 128, 29, 6, 87, 105, 26, 72, 60, 43, 37, 139, 0, 85, 72, 19, 55, 85, 21, 141, 75, 98, 59, 111, 82, 34, 85, 48, 76, 92, 53, 86, 17, 85, 31, 22, 33, 47, 51, 7, 84, 61, 88, 88, 70, 79, 44, 22, 68, 124, 85, 150, 64, 138, 69, 125, 20, 129, 4, 74, 89, 147, 9, 138, 44, 7, 75, 108, 62, 59, 89, 143, 33, 73, 84, 52, 67, 28, 40, 77, 74, 67, 12, 78, 61, 72, 29, 73, 47, 52, 28, 130, 76, 109, 80, 44, 49, 76, 35, 9, 80, 79, 29, 129, 9, 136, 82, 44, 52, 62, 12, 132, 40, 20, 46, 139, 74, 32, 55, 50, 13, 67, 39, 143, 27, 73, 81, 125, 50, 8, 10, 133, 83, 141, 56, 137, 80, 113, 43, 148, 7, 95, 89, 132, 33, 135, 82, 140, 45, 24, 19, 70, 80, 80, 85, 147, 38, 105, 72, 63, 43, 72, 84, 105, 86, 89, 14, 110, 0, 119, 12, 21, 23, 8, 61, 114, 63, 72, 83, 82, 65, 52, 41, 90, 88, 73, 40, 40, 16, 35, 22, 41, 38, 84, 10, 32, 49, 121, 3, 82, 87, 105, 52, 126, 73, 94, 69, 21, 29, 120, 11, 137, 86, 44, 65, 159, 21, 11, 57, 147, 46, 26, 43, 27, 9, 105, 80, 50, 63, 121, 11, 69, 48, 73, 89, 78, 67, 14, 75, 43, 9, 46, 77, 115, 17, 103, 82, 125, 64, 96, 59, 120, 39, 121, 7, 39, 62, 102, 85, 150, 66, 114, 23, 142, 71, 12, 44, 30, 38, 24, 67, 115, 27, 7, 15, 102, 27, 107, 64, 23, 23, 55, 83, 116, 69, 156, 63, 85, 16, 145, 42, 1, 33, 54, 35, 136, 60, 50, 82, 150, 25, 152, 2, 140, 22, 56, 80, 82, 39, 104, 54, 95, 17, 64, 79, 46, 25, 19, 49, 87, 57, 128, 49, 63, 6, 65, 59, 40, 61, 25, 84, 120, 67, 135, 28, 83, 12, 106, 69, 122, 54, 83, 47, 138, 24, 109, 58, 120, 73, 90, 22, 119, 60, 59, 3, 93, 5, 119, 42, 108, 29, 61, 31, 123, 24, 57, 64, 9, 79, 88, 86, 97, 33, 61, 42, 157, 45, 82, 27, 27, 22, 73, 0, 122, 55, 38, 61, 47, 42, 22, 81, 41, 40, 83, 43, 66, 21, 152, 43, 9, 2, 81, 45, 153, 49, 105, 79, 92, 52, 94, 11, 140, 44, 109, 53, 121, 15, 69, 3, 134, 85, 84, 28, 23, 85, 46, 20, 60, 27, 127, 10, 48, 0, 121, 89, 134, 36, 146, 13, 38, 68, 98, 9, 72, 3, 86, 53, 68, 35, 122, 52, 0, 67, 146, 74, 31, 61, 127, 9, 35, 54, 54, 48, 24, 52, 115, 34, 32, 76, 114, 89, 59, 8, 72, 65, 61, 45, 52, 58, 10, 70, 47, 68, 79, 63, 73, 83, 134, 69, 23, 87, 51, 84, 23, 32, 33, 65, 126, 23, 53, 85, 45, 85, 55, 82, 131, 72, 129, 33, 148, 13, 96, 11, 62, 22, 76, 56, 25, 25, 131, 56, 152, 23, 152, 46, 9, 7, 64, 73, 31, 28, 55, 69, 10, 81, 126, 15, 114, 51, 39, 76, 66, 8, 1, 23, 95, 3, 127, 72, 47, 59, 104, 8, 81, 54, 6, 34, 38, 22, 132, 70, 117, 22, 103, 73, 44, 64, 128, 48, 73, 29, 82, 85, 135, 1, 40, 23, 131, 69, 112, 63, 137, 51, 61, 66, 2, 85, 117, 29, 85, 75, 52, 1, 23, 53, 158, 74, 98, 69, 114, 17, 154, 32, 31, 36, 25, 14, 10, 38, 124, 65, 82, 7, 53, 52, 83, 32, 13, 58, 37, 88, 63, 48, 37, 3, 106, 79, 0, 27, 159, 79, 16, 34, 99, 25, 94, 23, 7, 2, 4, 83, 107, 24, 146, 15, 59, 6, 6, 14, 77, 55, 103, 57, 2, 78, 101, 33, 46, 45, 51, 59, 21, 0, 62, 0, 18, 51, 6, 24, 8, 36, 51, 51, 48, 47, 111, 12, 29, 16, 120, 57, 112, 68, 78, 74, 65, 51, 50, 86, 155, 78, 152, 77, 2, 8, 133, 53, 96, 5, 46, 86, 33, 21, 110, 77, 23, 61, 98, 35, 101, 75, 139, 9, 43, 20, 26, 66, 124, 3, 148, 58, 105, 20, 60, 8, 136, 38, 154, 31, 110, 38, 53, 18, 48, 87, 6, 57, 156, 26, 38, 56, 113, 27, 130, 31, 74, 10, 69, 58, 28, 45, 29, 83, 25, 88, 45, 43, 77, 64, 125, 43, 77, 1, 60, 24, 73, 78, 109, 47, 66, 75, 62, 39, 155, 49, 137, 64, 59, 14, 89, 46, 113, 78, 110, 39, 66, 66, 92, 63, 103, 89, 79, 82, 96, 65, 136, 22, 36, 33, 96, 57, 39, 64, 117, 12, 99, 79, 27, 30, 31, 65, 157, 66, 0, 30, 38, 3, 39, 50, 123, 88, 71, 48, 104, 88, 94, 22, 55, 0, 34, 51, 49, 0, 38, 64, 28, 34, 112, 66, 34, 74, 137, 36, 22, 3, 7, 79, 90, 20, 66, 40, 3, 26, 100, 17, 127, 6, 11, 58, 117, 62, 79, 74, 67, 44, 122, 56, 82, 19, 6, 25, 116, 63, 68, 55, 35, 15, 101, 49, 130, 9, 108, 50, 140, 70, 27, 19, 103, 81, 0, 13, 117, 23, 97, 56, 68, 58, 52, 78, 35, 12, 134, 84, 71, 35, 71, 27, 59, 57, 81, 66, 30, 56, 108, 71, 127, 78, 109, 35, 153, 14, 13, 83, 55, 58, 24, 18, 51, 31, 128, 46, 137, 5, 115, 25, 115, 45, 57, 33, 135, 70, 114, 38, 122, 76, 85, 32, 112, 14, 17, 21, 152, 4, 67, 13, 89, 22, 15, 50, 114, 47, 144, 68, 61, 64, 58, 73, 75, 55, 150, 47, 99, 31, 50, 60, 12, 64, 29, 57, 148, 6, 112, 10, 10, 0, 149, 58, 159, 26, 46, 71, 84, 52, 21, 36, 82, 63, 99, 39, 4, 14, 147, 20, 139, 7, 78, 13, 2, 50, 41, 19, 100, 78, 32, 80, 78, 43, 45, 44, 21, 3, 86, 81, 95, 5, 138, 58, 87, 20, 32, 53, 109, 33, 158, 65, 146, 47, 1, 48, 148, 80, 141, 18, 6, 76, 36, 78, 48, 46, 156, 75, 158, 28, 31, 86, 91, 80, 46, 41, 130, 8, 150, 27, 106, 12, 132, 78, 158, 47, 118, 75, 53, 40, 7, 14, 15, 84, 118, 41, 151, 19, 126, 66, 87, 38, 113, 6, 126, 20, 13, 47, 147, 14, 68, 63, 6, 47, 113, 37, 68, 29, 91, 0, 90, 37, 45, 77, 122, 70, 105, 8, 61, 57, 112, 42, 56, 71, 46, 88, 134, 59, 94, 70, 103, 4, 18, 45, 32, 30, 107, 28, 141, 6, 49, 72, 158, 15, 32, 71, 102, 38, 49, 28, 113, 50, 26, 55, 11, 20, 71, 2, 31, 8, 2, 56, 88, 38, 114, 37, 20, 64, 5, 20, 69, 33, 122, 84, 111, 76, 57, 16, 87, 44, 12, 24, 81, 38, 78, 3, 144, 75, 149, 28, 23, 41, 100, 76, 54, 10, 14, 73, 136, 78, 134, 28, 54, 24, 71, 88, 77, 62, 19, 3, 5, 63, 40, 68, 108, 57, 96, 63, 158, 24, 146, 34, 130, 77, 60, 13, 118, 2, 54, 86, 86, 84, 159, 8, 128, 55, 37, 34, 114, 34, 28, 55, 157, 28, 148, 62, 90, 69, 33, 76, 29, 23, 126, 52, 82, 80, 15, 73, 6, 64, 90, 43, 105, 21, 12, 63, 142, 23, 83, 38, 34, 12, 75, 79, 85, 42, 134, 33, 58, 26, 68, 17, 65, 33, 71, 75, 83, 4, 135, 58, 129, 39, 4, 74, 30, 16, 81, 61, 88, 69, 125, 11, 88, 71, 13, 3, 119, 45, 50, 8, 68, 81, 50, 76, 59, 2, 20, 25, 156, 43, 141, 42, 12, 60, 45, 5, 75, 26, 96, 76, 53, 10, 50, 6, 112, 34, 38, 37, 93, 74, 48, 30, 61, 26, 21, 45, 62, 72, 122, 57, 4, 20, 76, 14, 13, 53, 53, 51, 45, 12, 15, 15, 139, 40, 86, 89, 58, 53, 0, 47, 22, 52, 101, 51, 151, 69, 128, 73, 135, 86, 21, 87, 23, 19, 104, 65, 120, 16, 40, 44, 66, 74, 151, 64, 19, 61, 113, 11, 127, 86, 29, 76, 23, 62, 99, 6, 104, 38, 58, 25, 97, 49, 131, 30, 92, 80, 1, 88, 62, 57, 104, 76, 95, 41, 72, 31, 100, 88, 135, 72, 91, 75, 52, 0, 44, 57, 74, 29, 121, 78, 156, 2, 130, 38, 44, 38, 61, 4, 75, 31, 146, 77, 8, 12, 120, 76, 75, 56, 36, 38, 28, 25, 83, 40, 40, 70, 116, 5, 127, 32, 109, 8, 15, 32, 48, 73, 87, 49, 67, 22, 18, 53, 39, 16, 79, 61, 144, 39, 24, 23, 64, 74, 63, 26, 52, 36, 68, 1, 158, 63, 48, 8, 124, 51, 70, 16, 81, 72, 87, 66, 75, 8, 7, 82, 151, 70, 100, 52, 136, 44, 63, 10, 118, 55, 71, 36, 141, 32, 44, 10, 117, 83, 117, 39, 115, 55, 137, 81, 115, 70, 147, 66, 142, 77, 147, 63, 2, 48, 101, 80, 7, 12, 156, 85, 122, 82, 58, 30, 87, 71, 124, 29, 106, 75, 99, 56, 2, 41, 104, 85, 36, 11, 90, 27, 120, 35, 7, 61, 128, 76, 8, 4, 66, 81, 80, 51, 148, 85, 38, 43, 154, 40, 19, 21, 130, 81, 118, 76, 102, 73, 108, 72, 76, 19, 79, 45, 123, 64, 105, 62, 9, 20, 65, 15, 95, 79, 151, 42, 130, 15, 74, 67, 63, 47, 83, 63, 140, 71, 147, 45, 88, 89, 12, 13, 159, 10, 42, 78, 1, 4, 110, 32, 123, 36, 51, 67, 35, 46, 87, 52, 104, 23, 45, 21, 137, 26, 19, 48, 134, 88, 84, 37, 114, 59, 82, 31, 148, 68, 130, 48, 56, 10, 74, 4, 30, 7, 15, 80, 156, 41, 56, 32, 0, 65, 99, 87, 119, 70, 75, 33, 0, 51, 139, 75, 159, 49, 125, 53, 12, 27, 90, 39, 75, 69, 127, 8, 22, 12, 77, 81, 69, 39, 126, 58, 76, 37, 92, 32, 63, 16, 20, 21, 33, 38, 5, 73, 12, 23, 121, 37, 105, 14, 96, 58, 111, 3, 137, 75, 92, 74, 10, 66, 44, 85, 27, 63, 124, 71, 107, 44, 15, 74, 78, 80, 93, 6, 102, 76, 153, 11, 58, 3, 93, 62, 34, 86, 24, 76, 139, 21, 60, 67, 152, 32, 124, 88, 125, 78, 55, 73, 144, 74, 97, 63, 121, 65, 92, 37, 103, 65, 154, 55, 89, 37, 22, 49, 36, 30, 137, 14, 1, 7, 141, 9, 54, 89, 69, 54, 76, 34, 30, 26, 150, 52, 47, 29, 53, 25, 10, 54, 129, 83, 44, 82, 124, 2, 40, 52, 153, 44, 121, 17, 143, 70, 129, 59, 133, 73, 37, 76, 121, 22, 33, 78, 83, 29, 119, 39, 142, 17, 123, 1, 124, 78, 81, 3, 87, 62, 79, 55, 50, 68, 20, 12, 5, 87, 23, 28, 27, 15, 37, 49, 1, 40, 106, 62, 71, 40, 18, 78, 83, 11, 105, 64, 101, 7, 132, 39, 6, 40, 114, 64, 67, 30, 63, 3, 120, 38, 3, 80, 111, 1, 45, 73, 124, 58, 64, 32, 148, 32, 118, 27, 52, 33, 3, 48, 25, 50, 96, 54, 46, 58, 19, 50, 66, 32, 2, 29, 147, 23, 84, 29, 21, 7, 33, 81, 60, 23, 153, 2, 27, 8, 63, 53, 67, 61, 22, 51, 153, 7, 28, 3, 103, 64, 150, 72, 90, 46, 31, 75, 19, 35, 60, 80, 109, 87, 12, 87, 148, 5, 16, 89, 13, 86, 53, 9, 46, 70, 134, 68, 1, 27, 72, 17, 102, 52, 32, 88, 136, 50, 77, 10, 96, 40, 124, 74, 103, 72, 104, 83, 117, 13, 119, 73, 129, 0, 42, 67, 136, 13, 29, 48, 25, 60, 4, 48, 148, 72, 85, 44, 146, 81, 130, 13, 38, 33, 82, 15, 88, 54, 74, 7, 46, 1, 114, 33, 94, 83, 13, 30, 158, 1, 34, 32, 157, 34, 2, 58, 37, 87, 24, 10, 79, 15, 148, 18, 1, 8, 129, 46, 73, 39, 118, 10, 10, 25, 88, 14, 123, 68, 85, 14, 147, 47, 68, 51, 126, 41, 158, 31, 118, 19, 57, 27, 88, 16, 87, 55, 72, 75, 58, 56, 108, 89, 125, 15, 44, 8, 44, 71, 54, 71, 80, 57, 10, 4, 49, 48, 14, 81, 130, 28, 152, 68, 70, 51, 104, 11, 6, 66, 129, 52, 97, 60, 154, 30, 62, 83, 84, 4, 66, 31, 155, 84, 11, 71, 8, 33, 67, 58, 31, 59, 99, 14, 139, 49, 73, 55, 145, 66, 117, 26, 18, 76, 115, 65, 95, 52, 71, 83, 81, 33, 54, 1, 61, 81, 36, 48, 129, 11, 6, 18, 134, 19, 8, 13, 24, 34, 135, 75, 158, 75, 24, 1, 117, 49, 141, 43, 150, 51, 68, 74, 58, 18, 24, 59, 41, 61, 81, 44, 8, 83, 76, 86, 8, 74, 27, 80, 75, 14, 13, 41, 137, 49, 123, 86, 39, 4, 64, 0, 140, 78, 20, 78, 72, 5, 38, 87, 41, 15, 4, 24, 71, 50, 98, 12, 22, 50, 12, 82, 57, 79, 37, 77, 143, 31, 93, 4, 57, 35, 132, 59, 145, 69, 10, 15, 83, 28, 95, 7, 139, 44, 58, 28, 27, 26, 74, 12, 97, 80, 136, 47, 94, 60, 89, 48, 68, 37, 80, 65, 99, 49, 148, 42, 76, 63, 109, 19, 126, 77, 159, 14, 12, 21, 135, 71, 99, 60, 74, 3, 84, 45, 83, 54, 128, 8, 101, 88, 107, 47, 106, 66, 3, 67, 33, 2, 27, 86, 90, 52, 61, 79, 8, 75, 15, 86, 32, 70, 140, 9, 43, 32, 142, 60, 127, 69, 7, 76, 103, 87, 49, 9, 34, 88, 127, 57, 4, 88, 82, 59, 51, 7, 78, 1, 142, 65, 117, 28, 38, 57, 110, 64, 107, 21, 142, 14, 33, 40, 106, 1, 30, 60, 26, 34, 16, 18, 69, 44, 11, 16, 22, 57, 58, 41, 145, 6, 9, 76, 90, 36, 58, 21, 33, 53, 67, 74, 91, 89, 14, 26, 94, 44, 146, 2, 14, 53, 29, 67, 55, 11, 13, 36, 6, 75, 11, 29, 22, 48, 144, 8, 48, 14, 116, 24, 85, 87, 74, 15, 107, 23, 39, 6, 21, 73, 65, 0, 90, 64, 47, 46, 99, 63, 13, 10, 44, 87, 23, 29, 125, 6, 68, 53, 12, 49, 84, 65, 34, 21, 77, 69, 30, 78, 125, 28, 139, 18, 144, 60, 42, 68, 100, 8, 67, 70, 124, 17, 50, 72, 86, 23, 38, 72, 159, 60, 24, 73, 122, 2, 148, 60, 117, 71, 12, 83, 97, 53, 113, 3, 14, 60, 87, 67, 13, 15, 149, 20, 151, 15, 70, 20, 124, 36, 38, 47, 86, 52, 41, 5, 52, 88, 45, 32, 3, 74, 121, 9, 159, 63, 38, 18, 143, 32, 125, 10, 39, 17, 70, 59, 120, 5, 151, 31, 52, 51, 101, 20, 124, 18, 119, 14, 151, 75, 95, 30, 35, 40, 40, 47, 5, 49, 66, 64, 101, 32, 129, 24, 125, 75, 45, 35, 48, 31, 25, 75, 143, 37, 118, 9, 62, 50, 36, 39, 25, 55, 101, 16, 5, 9, 105, 27, 135, 83, 152, 72, 82, 74, 35, 86, 142, 70, 123, 33, 3, 18, 39, 2, 118, 35, 48, 19, 104, 57, 17, 40, 159, 86, 74, 40, 83, 2, 107, 77, 97, 38, 102, 70, 129, 26, 118, 42, 29, 1, 149, 26, 2, 36, 131, 29, 10, 18, 41, 71, 128, 70, 157, 48, 55, 72, 111, 70, 110, 50, 0, 14, 122, 64, 56, 39, 107, 16, 1, 32, 147, 85, 132, 8, 118, 71, 127, 46, 101, 60, 98, 5, 147, 2, 39, 19, 14, 58, 14, 82, 134, 30, 144, 26, 143, 22, 85, 46, 21, 17, 63, 89, 78, 83, 104, 39, 13, 84, 79, 53, 106, 47, 74, 69, 27, 87, 108, 33, 64, 8, 22, 83, 69, 26, 68, 61, 106, 82, 80, 84, 122, 37, 71, 61, 62, 31, 63, 66, 47, 45, 3, 34, 76, 8, 65, 73, 19, 6, 61, 77, 79, 4, 9, 56, 16, 79, 17, 84, 67, 5, 78, 82, 154, 1, 158, 69, 60, 5, 127, 7, 46, 84, 18, 80, 16, 46, 154, 77, 93, 72, 23, 17, 151, 0, 107, 29, 110, 8, 45, 60, 19, 68, 41, 10, 93, 88, 49, 60, 137, 73, 76, 85, 71, 87, 0, 57, 99, 8, 130, 22, 137, 15, 109, 67, 141, 82, 43, 56, 32, 43, 69, 11, 21, 76, 109, 18, 152, 51, 28, 85, 120, 79, 156, 40, 47, 75, 1, 10, 131, 1, 141, 72, 9, 3, 134, 67, 90, 15, 83, 0, 143, 30, 19, 86, 46, 63, 38, 82, 17, 32, 19, 71, 86, 4, 55, 1, 74, 70, 8, 50, 141, 66, 96, 13, 63, 8, 106, 28, 123, 26, 9, 8, 37, 18, 137, 6, 113, 64, 38, 9, 61, 78, 127, 30, 157, 7, 21, 53, 20, 33, 43, 88, 23, 22, 56, 24, 157, 76, 68, 7, 13, 75, 1, 70, 20, 70, 102, 24, 149, 55, 145, 87, 103, 27, 85, 45, 60, 22, 70, 35, 24, 80, 159, 72, 103, 13, 31, 83, 143, 17, 26, 32, 145, 51, 153, 5, 19, 88, 131, 53, 114, 1, 34, 23, 134, 70, 15, 40, 118, 85, 144, 4, 151, 30, 8, 81, 94, 1, 25, 80, 113, 65, 31, 35, 53, 84, 127, 56, 20, 19, 41, 16, 9, 87, 67, 56, 136, 58, 155, 34, 124, 6, 65, 8, 10, 61, 0, 24, 21, 52, 139, 86, 70, 81, 148, 36, 30, 48, 129, 43, 81, 28, 119, 72, 75, 74, 70, 52, 49, 46, 153, 55, 147, 6, 35, 34, 73, 53, 4, 52, 62, 60, 7, 49, 84, 81, 105, 60, 95, 84, 13, 28, 151, 62, 146, 30, 9, 77, 6, 12, 87, 13, 155, 74, 27, 21, 89, 53, 130, 0, 104, 16, 130, 41, 143, 76, 122, 0, 102, 89, 72, 77, 67, 82, 72, 11, 68, 9, 157, 82, 27, 47, 69, 1, 131, 83, 64, 29, 117, 56, 56, 57, 48, 57, 92, 8, 83, 16, 108, 77, 94, 43, 28, 2, 53, 16, 31, 4, 105, 50, 113, 20, 131, 20, 67, 9, 112, 9, 110, 62, 117, 55, 101, 65, 60, 29, 149, 81, 78, 17, 45, 56, 50, 71, 61, 68, 98, 1, 47, 31, 27, 23, 139, 8, 47, 55, 77, 79, 81, 64, 112, 8, 157, 63, 91, 47, 101, 45, 74, 74, 96, 70, 139, 83, 119, 52, 2, 63, 136, 51, 6, 16, 67, 20, 12, 17, 121, 44, 94, 33, 159, 51, 103, 45, 55, 22, 70, 50, 12, 81, 86, 40, 120, 68, 86, 51, 60, 76, 70, 85, 84, 59, 67, 80, 72, 39, 157, 40, 154, 5, 41, 60, 49, 39, 23, 44, 39, 21, 70, 62, 127, 53, 60, 55, 157, 79, 20, 14, 11, 75, 25, 70, 146, 67, 29, 31, 34, 19, 96, 15, 135, 33, 5, 77, 88, 85, 26, 54, 60, 84, 31, 60, 5, 81, 31, 48, 19, 24, 144, 32, 120, 70, 142, 45, 96, 50, 157, 51, 86, 24, 30, 77, 146, 56, 9, 68, 147, 0, 89, 18, 144, 89, 139, 61, 27, 88, 108, 83, 84, 27, 43, 29, 146, 24, 43, 85, 149, 32, 106, 63, 36, 35, 136, 3, 156, 7, 97, 2, 91, 18, 21, 46, 105, 82, 8, 15, 66, 86, 122, 39, 157, 53, 124, 55, 114, 12, 35, 42, 136, 10, 70, 57, 8, 34, 106, 51, 5, 57, 97, 21, 61, 85, 106, 32, 113, 52, 150, 28, 117, 54, 149, 12, 40, 17, 77, 80, 72, 57, 104, 34, 82, 75, 133, 8, 124, 45, 134, 32, 59, 5, 112, 20, 47, 87, 30, 10, 41, 55, 17, 10, 155, 69, 28, 60, 142, 54, 75, 67, 119, 20, 58, 66, 61, 47, 154, 36, 155, 62, 9, 17, 94, 42, 136, 12, 142, 42, 63, 88, 142, 47, 33, 54, 56, 28, 20, 59, 10, 8, 125, 29, 78, 77, 104, 36, 28, 41, 59, 29, 97, 46, 90, 28, 158, 77, 117, 77, 145, 64, 31, 70, 56, 47, 112, 73, 24, 86, 8, 32, 106, 55, 53, 33, 119, 33, 27, 20, 106, 41, 126, 54, 12, 9, 147, 60, 130, 45, 133, 79, 125, 47, 13, 69, 80, 46, 11, 9, 5, 74, 45, 39, 139, 79, 112, 62, 111, 25, 90, 83, 140, 36, 115, 60, 20, 87, 50, 56, 157, 2, 20, 23, 127, 88, 100, 87, 97, 12, 20, 52, 49, 23, 26, 51, 111, 14, 109, 61, 87, 74, 114, 44, 24, 0, 106, 0, 103, 25, 141, 0, 37, 66, 37, 39, 16, 19, 14, 4, 94, 13, 144, 7, 72, 14, 14, 12, 42, 15, 36, 65, 7, 8, 107, 38, 130, 51, 43, 58, 49, 26, 137, 47, 118, 15, 97, 74, 139, 28, 113, 63, 2, 17, 103, 80, 97, 27, 15, 35, 154, 33, 151, 86, 58, 60, 88, 11, 89, 85, 99, 18, 62, 51, 96, 78, 78, 36, 156, 84, 38, 10, 24, 87, 125, 16, 36, 61, 124, 64, 16, 28, 25, 34, 42, 50, 102, 20, 138, 75, 78, 81, 96, 32, 60, 16, 43, 76, 83, 24, 144, 53, 88, 4, 14, 8, 15, 64, 66, 23, 133, 14, 1, 1, 74, 41, 64, 41, 20, 63, 62, 49, 138, 1, 91, 64, 101, 57, 138, 87, 46, 26, 38, 53, 17, 1, 115, 42, 144, 14, 2, 39, 140, 87, 108, 27, 63, 21, 20, 0, 18, 20, 13, 8, 7, 83, 149, 27, 59, 4, 83, 64, 87, 42, 57, 15, 123, 51, 133, 5, 102, 33, 20, 68, 145, 18, 118, 8, 4, 84, 116, 80, 126, 81, 87, 23, 128, 45, 140, 7, 101, 24, 108, 78, 69, 60, 155, 46, 44, 9, 27, 34, 64, 51, 136, 35, 14, 2, 10, 40, 53, 23, 144, 10, 89, 77, 26, 5, 31, 23, 145, 75, 41, 42, 52, 30, 39, 41, 151, 46, 46, 19, 42, 19, 13, 56, 89, 83, 27, 48, 34, 49, 82, 28, 30, 25, 103, 68, 95, 40, 137, 85, 71, 25, 121, 53, 76, 70, 115, 30, 122, 59, 146, 23, 7, 71, 30, 18, 153, 41, 69, 81, 88, 5, 37, 24, 15, 14, 139, 48, 139, 81, 94, 9, 27, 67, 41, 79, 135, 40, 94, 58, 37, 64, 49, 43, 158, 11, 78, 71, 154, 81, 58, 68, 58, 57, 126, 0, 19, 26, 39, 14, 32, 78, 149, 9, 83, 14, 25, 87, 30, 89, 145, 41, 39, 27, 50, 11, 55, 77, 85, 5, 40, 42, 107, 61, 141, 19, 154, 17, 49, 2, 155, 11, 62, 1, 119, 6, 123, 41, 31, 10, 125, 74, 137, 55, 79, 22, 142, 34, 103, 3, 98, 32, 86, 26, 47, 6, 74, 14, 155, 32, 94, 15, 155, 41, 44, 73, 64, 49, 150, 18, 13, 63, 100, 47, 129, 87, 60, 4, 8, 51, 29, 40, 109, 12, 134, 74, 34, 89, 100, 27, 89, 16, 101, 28, 74, 17, 152, 78, 23, 77, 32, 19, 68, 21, 51, 65, 133, 68, 104, 74, 26, 39, 19, 60, 156, 55, 116, 23, 18, 24, 72, 2, 129, 88, 43, 19, 158, 36, 18, 77, 46, 9, 136, 76, 102, 63, 0, 56, 156, 4, 119, 3, 84, 82, 55, 19, 105, 56, 0, 35, 132, 29, 96, 33, 15, 87, 147, 89, 9, 12, 127, 31, 1, 52, 51, 30, 141, 16, 26, 23, 48, 49, 105, 68, 135, 5, 112, 81, 57, 26, 114, 70, 61, 37, 32, 36, 2, 53, 109, 20, 13, 59, 106, 38, 71, 43, 57, 80, 34, 5, 69, 49, 121, 50, 45, 45, 135, 35, 25, 48, 5, 83, 132, 13, 115, 10, 154, 11, 71, 55, 37, 57, 69, 46, 24, 89, 77, 4, 133, 40, 8, 73, 45, 50, 24, 42, 17, 42, 56, 87, 79, 50, 32, 68, 133, 86, 64, 47, 151, 85, 5, 26, 94, 37, 152, 39, 20, 54, 98, 42, 156, 64, 43, 81, 144, 3, 119, 76, 123, 74, 17, 87, 113, 80, 8, 8, 36, 46, 65, 41, 53, 42, 37, 16, 80, 59, 105, 73, 33, 82, 96, 14, 136, 39, 9, 82, 147, 62, 59, 46, 120, 9, 157, 67, 66, 26, 44, 2, 124, 12, 147, 76, 90, 65, 139, 71, 138, 15, 20, 47, 102, 37, 127, 4, 1, 69, 50, 37, 122, 9, 4, 28, 44, 69, 153, 88, 89, 19, 27, 78, 34, 55, 52, 83, 128, 40, 88, 17, 69, 88, 29, 50, 80, 78, 66, 84, 155, 70, 35, 1, 31, 30, 37, 15, 36, 89, 155, 56, 144, 0, 108, 64, 18, 1, 0, 86, 49, 63, 153, 52, 22, 60, 128, 80, 80, 39, 120, 80, 68, 32, 31, 66, 117, 82, 144, 52, 112, 19, 131, 5, 105, 84, 44, 29, 129, 1, 46, 42, 101, 72, 88, 51, 22, 4, 37, 0, 75, 15, 104, 69, 84, 66, 67, 34, 159, 38, 65, 40, 36, 28, 28, 76, 122, 18, 18, 39, 50, 84, 13, 79, 121, 59, 79, 34, 14, 49, 78, 40, 142, 11, 31, 63, 124, 53, 88, 45, 87, 22, 12, 71, 83, 46, 6, 13, 121, 45, 136, 2, 37, 70, 112, 57, 18, 18, 10, 5, 39, 43, 37, 60, 87, 11, 154, 61, 120, 53, 44, 63, 91, 68, 67, 15, 12, 53, 10, 52, 139, 17, 121, 74, 153, 46, 11, 81, 81, 69, 26, 79, 64, 23, 3, 5, 106, 11, 144, 69, 91, 41, 128, 65, 53, 14, 10, 29, 110, 60, 37, 59, 104, 45, 83, 23, 28, 8, 34, 59, 92, 7, 119, 10, 105, 6, 27, 62, 108, 18, 102, 51, 149, 66, 5, 67, 37, 21, 25, 28, 148, 35, 155, 67, 68, 49, 36, 87, 76, 33, 132, 55, 125, 51, 21, 6, 80, 36, 72, 46, 1, 85, 18, 13, 21, 24, 61, 67, 67, 47, 119, 78, 30, 44, 98, 50, 7, 51, 123, 57, 53, 80, 91, 5, 107, 8, 29, 35, 57, 53, 133, 6, 49, 57, 100, 13, 64, 38, 32, 6, 19, 13, 156, 81, 136, 17, 77, 71, 57, 54, 0, 22, 69, 25, 90, 10, 130, 60, 122, 61, 59, 52, 134, 61, 141, 67, 24, 35, 127, 11, 115, 74, 14, 74, 135, 50, 139, 32, 39, 28, 81, 23, 109, 14, 97, 41, 5, 40, 93, 59, 40, 49, 23, 31, 157, 20, 102, 26, 59, 76, 34, 40, 143, 14, 130, 6, 74, 22, 3, 37, 60, 31, 97, 28, 104, 33, 70, 15, 51, 57, 70, 74, 150, 75, 146, 50, 109, 83, 105, 88, 100, 72, 44, 28, 49, 5, 132, 86, 25, 72, 11, 24, 30, 24, 136, 36, 27, 53, 93, 55, 6, 63, 58, 37, 5, 61, 101, 61, 30, 86, 118, 82, 114, 29, 102, 61, 40, 18, 65, 61, 52, 69, 17, 70, 134, 17, 110, 89, 152, 17, 26, 19, 121, 36, 138, 89, 136, 32, 42, 46, 58, 64, 112, 11, 140, 85, 59, 9, 121, 18, 108, 38, 39, 86, 29, 89, 12, 33, 7, 23, 64, 30, 120, 88, 67, 50, 131, 43, 117, 81, 99, 88, 85, 24, 103, 86, 80, 25, 53, 39, 101, 81, 109, 85, 85, 17, 64, 68, 159, 80, 29, 62, 130, 14, 0, 32, 16, 10, 74, 20, 75, 16, 155, 17, 100, 10, 0, 62, 109, 48, 104, 48, 19, 10, 30, 84, 146, 41, 148, 67, 5, 7, 156, 8, 128, 62, 16, 27, 0, 43, 87, 48, 66, 79, 21, 56, 145, 58, 22, 37, 151, 77, 120, 60, 23, 1, 46, 68, 50, 57, 104, 44, 90, 34, 19, 66, 140, 46, 11, 40, 147, 41, 137, 59, 21, 80, 66, 24, 28, 17, 119, 0, 91, 87, 49, 34, 23, 82, 5, 21, 59, 88, 93, 39, 142, 55, 52, 63, 107, 36, 113, 71, 90, 14, 139, 6, 72, 49, 70, 69, 154, 52, 48, 84, 11, 72, 27, 14, 69, 80, 109, 55, 48, 72, 94, 31, 87, 59, 91, 23, 86, 76, 67, 52, 47, 57, 129, 50, 55, 7, 60, 82, 121, 56, 49, 71, 57, 85, 90, 6, 117, 31, 6, 46, 76, 13, 138, 32, 52, 43, 68, 41, 109, 21, 60, 43, 19, 5, 24, 31, 146, 11, 56, 4, 96, 42, 120, 8, 64, 88, 7, 81, 58, 46, 145, 68, 153, 8, 147, 59, 5, 84, 139, 82, 67, 33, 28, 38, 19, 11, 139, 77, 11, 79, 159, 2, 118, 74, 23, 88, 83, 15, 132, 58, 78, 85, 17, 71, 80, 33, 112, 35, 30, 45, 48, 50, 94, 10, 28, 52, 138, 34, 63, 29, 31, 81, 58, 58, 85, 34, 96, 22, 98, 23, 78, 27, 59, 50, 132, 0, 127, 41, 19, 31, 98, 28, 142, 80, 22, 25, 92, 69, 141, 12, 146, 59, 85, 39, 70, 55, 28, 14, 149, 54, 13, 57, 32, 14, 86, 57, 86, 42, 97, 29, 100, 24, 58, 87, 30, 3, 110, 73, 15, 56, 79, 43, 78, 79, 2, 30, 26, 52, 84, 34, 69, 42, 25, 20, 90, 41, 104, 64, 148, 43, 109, 81, 51, 64, 84, 84, 96, 20, 58, 62, 156, 10, 72, 48, 117, 45, 74, 52, 25, 73, 8, 2, 145, 10, 91, 61, 149, 0, 155, 61, 5, 8, 138, 35, 25, 59, 156, 39, 42, 74, 8, 86, 61, 2, 138, 31, 9, 69, 114, 84, 121, 51, 22, 17, 47, 16, 109, 77, 90, 12, 107, 82, 8, 47, 102, 87, 155, 76, 117, 58, 112, 44, 123, 87, 66, 6, 27, 49, 156, 22, 55, 8, 91, 58, 89, 42, 33, 37, 93, 56, 1, 17, 64, 54, 141, 30, 9, 61, 54, 76, 57, 49, 110, 15, 3, 76, 108, 58, 31, 25, 127, 38, 77, 75, 110, 24, 93, 31, 56, 36, 28, 43, 59, 26, 2, 28, 81, 29, 117, 87, 159, 74, 42, 76, 58, 2, 115, 2, 154, 74, 143, 72, 149, 84, 61, 0, 158, 53, 71, 8, 0, 79, 155, 72, 95, 43, 76, 77, 66, 88, 22, 38, 15, 21, 12, 22, 36, 9, 53, 17, 27, 12, 103, 31, 157, 89, 89, 72, 107, 35, 33, 60, 138, 83, 45, 25, 100, 58, 44, 0, 6, 37, 159, 1, 150, 65, 15, 75, 55, 36, 143, 81, 141, 48, 122, 29, 150, 14, 103, 32, 25, 58, 18, 63, 12, 74, 147, 70, 115, 23, 125, 34, 52, 38, 117, 5, 54, 26, 32, 18, 0, 60, 149, 7, 9, 40, 138, 13, 77, 47, 10, 7, 79, 41, 151, 56, 128, 53, 109, 44, 12, 56, 88, 23, 110, 27, 103, 70, 67, 6, 106, 19, 23, 7, 121, 12, 38, 8, 93, 1, 88, 52, 7, 31, 155, 43, 92, 84, 81, 43, 109, 52, 53, 24, 11, 80, 33, 27, 129, 3, 152, 89, 26, 56, 113, 48, 83, 25, 79, 7, 127, 49, 11, 41, 58, 5, 121, 33, 0, 48, 130, 1, 53, 35, 146, 73, 94, 78, 149, 42, 73, 73, 144, 81, 140, 0, 61, 89, 126, 70, 42, 57, 69, 78, 24, 13, 50, 27, 131, 84, 106, 70, 16, 83, 43, 69, 1, 31, 100, 35, 91, 37, 152, 44, 111, 20, 10, 82, 109, 69, 153, 75, 107, 27, 149, 63, 65, 25, 51, 76, 60, 85, 97, 31, 109, 78, 52, 59, 124, 89, 10, 89, 95, 20, 88, 28, 121, 88, 53, 55, 129, 55, 147, 15, 10, 73, 99, 16, 63, 85, 56, 18, 155, 16, 23, 84, 53, 21, 103, 40, 85, 38, 28, 11, 112, 16, 149, 77, 113, 1, 95, 74, 105, 13, 118, 17, 6, 78, 62, 54, 69, 9, 90, 5, 123, 8, 148, 61, 135, 73, 140, 54, 47, 70, 85, 53, 2, 5, 102, 58, 88, 49, 16, 4, 17, 35, 20, 44, 55, 4, 150, 37, 142, 5, 7, 1, 32, 0, 82, 30, 137, 60, 137, 84, 91, 60, 27, 70, 135, 55, 126, 45, 3, 13, 129, 56, 120, 89, 157, 38, 2, 6, 150, 8, 116, 16, 158, 50, 9, 57, 2, 62, 35, 32, 52, 60, 104, 15, 73, 85, 129, 29, 107, 39, 125, 21, 105, 40, 104, 7, 154, 43, 15, 77, 131, 36, 50, 26, 158, 41, 119, 62, 51, 58, 73, 75, 32, 15, 32, 83, 91, 45, 148, 22, 75, 48, 159, 55, 103, 76, 73, 17, 30, 65, 157, 3, 110, 33, 34, 24, 94, 7, 44, 42, 48, 88, 58, 9, 81, 11, 70, 73, 70, 75, 21, 14, 107, 70, 7, 35, 121, 48, 156, 65, 57, 56, 133, 61, 136, 31, 101, 0, 117, 80, 130, 89, 142, 46, 111, 46, 82, 62, 50, 39, 0, 31, 59, 31, 13, 89, 22, 79, 39, 39, 22, 0, 84, 86, 105, 66, 101, 58, 5, 58, 54, 17, 121, 66, 46, 32, 66, 65, 67, 77, 113, 5, 45, 87, 53, 43, 132, 49, 129, 36, 152, 18, 32, 44, 30, 69, 92, 41, 159, 65, 49, 14, 90, 80, 111, 27, 38, 88, 135, 66, 64, 81, 49, 76, 73, 64, 93, 38, 134, 18, 145, 36, 125, 57, 36, 36, 108, 22, 34, 75, 123, 53, 50, 77, 83, 57, 75, 21, 35, 83, 89, 8, 126, 88, 46, 53, 42, 62, 73, 69, 132, 88, 17, 39, 155, 25, 83, 60, 21, 69, 119, 68, 141, 26, 12, 85, 135, 64, 111, 55, 41, 65, 133, 31, 23, 72, 115, 89, 146, 31, 53, 26, 31, 33, 17, 83, 134, 82, 58, 7, 150, 67, 33, 67, 147, 39, 23, 46, 8, 70, 86, 63, 98, 22, 123, 12, 96, 52, 158, 2, 152, 15, 46, 36, 36, 19, 119, 75, 88, 64, 66, 1, 71, 56, 145, 3, 60, 47, 20, 56, 93, 60, 65, 71, 41, 28, 60, 10, 66, 4, 26, 2, 158, 56, 25, 9, 91, 22, 8, 26, 126, 79, 30, 31, 107, 89, 46, 31, 23, 13, 112, 17, 109, 72, 51, 42, 27, 64, 153, 51, 127, 55, 155, 80, 57, 70, 85, 19, 62, 89, 118, 12, 20, 51, 27, 60, 70, 79, 119, 87, 113, 83, 140, 34, 148, 26, 97, 1, 123, 49, 62, 19, 92, 19, 133, 17, 37, 8, 52, 80, 6, 88, 115, 12, 22, 28, 22, 76, 114, 60, 20, 61, 107, 53, 32, 13, 47, 13, 69, 53, 143, 26, 18, 36, 3, 73, 23, 40, 9, 21, 123, 34, 5, 80, 91, 8, 132, 52, 36, 16, 126, 59, 66, 47, 88, 19, 45, 36, 72, 15, 66, 52, 88, 20, 71, 62, 50, 58, 153, 6, 2, 80, 135, 31, 9, 5, 91, 2, 108, 0, 26, 37, 25, 86, 42, 40, 54, 67, 73, 79, 100, 9, 14, 34, 36, 6, 65, 85, 132, 12, 42, 89, 47, 76, 2, 51, 92, 29, 49, 64, 8, 64, 47, 8, 72, 53, 42, 21, 18, 35, 130, 71, 27, 41, 111, 40, 76, 76, 94, 25, 80, 52, 52, 3, 69, 70, 130, 17, 4, 56, 121, 80, 0, 42, 83, 67, 114, 76, 122, 12, 35, 7, 77, 32, 30, 80, 155, 5, 143, 7, 47, 83, 17, 79, 27, 83, 20, 72, 33, 79, 77, 48, 98, 74, 148, 16, 137, 13, 65, 76, 20, 15, 39, 8, 42, 10, 70, 88, 12, 41, 64, 63, 44, 40, 64, 44, 140, 52, 113, 76, 87, 35, 146, 16, 134, 48, 137, 82, 65, 26, 107, 9, 17, 88, 30, 14, 4, 4, 145, 37, 114, 28, 30, 53, 109, 60, 125, 82, 1, 49, 149, 53, 132, 48, 37, 71, 144, 28, 118, 6, 31, 27, 24, 40, 96, 38, 111, 89, 70, 72, 147, 64, 106, 71, 55, 9, 13, 67, 125, 42, 120, 29, 36, 41, 126, 21, 34, 47, 148, 64, 78, 84, 7, 86, 157, 50, 27, 85, 62, 75, 143, 10, 52, 61, 113, 85, 52, 84, 60, 86, 69, 41, 100, 36, 101, 66, 61, 18, 69, 28, 58, 77, 109, 30, 31, 18, 92, 68, 50, 10, 147, 54, 103, 21, 138, 41, 62, 84, 83, 83, 138, 63, 153, 27, 25, 36, 36, 20, 137, 20, 119, 13, 32, 11, 46, 30, 79, 36, 15, 8, 125, 45, 120, 30, 157, 10, 120, 46, 98, 87, 75, 62, 5, 30, 82, 54, 89, 82, 150, 46, 105, 42, 105, 34, 77, 20, 120, 65, 128, 60, 102, 67, 127, 29, 53, 59, 148, 39, 152, 63, 4, 61, 35, 55, 33, 46, 32, 32, 59, 64, 55, 40, 125, 30, 93, 64, 38, 7, 19, 69, 93, 36, 94, 32, 57, 7, 15, 55, 149, 71, 57, 81, 152, 24, 100, 77, 91, 53, 114, 85, 54, 65, 55, 50, 151, 55, 38, 60, 95, 21, 154, 18, 54, 37, 103, 23, 109, 63, 144, 79, 17, 66, 105, 71, 16, 15, 50, 44, 144, 83, 40, 72, 144, 62, 134, 54, 1, 84, 57, 8, 117, 6, 35, 78, 58, 85, 4, 81, 68, 15, 92, 18, 40, 54, 116, 29, 99, 62, 56, 59, 48, 89, 135, 12, 13, 46, 137, 46, 1, 35, 73, 36, 76, 12, 76, 46, 143, 84, 51, 18, 70, 28, 159, 20, 12, 51, 114, 46, 138, 17, 68, 34, 57, 44, 142, 61, 43, 77, 141, 2, 22, 18, 37, 43, 17, 68, 81, 63, 17, 54, 133, 7, 142, 28, 80, 20, 7, 55, 25, 12, 42, 3, 103, 43, 157, 29, 51, 63, 156, 37, 18, 86, 140, 47, 129, 65, 147, 48, 63, 67, 102, 0, 70, 84, 3, 16, 48, 11, 68, 79, 103, 15, 79, 13, 73, 31, 158, 23, 86, 69, 128, 58, 104, 24, 1, 86, 39, 55, 80, 19, 4, 10, 108, 65, 117, 53, 59, 23, 89, 47, 12, 78, 5, 75, 60, 78, 44, 66, 127, 51, 71, 1, 47, 62, 45, 33, 106, 24, 43, 39, 120, 0, 64, 11, 33, 64, 120, 1, 67, 60, 51, 86, 109, 75, 2, 10, 138, 73, 9, 10, 132, 71, 112, 80, 88, 2, 79, 65, 85, 49, 38, 80, 49, 86, 39, 18, 77, 73, 143, 44, 39, 58, 145, 13, 102, 31, 136, 40, 127, 37, 141, 86, 10, 42, 136, 73, 127, 54, 48, 6, 148, 0, 21, 84, 86, 13, 65, 84, 43, 47, 73, 58, 85, 41, 66, 54, 29, 30, 32, 79, 68, 85, 47, 17, 30, 5, 67, 16, 56, 25, 153, 84, 119, 8, 97, 55, 13, 40, 4, 82, 113, 42, 32, 64, 110, 61, 153, 67, 138, 9, 110, 76, 149, 68, 69, 77, 6, 19, 69, 35, 106, 16, 85, 60, 84, 40, 133, 72, 131, 34, 15, 69, 12, 2, 137, 88, 47, 54, 113, 55, 25, 16, 119, 53, 111, 50, 75, 49, 30, 76, 125, 12, 55, 64, 98, 24, 81, 16, 145, 11, 104, 79, 98, 36, 89, 68, 154, 29, 83, 21, 23, 36, 151, 71, 7, 89, 31, 51, 123, 83, 87, 24, 143, 71, 159, 66, 67, 79, 76, 16, 107, 55, 97, 43, 108, 53, 48, 67, 5, 25, 107, 66, 106, 67, 35, 18, 1, 13, 94, 49, 0, 33, 28, 66, 96, 8, 44, 70, 126, 5, 22, 23, 119, 38, 146, 88, 12, 19, 134, 49, 6, 89, 22, 21, 92, 70, 110, 85, 92, 25, 75, 44, 127, 65, 66, 15, 92, 82, 109, 68, 84, 12, 158, 80, 38, 79, 102, 36, 82, 60, 159, 57, 121, 86, 101, 34, 23, 66, 0, 12, 94, 63, 106, 50, 12, 88, 100, 71, 134, 60, 137, 69, 79, 35, 130, 74, 35, 63, 54, 77, 147, 50, 122, 66, 26, 18, 149, 76, 134, 78, 35, 51, 73, 70, 48, 34, 84, 54, 158, 0, 159, 7, 146, 7, 78, 7, 132, 24, 70, 14, 113, 35, 85, 88, 54, 42, 107, 46, 77, 52, 84, 60, 43, 79, 105, 59, 45, 34, 98, 88, 10, 62, 141, 35, 17, 27, 55, 10, 0, 82, 56, 2, 102, 17, 106, 56, 26, 83, 142, 75, 138, 28, 98, 51, 134, 10, 3, 53, 69, 76, 56, 42, 124, 42, 146, 87, 12, 57, 123, 70, 129, 38, 59, 65, 50, 4, 12, 38, 107, 41, 29, 36, 101, 38, 22, 35, 156, 30, 132, 11, 29, 52, 56, 79, 109, 1, 152, 48, 130, 61, 52, 21, 1, 21, 82, 48, 116, 67, 74, 38, 9, 16, 115, 83, 43, 67, 16, 41, 62, 9, 70, 40, 150, 41, 152, 57, 23, 39, 8, 39, 90, 70, 131, 65, 113, 56, 34, 0, 68, 47, 105, 18, 100, 63, 98, 70, 88, 34, 109, 13, 10, 78, 50, 47, 102, 34, 125, 81, 6, 28, 149, 83, 62, 36, 143, 21, 27, 54, 94, 64, 57, 6, 79, 89, 157, 46, 123, 52, 14, 39, 3, 47, 124, 87, 4, 47, 94, 29, 68, 39, 138, 85, 67, 73, 108, 61, 146, 26, 110, 57, 146, 28, 140, 59, 91, 62, 135, 11, 88, 37, 43, 75, 47, 14, 101, 11, 87, 81, 41, 88, 82, 71, 18, 70, 123, 72, 58, 44, 120, 10, 26, 35, 95, 4, 89, 34, 63, 79, 101, 54, 136, 88, 20, 34, 124, 19, 4, 11, 147, 74, 113, 60, 138, 49, 64, 82, 34, 17, 47, 61, 143, 73, 134, 42, 15, 18, 121, 24, 32, 72, 63, 31, 44, 15, 47, 37, 153, 0, 70, 32, 123, 79, 87, 70, 32, 29, 9, 43, 6, 83, 21, 37, 111, 61, 22, 42, 153, 34, 69, 45, 57, 45, 52, 87, 87, 10, 111, 45, 86, 48, 61, 60, 18, 40, 158, 87, 100, 4, 26, 80, 95, 31, 74, 82, 62, 85, 45, 14, 43, 0, 35, 24, 75, 37, 6, 8, 159, 13, 37, 73, 47, 50, 44, 88, 59, 81, 108, 1, 151, 48, 106, 2, 143, 39, 60, 1, 103, 58, 2, 3, 111, 38, 110, 46, 38, 76, 18, 21, 25, 32, 58, 52, 56, 33, 78, 58, 78, 15, 155, 53, 40, 37, 43, 22, 51, 32, 27, 36, 86, 25, 5, 54, 71, 11, 143, 74, 115, 26, 45, 0, 143, 43, 48, 22, 126, 69, 99, 32, 28, 53, 11, 88, 36, 73, 62, 43, 158, 25, 53, 48, 9, 37, 57, 76, 108, 84, 159, 82, 125, 89, 117, 41, 114, 24, 29, 26, 40, 71, 62, 55, 77, 40, 121, 49, 118, 60, 76, 24, 60, 88, 128, 69, 156, 61, 153, 57, 34, 66, 86, 56, 22, 82, 147, 56, 122, 13, 19, 33, 2, 76, 44, 18, 106, 20, 18, 73, 157, 58, 52, 81, 123, 77, 13, 31, 84, 62, 136, 52, 5, 27, 115, 36, 129, 14, 46, 82, 159, 67, 100, 67, 18, 68, 16, 50, 27, 55, 1, 68, 109, 79, 26, 81, 67, 45, 55, 65, 67, 69, 29, 45, 83, 86, 26, 17, 14, 44, 139, 42, 36, 10, 47, 52, 55, 2, 64, 40, 148, 73, 64, 64, 109, 24, 124, 50, 115, 63, 25, 67, 151, 76, 60, 64, 114, 10, 122, 51, 126, 8, 7, 6, 144, 84, 11, 46, 128, 61, 158, 46, 77, 31, 52, 37, 129, 75, 3, 69, 45, 40, 89, 71, 141, 63, 96, 84, 128, 39, 102, 65, 105, 36, 72, 85, 154, 58, 144, 73, 111, 48, 64, 33, 15, 62, 86, 70, 28, 63, 144, 30, 92, 61, 113, 59, 60, 35, 56, 41, 144, 24, 5, 56, 41, 63, 87, 21, 102, 22, 112, 77, 80, 30, 85, 28, 31, 49, 98, 25, 132, 56, 20, 5, 73, 62, 95, 48, 156, 72, 62, 71, 134, 26, 113, 77, 69, 65, 36, 70, 35, 77, 138, 48, 11, 0, 47, 34, 142, 2, 43, 61, 26, 85, 44, 21, 76, 68, 148, 63, 47, 85, 10, 71, 131, 66, 139, 67, 121, 6, 134, 51, 144, 85, 109, 70, 44, 16, 36, 24, 30, 6, 80, 29, 84, 87, 61, 33, 93, 83, 110, 56, 8, 55, 28, 46, 159, 17, 87, 19, 53, 88, 83, 59, 115, 47, 28, 23, 117, 43, 18, 5, 109, 26, 136, 23, 22, 71, 92, 35, 83, 33, 81, 19, 131, 14, 113, 36, 4, 27, 140, 13, 35, 41, 99, 52, 31, 13, 122, 47, 32, 16, 114, 65, 44, 67, 85, 40, 143, 79, 146, 80, 0, 9, 101, 78, 12, 86, 89, 38, 68, 78, 132, 35, 143, 34, 61, 20, 127, 47, 4, 9, 131, 2, 122, 81, 11, 69, 50, 38, 6, 7, 100, 37, 26, 61, 2, 60, 101, 17, 156, 17, 101, 84, 1, 81, 119, 85, 2, 54, 142, 3, 112, 53, 15, 88, 17, 52, 16, 44, 67, 55, 7, 29, 136, 55, 125, 77, 95, 77, 159, 33, 24, 14, 36, 60, 150, 24, 116, 77, 82, 18, 146, 40, 154, 60, 89, 65, 81, 65, 98, 78, 143, 0, 49, 40, 70, 47, 152, 3, 119, 56, 40, 60, 154, 59, 56, 83, 105, 9, 112, 30, 29, 64, 139, 50, 132, 45, 33, 85, 51, 43, 136, 15, 147, 67, 29, 29, 130, 66, 29, 88, 21, 59, 46, 28, 104, 2, 54, 38, 109, 38, 17, 75, 46, 69, 4, 46, 79, 49, 135, 34, 94, 73, 6, 42, 12, 35, 23, 58, 125, 76, 123, 22, 118, 11, 68, 84, 23, 75, 129, 17, 51, 5, 74, 79, 48, 32, 105, 11, 152, 14, 91, 65, 155, 20, 132, 16, 36, 17, 31, 56, 80, 61, 8, 82, 15, 47, 157, 72, 114, 22, 51, 44, 25, 85, 123, 81, 74, 23, 134, 72, 11, 3, 47, 89, 29, 7, 52, 11, 2, 13, 130, 63, 116, 49, 148, 55, 103, 12, 11, 36, 147, 71, 118, 69, 47, 30, 16, 1, 93, 47, 72, 1, 1, 63, 151, 5, 48, 51, 116, 45, 37, 22, 78, 73, 30, 52, 51, 35, 47, 67, 152, 49, 76, 44, 39, 12, 21, 57, 112, 67, 99, 53, 93, 54, 43, 41, 109, 42, 36, 64, 4, 31, 73, 66, 87, 84, 50, 42, 100, 38, 29, 34, 131, 80, 84, 53, 110, 13, 118, 14, 146, 8, 77, 5, 51, 6, 158, 30, 132, 27, 50, 54, 13, 85, 96, 47, 89, 59, 5, 45, 53, 61, 89, 35, 69, 32, 148, 33, 4, 21, 10, 35, 123, 6, 63, 71, 107, 12, 33, 18, 34, 33, 2, 83, 13, 29, 126, 9, 108, 17, 63, 65, 144, 19, 94, 4, 68, 6, 77, 88, 55, 66, 123, 80, 150, 60, 155, 58, 91, 46, 146, 86, 69, 66, 156, 19, 86, 20, 112, 6, 75, 54, 75, 29, 56, 58, 123, 27, 27, 76, 83, 48, 98, 31, 69, 36, 90, 17, 40, 32, 154, 10, 140, 20, 147, 11, 119, 31, 56, 46, 143, 53, 142, 24, 68, 23, 64, 50, 119, 63, 0, 84, 91, 1, 47, 38, 159, 44, 128, 79, 1, 16, 16, 77, 140, 4, 120, 66, 111, 69, 112, 47, 40, 62, 26, 25, 78, 47, 42, 18, 117, 18, 137, 72, 137, 68, 13, 88, 15, 89, 9, 88, 41, 29, 26, 82, 31, 76, 49, 58, 57, 46, 82, 22, 120, 31, 66, 67, 61, 83, 139, 39, 85, 57, 158, 44, 19, 18, 78, 19, 113, 49, 0, 68, 128, 83, 56, 73, 77, 53, 10, 2, 43, 52, 99, 22, 97, 73, 37, 6, 34, 25, 61, 19, 24, 69, 85, 51, 79, 88, 94, 55, 10, 43, 94, 30, 40, 88, 149, 10, 87, 12, 4, 68, 39, 78, 125, 23, 85, 0, 6, 52, 25, 19, 118, 26, 150, 32, 25, 22, 22, 27, 45, 9, 46, 15, 88, 56, 96, 62, 37, 12, 95, 38, 37, 11, 147, 81, 57, 57, 56, 70, 78, 32, 103, 28, 80, 27, 139, 46, 146, 33, 96, 61, 38, 70, 28, 59, 81, 40, 141, 27, 59, 16, 131, 7, 141, 47, 141, 20, 35, 35, 87, 36, 121, 71, 85, 78, 76, 79, 83, 20, 2, 52, 88, 47, 96, 3, 23, 21, 87, 4, 49, 50, 135, 24, 70, 63, 141, 3, 24, 88, 71, 15, 134, 64, 28, 50, 19, 9, 21, 4, 51, 77, 98, 37, 121, 35, 133, 41, 58, 83, 6, 58, 121, 82, 16, 0, 128, 13, 11, 45, 143, 50, 131, 51, 89, 63, 136, 89, 149, 43, 130, 10, 43, 16, 84, 5, 94, 48, 139, 10, 46, 75, 53, 4, 10, 12, 126, 18, 149, 25, 134, 38, 143, 51, 124, 20, 159, 71, 58, 6, 50, 62, 136, 27, 16, 6, 119, 1, 42, 87, 108, 35, 130, 53, 46, 3, 28, 12, 90, 63, 80, 47, 56, 52, 8, 63, 0, 15, 155, 9, 40, 76, 20, 43, 40, 63, 56, 78, 42, 51, 24, 46, 0, 44, 39, 83, 115, 22, 146, 17, 158, 3, 132, 32, 54, 9, 91, 11, 0, 63, 75, 59, 101, 15, 141, 62, 100, 21, 93, 34, 63, 30, 122, 48, 148, 88, 154, 51, 59, 12, 151, 4, 14, 45, 139, 3, 22, 84, 8, 19, 124, 73, 138, 50, 10, 39, 158, 70, 114, 3, 99, 82, 124, 86, 62, 79, 66, 17, 80, 50, 36, 79, 141, 78, 10, 30, 74, 64, 128, 89, 69, 15, 45, 75, 113, 88, 39, 3, 86, 72, 95, 10, 111, 10, 16, 30, 54, 53, 42, 34, 100, 5, 81, 14, 44, 79, 124, 5, 86, 73, 105, 29, 38, 15, 82, 35, 64, 22, 79, 0, 123, 3, 137, 41, 12, 67, 35, 70, 147, 21, 95, 32, 157, 27, 112, 5, 74, 30, 6, 56, 130, 54, 106, 77, 158, 7, 100, 74, 30, 85, 158, 40, 144, 36, 81, 46, 32, 26, 102, 71, 4, 12, 30, 9, 29, 73, 26, 8, 80, 54, 40, 39, 140, 75, 34, 43, 75, 4, 153, 64, 124, 26, 35, 81, 20, 85, 154, 45, 107, 56, 114, 87, 138, 37, 139, 2, 126, 53, 73, 13, 103, 63, 30, 12, 2, 73, 28, 9, 82, 40, 11, 89, 78, 86, 76, 30, 138, 81, 6, 20, 15, 45, 58, 74, 119, 4, 45, 13, 56, 56, 154, 69, 14, 20, 118, 67, 30, 30, 29, 84, 120, 36, 142, 81, 133, 51, 119, 44, 39, 72, 104, 17, 99, 2, 85, 27, 17, 12, 135, 57, 81, 25, 110, 21, 43, 30, 137, 38, 102, 54, 68, 43, 43, 54, 3, 88, 138, 74, 95, 86, 152, 76, 22, 64, 98, 56, 7, 43, 74, 65, 101, 52, 58, 47, 148, 3, 112, 88, 90, 51, 137, 66, 77, 27, 42, 17, 108, 15, 5, 4, 1, 11, 138, 82, 3, 25, 74, 44, 13, 71, 145, 25, 60, 6, 91, 48, 39, 89, 42, 83, 100, 60, 70, 7, 136, 54, 42, 2, 133, 55, 22, 6, 136, 71, 6, 1, 16, 9, 139, 1, 68, 57, 73, 33, 49, 85, 103, 66, 132, 31, 128, 6, 1, 14, 148, 47, 14, 65, 9, 42, 59, 58, 126, 27, 97, 17, 111, 77, 15, 65, 133, 9, 121, 76, 97, 75, 42, 7, 70, 86, 49, 37, 4, 78, 156, 76, 117, 38, 131, 61, 20, 42, 52, 17, 23, 14, 98, 52, 108, 68, 22, 39, 93, 0, 41, 17, 111, 39, 156, 83, 117, 20, 87, 16, 8, 57, 116, 17, 70, 49, 154, 57, 135, 4, 136, 16, 159, 42, 70, 87, 29, 14, 15, 79, 112, 82, 124, 0, 86, 49, 21, 49, 1, 36, 34, 73, 156, 35, 16, 82, 56, 3, 26, 38, 25, 76, 109, 73, 49, 82, 68, 89, 38, 0, 82, 47, 42, 58, 152, 88, 36, 7, 80, 23, 113, 79, 5, 15, 159, 22, 96, 10, 94, 89, 63, 76, 155, 86, 61, 84, 89, 50, 128, 9, 110, 71, 10, 50, 47, 81, 6, 38, 4, 22, 51, 25, 62, 77, 56, 38, 107, 42, 111, 53, 118, 32, 80, 63, 17, 17, 23, 73, 129, 53, 60, 19, 27, 74, 90, 1, 128, 81, 4, 60, 85, 23, 6, 39, 64, 69, 76, 87, 19, 14, 81, 9, 108, 25, 135, 48, 48, 53, 82, 32, 147, 49, 144, 65, 7, 65, 49, 30, 42, 72, 88, 58, 126, 50, 75, 60, 114, 40, 78, 2, 71, 7, 22, 13, 6, 35, 120, 14, 4, 39, 100, 85, 145, 23, 115, 81, 59, 11, 119, 32, 83, 53, 154, 26, 1, 55, 52, 66, 92, 60, 41, 58, 88, 0, 47, 24, 55, 6, 96, 80, 135, 37, 82, 42, 85, 58, 134, 45, 79, 72, 47, 20, 84, 8, 73, 19, 77, 21, 62, 41, 109, 32, 18, 82, 79, 86, 135, 89, 40, 75, 76, 54, 24, 66, 33, 15, 42, 20, 76, 1, 14, 47, 145, 83, 157, 23, 135, 41, 113, 30, 96, 28, 103, 19, 26, 16, 77, 61, 152, 19, 8, 69, 21, 75, 95, 22, 5, 11, 93, 61, 106, 85, 63, 34, 31, 5, 152, 25, 100, 2, 109, 51, 45, 46, 122, 80, 130, 78, 61, 80, 58, 59, 78, 63, 78, 6, 73, 12, 17, 22, 151, 57, 72, 9, 52, 20, 145, 89, 50, 19, 64, 13, 70, 82, 11, 33, 43, 2, 94, 54, 107, 76, 115, 21, 133, 67, 45, 57, 84, 73, 131, 24, 3, 59, 21, 27, 123, 5, 34, 67, 109, 10, 9, 35, 95, 34, 132, 72, 142, 16, 126, 47, 66, 69, 61, 24, 67, 86, 56, 29, 1, 62, 148, 21, 101, 14, 27, 59, 79, 84, 137, 87, 157, 52, 8, 53, 96, 1, 40, 73, 91, 19, 107, 5, 157, 74, 10, 28, 61, 21, 119, 81, 61, 54, 112, 12, 17, 36, 112, 52, 37, 37, 127, 87, 67, 24, 24, 9, 69, 17, 113, 39, 108, 60, 83, 77, 139, 16, 4, 73, 142, 51, 53, 32, 153, 45, 36, 85, 155, 37, 25, 7, 94, 39, 8, 3, 127, 80, 97, 26, 49, 45, 131, 9, 128, 36, 101, 27, 84, 61, 131, 81, 29, 25, 61, 15, 93, 89, 3, 28, 103, 50, 18, 66, 141, 29, 12, 79, 78, 65, 158, 4, 155, 31, 153, 56, 49, 29, 144, 63, 25, 54, 34, 87, 39, 69, 135, 88, 21, 65, 144, 6, 85, 2, 27, 73, 30, 15, 142, 84, 16, 52, 158, 39, 56, 68, 98, 27, 26, 24, 20, 76, 127, 33, 142, 88, 157, 24, 90, 7, 80, 89, 55, 47, 4, 37, 145, 56, 76, 59, 83, 88, 50, 85, 97, 67, 113, 73, 8, 52, 87, 0, 131, 17, 119, 23, 121, 25, 48, 4, 114, 61, 20, 50, 10, 24, 147, 17, 122, 28, 79, 14, 12, 61, 65, 55, 48, 54, 152, 45, 124, 48, 43, 55, 87, 30, 140, 39, 94, 0, 23, 55, 137, 89, 9, 15, 142, 31, 12, 80, 158, 10, 129, 74, 55, 21, 26, 31, 74, 62, 53, 44, 110, 48, 16, 72, 88, 26, 41, 85, 26, 74, 34, 37, 67, 29, 35, 52, 31, 68, 41, 26, 46, 66, 123, 15, 73, 6, 29, 20, 92, 85, 55, 27, 20, 11, 156, 6, 3, 31, 134, 44, 89, 45, 156, 53, 4, 55, 35, 3, 158, 57, 59, 66, 152, 22, 142, 79, 79, 30, 139, 80, 17, 57, 102, 42, 73, 28, 47, 40, 17, 53, 23, 48, 135, 43, 91, 86, 65, 88, 21, 48, 52, 10, 114, 80, 33, 8, 141, 15, 74, 11, 131, 15, 111, 33, 83, 27, 100, 33, 149, 69, 87, 83, 131, 46, 46, 27, 153, 68, 104, 87, 61, 72, 40, 53, 62, 18, 72, 19, 51, 46, 156, 82, 108, 76, 71, 72, 153, 66, 62, 74, 3, 66, 138, 27, 102, 75, 61, 8, 71, 38, 117, 25, 95, 8, 77, 57, 33, 17, 0, 6, 70, 42, 36, 57, 125, 61, 44, 43, 36, 74, 57, 22, 1, 19, 119, 19, 68, 88, 0, 39, 91, 50, 129, 22, 157, 21, 52, 9, 122, 63, 94, 2, 64, 48, 141, 73, 84, 6, 147, 5, 93, 17, 60, 15, 144, 56, 107, 18, 87, 51, 52, 42, 152, 36, 114, 4, 70, 12, 25, 68, 38, 23, 68, 70, 131, 78, 111, 64, 0, 61, 100, 70, 116, 19, 16, 43, 1, 2, 26, 58, 118, 44, 83, 81, 63, 45, 127, 67, 130, 25, 152, 50, 56, 55, 33, 56, 133, 46, 68, 20, 131, 45, 108, 70, 116, 37, 137, 79, 42, 38, 22, 31, 139, 53, 20, 58, 66, 7, 86, 22, 87, 69, 26, 70, 142, 74, 28, 80, 23, 25, 88, 53, 92, 57, 95, 62, 102, 48, 118, 62, 63, 83, 14, 24, 35, 39, 58, 40, 59, 60, 8, 23, 64, 4, 60, 71, 58, 23, 148, 48, 125, 37, 143, 58, 104, 30, 112, 38, 145, 48, 71, 5, 50, 43, 157, 70, 120, 6, 120, 77, 82, 6, 104, 22, 118, 68, 122, 11, 105, 31, 118, 37, 48, 75, 33, 51, 157, 83, 149, 23, 133, 80, 120, 28, 134, 66, 25, 79, 146, 46, 100, 15, 23, 37, 5, 44, 151, 43, 96, 55, 33, 32, 141, 88, 152, 83, 130, 50, 59, 80, 128, 18, 112, 41, 66, 10, 13, 66, 29, 5, 18, 62, 67, 27, 77, 23, 110, 10, 79, 32, 44, 48, 79, 68, 86, 27, 42, 37, 133, 18, 31, 6, 147, 44, 123, 9, 149, 86, 107, 30, 102, 23, 48, 85, 159, 31, 150, 76, 130, 11, 70, 25, 79, 8, 52, 72, 99, 71, 99, 81, 151, 33, 131, 28, 105, 61, 50, 36, 134, 24, 76, 32, 139, 14, 92, 54, 11, 30, 89, 24, 54, 70, 24, 37, 147, 31, 142, 53, 102, 77, 153, 4, 132, 46, 103, 49, 59, 75, 25, 82, 143, 55, 102, 30, 46, 2, 117, 65, 122, 38, 45, 19, 107, 11, 41, 21, 53, 50, 97, 83, 115, 64, 44, 80, 36, 3, 149, 48, 62, 24, 53, 65, 7, 70, 111, 65, 135, 13, 146, 42, 63, 55, 49, 83, 60, 63, 132, 20, 133, 20, 63, 77, 39, 40, 69, 59, 3, 7, 23, 43, 21, 89, 25, 21, 88, 9, 11, 68, 32, 21, 39, 33, 64, 67, 21, 25, 39, 45, 88, 3, 84, 79, 7, 11, 140, 81, 91, 72, 10, 46, 116, 55, 69, 85, 159, 62, 122, 34, 108, 21, 100, 22, 55, 15, 110, 29, 34, 57, 46, 55, 124, 44, 54, 59, 70, 10, 13, 20, 24, 81, 156, 67, 13, 37, 128, 25, 25, 15, 15, 1, 33, 23, 91, 13, 143, 18, 114, 52, 46, 52, 11, 37, 55, 41, 86, 0, 146, 29, 57, 67, 93, 53, 133, 69, 70, 26, 61, 13, 14, 30, 60, 58, 81, 74, 155, 81, 81, 55, 140, 16, 136, 65, 145, 1, 22, 22, 69, 62, 65, 35, 122, 7, 121, 62, 16, 24, 80, 62, 36, 55, 60, 25, 75, 1, 89, 6, 70, 24, 117, 4, 88, 22, 81, 87, 39, 5, 59, 25, 136, 86, 91, 27, 120, 32, 28, 20, 20, 8, 85, 47, 87, 17, 76, 49, 123, 82, 32, 84, 22, 53, 143, 89, 158, 82, 92, 87, 28, 1, 159, 45, 146, 5, 75, 52, 68, 28, 7, 17, 25, 23, 40, 21, 137, 0, 98, 46, 73, 86, 125, 7, 66, 51, 72, 73, 38, 42, 148, 78, 84, 0, 104, 28, 4, 69, 106, 86, 31, 42, 101, 44, 147, 79, 148, 23, 156, 59, 115, 54, 121, 39, 26, 4, 22, 36, 95, 58, 105, 57, 31, 80, 70, 31, 80, 68, 2, 71, 64, 5, 28, 86, 135, 39, 79, 11, 47, 82, 74, 35, 159, 78, 102, 46, 63, 74, 26, 26, 49, 49, 141, 21, 121, 75, 149, 37, 53, 46, 136, 77, 125, 49, 6, 11, 47, 25, 23, 64, 80, 10, 154, 42, 9, 52, 152, 58, 130, 21, 138, 36, 87, 61, 97, 32, 119, 37, 91, 74, 136, 64, 66, 57, 21, 8, 40, 25, 154, 7, 115, 85, 148, 84, 18, 38, 42, 71, 29, 46, 133, 59, 60, 72, 89, 55, 89, 54, 155, 13, 39, 82, 46, 35, 142, 19, 81, 79, 105, 16, 78, 42, 126, 7, 98, 38, 101, 50, 67, 25, 113, 58, 7, 64, 21, 40, 49, 6, 4, 33, 33, 10, 154, 82, 98, 60, 32, 54, 20, 74, 45, 26, 65, 42, 70, 70, 22, 69, 127, 44, 113, 81, 112, 22, 130, 47, 126, 80, 95, 55, 147, 75, 106, 58, 123, 75, 101, 22, 3, 6, 20, 16, 151, 38, 69, 2, 127, 12, 17, 11, 59, 86, 14, 51, 134, 50, 100, 84, 141, 74, 66, 11, 92, 10, 45, 47, 8, 72, 120, 62, 35, 19, 19, 57, 26, 7, 157, 36, 90, 2, 149, 30, 73, 68, 117, 33, 135, 30, 32, 9, 43, 28, 88, 13, 134, 39, 83, 52, 53, 82, 154, 3, 59, 73, 109, 25, 23, 60, 58, 13, 60, 59, 140, 41, 83, 56, 134, 15, 100, 43, 124, 75, 159, 12, 84, 17, 75, 34, 87, 60, 56, 69, 112, 74, 126, 40, 133, 47, 111, 23, 27, 39, 54, 20, 105, 38, 137, 9, 64, 72, 142, 0, 70, 53, 87, 26, 89, 51, 40, 13, 127, 22, 120, 43, 15, 11, 91, 24, 41, 2, 5, 16, 141, 55, 90, 25, 61, 10, 121, 20, 85, 80, 51, 4, 94, 84, 137, 76, 154, 79, 85, 37, 28, 78, 157, 75, 53, 7, 85, 82, 102, 12, 153, 40, 157, 25, 119, 11, 103, 39, 112, 71, 55, 75, 70, 39, 101, 41, 39, 15, 93, 58, 69, 86, 76, 7, 78, 53, 55, 56, 116, 65, 76, 11, 91, 54, 81, 59, 120, 72, 39, 88, 109, 29, 141, 79, 123, 35, 18, 54, 13, 60, 16, 73, 88, 30, 14, 62, 44, 33, 3, 82, 139, 23, 78, 30, 105, 25, 40, 14, 42, 0, 75, 66, 95, 44, 40, 46, 147, 68, 54, 8, 108, 16, 146, 44, 80, 45, 116, 41, 31, 58, 13, 21, 124, 4, 84, 3, 91, 49, 81, 88, 36, 82, 45, 63, 142, 33, 62, 59, 43, 43, 101, 31, 52, 76, 48, 35, 116, 84, 81, 57, 43, 45, 71, 4, 88, 33, 107, 1, 73, 37, 135, 2, 126, 22, 98, 48, 158, 6, 110, 78, 101, 70, 122, 35, 16, 76, 138, 53, 122, 31, 98, 83, 91, 85, 106, 8, 25, 47, 40, 1, 99, 5, 15, 29, 125, 22, 120, 84, 120, 4, 132, 64, 60, 41, 51, 16, 156, 68, 70, 65, 127, 74, 62, 27, 43, 74, 59, 47, 25, 38, 144, 41, 82, 64, 124, 21, 99, 64, 87, 15, 1, 37, 59, 74, 159, 35, 80, 12, 150, 70, 59, 17, 83, 22, 30, 37, 113, 10, 94, 88, 88, 65, 34, 78, 23, 57, 19, 80, 35, 33, 83, 89, 90, 19, 68, 25, 8, 11, 46, 83, 112, 56, 65, 64, 93, 19, 35, 20, 135, 62, 148, 41, 23, 34, 118, 63, 109, 84, 36, 8, 99, 34, 151, 10, 36, 68, 31, 55, 62, 21, 52, 6, 133, 38, 100, 12, 92, 81, 102, 4, 71, 6, 73, 65, 55, 35, 129, 12, 45, 24, 54, 30, 73, 71, 77, 18, 96, 24, 96, 26, 54, 52, 73, 50, 10, 51, 24, 16, 96, 73, 150, 13, 102, 55, 84, 36, 34, 29, 64, 27, 112, 59, 41, 87, 112, 50, 132, 30, 43, 17, 79, 25, 131, 85, 101, 35, 93, 67, 79, 56, 123, 78, 40, 55, 132, 28, 92, 33, 99, 43, 55, 62, 34, 30, 20, 57, 59, 68, 150, 49, 96, 60, 126, 87, 1, 30, 92, 20, 7, 33, 126, 75, 153, 86, 153, 77, 156, 27, 116, 59, 115, 4, 29, 11, 79, 40, 115, 44, 54, 54, 49, 75, 92, 55, 137, 58, 114, 35, 40, 6, 151, 84, 99, 61, 104, 14, 58, 84, 119, 61, 114, 41, 55, 14, 25, 49, 159, 24, 151, 81, 54, 85, 117, 74, 89, 56, 140, 83, 36, 15, 120, 69, 22, 43, 143, 80, 95, 76, 4, 77, 28, 42, 149, 88, 90, 77, 49, 54, 138, 39, 139, 66, 151, 63, 7, 72, 75, 27, 95, 13, 46, 5, 64, 12, 116, 74, 83, 79, 65, 44, 39, 37, 116, 75, 78, 24, 50, 17, 19, 79, 39, 30, 4, 7, 85, 65, 98, 6, 54, 29, 27, 25, 48, 7, 110, 45, 92, 44, 75, 64, 132, 75, 142, 44, 56, 30, 75, 22, 17, 4, 87, 85, 145, 71, 44, 54, 132, 76, 75, 78, 29, 63, 9, 86, 124, 68, 11, 83, 60, 37, 0, 5, 146, 37, 21, 60, 107, 22, 151, 65, 57, 52, 115, 18, 58, 27, 15, 66, 148, 38, 41, 86, 85, 13, 135, 65, 73, 54, 51, 81, 0, 26, 153, 81, 152, 64, 103, 41, 52, 8, 69, 13, 24, 44, 86, 1, 136, 29, 45, 38, 83, 51, 85, 26, 33, 88, 146, 60, 37, 5, 46, 54, 155, 8, 74, 6, 54, 79, 103, 11, 103, 2, 74, 26, 151, 73, 150, 29, 83, 76, 93, 29, 27, 44, 33, 72, 115, 56, 111, 52, 130, 36, 55, 63, 104, 56, 118, 84, 145, 45, 22, 63, 137, 44, 128, 21, 4, 32, 133, 30, 127, 66, 128, 64, 83, 80, 123, 46, 84, 71, 11, 77, 59, 1, 111, 47, 35, 5, 8, 76, 135, 79, 137, 70, 156, 42, 30, 55, 64, 24, 86, 16, 143, 82, 4, 38, 75, 45, 7, 60, 90, 38, 51, 10, 19, 81, 113, 12, 88, 73, 40, 80, 118, 46, 132, 7, 35, 11, 122, 88, 138, 21, 112, 1, 110, 36, 31, 15, 132, 21, 50, 87, 89, 75, 136, 57, 25, 89, 105, 1, 154, 38, 41, 62, 6, 69, 53, 36, 16, 56, 54, 34, 105, 63, 147, 53, 100, 25, 14, 68, 69, 63, 41, 11, 65, 58, 37, 54, 3, 12, 37, 74, 69, 56, 25, 78, 141, 41, 5, 0, 100, 80, 8, 30, 123, 32, 47, 12, 87, 87, 101, 89, 112, 48, 133, 88, 41, 73, 32, 87, 34, 68, 71, 10, 19, 40, 44, 77, 37, 56, 130, 29, 5, 79, 150, 2, 6, 29, 75, 68, 61, 59, 71, 41, 120, 54, 74, 61, 97, 23, 80, 44, 150, 34, 31, 38, 66, 18, 124, 62, 77, 33, 136, 6, 84, 18, 47, 4, 60, 66, 11, 6, 26, 87, 112, 83, 56, 45, 110, 25, 79, 79, 123, 10, 33, 13, 74, 72, 90, 31, 39, 44, 48, 64, 18, 6, 57, 82, 124, 49, 41, 34, 82, 41, 87, 18, 133, 36, 63, 36, 15, 33, 122, 77, 99, 17, 93, 42, 124, 13, 31, 17, 0, 88, 84, 42, 13, 14, 121, 87, 46, 18, 143, 49, 143, 86, 90, 0, 6, 81, 67, 49, 150, 22, 147, 22, 84, 19, 103, 78, 137, 32, 154, 62, 66, 85, 106, 57, 70, 48, 132, 61, 94, 82, 11, 61, 114, 82, 15, 67, 62, 28, 140, 29, 140, 14, 81, 17, 18, 72, 86, 44, 7, 45, 144, 23, 34, 22, 120, 82, 148, 51, 14, 59, 20, 86, 42, 30, 137, 39, 16, 80, 69, 89, 158, 17, 5, 41, 23, 42, 64, 59, 61, 46, 75, 47, 13, 61, 138, 86, 90, 54, 91, 73, 62, 73, 147, 86, 99, 54, 127, 48, 37, 28, 144, 35, 128, 74, 28, 73, 158, 37, 92, 26, 24, 84, 148, 25, 78, 12, 43, 6, 5, 42, 140, 53, 89, 25, 38, 66, 56, 82, 32, 81, 86, 58, 92, 34, 19, 30, 29, 78, 131, 35, 98, 13, 63, 1, 109, 3, 60, 87, 102, 59, 81, 35, 55, 71, 15, 72, 62, 65, 114, 48, 101, 12, 3, 89, 138, 20, 52, 18, 104, 66, 88, 41, 111, 26, 76, 81, 0, 81, 62, 25, 44, 50, 64, 43, 66, 13, 40, 57, 119, 80, 130, 16, 2, 75, 92, 47, 5, 52, 2, 43, 140, 65, 75, 39, 35, 37, 132, 22, 62, 32, 140, 24, 92, 71, 112, 78, 63, 69, 80, 43, 36, 44, 142, 8, 129, 82, 24, 51, 142, 50, 155, 77, 87, 73, 106, 53, 137, 18, 78, 4, 116, 46, 37, 7, 151, 14, 72, 87, 97, 4, 23, 30, 79, 19, 89, 27, 11, 34, 70, 58, 77, 6, 34, 58, 157, 42, 141, 40, 140, 61, 128, 16, 6, 26, 85, 20, 53, 73, 35, 31, 119, 82, 94, 76, 15, 42, 64, 10, 155, 44, 24, 85, 21, 54, 11, 59, 123, 85, 13, 65, 50, 78, 16, 8, 88, 77, 157, 33, 145, 17, 126, 42, 31, 16, 72, 70, 49, 84, 7, 34, 119, 88, 127, 77, 130, 32, 82, 57, 109, 56, 28, 39, 18, 32, 99, 72, 123, 58, 143, 35, 57, 60, 17, 31, 67, 7, 51, 80, 80, 37, 133, 52, 154, 86, 119, 35, 16, 45, 78, 51, 80, 16, 9, 65, 27, 2, 143, 54, 72, 71, 63, 62, 49, 62, 54, 78, 43, 66, 156, 69, 105, 19, 104, 18, 130, 2, 9, 30, 150, 77, 31, 54, 13, 24, 153, 22, 54, 16, 111, 6, 1, 39, 139, 35, 154, 85, 24, 70, 70, 13, 97, 50, 102, 15, 116, 85, 114, 30, 41, 4, 96, 79, 93, 69, 72, 26, 155, 45, 87, 77, 100, 50, 91, 25, 29, 21, 6, 5, 118, 57, 43, 35, 33, 57, 91, 15, 51, 13, 36, 26, 108, 14, 30, 41, 3, 36, 147, 78, 134, 5, 55, 61, 33, 45, 92, 24, 144, 33, 22, 56, 134, 8, 7, 56, 37, 84, 82, 79, 22, 45, 56, 20, 105, 2, 134, 89, 66, 20, 145, 15, 138, 45, 152, 40, 63, 11, 123, 66, 113, 53, 111, 78, 83, 41, 73, 27, 65, 79, 18, 57, 26, 44, 77, 60, 48, 17, 51, 78, 157, 77, 106, 60, 156, 29, 119, 49, 136, 48, 34, 65, 92, 83, 140, 68, 48, 78, 8, 40, 79, 5, 17, 76, 85, 71, 4, 71, 156, 70, 19, 29, 22, 66, 125, 85, 145, 85, 3, 57, 155, 42, 101, 83, 134, 77, 31, 53, 147, 69, 150, 7, 109, 0, 83, 49, 63, 42, 133, 89, 149, 49, 149, 13, 19, 59, 115, 43, 50, 73, 82, 36, 75, 20, 93, 22, 111, 22, 134, 81, 118, 51, 149, 50, 55, 53, 22, 75, 131, 71, 11, 62, 2, 66, 151, 13, 70, 0, 47, 78, 40, 4, 131, 6, 46, 56, 14, 37, 106, 36, 151, 88, 2, 37, 41, 77, 138, 16, 25, 4, 84, 15, 30, 4, 41, 35, 152, 38, 125, 31, 55, 46, 90, 73, 76, 75, 30, 66, 69, 29, 148, 53, 94, 26, 68, 80, 7, 39, 14, 5, 110, 69, 153, 25, 118, 33, 149, 41, 118, 83, 58, 89, 150, 79, 88, 12, 99, 84, 11, 15, 45, 48, 14, 22, 45, 88, 79, 46, 106, 34, 7, 78, 110, 84, 105, 89, 146, 52, 119, 24, 18, 46, 69, 23, 7, 68, 152, 71, 85, 12, 76, 26, 85, 83, 37, 30, 113, 44, 146, 57, 112, 69, 7, 40, 103, 44, 38, 67, 17, 29, 102, 56, 147, 28, 100, 56, 122, 58, 159, 27, 133, 48, 30, 79, 128, 32, 21, 82, 136, 1, 71, 53, 73, 8, 98, 54, 21, 38, 48, 45, 64, 75, 131, 32, 66, 59, 78, 33, 91, 79, 86, 41, 137, 27, 36, 4, 94, 80, 76, 3, 16, 51, 153, 1, 43, 25, 71, 60, 156, 89, 121, 21, 36, 53, 55, 45, 34, 82, 118, 47, 84, 75, 25, 64, 82, 43, 68, 31, 129, 25, 96, 88, 8, 48, 64, 84, 20, 1, 79, 54, 44, 86, 136, 81, 72, 16, 46, 72, 71, 68, 91, 12, 101, 40, 74, 31, 138, 77, 120, 26, 23, 15, 97, 9, 106, 87, 132, 38, 140, 84, 108, 6, 94, 53, 6, 4, 54, 68, 130, 35, 23, 12, 141, 17, 19, 76, 85, 56, 100, 79, 91, 59, 96, 7, 119, 7, 66, 0, 17, 25, 67, 81, 143, 19, 100, 41, 35, 64, 144, 71, 83, 75, 25, 6, 109, 9, 3, 87, 76, 29, 25, 10, 137, 25, 128, 23, 15, 54, 0, 66, 28, 35, 17, 45, 21, 33, 114, 57, 154, 16, 30, 21, 99, 45, 41, 32, 132, 77, 150, 53, 6, 27, 101, 87, 124, 82, 24, 65, 101, 79, 139, 56, 15, 57, 24, 62, 144, 49, 126, 72, 149, 18, 152, 31, 107, 14, 32, 17, 28, 28, 124, 54, 72, 89, 74, 85, 4, 64, 57, 14, 129, 7, 74, 42, 59, 54, 93, 30, 58, 22, 84, 26, 70, 83, 48, 66, 124, 47, 134, 21, 63, 19, 26, 75, 27, 3, 111, 75, 91, 82, 1, 83, 16, 5, 156, 50, 53, 6, 5, 48, 65, 83, 113, 51, 132, 84, 3, 29, 99, 55, 71, 58, 140, 15, 132, 50, 51, 82, 93, 51, 25, 5, 61, 27, 81, 12, 125, 46, 83, 62, 93, 23, 12, 52, 147, 36, 97, 89, 129, 70, 130, 49, 112, 58, 27, 13, 50, 61, 35, 76, 135, 76, 44, 30, 13, 62, 20, 60, 155, 71, 33, 1, 49, 36, 83, 78, 119, 46, 75, 63, 105, 48, 154, 53, 65, 62, 74, 86, 38, 12, 42, 14, 59, 45, 49, 12, 71, 13, 44, 31, 142, 52, 155, 6, 22, 8, 35, 29, 18, 10, 72, 25, 77, 77, 145, 88, 13, 44, 13, 12, 123, 44, 110, 44, 97, 20, 4, 51, 94, 62, 63, 28, 54, 31, 156, 20, 136, 7, 83, 1, 60, 45, 110, 53, 159, 41, 4, 15, 20, 37, 3, 52, 121, 28, 103, 62, 106, 64, 25, 63, 8, 54, 142, 22, 102, 29, 42, 1, 25, 62, 13, 9, 150, 12, 86, 71, 84, 51, 111, 73, 13, 72, 54, 33, 138, 43, 34, 11, 14, 31, 17, 19, 68, 3, 67, 10, 106, 17, 28, 72, 80, 60, 62, 15, 105, 17, 89, 61, 142, 48, 112, 64, 124, 28, 65, 17, 149, 34, 66, 16, 104, 4, 59, 44, 31, 2, 11, 2, 129, 2, 122, 42, 39, 56, 150, 4, 38, 49, 81, 67, 9, 18, 79, 1, 63, 0, 35, 17, 18, 34, 103, 60, 84, 78, 9, 25, 109, 59, 32, 75, 93, 20, 136, 46, 72, 66, 106, 73, 72, 45, 58, 34, 125, 39, 10, 34, 20, 89, 72, 33, 135, 49, 46, 23, 36, 40, 60, 52, 85, 77, 42, 31, 19, 78, 75, 5, 99, 65, 106, 49, 149, 74, 131, 50, 2, 14, 30, 33, 54, 57, 125, 9, 39, 31, 116, 27, 85, 52, 14, 16, 154, 56, 15, 85, 13, 34, 147, 33, 52, 48, 129, 8, 135, 10, 18, 81, 119, 15, 55, 86, 49, 18, 12, 76, 93, 28, 154, 25, 26, 3, 65, 18, 38, 17, 18, 56, 61, 30, 109, 7, 140, 67, 103, 55, 75, 58, 43, 60, 61, 29, 72, 63, 77, 70, 25, 65, 125, 0, 50, 7, 53, 54, 85, 29, 113, 75, 100, 57, 141, 58, 51, 3, 109, 11, 78, 37, 130, 18, 110, 43, 104, 31, 75, 17, 73, 7, 159, 43, 126, 32, 7, 53, 91, 55, 17, 50, 42, 88, 44, 84, 37, 32, 33, 31, 77, 76, 139, 59, 64, 56, 52, 89, 118, 49, 5, 39, 125, 2, 122, 87, 145, 72, 73, 77, 36, 5, 36, 27, 141, 13, 109, 76, 110, 30, 44, 7, 65, 28, 74, 81, 36, 45, 13, 43, 23, 5, 157, 73, 129, 34, 101, 59, 89, 84, 152, 29, 31, 74, 156, 73, 54, 83, 27, 6, 115, 49, 139, 36, 118, 64, 140, 30, 51, 14, 42, 23, 30, 68, 47, 3, 10, 27, 91, 33, 7, 62, 128, 37, 93, 76, 58, 19, 158, 86, 17, 58, 50, 2, 43, 13, 126, 76, 27, 27, 108, 63, 87, 56, 25, 18, 146, 32, 126, 39, 144, 64, 112, 26, 141, 85, 4, 13, 159, 16, 85, 3, 40, 35, 91, 39, 10, 88, 40, 28, 108, 28, 60, 40, 57, 3, 82, 10, 45, 72, 41, 37, 83, 31, 23, 24, 2, 20, 72, 64, 116, 64, 116, 89, 67, 84, 122, 8, 157, 39, 11, 53, 144, 21, 157, 54, 113, 47, 94, 27, 118, 25, 157, 26, 121, 8, 120, 51, 42, 32, 59, 87, 39, 34, 103, 53, 132, 23, 61, 74, 111, 41, 49, 22, 158, 21, 31, 34, 135, 0, 96, 37, 99, 13, 17, 18, 44, 75, 154, 21, 73, 48, 90, 62, 48, 37, 129, 51, 122, 78, 154, 27, 16, 40, 5, 55, 38, 14, 125, 38, 144, 15, 12, 50, 151, 44, 13, 64, 125, 63, 67, 41, 60, 83, 0, 74, 73, 20, 69, 38, 125, 56, 112, 70, 35, 23, 80, 71, 72, 22, 43, 57, 59, 85, 143, 63, 5, 32, 47, 28, 141, 10, 52, 22, 21, 21, 151, 3, 34, 3, 45, 31, 47, 10, 133, 37, 3, 86, 26, 71, 134, 12, 85, 1, 137, 45, 72, 44, 30, 34, 146, 76, 73, 1, 120, 3, 56, 11, 119, 34, 157, 56, 37, 63, 29, 87, 9, 63, 145, 78, 24, 29, 52, 12, 54, 19, 84, 30, 99, 19, 38, 11, 40, 30, 27, 0, 22, 10, 44, 26, 64, 45, 24, 77, 29, 15, 153, 20, 152, 59, 78, 78, 30, 8, 119, 28, 103, 16, 82, 72, 108, 36, 156, 28, 64, 21, 100, 59, 119, 27, 90, 40, 6, 65, 4, 0, 155, 51, 98, 41, 9, 32, 83, 26, 29, 65, 51, 70, 26, 22, 91, 38, 92, 67, 17, 67, 130, 58, 77, 67, 146, 43, 142, 72, 64, 58, 76, 80, 74, 32, 112, 54, 31, 57, 11, 76, 1, 12, 106, 68, 125, 35, 19, 43, 110, 17, 116, 68, 4, 3, 65, 68, 61, 51, 53, 56, 100, 44, 128, 1, 143, 46, 48, 12, 116, 10, 51, 33, 101, 62, 0, 0, 101, 76, 42, 69, 37, 44, 89, 15, 26, 63, 26, 78, 107, 3, 51, 21, 21, 15, 107, 67, 0, 21, 75, 89, 130, 30, 13, 27, 71, 23, 104, 12, 159, 52, 128, 68, 12, 69, 141, 22, 21, 62, 110, 74, 2, 59, 62, 33, 59, 13, 114, 88, 68, 56, 155, 82, 117, 61, 12, 59, 89, 30, 58, 36, 123, 48, 81, 34, 28, 69, 101, 82, 81, 70, 52, 24, 113, 74, 58, 72, 110, 1, 1, 6, 15, 5, 106, 54, 146, 4, 82, 89, 38, 28, 75, 43, 101, 4, 54, 12, 138, 25, 1, 72, 38, 62, 86, 82, 55, 33, 99, 21, 23, 54, 136, 4, 58, 82, 111, 71, 63, 84, 9, 67, 25, 31, 77, 3, 49, 47, 44, 58, 9, 81, 49, 35, 155, 64, 95, 29, 40, 27, 42, 56, 27, 40, 147, 42, 117, 75, 5, 12, 45, 2, 84, 89, 68, 59, 49, 68, 110, 82, 53, 58, 43, 64, 95, 66, 25, 17, 68, 22, 154, 49, 31, 45, 134, 86, 13, 82, 56, 67, 12, 34, 90, 9, 13, 0, 65, 19, 92, 49, 149, 3, 20, 45, 20, 28, 35, 27, 5, 3, 12, 55, 101, 85, 110, 55, 108, 43, 66, 82, 26, 76, 21, 58, 32, 4, 111, 36, 9, 38, 9, 48, 149, 1, 105, 77, 94, 50, 48, 68, 109, 88, 110, 72, 80, 15, 122, 17, 57, 87, 52, 45, 91, 63, 55, 54, 69, 10, 3, 17, 71, 20, 123, 30, 121, 27, 126, 33, 54, 66, 66, 78, 145, 14, 60, 36, 116, 72, 145, 40, 95, 11, 16, 81, 65, 27, 45, 7, 74, 24, 94, 67, 81, 58, 111, 43, 96, 6, 73, 35, 143, 48, 20, 84, 76, 60, 127, 52, 146, 0, 57, 40, 127, 70, 132, 26, 95, 1, 25, 35, 116, 8, 87, 89, 63, 37, 24, 11, 117, 42, 73, 21, 104, 9, 38, 50, 9, 47, 134, 4, 140, 1, 25, 13, 135, 15, 47, 60, 145, 22, 23, 33, 21, 42, 45, 66, 16, 32, 109, 89, 72, 54, 140, 80, 80, 24, 47, 48, 65, 48, 151, 60, 101, 21, 39, 49, 35, 56, 1, 79, 63, 4, 82, 69, 134, 35, 65, 34, 155, 35, 6, 71, 32, 85, 138, 0, 23, 38, 12, 31, 73, 44, 76, 64, 26, 15, 64, 78, 55, 37, 10, 58, 123, 55, 106, 44, 37, 89, 74, 21, 130, 85, 49, 7, 108, 23, 96, 36, 62, 64, 100, 0, 12, 70, 113, 38, 17, 30, 10, 65, 109, 15, 56, 72, 146, 12, 65, 72, 62, 35, 155, 55, 126, 19, 70, 46, 41, 18, 30, 49, 90, 85, 23, 74, 108, 40, 135, 8, 138, 56, 137, 57, 38, 39, 79, 2, 82, 76, 132, 82, 8, 66, 111, 72, 3, 51, 13, 78, 62, 7, 16, 38, 136, 69, 59, 79, 151, 23, 139, 88, 54, 75, 27, 81, 108, 55, 30, 22, 57, 13, 33, 89, 94, 66, 72, 72, 147, 12, 22, 80, 117, 59, 3, 55, 75, 0, 102, 79, 60, 9, 43, 26, 107, 63, 23, 56, 14, 48, 85, 81, 28, 5, 94, 17, 159, 15, 89, 13, 16, 20, 58, 65, 100, 66, 55, 28, 53, 63, 66, 56, 101, 53, 108, 12, 30, 64, 86, 61, 49, 55, 148, 59, 14, 69, 6, 9, 94, 72, 146, 48, 35, 80, 7, 69, 61, 36, 36, 23, 67, 37, 75, 83, 80, 66, 96, 17, 20, 20, 48, 70, 59, 15, 70, 29, 68, 60, 67, 76, 51, 22, 77, 63, 9, 70, 116, 31, 126, 35, 114, 43, 70, 66, 100, 30, 130, 42, 52, 62, 57, 51, 140, 88, 27, 16, 56, 22, 59, 41, 27, 38, 116, 36, 64, 35, 124, 77, 11, 10, 8, 35, 100, 18, 35, 25, 133, 26, 122, 33, 117, 57, 17, 62, 11, 12, 158, 35, 63, 82, 91, 29, 26, 57, 82, 9, 92, 88, 115, 58, 71, 28, 113, 34, 141, 89, 148, 34, 124, 25, 4, 19, 114, 62, 149, 85, 150, 89, 67, 26, 76, 83, 97, 65, 19, 45, 146, 51, 153, 10, 6, 21, 105, 46, 111, 8, 45, 86, 16, 29, 27, 17, 143, 20, 56, 13, 128, 51, 116, 60, 68, 44, 138, 84, 143, 65, 99, 12, 153, 70, 10, 55, 136, 41, 119, 69, 125, 48, 33, 28, 135, 25, 100, 73, 53, 13, 8, 5, 81, 22, 57, 19, 137, 2, 122, 83, 145, 43, 43, 65, 58, 24, 90, 57, 75, 41, 20, 18, 147, 77, 73, 67, 55, 3, 85, 48, 3, 19, 1, 58, 52, 46, 112, 60, 22, 2, 113, 82, 118, 65, 110, 58, 56, 43, 60, 75, 100, 82, 137, 21, 41, 66, 79, 62, 90, 32, 40, 15, 32, 25, 7, 5, 143, 16, 20, 77, 118, 50, 76, 88, 99, 89, 138, 10, 140, 86, 81, 30, 138, 72, 159, 89, 3, 33, 36, 86, 36, 42, 114, 78, 71, 66, 67, 87, 118, 73, 112, 3, 119, 18, 32, 3, 28, 31, 53, 69, 32, 62, 126, 67, 108, 75, 89, 69, 29, 24, 68, 33, 132, 2, 87, 6, 125, 52, 98, 45, 1, 41, 109, 2, 4, 26, 152, 33, 9, 14, 9, 1, 42, 81, 70, 44, 27, 69, 16, 22, 17, 63, 117, 40, 123, 21, 18, 50, 91, 71, 27, 82, 88, 35, 17, 41, 138, 62, 135, 68, 136, 0, 116, 2, 66, 44, 149, 8, 97, 5, 127, 43, 63, 61, 115, 33, 51, 49, 126, 46, 140, 43, 125, 1, 104, 20, 49, 1, 118, 13, 102, 60, 153, 30, 126, 16, 131, 48, 0, 2, 93, 68, 121, 52, 140, 28, 13, 23, 157, 15, 117, 66, 4, 76, 133, 10, 40, 7, 138, 8, 107, 65, 27, 66, 52, 85, 110, 31, 102, 83, 135, 46, 69, 21, 118, 30, 83, 61, 36, 58, 88, 10, 0, 89, 131, 88, 110, 12, 46, 64, 46, 65, 40, 87, 57, 50, 84, 20, 8, 20, 12, 32, 130, 87, 83, 36, 82, 70, 116, 54, 73, 15, 35, 44, 119, 66, 130, 37, 119, 29, 145, 54, 64, 14, 93, 80, 5, 31, 143, 62, 149, 62, 102, 10, 147, 35, 142, 36, 78, 5, 62, 4, 85, 69, 147, 32, 133, 64, 89, 11, 121, 55, 113, 26, 90, 16, 97, 76, 139, 68, 115, 7, 59, 39, 61, 7, 22, 47, 115, 37, 78, 75, 45, 52, 18, 3, 15, 34, 106, 45, 97, 22, 39, 67, 86, 33, 50, 20, 134, 62, 131, 21, 130, 19, 116, 32, 77, 35, 66, 63, 71, 26, 158, 9, 135, 18, 115, 50, 87, 25, 114, 74, 105, 22, 88, 27, 146, 6, 69, 20, 50, 25, 141, 60, 148, 29, 11, 8, 38, 31, 111, 62, 132, 53, 33, 39, 46, 11, 73, 24, 1, 67, 18, 69, 22, 89, 116, 35, 103, 79, 37, 4, 64, 26, 140, 57, 142, 39, 134, 11, 37, 52, 50, 33, 139, 70, 143, 69, 35, 50, 9, 4, 24, 20, 36, 59, 103, 20, 109, 22, 29, 80, 107, 73, 120, 59, 154, 87, 92, 59, 65, 50, 135, 67, 14, 89, 27, 46, 90, 84, 67, 59, 38, 16, 79, 23, 145, 49, 23, 70, 146, 72, 53, 74, 100, 7, 36, 80, 119, 17, 131, 10, 6, 30, 137, 12, 4, 5, 58, 31, 49, 61, 13, 7, 57, 1, 143, 13, 110, 20, 107, 72, 137, 29, 42, 59, 81, 77, 102, 78, 130, 65, 96, 2, 143, 40, 87, 72, 146, 35, 155, 59, 38, 48, 62, 46, 141, 87, 48, 29, 137, 63, 54, 49, 13, 22, 141, 33, 153, 36, 80, 18, 142, 73, 81, 50, 146, 49, 9, 54, 65, 53, 71, 78, 101, 86, 22, 44, 26, 12, 89, 3, 122, 71, 56, 74, 110, 19, 106, 78, 92, 4, 119, 59, 24, 68, 151, 66, 98, 40, 154, 84, 81, 85, 74, 46, 43, 63, 0, 85, 150, 6, 48, 2, 103, 51, 18, 4, 151, 53, 97, 35, 66, 5, 107, 78, 96, 68, 98, 18, 108, 20, 10, 69, 8, 87, 123, 37, 74, 36, 152, 28, 13, 73, 104, 75, 81, 15, 112, 49, 23, 35, 37, 75, 113, 7, 32, 86, 91, 21, 100, 61, 60, 48, 69, 19, 10, 64, 114, 8, 129, 48, 58, 8, 157, 80, 152, 75, 107, 34, 71, 14, 159, 81, 84, 47, 62, 40, 91, 40, 152, 10, 80, 69, 15, 2, 93, 43, 78, 25, 16, 54, 139, 37, 129, 84, 96, 23, 135, 42, 66, 80, 89, 87, 100, 54, 96, 81, 12, 77, 79, 16, 150, 40, 43, 23, 127, 18, 95, 80, 132, 69, 156, 5, 82, 53, 128, 84, 38, 30, 36, 12, 140, 89, 131, 42, 1, 0, 2, 72, 106, 84, 37, 72, 103, 7, 4, 87, 19, 75, 16, 55, 22, 41, 106, 89, 116, 56, 44, 55, 151, 29, 127, 62, 159, 48, 19, 15, 87, 14, 102, 49, 47, 0, 107, 48, 133, 56, 55, 59, 127, 59, 6, 72, 149, 6, 132, 54, 74, 28, 159, 73, 148, 14, 4, 57, 104, 49, 142, 15, 14, 29, 133, 3, 59, 22, 77, 22, 43, 21, 117, 70, 3, 32, 21, 55, 152, 21, 39, 13, 56, 76, 48, 38, 2, 1, 129, 41, 30, 67, 89, 88, 40, 56, 15, 31, 56, 5, 32, 73, 102, 28, 133, 81, 139, 52, 122, 20, 104, 19, 58, 69, 97, 57, 151, 59, 71, 80, 68, 87, 151, 47, 69, 61, 44, 46, 71, 9, 105, 69, 66, 89, 64, 80, 50, 12, 117, 19, 107, 31, 132, 85, 77, 66, 9, 44, 132, 62, 49, 69, 101, 30, 11, 70, 39, 35, 147, 26, 61, 9, 114, 45, 117, 86, 90, 86, 103, 54, 148, 10, 9, 74, 109, 27, 25, 33, 23, 2, 103, 74, 104, 37, 64, 61, 29, 8, 11, 60, 8, 9, 145, 59, 43, 38, 134, 56, 57, 37, 155, 30, 94, 20, 85, 79, 99, 44, 8, 7, 36, 76, 9, 41, 122, 50, 55, 44, 15, 16, 114, 72, 144, 12, 75, 73, 112, 72, 81, 81, 155, 28, 108, 52, 96, 51, 74, 34, 10, 49, 88, 24, 147, 87, 151, 34, 63, 9, 7, 80, 17, 81, 79, 66, 48, 13, 21, 85, 141, 31, 100, 31, 10, 19, 26, 42, 36, 25, 70, 18, 58, 33, 138, 88, 132, 6, 91, 7, 114, 19, 66, 33, 102, 86, 84, 83, 72, 20, 83, 39, 151, 41, 44, 53, 77, 17, 123, 76, 33, 22, 103, 8, 20, 55, 0, 7, 121, 40, 100, 26, 97, 36, 97, 45, 86, 74, 128, 10, 8, 62, 78, 46, 75, 42, 11, 66, 35, 9, 156, 49, 77, 65, 28, 62, 45, 81, 122, 46, 113, 18, 152, 1, 153, 62, 121, 2, 70, 54, 104, 58, 146, 39, 133, 2, 107, 81, 128, 44, 71, 81, 34, 39, 58, 20, 5, 28, 62, 76, 120, 71, 130, 69, 69, 12, 23, 51, 28, 29, 76, 82, 137, 78, 116, 33, 35, 65, 30, 19, 1, 5, 60, 32, 3, 83, 150, 45, 1, 87, 88, 46, 153, 32, 17, 26, 127, 63, 42, 36, 95, 26, 13, 52, 9, 0, 116, 78, 6, 36, 10, 22, 89, 79, 12, 65, 102, 88, 119, 9, 70, 67, 90, 58, 49, 88, 102, 25, 78, 39, 140, 76, 58, 16, 155, 3, 56, 14, 70, 33, 147, 7, 29, 82, 114, 20, 44, 23, 145, 27, 137, 62, 136, 11, 41, 22, 6, 77, 15, 71, 54, 22, 10, 75, 154, 19, 34, 34, 39, 79, 141, 7, 53, 30, 149, 14, 49, 59, 100, 42, 32, 60, 72, 42, 32, 46, 16, 85, 79, 33, 15, 81, 75, 28, 115, 13, 82, 21, 37, 67, 159, 34, 3, 27, 96, 16, 50, 31, 153, 38, 98, 55, 62, 8, 80, 53, 54, 46, 109, 50, 30, 54, 12, 62, 147, 10, 15, 23, 21, 51, 109, 45, 52, 27, 68, 54, 103, 48, 97, 11, 96, 71, 81, 20, 1, 53, 66, 39, 85, 9, 14, 36, 108, 54, 109, 46, 113, 62, 7, 87, 38, 19, 148, 24, 49, 65, 25, 26, 30, 61, 32, 1, 50, 29, 54, 63, 33, 63, 89, 80, 64, 85, 119, 67, 115, 62, 67, 63, 74, 33, 72, 58, 93, 11, 41, 74, 142, 12, 95, 61, 71, 71, 126, 71, 108, 85, 120, 15, 113, 23, 22, 29, 32, 23, 5, 69, 102, 9, 101, 1, 118, 18, 114, 0, 117, 69, 76, 84, 34, 31, 10, 9, 116, 7, 144, 45, 36, 47, 5, 86, 152, 79, 108, 30, 17, 61, 27, 28, 126, 38, 144, 58, 31, 41, 26, 48, 48, 28, 99, 36, 98, 67, 54, 15, 63, 5, 87, 88, 42, 29, 106, 40, 67, 89, 105, 15, 60, 7, 115, 77, 139, 26, 15, 49, 114, 55, 135, 9, 118, 78, 131, 31, 83, 84, 147, 72, 18, 14, 82, 83, 112, 89, 65, 6, 68, 76, 43, 10, 67, 54, 139, 12, 116, 38, 138, 19, 44, 60, 139, 20, 76, 5, 85, 18, 68, 19, 135, 53, 154, 44, 126, 60, 95, 35, 69, 0, 57, 69, 109, 4, 92, 28, 70, 30, 117, 85, 22, 77, 65, 74, 6, 45, 91, 70, 123, 19, 120, 2, 70, 77, 53, 64, 140, 21, 32, 51, 97, 51, 60, 54, 95, 87, 96, 35, 131, 47, 18, 22, 104, 68, 131, 27, 65, 52, 133, 43, 143, 60, 115, 86, 124, 23, 81, 42, 55, 85, 147, 57, 42, 16, 124, 60, 102, 11, 48, 15, 73, 88, 17, 51, 92, 6, 69, 7, 139, 11, 129, 77, 150, 33, 148, 9, 35, 0, 26, 46, 26, 59, 104, 71, 69, 5, 98, 57, 93, 32, 78, 34, 46, 60, 156, 77, 68, 77, 128, 26, 125, 86, 8, 1, 3, 68, 57, 2, 47, 44, 95, 59, 35, 59, 48, 83, 4, 41, 112, 75, 41, 24, 49, 10, 26, 41, 2, 24, 0, 4, 38, 1, 102, 16, 50, 28, 26, 14, 22, 78, 116, 86, 159, 69, 121, 83, 66, 27, 45, 62, 108, 7, 104, 82, 144, 20, 142, 25, 25, 44, 129, 78, 150, 86, 144, 31, 128, 75, 24, 61, 43, 1, 152, 70, 145, 28, 77, 30, 35, 38, 95, 63, 116, 70, 113, 87, 59, 48, 129, 69, 20, 38, 5, 43, 139, 64, 17, 13, 51, 68, 129, 32, 130, 68, 109, 43, 0, 41, 121, 67, 26, 11, 7, 20, 118, 24, 63, 35, 116, 40, 115, 59, 56, 50, 3, 4, 43, 46, 21, 88, 92, 51, 113, 84, 67, 3, 71, 49, 62, 14, 31, 89, 151, 82, 48, 23, 34, 80, 39, 38, 7, 24, 119, 25, 147, 61, 87, 47, 123, 42, 10, 83, 41, 7, 0, 46, 89, 2, 11, 54, 42, 79, 113, 13, 80, 3, 151, 22, 113, 66, 58, 48, 51, 37, 82, 58, 151, 28, 154, 65, 14, 43, 119, 58, 40, 33, 107, 20, 127, 17, 118, 1, 26, 27, 93, 87, 118, 48, 124, 39, 128, 22, 154, 68, 73, 59, 141, 46, 49, 20, 30, 83, 2, 86, 53, 86, 3, 14, 133, 77, 142, 32, 67, 72, 54, 81, 24, 5, 41, 27, 82, 56, 112, 0, 31, 73, 107, 88, 35, 69, 80, 4, 28, 33, 137, 83, 140, 8, 8, 43, 38, 65, 54, 36, 7, 57, 111, 42, 5, 2, 152, 67, 54, 23, 69, 31, 126, 6, 114, 6, 105, 7, 21, 11, 40, 34, 149, 45, 83, 58, 113, 32, 141, 69, 51, 85, 104, 6, 36, 77, 142, 83, 145, 39, 99, 3, 102, 18, 111, 58, 149, 79, 9, 23, 127, 20, 16, 68, 84, 56, 115, 0, 0, 83, 85, 59, 1, 60, 128, 2, 8, 68, 124, 83, 29, 22, 116, 39, 89, 5, 156, 12, 156, 87, 150, 83, 128, 54, 82, 29, 130, 4, 44, 13, 42, 48, 107, 68, 56, 54, 3, 65, 129, 47, 11, 51, 111, 67, 105, 33, 53, 0, 87, 54, 0, 76, 111, 0, 133, 23, 18, 29, 68, 72, 14, 18, 158, 34, 53, 68, 84, 22, 33, 49, 82, 23, 60, 51, 90, 50, 55, 51, 102, 84, 27, 32, 85, 8, 87, 28, 58, 67, 120, 52, 5, 66, 10, 56, 113, 21, 39, 36, 3, 71, 89, 44, 144, 82, 152, 61, 67, 64, 110, 49, 100, 29, 157, 32, 140, 58, 73, 42, 133, 29, 5, 46, 99, 70, 107, 32, 27, 72, 44, 17, 105, 35, 159, 85, 5, 62, 134, 87, 112, 51, 130, 34, 147, 29, 22, 54, 158, 52, 50, 48, 154, 6, 101, 47, 97, 10, 143, 15, 78, 18, 146, 38, 112, 43, 158, 42, 102, 47, 77, 45, 57, 73, 64, 70, 135, 74, 117, 21, 52, 52, 98, 86, 52, 14, 62, 86, 73, 38, 29, 68, 53, 81, 130, 56, 57, 84, 64, 76, 134, 9, 45, 16, 9, 49, 150, 20, 68, 75, 29, 38, 80, 58, 72, 43, 73, 9, 102, 3, 6, 74, 97, 69, 25, 43, 158, 27, 142, 82, 71, 31, 12, 40, 69, 82, 31, 22, 6, 59, 115, 53, 153, 69, 155, 33, 75, 13, 10, 41, 28, 19, 22, 9, 96, 4, 131, 44, 97, 72, 136, 28, 149, 61, 123, 62, 152, 34, 27, 33, 79, 83, 4, 59, 55, 42, 1, 18, 26, 69, 66, 9, 65, 63, 85, 50, 153, 74, 140, 27, 139, 41, 1, 61, 43, 84, 40, 9, 149, 51, 49, 33, 129, 86, 137, 48, 144, 61, 17, 60, 53, 78, 158, 54, 156, 18, 122, 10, 63, 60, 61, 87, 1, 89, 87, 34, 134, 47, 39, 70, 115, 41, 117, 76, 51, 38, 80, 26, 51, 74, 128, 30, 4, 70, 12, 39, 18, 19, 90, 68, 31, 67, 66, 53, 35, 26, 53, 41, 136, 14, 99, 85, 148, 44, 7, 44, 133, 27, 40, 89, 122, 26, 15, 3, 65, 54, 48, 5, 87, 63, 102, 35, 77, 85, 15, 4, 37, 14, 131, 57, 2, 88, 135, 44, 152, 9, 108, 39, 128, 78, 50, 40, 93, 52, 153, 24, 45, 37, 91, 88, 50, 23, 55, 81, 129, 72, 137, 16, 47, 36, 125, 87, 135, 20, 123, 65, 54, 62, 99, 51, 0, 11, 126, 57, 41, 57, 34, 71, 132, 18, 132, 74, 135, 17, 158, 48, 6, 80, 156, 78, 38, 54, 61, 53, 116, 71, 34, 84, 68, 10, 76, 69, 86, 85, 9, 13, 127, 81, 120, 47, 79, 85, 116, 48, 37, 17, 140, 64, 142, 59, 158, 83, 138, 6, 93, 66, 18, 52, 153, 26, 137, 34, 88, 40, 103, 47, 20, 22, 115, 40, 90, 35, 41, 53, 139, 13, 13, 39, 108, 81, 129, 49, 24, 17, 137, 24, 89, 89, 72, 6, 21, 81, 27, 31, 146, 61, 55, 24, 11, 63, 139, 45, 100, 64, 112, 7, 127, 50, 115, 15, 98, 8, 2, 26, 14, 85, 73, 2, 2, 31, 117, 3, 47, 7, 73, 22, 145, 21, 133, 24, 157, 57, 81, 4, 14, 32, 116, 4, 8, 46, 156, 47, 29, 49, 97, 66, 66, 48, 133, 25, 150, 55, 158, 66, 113, 72, 5, 17, 81, 32, 70, 8, 8, 45, 37, 83, 14, 35, 136, 8, 78, 69, 31, 44, 108, 47, 112, 18, 63, 57, 48, 1, 124, 41, 24, 7, 21, 39, 94, 85, 107, 6, 37, 45, 87, 33, 47, 80, 93, 79, 60, 70, 126, 37, 29, 2, 32, 67, 114, 5, 96, 53, 18, 11, 0, 17, 143, 41, 47, 22, 117, 34, 61, 55, 82, 67, 60, 3, 125, 73, 31, 1, 149, 67, 114, 18, 74, 13, 50, 74, 111, 31, 125, 8, 37, 27, 82, 66, 111, 29, 58, 32, 43, 68, 155, 89, 54, 74, 73, 82, 15, 7, 50, 75, 155, 29, 103, 26, 14, 11, 124, 80, 2, 11, 13, 26, 152, 52, 62, 88, 30, 81, 86, 83, 119, 77, 118, 45, 157, 19, 92, 16, 16, 17, 149, 38, 47, 88, 135, 29, 3, 30, 153, 21, 33, 25, 120, 21, 35, 8, 139, 47, 99, 69, 45, 78, 102, 8, 118, 36, 11, 65, 6, 2, 3, 58, 24, 30, 32, 56, 150, 85, 10, 85, 42, 44, 78, 49, 80, 67, 14, 17, 23, 45, 109, 64, 154, 39, 128, 17, 51, 19, 81, 49, 53, 29, 124, 61, 156, 33, 28, 79, 73, 46, 22, 72, 14, 84, 159, 59, 158, 81, 40, 65, 59, 38, 47, 39, 75, 84, 142, 38, 10, 48, 18, 64, 93, 41, 42, 54, 41, 36, 153, 83, 67, 36, 71, 84, 38, 13, 159, 9, 118, 5, 111, 17, 50, 35, 116, 44, 141, 28, 132, 43, 1, 54, 150, 74, 70, 11, 63, 87, 2, 44, 18, 49, 143, 42, 32, 35, 141, 36, 151, 6, 131, 63, 104, 89, 60, 38, 14, 77, 58, 42, 92, 62, 75, 75, 49, 78, 11, 39, 4, 1, 146, 45, 8, 28, 16, 37, 80, 56, 92, 39, 22, 70, 148, 86, 2, 79, 97, 71, 121, 30, 45, 53, 149, 64, 100, 39, 95, 70, 95, 28, 154, 70, 24, 12, 11, 78, 32, 57, 86, 30, 145, 12, 14, 88, 85, 11, 38, 86, 43, 12, 116, 25, 32, 48, 103, 61, 143, 77, 121, 19, 158, 76, 81, 1, 7, 85, 117, 44, 122, 65, 152, 84, 95, 36, 67, 85, 158, 84, 100, 1, 65, 37, 130, 59, 117, 68, 41, 41, 46, 34, 39, 46, 67, 78, 6, 67, 86, 12, 111, 32, 33, 30, 148, 83, 113, 14, 91, 83, 97, 48, 64, 3, 32, 37, 105, 47, 126, 48, 99, 27, 29, 33, 72, 62, 103, 42, 119, 2, 77, 36, 116, 50, 111, 35, 55, 23, 129, 63, 97, 44, 3, 8, 64, 7, 125, 40, 126, 31, 96, 29, 136, 5, 75, 36, 126, 49, 26, 33, 64, 53, 71, 76, 17, 44, 139, 38, 49, 4, 131, 11, 68, 24, 51, 41, 47, 79, 47, 53, 10, 68, 113, 86, 100, 14, 15, 53, 143, 56, 121, 72, 80, 73, 52, 71, 65, 57, 12, 11, 68, 27, 59, 35, 141, 4, 45, 3, 143, 57, 103, 1, 108, 67, 42, 75, 156, 52, 108, 82, 89, 43, 148, 45, 57, 74, 111, 2, 78, 50, 23, 11, 159, 29, 145, 60, 83, 5, 21, 1, 35, 87, 82, 82, 57, 10, 87, 76, 120, 25, 115, 71, 41, 89, 123, 45, 56, 31, 34, 6, 2, 64, 122, 3, 23, 59, 88, 57, 115, 16, 94, 12, 19, 42, 31, 47, 148, 12, 106, 22, 51, 50, 141, 51, 154, 71, 38, 36, 66, 58, 128, 0, 12, 0, 63, 54, 125, 36, 118, 81, 52, 7, 148, 31, 64, 16, 133, 19, 126, 82, 69, 55, 58, 71, 40, 58, 156, 16, 127, 89, 16, 67, 93, 3, 20, 17, 92, 43, 11, 23, 137, 52, 60, 53, 32, 65, 51, 89, 110, 14, 87, 27, 43, 40, 19, 52, 124, 67, 89, 9, 3, 78, 155, 10, 137, 53, 127, 82, 70, 76, 152, 37, 31, 32, 138, 57, 63, 64, 99, 23, 50, 79, 154, 67, 144, 44, 159, 46, 42, 39, 120, 23, 104, 35, 102, 43, 2, 38, 115, 46, 131, 54, 65, 13, 78, 60, 139, 31, 55, 5, 143, 29, 51, 34, 140, 19, 24, 60, 101, 46, 44, 22, 67, 71, 61, 70, 40, 66, 66, 38, 13, 17, 27, 84, 76, 28, 7, 46, 29, 70, 138, 71, 11, 48, 63, 70, 33, 6, 68, 65, 98, 2, 45, 65, 91, 20, 41, 31, 57, 11, 110, 22, 66, 41, 85, 10, 137, 74, 105, 10, 150, 9, 46, 17, 99, 74, 109, 74, 98, 61, 41, 68, 97, 25, 128, 5, 144, 42, 82, 0, 37, 86, 133, 13, 139, 89, 99, 42, 1, 51, 9, 71, 157, 62, 77, 8, 28, 48, 112, 39, 39, 80, 128, 35, 83, 74, 6, 54, 63, 27, 143, 8, 45, 74, 44, 74, 11, 50, 130, 24, 131, 19, 77, 89, 156, 88, 16, 26, 92, 78, 51, 0, 71, 86, 48, 63, 87, 32, 18, 75, 10, 6, 17, 48, 59, 37, 4, 2, 79, 24, 151, 2, 115, 28, 28, 16, 9, 51, 30, 42, 94, 8, 57, 61, 147, 55, 60, 12, 103, 0, 27, 35, 80, 7, 156, 48, 30, 28, 135, 69, 92, 79, 28, 21, 127, 23, 113, 67, 142, 26, 75, 77, 48, 33, 63, 81, 25, 46, 79, 6, 133, 66, 153, 43, 26, 20, 4, 29, 129, 5, 104, 51, 131, 3, 83, 44, 159, 64, 63, 46, 4, 54, 79, 31, 147, 34, 90, 89, 128, 63, 20, 32, 53, 83, 29, 17, 62, 58, 2, 46, 82, 3, 39, 10, 75, 86, 90, 29, 55, 60, 151, 87, 86, 9, 90, 75, 7, 25, 28, 65, 33, 48, 34, 27, 138, 14, 47, 74, 64, 77, 134, 55, 105, 70, 15, 13, 143, 28, 6, 48, 65, 12, 78, 57, 130, 7, 127, 5, 128, 72, 46, 4, 116, 47, 72, 56, 36, 2, 34, 13, 10, 32, 120, 58, 112, 13, 106, 65, 63, 15, 146, 53, 24, 4, 110, 66, 54, 47, 78, 70, 75, 88, 32, 2, 6, 50, 75, 72, 119, 40, 149, 89, 58, 75, 10, 59, 81, 0, 34, 61, 55, 87, 39, 71, 63, 51, 67, 48, 97, 19, 94, 56, 8, 41, 57, 23, 20, 36, 148, 28, 133, 65, 27, 79, 117, 8, 142, 10, 24, 33, 38, 21, 81, 36, 128, 71, 121, 0, 32, 28, 92, 27, 69, 72, 132, 37, 38, 45, 14, 57, 117, 67, 35, 43, 20, 79, 95, 65, 42, 22, 50, 14, 27, 43, 92, 30, 113, 45, 134, 16, 18, 26, 62, 78, 65, 46, 97, 40, 47, 1, 54, 45, 38, 78, 26, 77, 22, 62, 108, 13, 112, 55, 106, 59, 122, 1, 145, 74, 32, 42, 16, 33, 81, 5, 154, 12, 13, 11, 96, 12, 103, 22, 53, 34, 33, 34, 64, 55, 84, 88, 84, 58, 28, 89, 63, 68, 104, 55, 127, 45, 3, 40, 19, 58, 57, 59, 7, 3, 76, 62, 84, 14, 3, 85, 107, 19, 93, 85, 155, 24, 66, 19, 26, 21, 46, 6, 22, 86, 87, 86, 144, 46, 155, 88, 84, 50, 155, 57, 55, 84, 126, 64, 70, 68, 111, 15, 153, 72, 86, 7, 125, 72, 72, 80, 27, 77, 158, 58, 63, 40, 98, 17, 33, 71, 85, 76, 24, 36, 23, 3, 129, 89, 113, 19, 30, 13, 54, 2, 157, 31, 122, 6, 114, 16, 26, 65, 71, 44, 90, 71, 17, 8, 32, 31, 14, 15, 131, 89, 77, 38, 147, 65, 63, 75, 75, 19, 153, 47, 7, 42, 120, 45, 157, 18, 54, 61, 135, 81, 95, 82, 58, 54, 38, 85, 96, 67, 85, 74, 12, 25, 51, 72, 106, 35, 85, 54, 138, 59, 73, 74, 78, 72, 111, 57, 75, 53, 60, 14, 37, 41, 61, 3, 122, 41, 146, 3, 64, 39, 128, 50, 28, 77, 11, 19, 137, 7, 25, 66, 94, 68, 59, 84, 105, 3, 21, 19, 25, 42, 30, 62, 12, 75, 101, 13, 103, 59, 82, 25, 137, 4, 155, 47, 36, 72, 124, 10, 65, 89, 35, 71, 33, 7, 116, 12, 43, 71, 53, 72, 91, 6, 141, 50, 33, 36, 31, 24, 65, 30, 86, 29, 0, 70, 118, 0, 17, 2, 138, 3, 79, 10, 3, 43, 143, 12, 99, 33, 126, 89, 26, 40, 52, 55, 77, 83, 81, 39, 56, 88, 30, 46, 61, 16, 60, 34, 51, 26, 44, 32, 64, 25, 10, 84, 118, 7, 137, 31, 126, 26, 58, 45, 76, 41, 1, 34, 16, 74, 30, 72, 81, 80, 65, 65, 68, 4, 146, 82, 150, 39, 112, 65, 159, 40, 72, 21, 50, 53, 154, 88, 26, 84, 29, 75, 114, 71, 125, 60, 52, 39, 153, 29, 102, 6, 34, 2, 108, 37, 77, 16, 40, 48, 58, 49, 38, 51, 55, 49, 22, 55, 109, 5, 57, 12, 63, 39, 152, 80, 52, 64, 65, 3, 122, 75, 61, 86, 23, 16, 105, 65, 152, 30, 33, 20, 140, 11, 86, 47, 154, 14, 43, 59, 97, 81, 98, 77, 1, 47, 119, 55, 158, 26, 142, 67, 101, 37, 117, 50, 139, 78, 136, 85, 124, 15, 119, 57, 125, 80, 63, 38, 42, 33, 158, 67, 158, 62, 79, 17, 6, 86, 69, 43, 15, 44, 141, 8, 53, 37, 118, 56, 130, 67, 90, 48, 28, 13, 159, 23, 79, 26, 52, 74, 80, 86, 5, 82, 37, 69, 86, 54, 73, 34, 107, 0, 4, 75, 20, 66, 73, 60, 34, 10, 71, 18, 84, 24, 110, 79, 125, 4, 128, 56, 60, 89, 95, 64, 110, 2, 159, 30, 137, 22, 154, 37, 110, 42, 114, 75, 150, 63, 133, 33, 104, 60, 73, 52, 104, 3, 142, 85, 118, 66, 39, 26, 14, 23, 13, 4, 6, 41, 30, 58, 131, 59, 40, 19, 127, 73, 15, 24, 60, 77, 157, 64, 29, 43, 31, 72, 96, 41, 4, 18, 74, 59, 60, 0, 5, 78, 62, 17, 104, 46, 10, 10, 93, 73, 100, 46, 42, 84, 110, 87, 106, 43, 23, 18, 51, 53, 91, 4, 39, 65, 79, 48, 16, 14, 2, 42, 6, 53, 87, 78, 110, 65, 157, 9, 130, 3, 144, 88, 5, 51, 103, 46, 70, 4, 156, 31, 62, 70, 132, 60, 157, 55, 51, 71, 64, 62, 93, 37, 40, 40, 25, 1, 91, 10, 28, 61, 112, 87, 125, 65, 139, 63, 87, 39, 12, 73, 14, 3, 151, 67, 29, 13, 149, 17, 22, 32, 99, 40, 39, 74, 25, 27, 151, 8, 60, 62, 116, 6, 100, 62, 43, 44, 2, 82, 144, 5, 35, 53, 137, 67, 47, 43, 48, 10, 150, 16, 140, 56, 93, 81, 34, 62, 23, 68, 112, 84, 91, 52, 71, 69, 115, 24, 9, 46, 35, 48, 104, 29, 159, 32, 51, 54, 1, 28, 58, 50, 118, 80, 88, 55, 82, 37, 138, 7, 146, 54, 6, 82, 98, 49, 11, 56, 155, 48, 143, 83, 158, 59, 103, 37, 148, 1, 37, 36, 106, 4, 96, 86, 11, 52, 125, 66, 20, 80, 147, 58, 94, 34, 18, 27, 46, 67, 66, 55, 48, 65, 61, 56, 46, 48, 115, 6, 92, 0, 78, 44, 5, 36, 95, 18, 40, 64, 95, 71, 117, 14, 20, 49, 63, 25, 90, 79, 126, 3, 42, 70, 76, 22, 68, 69, 82, 38, 14, 56, 44, 20, 104, 27, 130, 73, 40, 50, 63, 17, 12, 45, 154, 0, 18, 25, 112, 23, 145, 62, 90, 81, 15, 26, 68, 0, 51, 11, 28, 37, 158, 43, 134, 46, 111, 49, 91, 32, 65, 4, 32, 69, 144, 18, 99, 4, 22, 19, 108, 79, 44, 41, 137, 28, 15, 51, 76, 40, 33, 74, 86, 77, 68, 13, 82, 13, 20, 10, 49, 77, 85, 84, 76, 50, 126, 30, 18, 9, 3, 61, 24, 41, 145, 29, 5, 10, 123, 50, 53, 20, 90, 78, 112, 36, 42, 25, 31, 0, 37, 61, 146, 69, 44, 19, 25, 69, 115, 79, 139, 27, 21, 61, 142, 6, 134, 71, 96, 25, 84, 77, 3, 46, 85, 15, 42, 26, 44, 11, 81, 71, 115, 80, 10, 11, 137, 23, 89, 49, 133, 50, 126, 17, 85, 22, 124, 9, 125, 58, 76, 65, 118, 77, 41, 76, 149, 59, 86, 68, 125, 59, 137, 33, 123, 13, 89, 10, 5, 19, 47, 15, 12, 1, 123, 23, 48, 59, 120, 87, 88, 62, 50, 3, 64, 46, 22, 30, 152, 60, 12, 46, 146, 25, 126, 61, 51, 79, 53, 19, 109, 71, 16, 16, 67, 2, 124, 27, 82, 24, 122, 23, 145, 24, 154, 13, 22, 67, 149, 33, 19, 70, 7, 67, 56, 0, 96, 34, 81, 68, 84, 72, 154, 22, 100, 49, 148, 76, 41, 69, 14, 13, 67, 42, 66, 34, 121, 81, 49, 16, 63, 41, 95, 25, 23, 52, 5, 72, 80, 72, 93, 63, 98, 26, 59, 59, 74, 88, 79, 73, 82, 26, 89, 64, 26, 50, 52, 75, 31, 71, 49, 53, 134, 27, 1, 45, 93, 12, 11, 67, 110, 54, 149, 52, 10, 26, 80, 41, 24, 45, 117, 51, 86, 75, 80, 0, 155, 39, 143, 52, 6, 15, 142, 4, 25, 45, 21, 41, 140, 26, 51, 9, 77, 44, 46, 7, 5, 76, 48, 26, 127, 28, 17, 15, 46, 29, 124, 84, 86, 36, 61, 49, 121, 58, 48, 42, 9, 45, 25, 39, 101, 43, 46, 8, 69, 64, 97, 64, 80, 80, 49, 80, 17, 64, 109, 57, 25, 40, 97, 15, 21, 28, 51, 40, 29, 85, 142, 20, 13, 54, 12, 26, 133, 15, 144, 27, 5, 22, 76, 71, 112, 76, 129, 16, 116, 43, 40, 24, 33, 50, 130, 27, 151, 25, 79, 51, 36, 62, 86, 43, 7, 28, 16, 21, 27, 4, 45, 28, 10, 57, 157, 8, 49, 89, 2, 69, 117, 46, 66, 61, 1, 22, 113, 33, 121, 13, 1, 38, 42, 12, 147, 3, 67, 65, 21, 22, 55, 76, 131, 79, 16, 86, 135, 78, 71, 57, 72, 59, 101, 48, 74, 45, 138, 60, 94, 45, 54, 44, 97, 70, 150, 68, 104, 41, 25, 74, 13, 81, 16, 64, 104, 32, 125, 19, 113, 46, 85, 36, 39, 23, 40, 79, 100, 51, 62, 37, 86, 65, 123, 61, 54, 4, 146, 14, 116, 30, 89, 58, 10, 67, 107, 83, 61, 23, 65, 14, 159, 88, 0, 87, 6, 22, 80, 11, 29, 53, 63, 78, 61, 22, 10, 20, 95, 57, 88, 87, 85, 66, 149, 39, 99, 29, 58, 17, 44, 24, 124, 11, 99, 47, 30, 17, 41, 67, 37, 50, 150, 62, 76, 21, 118, 52, 127, 16, 13, 5, 101, 3, 130, 83, 154, 41, 71, 54, 121, 34, 145, 26, 46, 47, 41, 84, 0, 80, 8, 16, 129, 23, 24, 43, 16, 13, 89, 39, 129, 57, 64, 15, 137, 30, 158, 45, 153, 80, 17, 77, 80, 76, 41, 39, 32, 8, 1, 9, 94, 40, 114, 2, 17, 59, 21, 50, 103, 52, 143, 67, 81, 76, 68, 83, 79, 47, 88, 43, 147, 84, 30, 88, 120, 48, 83, 9, 60, 56, 32, 41, 24, 3, 45, 51, 1, 29, 83, 66, 131, 0, 14, 25, 81, 60, 107, 43, 105, 78, 152, 53, 95, 67, 120, 56, 136, 79, 18, 48, 142, 76, 34, 50, 57, 24, 91, 42, 3, 38, 152, 47, 8, 27, 144, 47, 145, 9, 127, 61, 133, 58, 52, 57, 29, 41, 46, 73, 57, 89, 14, 27, 117, 79, 15, 78, 68, 45, 63, 22, 59, 69, 152, 74, 6, 10, 151, 58, 126, 65, 56, 6, 37, 80, 61, 62, 77, 56, 82, 86, 111, 37, 41, 82, 142, 29, 44, 78, 158, 18, 49, 87, 130, 88, 88, 32, 19, 85, 128, 19, 133, 78, 17, 14, 145, 7, 72, 23, 54, 50, 119, 48, 19, 46, 94, 16, 118, 4, 127, 21, 148, 46, 66, 35, 104, 86, 107, 7, 59, 83, 115, 1, 38, 84, 38, 58, 9, 11, 148, 17, 135, 47, 28, 4, 106, 72, 10, 17, 112, 24, 123, 38, 12, 18, 63, 63, 50, 30, 118, 87, 95, 69, 37, 79, 65, 66, 31, 84, 151, 18, 14, 71, 70, 36, 101, 2, 55, 55, 10, 37, 149, 65, 100, 83, 65, 11, 85, 86, 16, 58, 68, 66, 91, 9, 110, 67, 102, 1, 129, 67, 135, 32, 129, 44, 89, 26, 47, 9, 142, 66, 127, 83, 57, 25, 72, 82, 91, 56, 25, 41, 149, 82, 148, 20, 116, 62, 33, 4, 109, 66, 120, 49, 53, 11, 44, 36, 13, 51, 9, 55, 53, 49, 84, 44, 52, 29, 70, 56, 158, 20, 21, 13, 122, 21, 120, 83, 88, 66, 150, 3, 18, 2, 156, 23, 125, 54, 139, 62, 121, 46, 84, 64, 10, 1, 19, 34, 71, 17, 84, 13, 91, 26, 16, 39, 24, 8, 20, 62, 110, 26, 3, 1, 57, 30, 104, 62, 44, 27, 18, 85, 150, 17, 5, 5, 10, 16, 146, 19, 144, 80, 56, 15, 125, 33, 132, 79, 147, 18, 66, 45, 53, 70, 84, 11, 31, 14, 73, 87, 67, 35, 49, 51, 47, 66, 75, 57, 13, 25, 52, 47, 111, 83, 5, 70, 153, 65, 81, 62, 91, 81, 56, 37, 105, 4, 28, 7, 42, 52, 127, 36, 6, 17, 18, 67, 83, 73, 13, 38, 27, 37, 8, 56, 88, 81, 150, 26, 133, 74, 145, 8, 26, 13, 130, 23, 111, 79, 134, 1, 45, 17, 107, 25, 24, 47, 98, 39, 125, 17, 159, 50, 26, 29, 110, 59, 78, 28, 5, 65, 156, 51, 71, 39, 67, 62, 131, 22, 52, 4, 86, 60, 91, 76, 38, 4, 26, 73, 150, 56, 84, 76, 46, 14, 8, 21, 115, 20, 43, 83, 48, 77, 81, 8, 82, 84, 107, 17, 58, 76, 65, 60, 83, 13, 75, 82, 140, 48, 41, 1, 67, 68, 124, 22, 46, 89, 67, 21, 16, 2, 107, 87, 146, 10, 47, 63, 9, 89, 21, 70, 21, 30, 27, 7, 124, 24, 125, 41, 154, 64, 146, 63, 95, 2, 0, 77, 32, 34, 81, 6, 21, 35, 104, 73, 9, 6, 121, 63, 106, 80, 93, 25, 100, 65, 32, 38, 45, 79, 17, 72, 137, 61, 50, 1, 27, 89, 154, 76, 72, 69, 158, 32, 144, 11, 15, 30, 110, 80, 53, 53, 128, 7, 69, 52, 66, 72, 118, 39, 44, 5, 77, 46, 159, 11, 33, 43, 43, 53, 91, 67, 7, 32, 145, 65, 12, 58, 39, 73, 80, 64, 139, 76, 120, 78, 94, 57, 152, 42, 97, 30, 138, 47, 106, 88, 1, 74, 0, 23, 91, 69, 154, 47, 0, 1, 46, 74, 135, 38, 139, 58, 2, 81, 132, 73, 133, 35, 64, 87, 7, 19, 4, 72, 3, 45, 105, 28, 62, 48, 2, 15, 138, 29, 7, 50, 117, 11, 50, 59, 155, 36, 90, 59, 99, 46, 42, 6, 48, 44, 97, 16, 55, 26, 113, 4, 36, 22, 53, 28, 149, 70, 150, 44, 122, 44, 105, 55, 157, 47, 9, 26, 105, 76, 55, 74, 105, 39, 10, 74, 97, 79, 59, 20, 76, 61, 24, 83, 74, 75, 47, 47, 140, 74, 115, 67, 129, 28, 57, 48, 120, 24, 43, 27, 78, 48, 42, 9, 153, 19, 20, 9, 86, 32, 3, 3, 144, 66, 71, 67, 68, 16, 93, 50, 154, 15, 41, 56, 155, 12, 112, 21, 78, 11, 71, 0, 19, 16, 115, 11, 105, 43, 69, 14, 154, 23, 68, 82, 80, 21, 72, 76, 8, 58, 114, 32, 82, 50, 58, 12, 62, 62, 23, 0, 67, 19, 3, 60, 128, 66, 14, 87, 52, 50, 107, 51, 153, 13, 149, 16, 92, 40, 14, 21, 111, 56, 37, 62, 49, 31, 122, 16, 71, 34, 136, 37, 52, 56, 95, 6, 88, 79, 104, 25, 154, 46, 43, 82, 142, 69, 128, 4, 155, 7, 141, 39, 82, 8, 72, 78, 92, 15, 76, 57, 41, 75, 158, 5, 22, 1, 13, 13, 156, 71, 26, 89, 25, 81, 134, 83, 18, 28, 1, 65, 102, 13, 147, 73, 136, 83, 142, 58, 43, 31, 28, 10, 29, 56, 61, 35, 141, 61, 154, 63, 84, 38, 2, 45, 14, 40, 68, 48, 124, 57, 124, 70, 140, 37, 90, 67, 68, 68, 115, 61, 142, 57, 44, 12, 95, 14, 98, 68, 99, 78, 86, 21, 89, 52, 7, 9, 85, 70, 134, 41, 14, 46, 90, 55, 19, 36, 73, 57, 111, 30, 134, 65, 69, 73, 60, 81, 29, 58, 38, 26, 157, 17, 107, 10, 90, 66, 62, 11, 115, 38, 27, 57, 85, 61, 97, 3, 19, 53, 70, 60, 50, 16, 78, 29, 156, 45, 119, 16, 80, 34, 94, 79, 37, 1, 40, 85, 98, 76, 92, 75, 29, 37, 152, 6, 11, 5, 158, 88, 23, 49, 158, 85, 120, 13, 30, 0, 127, 2, 88, 25, 108, 56, 87, 79, 111, 88, 61, 58, 55, 68, 83, 50, 44, 76, 130, 26, 23, 89, 18, 88, 100, 32, 136, 56, 8, 60, 96, 89, 76, 51, 105, 83, 40, 69, 152, 26, 157, 69, 127, 34, 114, 68, 151, 83, 33, 68, 56, 49, 155, 0, 48, 56, 99, 57, 8, 88, 100, 28, 103, 71, 17, 69, 129, 18, 15, 20, 138, 23, 20, 13, 159, 68, 135, 63, 67, 32, 156, 34, 31, 19, 46, 57, 42, 41, 116, 61, 26, 6, 79, 70, 36, 13, 41, 64, 21, 12, 98, 4, 11, 28, 133, 32, 155, 60, 131, 87, 9, 33, 124, 16, 129, 73, 138, 68, 35, 60, 66, 2, 33, 62, 116, 1, 157, 71, 67, 43, 112, 2, 75, 46, 145, 57, 40, 11, 79, 9, 73, 61, 22, 85, 23, 4, 78, 68, 29, 77, 145, 79, 120, 85, 105, 51, 120, 40, 94, 86, 21, 79, 35, 88, 3, 56, 7, 18, 94, 77, 41, 44, 37, 35, 133, 45, 151, 52, 97, 39, 57, 32, 36, 49, 88, 48, 65, 36, 15, 60, 55, 67, 77, 87, 70, 45, 74, 60, 47, 69, 46, 50, 94, 75, 120, 17, 51, 55, 146, 85, 57, 20, 3, 42, 2, 12, 78, 41, 77, 43, 82, 16, 34, 7, 98, 7, 47, 19, 86, 67, 100, 68, 144, 76, 103, 85, 156, 86, 69, 22, 3, 10, 122, 74, 116, 34, 63, 52, 107, 75, 127, 15, 56, 12, 158, 60, 18, 17, 130, 12, 136, 72, 20, 39, 158, 8, 40, 83, 157, 35, 133, 62, 102, 39, 108, 2, 49, 44, 114, 81, 88, 8, 140, 60, 19, 83, 1, 25, 92, 13, 156, 32, 81, 10, 71, 29, 73, 32, 115, 73, 13, 76, 53, 89, 62, 47, 63, 44, 15, 70, 84, 67, 141, 57, 57, 39, 131, 70, 1, 64, 159, 77, 34, 4, 150, 50, 121, 54, 70, 34, 82, 78, 101, 29, 141, 34, 18, 60, 29, 6, 69, 18, 95, 81, 11, 74, 140, 42, 3, 64, 93, 84, 74, 47, 88, 29, 20, 71, 88, 50, 158, 78, 146, 22, 72, 34, 76, 17, 7, 66, 84, 31, 114, 15, 57, 31, 30, 50, 153, 31, 135, 14, 75, 51, 114, 36, 38, 75, 61, 69, 25, 8, 144, 22, 139, 73, 17, 24, 151, 89, 107, 80, 25, 30, 66, 50, 143, 59, 9, 28, 146, 36, 20, 53, 143, 66, 131, 67, 134, 75, 41, 72, 71, 19, 43, 62, 55, 31, 118, 28, 146, 71, 55, 32, 108, 24, 77, 42, 123, 39, 101, 36, 33, 59, 144, 43, 30, 2, 64, 2, 14, 61, 127, 24, 131, 55, 144, 34, 149, 40, 88, 61, 34, 35, 1, 75, 19, 73, 113, 54, 65, 56, 52, 25, 48, 36, 134, 63, 32, 66, 33, 9, 139, 85, 56, 81, 38, 24, 12, 14, 155, 27, 133, 70, 34, 72, 75, 11, 9, 19, 40, 82, 130, 57, 35, 36, 103, 18, 30, 35, 137, 65, 111, 63, 124, 63, 98, 85, 31, 3, 28, 68, 136, 67, 125, 88, 102, 66, 95, 42, 76, 43, 89, 36, 93, 21, 62, 42, 91, 84, 69, 16, 149, 24, 34, 56, 114, 39, 23, 71, 5, 85, 81, 24, 41, 6, 151, 7, 126, 51, 11, 84, 20, 4, 7, 10, 46, 76, 51, 62, 149, 57, 62, 67, 51, 45, 121, 31, 151, 80, 86, 62, 41, 52, 46, 39, 39, 77, 11, 43, 116, 9, 11, 42, 26, 28, 78, 89, 100, 11, 24, 32, 98, 30, 76, 48, 36, 67, 33, 55, 30, 1, 74, 43, 146, 64, 72, 28, 36, 0, 28, 74, 20, 69, 52, 65, 69, 24, 28, 56, 27, 10, 82, 81, 39, 75, 0, 58, 47, 73, 125, 13, 2, 33, 112, 40, 56, 9, 149, 44, 65, 87, 82, 34, 20, 31, 124, 69, 2, 16, 96, 21, 133, 76, 100, 75, 80, 28, 106, 46, 22, 73, 124, 46, 83, 10, 28, 70, 126, 74, 8, 29, 111, 59, 9, 73, 88, 68, 45, 80, 77, 41, 61, 71, 37, 9, 38, 38, 43, 70, 105, 85, 125, 3, 35, 89, 62, 80, 50, 41, 97, 82, 139, 25, 123, 29, 110, 47, 44, 81, 76, 20, 104, 80, 44, 72, 19, 7] \ No newline at end of file diff --git a/rustplus_old/api/remote/camera/camera_manager.py b/rustplus_old/api/remote/camera/camera_manager.py deleted file mode 100644 index 799ca77..0000000 --- a/rustplus_old/api/remote/camera/camera_manager.py +++ /dev/null @@ -1,175 +0,0 @@ -import time -from typing import Iterable, Union, List, Coroutine, Set, Callable - -from PIL import Image - -from .camera_parser import Parser -from ..rustplus_proto import ( - AppCameraInput, - Vector2, - AppEmpty, - AppRequest, - AppCameraInfo, -) -from ...structures import Vector -from .structures import CameraInfo, Entity, LimitedQueue - - -class CameraManager: - def __init__( - self, rust_socket, cam_id: str, cam_info_message: AppCameraInfo - ) -> None: - self.rust_socket = rust_socket - self._cam_id: str = cam_id - self._last_packets: LimitedQueue = LimitedQueue(6) - self._cam_info_message: CameraInfo = CameraInfo(cam_info_message) - self._open: bool = True - self.parser: Parser = Parser( - self._cam_info_message.width, self._cam_info_message.height - ) - self.time_since_last_subscribe: float = time.time() - self.frame_callbacks: Set[Callable[[Image.Image], Coroutine]] = set() - - async def add_packet(self, packet) -> None: - self._last_packets.add(packet) - - if len(self.frame_callbacks) == 0: - return - - frame = await self._create_frame() - - for callback in self.frame_callbacks: - await callback(frame) - - def on_frame_received( - self, coro: Callable[[Image.Image], Coroutine] - ) -> Callable[[Image.Image], Coroutine]: - self.frame_callbacks.add(coro) - return coro - - def has_frame_data(self) -> bool: - return self._last_packets is not None and len(self._last_packets) > 0 - - async def _create_frame( - self, - render_entities: bool = True, - entity_render_distance: float = float("inf"), - max_entity_amount: int = float("inf"), - ) -> Union[Image.Image, None]: - if self._last_packets is None: - return None - - if len(self._last_packets) == 0: - return None - - if not self._open: - raise Exception("Camera is closed") - - for i in range(len(self._last_packets)): - self.parser.handle_camera_ray_data(self._last_packets.get(i)) - self.parser.step() - - last_packet = self._last_packets.get_last() - - self._last_packets.clear() - self._last_packets.add(last_packet) - - return self.parser.render( - render_entities, - last_packet.entities, - last_packet.vertical_fov, - self._cam_info_message.far_plane, - entity_render_distance, - ( - max_entity_amount - if max_entity_amount is not None - else len(self._last_packets.get_last().entities) - ), - ) - - async def get_frame( - self, - render_entities: bool = True, - entity_render_distance: float = float("inf"), - max_entity_amount: int = float("inf"), - ) -> Union[Image.Image, None]: - return await self._create_frame( - render_entities, entity_render_distance, max_entity_amount - ) - - def can_move(self, control_type: int) -> bool: - return self._cam_info_message.is_move_option_permissible(control_type) - - async def clear_movement(self) -> None: - await self.send_combined_movement() - - async def send_actions(self, actions: Iterable[int]) -> None: - await self.send_combined_movement(actions) - - async def send_mouse_movement(self, mouse_delta: Vector) -> None: - await self.send_combined_movement(joystick_vector=mouse_delta) - - async def send_combined_movement( - self, movements: Iterable[int] = None, joystick_vector: Vector = None - ) -> None: - if joystick_vector is None: - joystick_vector = Vector() - - if movements is None: - movements = [] - - value = 0 - for movement in movements: - value = value | movement - - await self.rust_socket._handle_ratelimit(0.01) - app_request: AppRequest = self.rust_socket._generate_protobuf() - cam_input = AppCameraInput() - - cam_input.buttons = value - vector = Vector2() - vector.x = joystick_vector.x - vector.y = joystick_vector.y - cam_input.mouse_delta = vector - app_request.camera_input = cam_input - - await self.rust_socket.remote.send_message(app_request) - await self.rust_socket.remote.add_ignored_response(app_request.seq) - - async def exit_camera(self) -> None: - await self.rust_socket._handle_ratelimit() - app_request: AppRequest = self.rust_socket._generate_protobuf() - app_request.camera_unsubscribe = AppEmpty() - - await self.rust_socket.remote.send_message(app_request) - await self.rust_socket.remote.add_ignored_response(app_request.seq) - - self._open = False - self._last_packets.clear() - - async def resubscribe(self) -> None: - await self.rust_socket.remote.subscribe_to_camera(self._cam_id, True) - self.time_since_last_subscribe = time.time() - self._open = True - self.rust_socket.remote.camera_manager = self - - async def get_entities_in_frame(self) -> List[Entity]: - if self._last_packets is None: - return [] - - if len(self._last_packets) == 0: - return [] - - return self._last_packets.get_last().entities - - async def get_distance_from_player(self) -> float: - if self._last_packets is None: - return float("inf") - - if len(self._last_packets) == 0: - return float("inf") - - return self._last_packets.get_last().distance - - async def get_max_distance(self) -> float: - return self._cam_info_message.far_plane diff --git a/rustplus_old/api/remote/camera/camera_parser.py b/rustplus_old/api/remote/camera/camera_parser.py deleted file mode 100644 index c084e9f..0000000 --- a/rustplus_old/api/remote/camera/camera_parser.py +++ /dev/null @@ -1,785 +0,0 @@ -import math -from importlib import resources -from math import radians, tan -import random -from typing import Union, Tuple, List, Any, Dict -import numpy as np -from scipy.spatial import ConvexHull -from PIL import Image, ImageDraw, ImageFont - -from .camera_constants import LOOKUP_CONSTANTS -from .structures import Entity, Vector3 - -SCIENTIST_COLOUR = "#3098f2" -PLAYER_COLOUR = "#fa2828" -TREE_COLOUR = "#03ad15" -FONT_PATH = "rustplus.utils.fonts" - - -class Parser: - def __init__(self, width: int, height: int) -> None: - self.width = width - self.height = height - self.data_pointer = 0 - self._rays = None - self._ray_lookback = [[0 for _ in range(3)] for _ in range(64)] - self._sample_offset = 0 - self.colours = [ - (127, 127, 127), - (204, 178, 178), - (76, 178, 255), - (153, 153, 153), - (178, 178, 178), - (204, 153, 102), - (255, 102, 102), - (255, 25, 25), - ] - - self.scale_factor = 6 - self.colour_output = None - self.depth_output = None - - self.reset_output() - - self.entities = [] - self.last_fov = 0 - - def reset_output(self) -> None: - self.colour_output = np.full( - (self.width * self.scale_factor, self.height * self.scale_factor, 3), - np.array([208, 230, 252]), - ) - self.depth_output = np.zeros( - (self.width * self.scale_factor, self.height * self.scale_factor) - ) - - def handle_camera_ray_data(self, data) -> None: - if data is None: - return - - self._rays = data - self.data_pointer = 0 - self._sample_offset = 2 * data.sample_offset - while self._sample_offset >= 2 * self.width * self.height: - self._sample_offset -= 2 * self.width * self.height - self._ray_lookback = [[0 for _ in range(3)] for _ in range(64)] - - def step(self) -> None: - if self._rays is None: - return - - while True: - if self.process_rays_batch(): - self._rays = None - break - - def process_rays_batch(self) -> bool: - if self._rays is None: - return True - - for h in range(100): - if self.data_pointer >= len(self._rays.ray_data) - 1: - return True - - ray = self.next_ray(self._rays.ray_data) - - while self._sample_offset >= 2 * self.width * self.height: - self._sample_offset -= 2 * self.width * self.height - - distance = ray[0] - alignment = ray[1] - material = ray[2] - - index1 = LOOKUP_CONSTANTS[self._sample_offset] - self._sample_offset += 1 - index2 = int(LOOKUP_CONSTANTS[self._sample_offset] * self.width + index1) - self._sample_offset += 1 - - x = (index2 % self.width) * self.scale_factor - y = ( - (self.width * self.height - 1 - index2) // self.width - ) * self.scale_factor - - if ( - not (distance == 1 and alignment == 0 and material == 0) - and material != 7 - ): - self.colour_output[ - x : x + self.scale_factor, y : y + self.scale_factor - ] = MathUtils._convert_colour( - ( - (colour := self.colours[material])[0], - colour[1], - colour[2], - alignment, - ) - ) - - else: - self.colour_output[ - x : x + self.scale_factor, y : y + self.scale_factor - ] = (208, 230, 252) - distance = float("inf") - - self.depth_output[x : x + self.scale_factor, y : y + self.scale_factor] = ( - distance - ) - - return False - - def next_ray(self, ray_data) -> List[Union[float, int]]: - byte = ray_data[self.data_pointer] - self.data_pointer += 1 - - if byte == 255: - second_byte = ray_data[self.data_pointer] - self.data_pointer += 1 - third_byte = ray_data[self.data_pointer] - self.data_pointer += 1 - fourth_byte = ray_data[self.data_pointer] - self.data_pointer += 1 - - t = (second_byte << 2) | (third_byte >> 6) - r = 63 & third_byte - i = fourth_byte - - u = (3 * (int(t / 128) | 0) + 5 * (int(r / 16) | 0) + 7 * i) & 63 - self._ray_lookback[u][0] = t - self._ray_lookback[u][1] = r - self._ray_lookback[u][2] = i - - else: - c = 192 & byte - - if c == 0: - h = 63 & byte - y = self._ray_lookback[h] - t = y[0] - r = y[1] - i = y[2] - - elif c == 64: - p = 63 & byte - v = self._ray_lookback[p] - b = v[0] - w = v[1] - x = v[2] - g = ray_data[self.data_pointer] - self.data_pointer += 1 - t = b + ((g >> 3) - 15) - r = w + ((7 & g) - 3) - i = x - - elif c == 128: - R = 63 & byte - C = self._ray_lookback[R] - I = C[0] - P = C[1] - k = C[2] - - t = I + (ray_data[self.data_pointer] - 127) - self.data_pointer += 1 - r = P - i = k - - else: - A = ray_data[self.data_pointer] - self.data_pointer += 1 - F = ray_data[self.data_pointer] - self.data_pointer += 1 - - t = (A << 2) | (F >> 6) - r = 63 & F - i = 63 & byte - - D = (3 * (int(t / 128) | 0) + 5 * (int(r / 16) | 0) + 7 * i) & 63 - self._ray_lookback[D][0] = t - self._ray_lookback[D][1] = r - self._ray_lookback[D][2] = i - - return [t / 1023, r / 63, i] - - def handle_entities( - self, - image_draw: ImageDraw, - image_data: Any, - entities: List[Entity], - cam_fov: float, - depth_data: Any, - far_plane: float, - width: int, - height: int, - entity_render_distance: float, - max_entity_amount: int, - ) -> Any: - image_data = np.array(image_data) - - players = [player for player in entities if player.type == 2] - trees = [tree for tree in entities if tree.type == 1] - - tree_amount = max_entity_amount - len(players) - target_trees = [] - - if len(trees) < tree_amount: - target_trees = trees - - else: - if self.last_fov == cam_fov: - for entity in self.entities: - # Entity is an entity id and we should try and find it in the trees list - for tree in trees: - if tree.entity_id == entity: - target_trees.append(tree) - break - - if len(target_trees) < tree_amount: - random.shuffle(trees) - target_trees += trees[: tree_amount - len(target_trees)] - - self.entities = [tree.entity_id for tree in target_trees] - self.last_fov = cam_fov - - entities = players + target_trees - entities.sort(key=lambda e: e.position.z, reverse=True) - - # position, rotation, size of camera - cam_pos = np.array([0, 0, 0]) - cam_rot = np.array([0, 0, 0]) - cam_near = 0.01 - cam_far = 1000 - - # aspect ratio of the image - aspect_ratio = width / height - - view_matrix = MathUtils.camera_matrix(cam_pos, cam_rot) - projection_matrix = MathUtils.perspective_matrix( - cam_fov, aspect_ratio, cam_near, cam_far - ) - - text = set() - - for entity in entities: - if entity.position.z > entity_render_distance and entity.type == 1: - continue - - Parser.handle_entity( - entity, - image_draw, - cam_pos, - projection_matrix, - view_matrix, - image_data, - depth_data, - width, - height, - cam_near, - cam_far, - far_plane, - cam_fov, - aspect_ratio, - text, - ) - - return text, image_data - - @staticmethod - def handle_entity( - entity, - image_draw, - cam_pos, - projection_matrix, - view_matrix, - image_data, - depth_data, - width, - height, - cam_near, - cam_far, - far_plane, - cam_fov, - aspect_ratio, - text, - ) -> None: - entity.size.x = min(entity.size.x, 5) - entity.size.y = min(entity.size.y, 5) - entity.size.z = min(entity.size.z, 5) - - entity_pos = np.array( - [ - entity.position.x, - entity.position.y + (2 if entity.type == 1 else 0), - entity.position.z, - 0, - ] - ) - entity_rot = np.array( - [entity.rotation.x, entity.rotation.y, entity.rotation.z, 0] - ) - entity_size = np.array([entity.size.x, entity.size.y, entity.size.z, 0]) - - vertices = ( - MathUtils.get_player_vertices(entity.size) - if entity.type == 2 - else MathUtils.get_tree_vertices(entity.size) - ) - # Add the position for the name tag to the vertices - vertices = np.append(vertices, [np.array([0, 1.3, 0, 1])], axis=0) - - model_matrix = np.matmul( - np.matmul( - MathUtils.translation_matrix(entity_pos), - MathUtils.rotation_matrix(entity_rot), - ), - MathUtils.scale_matrix(entity_size), - ) - - # Add rotation to face the camera - cam_direction = cam_pos - entity_pos[:3] - cam_direction[1] = 0 - cam_angle = np.arctan2(cam_direction[2], cam_direction[0]) - cam_rotation_matrix = MathUtils.rotation_matrix([0, cam_angle, 0, 0]) - model_matrix = np.matmul(model_matrix, cam_rotation_matrix) - - mvp_matrix = np.matmul(np.matmul(projection_matrix, view_matrix), model_matrix) - - # Calculate the transformed vertices - transformed_vertices = np.matmul(mvp_matrix, vertices.T).T - - # Normalize the transformed vertices and calculate pixel coordinates - pixel_coords = tuple( - map( - tuple, - np.round( - ( - (transformed_vertices[:, :2] / transformed_vertices[:, 3, None]) - * np.array([width, -height]) - / 2 - ) - + np.array([width, height]) / 2 - ).astype(np.int32), - ) - ) - - # Remove the last element of the pixel_coords array - name_place = pixel_coords[-1] - pixel_coords = pixel_coords[:-1] - - colour = ( - (PLAYER_COLOUR if not entity.name.isdigit() else SCIENTIST_COLOUR) - if entity.type == 2 - else MathUtils.get_slightly_random_colour(TREE_COLOUR, entity.position) - ) - - MathUtils.set_polygon_with_depth( - MathUtils.gift_wrap_algorithm(pixel_coords), - image_data, - depth_data, - math.sqrt( - entity.position.x**2 + entity.position.y**2 + entity.position.z**2 - ), - colour, - width, - height, - far_plane, - ) - - if entity.type == 2: - font_size = max( - MathUtils.get_font_size( - entity.position.z, 250, cam_near, cam_far, aspect_ratio, cam_fov - ), - 1, - ) - # The font size should be proportional to the size of the entity as it gets further away - with resources.path(FONT_PATH, "PermanentMarker.ttf") as path: - font = ImageFont.truetype(str(path), font_size) - size = image_draw.textsize(entity.name, font=font) - - name_place1 = ( - name_place[0] - size[0] // 2, - name_place[1] - size[1] // 2, - ) - text.add((name_place1, entity.name, font)) - - def render( - self, - render_entities: bool, - entities: List[Entity], - fov: float, - far_plane: float, - entity_render_distance: float, - max_entity_amount: int, - ) -> Image.Image: - # We have the output array filled with RayData objects - # We can get the material at each pixel and use that to get the colour - # We can then use the alignment to get the alpha value - - image = Image.new( - "RGBA", - (self.width * self.scale_factor, self.height * self.scale_factor), - (0, 0, 0), - ) - draw = ImageDraw.Draw(image) - - if not render_entities: - entities = [] - - text, image_data = self.handle_entities( - draw, - self.colour_output, - entities, - fov, - self.depth_output, - far_plane, - image.size[0], - image.size[1], - entity_render_distance, - max_entity_amount, - ) - image_data = image_data.astype("uint8") - - # transpose the array - transposed_arr = image_data.transpose((1, 0, 2)) - - # This doesn't work: - image = Image.fromarray(transposed_arr, "RGB") - - draw = ImageDraw.Draw(image) - for pos, name, font in text: - draw.text(pos, name, font=font, fill="black") - - return image - - -class MathUtils: - VERTEX_CACHE: Dict[Vector3, np.ndarray] = {} - COLOUR_CACHE: Dict[Tuple[float, float, float, float], Tuple[int, int, int]] = {} - - @staticmethod - def camera_matrix(position, rotation) -> np.ndarray: - matrix = np.matmul( - MathUtils.rotation_matrix(rotation), MathUtils.translation_matrix(-position) - ) - return np.linalg.inv(matrix) - - @staticmethod - def scale_matrix(size) -> np.ndarray: - return np.array( - [[size[0], 0, 0, 0], [0, size[1], 0, 0], [0, 0, size[2], 0], [0, 0, 0, 1]] - ) - - @staticmethod - def rotation_matrix(rotation) -> np.ndarray: - pitch = rotation[0] - yaw = rotation[1] - roll = rotation[2] - - rotation_x = np.array( - [ - [1, 0, 0, 0], - [0, np.cos(pitch), -np.sin(pitch), 0], - [0, np.sin(pitch), np.cos(pitch), 0], - [0, 0, 0, 1], - ] - ) - - rotation_y = np.array( - [ - [np.cos(yaw), 0, np.sin(yaw), 0], - [0, 1, 0, 0], - [-np.sin(yaw), 0, np.cos(yaw), 0], - [0, 0, 0, 1], - ] - ) - - rotation_z = np.array( - [ - [np.cos(roll), -np.sin(roll), 0, 0], - [np.sin(roll), np.cos(roll), 0, 0], - [0, 0, 1, 0], - [0, 0, 0, 1], - ] - ) - - return np.matmul(np.matmul(rotation_x, rotation_y), rotation_z) - - @staticmethod - def translation_matrix(position) -> np.ndarray: - return np.array( - [ - [1, 0, 0, position[0]], - [0, 1, 0, position[1]], - [0, 0, 1, -position[2]], - [0, 0, 0, 1], - ] - ) - - @staticmethod - def perspective_matrix(fov, aspect_ratio, near, far) -> np.ndarray: - f = 1 / tan(radians(fov) / 2) - return np.array( - [ - [f / aspect_ratio, 0, 0, 0], - [0, f, 0, 0], - [0, 0, (far + near) / (near - far), 2 * far * near / (near - far)], - [0, 0, -1, 0], - ] - ) - - @staticmethod - def gift_wrap_algorithm(vertices) -> List[Tuple[float, float]]: - data = np.array(vertices) - - # Check that the min and max are not the same - if ( - data.max(axis=0)[0] == data.min(axis=0)[0] - or data.max(axis=0)[1] == data.min(axis=0)[1] - ): - return [] - - # use convex hull algorithm to find the convex hull from scipy - hull = ConvexHull(data) - # get the vertices of the convex hull - return [tuple(data[i]) for i in hull.vertices] - - @classmethod - def _convert_colour( - cls, - colour: Tuple[float, float, float, float], - ) -> Tuple[int, int, int]: - if colour in cls.COLOUR_CACHE: - return cls.COLOUR_CACHE[colour] - - colour = ( - int(colour[3] * colour[0]), - int(colour[3] * colour[1]), - int(colour[3] * colour[2]), - ) - - cls.COLOUR_CACHE[colour] = colour - return colour - - @staticmethod - def solve_quadratic(a: float, b: float, c: float, larger: bool) -> float: - """ - Solves a quadratic equation but only returns either the larger or smaller root depending on the larger parameter - """ - if a == 0: - return -c / b - - discriminant = b**2 - 4 * a * c - - if discriminant < 0: - return 0 - - if larger: - return (-b + math.sqrt(discriminant)) / (2 * a) - else: - return (-b - math.sqrt(discriminant)) / (2 * a) - - @classmethod - def get_tree_vertices(cls, size) -> np.ndarray: - if size in cls.VERTEX_CACHE: - return cls.VERTEX_CACHE[size] - - number_of_segments = 14 - segment_angle = (2 * math.pi) / number_of_segments - - vertex_list = [] - - for x_value in [size.y / 8, -size.y / 8]: - for i in range(number_of_segments): - angle = segment_angle * i - - z = math.sin(angle) * abs(x_value) - new_x = math.cos(angle) * abs(x_value) - - vertex_list.append([new_x, 0, z, 1]) - - vertex_list.append([0, size.y / 2, 0, 1]) - - vertices = np.array(vertex_list) - cls.VERTEX_CACHE[size] = vertices - return vertices - - @classmethod - def get_player_vertices(cls, size) -> np.ndarray: - if size in cls.VERTEX_CACHE: - return cls.VERTEX_CACHE[size] - - number_of_segments = 14 - segment_angle = (2 * math.pi) / number_of_segments - - vertex_list1 = [] - vertex_list2 = [] - - # The vertices of the pill - height = size.y + 0.3 - width = 0.5 * size.x**size.z - increment = 0.1 - - x = 0 - while x <= width: - for offset in range(-1, 2, 2): - x_value = x * offset - - # Use the quadratic formula to find the y values of the top and bottom of the pill - y1 = MathUtils.solve_quadratic( - 1, -2 * 0.5, x_value**2 + 0.5**2 - 0.5**2, False - ) - y2 = MathUtils.solve_quadratic( - 1, - -2 * (height - 0.5), - x_value**2 + (height - 0.5) ** 2 - 0.5**2, - True, - ) - - if y1 == 0 or y2 == 0: - x_value += increment - continue - - for i in range(number_of_segments): - angle = segment_angle * i - - z = math.sin(angle) * abs(x_value) - new_x = math.cos(angle) * abs(x_value) - - vertex_list1.append([new_x, y1 / 2, z, 1]) - vertex_list2.append([new_x, y2 / 2, z, 1]) - - # when x is greater than 4/5 of the width, decrease the increment - if x > 0.8 * width: - increment = 0.001 - - x += increment - - vertices = np.array(vertex_list1 + vertex_list2[::-1]) - cls.VERTEX_CACHE[size] = vertices - return vertices - - @staticmethod - def get_slightly_random_colour(colour: str, entity_pos: Vector3) -> str: - """ - Returns a slightly randomised version of the colour passed in - Must be the same colour for the same entity id - """ - - r, g, b = int(colour[1:3], 16), int(colour[3:5], 16), int(colour[5:7], 16) - - # Create an algorithm will slightly vary the colour based on the distance from the origin - # This is to make it easier to distinguish between entities - - distance_squared = entity_pos.x**2 + entity_pos.y**2 + 2 * entity_pos.z**2 - - r += int(distance_squared * 0.0003) % 10 - g += int(distance_squared * 0.0003) % 10 - b += int(distance_squared * 0.0003) % 10 - - return f"#{r}{g}{b}" - - @staticmethod - def get_font_size(distance, font_size, near, far, aspect_ratio, fov) -> int: - """ - Given the distance from the screen, uses perspective projection matrix to return a font size for some text. - - Args: - distance (float): Distance from the screen in meters - text (str): Text to calculate font size for - font_size (int): Base font size in pixels - screen_width (int): Width of the screen in pixels - screen_height (int): Height of the screen in pixels - - Returns: - int: Font size in pixels - """ - f = 1.0 / np.tan(np.deg2rad(fov / 2.0)) - projection_matrix = np.array( - [ - [f / aspect_ratio, 0.0, 0.0, 0.0], - [0.0, f, 0.0, 0.0], - [ - 0.0, - 0.0, - (far + near) / (near - far), - 2.0 * far * near / (near - far), - ], - [0.0, 0.0, -1.0, 0.0], - ] - ) - - # Define the modelview matrix based on the distance from the screen - modelview_matrix = np.array( - [ - [1.0, 0.0, 0.0, 0.0], - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 1.0, -distance], - [0.0, 0.0, 0.0, 1.0], - ] - ) - - # Calculate the projection of the text onto the screen - text_projection = projection_matrix @ modelview_matrix - projected_text = np.array([font_size, 0, 0, 1]) @ text_projection - projected_text /= projected_text[3] - projected_size = projected_text[0] - - return int(projected_size) - - @staticmethod - def set_polygon_with_depth( - vertices, image_data, depth_data, depth, colour, width, height, far_plane - ) -> None: - if len(vertices) <= 1: - return - - colour = MathUtils.convert_colour_to_tuple(colour) - - pixels = MathUtils.get_vertices_in_polygon(vertices, width, height) - - if len(pixels) == 0: - return - - pixels = pixels[ - (pixels[:, 0] >= 0) - & (pixels[:, 0] < depth_data.shape[0]) - & (pixels[:, 1] >= 0) - & (pixels[:, 1] < depth_data.shape[1]) - ] - - # Get all pixels where depth_data[x, y] * far_plane > depth is true - pixels = pixels[ - depth_data[pixels[:, 0], pixels[:, 1]] * far_plane > depth - 0.5 - ] - - # Set the pixels to the colour - image_data[pixels[:, 0], pixels[:, 1]] = colour - - @staticmethod - def convert_colour_to_tuple(colour) -> Tuple[int, int, int]: - """ - Converts a colour in the form - #RRGGBB - to a tuple of the form - (R, G, B) - """ - return int(colour[1:3], 16), int(colour[3:5], 16), int(colour[5:7], 16) - - @staticmethod - def get_vertices_in_polygon(vertices, width, height) -> np.ndarray: - """ - Takes a list of vertices and returns the vertices that are inside the polygon defined by the vertices - vertices is a list of vertices in the form [x, y] - width and height specify the size of the bounding box around the polygon - """ - # Create an image mask for the polygon - mask = Image.new("L", (width, height), 0) - ImageDraw.Draw(mask).polygon(vertices, outline=1, fill=1) - - # Convert the mask to a NumPy array - mask_arr = np.array(mask) - - # Find the indices of the non-zero values in the mask array - y, x = np.nonzero(mask_arr) - - # Return the vertices that correspond to the non-zero indices - return np.array(list(zip(x, y))) diff --git a/rustplus_old/api/remote/camera/structures.py b/rustplus_old/api/remote/camera/structures.py deleted file mode 100644 index a04034c..0000000 --- a/rustplus_old/api/remote/camera/structures.py +++ /dev/null @@ -1,103 +0,0 @@ -from typing import Any - -from ..rustplus_proto import AppCameraInfo, AppCameraRaysEntity, AppCameraRays - - -class CameraInfo: - def __init__(self, camera_info_message: AppCameraInfo) -> None: - self.width: int = camera_info_message.width - self.height: int = camera_info_message.height - self.near_plane: float = camera_info_message.near_plane - self.far_plane: float = camera_info_message.far_plane - self.control_flags: int = camera_info_message.control_flags - - def is_move_option_permissible(self, value: int) -> bool: - return self.control_flags & value == value - - def __str__(self) -> str: - return ( - f"CameraInfo(width={self.width}, height={self.height}, near_plane={self.near_plane}, " - f"far_plane={self.far_plane}, control_flags={self.control_flags})" - ) - - -class Entity: - def __init__(self, entity_data: AppCameraRaysEntity) -> None: - self.entity_id: int = entity_data.entity_id - self.type: int = entity_data.type - self.position: Vector3 = Vector3(entity_data.position) - self.rotation: Vector3 = Vector3(entity_data.rotation) - self.size: Vector3 = Vector3(entity_data.size) - self.name: str = entity_data.name - - def __str__(self) -> str: - return ( - f"Entity(entity_id={self.entity_id}, type={self.type}, position={self.position}, " - f"rotation={self.rotation}, size={self.size}, name={self.name})" - ) - - def __repr__(self): - return self.__str__() - - -class Vector3: - def __init__(self, vector3=None, x=None, y=None, z=None) -> None: - self.x: float = vector3.x if x is None else x - self.y: float = vector3.y if y is None else y - self.z: float = vector3.z if z is None else z - - def __eq__(self, other): - if not isinstance(other, Vector3): - return False - - return self.x == other.x and self.y == other.y and self.z == other.z - - def __hash__(self): - return hash((self.x, self.y, self.z)) - - def __str__(self) -> str: - return f"Vector3(x={self.x}, y={self.y}, z={self.z})" - - -class RayPacket: - def __init__(self, ray_packet: AppCameraRays) -> None: - self.vertical_fov = ray_packet.vertical_fov - self.sample_offset = ray_packet.sample_offset - self.ray_data = ray_packet.ray_data - self.distance = ray_packet.distance - self.entities = [Entity(data) for data in ray_packet.entities] - - def __str__(self) -> str: - return ( - f"RayPacket(vertical_fov={self.vertical_fov}, sample_offset={self.sample_offset}, " - f"ray_data={self.ray_data}, distance={self.distance}, entities={self.entities})" - ) - - -class LimitedQueue: - def __init__(self, length) -> None: - self._length = length - self._queue = [] - - def add(self, item) -> None: - self._queue.append(item) - if len(self._queue) > self._length: - self._queue.pop(0) - - def get(self, index=0) -> Any: - if index >= len(self._queue) or index < 0: - return None - - return self._queue[index] - - def get_last(self) -> Any: - return self._queue[-1] - - def pop(self) -> Any: - return self._queue.pop(0) - - def clear(self) -> None: - self._queue.clear() - - def __len__(self) -> int: - return len(self._queue) diff --git a/rustplus_old/api/remote/events/__init__.py b/rustplus_old/api/remote/events/__init__.py deleted file mode 100644 index e303ed1..0000000 --- a/rustplus_old/api/remote/events/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .registered_listener import RegisteredListener -from .events import EntityEvent, TeamEvent, ChatEvent, MarkerEvent, ProtobufEvent -from .event_loop_manager import EventLoopManager -from .event_handler import EventHandler diff --git a/rustplus_old/api/remote/events/event_handler.py b/rustplus_old/api/remote/events/event_handler.py deleted file mode 100644 index 6c45f9e..0000000 --- a/rustplus_old/api/remote/events/event_handler.py +++ /dev/null @@ -1,44 +0,0 @@ -from typing import Set, Union - -from ....utils import ServerID -from .events import EntityEvent, TeamEvent, ChatEvent, ProtobufEvent -from .registered_listener import RegisteredListener -from ..rustplus_proto import AppMessage - - -class EventHandler: - @staticmethod - async def run_entity_event( - name: Union[str, int], app_message: AppMessage, server_id: ServerID - ) -> None: - handlers: Set[RegisteredListener] = EntityEvent.handlers.get_handlers( - server_id - ).get(str(name)) - - if handlers is None: - return - - for handler in handlers.copy(): - await handler.get_coro()( - EntityEvent(app_message, handler.get_entity_type()) - ) - - @staticmethod - async def run_team_event(app_message: AppMessage, server_id: ServerID) -> None: - handlers: Set[RegisteredListener] = TeamEvent.handlers.get_handlers(server_id) - for handler in handlers.copy(): - await handler.get_coro()(TeamEvent(app_message)) - - @staticmethod - async def run_chat_event(app_message: AppMessage, server_id: ServerID) -> None: - handlers: Set[RegisteredListener] = ChatEvent.handlers.get_handlers(server_id) - for handler in handlers.copy(): - await handler.get_coro()(ChatEvent(app_message)) - - @staticmethod - async def run_proto_event(byte_data: bytes, server_id: ServerID) -> None: - handlers: Set[RegisteredListener] = ProtobufEvent.handlers.get_handlers( - server_id - ) - for handler in handlers.copy(): - await handler.get_coro()(ProtobufEvent(byte_data)) diff --git a/rustplus_old/api/remote/events/event_loop_manager.py b/rustplus_old/api/remote/events/event_loop_manager.py deleted file mode 100644 index 16392cd..0000000 --- a/rustplus_old/api/remote/events/event_loop_manager.py +++ /dev/null @@ -1,25 +0,0 @@ -import asyncio -from typing import Dict - -from ....utils import ServerID - - -class EventLoopManager: - _loop: Dict[ServerID, asyncio.AbstractEventLoop] = {} - - @staticmethod - def get_loop(server_id: ServerID) -> asyncio.AbstractEventLoop: - if ( - EventLoopManager._loop is None - or EventLoopManager._loop.get(server_id) is None - ): - raise RuntimeError("Event loop is not set") - - if EventLoopManager._loop.get(server_id).is_closed(): - raise RuntimeError("Event loop is not running") - - return EventLoopManager._loop.get(server_id) - - @staticmethod - def set_loop(loop: asyncio.AbstractEventLoop, server_id: ServerID) -> None: - EventLoopManager._loop[server_id] = loop diff --git a/rustplus_old/api/remote/events/events.py b/rustplus_old/api/remote/events/events.py deleted file mode 100644 index 6a6afaa..0000000 --- a/rustplus_old/api/remote/events/events.py +++ /dev/null @@ -1,126 +0,0 @@ -from typing import List - -from ..rustplus_proto import AppMessage, AppEntityPayloadItem -from ...structures import RustChatMessage -from ...structures.rust_team_info import RustTeamInfo -from ...structures.rust_marker import RustMarker -from .handler_list import HandlerList, EntityHandlerList - - -class Item: - def __init__(self, app_message: AppEntityPayloadItem) -> None: - self._item_id: int = app_message.item_id - self._quantity: int = app_message.quantity - self._item_is_blueprint: bool = app_message.item_is_blueprint - - @property - def item_id(self) -> int: - return self._item_id - - @property - def quantity(self) -> int: - return self._quantity - - @property - def item_is_blueprint(self) -> bool: - return self._item_is_blueprint - - -class TeamEvent: - handlers = HandlerList() - - def __init__(self, app_message: AppMessage) -> None: - self._player_id: int = app_message.broadcast.team_changed.player_id - self._team_info = RustTeamInfo(app_message.broadcast.team_changed.team_info) - - @property - def player_id(self) -> int: - return self._player_id - - @property - def team_info(self) -> RustTeamInfo: - return self._team_info - - -class ChatEvent: - handlers = HandlerList() - - def __init__(self, app_message: AppMessage) -> None: - self._message = RustChatMessage(app_message.broadcast.team_message.message) - - @property - def message(self) -> RustChatMessage: - return self._message - - -class EntityEvent: - handlers = EntityHandlerList() - - def __init__(self, app_message: AppMessage, entity_type) -> None: - self._type = int(entity_type) - self._entity_id: int = app_message.broadcast.entity_changed.entity_id - self._value: bool = app_message.broadcast.entity_changed.payload.value - self._capacity: int = app_message.broadcast.entity_changed.payload.capacity - self._has_protection: bool = ( - app_message.broadcast.entity_changed.payload.has_protection - ) - self._protection_expiry: int = ( - app_message.broadcast.entity_changed.payload.protection_expiry - ) - - self._items: List[Item] = [ - Item(item) for item in app_message.broadcast.entity_changed.payload.items - ] - - @property - def type(self) -> int: - return self._type - - @property - def entity_id(self) -> int: - return self._entity_id - - @property - def value(self) -> bool: - return self._value - - @property - def capacity(self) -> int: - return self._capacity - - @property - def has_protection(self) -> bool: - return self._has_protection - - @property - def protection_expiry(self) -> int: - return self._protection_expiry - - @property - def items(self) -> List[Item]: - return self._items - - -class MarkerEvent: - def __init__(self, marker, is_new) -> None: - self._marker = marker - self._is_new = is_new - - @property - def marker(self) -> RustMarker: - return self._marker - - @property - def is_new(self) -> bool: - return self._is_new - - -class ProtobufEvent: - handlers = HandlerList() - - def __init__(self, byte_data) -> None: - self._byte_data = byte_data - - @property - def byte_data(self) -> bytes: - return self._byte_data diff --git a/rustplus_old/api/remote/events/handler_list.py b/rustplus_old/api/remote/events/handler_list.py deleted file mode 100644 index d98c989..0000000 --- a/rustplus_old/api/remote/events/handler_list.py +++ /dev/null @@ -1,63 +0,0 @@ -from collections import defaultdict -from typing import Set, Dict -from .registered_listener import RegisteredListener -from ....utils import ServerID - - -class HandlerList: - def __init__(self) -> None: - self._handlers: Dict[ServerID, Set[RegisteredListener]] = defaultdict(set) - - def unregister(self, listener: RegisteredListener, server_id: ServerID) -> None: - self._handlers[server_id].remove(listener) - - def register(self, listener: RegisteredListener, server_id: ServerID) -> None: - self._handlers[server_id].add(listener) - - def has(self, listener: RegisteredListener, server_id: ServerID) -> bool: - return listener in self._handlers[server_id] - - def unregister_all(self) -> None: - self._handlers.clear() - - def get_handlers( - self, server_id: ServerID - ) -> Dict[ServerID, Set[RegisteredListener]]: - return self._handlers.get(server_id, set()) - - -class EntityHandlerList(HandlerList): - def __init__(self) -> None: - super().__init__() - self._handlers: Dict[ServerID, Dict[str, Set[RegisteredListener]]] = ( - defaultdict(dict) - ) - - def unregister(self, listener: RegisteredListener, server_id: ServerID) -> None: - if listener.listener_id in self._handlers.get(server_id): - self._handlers.get(server_id).get(listener.listener_id).remove(listener) - - def register(self, listener: RegisteredListener, server_id: ServerID) -> None: - if server_id not in self._handlers: - self._handlers[server_id] = defaultdict(set) - - if listener.listener_id not in self._handlers.get(server_id): - self._handlers.get(server_id)[listener.listener_id] = set() - - self._handlers.get(server_id).get(listener.listener_id).add(listener) - - def has(self, listener: RegisteredListener, server_id: ServerID) -> bool: - if server_id in self._handlers and listener.listener_id in self._handlers.get( - server_id - ): - return listener in self._handlers.get(server_id).get(listener.listener_id) - - return False - - def unregister_all(self) -> None: - self._handlers.clear() - - def get_handlers( - self, server_id: ServerID - ) -> Dict[ServerID, Set[RegisteredListener]]: - return self._handlers.get(server_id, dict()) diff --git a/rustplus_old/api/remote/events/map_event_listener.py b/rustplus_old/api/remote/events/map_event_listener.py deleted file mode 100644 index 412ff52..0000000 --- a/rustplus_old/api/remote/events/map_event_listener.py +++ /dev/null @@ -1,104 +0,0 @@ -import asyncio -import threading -import time - -from .event_loop_manager import EventLoopManager -from .events import MarkerEvent - - -class MapEventListener: - def __init__(self, api) -> None: - self.api = api - self.thread = None - self.gc = None - self._iter_delay = 5 - self.persistent_ids = {} - self.highest_id = 0 - self.listeners = [] - - def add_listener(self, listener) -> None: - self.listeners.append(listener) - - def remove_listener(self, listener) -> bool: - try: - self.listeners.remove(listener) - return True - except ValueError: - return False - - def start(self, delay) -> None: - self._iter_delay = delay - self.thread = threading.Thread( - target=self._run, daemon=True, name="MapEventListener" - ) - self.thread.start() - self.gc = IDGarbageCollector(self.persistent_ids) - self.gc.start() - - def _run(self) -> None: - while True: - try: - future = asyncio.run_coroutine_threadsafe( - self.api.get_markers(), - EventLoopManager.get_loop(self.api.server_id), - ) - new_highest_id = 0 - for marker in future.result(): - new = False - - if marker.id in self.persistent_ids: - self.call_event(marker, new) - continue - - if marker.id > self.highest_id: - new = True - if marker.id > new_highest_id: - new_highest_id = marker.id - - # Removal Times - removal_time = time.time() - - if marker.type == 3 or marker.type == 1: - removal_time = float("inf") - else: - removal_time += 120 * 60 - - self.persistent_ids[marker.id] = removal_time - - self.call_event(marker, new) - - self.highest_id = new_highest_id - - except Exception as e: - print(e) - - time.sleep(self._iter_delay) - - def call_event(self, marker, is_new) -> None: - for listener in self.listeners: - asyncio.run_coroutine_threadsafe( - listener.get_coro()(MarkerEvent(marker, is_new)), - EventLoopManager.get_loop(self.api.server_id), - ).result() - - -class IDGarbageCollector: - def __init__(self, target: dict) -> None: - self.target = target - self.thread = None - - def start(self) -> None: - self.thread = threading.Thread( - target=self._run, daemon=True, name="IDGarbageCollector" - ) - self.thread.start() - - def _run(self) -> None: - while True: - try: - for key in list(self.target.keys()): - if self.target[key] < time.time(): - del self.target[key] - except Exception as e: - print(e) - time.sleep(5) diff --git a/rustplus_old/api/remote/events/registered_listener.py b/rustplus_old/api/remote/events/registered_listener.py deleted file mode 100644 index 8ec6843..0000000 --- a/rustplus_old/api/remote/events/registered_listener.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Union, Coroutine - - -class RegisteredListener: - def __init__( - self, - listener_id: Union[str, int], - coroutine: Coroutine, - entity_type: int = None, - ) -> None: - self.listener_id = str(listener_id) - self._coroutine = coroutine - self._entity_type = entity_type - - def get_coro(self): - return self._coroutine - - def get_entity_type(self): - return self._entity_type - - def __eq__(self, other) -> bool: - if not isinstance(other, RegisteredListener): - return False - - return ( - self.listener_id == other.listener_id - and self._coroutine == other.get_coro() - and self._entity_type == other.get_entity_type() - ) - - def __hash__(self): - return hash((self.listener_id, self._coroutine, self._entity_type)) diff --git a/rustplus_old/api/remote/fcm_listener.py b/rustplus_old/api/remote/fcm_listener.py deleted file mode 100644 index efed9d1..0000000 --- a/rustplus_old/api/remote/fcm_listener.py +++ /dev/null @@ -1,21 +0,0 @@ -from push_receiver import PushReceiver -from threading import Thread - - -class FCMListener: - def __init__(self, data: dict = None) -> None: - self.thread = None - self.data = data - self._push_listener = PushReceiver(credentials=self.data["fcm_credentials"]) - - def on_notification(self, obj, notification, data_message) -> None: - pass - - def start(self, daemon=False) -> None: - self.thread = Thread(target=self.__fcm_listen, daemon=daemon).start() - - def __fcm_listen(self) -> None: - if self.data is None: - raise ValueError("Data is None") - - self._push_listener.listen(callback=self.on_notification) diff --git a/rustplus_old/api/remote/heartbeat.py b/rustplus_old/api/remote/heartbeat.py deleted file mode 100644 index bedf410..0000000 --- a/rustplus_old/api/remote/heartbeat.py +++ /dev/null @@ -1,32 +0,0 @@ -import asyncio -import time - - -class HeartBeat: - def __init__(self, rust_api) -> None: - self.rust_api = rust_api - self.next_run = time.time() - self.running = False - - async def start_beat(self) -> None: - if self.running: - return - - self.running = True - - asyncio.create_task(self._heart_beat()) - - async def _heart_beat(self) -> None: - while True: - if time.time() >= self.next_run: - await self.beat() - - else: - await asyncio.sleep(1) - - async def beat(self) -> None: - if self.rust_api.remote.ws is not None and self.rust_api.remote.is_open(): - await self.rust_api.send_wakeup_request() - - def reset_rhythm(self) -> None: - self.next_run = time.time() + 240 diff --git a/rustplus_old/api/remote/ratelimiter.py b/rustplus_old/api/remote/ratelimiter.py deleted file mode 100644 index 3a89f7f..0000000 --- a/rustplus_old/api/remote/ratelimiter.py +++ /dev/null @@ -1,134 +0,0 @@ -import math -import time -import asyncio -from typing import Dict - -from ...exceptions.exceptions import RateLimitError -from ...utils import ServerID - - -class TokenBucket: - def __init__( - self, current: float, maximum: float, refresh_rate: float, refresh_amount: float - ) -> None: - self.current = current - self.max = maximum - self.refresh_rate = refresh_rate - self.refresh_amount = refresh_amount - self.last_update = time.time() - self.refresh_per_second = self.refresh_amount / self.refresh_rate - - def can_consume(self, amount) -> bool: - if (self.current - amount) >= 0: - return True - - return False - - def consume(self, amount: int = 1) -> None: - self.current -= amount - - def refresh(self) -> None: - time_now = time.time() - - time_delta = time_now - self.last_update - self.last_update = time_now - - self.current = min([self.current + time_delta * self.refresh_amount, self.max]) - - -class RateLimiter: - SERVER_LIMIT = 50 - SERVER_REFRESH_AMOUNT = 15 - - @classmethod - def default(cls) -> "RateLimiter": - """ - Returns a default rate limiter with 3 tokens per second - """ - return cls() - - def __init__(self) -> None: - self.socket_buckets: Dict[ServerID, TokenBucket] = {} - self.server_buckets: Dict[str, TokenBucket] = {} - self.lock = asyncio.Lock() - - def add_socket( - self, - server_id: ServerID, - current: float, - maximum: float, - refresh_rate: float, - refresh_amount: float, - ) -> None: - self.socket_buckets[server_id] = TokenBucket( - current, maximum, refresh_rate, refresh_amount - ) - if server_id.get_server_string() not in self.server_buckets: - self.server_buckets[server_id.get_server_string()] = TokenBucket( - self.SERVER_LIMIT, self.SERVER_LIMIT, 1, self.SERVER_REFRESH_AMOUNT - ) - - async def can_consume(self, server_id: ServerID, amount: int = 1) -> bool: - """ - Returns whether the user can consume the amount of tokens provided - """ - async with self.lock: - can_consume = True - - for bucket in [ - self.socket_buckets.get(server_id), - self.server_buckets.get(server_id.get_server_string()), - ]: - bucket.refresh() - if not bucket.can_consume(amount): - can_consume = False - - return can_consume - - async def consume(self, server_id: ServerID, amount: int = 1) -> None: - """ - Consumes an amount of tokens from the bucket. You should first check to see whether it is possible with can_consume - """ - async with self.lock: - for bucket in [ - self.socket_buckets.get(server_id), - self.server_buckets.get(server_id.get_server_string()), - ]: - bucket.refresh() - if not bucket.can_consume(amount): - self.lock.release() - raise RateLimitError("Not Enough Tokens") - bucket.consume(amount) - - async def get_estimated_delay_time( - self, server_id: ServerID, target_cost: int - ) -> float: - """ - Returns how long until the amount of tokens needed will be available - """ - async with self.lock: - delay = 0 - for bucket in [ - self.socket_buckets.get(server_id), - self.server_buckets.get(server_id.get_server_string()), - ]: - val = ( - math.ceil( - ( - ((target_cost - bucket.current) / bucket.refresh_per_second) - + 0.1 - ) - * 100 - ) - / 100 - ) - if val > delay: - delay = val - return delay - - async def remove(self, server_id: ServerID) -> None: - """ - Removes the limiter - """ - async with self.lock: - del self.socket_buckets[server_id] diff --git a/rustplus_old/api/remote/rplus_version_handler.py b/rustplus_old/api/remote/rplus_version_handler.py deleted file mode 100644 index ce4a5e8..0000000 --- a/rustplus_old/api/remote/rplus_version_handler.py +++ /dev/null @@ -1,19 +0,0 @@ -import requests -import logging - - -class MagicValueGrabber: - @staticmethod - def get_magic_value() -> int: - data = requests.get("https://companion-rust.facepunch.com/api/version") - - if data.status_code == 200: - data = data.json() - time = data.get("minPublishedTime", None) - if time is not None: - return time + 1 - - logging.getLogger("rustplus.py").warning( - "[Rustplus.py] Failed to get magic value from RustPlus Server" - ) - return 9999999999999 diff --git a/rustplus_old/api/remote/rust_remote_interface.py b/rustplus_old/api/remote/rust_remote_interface.py deleted file mode 100644 index 0686932..0000000 --- a/rustplus_old/api/remote/rust_remote_interface.py +++ /dev/null @@ -1,256 +0,0 @@ -import asyncio -import logging -from asyncio import Future -from typing import Union, Dict - -import betterproto - -from .camera.camera_manager import CameraManager -from .events import EventLoopManager, EntityEvent, RegisteredListener -from .rustplus_proto import AppRequest, AppMessage, AppEmpty, AppCameraSubscribe -from .rustws import RustWebsocket, CONNECTED, PENDING_CONNECTION -from .ratelimiter import RateLimiter -from .rplus_version_handler import MagicValueGrabber -from ...utils import ServerID, YieldingEvent -from ...conversation import ConversationFactory -from ...commands import CommandHandler -from ...exceptions import ( - ClientNotConnectedError, - RequestError, - SmartDeviceRegistrationError, -) - - -class RustRemote: - def __init__( - self, - server_id: ServerID, - command_options, - ratelimit_limit, - ratelimit_refill, - use_proxy: bool = False, - api=None, - use_test_server: bool = False, - rate_limiter: RateLimiter = None, - debug: bool = False, - ) -> None: - self.server_id = server_id - self.api = api - self.command_options = command_options - self.ratelimit_limit = ratelimit_limit - self.ratelimit_refill = ratelimit_refill - self.use_proxy = use_proxy - if isinstance(rate_limiter, RateLimiter): - self.ratelimiter = rate_limiter - else: - self.ratelimiter = RateLimiter.default() - - self.ratelimiter.add_socket( - self.server_id, ratelimit_limit, ratelimit_limit, 1, ratelimit_refill - ) - self.ws = None - self.logger = logging.getLogger("rustplus.py") - - self.ignored_responses = set() - self.pending_response_events: Dict[int, YieldingEvent] = {} - - self.command_handler = None - if command_options is None: - self.use_commands = False - else: - self.use_commands = True - self.command_handler = CommandHandler(self.command_options, api) - - self.magic_value = MagicValueGrabber.get_magic_value() - self.conversation_factory = ConversationFactory(api) - self.use_test_server = use_test_server - self.pending_entity_subscriptions = [] - self.camera_manager: Union[CameraManager, None] = None - self.debug = debug - - async def connect( - self, - retries, - delay, - on_failure, - on_success, - on_success_args_kwargs, - on_failure_args_kwargs, - ) -> None: - self.ws = RustWebsocket( - server_id=self.server_id, - remote=self, - use_proxy=self.use_proxy, - magic_value=self.magic_value, - use_test_server=self.use_test_server, - on_failure=on_failure, - on_success=on_success, - delay=delay, - on_success_args_kwargs=on_success_args_kwargs, - on_failure_args_kwargs=on_failure_args_kwargs, - debug=self.debug, - ) - await self.ws.connect(retries=retries) - - for entity_id, coroutine in self.pending_entity_subscriptions: - self.handle_subscribing_entity(entity_id, coroutine) - - async def close(self) -> None: - if self.ws is not None: - await self.ws.close() - del self.ws - self.ws = None - - def is_pending(self) -> bool: - if self.ws is not None: - return self.ws.connection_status == PENDING_CONNECTION - return False - - def is_open(self) -> bool: - if self.ws is not None: - return self.ws.connection_status == CONNECTED - return False - - async def send_message(self, request: AppRequest) -> None: - if self.ws is None: - raise ClientNotConnectedError("No Current Websocket Connection") - - if self.debug: - self.logger.info( - f"[RustPlus.py] Sending Message with seq {request.seq}: {request}" - ) - - self.pending_response_events[request.seq] = YieldingEvent() - await self.ws.send_message(request) - - async def get_response( - self, seq: int, app_request: AppRequest, error_check: bool = True - ) -> AppMessage: - """ - Returns a given response from the server. - """ - - attempts = 1 - - while True: - event = self.pending_response_events.get(seq) - if event is None: - raise Exception("Event Doesn't exist") - - response: AppMessage = await event.event_wait_for(4) - if response is not None: - break - - await self.send_message(app_request) - - if attempts % 150 == 0: - self.logger.info( - f"[RustPlus.py] Been waiting 10 minutes for a response for seq {seq}" - ) - - attempts += 1 - - self.pending_response_events.pop(seq) - - if response.response.error.error == "rate_limit": - logging.getLogger("rustplus.py").warning( - "[Rustplus.py] RateLimit Exception Occurred. Retrying after bucket is full" - ) - - # Fully Refill the bucket - bucket = self.ratelimiter.socket_buckets.get(self.server_id) - bucket.current = 0 - - while bucket.current < bucket.max: - await asyncio.sleep(1) - bucket.refresh() - - # Reattempt the sending with a full bucket - cost = self.ws.get_proto_cost(app_request) - - while True: - if await self.ratelimiter.can_consume(self.server_id, cost): - await self.ratelimiter.consume(self.server_id, cost) - break - - await asyncio.sleep( - await self.ratelimiter.get_estimated_delay_time( - self.server_id, cost - ) - ) - - await self.send_message(app_request) - response = await self.get_response(seq, app_request) - - elif self.ws.error_present(response.response.error.error) and error_check: - raise RequestError(response.response.error.error) - - return response - - def handle_subscribing_entity(self, entity_id: int, coroutine) -> None: - if not self.is_open(): - self.pending_entity_subscriptions.append((entity_id, coroutine)) - return - - async def get_entity_info(remote: RustRemote, eid): - await remote.api._handle_ratelimit() - - app_request: AppRequest = remote.api._generate_protobuf() - app_request.entity_id = eid - app_request.get_entity_info = AppEmpty() - - await remote.send_message(app_request) - - return await remote.get_response(app_request.seq, app_request, False) - - def entity_event_callback(future_inner: Future) -> None: - entity_info: AppMessage = future_inner.result() - - if betterproto.serialized_on_wire(entity_info.response.error): - raise SmartDeviceRegistrationError( - f"Entity: '{entity_id}' has not been found" - ) - - EntityEvent.handlers.register( - RegisteredListener( - entity_id, coroutine, entity_info.response.entity_info.type - ), - self.server_id, - ) - - future = asyncio.run_coroutine_threadsafe( - get_entity_info(self, entity_id), EventLoopManager.get_loop(self.server_id) - ) - future.add_done_callback(entity_event_callback) - - async def subscribe_to_camera( - self, entity_id: int, ignore_response: bool = False - ) -> AppRequest: - await self.api._handle_ratelimit() - app_request: AppRequest = self.api._generate_protobuf() - subscribe = AppCameraSubscribe() - subscribe.camera_id = entity_id - app_request.camera_subscribe = subscribe - - await self.send_message(app_request) - - if ignore_response: - await self.add_ignored_response(app_request.seq) - - return app_request - - async def create_camera_manager(self, cam_id) -> CameraManager: - if self.camera_manager is not None: - if self.camera_manager._cam_id == cam_id: - return self.camera_manager - - app_request = await self.subscribe_to_camera(cam_id) - app_message = await self.get_response(app_request.seq, app_request) - - self.camera_manager = CameraManager( - self.api, cam_id, app_message.response.camera_subscribe_info - ) - return self.camera_manager - - async def add_ignored_response(self, seq) -> None: - self.ignored_responses.add(seq) diff --git a/rustplus_old/api/remote/rustplus_proto/__init__.py b/rustplus_old/api/remote/rustplus_proto/__init__.py deleted file mode 100644 index c59bf8f..0000000 --- a/rustplus_old/api/remote/rustplus_proto/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .rustplus import * diff --git a/rustplus_old/api/remote/rustplus_proto/rustplus.py b/rustplus_old/api/remote/rustplus_proto/rustplus.py deleted file mode 100644 index 83d882b..0000000 --- a/rustplus_old/api/remote/rustplus_proto/rustplus.py +++ /dev/null @@ -1,498 +0,0 @@ -# Generated by the protocol buffer compiler. DO NOT EDIT! -# sources: rustplus.proto -# plugin: python-betterproto -from dataclasses import dataclass -from typing import List - -import betterproto - - -class AppEntityType(betterproto.Enum): - Switch = 1 - Alarm = 2 - StorageMonitor = 3 - - -class AppMarkerType(betterproto.Enum): - Undefined = 0 - Player = 1 - Explosion = 2 - VendingMachine = 3 - CH47 = 4 - CargoShip = 5 - Crate = 6 - GenericRadius = 7 - PatrolHelicopter = 8 - - -class AppCameraRaysEntityType(betterproto.Enum): - Tree = 1 - Player = 2 - - -@dataclass -class Vector2(betterproto.Message): - x: float = betterproto.float_field(1) - y: float = betterproto.float_field(2) - - -@dataclass -class Vector3(betterproto.Message): - x: float = betterproto.float_field(1) - y: float = betterproto.float_field(2) - z: float = betterproto.float_field(3) - - -@dataclass -class Vector4(betterproto.Message): - x: float = betterproto.float_field(1) - y: float = betterproto.float_field(2) - z: float = betterproto.float_field(3) - w: float = betterproto.float_field(4) - - -@dataclass -class Half3(betterproto.Message): - x: float = betterproto.float_field(1) - y: float = betterproto.float_field(2) - z: float = betterproto.float_field(3) - - -@dataclass -class Color(betterproto.Message): - r: float = betterproto.float_field(1) - g: float = betterproto.float_field(2) - b: float = betterproto.float_field(3) - a: float = betterproto.float_field(4) - - -@dataclass -class Ray(betterproto.Message): - origin: "Vector3" = betterproto.message_field(1) - direction: "Vector3" = betterproto.message_field(2) - - -@dataclass -class ClanActionResult(betterproto.Message): - request_id: int = betterproto.int32_field(1) - result: int = betterproto.int32_field(2) - has_clan_info: bool = betterproto.bool_field(3) - clan_info: "ClanInfo" = betterproto.message_field(4) - - -@dataclass -class ClanInfo(betterproto.Message): - clan_id: int = betterproto.int64_field(1) - name: str = betterproto.string_field(2) - created: int = betterproto.int64_field(3) - creator: int = betterproto.uint64_field(4) - motd: str = betterproto.string_field(5) - motd_timestamp: int = betterproto.int64_field(6) - motd_author: int = betterproto.uint64_field(7) - logo: bytes = betterproto.bytes_field(8) - color: int = betterproto.sint32_field(9) - roles: List["ClanInfoRole"] = betterproto.message_field(10) - members: List["ClanInfoMember"] = betterproto.message_field(11) - invites: List["ClanInfoInvite"] = betterproto.message_field(12) - max_member_count: int = betterproto.int32_field(13) - - -@dataclass -class ClanInfoRole(betterproto.Message): - role_id: int = betterproto.int32_field(1) - rank: int = betterproto.int32_field(2) - name: str = betterproto.string_field(3) - can_set_motd: bool = betterproto.bool_field(4) - can_set_logo: bool = betterproto.bool_field(5) - can_invite: bool = betterproto.bool_field(6) - can_kick: bool = betterproto.bool_field(7) - can_promote: bool = betterproto.bool_field(8) - can_demote: bool = betterproto.bool_field(9) - can_set_player_notes: bool = betterproto.bool_field(10) - can_access_logs: bool = betterproto.bool_field(11) - - -@dataclass -class ClanInfoMember(betterproto.Message): - steam_id: int = betterproto.uint64_field(1) - role_id: int = betterproto.int32_field(2) - joined: int = betterproto.int64_field(3) - last_seen: int = betterproto.int64_field(4) - notes: str = betterproto.string_field(5) - online: bool = betterproto.bool_field(6) - - -@dataclass -class ClanInfoInvite(betterproto.Message): - steam_id: int = betterproto.uint64_field(1) - recruiter: int = betterproto.uint64_field(2) - timestamp: int = betterproto.int64_field(3) - - -@dataclass -class ClanLog(betterproto.Message): - clan_id: int = betterproto.int64_field(1) - log_entries: List["ClanLogEntry"] = betterproto.message_field(2) - - -@dataclass -class ClanLogEntry(betterproto.Message): - timestamp: int = betterproto.int64_field(1) - event_key: str = betterproto.string_field(2) - arg1: str = betterproto.string_field(3) - arg2: str = betterproto.string_field(4) - arg3: str = betterproto.string_field(5) - arg4: str = betterproto.string_field(6) - - -@dataclass -class ClanInvitations(betterproto.Message): - invitations: List["ClanInvitationsInvitation"] = betterproto.message_field(1) - - -@dataclass -class ClanInvitationsInvitation(betterproto.Message): - clan_id: int = betterproto.int64_field(1) - recruiter: int = betterproto.uint64_field(2) - timestamp: int = betterproto.int64_field(3) - - -@dataclass -class AppRequest(betterproto.Message): - seq: int = betterproto.uint32_field(1) - player_id: int = betterproto.uint64_field(2) - player_token: int = betterproto.int32_field(3) - entity_id: int = betterproto.uint32_field(4) - get_info: "AppEmpty" = betterproto.message_field(8) - get_time: "AppEmpty" = betterproto.message_field(9) - get_map: "AppEmpty" = betterproto.message_field(10) - get_team_info: "AppEmpty" = betterproto.message_field(11) - get_team_chat: "AppEmpty" = betterproto.message_field(12) - send_team_message: "AppSendMessage" = betterproto.message_field(13) - get_entity_info: "AppEmpty" = betterproto.message_field(14) - set_entity_value: "AppSetEntityValue" = betterproto.message_field(15) - check_subscription: "AppEmpty" = betterproto.message_field(16) - set_subscription: "AppFlag" = betterproto.message_field(17) - get_map_markers: "AppEmpty" = betterproto.message_field(18) - promote_to_leader: "AppPromoteToLeader" = betterproto.message_field(20) - get_clan_info: "AppEmpty" = betterproto.message_field(21) - set_clan_motd: "AppSendMessage" = betterproto.message_field(22) - get_clan_chat: "AppEmpty" = betterproto.message_field(23) - send_clan_message: "AppSendMessage" = betterproto.message_field(24) - get_nexus_auth: "AppGetNexusAuth" = betterproto.message_field(25) - camera_subscribe: "AppCameraSubscribe" = betterproto.message_field(30) - camera_unsubscribe: "AppEmpty" = betterproto.message_field(31) - camera_input: "AppCameraInput" = betterproto.message_field(32) - - -@dataclass -class AppMessage(betterproto.Message): - response: "AppResponse" = betterproto.message_field(1) - broadcast: "AppBroadcast" = betterproto.message_field(2) - - -@dataclass -class AppResponse(betterproto.Message): - seq: int = betterproto.uint32_field(1) - success: "AppSuccess" = betterproto.message_field(4) - error: "AppError" = betterproto.message_field(5) - info: "AppInfo" = betterproto.message_field(6) - time: "AppTime" = betterproto.message_field(7) - map: "AppMap" = betterproto.message_field(8) - team_info: "AppTeamInfo" = betterproto.message_field(9) - team_chat: "AppTeamChat" = betterproto.message_field(10) - entity_info: "AppEntityInfo" = betterproto.message_field(11) - flag: "AppFlag" = betterproto.message_field(12) - map_markers: "AppMapMarkers" = betterproto.message_field(13) - clan_info: "AppClanInfo" = betterproto.message_field(15) - clan_chat: "AppClanChat" = betterproto.message_field(16) - nexus_auth: "AppNexusAuth" = betterproto.message_field(17) - camera_subscribe_info: "AppCameraInfo" = betterproto.message_field(20) - - -@dataclass -class AppBroadcast(betterproto.Message): - team_changed: "AppTeamChanged" = betterproto.message_field(4) - team_message: "AppNewTeamMessage" = betterproto.message_field(5) - entity_changed: "AppEntityChanged" = betterproto.message_field(6) - clan_changed: "AppClanChanged" = betterproto.message_field(7) - clan_message: "AppNewClanMessage" = betterproto.message_field(8) - camera_rays: "AppCameraRays" = betterproto.message_field(10) - - -@dataclass -class AppEmpty(betterproto.Message): - pass - - -@dataclass -class AppSendMessage(betterproto.Message): - message: str = betterproto.string_field(1) - - -@dataclass -class AppSetEntityValue(betterproto.Message): - value: bool = betterproto.bool_field(1) - - -@dataclass -class AppPromoteToLeader(betterproto.Message): - steam_id: int = betterproto.uint64_field(1) - - -@dataclass -class AppGetNexusAuth(betterproto.Message): - app_key: str = betterproto.string_field(1) - - -@dataclass -class AppSuccess(betterproto.Message): - pass - - -@dataclass -class AppError(betterproto.Message): - error: str = betterproto.string_field(1) - - -@dataclass -class AppFlag(betterproto.Message): - value: bool = betterproto.bool_field(1) - - -@dataclass -class AppInfo(betterproto.Message): - name: str = betterproto.string_field(1) - header_image: str = betterproto.string_field(2) - url: str = betterproto.string_field(3) - map: str = betterproto.string_field(4) - map_size: int = betterproto.uint32_field(5) - wipe_time: int = betterproto.uint32_field(6) - players: int = betterproto.uint32_field(7) - max_players: int = betterproto.uint32_field(8) - queued_players: int = betterproto.uint32_field(9) - seed: int = betterproto.uint32_field(10) - salt: int = betterproto.uint32_field(11) - logo_image: str = betterproto.string_field(12) - nexus: str = betterproto.string_field(13) - nexus_id: int = betterproto.int32_field(14) - nexus_zone: str = betterproto.string_field(15) - - -@dataclass -class AppTime(betterproto.Message): - day_length_minutes: float = betterproto.float_field(1) - time_scale: float = betterproto.float_field(2) - sunrise: float = betterproto.float_field(3) - sunset: float = betterproto.float_field(4) - time: float = betterproto.float_field(5) - - -@dataclass -class AppMap(betterproto.Message): - width: int = betterproto.uint32_field(1) - height: int = betterproto.uint32_field(2) - jpg_image: bytes = betterproto.bytes_field(3) - ocean_margin: int = betterproto.int32_field(4) - monuments: List["AppMapMonument"] = betterproto.message_field(5) - background: str = betterproto.string_field(6) - - -@dataclass -class AppMapMonument(betterproto.Message): - token: str = betterproto.string_field(1) - x: float = betterproto.float_field(2) - y: float = betterproto.float_field(3) - - -@dataclass -class AppEntityInfo(betterproto.Message): - type: "AppEntityType" = betterproto.enum_field(1) - payload: "AppEntityPayload" = betterproto.message_field(3) - - -@dataclass -class AppEntityPayload(betterproto.Message): - value: bool = betterproto.bool_field(1) - items: List["AppEntityPayloadItem"] = betterproto.message_field(2) - capacity: int = betterproto.int32_field(3) - has_protection: bool = betterproto.bool_field(4) - protection_expiry: int = betterproto.uint32_field(5) - - -@dataclass -class AppEntityPayloadItem(betterproto.Message): - item_id: int = betterproto.int32_field(1) - quantity: int = betterproto.int32_field(2) - item_is_blueprint: bool = betterproto.bool_field(3) - - -@dataclass -class AppTeamInfo(betterproto.Message): - leader_steam_id: int = betterproto.uint64_field(1) - members: List["AppTeamInfoMember"] = betterproto.message_field(2) - map_notes: List["AppTeamInfoNote"] = betterproto.message_field(3) - leader_map_notes: List["AppTeamInfoNote"] = betterproto.message_field(4) - - -@dataclass -class AppTeamInfoMember(betterproto.Message): - steam_id: int = betterproto.uint64_field(1) - name: str = betterproto.string_field(2) - x: float = betterproto.float_field(3) - y: float = betterproto.float_field(4) - is_online: bool = betterproto.bool_field(5) - spawn_time: int = betterproto.uint32_field(6) - is_alive: bool = betterproto.bool_field(7) - death_time: int = betterproto.uint32_field(8) - - -@dataclass -class AppTeamInfoNote(betterproto.Message): - type: int = betterproto.int32_field(2) - x: float = betterproto.float_field(3) - y: float = betterproto.float_field(4) - icon: int = betterproto.int32_field(5) - colour_index: int = betterproto.int32_field(6) - label: str = betterproto.string_field(7) - - -@dataclass -class AppTeamMessage(betterproto.Message): - steam_id: int = betterproto.uint64_field(1) - name: str = betterproto.string_field(2) - message: str = betterproto.string_field(3) - color: str = betterproto.string_field(4) - time: int = betterproto.uint32_field(5) - - -@dataclass -class AppTeamChat(betterproto.Message): - messages: List["AppTeamMessage"] = betterproto.message_field(1) - - -@dataclass -class AppMarker(betterproto.Message): - id: int = betterproto.uint32_field(1) - type: "AppMarkerType" = betterproto.enum_field(2) - x: float = betterproto.float_field(3) - y: float = betterproto.float_field(4) - steam_id: int = betterproto.uint64_field(5) - rotation: float = betterproto.float_field(6) - radius: float = betterproto.float_field(7) - color1: "Vector4" = betterproto.message_field(8) - color2: "Vector4" = betterproto.message_field(9) - alpha: float = betterproto.float_field(10) - name: str = betterproto.string_field(11) - out_of_stock: bool = betterproto.bool_field(12) - sell_orders: List["AppMarkerSellOrder"] = betterproto.message_field(13) - - -@dataclass -class AppMarkerSellOrder(betterproto.Message): - item_id: int = betterproto.int32_field(1) - quantity: int = betterproto.int32_field(2) - currency_id: int = betterproto.int32_field(3) - cost_per_item: int = betterproto.int32_field(4) - amount_in_stock: int = betterproto.int32_field(5) - item_is_blueprint: bool = betterproto.bool_field(6) - currency_is_blueprint: bool = betterproto.bool_field(7) - item_condition: float = betterproto.float_field(8) - item_condition_max: float = betterproto.float_field(9) - - -@dataclass -class AppMapMarkers(betterproto.Message): - markers: List["AppMarker"] = betterproto.message_field(1) - - -@dataclass -class AppClanInfo(betterproto.Message): - clan_info: "ClanInfo" = betterproto.message_field(1) - - -@dataclass -class AppClanMessage(betterproto.Message): - steam_id: int = betterproto.uint64_field(1) - name: str = betterproto.string_field(2) - message: str = betterproto.string_field(3) - time: int = betterproto.int64_field(4) - - -@dataclass -class AppClanChat(betterproto.Message): - messages: List["AppClanMessage"] = betterproto.message_field(1) - - -@dataclass -class AppNexusAuth(betterproto.Message): - server_id: str = betterproto.string_field(1) - player_token: int = betterproto.int32_field(2) - - -@dataclass -class AppTeamChanged(betterproto.Message): - player_id: int = betterproto.uint64_field(1) - team_info: "AppTeamInfo" = betterproto.message_field(2) - - -@dataclass -class AppNewTeamMessage(betterproto.Message): - message: "AppTeamMessage" = betterproto.message_field(1) - - -@dataclass -class AppEntityChanged(betterproto.Message): - entity_id: int = betterproto.uint32_field(1) - payload: "AppEntityPayload" = betterproto.message_field(2) - - -@dataclass -class AppClanChanged(betterproto.Message): - clan_info: "ClanInfo" = betterproto.message_field(1) - - -@dataclass -class AppNewClanMessage(betterproto.Message): - clan_id: int = betterproto.int64_field(1) - message: "AppClanMessage" = betterproto.message_field(2) - - -@dataclass -class AppCameraSubscribe(betterproto.Message): - camera_id: str = betterproto.string_field(1) - - -@dataclass -class AppCameraInput(betterproto.Message): - buttons: int = betterproto.int32_field(1) - mouse_delta: "Vector2" = betterproto.message_field(2) - - -@dataclass -class AppCameraInfo(betterproto.Message): - width: int = betterproto.int32_field(1) - height: int = betterproto.int32_field(2) - near_plane: float = betterproto.float_field(3) - far_plane: float = betterproto.float_field(4) - control_flags: int = betterproto.int32_field(5) - - -@dataclass -class AppCameraRays(betterproto.Message): - vertical_fov: float = betterproto.float_field(1) - sample_offset: int = betterproto.int32_field(2) - ray_data: bytes = betterproto.bytes_field(3) - distance: float = betterproto.float_field(4) - entities: List["AppCameraRaysEntity"] = betterproto.message_field(5) - time_of_day: float = betterproto.float_field(6) - - -@dataclass -class AppCameraRaysEntity(betterproto.Message): - entity_id: int = betterproto.uint32_field(1) - type: "AppCameraRaysEntityType" = betterproto.enum_field(2) - position: "Vector3" = betterproto.message_field(3) - rotation: "Vector3" = betterproto.message_field(4) - size: "Vector3" = betterproto.message_field(5) - name: str = betterproto.string_field(6) diff --git a/rustplus_old/api/remote/rustws.py b/rustplus_old/api/remote/rustws.py deleted file mode 100644 index 1f0bfb6..0000000 --- a/rustplus_old/api/remote/rustws.py +++ /dev/null @@ -1,394 +0,0 @@ -import asyncio -import base64 -import logging -import time -from datetime import datetime -from typing import Optional, Union, Coroutine -import betterproto -from asyncio import Task, AbstractEventLoop -from websockets.client import connect -from websockets.legacy.client import WebSocketClientProtocol - -from .camera.structures import RayPacket -from .rustplus_proto import AppMessage, AppRequest -from .events import EventHandler -from ..structures import RustChatMessage -from ...exceptions import ClientNotConnectedError -from ...conversation import Conversation -from ...utils import ServerID, YieldingEvent - -CONNECTED = 1 -PENDING_CONNECTION = 2 -CLOSING = 4 -CLOSED = 3 - - -class RustWebsocket: - def __init__( - self, - server_id: ServerID, - remote, - use_proxy, - magic_value, - use_test_server, - on_failure, - on_success, - delay, - on_success_args_kwargs, - on_failure_args_kwargs, - debug: bool = False, - ): - self.connection: Union[WebSocketClientProtocol, None] = None - self.task: Union[Task, None] = None - self.server_id = server_id - self.connection_status = CLOSED - self.use_proxy = use_proxy - self.remote = remote - self.logger = logging.getLogger("rustplus.py") - self.connected_time = time.time() - self.magic_value = magic_value - self.use_test_server = use_test_server - self.outgoing_conversation_messages = [] - self.on_failure = on_failure - self.on_success = on_success - self.delay = delay - self.on_success_args_kwargs = on_success_args_kwargs - self.on_failure_args_kwargs = on_failure_args_kwargs - self.debug = debug - - async def connect( - self, retries=float("inf"), ignore_open_value: bool = False - ) -> None: - if ( - not self.connection_status == CONNECTED or ignore_open_value - ) and not self.remote.is_pending(): - attempts = 0 - - while True: - if attempts >= retries: - raise ConnectionAbortedError("Reached Retry Limit") - - self.connection_status = PENDING_CONNECTION - - try: - address = ( - ( - f"wss://{self.server_id.ip}" - if self.server_id.port is None - else f"ws://{self.server_id.ip}:{self.server_id.port}" - ) - if self.use_test_server - else ( - f"wss://companion-rust.facepunch.com/game/{self.server_id.ip}/{self.server_id.port}" - if self.use_proxy - else f"ws://{self.server_id.ip}:{self.server_id.port}" - ) - ) - address += f"?v={str(self.magic_value)}" - - if self.debug: - self.logger.info(f"[RustPlus.py] Connecting to {address}") - - self.connection = await connect( - address, - close_timeout=0, - ping_interval=None, - max_size=1_000_000_000, - ) - self.connected_time = time.time() - - if self.on_success is not None: - try: - if asyncio.iscoroutinefunction(self.on_success): - await self.on_success( - *self.on_success_args_kwargs[0], - **self.on_success_args_kwargs[1], - ) - else: - self.on_success( - *self.on_success_args_kwargs[0], - **self.on_success_args_kwargs[1], - ) - except Exception as e: - self.logger.warning(e) - break - - except Exception as exception: - self.logger.info(f"[RustPlus.py] {exception}") - - print_error = True - if not isinstance(exception, KeyboardInterrupt): - # Run the failure callback - if self.on_failure is not None: - try: - if asyncio.iscoroutinefunction(self.on_failure): - val = await self.on_failure( - *self.on_failure_args_kwargs[0], - **self.on_failure_args_kwargs[1], - ) - else: - val = self.on_failure( - *self.on_failure_args_kwargs[0], - **self.on_failure_args_kwargs[1], - ) - - if val is not None: - print_error = val - - except Exception as e: - self.logger.warning(e) - - if print_error: - self.logger.warning( - f"{datetime.now().strftime('%d/%m/%Y %H:%M:%S')} " - f"[RustPlus.py] Cannot Connect to server. Retrying in {str(self.delay)} second/s" - ) - attempts += 1 - await asyncio.sleep(self.delay) - - self.connection_status = CONNECTED - - if not ignore_open_value: - self.task = asyncio.create_task( - self.run(), name="[RustPlus.py] Websocket Polling Task" - ) - - async def close(self) -> None: - self.connection_status = CLOSING - await self.connection.close() - self.connection = None - self.task.cancel() - self.task = None - self.connection_status = CLOSED - - if self.debug: - self.logger.info(f"[RustPlus.py] Connection Closed") - - async def send_message(self, message: AppRequest) -> None: - """ - Send the Protobuf to the server - """ - - if self.connection_status == CLOSED: - raise ClientNotConnectedError("Not Connected") - - try: - if self.use_test_server: - await self.connection.send( - base64.b64encode(bytes(message)).decode("utf-8") - ) - else: - await self.connection.send(bytes(message)) - except Exception: - self.logger.exception("An exception occurred whilst sending a message") - - while self.remote.is_pending(): - await asyncio.sleep(0.5) - return await self.send_message(message) - - async def run(self) -> None: - while self.connection_status == CONNECTED: - try: - data = await self.connection.recv() - - # See below for context on why this is needed - await self.run_coroutine_non_blocking( - EventHandler.run_proto_event(data, self.server_id) - ) - - app_message = AppMessage() - app_message.parse( - base64.b64decode(data) if self.use_test_server else data - ) - - except Exception as e: - if self.connection_status == CONNECTED: - print(e) - self.logger.exception( - f"{datetime.now().strftime('%d/%m/%Y %H:%M:%S')} [RustPlus.py] Connection interrupted, Retrying" - ) - await self.connect(ignore_open_value=True) - - continue - return - - try: - # This creates an asyncio task rather than awaiting the coroutine directly. - # This fixes the bug where if you called a BaseRustSocket#get... from within a RegisteredListener or callback, - # It would hang the websocket. This is because the websocket event loop would be stuck on the callback rather than polling the socket. - # This way, we can schedule the execution of all logic for this message, but continue polling the WS - await self.run_coroutine_non_blocking(self.handle_message(app_message)) - except Exception: - self.logger.exception( - "An Error occurred whilst handling the message from the server" - ) - - async def handle_message(self, app_message: AppMessage) -> None: - if self.debug: - self.logger.info( - f"[RustPlus.py] Received Message with seq {app_message.response.seq}: {app_message}" - ) - - if app_message.response.seq in self.remote.ignored_responses: - self.remote.ignored_responses.remove(app_message.response.seq) - return - - prefix = self.get_prefix( - str(app_message.broadcast.team_message.message.message) - ) - - if prefix is not None: - # This means it is a command - - if self.debug: - self.logger.info( - f"[RustPlus.py] Attempting to run Command: {app_message}" - ) - - message = RustChatMessage(app_message.broadcast.team_message.message) - await self.remote.command_handler.run_command(message, prefix) - - if self.is_entity_broadcast(app_message): - # This means that an entity has changed state - - if self.debug: - self.logger.info(f"[RustPlus.py] Running Entity Event: {app_message}") - - await EventHandler.run_entity_event( - app_message.broadcast.entity_changed.entity_id, - app_message, - self.server_id, - ) - - elif self.is_camera_broadcast(app_message): - if self.debug: - self.logger.info(f"[RustPlus.py] Running Camera Event: {app_message}") - - if self.remote.camera_manager is not None: - await self.remote.camera_manager.add_packet( - RayPacket(app_message.broadcast.camera_rays) - ) - - elif self.is_team_broadcast(app_message): - if self.debug: - self.logger.info(f"[RustPlus.py] Running Team Event: {app_message}") - - # This means that the team of the current player has changed - await EventHandler.run_team_event(app_message, self.server_id) - - elif self.is_message(app_message): - # This means that a message has been sent to the team chat - - if self.debug: - self.logger.info(f"[RustPlus.py] Running Chat Event: {app_message}") - - steam_id = int(app_message.broadcast.team_message.message.steam_id) - message = str(app_message.broadcast.team_message.message.message) - - # Conversation API - if self.remote.conversation_factory.has_conversation(steam_id): - if message not in self.outgoing_conversation_messages: - conversation: Conversation = ( - self.remote.conversation_factory.get_conversation(steam_id) - ) - - conversation.get_answers().append(message) - await conversation.get_current_prompt().on_response(message) - - if conversation.has_next(): - conversation.increment_prompt() - prompt = conversation.get_current_prompt() - prompt_string = await prompt.prompt() - await conversation.send_prompt(prompt_string) - - else: - prompt = conversation.get_current_prompt() - prompt_string = await prompt.on_finish() - if prompt_string != "": - await conversation.send_prompt(prompt_string) - self.remote.conversation_factory.abort_conversation(steam_id) - else: - self.outgoing_conversation_messages.remove(message) - - # Conversation API end - - await EventHandler.run_chat_event(app_message, self.server_id) - - else: - # This means that it wasn't sent by the server and is a message from the server in response to an action - event: YieldingEvent = self.remote.pending_response_events.get( - app_message.response.seq, None - ) - if event is not None: - if self.debug: - self.logger.info( - f"[RustPlus.py] Running Response Event: {app_message}" - ) - - event.set_with_value(app_message) - - def get_prefix(self, message: str) -> Optional[str]: - if self.remote.use_commands: - if message.startswith(self.remote.command_options.prefix): - return self.remote.command_options.prefix - else: - return None - - for overrule in self.remote.command_options.overruling_commands: - if message.startswith(overrule): - return overrule - - return None - - @staticmethod - def is_message(app_message: AppMessage) -> bool: - return betterproto.serialized_on_wire( - app_message.broadcast.team_message.message - ) - - @staticmethod - def is_camera_broadcast(app_message: AppMessage) -> bool: - return betterproto.serialized_on_wire(app_message.broadcast.camera_rays) - - @staticmethod - def is_entity_broadcast(app_message: AppMessage) -> bool: - return betterproto.serialized_on_wire(app_message.broadcast.entity_changed) - - @staticmethod - def is_team_broadcast(app_message: AppMessage) -> bool: - return betterproto.serialized_on_wire(app_message.broadcast.team_changed) - - @staticmethod - def get_proto_cost(app_request: AppRequest) -> int: - """ - Gets the cost of an AppRequest - """ - costs = [ - (app_request.get_time, 1), - (app_request.send_team_message, 2), - (app_request.get_info, 1), - (app_request.get_team_chat, 1), - (app_request.get_team_info, 1), - (app_request.get_map_markers, 1), - (app_request.get_map, 5), - (app_request.set_entity_value, 1), - (app_request.get_entity_info, 1), - (app_request.promote_to_leader, 1), - ] - for request, cost in costs: - if betterproto.serialized_on_wire(request): - return cost - - raise ValueError() - - @staticmethod - def error_present(message) -> bool: - """ - Checks message for error - """ - return message != "" - - @staticmethod - async def run_coroutine_non_blocking(coroutine: Coroutine) -> Task: - loop: AbstractEventLoop = asyncio.get_event_loop_policy().get_event_loop() - return loop.create_task(coroutine) diff --git a/rustplus_old/api/remote/server_checker.py b/rustplus_old/api/remote/server_checker.py deleted file mode 100644 index c4c4aa0..0000000 --- a/rustplus_old/api/remote/server_checker.py +++ /dev/null @@ -1,26 +0,0 @@ -import logging -import threading -import requests - - -class ServerChecker: - def __init__(self, ip: str, port: str) -> None: - self.ip = ip - self.port = port - self.logger = logging.getLogger("rustplus.py") - - def run(self) -> None: - threading.Thread(target=self._check_server, daemon=True).start() - - def _check_server(self) -> None: - try: - req = requests.post( - f"https://companion-rust.facepunch.com/api/server/test_connection?address={self.ip}&port={self.port}" - ) - for msg in req.json()["messages"]: - if "does not match your outgoing IP address" not in msg: - self.logger.warning(f"Error from server Checker: {msg}") - except Exception: - self.logger.exception( - f"Unable to test connection to server - {self.ip}:{self.port}" - ) diff --git a/rustplus_old/api/rust_api.py b/rustplus_old/api/rust_api.py deleted file mode 100644 index a99cd01..0000000 --- a/rustplus_old/api/rust_api.py +++ /dev/null @@ -1,428 +0,0 @@ -import asyncio -import requests -from typing import List, Union -from PIL import Image -from io import BytesIO -from datetime import datetime -from collections import defaultdict -from importlib import resources - -from .base_rust_api import BaseRustSocket -from .remote.camera.camera_manager import CameraManager -from .structures import ( - RustInfo, - RustMap, - RustMarker, - RustChatMessage, - RustTeamInfo, - RustEntityInfo, - RustContents, - RustItem, -) -from .remote.rustplus_proto import ( - AppEmpty, - AppSendMessage, - AppSetEntityValue, - AppPromoteToLeader, -) -from .remote import HeartBeat, RateLimiter -from ..commands import CommandOptions -from ..exceptions import * -from ..utils import ( - RustTime, - format_time, - format_coord, - convert_marker, - convert_monument, - translate_id_to_stack, - deprecated, - generate_grid, - avatar_processing, -) - - -class RustSocket(BaseRustSocket): - def __init__( - self, - ip: str = None, - port: str = None, - steam_id: int = None, - player_token: int = None, - command_options: CommandOptions = None, - raise_ratelimit_exception: bool = False, - ratelimit_limit: int = 25, - ratelimit_refill: int = 3, - use_proxy: bool = False, - use_test_server: bool = False, - event_loop: asyncio.AbstractEventLoop = None, - rate_limiter: RateLimiter = None, - debug: bool = False, - ) -> None: - super().__init__( - ip=ip, - port=port, - steam_id=steam_id, - player_token=player_token, - command_options=command_options, - raise_ratelimit_exception=raise_ratelimit_exception, - ratelimit_limit=ratelimit_limit, - ratelimit_refill=ratelimit_refill, - heartbeat=HeartBeat(self), - use_proxy=use_proxy, - use_test_server=use_test_server, - event_loop=event_loop, - rate_limiter=rate_limiter, - debug=debug, - ) - - async def get_time(self) -> RustTime: - await self._handle_ratelimit() - - app_request = self._generate_protobuf() - app_request.get_time = AppEmpty() - - await self.remote.send_message(app_request) - - response = await self.remote.get_response(app_request.seq, app_request) - - return format_time(response) - - async def send_team_message(self, message: Union[str, object]) -> None: - await self._handle_ratelimit(2) - - app_send_message = AppSendMessage() - app_send_message.message = str(message) - - app_request = self._generate_protobuf() - app_request.send_team_message = app_send_message - - await self.remote.add_ignored_response(app_request.seq) - - await self.remote.send_message(app_request) - - async def get_info(self) -> RustInfo: - await self._handle_ratelimit() - - app_request = self._generate_protobuf() - app_request.get_info = AppEmpty() - - await self.remote.send_message(app_request) - - response = await self.remote.get_response(app_request.seq, app_request) - - return RustInfo(response.response.info) - - async def get_team_chat(self) -> List[RustChatMessage]: - await self._handle_ratelimit() - - app_request = self._generate_protobuf() - app_request.get_team_chat = AppEmpty() - - await self.remote.send_message(app_request) - - messages = ( - await self.remote.get_response(app_request.seq, app_request) - ).response.team_chat.messages - - return [RustChatMessage(message) for message in messages] - - async def get_team_info(self) -> RustTeamInfo: - await self._handle_ratelimit() - - app_request = self._generate_protobuf() - app_request.get_team_info = AppEmpty() - - await self.remote.send_message(app_request) - - app_message = await self.remote.get_response(app_request.seq, app_request) - - return RustTeamInfo(app_message.response.team_info) - - async def get_markers(self) -> List[RustMarker]: - await self._handle_ratelimit() - - app_request = self._generate_protobuf() - app_request.get_map_markers = AppEmpty() - - await self.remote.send_message(app_request) - - app_message = await self.remote.get_response(app_request.seq, app_request) - - return [ - RustMarker(marker) for marker in app_message.response.map_markers.markers - ] - - async def get_raw_map_data(self) -> RustMap: - await self._handle_ratelimit(5) - - app_request = self._generate_protobuf() - app_request.get_map = AppEmpty() - - await self.remote.send_message(app_request) - - app_message = await self.remote.get_response(app_request.seq, app_request) - - return RustMap(app_message.response.map) - - async def get_map( - self, - add_icons: bool = False, - add_events: bool = False, - add_vending_machines: bool = False, - add_team_positions: bool = False, - override_images: dict = None, - add_grid: bool = False, - ) -> Image.Image: - if override_images is None: - override_images = {} - - map_size = int((await self.get_info()).size) - - await self._handle_ratelimit( - 5 - + ( - 1 - if [add_icons, add_events, add_vending_machines].count(True) >= 1 - else 0 + 1 if add_team_positions else 0 - ) - ) - - app_request = self._generate_protobuf() - app_request.get_map = AppEmpty() - - await self.remote.send_message(app_request) - - app_message = await self.remote.get_response(app_request.seq, app_request) - - game_map = app_message.response.map - monuments = list(game_map.monuments) - - try: - image = Image.open(BytesIO(game_map.jpg_image)) - except Exception: - raise ImageError("Invalid bytes for the image") - - if not self.use_test_server: - image = image.crop((500, 500, game_map.height - 500, game_map.width - 500)) - - game_map = image.resize((map_size, map_size), Image.LANCZOS).convert("RGBA") - - if add_grid: - grid = generate_grid(map_size) - - game_map.paste(grid, (5, 5), grid) - - if add_icons or add_events or add_vending_machines: - map_markers = ( - await self.get_markers() if add_events or add_vending_machines else [] - ) - - if add_icons: - for monument in monuments: - if str(monument.token) == "DungeonBase": - continue - icon = convert_monument(monument.token, override_images) - if monument.token in override_images: - icon = icon.resize((150, 150)) - if str(monument.token) == "train_tunnel_display_name": - icon = icon.resize((100, 125)) - game_map.paste( - icon, - (format_coord(int(monument.x), int(monument.y), map_size)), - icon, - ) - - if add_vending_machines: - with resources.path( - "rustplus.api.icons", "vending_machine.png" - ) as path: - vending_machine = Image.open(path).convert("RGBA") - vending_machine = vending_machine.resize((100, 100)) - - for marker in map_markers: - if add_events: - if ( - marker.type == 2 - or marker.type == 4 - or marker.type == 5 - or marker.type == 6 - or marker.type == 8 - ): - icon = convert_marker(str(marker.type), marker.rotation) - if marker.type == 6: - x = marker.x - y = marker.y - if y > map_size: - y = map_size - if y < 0: - y = 100 - if x > map_size: - x = map_size - 75 - if x < 0: - x = 50 - game_map.paste(icon, (int(x), map_size - int(y)), icon) - else: - game_map.paste( - icon, - (format_coord(int(marker.x), int(marker.y), map_size)), - icon, - ) - if add_vending_machines and marker.type == 3: - game_map.paste( - vending_machine, - (int(marker.x) - 50, map_size - int(marker.y) - 50), - vending_machine, - ) - if add_team_positions: - team = await self.get_team_info() - for member in team.members: - if member.is_alive: - avatar = ( - Image.open( - requests.get( - f"https://companion-rust.facepunch.com/api/avatar/{member.steam_id}", - stream=True, - ).raw - ) - .resize((100, 100), Image.LANCZOS) - .convert("RGBA") - ) - - player_avatar = avatar_processing(avatar, 5, member.is_online) - - game_map.paste( - player_avatar, - (format_coord(int(member.x), int(member.y), map_size)), - player_avatar, - ) - - return game_map.resize((2000, 2000), Image.LANCZOS) - - async def get_entity_info(self, eid: int = None) -> RustEntityInfo: - await self._handle_ratelimit() - - if eid is None: - raise ValueError("EID cannot be None") - - app_request = self._generate_protobuf() - app_request.entity_id = eid - app_request.get_entity_info = AppEmpty() - - await self.remote.send_message(app_request) - - app_message = await self.remote.get_response(app_request.seq, app_request) - - return RustEntityInfo(app_message.response.entity_info) - - async def _update_smart_device(self, eid: int, value: bool) -> None: - await self._handle_ratelimit() - - entity_value = AppSetEntityValue() - entity_value.value = value - - app_request = self._generate_protobuf() - - app_request.entity_id = eid - app_request.set_entity_value = entity_value - - await self.remote.add_ignored_response(app_request.seq) - - await self.remote.send_message(app_request) - - async def turn_on_smart_switch(self, eid: int = None) -> None: - if eid is None: - raise ValueError("EID cannot be None") - - await self._update_smart_device(eid, True) - - async def turn_off_smart_switch(self, eid: int = None) -> None: - if eid is None: - raise ValueError("EID cannot be None") - - await self._update_smart_device(eid, False) - - async def promote_to_team_leader(self, steam_id: int = None) -> None: - if steam_id is None: - raise ValueError("SteamID cannot be None") - - await self._handle_ratelimit() - - leader_packet = AppPromoteToLeader() - leader_packet.steam_id = steam_id - - app_request = self._generate_protobuf() - app_request.promote_to_leader = leader_packet - - await self.remote.add_ignored_response(app_request.seq) - - await self.remote.send_message(app_request) - - async def get_current_events(self) -> List[RustMarker]: - return [ - marker - for marker in (await self.get_markers()) - if marker.type == 2 - or marker.type == 4 - or marker.type == 5 - or marker.type == 6 - or marker.type == 8 - ] - - async def get_contents( - self, eid: int = None, combine_stacks: bool = False - ) -> RustContents: - if eid is None: - raise ValueError("EID cannot be None") - - returned_data = await self.get_entity_info(eid) - - target_time = datetime.utcfromtimestamp(int(returned_data.protection_expiry)) - difference = target_time - datetime.utcnow() - - items = [] - - for item in returned_data.items: - items.append( - RustItem( - translate_id_to_stack(item.item_id), - item.item_id, - item.quantity, - item.item_is_blueprint, - ) - ) - - if combine_stacks: - merged_map = defaultdict(tuple) - - for item in items: - data = merged_map[str(item.item_id)] - if data: - count = int(data[0]) + int(item.quantity) - merged_map[str(item.item_id)] = (count, bool(item.is_blueprint)) - else: - merged_map[str(item.item_id)] = ( - int(item.quantity), - bool(item.is_blueprint), - ) - - items = [] - for key in merged_map.keys(): - items.append( - RustItem( - translate_id_to_stack(key), - key, - int(merged_map[key][0]), - bool(merged_map[key][1]), - ) - ) - - return RustContents(difference, bool(returned_data.has_protection), items) - - @deprecated("Use RustSocket.get_contents") - async def get_tc_storage_contents( - self, eid: int = None, combine_stacks: bool = False - ) -> RustContents: - return await self.get_contents(eid=eid, combine_stacks=combine_stacks) - - async def get_camera_manager(self, cam_id: str) -> CameraManager: - return await self.remote.create_camera_manager(cam_id) diff --git a/rustplus_old/api/structures/__init__.py b/rustplus_old/api/structures/__init__.py deleted file mode 100644 index 5ac6b8f..0000000 --- a/rustplus_old/api/structures/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from .rust_time import RustTime -from .rust_info import RustInfo -from .rust_map import RustMap -from .rust_marker import RustMarker -from .rust_chat_message import RustChatMessage -from .rust_team_info import RustTeamInfo, RustTeamMember, RustTeamNote -from .rust_entity_info import RustEntityInfo -from .rust_contents import RustContents -from .rust_item import RustItem -from .util import Vector diff --git a/rustplus_old/api/structures/rust_chat_message.py b/rustplus_old/api/structures/rust_chat_message.py deleted file mode 100644 index bc3cef5..0000000 --- a/rustplus_old/api/structures/rust_chat_message.py +++ /dev/null @@ -1,36 +0,0 @@ -from ..remote.rustplus_proto import AppTeamMessage -from .serialization import Serializable - - -class RustChatMessage(Serializable): - def __init__(self, data: AppTeamMessage): - self._steam_id: int = data.steam_id - self._name: str = data.name - self._message: str = data.message - self._colour: str = data.color - self._time: int = data.time - - @property - def steam_id(self) -> int: - return self._steam_id - - @property - def name(self) -> str: - return self._name - - @property - def message(self) -> str: - return self._message - - @property - def colour(self) -> str: - return self._colour - - @property - def time(self) -> int: - return self._time - - def __repr__(self): - return "RustChatMessage[steam_id={}, sender_name={}, message={}, colour={}, time={}]".format( - self._steam_id, self._name, self._message, self._colour, self._time - ) diff --git a/rustplus_old/api/structures/rust_contents.py b/rustplus_old/api/structures/rust_contents.py deleted file mode 100644 index 6db2ccf..0000000 --- a/rustplus_old/api/structures/rust_contents.py +++ /dev/null @@ -1,30 +0,0 @@ -from datetime import timedelta -from typing import List -from .serialization import Serializable -from .rust_item import RustItem - - -class RustContents(Serializable): - def __init__(self, protection_time, has_protection, contents) -> None: - self._protection_time: timedelta = protection_time - self._has_protection: bool = has_protection - self._contents: List[RustItem] = contents - - @property - def protection_time(self) -> timedelta: - return self._protection_time - - @property - def has_protection(self) -> bool: - return self._has_protection - - @property - def contents(self) -> List[RustItem]: - return self._contents - - def __str__(self) -> str: - return ( - "RustContents[protection_time={}, has_protection={}, contents={}]".format( - self._protection_time, self._has_protection, self.contents - ) - ) diff --git a/rustplus_old/api/structures/rust_entity_info.py b/rustplus_old/api/structures/rust_entity_info.py deleted file mode 100644 index 563f55e..0000000 --- a/rustplus_old/api/structures/rust_entity_info.py +++ /dev/null @@ -1,73 +0,0 @@ -from typing import List -from .serialization import Serializable -from ..remote import AppEntityInfo, AppEntityPayloadItem - - -class RustEntityInfoItem(Serializable): - def __init__(self, data: AppEntityPayloadItem) -> None: - self._item_id: int = data.item_id - self._quantity: int = data.quantity - self._item_is_blueprint: bool = data.item_is_blueprint - - @property - def item_id(self) -> int: - return self._item_id - - @property - def quantity(self) -> int: - return self._quantity - - @property - def item_is_blueprint(self) -> bool: - return self._item_is_blueprint - - def __str__(self) -> str: - return ( - "RustEntityInfoItem[item_id={}, quantity={}, item_is_blueprint={}]".format( - self._item_id, self._quantity, self._item_is_blueprint - ) - ) - - -class RustEntityInfo(Serializable): - def __init__(self, data: AppEntityInfo) -> None: - self._type: int = data.type - self._value: bool = data.payload.value - self._items = [RustEntityInfoItem(item) for item in data.payload.items] - self._capacity: int = data.payload.capacity - self._has_protection: bool = data.payload.has_protection - self._protection_expiry: int = data.payload.protection_expiry - - @property - def type(self) -> int: - return self._type - - @property - def value(self) -> bool: - return self._value - - @property - def items(self) -> List[RustEntityInfoItem]: - return self._items - - @property - def capacity(self) -> int: - return self._capacity - - @property - def has_protection(self) -> bool: - return self._has_protection - - @property - def protection_expiry(self) -> int: - return self._protection_expiry - - def __str__(self) -> str: - return "RustEntityInfo[type={}, value={}, items={}, capacity={}, has_protection={}, protection_expiry={}]".format( - self._type, - self._value, - self._items, - self._capacity, - self._has_protection, - self._protection_expiry, - ) diff --git a/rustplus_old/api/structures/rust_info.py b/rustplus_old/api/structures/rust_info.py deleted file mode 100644 index 53d45de..0000000 --- a/rustplus_old/api/structures/rust_info.py +++ /dev/null @@ -1,79 +0,0 @@ -from ..remote.rustplus_proto import AppInfo -from .serialization import Serializable - - -class RustInfo(Serializable): - def __init__(self, data: AppInfo) -> None: - self._name: str = data.name - self._url: str = data.url - self._header_image: str = data.header_image - self._map: str = data.map - self._size: int = data.map_size - self._wipe_time: int = data.wipe_time - self._players: int = data.players - self._max_players: int = data.max_players - self._queued_players: int = data.queued_players - self._seed: int = data.seed - self._logo_image: str = data.logo_image - - @property - def url(self) -> str: - return self._url - - @property - def name(self) -> str: - return self._name - - @property - def map(self) -> str: - return self._map - - @property - def size(self) -> int: - return self._size - - @property - def players(self) -> int: - return self._players - - @property - def max_players(self) -> int: - return self._max_players - - @property - def queued_players(self) -> int: - return self._queued_players - - @property - def seed(self) -> int: - return self._seed - - @property - def wipe_time(self) -> int: - return self._wipe_time - - @property - def header_image(self) -> str: - return self._header_image - - @property - def logo_image(self) -> str: - return self._logo_image - - def __str__(self) -> str: - return ( - "RustInfo[url={}, name={}, map={}, size={}, players={}, max_players={}, queued_players={}, seed={}, " - "wipe_time={}, header_image={}, logo_image={}]".format( - self._url, - self._name, - self._map, - self._size, - self._players, - self._max_players, - self._queued_players, - self._seed, - self._wipe_time, - self._header_image, - self._logo_image, - ) - ) diff --git a/rustplus_old/api/structures/rust_item.py b/rustplus_old/api/structures/rust_item.py deleted file mode 100644 index 2589856..0000000 --- a/rustplus_old/api/structures/rust_item.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Union -from .serialization import Serializable - - -class RustItem(Serializable): - def __init__( - self, name: str, item_id: Union[str, int], quantity: int, is_blueprint: bool - ) -> None: - self._name: str = name - self._item_id: int = int(item_id) - self._quantity: int = quantity - self._is_blueprint: bool = is_blueprint - - @property - def name(self) -> str: - return self._name - - @property - def item_id(self) -> int: - return self._item_id - - @property - def quantity(self) -> int: - return self._quantity - - @property - def is_blueprint(self) -> bool: - return self._is_blueprint - - def __str__(self) -> str: - return "RustItem[name={}, item_id={}, quantity={}, is_blueprint={}]".format( - self._name, self._item_id, self._quantity, self._is_blueprint - ) diff --git a/rustplus_old/api/structures/rust_map.py b/rustplus_old/api/structures/rust_map.py deleted file mode 100644 index c7ed7ff..0000000 --- a/rustplus_old/api/structures/rust_map.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import List -from .serialization import Serializable -from ..remote.rustplus_proto import AppMap - - -class RustMonument(Serializable): - def __init__(self, token, x, y) -> None: - self._token: str = token - self._x: float = x - self._y: float = y - - @property - def token(self) -> str: - return self._token - - @property - def x(self) -> float: - return self._x - - @property - def y(self) -> float: - return self._y - - def __str__(self) -> str: - return "RustMonument[token={}, x={}, y={}]".format( - self._token, self._x, self._y - ) - - -class RustMap(Serializable): - def __init__(self, data: AppMap) -> None: - self._width: int = data.width - self._height: int = data.height - self._jpg_image: bytes = data.jpg_image - self._margin: int = data.ocean_margin - self._monuments = [ - RustMonument(monument.token, monument.x, monument.y) - for monument in data.monuments - ] - self._background: str = None if data.background == "" else data.background - - @property - def width(self) -> int: - return self._width - - @property - def height(self) -> int: - return self._height - - @property - def jpg_image(self) -> bytes: - return self._jpg_image - - @property - def margin(self) -> int: - return self._margin - - @property - def monuments(self) -> List[RustMonument]: - return self._monuments - - @property - def background(self) -> str: - return self._background - - def __str__(self) -> str: - return "RustMap[width={}, height={}, jpg_image={}, margin={}, monuments={}, background={}]".format( - self._width, - self._height, - len(self._jpg_image), - self._margin, - self._monuments, - self._background, - ) diff --git a/rustplus_old/api/structures/rust_marker.py b/rustplus_old/api/structures/rust_marker.py deleted file mode 100644 index 0b18604..0000000 --- a/rustplus_old/api/structures/rust_marker.py +++ /dev/null @@ -1,190 +0,0 @@ -from typing import List -from .serialization import Serializable -from ..remote.rustplus_proto import Vector4, AppMarkerSellOrder, AppMarker - - -class RustColour(Serializable): - def __init__(self, data: Vector4) -> None: - self._x: float = data.x - self._y: float = data.y - self._z: float = data.z - self._w: float = data.w - - @property - def x(self) -> float: - return self._x - - @property - def y(self) -> float: - return self._y - - @property - def z(self) -> float: - return self._z - - @property - def w(self) -> float: - return self._w - - def __str__(self) -> str: - return "RustColour[x={}, y={}, z={}, w={}]".format( - self._x, self._y, self._z, self._w - ) - - -class RustSellOrder(Serializable): - def __init__(self, data: AppMarkerSellOrder) -> None: - self._item_id: int = data.item_id - self._quantity: int = data.quantity - self._currency_id: int = data.currency_id - self._cost_per_item: int = data.cost_per_item - self._item_is_blueprint: bool = data.item_is_blueprint - self._currency_is_blueprint: bool = data.currency_is_blueprint - self._amount_in_stock: int = data.amount_in_stock - - @property - def item_id(self) -> int: - return self._item_id - - @property - def quantity(self) -> int: - return self._quantity - - @property - def currency_id(self) -> int: - return self._currency_id - - @property - def cost_per_item(self) -> int: - return self._cost_per_item - - @property - def item_is_blueprint(self) -> bool: - return self._item_is_blueprint - - @property - def currency_is_blueprint(self) -> bool: - return self._currency_is_blueprint - - @property - def amount_in_stock(self) -> int: - return self._amount_in_stock - - def __str__(self) -> str: - return ( - "RustSellOrder[item_id={}, quantity={}, currency_id={}, cost_per_item={}, item_is_blueprint={}, " - "currency_is_blueprint={}]".format( - self._item_id, - self._quantity, - self._currency_id, - self._cost_per_item, - self._item_is_blueprint, - self._currency_is_blueprint, - ) - ) - - -class RustMarker(Serializable): - PlayerMarker = 1 - ExplosionMarker = 2 - VendingMachineMarker = 3 - ChinookMarker = 4 - CargoShipMarker = 5 - CrateMarker = 6 - RadiusMarker = 7 - PatrolHelicopterMarker = 8 - - def __init__(self, data: AppMarker) -> None: - self._id: int = data.id - self._type: int = data.type - self._x: float = data.x - self._y: float = data.y - self._steam_id: int = data.steam_id - self._rotation: float = data.rotation - self._radius: float = data.radius - self._colour1 = RustColour(data.color1) - self._colour2 = RustColour(data.color2) - self._alpha: float = data.alpha - self._name: str = data.name - self._out_of_stock: bool = data.out_of_stock - self._sell_orders = [RustSellOrder(order) for order in data.sell_orders] - - @property - def id(self) -> int: - return self._id - - @property - def type(self) -> int: - return self._type - - @property - def x(self) -> float: - return self._x - - @property - def y(self) -> float: - return self._y - - @property - def steam_id(self) -> int: - return self._steam_id - - @property - def rotation(self) -> float: - return self._rotation - - @property - def radius(self) -> float: - return self._radius - - @property - def colour1(self) -> RustColour: - return self._colour1 - - @property - def colour2(self) -> RustColour: - return self._colour2 - - @property - def alpha(self) -> float: - return self._alpha - - @property - def name(self) -> str: - return self._name - - @property - def sell_orders(self) -> List[RustSellOrder]: - return self._sell_orders - - @property - def out_of_stock(self) -> bool: - return self._out_of_stock - - def __eq__(self, other): - if isinstance(other, RustMarker): - return self.id == other.id - return False - - def __str__(self) -> str: - return ( - "RustMarker[id={}, type={}, x={}, y={}, steam_id={}, rotation={}, radius={}, colour1={}, colour2={}, " - "alpha={}, name={}, sell_orders={}, out_of_stock={}]".format( - self._id, - self._type, - self._x, - self._y, - self._steam_id, - self._rotation, - self._radius, - self._colour1, - self._colour2, - self._alpha, - self._name, - self._sell_orders, - self._out_of_stock, - ) - ) - - def __hash__(self) -> int: - return hash((self._id, self._type)) diff --git a/rustplus_old/api/structures/rust_team_info.py b/rustplus_old/api/structures/rust_team_info.py deleted file mode 100644 index 7669dd5..0000000 --- a/rustplus_old/api/structures/rust_team_info.py +++ /dev/null @@ -1,130 +0,0 @@ -from typing import List -from .serialization import Serializable -from ..remote.rustplus_proto import AppTeamInfoMember, AppTeamInfoNote, AppTeamInfo - - -class RustTeamMember(Serializable): - def __init__(self, data: AppTeamInfoMember) -> None: - self._steam_id: int = data.steam_id - self._name: str = data.name - self._x: float = data.x - self._y: float = data.y - self._is_online: bool = data.is_online - self._spawn_time: int = data.spawn_time - self._is_alive: bool = data.is_alive - self._death_time: int = data.death_time - - @property - def steam_id(self) -> int: - return self._steam_id - - @property - def name(self) -> str: - return self._name - - @property - def x(self) -> float: - return self._x - - @property - def y(self) -> float: - return self._y - - @property - def is_online(self) -> bool: - return self._is_online - - @property - def spawn_time(self) -> int: - return self._spawn_time - - @property - def is_alive(self) -> bool: - return self._is_alive - - @property - def death_time(self) -> int: - return self._death_time - - def __str__(self) -> str: - return "RustTeamMember[steam_id={}, name={}, x={}, y={}, is_online={}, spawn_time={}, is_alive={}, death_time={}]".format( - self._steam_id, - self._name, - self._x, - self._y, - self._is_online, - self._spawn_time, - self._is_alive, - self._death_time, - ) - - -class RustTeamNote(Serializable): - def __init__(self, data: AppTeamInfoNote) -> None: - self._type: int = data.type - self._x: float = data.x - self._y: float = data.y - self._icon: int = data.icon - self._colour_index: int = data.colour_index - self._label: str = data.label - - @property - def type(self) -> int: - return self._type - - @property - def x(self) -> float: - return self._x - - @property - def y(self) -> float: - return self._y - - @property - def icon(self) -> int: - return self._icon - - @property - def colour_index(self) -> int: - return self._colour_index - - @property - def label(self) -> str: - return self._label - - def __str__(self) -> str: - return "RustTeamNote[type={}, x={}, y={}, icon={}, colour_index={}, label={}]".format( - self._type, self._x, self._y, self._icon, self._colour_index, self._label - ) - - -class RustTeamInfo(Serializable): - def __init__(self, data: AppTeamInfo) -> None: - self._leader_steam_id: int = data.leader_steam_id - self._members = [RustTeamMember(member) for member in data.members] - self._map_notes = [RustTeamNote(note) for note in data.map_notes] - self._leader_map_notes = [RustTeamNote(note) for note in data.leader_map_notes] - - @property - def leader_steam_id(self) -> int: - return self._leader_steam_id - - @property - def members(self) -> List[RustTeamMember]: - return self._members - - @property - def map_notes(self) -> List[RustTeamNote]: - return self._map_notes - - @property - def leader_map_notes(self) -> List[RustTeamNote]: - return self._leader_map_notes - - def __str__(self) -> str: - return "RustTeamInfo[leader_steam_id={}, members={}, map_notes={}, leader_map_notes={}]".format( - self._leader_steam_id, - self._members, - self._map_notes, - self._leader_map_notes, - ) diff --git a/rustplus_old/api/structures/rust_time.py b/rustplus_old/api/structures/rust_time.py deleted file mode 100644 index fe7b314..0000000 --- a/rustplus_old/api/structures/rust_time.py +++ /dev/null @@ -1,45 +0,0 @@ -from .serialization import Serializable - - -class RustTime(Serializable): - def __init__(self, day_length, sunrise, sunset, time, raw_time, time_scale) -> None: - self._day_length: float = day_length - self._sunrise: str = sunrise - self._sunset: str = sunset - self._time: str = time - self._raw_time: float = raw_time - self._time_scale: float = time_scale - - @property - def day_length(self) -> float: - return self._day_length - - @property - def sunrise(self) -> str: - return self._sunrise - - @property - def sunset(self) -> str: - return self._sunset - - @property - def time(self) -> str: - return self._time - - @property - def raw_time(self) -> float: - return self._raw_time - - @property - def time_scale(self) -> float: - return self._time_scale - - def __str__(self) -> str: - return "RustTime[day_length={}, sunrise={}, sunset={}, time={}, raw_time={}, time_scale={}]".format( - self._day_length, - self._sunrise, - self._sunset, - self._time, - self._raw_time, - self._time_scale, - ) diff --git a/rustplus_old/api/structures/serialization.py b/rustplus_old/api/structures/serialization.py deleted file mode 100644 index 87871f0..0000000 --- a/rustplus_old/api/structures/serialization.py +++ /dev/null @@ -1,17 +0,0 @@ -from collections.abc import Sequence - - -class Serializable: - def serialize(self): - data = {} - for k, v in self.__dict__.items(): - key = k if k[0] != "_" else k[1:] - if isinstance(v, Serializable): - data[key] = v.serialize() - elif isinstance(v, Sequence) and all( - isinstance(element, Serializable) for element in v - ): - data[key] = [e.serialize() for e in v] - else: - data[key] = str(v) - return data diff --git a/rustplus_old/api/structures/util.py b/rustplus_old/api/structures/util.py deleted file mode 100644 index 1dfac38..0000000 --- a/rustplus_old/api/structures/util.py +++ /dev/null @@ -1,7 +0,0 @@ -import dataclasses - - -@dataclasses.dataclass -class Vector: - x: float = 0 - y: float = 0 diff --git a/rustplus_old/commands/__init__.py b/rustplus_old/commands/__init__.py deleted file mode 100644 index 3cc2bff..0000000 --- a/rustplus_old/commands/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .command_options import CommandOptions -from .command import Command, CommandTime -from .command_handler import CommandHandler diff --git a/rustplus_old/commands/command.py b/rustplus_old/commands/command.py deleted file mode 100644 index 2b7d3a6..0000000 --- a/rustplus_old/commands/command.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import List - - -class CommandTime: - def __init__(self, formatted_time, raw_time) -> None: - self.formatted_time = formatted_time - self.raw_time = raw_time - - -class Command: - def __init__( - self, - sender_name: str, - sender_steam_id: int, - time: CommandTime, - command: str, - args: List[str], - ) -> None: - self.sender_name = sender_name - self.sender_steam_id = sender_steam_id - self.time = time - self.command = command - self.args = args diff --git a/rustplus_old/commands/command_data.py b/rustplus_old/commands/command_data.py deleted file mode 100644 index e9158c4..0000000 --- a/rustplus_old/commands/command_data.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Callable, List - - -class CommandData: - def __init__(self, coro, aliases, callable_func) -> None: - self.coro = coro - self._aliases = aliases - self._callable_func = callable_func - - @property - def aliases(self) -> List[str]: - if self._aliases is None: - return [] - - return self._aliases - - @property - def callable_func(self) -> Callable: - if self._callable_func is None: - return lambda x: False - - return self._callable_func diff --git a/rustplus_old/commands/command_handler.py b/rustplus_old/commands/command_handler.py deleted file mode 100644 index 47d5107..0000000 --- a/rustplus_old/commands/command_handler.py +++ /dev/null @@ -1,68 +0,0 @@ -import asyncio -import shlex -from datetime import datetime - -from . import Command, CommandTime -from ..api.structures import RustChatMessage -from ..commands.command_options import CommandOptions -from ..commands.command_data import CommandData -from ..api.remote.events import RegisteredListener - - -class CommandHandler: - def __init__(self, command_options: CommandOptions, api) -> None: - self.command_options = command_options - self.commands = {} - self.api = api - - def register_command(self, data: CommandData) -> None: - if not asyncio.iscoroutinefunction(data.coro): - raise TypeError("The event registered must be a coroutine") - - self.commands[data.coro.__name__] = data - - async def run_command(self, message: RustChatMessage, prefix) -> None: - if prefix == self.command_options.prefix: - command = shlex.split(message.message)[0][len(prefix) :] - else: - command = prefix - - if command in self.commands: - data = self.commands[command] - - await data.coro( - Command( - message.name, - message.steam_id, - CommandTime(datetime.utcfromtimestamp(message.time), message.time), - command, - shlex.split(message.message)[1:], - ) - ) - else: - for command_name, data in self.commands.items(): - # Loop through all the commands and see if the command is in the data aliases list - # or if it matches the callable function - - if command in data.aliases or data.callable_func(command): - await data.coro( - Command( - message.name, - message.steam_id, - CommandTime( - datetime.utcfromtimestamp(message.time), message.time - ), - command, - shlex.split(message.message)[1:], - ), - ) - break - - def has_command(self, listener: RegisteredListener) -> bool: - return listener.listener_id in self.commands - - def remove_command(self, listener: RegisteredListener) -> None: - try: - del self.commands[listener.listener_id] - except KeyError: - pass diff --git a/rustplus_old/commands/command_options.py b/rustplus_old/commands/command_options.py deleted file mode 100644 index c12d463..0000000 --- a/rustplus_old/commands/command_options.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import List - -from ..exceptions import PrefixNotDefinedError - - -class CommandOptions: - def __init__( - self, prefix: str = None, overruling_commands: List[str] = None - ) -> None: - if prefix is None: - raise PrefixNotDefinedError("No prefix") - - if overruling_commands is None: - overruling_commands = [] - - self.prefix = prefix - self.overruling_commands = overruling_commands diff --git a/rustplus_old/conversation/__init__.py b/rustplus_old/conversation/__init__.py deleted file mode 100644 index fb32bed..0000000 --- a/rustplus_old/conversation/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .conversation import Conversation -from .conversation_prompt import ConversationPrompt -from .conversation_factory import ConversationFactory diff --git a/rustplus_old/conversation/conversation.py b/rustplus_old/conversation/conversation.py deleted file mode 100644 index 87042cb..0000000 --- a/rustplus_old/conversation/conversation.py +++ /dev/null @@ -1,62 +0,0 @@ -import asyncio -from typing import List, Any -from .conversation_prompt import ConversationPrompt -from ..api.remote.events import EventLoopManager - - -class Conversation: - def __init__( - self, - api, - target: int = None, - prompts: List[ConversationPrompt] = None, - register=None, - ) -> None: - if target is None: - raise ValueError("target must be specified") - self._target = target - - if prompts is None: - self._prompts = [] - else: - self._prompts = prompts - - self._answers = [] - self._seq = 0 - self._api = api - self._register = register - - def add_prompt(self, prompt: ConversationPrompt) -> None: - super(type(prompt), prompt).__init__(self) - self._prompts.append(prompt) - - def add_all_prompts(self, prompts: List[ConversationPrompt]) -> None: - for prompt in prompts: - super(ConversationPrompt, prompt).__init__(self) - self.add_prompt(prompt) - - def has_next(self) -> bool: - return self._seq + 1 < len(self._prompts) - - def get_current_prompt(self) -> ConversationPrompt: - return self._prompts[self._seq] - - def increment_prompt(self) -> None: - self._seq += 1 - - async def send_prompt(self, message: str) -> None: - if self._api.remote.ws is not None: - self._api.remote.ws.outgoing_conversation_messages.append(message) - await self._api.send_team_message(message) - - async def start(self) -> None: - self._register(self._target, self) - await self.send_prompt(await self._prompts[0].prompt()) - - def run_coro(self, coro, args) -> Any: - return asyncio.run_coroutine_threadsafe( - coro(*args), EventLoopManager.get_loop(self._api.server_id) - ).result() - - def get_answers(self) -> List[str]: - return self._answers diff --git a/rustplus_old/conversation/conversation_factory.py b/rustplus_old/conversation/conversation_factory.py deleted file mode 100644 index 33b3b85..0000000 --- a/rustplus_old/conversation/conversation_factory.py +++ /dev/null @@ -1,50 +0,0 @@ -import time -from threading import Thread - -from .conversation import Conversation - - -class ConversationFactory: - def __init__(self, api) -> None: - self.api = api - self.conversations = {} - self.expires = {} - self.gc_thread = Thread(target=self.garbage_collect, daemon=True) - self.gc_thread.start() - - def create_conversation(self, steamid: int) -> Conversation: - if steamid in self.conversations: - raise ValueError("Conversation already exists") - - return Conversation( - api=self.api, target=steamid, register=self._register_conversation - ) - - def _register_conversation(self, steamid, convo: Conversation) -> None: - self.conversations[steamid] = convo - self.expires[steamid] = time.time() + 60 * 5 - - def has_conversation(self, steamid: int) -> bool: - return steamid in self.conversations - - def get_conversation(self, steamid: int) -> Conversation: - return self.conversations[steamid] - - def abort_conversation(self, steamid: int) -> None: - try: - del self.conversations[steamid] - del self.expires[steamid] - except KeyError: - pass - - def garbage_collect(self) -> None: - while True: - to_remove = [] - for steamid, expire_time in self.expires.items(): - if expire_time < time.time(): - to_remove.append(steamid) - - for steamid in to_remove: - self.abort_conversation(steamid) - - time.sleep(5) diff --git a/rustplus_old/conversation/conversation_prompt.py b/rustplus_old/conversation/conversation_prompt.py deleted file mode 100644 index dc73678..0000000 --- a/rustplus_old/conversation/conversation_prompt.py +++ /dev/null @@ -1,12 +0,0 @@ -class ConversationPrompt: - def __init__(self, conversation) -> None: - self.conversation = conversation - - async def prompt(self) -> str: - return "" - - async def on_response(self, response) -> None: - pass - - async def on_finish(self) -> str: - return "" diff --git a/rustplus_old/exceptions/__init__.py b/rustplus_old/exceptions/__init__.py deleted file mode 100644 index ea1088f..0000000 --- a/rustplus_old/exceptions/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from .exceptions import ( - RateLimitError, - ServerNotResponsiveError, - CommandsNotEnabledError, - ResponseNotReceivedError, - PrefixNotDefinedError, - ImageError, - ClientNotConnectedError, - RequestError, - SmartDeviceRegistrationError, - ServerSwitchDisallowedError, -) diff --git a/rustplus_old/exceptions/exceptions.py b/rustplus_old/exceptions/exceptions.py deleted file mode 100644 index 6f6ab68..0000000 --- a/rustplus_old/exceptions/exceptions.py +++ /dev/null @@ -1,64 +0,0 @@ -class Error(Exception): - """Base class for other exceptions""" - - pass - - -class RateLimitError(Error): - """Raised When an issue with the ratelimit has occurred""" - - pass - - -class ServerNotResponsiveError(Error): - """Raised when the target Server is not online / Unavailable""" - - pass - - -class CommandsNotEnabledError(Error): - """Raised when events are not enabled""" - - pass - - -class ResponseNotReceivedError(Error): - """Raised when a response has not been received from the server""" - - pass - - -class PrefixNotDefinedError(Error): - """Raised when a prefix is not given""" - - pass - - -class ImageError(Error): - """Raised when the bytes received are not valid""" - - pass - - -class ClientNotConnectedError(Error): - """Raised when you are not connected to the Rust server""" - - pass - - -class RequestError(Error): - """Raised when an error is received from the server""" - - pass - - -class SmartDeviceRegistrationError(Error): - """Raised when the entity cannot be registered with""" - - pass - - -class ServerSwitchDisallowedError(Error): - """Raised when you are using the test server and attempt to swap server""" - - pass diff --git a/rustplus_old/utils/__init__.py b/rustplus_old/utils/__init__.py deleted file mode 100644 index f0acb2b..0000000 --- a/rustplus_old/utils/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .rust_utils import * -from .deprecated import deprecated -from .grab_items import translate_id_to_stack -from .server_id import ServerID -from .yielding_event import YieldingEvent -from .emojis import Emoji diff --git a/rustplus_old/utils/deprecated.py b/rustplus_old/utils/deprecated.py deleted file mode 100644 index 75f20f8..0000000 --- a/rustplus_old/utils/deprecated.py +++ /dev/null @@ -1,32 +0,0 @@ -import functools -import inspect -import warnings - - -def deprecated(reason): - """ - This is a decorator which can be used to mark functions - as deprecated. It will result in a warning being emitted - when the function is used. - """ - - def decorator(func1): - if inspect.isclass(func1): - fmt1 = "Call to deprecated class {name} ({reason})." - else: - fmt1 = "Call to deprecated function {name} ({reason})." - - @functools.wraps(func1) - def new_func1(*args, **kwargs): - warnings.simplefilter("always", DeprecationWarning) - warnings.warn( - fmt1.format(name=func1.__name__, reason=reason), - category=DeprecationWarning, - stacklevel=2, - ) - warnings.simplefilter("default", DeprecationWarning) - return func1(*args, **kwargs) - - return new_func1 - - return decorator diff --git a/rustplus_old/utils/emojis.py b/rustplus_old/utils/emojis.py deleted file mode 100644 index cdb55c8..0000000 --- a/rustplus_old/utils/emojis.py +++ /dev/null @@ -1,31 +0,0 @@ -from enum import Enum - - -class Emoji(Enum): - ANGRY = ":angry+0:" - COFFEE_CAN = ":coffeecan+0:" - EYEBROW = ":eyebrow+0:" - FUNNY = ":funny+0:" - HAPPY = ":happy+0:" - LAUGH = ":laugh+0:" - LOVE = ":love+0:" - MASK = ":mask+0:" - NERVOUS = ":nervous+0:" - NEUTRAL = ":neutral+0:" - HEART_ROCK = ":heartrock+0:" - SMILE_CRY = ":smilecry+0:" - COOL = ":cool+0:" - LIGHT = ":light+0:" - WORRIED = ":worried+0:" - HEART = ":heart:" - SKULL = ":skull:" - EYES = ":eyes:" - DANCE = ":dance:" - EXCLAMATION = ":exclamation:" - TRUMPET = ":trumpet:" - WAVE = ":wave:" - YELLOW_PIN = ":yellowpin:" - SCIENTIST = ":scientist+0:" - - def __str__(self): - return self.value diff --git a/rustplus_old/utils/fonts/PermanentMarker.ttf b/rustplus_old/utils/fonts/PermanentMarker.ttf deleted file mode 100644 index 8052508cfd6ac4617327bcdf7726aafda67a4bab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74752 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 diff --git a/rustplus_old/utils/fonts/__init__.py b/rustplus_old/utils/fonts/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/rustplus_old/utils/grab_items.py b/rustplus_old/utils/grab_items.py deleted file mode 100644 index 45e9976..0000000 --- a/rustplus_old/utils/grab_items.py +++ /dev/null @@ -1,796 +0,0 @@ -from typing import Union - -import requests -import json - -item_ids = { - "-2139580305": "Auto Turret", - "-2124352573": "Acoustic Guitar", - "-2123125470": "Advanced Healing Tea", - "-2107018088": "Shovel Bass", - "-2099697608": "Stones", - "-2097376851": "Nailgun Nails", - "-2094954543": "Wood Armor Helmet", - "-2086926071": "Potato", - "-2084071424": "Potato Seed", - "-2072273936": "Bandage", - "-2069578888": "M249", - "-2067472972": "Sheet Metal Door", - "-2058362263": "Small Candle Set", - "-2049214035": "Pressure Pad", - "-2047081330": "Movember Moustache", - "-2040817543": "Pan Flute", - "-2027793839": "Advent Calendar", - "-2025184684": "Shirt", - "-2024549027": "Heavy Frankenstein Legs", - "-2022172587": "Diving Tank", - "-2012470695": "Improvised Balaclava", - "-2002277461": "Road Sign Jacket", - "-2001260025": "Instant Camera", - "-1999722522": "Furnace", - "-1997543660": "Horse Saddle", - "-1994909036": "Sheet Metal", - "-1992717673": "Large Furnace", - "-1985799200": "Rug", - "-1982036270": "High Quality Metal Ore", - "-1978999529": "Salvaged Cleaver", - "-1973785141": "Fogger-3000", - "-1966748496": "Mace", - "-1962971928": "Mushroom", - "-1961560162": "Firecracker String", - "-1950721390": "Concrete Barricade", - "-1941646328": "Can of Tuna", - "-1938052175": "Charcoal", - "-1916473915": "Chinese Lantern", - "-1904821376": "Orange Roughy", - "-1903165497": "Bone Helmet", - "-1899491405": "Glue", - "-1880870149": "Red Keycard", - "-1880231361": "Flatbed Vehicle Module", - "-1878764039": "Small Trout", - "-1878475007": "Satchel Charge", - "-1863559151": "Water Barrel", - "-1861522751": "Research Table", - "-1850571427": "Silencer", - "-1848736516": "Cooked Chicken", - "-1843426638": "MLRS Rocket", - "-1841918730": "High Velocity Rocket", - "-1832422579": "One Sided Town Sign Post", - "-1824943010": "Jack O Lantern Happy", - "-1819763926": "Wind Turbine", - "-1819233322": "Medium Wooden Sign", - "-1815301988": "Water Pistol", - "-1812555177": "LR-300 Assault Rifle", - "-1802083073": "High Quality Valves", - "-1800345240": "Speargun Spear", - "-1785231475": "Surgeon Scrubs", - "-1780802565": "Salvaged Icepick", - "-1779183908": "Paper", - "-1778897469": "Button", - "-1778159885": "Heavy Plate Pants", - "-1776128552": "Green Berry Seed", - "-1773144852": "Hide Skirt", - "-1772746857": "Heavy Scientist Suit", - "-1768880890": "Small Shark", - "-1758372725": "Thompson", - "-1754948969": "Sleeping Bag", - "-1736356576": "Reactive Target", - "-1732475823": "Medium Frankenstein Head", - "-1729415579": "Adv. Anti-Rad Tea", - "-1709878924": "Raw Human Meat", - "-1707425764": "Fishing Tackle", - "-1698937385": "Herring", - "-1695367501": "Shorts", - "-1693832478": "Large Flatbed Vehicle Module", - "-1691396643": "HV Pistol Ammo", - "-1685290200": "12 Gauge Buckshot", - "-1679267738": "Graveyard Fence", - "-1677315902": "Pure Healing Tea", - "-1673693549": "Empty Propane Tank", - "-1671551935": "Torpedo", - "-1667224349": "Decorative Baubels", - "-1663759755": "Homemade Landmine", - "-1654233406": "Sardine", - "-1651220691": "Pookie Bear", - "-1647846966": "Two Sided Ornate Hanging Sign", - "-1624770297": "Light Frankenstein Torso", - "-1622660759": "Large Present", - "-1622110948": "Bandit Guard Gear", - "-1621539785": "Beach Parasol", - "-1615281216": "Armored Passenger Vehicle Module", - "-1614955425": "Strengthened Glass Window", - "-1607980696": "Workbench Level 3", - "-1588628467": "Computer Station", - "-1583967946": "Stone Hatchet", - "-1581843485": "Sulfur", - "-1579932985": "Horse Dung", - "-1569700847": "Headset", - "-1557377697": "Empty Tuna Can", - "-1553999294": "Red Boomer", - "-1549739227": "Boots", - "-1539025626": "Miners Hat", - "-1538109120": "Violet Volcano Firework", - "-1535621066": "Stone Fireplace", - "-1530414568": "Cassette Recorder", - "-1520560807": "Raw Bear Meat", - "-1519126340": "Drop Box", - "-1518883088": "Night Vision Goggles", - "-1517740219": "Speargun", - "-1511285251": "Pumpkin Seed", - "-1509851560": "Cooked Deer Meat", - "-1507239837": "HBHF Sensor", - "-1506417026": "Ninja Suit", - "-1506397857": "Salvaged Hammer", - "-1501451746": "Cockpit Vehicle Module", - "-1488398114": "Composter", - "-1486461488": "Red Roman Candle", - "-1478445584": "Tuna Can Lamp", - "-1478212975": "Wolf Headdress", - "-1478094705": "Boogie Board", - "-1469578201": "Longsword", - "-1448252298": "Electrical Branch", - "-1442559428": "Hobo Barrel", - "-1440987069": "Raw Chicken Breast", - "-1432674913": "Anti-Radiation Pills", - "-1429456799": "Prison Cell Wall", - "-1423304443": "Medium Neon Sign", - "-1405508498": "Muzzle Boost", - "-1379835144": "Festive Window Garland", - "-1379036069": "Canbourine", - "-1370759135": "Portrait Picture Frame", - "-1368584029": "Sickle", - "-1367281941": "Waterpipe Shotgun", - "-1336109173": "Wood Double Door", - "-1331212963": "Star Tree Topper", - "-1330640246": "Junkyard Drum Kit", - "-1323101799": "Double Horse Saddle", - "-1321651331": "Explosive 5.56 Rifle Ammo", - "-1316706473": "Camera", - "-1306288356": "Green Roman Candle", - "-1305326964": "Green Berry Clone", - "-1302129395": "Pickaxe", - "-1293296287": "Small Oil Refinery", - "-1286302544": "OR Switch", - "-1284169891": "Water Pump", - "-1273339005": "Bed", - "-1266045928": "Bunny Onesie", - "-1262185308": "Binoculars", - "-1252059217": "Hatchet", - "-1234735557": "Wooden Arrow", - "-1230433643": "Festive Double Doorway Garland", - "-1215753368": "Flame Thrower", - "-1215166612": "A Barrel Costume", - "-1214542497": "HMLMG", - "-1211268013": "Basic Horse Shoes", - "-1211166256": "5.56 Rifle Ammo", - "-1199897172": "Metal Vertical embrasure", - "-1199897169": "Metal horizontal embrasure", - "-1196547867": "Electric Furnace", - "-1184406448": "Basic Max Health Tea", - "-1183726687": "Wooden Window Bars", - "-1167031859": "Spoiled Wolf Meat", - "-1166712463": "Fluid Splitter", - "-1163532624": "Jacket", - "-1162759543": "Cooked Horse Meat", - "-1160621614": "Red Industrial Wall Light", - "-1157596551": "Sulfur Ore", - "-1138208076": "Small Wooden Sign", - "-1137865085": "Machete", - "-1130709577": "Pump Jack", - "-1130350864": "Raw Horse Meat", - "-1123473824": "Multiple Grenade Launcher", - "-1117626326": "Chainlink Fence", - "-1113501606": "Boom Box", - "-1112793865": "Door Key", - "-1108136649": "Tactical Gloves", - "-1104881824": "Rug Bear Skin", - "-1102429027": "Heavy Plate Jacket", - "-1101924344": "Wetsuit", - "-1100422738": "Spinning wheel", - "-1100168350": "Large Water Catcher", - "-1073015016": "Skull Spikes", - "-1049881973": "Cowbell", - "-1049172752": "Storage Adaptor", - "-1044468317": "RF Broadcaster", - "-1043618880": "Ghost Costume", - "-1040518150": "Camper Vehicle Module", - "-1039528932": "Small Water Bottle", - "-1036635990": "12 Gauge Incendiary Shell", - "-1023374709": "Wood Shutters", - "-1023065463": "High Velocity Arrow", - "-1022661119": "Baseball Cap", - "-1021495308": "Metal Spring", - "-1018587433": "Animal Fat", - "-1009359066": "SAM Site", - "-1004426654": "Bunny Ears", - "-1003665711": "Super Serum", - "-1002156085": "Gold Egg", - "-1000573653": "Frog Boots", - "-996185386": "XL Picture Frame", - "-992286106": "White Berry Seed", - "-989755543": "Burnt Bear Meat", - "-986782031": "Rabbit Mask", - "-985781766": "High Ice Wall", - "-979951147": "Jerry Can Guitar", - "-979302481": "Easter Door Wreath", - "-967648160": "High External Stone Wall", - "-965336208": "Chocolate Bar", - "-961457160": "New Year Gong", - "-956706906": "Prison Cell Gate", - "-946369541": "Low Grade Fuel", - "-939424778": "Flasher Light", - "-936921910": "Flashbang", - "-932201673": "Scrap", - "-930193596": "Fertilizer", - "-929092070": "Basic Healing Tea", - "-912398867": "Cassette - Medium", - "-904863145": "Semi-Automatic Rifle", - "-888153050": "Halloween Candy", - "-886280491": "Hemp Clone", - "-858312878": "Cloth", - "-855748505": "Simple Handmade Sight", - "-854270928": "Dragon Door Knocker", - "-852563019": "M92 Pistol", - "-851988960": "Salmon", - "-850982208": "Key Lock", - "-845557339": "Landscape Picture Frame", - "-842267147": "Snowman Helmet", - "-819720157": "Metal Window Bars", - "-804769727": "Plant Fiber", - "-803263829": "Coffee Can Helmet", - "-798293154": "Laser Detector", - "-796583652": "Shop Front", - "-784870360": "Electric Heater", - "-781014061": "Sprinkler", - "-778875547": "Corn Clone", - "-778367295": "L96 Rifle", - "-769647921": "Skull Trophy", - "-765183617": "Double Barrel Shotgun", - "-763071910": "Lumberjack Hoodie", - "-761829530": "Burlap Shoes", - "-751151717": "Spoiled Chicken", - "-747743875": "Egg Suit", - "-746647361": "Memory Cell", - "-746030907": "Granola Bar", - "-742865266": "Rocket", - "-733625651": "Paddling Pool", - "-727717969": "12 Gauge Slug", - "-722241321": "Small Present", - "-702051347": "Bandana Mask", - "-700591459": "Can of Beans", - "-699558439": "Roadsign Gloves", - "-697981032": "Inner Tube", - "-695978112": "Smart Alarm", - "-695124222": "Giant Candy Decor", - "-692338819": "Small Rechargeable Battery", - "-691113464": "High External Stone Gate", - "-690968985": "Blocker", - "-690276911": "Glowing Eyes", - "-682687162": "Burnt Human Meat", - "-656349006": "Green Boomer", - "-649128577": "Basic Wood Tea", - "-629028935": "Electric Fuse", - "-626174997": "Taxi Vehicle Module", - "-596876839": "Spray Can", - "-592016202": "Explosives", - "-587989372": "Catfish", - "-586784898": "Mail Box", - "-586342290": "Blueberries", - "-583379016": "Megaphone", - "-582782051": "Snap Trap", - "-575744869": "Party Hat", - "-575483084": "Santa Hat", - "-568419968": "Grub", - "-567909622": "Pumpkin", - "-566907190": "RF Pager", - "-563624462": "Splitter", - "-559599960": "Sandbag Barricade", - "-558880549": "Gingerbread Suit", - "-557539629": "Pure Wood Tea", - "-555122905": "Sofa", - "-544317637": "Research Paper", - "-542577259": "Minnows", - "-541206665": "Advanced Wood Tea", - "-520133715": "Yellow Berry Seed", - "-515830359": "Blue Roman Candle", - "-502177121": "Door Controller", - "-496584751": "Rad. Removal Tea", - "-493159321": "Medium Quality Spark Plugs", - "-489848205": "Large Candle Set", - "-487356515": "Anti-Rad Tea", - "-484206264": "Blue Keycard", - "-470439097": "Arctic Suit", - "-465682601": "SUPER Stocking", - "-463122489": "Watch Tower", - "-458565393": "Root Combiner", - "-454370658": "Red Volcano Firework", - "-395377963": "Raw Wolf Meat", - "-384243979": "SAM Ammo", - "-379734527": "Pattern Boomer", - "-369760990": "Small Stash", - "-365097295": "Powered Water Purifier", - "-363689972": "Snowball", - "-343857907": "Sound Light", - "-335089230": "High External Wooden Gate", - "-324675402": "Reindeer Antlers", - "-321733511": "Crude Oil", - "-321431890": "Beach Chair", - "-316250604": "Wooden Ladder", - "-297099594": "Heavy Frankenstein Head", - "-295829489": "Test Generator", - "-282113991": "Simple Light", - "-280223496": "Violet Boomer", - "-265876753": "Gun Powder", - "-265292885": "Fluid Combiner", - "-262590403": "Salvaged Axe", - "-253079493": "Scientist Suit", - "-242084766": "Cooked Pork", - "-237809779": "Hemp Seed", - "-216999575": "Counter", - "-216116642": "Skull Door Knocker", - "-211235948": "Xylobone", - "-209869746": "Decorative Plastic Candy Canes", - "-196667575": "Flashlight", - "-194953424": "Metal Facemask", - "-194509282": "Butcher Knife", - "-180129657": "Wood Storage Box", - "-173268132": "Rustig\u00e9 Egg - Blue", - "-173268131": "Rustig\u00e9 Egg - Purple", - "-173268129": "Rustig\u00e9 Egg - Red", - "-173268128": "Rustig\u00e9 Egg - White", - "-173268126": "Rustig\u00e9 Egg - Ivory", - "-173268125": "Rustig\u00e9 Egg - Green", - "-151838493": "Wood", - "-151387974": "Deluxe Christmas Lights", - "-148794216": "Garage Door", - "-148229307": "Metal Shop Front", - "-144513264": "Pipe Tool", - "-144417939": "Wire Tool", - "-143132326": "Huge Wooden Sign", - "-135252633": "Sled", - "-134959124": "Light Frankenstein Head", - "-132516482": "Weapon Lasersight", - "-132247350": "Small Water Catcher", - "-129230242": "Decorative Pinecones", - "-126305173": "Painted Egg", - "-119235651": "Water Jug", - "-113413047": "Diving Mask", - "-110921842": "Locker", - "-99886070": "Violet Roman Candle", - "-97956382": "Tool Cupboard", - "-97459906": "Jumpsuit", - "-92759291": "Wooden Floor Spikes", - "-89874794": "Low Quality Spark Plugs", - "-78533081": "Burnt Deer Meat", - "-75944661": "Eoka Pistol", - "-48090175": "Snow Jacket", - "-44876289": "Igniter", - "-41896755": "Workbench Level 2", - "-41440462": "Spas-12 Shotgun", - "-33009419": "Pure Anti-Rad Tea", - "-23994173": "Boonie Hat", - "-22883916": "Dragon Mask", - "-20045316": "Mobile Phone", - "-17123659": "Smoke Rocket WIP!!!!", - "-8312704": "Beach Towel", - "-7270019": "Orange Boomer", - "-4031221": "Metal Ore", - "3222790": "Hide Halterneck", - "3380160": "Card Movember Moustache", - "14241751": "Fire Arrow", - "15388698": "Stone Barricade", - "20489901": "Purple Sunglasses", - "21402876": "Burlap Gloves", - "23352662": "Large Banner Hanging", - "23391694": "Bunny Hat", - "28201841": "M39 Rifle", - "37122747": "Green Keycard", - "39600618": "Microphone Stand", - "42535890": "Medium Animated Neon Sign", - "51984655": "Incendiary Pistol Bullet", - "60528587": "Roadsign Horse Armor", - "62577426": "Photograph", - "69511070": "Metal Fragments", - "73681876": "Tech Trash", - "86840834": "NVGM Scientist Suit", - "95950017": "Metal Pipe", - "98508942": "XXL Picture Frame", - "99588025": "High External Wooden Wall", - "106959911": "Light Frankenstein Legs", - "121049755": "Tall Picture Frame", - "122783240": "Black Berry Clone", - "140006625": "PTZ CCTV Camera", - "143803535": "F1 Grenade", - "170758448": "Cockpit With Engine Vehicle Module", - "171931394": "Stone Pickaxe", - "174866732": "16x Zoom Scope", - "176787552": "Rifle Body", - "177226991": "Scarecrow", - "190184021": "Kayak", - "196700171": "Hide Vest", - "198438816": "Vending Machine", - "200773292": "Hammer", - "204391461": "Coal :(", - "204970153": "Wrapped Gift", - "215754713": "Bone Arrow", - "223891266": "T-Shirt", - "237239288": "Pants", - "254522515": "Large Medkit", - "261913429": "White Volcano Firework", - "263834859": "Basic Scrap Tea", - "268565518": "Storage Vehicle Module", - "271048478": "Rat Mask", - "273172220": "Plumber's Trumpet", - "273951840": "Scarecrow Suit", - "277730763": "Mummy Suit", - "282103175": "Giant Lollipop Decor", - "286193827": "Pickles", - "286648290": "Disco Floor", - "296519935": "Diving Fins", - "304481038": "Flare", - "317398316": "High Quality Metal", - "342438846": "Anchovy", - "343045591": "MLRS Aiming Module", - "349762871": "40mm HE Grenade", - "352130972": "Rotten Apple", - "352321488": "Sunglasses", - "352499047": "Shotgun Trap", - "359723196": "Chippy Arcade Game", - "363163265": "Hose Tool", - "390728933": "Yellow Berry Clone", - "418081930": "Wood Chestplate", - "442289265": "Holosight", - "442886268": "Rocket Launcher", - "443432036": "Fluid Switch & Pump", - "476066818": "Cassette - Long", - "479143914": "Gears", - "479292118": "Large Loot Bag", - "492357192": "RAND Switch", - "524678627": "Advanced Scrap Tea", - "528668503": "Flame Turret", - "553270375": "Large Rechargeable Battery", - "553887414": "Skull Fire Pit", - "559147458": "Survival Fish Trap", - "567235583": "8x Zoom Scope", - "567871954": "Secret Lab Chair", - "573676040": "Coffin", - "573926264": "Semi Automatic Body", - "576509618": "Portable Boom Box", - "588596902": "Handmade Shell", - "593465182": "Table", - "596469572": "RF Transmitter", - "602741290": "Burlap Shirt", - "603811464": "Advanced Max Health Tea", - "605467368": "Incendiary 5.56 Rifle Ammo", - "609049394": "Battery - Small", - "610102428": "Industrial Conveyor", - "613961768": "Bota Bag", - "621915341": "Raw Pork", - "634478325": "CCTV Camera", - "642482233": "Sticks", - "649912614": "Revolver", - "656371026": "High Quality Carburetor", - "656371027": "Medium Quality Carburetor", - "656371028": "Low Quality Carburetor", - "657352755": "Beach Table", - "665332906": "Timer", - "671063303": "Riot Helmet", - "671706427": "Reinforced Glass Window", - "674734128": "Festive Doorway Garland", - "680234026": "Yellow Perch", - "696029452": "Paper Map", - "699075597": "Wooden Cross", - "709206314": "Tiger Mask", - "722955039": "Water Gun", - "742745918": "Industrial Splitter", - "755224797": "Vodka Bottle", - "756517185": "Medium Present", - "762289806": "Siren Light", - "782422285": "Sofa - Pattern", - "785728077": "Pistol Bullet", - "794356786": "Hide Boots", - "794443127": "Christmas Tree", - "795236088": "Torch", - "795371088": "Pump Shotgun", - "803222026": "Repair Bench", - "803954639": "Blue Berry Seed", - "809199956": "Gravestone", - "809942731": "Scarecrow Wrap", - "813023040": "Cooked Wolf Meat", - "818877484": "Semi-Automatic Pistol", - "826309791": "Two Sided Town Sign Post", - "830839496": "Red Berry Seed", - "832133926": "Wood Armor Pants", - "833533164": "Large Wood Box", - "835042040": "Medium Frankenstein Legs", - "838308300": "Burst Module", - "838831151": "Blue Berry Clone", - "844440409": "Bronze Egg", - "850280505": "Bucket Helmet", - "853471967": "Laser Light", - "854447607": "White Berry", - "858486327": "Green Berry", - "866332017": "Large Neon Sign", - "866889860": "Wooden Barricade", - "882559853": "Spider Webs", - "884424049": "Compound Bow", - "888415708": "RF Receiver", - "895374329": "Passenger Vehicle Module", - "915408809": "40mm Smoke Grenade", - "926800282": "Medium Quality Valves", - "935692442": "Longsleeve T-Shirt", - "936496778": "Floor grill", - "952603248": "Weapon flashlight", - "963906841": "Rock", - "968019378": "Clatter Helmet", - "968421290": "Connected Speaker", - "975983052": "Twitch Rivals Trophy", - "980333378": "Hide Poncho", - "988652725": "Smart Switch", - "989925924": "Raw Fish", - "996293980": "Human Skull", - "998894949": "Corn Seed", - "999690781": "Geiger Counter", - "1052926200": "Mining Quarry", - "1055319033": "40mm Shotgun Round", - "1058261682": "Christmas Lights", - "1072924620": "High Quality Spark Plugs", - "1079279582": "Medical Syringe", - "1081315464": "Nest Hat", - "1090916276": "Pitchfork", - "1094293920": "Wrapping Paper", - "1099314009": "Barbeque", - "1103488722": "Snowball Gun", - "1104520648": "Chainsaw", - "1107575710": "Arctic Scientist Suit", - "1110385766": "Metal Chest Plate", - "1112162468": "Blue Berry", - "1121925526": "Candy Cane", - "1142993169": "Ceiling Light", - "1149964039": "Storage Monitor", - "1153652756": "Large Wooden Sign", - "1158340331": "Medium Quality Crankshaft", - "1158340332": "High Quality Crankshaft", - "1158340334": "Low Quality Crankshaft", - "1159991980": "Code Lock", - "1160881421": "Hitch & Trough", - "1171735914": "AND Switch", - "1177596584": "Elevator", - "1181207482": "Heavy Plate Helmet", - "1186655046": "Fuel Tank Vehicle Module", - "1189981699": "Crate Costume", - "1199391518": "Road Signs", - "1205084994": "Large Photo Frame", - "1205607945": "Two Sided Hanging Sign", - "1221063409": "Armored Double Door", - "1230323789": "SMG Body", - "1230691307": "Captain's Log", - "1234878710": "Telephone", - "1234880403": "Sewing Kit", - "1242482355": "Jack O Lantern Angry", - "1242522330": "Cursed Cauldron", - "1248356124": "Timed Explosive Charge", - "1259919256": "Mixing Table", - "1263920163": "Smoke Grenade", - "1266491000": "Hazmat Suit", - "1268178466": "Green Industrial Wall Light", - "1272194103": "Red Berry", - "1272430949": "Wheelbarrow Piano", - "1272768630": "Spoiled Human Meat", - "1293102274": "XOR Switch", - "1305578813": "Small Neon Sign", - "1315082560": "Ox Mask", - "1318558775": "MP5A4", - "1319617282": "Small Loot Bag", - "1324203999": "Champagne Boomer", - "1326180354": "Salvaged Sword", - "1327005675": "Short Ice Wall", - "1330084809": "Low Quality Valves", - "1346158228": "Pumpkin Bucket", - "1353298668": "Armored Door", - "1358643074": "Snow Machine", - "1366282552": "Leather Gloves", - "1367190888": "Corn", - "1371909803": "Tesla Coil", - "1373240771": "Wooden Barricade Cover", - "1373971859": "Python Revolver", - "1376065505": "Rear Seats Vehicle Module", - "1381010055": "Leather", - "1382263453": "Barbed Wooden Barricade", - "1390353317": "Sheet Metal Double Door", - "1391703481": "Burnt Pork", - "1397052267": "Supply Signal", - "1400460850": "Saddle bag", - "1401987718": "Duct Tape", - "1409529282": "Door Closer", - "1413014235": "Fridge", - "1414245162": "Note", - "1414245522": "Rope", - "1422530437": "Raw Deer Meat", - "1424075905": "Water Bucket", - "1430085198": "Industrial Crafter", - "1443579727": "Hunting Bow", - "1451568081": "Chainlink Fence Gate", - "1478091698": "Muzzle Brake", - "1480022580": "Basic Ore Tea", - "1488979457": "Jackhammer", - "1491189398": "Paddle", - "1491753484": "Medium Frankenstein Torso", - "1512054436": "Potato Clone", - "1516985844": "Netting", - "1521286012": "Double Sign Post", - "1523195708": "Targeting Computer", - "1523403414": "Cassette - Short", - "1524187186": "Workbench Level 1", - "1524980732": "Carvable Pumpkin", - "1525520776": "Building Plan", - "1533551194": "White Berry Clone", - "1534542921": "Chair", - "1536610005": "Cooked Human Meat", - "1538126328": "Industrial Combiner", - "1540934679": "Wooden Spear", - "1542290441": "Single Sign Post", - "1545779598": "Assault Rifle", - "1548091822": "Apple", - "1553078977": "Bleach", - "1556365900": "Molotov Cocktail", - "1559779253": "Engine Vehicle Module", - "1559915778": "Single Horse Saddle", - "1568388703": "Diesel Fuel", - "1569882109": "Handmade Fishing Rod", - "1575635062": "Frankenstein Table", - "1581210395": "Large Planter Box", - "1588298435": "Bolt Action Rifle", - "1588492232": "Drone", - "1601468620": "Blue Jumpsuit", - "1602646136": "Stone Spear", - "1608640313": "Tank Top", - "1614528785": "Heavy Frankenstein Torso", - "1623701499": "Industrial Wall Light", - "1629293099": "Snowman", - "1638322904": "Incendiary Rocket", - "1643667218": "Large Animated Neon Sign", - "1655650836": "Metal Barricade", - "1655979682": "Empty Can Of Beans", - "1658229558": "Lantern", - "1659114910": "Gas Mask", - "1659447559": "Wooden Horse Armor", - "1660145984": "Yellow Berry", - "1668129151": "Cooked Fish", - "1668858301": "Small Stocking", - "1675639563": "Beenie Hat", - "1686524871": "Decorative Gingerbread Men", - "1696050067": "Modular Car Lift", - "1697996440": "Landscape Photo Frame", - "1711033574": "Bone Club", - "1712070256": "HV 5.56 Rifle Ammo", - "1712261904": "Pure Max Health Tea", - "1714496074": "Candle Hat", - "1719978075": "Bone Fragments", - "1722154847": "Hide Pants", - "1723747470": "Tree Lights", - "1729120840": "Wooden Door", - "1729374708": "Pure Ore Tea", - "1729712564": "Portrait Photo Frame", - "1744298439": "Blue Boomer", - "1746956556": "Bone Armor", - "1751045826": "Hoodie", - "1757265204": "Silver Egg", - "1770475779": "Worm", - "1771755747": "Black Berry", - "1776460938": "Blood", - "1783512007": "Cactus Flesh", - "1784406797": "Sousaphone", - "1789825282": "Candy Cane Club", - "1796682209": "Custom SMG", - "1803831286": "Garry's Mod Tool Gun", - "1814288539": "Bone Knife", - "1819863051": "Sky Lantern", - "1827479659": "Burnt Wolf Meat", - "1835946060": "Cable Tunnel", - "1840570710": "Above Ground Pool", - "1840822026": "Beancan Grenade", - "1849887541": "Small Generator", - "1850456855": "Road Sign Kilt", - "1856217390": "Egg Basket", - "1873897110": "Cooked Bear Meat", - "1874610722": "Armored Cockpit Vehicle Module", - "1877339384": "Burlap Headwrap", - "1882709339": "Metal Blade", - "1883981798": "Low Quality Pistons", - "1883981800": "High Quality Pistons", - "1883981801": "Medium Quality Pistons", - "1885488976": "Spooky Speaker", - "1895235349": "Disco Ball", - "1898094925": "Pumpkin Plant Clone", - "1899610628": "Medium Loot Bag", - "1903654061": "Small Planter Box", - "1905387657": "Pure Rad. Removal Tea", - "1911552868": "Black Berry Seed", - "1914691295": "Prototype 17", - "1917703890": "Burnt Horse Meat", - "1931713481": "Black Raspberries", - "1946219319": "Camp Fire", - "1948067030": "Ladder Hatch", - "1950721418": "Salvaged Shelves", - "1951603367": "Switch", - "1953903201": "Nailgun", - "1965232394": "Crossbow", - "1973165031": "Birthday Cake", - "1973684065": "Burnt Chicken", - "1975934948": "Survey Charge", - "1983621560": "Floor triangle grill", - "1989785143": "High Quality Horse Shoes", - "1992974553": "Burlap Trousers", - "2005491391": "Extended Magazine", - "2009734114": "Christmas Door Wreath", - "2019042823": "Tarp", - "2021351233": "Advanced Rad. Removal Tea", - "2023888403": "Medium Rechargeable Battery", - "2024467711": "Pure Scrap Tea", - "2040726127": "Combat Knife", - "2041899972": "Triangle Ladder Hatch", - "2048317869": "Wolf Skull", - "2063916636": "Advanced Ore Tea", - "2070189026": "Large Banner on pole", - "2087678962": "Search Light", - "2090395347": "Large Solar Panel", - "2100007442": "Audio Alarm", - "2104517339": "Strobe Light", - "2106561762": "Decorative Tinsel", - "2114754781": "Water Purifier", - "2126889441": "Santa Beard", - "2133269020": "Red Berry Clone", -} -stack_to_id = {} - - -def translate_id_to_stack(value_id: Union[str, int]) -> str: - global item_ids - try: - return item_ids[str(value_id)] - except KeyError: - return "Not Found" - - -def translate_stack_to_id(item: str) -> int: - global item_ids - global stack_to_id - if stack_to_id == {}: - for i in item_ids: - stack_to_id[item_ids[i].lower()] = i - try: - return stack_to_id[item.lower()] - except KeyError: - return "Not Found" - - -def grab_items(reversed=False) -> None: - data = {} - - for line in ( - requests.get( - "https://raw.githubusercontent.com/olijeffers0n/RustItems/master/data/items.md" - ) - .content.decode() - .splitlines(False)[2:] - ): - if len(line) == 0: - continue - - item = line.split("|")[1:-1] - - if item[1] == "" or item[2] == "N/A": - continue - - if not reversed: - data[int(item[2])] = item[0] - else: - data[str(item[0])] = int(item[2]) - - with open("rust_items.json", "w") as output: - json.dump(data, output, indent=4, sort_keys=True) - - -if __name__ == "__main__": - grab_items() diff --git a/rustplus_old/utils/rust_utils.py b/rustplus_old/utils/rust_utils.py deleted file mode 100644 index f2520a3..0000000 --- a/rustplus_old/utils/rust_utils.py +++ /dev/null @@ -1,297 +0,0 @@ -from importlib import resources -from typing import Tuple -from PIL import Image, ImageDraw, ImageFont -import logging -import string - -from ..api.remote.rustplus_proto import AppMessage -from ..api.structures import RustTime - -ICONS_PATH = "rustplus.api.icons" -FONT_PATH = "rustplus.utils.fonts" -GRID_DIAMETER = 146.28571428571428 - -PLAYER_MARKER_ONLINE_COLOR = (201, 242, 155, 255) -PLAYER_MARKER_OFFLINE_COLOR = (128, 128, 128, 255) - - -def format_time(protobuf: AppMessage) -> RustTime: - def convert_time(time) -> str: - hours, minutes = divmod(time * 60, 60) - - return ( - f"{int(hours)}:0{int(minutes)}" - if minutes <= 9 - else f"{int(hours)}:{int(minutes)}" - ) - - sunrise = convert_time(protobuf.response.time.sunrise) - sunset = convert_time(protobuf.response.time.sunset) - parsed_time = convert_time(protobuf.response.time.time) - - return RustTime( - protobuf.response.time.day_length_minutes, - sunrise, - sunset, - parsed_time, - protobuf.response.time.time, - protobuf.response.time.time_scale, - ) - - -def format_coord(x, y, map_size) -> Tuple[int, int]: - y = map_size - y - 75 - x -= 75 - - if x < 0: - x = 0 - if x > map_size: - x = map_size - 150 - if y < 0: - y = 0 - if y > map_size: - y = map_size - 150 - - return x, y - - -def convert_marker(name, angle) -> Image.Image: - name_to_file = { - "2": "explosion.png", - "4": "chinook.png", - "5": "cargo.png", - "6": "crate.png", - "8": "patrol.png", - } - - with resources.path(ICONS_PATH, name_to_file[name]) as path: - icon = Image.open(path).convert("RGBA") - if name == "6": - icon = icon.resize((85, 85)) - elif name == "2": - icon = icon.resize((96, 96)) - elif name == "4": - with resources.path(ICONS_PATH, "chinook_blades.png") as path: - blades = Image.open(path).convert("RGBA") - blades = blades.resize((100, 100)) - icon.paste(blades, (64 - 50, 96 - 50), blades) - icon.paste(blades, (64 - 50, 32 - 50), blades) - elif name == "8": - icon = icon.resize((200, 200)) - with resources.path(ICONS_PATH, "chinook_blades.png") as path: - blades = Image.open(path).convert("RGBA") - blades = blades.resize((200, 200)) - icon.paste(blades, (0, 0), blades) - icon = icon.rotate(angle) - return icon - - -def convert_monument(name: str, override_images: dict) -> Image.Image: - name_to_file = { - "supermarket": "supermarket.png", - "mining_outpost_display_name": "mining_outpost.png", - "gas_station": "oxums.png", - "fishing_village_display_name": "fishing.png", - "large_fishing_village_display_name": "fishing.png", - "lighthouse_display_name": "lighthouse.png", - "excavator": "excavator.png", - "water_treatment_plant_display_name": "water_treatment.png", - "train_yard_display_name": "train_yard.png", - "outpost": "outpost.png", - "bandit_camp": "bandit.png", - "junkyard_display_name": "junkyard.png", - "dome_monument_name": "dome.png", - "satellite_dish_display_name": "satellite.png", - "power_plant_display_name": "power_plant.png", - "military_tunnels_display_name": "military_tunnels.png", - "airfield_display_name": "airfield.png", - "launchsite": "launchsite.png", - "sewer_display_name": "sewer.png", - "oil_rig_small": "small_oil_rig.png", - "large_oil_rig": "large_oil_rig.png", - "underwater_lab": "underwater_lab.png", - "AbandonedMilitaryBase": "desert_base.png", - "ferryterminal": "ferryterminal.png", - "harbor_display_name": "harbour.png", - "harbor_2_display_name": "harbour.png", - "arctic_base_a": "arctic_base.png", - "arctic_base_b": "arctic_base.png", - "missile_silo_monument": "missile_silo.png", - "stables_a": "stables.png", - "stables_b": "stables.png", - "mining_quarry_stone_display_name": "mining_quarry_stone.png", - "mining_quarry_sulfur_display_name": "mining_quarry_sulfur.png", - "mining_quarry_hqm_display_name": "mining_quarry_hqm.png", - "train_tunnel_link_display_name": "train.png", - "train_tunnel_display_name": "train.png", - } - - try: - return override_images[name] - except KeyError: - pass - - if name in name_to_file: - file_name = name_to_file[name] - with resources.path(ICONS_PATH, file_name) as path: - icon = Image.open(path).convert("RGBA") - elif "swamp" in name: - with resources.path(ICONS_PATH, "swamp.png") as path: - icon = Image.open(path).convert("RGBA") - else: - logging.getLogger("rustplus.py").info( - f"{name} - Has no icon, report this as an issue" - ) - with resources.path(ICONS_PATH, "icon.png") as path: - icon = Image.open(path).convert("RGBA") - return icon - - -def entity_type_to_string(id) -> str: - if id == 1: - return "Switch" - elif id == 2: - return "Alarm" - elif id == 3: - return "Storage Monitor" - else: - raise ValueError("Not Valid type") - - -def _get_grid_x(x): - counter = 1 - start_grid = 0 - while start_grid < x + GRID_DIAMETER: - if start_grid <= x <= (start_grid + GRID_DIAMETER): - # We're at the correct grid! - return _number_to_letters(counter) - - counter += 1 - start_grid += GRID_DIAMETER - - -def _get_grid_y(y, map_size): - counter = 1 - number_of_grids = map_size // GRID_DIAMETER - start_grid = 0 - while start_grid < y + GRID_DIAMETER: - if start_grid <= y <= (start_grid + GRID_DIAMETER): - return number_of_grids - counter - counter += 1 - start_grid += GRID_DIAMETER - - -def _number_to_letters(num): - power, mod = divmod(num, 26) - out = chr(64 + mod) if mod else (power, "Z") - return _number_to_letters(power) + out if power else out - - -def _get_corrected_map_size(map_size): - remainder = map_size % GRID_DIAMETER - offset = GRID_DIAMETER - remainder - return map_size - remainder if remainder < 120 else map_size + offset - - -def _is_outside_grid_system(x, y, map_size, offset=0): - return ( - x < -offset or x > (map_size + offset) or y < -offset or y > (map_size + offset) - ) - - -class HackyBackwardsCompatCoordClass: - def __init__(self, x, y): - self.x = x - self.y = y - - def __getitem__(self, item): - if item == 0: - return self.x - elif item == 1: - return self.y - else: - raise IndexError("Index out of range") - - def __iter__(self): - yield self.x - yield self.y - - def __repr__(self): - return f"{self.x}{self.y}" - - def __str__(self): - return self.__repr__() - - -def convert_xy_to_grid( - coords: tuple, map_size: float, catch_out_of_bounds: bool = True -) -> HackyBackwardsCompatCoordClass: - corrected_map_size = _get_corrected_map_size(map_size) - - grid_pos_letters = _get_grid_x(coords[0]) - grid_pos_number = str(int(_get_grid_y(coords[1], corrected_map_size))) - - return HackyBackwardsCompatCoordClass(grid_pos_letters, grid_pos_number) - - -def generate_grid( - map_size: int, - text_size: int = 20, - text_padding: int = 5, - color: str = "black", -) -> Image.Image: - img = Image.new("RGBA", (map_size, map_size), (0, 0, 0, 0)) - d = ImageDraw.Draw(img) - - with resources.path(FONT_PATH, "PermanentMarker.ttf") as path: - font = ImageFont.truetype(str(path), text_size) - - letters = list(string.ascii_uppercase) - letters.extend( - a + b for a in string.ascii_uppercase for b in string.ascii_uppercase - ) - - num_cells = int(map_size / GRID_DIAMETER) - - for i in range(num_cells): - for j in range(num_cells): - start = (i * GRID_DIAMETER, j * GRID_DIAMETER) - end = ((i + 1) * GRID_DIAMETER, (j + 1) * GRID_DIAMETER) - d.rectangle((start, end), outline=color) - - text = letters[i] + str(j) - text_pos = (start[0] + text_padding, start[1] + text_padding) - d.text(text_pos, text, fill=color, font=font) - - return img - - -def avatar_processing( - image: Image.Image, border_size: int, player_online: bool = False -) -> Image.Image: - size_with_border = ( - image.size[0] + 2 * border_size, - image.size[1] + 2 * border_size, - ) - - border_image = Image.new("RGBA", size_with_border, (0, 0, 0, 0)) - - mask = Image.new("L", size_with_border, 0) - draw = ImageDraw.Draw(mask) - - draw.ellipse([0, 0, size_with_border[0], size_with_border[1]], fill=255) - - border_layer = Image.new( - "RGBA", - size_with_border, - PLAYER_MARKER_ONLINE_COLOR if player_online else PLAYER_MARKER_OFFLINE_COLOR, - ) - border_image.paste(border_layer, mask=mask) - - image_mask = Image.new("L", image.size, 0) - draw = ImageDraw.Draw(image_mask) - draw.ellipse([0, 0, image.size[0], image.size[1]], fill=255) - - border_image.paste(image, (border_size, border_size), image_mask) - - return border_image diff --git a/rustplus_old/utils/server_id.py b/rustplus_old/utils/server_id.py deleted file mode 100644 index 699f5a3..0000000 --- a/rustplus_old/utils/server_id.py +++ /dev/null @@ -1,26 +0,0 @@ -class ServerID: - def __init__(self, ip, port, player_id, player_token) -> None: - self.ip = ip - self.port = port - self.player_id = player_id - self.player_token = player_token - - def __str__(self) -> str: - return f"{self.ip}:{self.port} {self.player_id} {self.player_token}" - - def get_server_string(self) -> str: - return f"{self.ip}:{self.port}" - - def __hash__(self): - return hash(self.__str__()) - - def __eq__(self, o: object) -> bool: - if not isinstance(o, ServerID): - return False - - return ( - self.ip == o.ip - and self.port == o.port - and self.player_id == o.player_id - and self.player_token == o.player_token - ) diff --git a/rustplus_old/utils/yielding_event.py b/rustplus_old/utils/yielding_event.py deleted file mode 100644 index a10d21e..0000000 --- a/rustplus_old/utils/yielding_event.py +++ /dev/null @@ -1,27 +0,0 @@ -import asyncio -import contextlib -from typing import Any, Union - - -class YieldingEvent(asyncio.Event): - def __init__(self) -> None: - self.value: Union[Any, None] = None - super().__init__() - - def set_with_value(self, value: Any) -> None: - self.value = value - super().set() - - def clear(self) -> None: - self.value = None - super().clear() - - async def wait(self) -> Any: - await super().wait() - return self.value - - async def event_wait_for(self, timeout) -> Any: - # suppress TimeoutError because we'll return False in case of timeout - with contextlib.suppress(asyncio.TimeoutError): - await asyncio.wait_for(self.wait(), timeout) - return self.value if self.is_set() else None