



'''simple docstring'''

from typing import Any

class       __magic_name__		:







							def __init__(				self   :			Optional[int]      ,_UpperCAmelCase   :			Any						):
									_a	: Union[str, Any]								=				data
									_a	: int								=				None







							def __repr__(				self   :			List[Any]						):
									return F"""Node({self.data})"""

class       __magic_name__		:







							def __init__(				self   :			Any						):
									_a	: Dict								=				None







							def __iter__(				self   :			Dict						):
									_a	: List[str]								=				self.head
									while node:
											yield node.data
											_a	: List[str]								=				node.next







							def __len__(				self   :			int						):
									return sum(1 for _ in self						)







							def __repr__(				self   :			Any						):
									return "->".join([str(_UpperCAmelCase						) for item in self]						)







							def __getitem__(				self   :			int      ,_UpperCAmelCase   :			int						):
									if not 0 <= index < len(self						):
											raise ValueError('list index out of range.'						)
									for i, node in enumerate(self						):
											if i == index:
													return node
									return None







							def __setitem__(				self   :			int      ,_UpperCAmelCase   :			int      ,_UpperCAmelCase   :			Any						):
									if not 0 <= index < len(self						):
											raise ValueError('list index out of range.'						)
									_a	: List[Any]								=				self.head
									for _ in range(_UpperCAmelCase						):
											_a	: List[Any]								=				current.next
									_a	: List[str]								=				data







							def 				__lowercase     (				self   :			List[Any]      ,_UpperCAmelCase   :			Any						):
									self.insert_nth(len(self						)      ,_UpperCAmelCase						)







							def 				__lowercase     (				self   :			List[Any]      ,_UpperCAmelCase   :			Any						):
									self.insert_nth(0      ,_UpperCAmelCase						)







							def 				__lowercase     (				self   :			Optional[int]      ,_UpperCAmelCase   :			int      ,_UpperCAmelCase   :			Any						):
									if not 0 <= index <= len(self						):
											raise IndexError('list index out of range'						)
									_a	: int								=				Node(_UpperCAmelCase						)
									if self.head is None:
											_a	: str								=				new_node
									elif index == 0:
											_a	: Union[str, Any]								=				self.head  # link new_node to head
											_a	: List[Any]								=				new_node
									else:
											_a	: Tuple								=				self.head
											for _ in range(index - 1						):
													_a	: List[Any]								=				temp.next
											_a	: Dict								=				temp.next
											_a	: str								=				new_node







							def 				__lowercase     (				self   :			Tuple						):  # print every node data
									print(self						)







							def 				__lowercase     (				self   :			str						):
									return self.delete_nth(0						)







							def 				__lowercase     (				self   :			List[Any]						):  # delete from tail
									return self.delete_nth(len(self						) - 1						)







							def 				__lowercase     (				self   :			Optional[int]      ,_UpperCAmelCase   :			int = 0						):
									if not 0 <= index <= len(self						) - 1:  # test if index is valid
											raise IndexError('List index out of range.'						)
									_a	: Union[str, Any]								=				self.head  # default first node
									if index == 0:
											_a	: List[Any]								=				self.head.next
									else:
											_a	: Union[str, Any]								=				self.head
											for _ in range(index - 1						):
													_a	: int								=				temp.next
											_a	: Union[str, Any]								=				temp.next
											_a	: Any								=				temp.next.next
									return delete_node.data







							def 				__lowercase     (				self   :			Any						):
									return self.head is None







							def 				__lowercase     (				self   :			Dict						):
									_a	: Optional[int]								=				None
									_a	: List[Any]								=				self.head

									while current:
											# Store the current node's next node.
											_a	: Optional[Any]								=				current.next
											# Make the current node's next point backwards
											_a	: Optional[Any]								=				prev
											# Make the previous node be the current node
											_a	: Dict								=				current
											# Make the current node the next node (to progress iteration)
											_a	: Union[str, Any]								=				next_node
									# Return prev in order to put the head at the end
									_a	: Optional[int]								=				prev



def 	__lowerCamelCase	( )     -> None:
		_a	: Optional[int]								=				LinkedList()
		assert linked_list.is_empty() is True
		assert str(lowerCAmelCase_    ) == ""

		try:
				linked_list.delete_head()
				raise AssertionError  # This should not happen.
		except IndexError:
				assert True  # This should happen.

		try:
				linked_list.delete_tail()
				raise AssertionError  # This should not happen.
		except IndexError:
				assert True  # This should happen.

		for i in range(10    ):
				assert len(lowerCAmelCase_    ) == i
				linked_list.insert_nth(lowerCAmelCase_		,     i + 1    )
		assert str(lowerCAmelCase_    ) == "->".join(str(lowerCAmelCase_    ) for i in range(1		,     11    )    )

		linked_list.insert_head(0    )
		linked_list.insert_tail(11    )
		assert str(lowerCAmelCase_    ) == "->".join(str(lowerCAmelCase_    ) for i in range(0		,     12    )    )

		assert linked_list.delete_head() == 0
		assert linked_list.delete_nth(9    ) == 10
		assert linked_list.delete_tail() == 11
		assert len(lowerCAmelCase_    ) == 9
		assert str(lowerCAmelCase_    ) == "->".join(str(lowerCAmelCase_    ) for i in range(1		,     10    )    )

		assert all(linked_list[i] == i + 1 for i in range(0		,     9    )    ) is True

		for i in range(0		,     9    ):
				_a	: List[str]								=				-i
		assert all(linked_list[i] == -i for i in range(0		,     9    )    ) is True

		linked_list.reverse()
		assert str(lowerCAmelCase_    ) == "->".join(str(lowerCAmelCase_    ) for i in range(-8		,     1    )    )



