Function that generates the OpenSignalsTools Notebooks File Hierarchy programatically.

    ----------
    Parameters
    ----------
    root : None or str
        The file path where the OpenSignalsTools Environment will be stored.

    update : bool
        If True the old files will be replaced by the new ones.

    clone : bool
        If True then all the available Notebooks will be stored in the users computer.
        If False only the folder hierarchy of OpenSignalsTools will be generated, giving to the
        user a blank template for creating his own Notebook Environment.

    Returns
    -------
    out : str
        The root file path of OpenSignalsTools Environment is returned.

def opensignals_hierarchy(root=None, update=False, clone=False):
    """
    Function that generates the OpenSignalsTools Notebooks File Hierarchy programatically.

    ----------
    Parameters
    ----------
    root : None or str
        The file path where the OpenSignalsTools Environment will be stored.

    update : bool
        If True the old files will be replaced by the new ones.

    clone : bool
        If True then all the available Notebooks will be stored in the users computer.
        If False only the folder hierarchy of OpenSignalsTools will be generated, giving to the
        user a blank template for creating his own Notebook Environment.

    Returns
    -------
    out : str
        The root file path of OpenSignalsTools Environment is returned.
    """

    if root is None:
        root = os.getcwd()

    categories = list(NOTEBOOK_KEYS.keys())

    # ============================ Creation of the main directory ==================================
    current_dir = root + "\\opensignalstools_environment"
    if not os.path.isdir(current_dir):
        os.makedirs(current_dir)

    # ================== Copy of 'images' 'styles' and 'signal_samples' folders ====================
    for var in ["images", "styles", "signal_samples"]:
        if not os.path.isdir(root + "\\opensignalstools_environment\\" + var):
            src = os.getcwd() + "\\" + var
            destination = current_dir + "\\" + var
            shutil.copytree(src, destination)
        elif update is True:
            shutil.rmtree(root + "\\opensignalstools_environment\\" + var)
            src = os.getcwd() + "\\" + var
            destination = current_dir + "\\" + var
            shutil.copytree(src, destination)

    # =========================== Generation of 'Categories' folder ================================
    current_dir = root + "\\opensignalstools_environment\\Categories"
    if not os.path.isdir(current_dir):
        os.makedirs(current_dir)

    for category in categories:
        if not os.path.isdir(current_dir + "\\" + category):
            os.makedirs(current_dir + "\\" + category)

    if clone is True:
        # Fill each folder inside "Categories" directory with the respective notebooks.
        # Each notebook will be created by a specific function.
        dir_path = root + "\\notebook_code"
        list_of_code_dirs = os.listdir(dir_path)
        for folder in list_of_code_dirs:
            folder_path = root + "\\notebook_code\\" + folder
            if folder != "MainFiles" and folder != "__pycache__":
                list_of_code_files = os.listdir(folder_path)
                for file in list_of_code_files:
                    if file != "__pycache__":
                        spec = importlib.util.spec_from_file_location(file, folder_path +
                                                                      "\\" + file)
                        foo = importlib.util.module_from_spec(spec)
                        spec.loader.exec_module(foo)
                        foo.run(root + "\\opensignalstools_environment")

        # Generation of opensignalstools environment main files.
        main_page = notebook("Main_Files_By_Category")
        main_page.write_to_file(root + "\\opensignalstools_environment", "opensignalstools",
                                footer=False)

        by_difficulty = notebook("Main_Files_By_Difficulty", "Notebooks Grouped by Difficulty", notebook_description=DESCRIPTION_GROUP_BY)
        by_difficulty.write_to_file(root + "\\opensignalstools_environment", "by_diff",
                                    footer=False)

        by_tags = notebook("Main_Files_By_Tag", "Notebooks Grouped by Tag Values",
                           notebook_description=DESCRIPTION_GROUP_BY)
        by_tags.write_to_file(root + "\\opensignalstools_environment", "by_tag",
                              footer=False)

        by_signal_type = notebook("Main_Files_By_Signal_Type", "Notebooks Grouped by Signal Type",
                                  notebook_description=DESCRIPTION_GROUP_BY)
        by_signal_type.write_to_file(root + "\\opensignalstools_environment",
                                     "by_signal_type", footer=False)

        signal_samples = notebook("Main_Files_Signal_Samples", "Signal Samples Library",
                                  notebook_description=DESCRIPTION_SIGNAL_SAMPLES)
        signal_samples.write_to_file(root + "\\opensignalstools_environment",
                                     "signal_samples", footer=False)

    return root + "\\opensignalstools_environment"