'''simple docstring'''

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       (   UpperCAmelCase     ):
 lowercase__				:    List[Any]  =					[]
 if isinstance(UpperCAmelCase		,     UpperCAmelCase     ):
  for v in tree.values():
   shapes.extend(_fetch_dims(UpperCAmelCase     )     )
 elif isinstance(UpperCAmelCase		,     (list, tuple)     ):
  for t in tree:
   shapes.extend(_fetch_dims(UpperCAmelCase     )     )
 elif isinstance(UpperCAmelCase		,     torch.Tensor     ):
  shapes.append(tree.shape     )
 else:
  raise ValueError('''Not supported'''     )

 return shapes
@torch.jit.ignore
def 			__UpperCamelCase       (   UpperCAmelCase		,     UpperCAmelCase     ):
 lowercase__				:    Union[str, Any]  =					[]
 for d in reversed(UpperCAmelCase     ):
  idx.append(flat_idx % d     )
  lowercase__				:    Optional[Any]  =					flat_idx // d

 return tuple(reversed(UpperCAmelCase     )     )
@torch.jit.ignore
def 			__UpperCamelCase       (   UpperCAmelCase		,     UpperCAmelCase		,     UpperCAmelCase		,     UpperCAmelCase = None		,     UpperCAmelCase = None		,     ):

 # start_edges and end_edges both indicate whether, starting from any given
 # dimension, the start/end index is at the top/bottom edge of the
 # corresponding tensor, modeled as a tree
 def reduce_edge_list(UpperCAmelCase     ) -> None:
  lowercase__				:    List[str]  =					True
  for i in range(len(UpperCAmelCase     )     ):
   lowercase__				:    str  =					-1 * (i + 1)
   l[reversed_idx] &= tally
   lowercase__				:    List[Any]  =					l[reversed_idx]

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

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

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

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

 lowercase__				:    Tuple[slice, ...]  =					tuple(UpperCAmelCase     )
 lowercase__				:    Dict  =					len(UpperCAmelCase     )

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

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

  lowercase__				:    Union[str, Any]  =					start[divergence_idx]
  return tuple(
      path + (slice(UpperCAmelCase		,     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

  lowercase__				:    Optional[int]  =					end[divergence_idx]
  return tuple(
      path + (slice(UpperCAmelCase		,     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()     )
  lowercase__				:    str  =					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       (   UpperCAmelCase		,     UpperCAmelCase		,     UpperCAmelCase		,     UpperCAmelCase     ):
 lowercase__				:    str  =					t.shape[:no_batch_dims]
 lowercase__				:    Optional[int]  =					list(_flat_idx_to_idx(UpperCAmelCase		,     UpperCAmelCase     )     )
 # _get_minimal_slice_set is inclusive
 lowercase__				:    Dict  =					list(_flat_idx_to_idx(flat_end - 1		,     UpperCAmelCase     )     )

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

 lowercase__				:    Optional[Any]  =					[t[s] for s in slices]

 return torch.cat([s.view((-1,) + t.shape[no_batch_dims:]     ) for s in sliced_tensors]     )
def 			__UpperCamelCase       (   UpperCAmelCase		,     UpperCAmelCase		,     UpperCAmelCase		,     UpperCAmelCase		,     UpperCAmelCase = False		,     UpperCAmelCase = None		,     UpperCAmelCase = False		,     ):
 if not (len(UpperCAmelCase     ) > 0):
  raise ValueError('''Must provide at least one input'''     )

 lowercase__				:    str  =					[shape[:no_batch_dims] for shape in _fetch_dims(UpperCAmelCase     )]
 lowercase__				:    str  =					tuple([max(UpperCAmelCase     ) for s in zip(*UpperCAmelCase     )]     )

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

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

 lowercase__				:    str  =					1
 for d in orig_batch_dims:
  flat_batch_dim *= d

 lowercase__				:    Union[str, Any]  =					flat_batch_dim // chunk_size + (flat_batch_dim % chunk_size != 0)

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

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

  lowercase__				:    Dict[str, Any]  =					tensor_tree_map(UpperCAmelCase		,     UpperCAmelCase     )

  # Run the layer on the chunk
  lowercase__				:    Optional[int]  =					layer(**UpperCAmelCase     )

  # Allocate space for the output
  if out is None:
   lowercase__				:    Union[str, Any]  =					tensor_tree_map(lambda UpperCAmelCase     : t.new_zeros((flat_batch_dim,) + t.shape[1:]     )		,     UpperCAmelCase     )

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

   def assign(UpperCAmelCase		,     UpperCAmelCase     ) -> None:
    for k, v in da.items():
     if isinstance(UpperCAmelCase		,     UpperCAmelCase     ):
      assign(UpperCAmelCase		,     da[k]     )
     else:
      if _add_into_out:
       v[i : i + chunk_size] += da[k]
      else:
       lowercase__				:    int  =					da[k]

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

  i += chunk_size

 lowercase__				:    List[str]  =					tensor_tree_map(lambda UpperCAmelCase     : t.view(orig_batch_dims + t.shape[1:]     )		,     UpperCAmelCase     )

 return out





class 			UpperCAmelCase  :





       '''simple docstring'''



       def __init__(						self	,   __lowerCAmelCase = 512	,   )  ->  Optional[int]:
        lowercase__				:    Optional[Any]  =					max_chunk_size
        lowercase__				:    Optional[int]  =					None
        lowercase__				:    Optional[tuple]  =					None

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

        if min_chunk_size >= self.max_chunk_size:
         return min_chunk_size

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

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

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

        return candidates[min_viable_chunk_size_index]

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

        return consistent


       def _lowerCAmelCase(						self	,   __lowerCAmelCase	,   __lowerCAmelCase	,   __lowerCAmelCase	,   )  ->  int:
        lowercase__				:    str  =					True
        lowercase__				:    tuple  =					tree_map(lambda __lowerCAmelCase : a.shape if isinstance(__lowerCAmelCase	,   torch.Tensor ) else a	,   __lowerCAmelCase	,   __lowerCAmelCase )
        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(__lowerCAmelCase )
         lowercase__				:    int  =					self._compare_arg_caches(self.cached_arg_data	,   __lowerCAmelCase )
        else:
         # Otherwise, we can reuse the precomputed value
         lowercase__				:    Optional[int]  =					False

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

        assert self.cached_chunk_size is not None

        return self.cached_chunk_size


'''simple docstring'''

def 			__UpperCamelCase       (   UpperCAmelCase     ):
 lowercase__				:    Optional[int]  =					1
 for i in range(1		,     num + 1     ):
  fact *= i
 return fact
def 			__UpperCamelCase       (   UpperCAmelCase     ):
 lowercase__				:    Optional[Any]  =					0
 while number > 0:
  lowercase__				:    str  =					number % 10
  sum_of_digits += last_digit
  lowercase__				:    List[str]  =					number // 10  # Removing the last_digit from the given number
 return sum_of_digits
def 			__UpperCamelCase       (   UpperCAmelCase = 100     ):
 lowercase__				:    Optional[int]  =					factorial(UpperCAmelCase     )
 lowercase__				:    Dict  =					split_and_add(UpperCAmelCase     )
 return result


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

