docs: def generate_raml_tree(flat_resources, api_root):
      """Generate a dict of OrderedDicts, using the URIs of the Pale endpoints as the structure for the tree.
      Each level of the tree will contain a "path" property and an "endpoint" property.
      The "path" will contain further nested endpoints, sorted alphabetically.
      The "endpoint" will contain the documentation on the endpoint that ends at that level.
      """
  
      def clean_angle_brackets(string):
          """Remove the angle brackets from a string and return the cleaned string"""
          if string == None:
              result = None
          elif ":" in string:
              path = re.search("(\w+/<\w+)", string).group(0)
              result = re.sub(r'[<]','{', path)
              result += "}"
          else:
              result = re.sub(r'[>]','}', re.sub(r'[<]','{', string))
          return result
  
      def add_or_find_path(input, tree):
          """Recursively add or find a path to an input dict.
          The tree is a list of directories in nested order.
          Returns a list, containing 1) the innermost node's "endpoint" dict
          and 2) True if it was added as an empty dict, or False if not."""
  
          # if this is the last branch, return or add and return it
          if len(tree) == 1:
              if input.get(tree[0]) != None \
                  and input.get(tree[0]).get("endpoint") != None \
                  and len(input.get(tree[0]).get("endpoint")) > 0:
                  return [input[tree[0]], False]
              else:
                  input[tree[0]] = {}
                  input[tree[0]]["path"] = {}
                  input[tree[0]]["endpoint"] = {}
                  return [input[tree[0]], True]
  
          # if this is not the last branch, check if it exists and add if necessary
          # then recurse on the next one
          else:
              if input.get(tree[0]) == None:
                  input[tree[0]] = {}
                  input[tree[0]]["path"] = {}
              return add_or_find_path(input[tree[0]]["path"], tree[+1:])
  
      def sort_tree_alphabetically(tree):
          """Recursively sort a tree by the keys in each "path" dict.
          Each "path" dict will be converted to an OrderedDict that is sorted alphabetically.
          """
  
          if tree.get("path") != None and len(tree["path"]) > 0:
              sorted_path = OrderedDict(sorted(tree["path"].items(), key=lambda t: t[0]))
              tree["path"] = sorted_path
              for branch in tree["path"]:
                  sort_tree_alphabetically(tree["path"][branch])
  
  
      # use a combination of three regex patterns to find all the components of the path
      # these will be used to generate the nested dict that we will convert to RAML
  
      # pattern #1: matches "path/<id:specialchars>"
      re_dir_nested = "(\w+/[<>\w]+:.*>)"
      # pattern #2: matches "path/<id>""
      re_dir_unique = "(\w+/<[\w\(\)\?\!\.\+]+>)"
      # pattern #3: matches "path" or "<id>" not appearing before "<"
      re_dir_either = "([<>\w\(\)\?\!\.\+]+)(?!<)"
      # combine the patterns
      uri_re_pattern = re_dir_nested + "|" + re_dir_unique + "|" + re_dir_either
  
  
      resource_tree = {}
      resource_tree["path"] = {}
  
      for doc in flat_resources:
  
          if flat_resources[doc].get("uri") != None:
              this_uri = flat_resources[doc]["uri"]
              uri_matches = re.findall(uri_re_pattern, flat_resources[doc]["uri"])
              uri_tree = []
  
              # treat the 'uri' string as a nested path, parsing out each directory and adding
              # to the 'uri_tree' list from left to right
              # leftmost element in list is root of path
              for match in uri_matches:
                  for directory in match:
                      if directory != "" and directory != api_root:
                          branch = directory
                          matched_group = re.search('([\w+/]?[<:!\?\+\(\.\*\)>\w]+>)', directory)
                          if matched_group:
                              nested_prefix = clean_angle_brackets(directory)
                              if nested_prefix != None:
                                  branch = nested_prefix
                          elif "<" in directory:
                              branch = clean_angle_brackets(directory)
                          uri_tree.append(branch)
  
              # find the path within the tree
              target = add_or_find_path(resource_tree["path"], uri_tree)
              # add the endpoint to the tree
              target[0]["endpoint"] = flat_resources[doc]
  
      sort_tree_alphabetically(resource_tree)
      return resource_tree