import unittest

import numpy as np
import timeout_decorator  # noqa

from transformers import BlenderbotSmallConfig, is_flax_available
from transformers.testing_utils import require_flax, slow

from ...generation.test_flax_utils import FlaxGenerationTesterMixin
from ...test_modeling_flax_common import FlaxModelTesterMixin, ids_tensor


if is_flax_available():
		import os

		# The slow tests are often failing with OOM error on GPU
		# This makes JAX allocate exactly what is needed on demand, and deallocate memory that is no longer needed
		# but will be slower as stated here https://jax.readthedocs.io/en/latest/gpu_memory_allocation.html
		__a    :	Optional[int]         =    """platform"""

		import jax
		import jax.numpy as jnp

		from transformers.models.blenderbot_small.modeling_flax_blenderbot_small import (
		    FlaxBlenderbotSmallForConditionalGeneration,
		    FlaxBlenderbotSmallModel,
		    shift_tokens_right,
		)





def 							UpperCAmelCase		(       lowercase				,     lowercase				,     lowercase=None				,     lowercase=None				,     lowercase=None				,     lowercase=None				,     lowercase=None				,     lowercase=None				,     ):







				"""simple docstring"""



				if attention_mask is None:
								__lowercase					     =				np.where(input_ids != config.pad_token_id				,     1				,     0				)
				if decoder_attention_mask is None:
								__lowercase					     =				np.where(decoder_input_ids != config.pad_token_id				,     1				,     0				)
				if head_mask is None:
								__lowercase					     =				np.ones((config.encoder_layers, config.encoder_attention_heads)				)
				if decoder_head_mask is None:
								__lowercase					     =				np.ones((config.decoder_layers, config.decoder_attention_heads)				)
				if cross_attn_head_mask is None:
								__lowercase					     =				np.ones((config.decoder_layers, config.decoder_attention_heads)				)
				return {
				    "input_ids": input_ids,
				    "decoder_input_ids": decoder_input_ids,
				    "attention_mask": attention_mask,
				    "decoder_attention_mask": attention_mask,
				}




