

import logging
import math
from functools import partial
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Union

import torch

from .tensor_utils import tensor_tree_map, tree_map



def   __UpperCAmelCase					(      __a :     Any      )     ->	Any:

					"""simple docstring"""

					_a      :       List[str]   =						[]
					if isinstance(__a						,__a      ):
										for v in tree.values():
															shapes.extend(_fetch_dims(__a      )      )
					elif isinstance(__a						,(list, tuple)      ):
										for t in tree:
															shapes.extend(_fetch_dims(__a      )      )
					elif isinstance(__a						,torch.Tensor      ):
										shapes.append(tree.shape      )
					else:
										raise ValueError('''Not supported'''      )

					return shapes



@torch.jit.ignore
def   __UpperCAmelCase					(      __a :     Optional[int]						,__a :     str      )     ->	Any:

					"""simple docstring"""

					_a      :       Optional[Any]   =						[]
					for d in reversed(__a      ):
										idx.append(flat_idx % d      )
										_a      :       Tuple   =						flat_idx // d

					return tuple(reversed(__a      )      )



@torch.jit.ignore
def   __UpperCAmelCase					(      __a :     Tuple						,__a :     Tuple						,__a :     Any						,__a :     Union[str, Any] = None						,__a :     int = None						,)     ->	Union[str, Any]:

					"""simple docstring"""

					def reduce_edge_list(__a :     Union[str, Any]      ) -> None:
										_a      :       List[str]   =						True
										for i in range(len(__a      )      ):
															_a      :       List[Any]   =						-1 * (i + 1)
															l[reversed_idx] &= tally
															_a      :       List[Any]   =						l[reversed_idx]

					if start_edges is None:
										_a      :       List[Any]   =						[s == 0 for s in start]
										reduce_edge_list(__a      )
					if end_edges is None:
										_a      :       List[str]   =						[e == (d - 1) for e, d in zip(__a						,__a      )]
										reduce_edge_list(__a      )

					# Base cases. Either start/end are empty and we're done, or the final,
					# one-dimensional tensor can be simply sliced
					if len(__a      ) == 0:
										return [()]
					elif len(__a      ) == 1:
										return [(slice(start[0]						,end[0] + 1      ),)]

					_a      :       List[Tuple[slice, ...]]   =						[]
					_a      :       List[slice]   =						[]

					# Dimensions common to start and end can be selected directly
					for s, e in zip(__a						,__a      ):
										if s == e:
															path_list.append(slice(__a						,s + 1      )      )
										else:
															break

					_a      :       Tuple[slice, ...]   =						tuple(__a      )
					_a      :       List[Any]   =						len(__a      )

					# start == end, and we're done
					if divergence_idx == len(__a      ):
										return [path]

					def upper() -> Tuple[Tuple[slice, ...], ...]:
										assert start_edges is not None
										assert end_edges is not None

										_a      :       Any   =						start[divergence_idx]
										return tuple(
										    path + (slice(__a						,sdi + 1      ),) + s
										    for s in _get_minimal_slice_set(
										        start[divergence_idx + 1 :]						,[d - 1 for d in dims[divergence_idx + 1 :]]						,dims[divergence_idx + 1 :]						,start_edges=start_edges[divergence_idx + 1 :]						,end_edges=[True for _ in end_edges[divergence_idx + 1 :]]						,)      )

					def lower() -> Tuple[Tuple[slice, ...], ...]:
										assert start_edges is not None
										assert end_edges is not None

										_a      :       List[str]   =						end[divergence_idx]
										return tuple(
										    path + (slice(__a						,edi + 1      ),) + s
										    for s in _get_minimal_slice_set(
										        [0 for _ in start[divergence_idx + 1 :]]						,end[divergence_idx + 1 :]						,dims[divergence_idx + 1 :]						,start_edges=[True for _ in start_edges[divergence_idx + 1 :]]						,end_edges=end_edges[divergence_idx + 1 :]						,)      )

					# If both start and end are at the edges of the subtree rooted at
					# divergence_idx, we can just select the whole subtree at once
					if start_edges[divergence_idx] and end_edges[divergence_idx]:
										slices.append(path + (slice(start[divergence_idx]						,end[divergence_idx] + 1      ),)      )
					# If just start is at the edge, we can grab almost all of the subtree,
					# treating only the ragged bottom edge as an edge case
					elif start_edges[divergence_idx]:
										slices.append(path + (slice(start[divergence_idx]						,end[divergence_idx]      ),)      )
										slices.extend(lower()      )
					# Analogous to the previous case, but the top is ragged this time
					elif end_edges[divergence_idx]:
										slices.extend(upper()      )
										slices.append(path + (slice(start[divergence_idx] + 1						,end[divergence_idx] + 1      ),)      )
					# If both sides of the range are ragged, we need to handle both sides
					# separately. If there's contiguous meat in between them, we can index it
					# in one big chunk
					else:
										slices.extend(upper()      )
										_a      :       Tuple   =						end[divergence_idx] - start[divergence_idx]
										if middle_ground > 1:
															slices.append(path + (slice(start[divergence_idx] + 1						,end[divergence_idx]      ),)      )
										slices.extend(lower()      )

					return slices



