docs: def load_state_recursively(parent, state_path=None, dirty_states=[]):
      """Recursively loads the state
  
      It calls this method on each sub-state of a container state.
  
      :param parent:  the root state of the last load call to which the loaded state will be added
      :param state_path: the path on the filesystem where to find the meta file for the state
      :param dirty_states: a dict of states which changed during loading
      :return:
      """
      from rafcon.core.states.execution_state import ExecutionState
      from rafcon.core.states.container_state import ContainerState
      from rafcon.core.states.hierarchy_state import HierarchyState
  
      path_core_data = os.path.join(state_path, FILE_NAME_CORE_DATA)
  
      logger.debug("Load state recursively: {0}".format(str(state_path)))
  
      # TODO: Should be removed with next minor release
      if not os.path.exists(path_core_data):
          path_core_data = os.path.join(state_path, FILE_NAME_CORE_DATA_OLD)
  
      try:
          state_info = load_data_file(path_core_data)
      except ValueError as e:
          logger.exception("Error while loading state data: {0}".format(e))
          return
      except LibraryNotFoundException as e:
          logger.error("Library could not be loaded: {0}\n"
                       "Skipping library and continuing loading the state machine".format(e))
          state_info = storage_utils.load_objects_from_json(path_core_data, as_dict=True)
          state_id = state_info["state_id"]
          dummy_state = HierarchyState(LIBRARY_NOT_FOUND_DUMMY_STATE_NAME, state_id=state_id)
          # set parent of dummy state
          if isinstance(parent, ContainerState):
              parent.add_state(dummy_state, storage_load=True)
          else:
              dummy_state.parent = parent
          return dummy_state
  
      # Transitions and data flows are not added when loading a state, as also states are not added.
      # We have to wait until the child states are loaded, before adding transitions and data flows, as otherwise the
      # validity checks for transitions and data flows would fail
      if not isinstance(state_info, tuple):
          state = state_info
      else:
          state = state_info[0]
          transitions = state_info[1]
          data_flows = state_info[2]
  
      # set parent of state
      if parent is not None and isinstance(parent, ContainerState):
          parent.add_state(state, storage_load=True)
      else:
          state.parent = parent
  
      # read script file if an execution state
      if isinstance(state, ExecutionState):
          script_text = read_file(state_path, state.script.filename)
          state.script_text = script_text
  
      # load semantic data
      try:
          semantic_data = load_data_file(os.path.join(state_path, SEMANTIC_DATA_FILE))
          state.semantic_data = semantic_data
      except Exception as e:
          # semantic data file does not have to be there
          pass
  
      one_of_my_child_states_not_found = False
  
      # load child states
      for p in os.listdir(state_path):
          child_state_path = os.path.join(state_path, p)
          if os.path.isdir(child_state_path):
              child_state = load_state_recursively(state, child_state_path, dirty_states)
              if child_state.name is LIBRARY_NOT_FOUND_DUMMY_STATE_NAME:
                  one_of_my_child_states_not_found = True
  
      if one_of_my_child_states_not_found:
          # omit adding transitions and data flows in this case
          pass
      else:
          # Now we can add transitions and data flows, as all child states were added
          if isinstance(state_info, tuple):
              state.transitions = transitions
              state.data_flows = data_flows
  
      state.file_system_path = state_path
  
      if state.marked_dirty:
          dirty_states.append(state)
  
      return state