class   _UpperCamelCase :


			"""simple docstring"""






			def __init__(  self ,  lowerCAmelCase__ ,  lowerCAmelCase__=13 ,  lowerCAmelCase__=7 ,  lowerCAmelCase__=True ,  lowerCAmelCase__=False ,  lowerCAmelCase__=99 ,  lowerCAmelCase__=16 ,  lowerCAmelCase__=2 ,  lowerCAmelCase__=4 ,  lowerCAmelCase__=4 ,  lowerCAmelCase__="gelu" ,  lowerCAmelCase__=0.1 ,  lowerCAmelCase__=0.1 ,  lowerCAmelCase__=32 ,  lowerCAmelCase__=2 ,  lowerCAmelCase__=1 ,  lowerCAmelCase__=0 ,  lowerCAmelCase__=0.02 ,  )	->   List[str]:

							'''simple docstring'''


							__lowercase					     =				parent
							__lowercase					     =				batch_size
							__lowercase					     =				seq_length
							__lowercase					     =				is_training
							__lowercase					     =				use_labels
							__lowercase					     =				vocab_size
							__lowercase					     =				hidden_size
							__lowercase					     =				num_hidden_layers
							__lowercase					     =				num_attention_heads
							__lowercase					     =				intermediate_size
							__lowercase					     =				hidden_act
							__lowercase					     =				hidden_dropout_prob
							__lowercase					     =				attention_probs_dropout_prob
							__lowercase					     =				max_position_embeddings
							__lowercase					     =				eos_token_id
							__lowercase					     =				pad_token_id
							__lowercase					     =				bos_token_id
							__lowercase					     =				initializer_range





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   Tuple:

							'''simple docstring'''


							__lowercase					     =				np.clip(ids_tensor([self.batch_size, self.seq_length - 1] ,  self.vocab_size		) ,  3 ,  self.vocab_size		)
							__lowercase					     =				np.concatenate((input_ids, 2 * np.ones((self.batch_size, 1) ,  dtype=np.intaa		)) ,  -1		)

							__lowercase					     =				shift_tokens_right(lowerCAmelCase__ ,  1 ,  2		)

							__lowercase					     =				BlenderbotSmallConfig(
							    vocab_size=self.vocab_size ,  d_model=self.hidden_size ,  encoder_layers=self.num_hidden_layers ,  decoder_layers=self.num_hidden_layers ,  encoder_attention_heads=self.num_attention_heads ,  decoder_attention_heads=self.num_attention_heads ,  encoder_ffn_dim=self.intermediate_size ,  decoder_ffn_dim=self.intermediate_size ,  dropout=self.hidden_dropout_prob ,  attention_dropout=self.attention_probs_dropout_prob ,  max_position_embeddings=self.max_position_embeddings ,  eos_token_id=self.eos_token_id ,  bos_token_id=self.bos_token_id ,  pad_token_id=self.pad_token_id ,  initializer_range=self.initializer_range ,  use_cache=lowerCAmelCase__ ,  )
							__lowercase					     =				prepare_blenderbot_inputs_dict(lowerCAmelCase__ ,  lowerCAmelCase__ ,  lowerCAmelCase__		)
							return config, inputs_dict





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   Optional[int]:

							'''simple docstring'''


							__lowercase     ,	__lowercase					     =				self.prepare_config_and_inputs()
							return config, inputs_dict





			def 			_SCREAMING_SNAKE_CASE     (  self ,  lowerCAmelCase__ ,  lowerCAmelCase__ ,  lowerCAmelCase__		)	->   List[Any]:

							'''simple docstring'''


							__lowercase					     =				20
							__lowercase					     =				model_class_name(lowerCAmelCase__		)

							__lowercase					     =				model.encode(inputs_dict['''input_ids''']		)

							__lowercase     ,	__lowercase					     =				(
							    inputs_dict['''decoder_input_ids'''],
							    inputs_dict['''decoder_attention_mask'''],
							)

							__lowercase					     =				model.init_cache(decoder_input_ids.shape[0] ,  lowerCAmelCase__ ,  lowerCAmelCase__		)
							__lowercase					     =				jnp.ones((decoder_input_ids.shape[0], max_decoder_length) ,  dtype='''i4'''		)

							__lowercase					     =				jnp.broadcast_to(
							    jnp.arange(decoder_input_ids.shape[-1] - 1		)[None, :] ,  (decoder_input_ids.shape[0], decoder_input_ids.shape[-1] - 1) ,  )
							__lowercase					     =				model.decode(
							    decoder_input_ids[:, :-1] ,  lowerCAmelCase__ ,  decoder_attention_mask=lowerCAmelCase__ ,  past_key_values=lowerCAmelCase__ ,  decoder_position_ids=lowerCAmelCase__ ,  )

							__lowercase					     =				jnp.array(decoder_input_ids.shape[0] * [[decoder_input_ids.shape[-1] - 1]] ,  dtype='''i4'''		)
							__lowercase					     =				model.decode(
							    decoder_input_ids[:, -1:] ,  lowerCAmelCase__ ,  decoder_attention_mask=lowerCAmelCase__ ,  past_key_values=outputs_cache.past_key_values ,  decoder_position_ids=lowerCAmelCase__ ,  )

							__lowercase					     =				model.decode(lowerCAmelCase__ ,  lowerCAmelCase__		)

							__lowercase					     =				np.max(np.abs((outputs_cache_next[0][:, -1, :5] - outputs[0][:, -1, :5])		)		)
							self.parent.assertTrue(diff < 1E-3 ,  msg=F"Max diff is {diff}"		)





			def 			_SCREAMING_SNAKE_CASE     (  self ,  lowerCAmelCase__ ,  lowerCAmelCase__ ,  lowerCAmelCase__		)	->   Optional[int]:

							'''simple docstring'''


							__lowercase					     =				20
							__lowercase					     =				model_class_name(lowerCAmelCase__		)

							__lowercase					     =				model.encode(inputs_dict['''input_ids''']		)

							__lowercase     ,	__lowercase					     =				(
							    inputs_dict['''decoder_input_ids'''],
							    inputs_dict['''decoder_attention_mask'''],
							)

							__lowercase					     =				jnp.concatenate(
							    [
							        decoder_attention_mask,
							        jnp.zeros((decoder_attention_mask.shape[0], max_decoder_length - decoder_attention_mask.shape[1])		),
							    ] ,  axis=-1 ,  )

							__lowercase					     =				model.init_cache(decoder_input_ids.shape[0] ,  lowerCAmelCase__ ,  lowerCAmelCase__		)
							__lowercase					     =				jnp.broadcast_to(
							    jnp.arange(decoder_input_ids.shape[-1] - 1		)[None, :] ,  (decoder_input_ids.shape[0], decoder_input_ids.shape[-1] - 1) ,  )

							__lowercase					     =				model.decode(
							    decoder_input_ids[:, :-1] ,  lowerCAmelCase__ ,  decoder_attention_mask=lowerCAmelCase__ ,  past_key_values=lowerCAmelCase__ ,  decoder_position_ids=lowerCAmelCase__ ,  )
							__lowercase					     =				jnp.array(decoder_input_ids.shape[0] * [[decoder_input_ids.shape[-1] - 1]] ,  dtype='''i4'''		)
							__lowercase					     =				model.decode(
							    decoder_input_ids[:, -1:] ,  lowerCAmelCase__ ,  past_key_values=outputs_cache.past_key_values ,  decoder_attention_mask=lowerCAmelCase__ ,  decoder_position_ids=lowerCAmelCase__ ,  )

							__lowercase					     =				model.decode(lowerCAmelCase__ ,  lowerCAmelCase__ ,  decoder_attention_mask=lowerCAmelCase__		)

							__lowercase					     =				np.max(np.abs((outputs_cache_next[0][:, -1, :5] - outputs[0][:, -1, :5])		)		)
							self.parent.assertTrue(diff < 1E-3 ,  msg=F"Max diff is {diff}"		)