def 	__lowerCamelCase	( )     -> None:
		_a	: Optional[int]								=				[
		    -9,
		    100,
		    Node(77345112    ),
		    'dlrow olleH',
		    7,
		    5555,
		    0,
		    -192.55_555,
		    'Hello, world!',
		    77.9,
		    Node(10    ),
		    None,
		    None,
		    12.20,
		]
		_a	: Union[str, Any]								=				LinkedList()

		for i in test_input:
				linked_list.insert_tail(lowerCAmelCase_    )

		# Check if it's empty or not
		assert linked_list.is_empty() is False
		assert (
		    str(lowerCAmelCase_    ) == "-9->100->Node(77345112)->dlrow olleH->7->5555->0->"
		    "-192.55555->Hello, world!->77.9->Node(10)->None->None->12.2"
		)

		# Delete the head
		_a	: List[Any]								=				linked_list.delete_head()
		assert result == -9
		assert (
		    str(lowerCAmelCase_    ) == "100->Node(77345112)->dlrow olleH->7->5555->0->-192.55555->"
		    "Hello, world!->77.9->Node(10)->None->None->12.2"
		)

		# Delete the tail
		_a	: Dict								=				linked_list.delete_tail()
		assert result == 12.2
		assert (
		    str(lowerCAmelCase_    ) == "100->Node(77345112)->dlrow olleH->7->5555->0->-192.55555->"
		    "Hello, world!->77.9->Node(10)->None->None"
		)

		# Delete a node in specific location in linked list
		_a	: Dict								=				linked_list.delete_nth(10    )
		assert result is None
		assert (
		    str(lowerCAmelCase_    ) == "100->Node(77345112)->dlrow olleH->7->5555->0->-192.55555->"
		    "Hello, world!->77.9->Node(10)->None"
		)

		# Add a Node instance to its head
		linked_list.insert_head(Node('Hello again, world!'    )    )
		assert (
		    str(lowerCAmelCase_    )
		    == "Node(Hello again, world!)->100->Node(77345112)->dlrow olleH->"
		    "7->5555->0->-192.55555->Hello, world!->77.9->Node(10)->None"
		)

		# Add None to its tail
		linked_list.insert_tail(lowerCAmelCase_    )
		assert (
		    str(lowerCAmelCase_    )
		    == "Node(Hello again, world!)->100->Node(77345112)->dlrow olleH->"
		    "7->5555->0->-192.55555->Hello, world!->77.9->Node(10)->None->None"
		)

		# Reverse the linked list
		linked_list.reverse()
		assert (
		    str(lowerCAmelCase_    )
		    == "None->None->Node(10)->77.9->Hello, world!->-192.55555->0->5555->"
		    "7->dlrow olleH->Node(77345112)->100->Node(Hello again, world!)"
		)



def 	__lowerCamelCase	( )     -> Dict:
		from doctest import testmod

		testmod()

		_a	: int								=				LinkedList()
		linked_list.insert_head(input('Inserting 1st at head '    ).strip()    )
		linked_list.insert_head(input('Inserting 2nd at head '    ).strip()    )
		print('\nPrint list:'    )
		linked_list.print_list()
		linked_list.insert_tail(input('\nInserting 1st at tail '    ).strip()    )
		linked_list.insert_tail(input('Inserting 2nd at tail '    ).strip()    )
		print('\nPrint list:'    )
		linked_list.print_list()
		print('\nDelete head'    )
		linked_list.delete_head()
		print('Delete tail'    )
		linked_list.delete_tail()
		print('\nPrint list:'    )
		linked_list.print_list()
		print('\nReverse linked list'    )
		linked_list.reverse()
		print('\nPrint list:'    )
		linked_list.print_list()
		print('\nString representation of linked list:'    )
		print(lowerCAmelCase_    )
		print('\nReading/changing Node data using indexing:'    )
		print(f"""Element at Position 1: {linked_list[1]}"""    )
		_a	: List[str]								=				input('Enter New Value: '    ).strip()
		print('New list:'    )
		print(lowerCAmelCase_    )
		print(f"""length of linked_list is : {len(lowerCAmelCase_    )}"""    )


if __name__ == "__main__":
							main()









'''simple docstring'''

from abc import ABC, abstractmethod
from argparse import ArgumentParser

class       __magic_name__		(       _UpperCamelCase  ):







							@staticmethod
							@abstractmethod
							def 				__lowercase     (				_UpperCAmelCase   :			ArgumentParser						):
									raise NotImplementedError()







							@abstractmethod
							def 				__lowercase     (				self   :			str						):
									raise NotImplementedError()