@torch.jit.ignore
def   __UpperCAmelCase					(      __a :     int						,__a :     List[str]						,__a :     Union[str, Any]						,__a :     Optional[int]      )     ->	Optional[int]:

					"""simple docstring"""

					_a      :       str   =						t.shape[:no_batch_dims]
					_a      :       Optional[Any]   =						list(_flat_idx_to_idx(__a						,__a      )      )
					# _get_minimal_slice_set is inclusive
					_a      :       Tuple   =						list(_flat_idx_to_idx(flat_end - 1						,__a      )      )

					# Get an ordered list of slices to perform
					_a      :       Optional[Any]   =						_get_minimal_slice_set(
					    __a						,__a						,__a						,)

					_a      :       Optional[int]   =						[t[s] for s in slices]

					return torch.cat([s.view((-1,) + t.shape[no_batch_dims:]      ) for s in sliced_tensors]      )



def   __UpperCAmelCase					(      __a :     List[Any]						,__a :     Dict						,__a :     List[str]						,__a :     int						,__a :     Optional[Any] = False						,__a :     Any = None						,__a :     Tuple = False						,)     ->	int:

					"""simple docstring"""

					if not (len(__a      ) > 0):
										raise ValueError('''Must provide at least one input'''      )

					_a      :       List[Any]   =						[shape[:no_batch_dims] for shape in _fetch_dims(__a      )]
					_a      :       int   =						tuple([max(__a      ) for s in zip(*__a      )]      )

					def _prep_inputs(__a :     Union[str, Any]      ) -> torch.Tensor:
										if not low_mem:
															if not sum(t.shape[:no_batch_dims]      ) == no_batch_dims:
																				_a      :       int   =						t.expand(orig_batch_dims + t.shape[no_batch_dims:]      )
															_a      :       int   =						t.reshape(-1						,*t.shape[no_batch_dims:]      )
										else:
															_a      :       Optional[Any]   =						t.expand(orig_batch_dims + t.shape[no_batch_dims:]      )
										return t

					_a      :       Dict[str, Any]   =						tensor_tree_map(_prep_inputs						,__a      )
					_a      :       Optional[Any]   =						None
					if _out is not None:
										_a      :       int   =						tensor_tree_map(lambda __a      : t.view([-1] + list(t.shape[no_batch_dims:]      )      )						,_out      )

					_a      :       Tuple   =						1
					for d in orig_batch_dims:
										flat_batch_dim *= d

					_a      :       Any   =						flat_batch_dim // chunk_size + (flat_batch_dim % chunk_size != 0)

					def _select_chunk(__a :     Union[str, Any]      ) -> torch.Tensor:
										return t[i : i + chunk_size] if t.shape[0] != 1 else t

					_a      :       Optional[int]   =						0
					_a      :       List[Any]   =						prepped_outputs
					for _ in range(__a      ):
										# Chunk the input
										if not low_mem:
															_a      :       Optional[Any]   =						_select_chunk
										else:
															_a      :       Union[str, Any]   =						partial(
															    _chunk_slice						,flat_start=__a						,flat_end=min(__a						,i + chunk_size      )						,no_batch_dims=len(__a      )						,)

										_a      :       Dict[str, Any]   =						tensor_tree_map(__a						,__a      )

										# Run the layer on the chunk
										_a      :       Optional[int]   =						layer(**__a      )

										# Allocate space for the output
										if out is None:
															_a      :       List[Any]   =						tensor_tree_map(lambda __a      : t.new_zeros((flat_batch_dim,) + t.shape[1:]      )						,__a      )

										# Put the chunk in its pre-allocated space
										if isinstance(__a						,__a      ):

															def assign(__a :     str						,__a :     Union[str, Any]      ) -> None:
																				for k, v in da.items():
																									if isinstance(__a						,__a      ):
																														assign(__a						,da[k]      )
																									else:
																														if _add_into_out:
																																			v[i : i + chunk_size] += da[k]
																														else:
																																			_a      :       int   =						da[k]

															assign(__a						,__a      )
										elif isinstance(__a						,__a      ):
															for xa, xa in zip(__a						,__a      ):
																				if _add_into_out:
																									xa[i : i + chunk_size] += xa
																				else:
																									_a      :       List[str]   =						xa
										elif isinstance(__a						,torch.Tensor      ):
															if _add_into_out:
																				out[i : i + chunk_size] += output_chunk
															else:
																				_a      :       str   =						output_chunk
										else:
															raise ValueError('''Not supported'''      )

										i += chunk_size

					_a      :       List[Any]   =						tensor_tree_map(lambda __a      : t.view(orig_batch_dims + t.shape[1:]      )						,__a      )

					return out