@require_flax
class   _UpperCamelCase (		unittest.TestCase					):


			"""simple docstring"""






			__a    :					str     					=		99





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   Union[str, Any]:

							'''simple docstring'''


							__lowercase					     =				np.array(
							    [
							        [71, 82, 18, 33, 46, 91, 2],
							        [68, 34, 26, 58, 30, 82, 2],
							        [5, 97, 17, 39, 94, 40, 2],
							        [76, 83, 94, 25, 70, 78, 2],
							        [87, 59, 41, 35, 48, 66, 2],
							        [55, 13, 16, 58, 5, 2, 1],  # note padding
							        [64, 27, 31, 51, 12, 75, 2],
							        [52, 64, 86, 17, 83, 39, 2],
							        [48, 61, 9, 24, 71, 82, 2],
							        [26, 1, 60, 48, 22, 13, 2],
							        [21, 5, 62, 28, 14, 76, 2],
							        [45, 98, 37, 86, 59, 48, 2],
							        [70, 70, 50, 9, 28, 0, 2],
							    ] ,  dtype=np.intaa ,  )

							__lowercase					     =				input_ids.shape[0]
							__lowercase					     =				BlenderbotSmallConfig(
							    vocab_size=self.vocab_size ,  d_model=24 ,  encoder_layers=2 ,  decoder_layers=2 ,  encoder_attention_heads=2 ,  decoder_attention_heads=2 ,  encoder_ffn_dim=32 ,  decoder_ffn_dim=32 ,  max_position_embeddings=48 ,  eos_token_id=2 ,  pad_token_id=1 ,  bos_token_id=0 ,  )
							return config, input_ids, batch_size





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   Optional[Any]:

							'''simple docstring'''


							__lowercase     ,	__lowercase     ,	__lowercase					     =				self._get_config_and_data()
							__lowercase					     =				FlaxBlenderbotSmallForConditionalGeneration(lowerCAmelCase__		)
							__lowercase					     =				lm_model(input_ids=lowerCAmelCase__		)
							__lowercase					     =				(batch_size, input_ids.shape[1], config.vocab_size)
							self.assertEqual(outputs['''logits'''].shape ,  lowerCAmelCase__		)





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   str:

							'''simple docstring'''


							__lowercase					     =				BlenderbotSmallConfig(
							    vocab_size=self.vocab_size ,  d_model=14 ,  encoder_layers=2 ,  decoder_layers=2 ,  encoder_attention_heads=2 ,  decoder_attention_heads=2 ,  encoder_ffn_dim=8 ,  decoder_ffn_dim=8 ,  max_position_embeddings=48 ,  )
							__lowercase					     =				FlaxBlenderbotSmallForConditionalGeneration(lowerCAmelCase__		)
							__lowercase					     =				np.array([[71, 82, 18, 33, 46, 91, 2], [68, 34, 26, 58, 30, 2, 1]] ,  dtype=np.intaa		)
							__lowercase					     =				np.array([[82, 71, 82, 18, 2], [58, 68, 2, 1, 1]] ,  dtype=np.intaa		)
							__lowercase					     =				lm_model(input_ids=lowerCAmelCase__ ,  decoder_input_ids=lowerCAmelCase__		)
							__lowercase					     =				(*summary.shape, config.vocab_size)
							self.assertEqual(outputs['''logits'''].shape ,  lowerCAmelCase__		)





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   Union[str, Any]:

							'''simple docstring'''


							__lowercase					     =				np.array([[71, 82, 18, 33, 2, 1, 1], [68, 34, 26, 58, 30, 82, 2]] ,  dtype=np.intaa		)
							__lowercase					     =				shift_tokens_right(lowerCAmelCase__ ,  1 ,  2		)
							__lowercase					     =				np.equal(lowerCAmelCase__ ,  1		).astype(np.floataa		).sum()
							__lowercase					     =				np.equal(lowerCAmelCase__ ,  1		).astype(np.floataa		).sum()
							self.assertEqual(shifted.shape ,  input_ids.shape		)
							self.assertEqual(lowerCAmelCase__ ,  n_pad_before - 1		)
							self.assertTrue(np.equal(shifted[:, 0] ,  2		).all()		)




