'''simple docstring'''




from importlib import import_module

from .logging import get_logger


__SCREAMING_SNAKE_CASE       :     Dict     =  get_logger(__name__)

class 	lowerCamelCase_	:
      '''simple docstring'''

      def __init__(       self						:				Dict						,					A						:				Dict						,					A						:				Union[str, Any]=None       ):
             _UpperCAmelCase     :  str							      =    attrs or []
             if module is not None:
                    for key in module.__dict__:
                           if key in attrs or not key.startswith("__"       ):
                                  setattr(self						,					A						,					getattr(A						,					A       )       )
             _UpperCAmelCase     :  str							      =    module._original_module if isinstance(A						,					_PatchedModuleObj       ) else module

class 	lowerCamelCase_	:
      '''simple docstring'''

      __UpperCamelCase:  Tuple						=						[]




      def __init__(       self						:				int						,					A						:				int						,					A						:				str						,					A						:				Union[str, Any]						,					A						:				Dict=None       ):
             _UpperCAmelCase     :  Tuple							      =    obj
             _UpperCAmelCase     :  List[Any]							      =    target
             _UpperCAmelCase     :  Any							      =    new
             _UpperCAmelCase     :  str							      =    target.split("."       )[0]
             _UpperCAmelCase     :  Optional[int]							      =    {}
             _UpperCAmelCase     :  str							      =    attrs or []




      def __enter__(       self						:				List[str]       ):
             *_UpperCAmelCase      ,  _UpperCAmelCase     :  Union[str, Any]							      =    self.target.split("."       )

             # Patch modules:
             # it's used to patch attributes of submodules like "os.path.join";
             # in this case we need to patch "os" and "os.path"

             for i in range(len(A       )       ):
                    try:
                           _UpperCAmelCase     :  str							      =    import_module(".".join(submodules[: i + 1]       )       )
                    except ModuleNotFoundError:
                           continue
                    # We iterate over all the globals in self.obj in case we find "os" or "os.path"
                    for attr in self.obj.__dir__():
                           _UpperCAmelCase     :  Optional[Any]							      =    getattr(self.obj						,					A       )
                           # We don't check for the name of the global, but rather if its value *is* "os" or "os.path".
                           # This allows to patch renamed modules like "from os import path as ospath".
                           if obj_attr is submodule or (
                               (isinstance(A						,					_PatchedModuleObj       ) and obj_attr._original_module is submodule)
                           ):
                                  _UpperCAmelCase     :  Optional[Any]							      =    obj_attr
                                  # patch at top level
                                  setattr(self.obj						,					A						,					_PatchedModuleObj(A						,					attrs=self.attrs       )       )
                                  _UpperCAmelCase     :  int							      =    getattr(self.obj						,					A       )
                                  # construct lower levels patches
                                  for key in submodules[i + 1 :]:
                                         setattr(A						,					A						,					_PatchedModuleObj(getattr(A						,					A						,					A       )						,					attrs=self.attrs       )       )
                                         _UpperCAmelCase     :  str							      =    getattr(A						,					A       )
                                  # finally set the target attribute
                                  setattr(A						,					A						,					self.new       )

        # Patch attribute itself:
        # it's used for builtins like "open",
        # and also to patch "os.path.join" we may also need to patch "join"
        # itself if it was imported as "from os.path import join".

             if submodules:  # if it's an attribute of a submodule like "os.path.join"
                    try:
                           _UpperCAmelCase     :  int							      =    getattr(import_module(".".join(A       )       )						,					A       )
                    except (AttributeError, ModuleNotFoundError):
                           return
                    # We iterate over all the globals in self.obj in case we find "os.path.join"
                    for attr in self.obj.__dir__():
                           # We don't check for the name of the global, but rather if its value *is* "os.path.join".
                           # This allows to patch renamed attributes like "from os.path import join as pjoin".
                           if getattr(self.obj						,					A       ) is attr_value:
                                  _UpperCAmelCase     :  List[Any]							      =    getattr(self.obj						,					A       )
                                  setattr(self.obj						,					A						,					self.new       )
             elif target_attr in globals()["__builtins__"]:  # if it'a s builtin like "open"
                    _UpperCAmelCase     :  Union[str, Any]							      =    globals()["__builtins__"][target_attr]
                    setattr(self.obj						,					A						,					self.new       )
             else:
                    raise RuntimeError(F"""Tried to patch attribute {target_attr} instead of a submodule."""       )




      def __exit__(       self						:				Union[str, Any]						,					*A						:				str       ):
             for attr in list(self.original       ):
                    setattr(self.obj						,					A						,					self.original.pop(A       )       )




      def      _A	(       self						:				Dict       ):
             self.__enter__()
             self._active_patches.append(self       )





      def      _A	(       self						:				List[str]       ):
             try:
                    self._active_patches.remove(self       )
             except ValueError:
                    # If the patch hasn't been started this will fail
                    return None

             return self.__exit__()


'''simple docstring'''




def 	UpperCamelCase_							(					_UpperCAmelCase  :      int			,	_UpperCAmelCase  :      int    )    ->    int:


       """simple docstring"""







       _UpperCAmelCase     :  List[str]							      =    1  # To kept the Calculated Value
       # Since C(n, k) = C(n, n-k)
       if k > (n - k):
              _UpperCAmelCase     :  Any							      =    n - k
       # Calculate C(n,k)
       for i in range(_UpperCAmelCase    ):
              result *= n - i
              result //= i + 1
       return result

def 	UpperCamelCase_							(					_UpperCAmelCase  :      int    )    ->    int:


       """simple docstring"""







       return binomial_coefficient(2 * node_count			,	_UpperCAmelCase    ) // (node_count + 1)

def 	UpperCamelCase_							(					_UpperCAmelCase  :      int    )    ->    int:


       """simple docstring"""







       if n < 0:
              raise ValueError("factorial() not defined for negative values"    )
       _UpperCAmelCase     :  List[str]							      =    1
       for i in range(1			,	n + 1    ):
              result *= i
       return result

def 	UpperCamelCase_							(					_UpperCAmelCase  :      int    )    ->    int:


       """simple docstring"""







       return catalan_number(_UpperCAmelCase    ) * factorial(_UpperCAmelCase    )


if __name__ == "__main__":
  __SCREAMING_SNAKE_CASE       :     Dict     =  int(input("""Enter the number of nodes: """).strip() or 0)
  if node_count <= 0:
    raise ValueError("""We need some nodes to work with.""")
  print(
      F'Given {node_count} nodes, there are {binary_tree_count(node_count)} '
      F'binary trees and {catalan_number(node_count)} binary search trees.'
  )

