docs: def _run(self):
          # type: (Downloader) -> None
          """Execute Downloader
          :param Downloader self: this
          """
          # mark start
          self._start_time = blobxfer.util.datetime_now()
          logger.info('blobxfer start time: {0}'.format(self._start_time))
          # ensure destination path
          blobxfer.operations.download.Downloader.ensure_local_destination(
              self._creds, self._spec, self._general_options.dry_run)
          logger.info('downloading blobs/files to local path: {}'.format(
              self._spec.destination.path))
          self._catalog_local_files_for_deletion()
          # initialize resume db if specified
          if self._general_options.resume_file is not None:
              self._resume = blobxfer.operations.resume.DownloadResumeManager(
                  self._general_options.resume_file)
          # initialize MD5 processes
          if (self._spec.options.check_file_md5 and
                  self._general_options.concurrency.md5_processes > 0):
              self._md5_offload = blobxfer.operations.md5.LocalFileMd5Offload(
                  num_workers=self._general_options.concurrency.md5_processes)
              self._md5_offload.initialize_check_thread(
                  self._check_for_downloads_from_md5)
          # initialize crypto processes
          if self._general_options.concurrency.crypto_processes > 0:
              self._crypto_offload = blobxfer.operations.crypto.CryptoOffload(
                  num_workers=self._general_options.concurrency.crypto_processes)
              self._crypto_offload.initialize_check_thread(
                  self._check_for_crypto_done)
          # initialize download threads
          self._initialize_transfer_threads()
          self._initialize_disk_threads()
          # initialize local counters
          files_processed = 0
          skipped_files = 0
          skipped_size = 0
          # iterate through source paths to download
          for src in self._spec.sources:
              for rfile in src.files(
                      self._creds, self._spec.options,
                      self._general_options.dry_run):
                  # form local path for remote file
                  if (not self._spec.destination.is_dir and
                          self._spec.options.rename):
                      lpath = pathlib.Path(self._spec.destination.path)
                  else:
                      lpath = None
                      if self._spec.options.strip_components > 0:
                          _lparts = pathlib.Path(rfile.name).parts
                          _strip = min(
                              (len(_lparts) - 1,
                               self._spec.options.strip_components)
                          )
                          if _strip > 0:
                              lpath = pathlib.Path(*_lparts[_strip:])
                      if lpath is None:
                          lpath = pathlib.Path(rfile.name)
                      lpath = pathlib.Path(self._spec.destination.path) / lpath
                  files_processed += 1
                  # check on download conditions
                  action = self._check_download_conditions(lpath, rfile)
                  # remove from delete after set
                  try:
                      self._delete_after.remove(lpath)
                  except KeyError:
                      pass
                  if action == DownloadAction.Skip:
                      skipped_files += 1
                      skipped_size += rfile.size
                      if self._general_options.dry_run:
                          logger.info('[DRY RUN] skipping: {} -> {}'.format(
                              lpath, rfile.path))
                      continue
                  # add potential download to set
                  dlid = (
                      blobxfer.operations.download.Downloader.
                      create_unique_transfer_operation_id(rfile)
                  )
                  with self._transfer_lock:
                      self._transfer_set.add(dlid)
                      self._download_total += 1
                      self._download_bytes_total += rfile.size
                  # either MD5 check or download now
                  if action == DownloadAction.CheckMd5:
                      self._pre_md5_skip_on_check(lpath, rfile)
                  elif action == DownloadAction.Download:
                      if self._general_options.dry_run:
                          logger.info(
                              '[DRY RUN] download: {} -> {}'.format(
                                  rfile.path, lpath))
                          with self._transfer_lock:
                              self._transfer_set.remove(dlid)
                              self._download_total -= 1
                              self._download_bytes_total -= rfile.size
                      else:
                          self._add_to_download_queue(lpath, rfile)
          # set remote files processed
          with self._md5_meta_lock:
              self._all_remote_files_processed = True
          with self._transfer_lock:
              download_size_mib = (
                  self._download_bytes_total / blobxfer.util.MEGABYTE
              )
              logger.debug(
                  ('{0} files {1:.4f} MiB filesize and/or lmt_ge '
                   'skipped').format(
                      skipped_files, skipped_size / blobxfer.util.MEGABYTE))
              logger.debug(
                  ('{0} remote files processed, waiting for download '
                   'completion of approx. {1:.4f} MiB').format(
                       files_processed, download_size_mib))
          del files_processed
          del skipped_files
          del skipped_size
          # wait for downloads to complete
          self._wait_for_transfer_threads(terminate=False)
          self._wait_for_disk_threads(terminate=False)
          end_time = blobxfer.util.datetime_now()
          # update progress bar
          self._update_progress_bar()
          # check for exceptions
          if len(self._exceptions) > 0:
              logger.error('exceptions encountered while downloading')
              # raise the first one
              raise self._exceptions[0]
          # check for mismatches
          if (self._download_sofar != self._download_total or
                  self._download_bytes_sofar != self._download_bytes_total):
              raise RuntimeError(
                  'download mismatch: [count={}/{} bytes={}/{}]'.format(
                      self._download_sofar, self._download_total,
                      self._download_bytes_sofar, self._download_bytes_total))
          # delete all remaining local files not accounted for if
          # delete extraneous enabled
          self._delete_extraneous_files()
          # delete resume file if we've gotten this far
          if self._resume is not None:
              self._resume.delete()
          # output throughput
          if self._download_start_time is not None:
              dltime = (end_time - self._download_start_time).total_seconds()
              if dltime == 0:  # noqa
                  dltime = 1e-9
              download_size_mib = (
                  self._download_bytes_total / blobxfer.util.MEGABYTE
              )
              dlmibspeed = download_size_mib / dltime
              logger.info(
                  ('elapsed download + verify time and throughput of {0:.4f} '
                   'GiB: {1:.3f} sec, {2:.4f} Mbps ({3:.3f} MiB/sec)').format(
                       download_size_mib / 1024, dltime, dlmibspeed * 8,
                       dlmibspeed))
          end_time = blobxfer.util.datetime_now()
          logger.info('blobxfer end time: {0} (elapsed: {1:.3f} sec)'.format(
              end_time, (end_time - self._start_time).total_seconds()))