@require_flax
class   _UpperCamelCase (		_UpperCAmelCase		,unittest.TestCase		,_UpperCAmelCase					):


			"""simple docstring"""






			__a    :					Optional[Any]     					=		True
			__a    :					Any     					=		(
			    (
			        FlaxBlenderbotSmallModel,
			        FlaxBlenderbotSmallForConditionalGeneration,
			    )
			    if is_flax_available()
			    else ()
			)
			__a    :					str     					=		(FlaxBlenderbotSmallForConditionalGeneration,) if is_flax_available() else ()





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   Tuple:

							'''simple docstring'''


							__lowercase					     =				FlaxBlenderbotSmallModelTester(self		)





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   Optional[int]:

							'''simple docstring'''


							__lowercase     ,	__lowercase					     =				self.model_tester.prepare_config_and_inputs()
							for model_class in self.all_model_classes:
											self.model_tester.check_use_cache_forward(lowerCAmelCase__ ,  lowerCAmelCase__ ,  lowerCAmelCase__		)





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   List[str]:

							'''simple docstring'''


							__lowercase     ,	__lowercase					     =				self.model_tester.prepare_config_and_inputs()
							for model_class in self.all_model_classes:
											self.model_tester.check_use_cache_forward_with_attn_mask(lowerCAmelCase__ ,  lowerCAmelCase__ ,  lowerCAmelCase__		)





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   List[str]:

							'''simple docstring'''


							__lowercase     ,	__lowercase					     =				self.model_tester.prepare_config_and_inputs_for_common()

							for model_class in self.all_model_classes:
											with self.subTest(model_class.__name__		):
															__lowercase					     =				self._prepare_for_class(lowerCAmelCase__ ,  lowerCAmelCase__		)
															__lowercase					     =				model_class(lowerCAmelCase__		)

															@jax.jit
															def encode_jitted(lowerCAmelCase__ ,  lowerCAmelCase__=None ,  **lowerCAmelCase__		):
																			return model.encode(input_ids=lowerCAmelCase__ ,  attention_mask=lowerCAmelCase__		)

															with self.subTest('''JIT Enabled'''		):
																			__lowercase					     =				encode_jitted(**lowerCAmelCase__		).to_tuple()

															with self.subTest('''JIT Disabled'''		):
																			with jax.disable_jit():
																							__lowercase					     =				encode_jitted(**lowerCAmelCase__		).to_tuple()

															self.assertEqual(len(lowerCAmelCase__		) ,  len(lowerCAmelCase__		)		)
															for jitted_output, output in zip(lowerCAmelCase__ ,  lowerCAmelCase__		):
																			self.assertEqual(jitted_output.shape ,  output.shape		)





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   Optional[int]:

							'''simple docstring'''


							__lowercase     ,	__lowercase					     =				self.model_tester.prepare_config_and_inputs_for_common()

							for model_class in self.all_model_classes:
											with self.subTest(model_class.__name__		):
															__lowercase					     =				model_class(lowerCAmelCase__		)
															__lowercase					     =				model.encode(inputs_dict['''input_ids'''] ,  inputs_dict['''attention_mask''']		)

															__lowercase					     =				{
															    '''decoder_input_ids''': inputs_dict['''decoder_input_ids'''],
															    '''decoder_attention_mask''': inputs_dict['''decoder_attention_mask'''],
															    '''encoder_outputs''': encoder_outputs,
															}

															@jax.jit
															def decode_jitted(lowerCAmelCase__ ,  lowerCAmelCase__ ,  lowerCAmelCase__		):
																			return model.decode(
																			    decoder_input_ids=lowerCAmelCase__ ,  decoder_attention_mask=lowerCAmelCase__ ,  encoder_outputs=lowerCAmelCase__ ,  )

															with self.subTest('''JIT Enabled'''		):
																			__lowercase					     =				decode_jitted(**lowerCAmelCase__		).to_tuple()

															with self.subTest('''JIT Disabled'''		):
																			with jax.disable_jit():
																							__lowercase					     =				decode_jitted(**lowerCAmelCase__		).to_tuple()

															self.assertEqual(len(lowerCAmelCase__		) ,  len(lowerCAmelCase__		)		)
															for jitted_output, output in zip(lowerCAmelCase__ ,  lowerCAmelCase__		):
																			self.assertEqual(jitted_output.shape ,  output.shape		)





			@slow
			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   List[Any]:

							'''simple docstring'''


							for model_class_name in self.all_model_classes:
											__lowercase					     =				model_class_name.from_pretrained('''facebook/blenderbot_small-90M'''		)
											# FlaxBlenderbotForSequenceClassification expects eos token in input_ids
											__lowercase					     =				np.ones((1, 1)		) * model.config.eos_token_id
											__lowercase					     =				model(lowerCAmelCase__		)
											self.assertIsNotNone(lowerCAmelCase__		)
