docs: def create_download_specifications(ctx_cli_options, config):
      # type: (dict, dict) -> List[blobxfer.models.download.Specification]
      """Create a list of Download Specification objects from configuration
      :param dict ctx_cli_options: cli options
      :param dict config: config dict
      :rtype: list
      :return: list of Download Specification objects
      """
      cli_conf = ctx_cli_options[ctx_cli_options['_action']]
      cli_options = cli_conf['options']
      specs = []
      for conf in config['download']:
          if 'options' in conf:
              conf_options = conf['options']
          else:
              conf_options = {}
          # create download options
          mode = _merge_setting(
              cli_options, conf_options, 'mode', default='auto').lower()
          if mode == 'auto':
              mode = blobxfer.models.azure.StorageModes.Auto
          elif mode == 'append':
              mode = blobxfer.models.azure.StorageModes.Append
          elif mode == 'block':
              mode = blobxfer.models.azure.StorageModes.Block
          elif mode == 'file':
              mode = blobxfer.models.azure.StorageModes.File
          elif mode == 'page':
              mode = blobxfer.models.azure.StorageModes.Page
          else:
              raise ValueError('unknown mode: {}'.format(mode))
          # load RSA private key PEM file if specified
          rpk = _merge_setting(
              cli_options, conf_options, 'rsa_private_key', default=None)
          if blobxfer.util.is_not_empty(rpk):
              rpkp = _merge_setting(
                  cli_options, conf_options, 'rsa_private_key_passphrase',
                  default=None)
              rpk = blobxfer.operations.crypto.load_rsa_private_key_file(
                  rpk, rpkp)
          else:
              rpk = None
          # create specification
          conf_sod = conf_options.get('skip_on', {})
          cli_sod = cli_options['skip_on']
          conf_rfp = conf_options.get('restore_file_properties', {})
          cli_rfp = cli_options['restore_file_properties']
          ds = blobxfer.models.download.Specification(
              download_options=blobxfer.models.options.Download(
                  check_file_md5=_merge_setting(
                      cli_options, conf_options, 'check_file_md5',
                      default=False),
                  chunk_size_bytes=_merge_setting(
                      cli_options, conf_options, 'chunk_size_bytes',
                      default=0),
                  delete_extraneous_destination=_merge_setting(
                      cli_options, conf_options,
                      'delete_extraneous_destination', default=False),
                  max_single_object_concurrency=_merge_setting(
                      cli_options, conf_options,
                      'max_single_object_concurrency', default=8),
                  mode=mode,
                  overwrite=_merge_setting(
                      cli_options, conf_options, 'overwrite', default=True),
                  recursive=_merge_setting(
                      cli_options, conf_options, 'recursive', default=True),
                  rename=_merge_setting(
                      cli_options, conf_options, 'rename', default=False),
                  restore_file_properties=blobxfer.models.options.FileProperties(
                      attributes=_merge_setting(
                          cli_rfp, conf_rfp, 'attributes',
                          default=False),
                      cache_control=None,
                      lmt=_merge_setting(
                          cli_rfp, conf_rfp, 'lmt', default=False),
                      md5=None,
                  ),
                  rsa_private_key=rpk,
                  strip_components=_merge_setting(
                      cli_options, conf_options, 'strip_components',
                      default=0),
              ),
              skip_on_options=blobxfer.models.options.SkipOn(
                  filesize_match=_merge_setting(
                      cli_sod, conf_sod, 'filesize_match', default=False),
                  lmt_ge=_merge_setting(
                      cli_sod, conf_sod, 'lmt_ge', default=False),
                  md5_match=_merge_setting(
                      cli_sod, conf_sod, 'md5_match', default=False),
              ),
              local_destination_path=blobxfer.models.download.
              LocalDestinationPath(
                  conf['destination']
              )
          )
          # create remote source paths
          for src in conf['source']:
              if len(src) != 1:
                  raise RuntimeError(
                      'invalid number of source pairs specified per entry')
              sa = next(iter(src))
              asp = blobxfer.operations.azure.SourcePath()
              asp.add_path_with_storage_account(src[sa], sa)
              incl = _merge_setting(cli_conf, conf, 'include', default=None)
              if blobxfer.util.is_not_empty(incl):
                  asp.add_includes(incl)
              excl = _merge_setting(cli_conf, conf, 'exclude', default=None)
              if blobxfer.util.is_not_empty(excl):
                  asp.add_excludes(excl)
              ds.add_azure_source_path(asp)
          # append spec to list
          specs.append(ds)
      return specs