class 							UpperCAmelCase_						:
							"""simple docstring"""







							def __init__(     self			,				_a = 5_1_2			,				)       ->       Optional[Any]:
												_a      :       List[str]   =						max_chunk_size
												_a      :       Optional[int]   =						None
												_a      :       Optional[tuple]   =						None


							def 							__lowercase							(     self			,				_a			,				_a			,				_a			)       ->       int:
												logging.info('''Tuning chunk size...'''			)

												if min_chunk_size >= self.max_chunk_size:
																	return min_chunk_size

												_a      :       List[int]   =						[2**l for l in range(int(math.log(self.max_chunk_size			,				2			)			) + 1			)]
												_a      :       List[str]   =						[c for c in candidates if c > min_chunk_size]
												_a      :       Optional[int]   =						[min_chunk_size] + candidates
												candidates[-1] += 4

												def test_chunk_size(_a			) -> bool:
																	try:
																						with torch.no_grad():
																											fn(*_a			,				chunk_size=_a			)
																						return True
																	except RuntimeError:
																						return False

												_a      :       Optional[int]   =						0
												_a      :       List[str]   =						len(_a			) - 1
												while i > min_viable_chunk_size_index:
																	_a      :       List[Any]   =						test_chunk_size(candidates[i]			)
																	if not viable:
																						_a      :       Any   =						(min_viable_chunk_size_index + i) // 2
																	else:
																						_a      :       Dict   =						i
																						_a      :       Dict   =						(i + len(_a			) - 1) // 2

												return candidates[min_viable_chunk_size_index]


							def 							__lowercase							(     self			,				_a			,				_a			)       ->       bool:
												_a      :       Dict   =						True
												for aa, aa in zip(_a			,				_a			):
																	assert type(_a			) == type(_a			)
																	if isinstance(_a			,				(list, tuple)			):
																						consistent &= self._compare_arg_caches(_a			,				_a			)
																	elif isinstance(_a			,				_a			):
																						_a      :       Union[str, Any]   =						[v for _, v in sorted(aa.items()			,				key=lambda _a			: x[0]			)]
																						_a      :       Union[str, Any]   =						[v for _, v in sorted(aa.items()			,				key=lambda _a			: x[0]			)]
																						consistent &= self._compare_arg_caches(_a			,				_a			)
																	else:
																						consistent &= aa == aa

												return consistent




							def 							__lowercase							(     self			,				_a			,				_a			,				_a			,				)       ->       int:
												_a      :       Dict   =						True
												_a      :       tuple   =						tree_map(lambda _a			: a.shape if isinstance(_a			,				torch.Tensor			) else a			,				_a			,				_a			)
												if self.cached_arg_data is not None:
																	# If args have changed shape/value, we need to re-tune
																	assert len(self.cached_arg_data			) == len(_a			)
																	_a      :       Dict   =						self._compare_arg_caches(self.cached_arg_data			,				_a			)
												else:
																	# Otherwise, we can reuse the precomputed value
																	_a      :       Dict   =						False

												if not consistent:
																	_a      :       Optional[int]   =						self._determine_favorable_chunk_size(
																	    _a			,				_a			,				_a			,				)
																	_a      :       Union[str, Any]   =						arg_data

												assert self.cached_chunk_size is not None

												return self.cached_chunk_size










def    _A	(   lowerCamelCase ):
   a__						:    Optional[Any]   		=	1
   for i in range(1				,			num + 1 ):
      fact *= i
   return fact






def    _A	(   lowerCamelCase ):
   a__						:    List[Any]   		=	0
   while number > 0:
      a__						:    str   		=	number % 10
      sum_of_digits += last_digit
      a__						:    Dict   		=	number // 10  # Removing the last_digit from the given number
   return sum_of_digits






def    _A	(   lowerCamelCase = 100 ):
   a__						:    Any   		=	factorial(lowerCamelCase )
   a__						:    Optional[Any]   		=	split_and_add(lowerCamelCase )
   return result


if __name__ == "__main__":
  print(solution(int(input("""Enter the Number: """).strip())))