from typing import Any




class   _UpperCamelCase :


			"""simple docstring"""






			def __init__(  self ,  lowerCAmelCase__		)	->   int:

							'''simple docstring'''


							__lowercase					     =				data
							__lowercase					     =				None





			def __repr__(  self		)	->   str:

							'''simple docstring'''


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




class   _UpperCamelCase :


			"""simple docstring"""






			def __init__(  self		)	->   Optional[Any]:

							'''simple docstring'''


							__lowercase					     =				None





			def __iter__(  self		)	->   Any:

							'''simple docstring'''


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





			def __len__(  self		)	->   int:

							'''simple docstring'''


							return sum(1 for _ in self		)





			def __repr__(  self		)	->   str:

							'''simple docstring'''


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





			def __getitem__(  self ,  lowerCAmelCase__		)	->   Any:

							'''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 ,  lowerCAmelCase__ ,  lowerCAmelCase__		)	->   None:

							'''simple docstring'''


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





			def 			_SCREAMING_SNAKE_CASE     (  self ,  lowerCAmelCase__		)	->   None:

							'''simple docstring'''


							self.insert_nth(len(self		) ,  lowerCAmelCase__		)





			def 			_SCREAMING_SNAKE_CASE     (  self ,  lowerCAmelCase__		)	->   None:

							'''simple docstring'''


							self.insert_nth(0 ,  lowerCAmelCase__		)





			def 			_SCREAMING_SNAKE_CASE     (  self ,  lowerCAmelCase__ ,  lowerCAmelCase__		)	->   None:

							'''simple docstring'''


							if not 0 <= index <= len(self		):
											raise IndexError('''list index out of range'''		)
							__lowercase					     =				Node(lowerCAmelCase__		)
							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 			_SCREAMING_SNAKE_CASE     (  self		)	->   None:  # print every node data

							'''simple docstring'''


							print(self		)





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   Any:

							'''simple docstring'''


							return self.delete_nth(0		)





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   Any:  # delete from tail

							'''simple docstring'''


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





			def 			_SCREAMING_SNAKE_CASE     (  self ,  lowerCAmelCase__ = 0		)	->   Any:

							'''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 			_SCREAMING_SNAKE_CASE     (  self		)	->   bool:

							'''simple docstring'''


							return self.head is None





			def 			_SCREAMING_SNAKE_CASE     (  self		)	->   None:

							'''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		(       ):







				"""simple docstring"""



				__lowercase					     =				LinkedList()
				assert linked_list.is_empty() is True
				assert str(lowercase				) == ""

				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(lowercase				) == i
								linked_list.insert_nth(lowercase				,     i + 1				)
				assert str(lowercase				) == "->".join(str(lowercase				) for i in range(1				,     11				)				)

				linked_list.insert_head(0				)
				linked_list.insert_tail(11				)
				assert str(lowercase				) == "->".join(str(lowercase				) 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(lowercase				) == 9
				assert str(lowercase				) == "->".join(str(lowercase				) 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				):
								__lowercase					     =				-i
				assert all(linked_list[i] == -i for i in range(0				,     9				)				) is True

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





def 							UpperCAmelCase		(       ):







				"""simple docstring"""



				__lowercase					     =				[
				    -9,
				    100,
				    Node(77345112				),
				    '''dlrow olleH''',
				    7,
				    5555,
				    0,
				    -192.55555,
				    '''Hello, world!''',
				    77.9,
				    Node(10				),
				    None,
				    None,
				    12.20,
				]
				__lowercase					     =				LinkedList()

				for i in test_input:
								linked_list.insert_tail(lowercase				)

				# Check if it's empty or not
				assert linked_list.is_empty() is False
				assert (
				    str(lowercase				) == "-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(lowercase				) == "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(lowercase				) == "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(10				)
				assert result is None
				assert (
				    str(lowercase				) == "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(lowercase				)
				    == "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(lowercase				)
				assert (
				    str(lowercase				)
				    == "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(lowercase				)
				    == "None->None->Node(10)->77.9->Hello, world!->-192.55555->0->5555->"
				    "7->dlrow olleH->Node(77345112)->100->Node(Hello again, world!)"
				)





def 							UpperCAmelCase		(       ):







				"""simple docstring"""



				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(lowercase				)
				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(lowercase				)
				print(F"length of linked_list is : {len(lowercase				)}"				)


if __name__ == "__main__":
		main()