docs: def download_all_inputs(exclude=None, parallel=False, max_threads=8):
      '''
      :param exclude: List of input variables that should not be downloaded.
      :type exclude: Array of strings
      :param parallel: Should we download multiple files in parallel? (default: False)
      :type filename: boolean
      :param max_threads: If parallel is True, how many threads should be used
          to download files? (default: 8)
      :type append: int
      :returns: dict of lists of strings where each key is the input variable
                  and each list element is the full path to the file that has
                  been downloaded.
  
      This function downloads all files that were supplied as inputs to the app.
      By convention, if an input parameter "FOO" has value
  
          {"$dnanexus_link": "file-xxxx"}
  
      and filename INPUT.TXT, then the linked file will be downloaded into the
      path:
  
          $HOME/in/FOO/INPUT.TXT
  
      If an input is an array of files, then all files will be placed into
      numbered subdirectories under a parent directory named for the
      input. For example, if the input key is FOO, and the inputs are {A, B,
      C}.vcf then, the directory structure will be:
  
          $HOME/in/FOO/0/A.vcf
                       1/B.vcf
                       2/C.vcf
  
      Zero padding is used to ensure argument order. For example, if there are
      12 input files {A, B, C, D, E, F, G, H, I, J, K, L}.txt, the directory
      structure will be:
  
          $HOME/in/FOO/00/A.vcf
                       ...
                       11/L.vcf
  
      This allows using shell globbing (FOO/*/*.vcf) to get all the files in the input
      order and prevents issues with files which have the same filename.'''
  
      # Input directory, where all inputs are downloaded
      idir = file_load_utils.get_input_dir()
      try:
          job_input_file = file_load_utils.get_input_json_file()
          dirs, inputs, rest = file_load_utils.get_job_input_filenames(job_input_file)
      except IOError:
          msg = 'Error: Could not find the input json file: {0}.\n'.format(job_input_file)
          msg += '       This function should only be called from within a running job.'
          print(msg)
          raise
  
      # Exclude directories
      # dirs contain all folders (e.g. $HOME/in/FOO) and their sub folders (e.g. $HOME/in/FOO/1, $HOME/in/FOO/2, etc.)
      # If the main folder is excluded, its sub-folder would also be excluded from dirs_to_create
      dirs_to_create = []
      for d in dirs:
          keep = True
          if (exclude is not None) and (d is not None):
              if (d.split('/')[0] in exclude):
                  keep = False
          if keep:
              dirs_to_create.append(d)
  
      # Create the directory structure, in preparation for download.
      # Allows performing the download in parallel.
      _create_dirs(idir, dirs_to_create)
  
      # Remove excluded inputs
      if exclude:
          inputs = file_load_utils.filter_dict(inputs, exclude)
  
      # Convert to a flat list of elements to download
      to_download = []
      for ival_list in inputs.values():
          to_download.extend(ival_list)
  
      # Download the files
      if parallel:
          total_mem = psutil.virtual_memory().total >> 20  # Total RAM in MB
          num_cores = multiprocessing.cpu_count()
          max_num_parallel_downloads = _get_num_parallel_threads(max_threads, num_cores, total_mem)
          sys.stderr.write("Downloading files using {} threads".format(max_num_parallel_downloads))
          _parallel_file_download(to_download, idir, max_num_parallel_downloads)
      else:
          _sequential_file_download(to_download, idir)
  
      helper_vars = _gen_helper_dict(inputs)
      return helper_vars