


from typing import Any







class        UpperCamelCase__   :

					def __init__(     self       :   Dict							,					UpperCamelCase__       :   Any       ):






										'''simple docstring'''






										lowercase_  							=			data
										lowercase_  							=			None







					def __repr__(     self       :   int       ):






										'''simple docstring'''






										return F'''Node({self.data})'''







class        UpperCamelCase__   :

					def __init__(     self       :   List[str]       ):






										'''simple docstring'''






										lowercase_  							=			None

					def __iter__(     self       :   Optional[Any]       ):






										'''simple docstring'''






										lowercase_  							=			self.head
										while node:
															yield node.data
															lowercase_  							=			node.next

					def __len__(     self       :   Tuple       ):






										'''simple docstring'''






										return sum(1 for _ in self       )

					def __repr__(     self       :   str       ):






										'''simple docstring'''






										return "->".join([str(UpperCamelCase__       ) for item in self]       )

					def __getitem__(     self       :   Any							,					UpperCamelCase__       :   int       ):






										'''simple docstring'''






										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       :   Tuple							,					UpperCamelCase__       :   int							,					UpperCamelCase__       :   Any       ):






										'''simple docstring'''






										if not 0 <= index < len(self       ):
															raise ValueError("""list index out of range."""       )
										lowercase_  							=			self.head
										for _ in range(UpperCamelCase__       ):
															lowercase_  							=			current.next
										lowercase_  							=			data

					def   UpperCAmelCase__       (     self       :   str							,					UpperCamelCase__       :   Any       ):






										'''simple docstring'''






										self.insert_nth(len(self       )							,					UpperCamelCase__       )

					def   UpperCAmelCase__       (     self       :   Tuple							,					UpperCamelCase__       :   Any       ):






										'''simple docstring'''






										self.insert_nth(0							,					UpperCamelCase__       )

					def   UpperCAmelCase__       (     self       :   int							,					UpperCamelCase__       :   int							,					UpperCamelCase__       :   Any       ):






										'''simple docstring'''






										if not 0 <= index <= len(self       ):
															raise IndexError("""list index out of range"""       )
										lowercase_  							=			Node(UpperCamelCase__       )
										if self.head is None:
															lowercase_  							=			new_node
										elif index == 0:
															lowercase_  							=			self.head  # link new_node to head
															lowercase_  							=			new_node
										else:
															lowercase_  							=			self.head
															for _ in range(index - 1       ):
																				lowercase_  							=			temp.next
															lowercase_  							=			temp.next
															lowercase_  							=			new_node

					def   UpperCAmelCase__       (     self       :   Dict       ):  # print every node data






										'''simple docstring'''






										print(self       )

					def   UpperCAmelCase__       (     self       :   Tuple       ):






										'''simple docstring'''






										return self.delete_nth(0       )

					def   UpperCAmelCase__       (     self       :   int       ):  # delete from tail






										'''simple docstring'''






										return self.delete_nth(len(self       ) - 1       )

					def   UpperCAmelCase__       (     self       :   str							,					UpperCamelCase__       :   int = 0       ):






										'''simple docstring'''






										if not 0 <= index <= len(self       ) - 1:  # test if index is valid
															raise IndexError("""List index out of range."""       )
										lowercase_  							=			self.head  # default first node
										if index == 0:
															lowercase_  							=			self.head.next
										else:
															lowercase_  							=			self.head
															for _ in range(index - 1       ):
																				lowercase_  							=			temp.next
															lowercase_  							=			temp.next
															lowercase_  							=			temp.next.next
										return delete_node.data

					def   UpperCAmelCase__       (     self       :   List[str]       ):






										'''simple docstring'''






										return self.head is None







					def   UpperCAmelCase__       (     self       :   Dict       ):






										'''simple docstring'''






										lowercase_  							=			None
										lowercase_  							=			self.head

										while current:
															# Store the current node's next node.
															lowercase_  							=			current.next
															# Make the current node's next point backwards
															lowercase_  							=			prev
															# Make the previous node be the current node
															lowercase_  							=			current
															# Make the current node the next node (to progress iteration)
															lowercase_  							=			next_node
										# Return prev in order to put the head at the end
										lowercase_  							=			prev



def 			UpperCAmelCase_				(      ):
					lowercase_  							=			LinkedList()
					assert linked_list.is_empty() is True
					assert str(UpperCAmelCase__  ) == ""

					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(1_0  ):
										assert len(UpperCAmelCase__  ) == i
										linked_list.insert_nth(UpperCAmelCase__						,							i + 1  )
					assert str(UpperCAmelCase__  ) == "->".join(str(UpperCAmelCase__  ) for i in range(1						,							1_1  )  )

					linked_list.insert_head(0  )
					linked_list.insert_tail(1_1  )
					assert str(UpperCAmelCase__  ) == "->".join(str(UpperCAmelCase__  ) for i in range(0						,							1_2  )  )

					assert linked_list.delete_head() == 0
					assert linked_list.delete_nth(9  ) == 1_0
					assert linked_list.delete_tail() == 1_1
					assert len(UpperCAmelCase__  ) == 9
					assert str(UpperCAmelCase__  ) == "->".join(str(UpperCAmelCase__  ) for i in range(1						,							1_0  )  )

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

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

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


def 			UpperCAmelCase_				(      ):
					lowercase_  							=			[
					    -9,
					    1_0_0,
					    Node(7_7_3_4_5_1_1_2  ),
					    """dlrow olleH""",
					    7,
					    5_5_5_5,
					    0,
					    -192.55555,
					    """Hello, world!""",
					    77.9,
					    Node(1_0  ),
					    None,
					    None,
					    12.20,
					]
					lowercase_  							=			LinkedList()

					for i in test_input:
										linked_list.insert_tail(UpperCAmelCase__  )

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

					# Delete the head
					lowercase_  							=			linked_list.delete_head()
					assert result == -9
					assert (
					    str(UpperCAmelCase__  ) == "100->Node(77345112)->dlrow olleH->7->5555->0->-192.55555->"
					    "Hello, world!->77.9->Node(10)->None->None->12.2"
					)

					# Delete the tail
					lowercase_  							=			linked_list.delete_tail()
					assert result == 12.2
					assert (
					    str(UpperCAmelCase__  ) == "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
					lowercase_  							=			linked_list.delete_nth(1_0  )
					assert result is None
					assert (
					    str(UpperCAmelCase__  ) == "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(UpperCAmelCase__  )
					    == "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(UpperCAmelCase__  )
					assert (
					    str(UpperCAmelCase__  )
					    == "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(UpperCAmelCase__  )
					    == "None->None->Node(10)->77.9->Hello, world!->-192.55555->0->5555->"
					    "7->dlrow olleH->Node(77345112)->100->Node(Hello again, world!)"
					)


def 			UpperCAmelCase_				(      ):
					from doctest import testmod

					testmod()

					lowercase_  							=			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(UpperCAmelCase__  )
					print("""\nReading/changing Node data using indexing:"""  )
					print(F'''Element at Position 1: {linked_list[1]}'''  )
					lowercase_  							=			input("""Enter New Value: """  ).strip()
					print("""New list:"""  )
					print(UpperCAmelCase__  )
					print(F'''length of linked_list is : {len(UpperCAmelCase__  )}'''  )


if __name__ == "__main__":
							main()






def 			UpperCAmelCase_				(      UpperCAmelCase__  ):
					return " ".join(input_str.split()[::-1]  )


if __name__ == "__main__":
							import doctest

							doctest.testmod()


