{ ... }:
{
  text = ''
    export _archive_pattern="_[0-9]{12}-[[:alnum:]]{40}"
    export _archive_pattern_compressed="_[0-9]{12}-[[:alnum:]]{40}\.t(ar|gz|xz)$"
    export _archive_pattern_fast="_[0-9]{12}-[[:alnum:]]{40}\.tar$"

    # Archive using multiple threads. Uses 75% of free RAM.
    # All directories by default.
    # Supports .archiveignore exclude file.
    # Usage: archive [DIRS]
    function archive() {
      local IFS=$'\n'
      local targets=(''${@})
      [[ "''${targets}" = "" ]] && targets=($(_ls_dir))

      process() {
        # Skip if already an archive.
        _is_archive "''${target}" && {
          _iterate_skip "Already an archive."
          return 0
        };

        # Cut full paths.
        [[ "''${target##*/}" = "" ]] || target="''${target##*/}"

        local date=$(_archive_date)

        # Parse name.
        local name=$(parse_pascal ''${target})

        # Exclude support.
        local exclude=""
        [[ -f ".archiveignore" ]] && exclude="--exclude-from=.archiveignore"
        [[ -f "''${target}/.archiveignore" ]] && exclude="--exclude-from=''${target}/.archiveignore"

        # Create archive.
        local hash=$(tar ''${exclude} -c ''${target} | pv -s $(/usr/bin/env du -sb ''${target} | awk '{print $1}') | xz -9e --threads=0 --memlimit=$(_archive_memlimit) | tee ''${name}.txz | sha1sum | cut -d\  -f1)

        # Append hash to target name.
        local new_name="''${name}_''${date}-''${hash}.txz"
        mv -- ''${name}.txz ''${new_name} && echo ''${new_name}
      }

      _iterate_targets process ''${targets[@]}
    }

    # Creates a simple archive.
    # If it is a file, it just reformats file name to match archive name.
    # For dirs, it first creates a tar archive.
    # All files by default.
    # Usage: archive_fast [DIRS]
    function archive_fast() {
      local IFS=$'\n'
      local targets=("''${@}")
      [[ "''${targets}" = "" ]] && targets=($(_ls_file))

      process() {
        # Skip if already an archive.
        _is_archive "''${target}" && {
          _iterate_skip "Already an archive."
          return 0
        };

        # Cut full paths.
        [[ "''${target##*/}" = "" ]] || target="''${target##*/}"

        # Start timestamp.
        local date=$(_archive_date)

        # Exclude support.
        local exclude
        [[ -f ".archiveignore" ]] && exclude="--exclude-from=.archiveignore"
        [[ -f "''${target}/.archiveignore" ]] && exclude="--exclude-from=''${target}/.archiveignore"

        local name
        local extension

        if [[ -d "''${target}" ]]; then
          name=$(parse_pascal "''${target}")

          # Create archive.
          local hash=$(tar ''${exclude} -c "''${target}" | pv -s $(/usr/bin/env du -sb "''${target}" | awk '{print $1}') | tee "''${name}".tar | sha1sum | cut -d\  -f1)

          # Append hash to target name.
          local new_name="''${name}_''${date}-''${hash}.tar"
          mv -- "''${name}".tar ''${new_name} && echo ''${new_name}
        else
          name=$(parse_pascal "''${target%.*}")
          extension=".''${target##*.}"

          # Check if extension matches name, then drop it.
          [[ "''${extension}" = ".''${target%.*}" ]] && extension=""

          local hash=$(pv "''${target}" | sha1sum | cut -d\  -f1)
          local new_name="''${name}_''${date}-''${hash}''${extension}"
          mv -- "''${target}" "''${new_name}" && echo ''${new_name}
        fi
      }

      _iterate_targets process ''${targets[@]}
    }

    # Check archives integrity.
    # Checks all archives by default.
    # Usage: archive_check [FILES]
    function archive_check() {
      local IFS=$'\n'
      local targets=(''${@})
      [[ "''${targets}" = "" ]] && targets=($(_ls_archive))

      process() {
        _archive_check "''${target}"
      }

      _iterate_targets process ''${targets[@]}
    }

    # Delete old versions of an archive.
    # All archives with 1 version by default.
    # Usage: archive_prune [NAME] [VERSIONS]
    function archive_prune() {
      local IFS=$'\n'
      local targets=(''${1})
      local versions=''${2}

      [[ "''${targets}" = "" ]] && targets=($(_archive_names))
      [[ "''${versions}" = "" ]] && versions=1

      if [[ ''${#} -gt 2 ]]; then
        help archive_prune
        return 2
      fi

      process() {
        local prune=($(ls | grep -E "^''${target}''${_archive_pattern}" | sort -r | sed -e "1,''${versions}d"))

        for archive in ''${prune[@]}; do
          rm -- "''${archive}" && echo "''${archive}"
        done
      }

      _iterate_targets process ''${targets[@]}
    }

    # Delete specified or all archive files.
    # Usage: archive_rm [FILES]
    function archive_rm() {
      local IFS=$'\n'
      local targets=(''${@})
      [[ "''${targets}" = "" ]] && targets=($(_ls_archive))

      process() {
        rm -- "''${target}" && echo "''${target}"
      }

      _iterate_targets process ''${targets[@]}
    }

    # Recompress previously created archive_fast with better compression.
    # Usage: archive_compress [FILES]
    function archive_compress() {
      local IFS=$'\n'
      local targets=(''${@})
      [[ "''${targets}" = "" ]] && targets=$(_ls_archive_fast)

      process() {
        local data=($(_archive_parse "''${target}"))
        local tmp="''${data[0]}.txz"

        # Check that old format.
        if [[ "''${data[3]}" != "tar" ]]; then
          _iterate_skip "Not in .tar format!"
          return 0
        fi

        # Check integrity.
        _archive_check "''${target}" || return 1

        # Recompress.
        local hash=$(pv "''${target}" | xz -9e --threads=0 --memlimit=$(_archive_memlimit) | tee "''${tmp}" | sha1sum | cut -d\  -f1)

        # Rename.
        local new_name="''${data[0]}_''${data[1]}-''${hash}.txz"
        mv -- ''${tmp} ''${new_name} && rm ''${target} && echo ''${new_name}
      }

      _iterate_targets process ''${targets[@]}
    }

    # Rename archives.
    # If no name specified, it simplifies archive's name.
    # If no archives specified, apply to all archives.
    # Usage: archive_name [ARCHIVE] [NAME]
    function archive_name() {
      local IFS=$'\n'
      local targets="''${1}"
      local name="''${2}"
      [[ "''${targets}" = "" ]] && targets=($(_ls_archive))

      process() {
        # Simplify name by default.
        if [[ "''${name}" = "" || ''${count} -gt 1 ]]; then
          name="''${target%_*}"
          name="$(parse_pascal ''${name})"
        fi

        # Remove old name.
        local data="''${target##*_}"
        local new_name="''${name}_''${data}"

        # Check for the same name.
        [[ "''${target}" = "''${new_name}" ]] && return 0

        # Check for existing target.
        if [[ -f "''${new_name}" ]]; then
          _error "''${new_name}: Already exists!"
          return 1
        fi

        # Rename.
        mv -- ''${target} ''${new_name} && echo ''${new_name}
      }

      _iterate_targets process ''${targets[@]}
    }

    # Extract previously created archive with checksum validation.
    # Supports unarchiving exact paths from the remote machines (rsync syntax).
    # Usage: unarchive [HOST:FILES]
    function unarchive() {
      local IFS=$'\n'
      local targets=(''${@})
      [[ "''${targets}" = "" ]] && targets=$(_ls_archive_compressed)

      process() {
        # Validate.
        # _archive_check "''${target}" || return 1
        if ! _is_compressed_archive "''${target}"; then
          _iterate_skip "Not a compressed archive."
          return 0
        fi

        # Remote archives.
        local remote
        local file="''${target}"

        if [[ "''${target//\\:/}" == *:* ]]; then
          local host="''${target%%:*}"
          file="''${target#*:}"
          remote=(trysudo ssh ''${host})
        fi

        # Extract.
        case "''${file##*.}" in
          "txz")
            ''${remote[@]} pv -f ''${file} | xz -d | tar -xf -
            ;;
          "tar")
            ''${remote[@]} pv -f ''${file} | tar -xf -
            ;;
          "tgz")
            ''${remote[@]} pv -f ''${file} | gzip -d | tar -xf -
            ;;
        esac
      }

      _iterate_targets process ''${targets[@]}
    }

    # Change archive's filesystem time to match creation date.
    # Usage: archive_touch [FILES]
    function archive_touch() {
      local IFS=$'\n'
      local targets=(''${@})
      [[ "''${targets}" = "" ]] && targets=$(_ls_archive)

      process() {
        local data=($(_archive_parse "''${target}"))
        local date=''${data[1]}
        touch -t ''${date} -- ''${target}
      }

      _iterate_targets process ''${targets[@]}
    }

    # Parse archive file name to get: name, date, hash and format.
    # Usage: _archive_parse <FILENAME>
    function _archive_parse() {
      local input="''${1}"
      local name="''${input%_*}"
      local format="''${input##*.}"
      local data="''${input##*_}"; data="''${data%.*}"
      local date="''${data%%-*}"
      local hash="''${data##*-}"

      # No extension if no dots.
      [[ "''${input}" = *\.* ]] || format=""

      echo "''${name}"
      echo "''${date}"
      echo "''${hash}"
      echo "''${format}"
    }

    # Autocomplete for archive_name function.
    # First arg is the archives list, second one is selected archive's current name.
    function _comp_archive_name() {
      local IFS=$'\n'
      COMPREPLY=()

      local cur="''${COMP_WORDS[COMP_CWORD]}"
      local prev="''${COMP_WORDS[COMP_CWORD-1]}"
      local command="''${COMP_WORDS[0]}"

      if [[ "''${prev}" = "''${command}" ]]; then
        COMPREPLY=( $(compgen -W "$(ls | grep -E ''${_archive_pattern})" -- ''${cur}) )
        return 0
      else
        local data=($(_archive_parse ''${prev}))
        local name="''${data[0]}"
        COMPREPLY=( $(compgen -W "''${name}" -- ''${cur}) )
        return 0
      fi
    }

    # Autocomplete with archives in current dir.
    function _comp_archive_grep() {
      _autocomplete_grep ''${_archive_pattern}
    }

    # Autocomplete with fast archives in current dir.
    function _comp_archive_grep_fast() {
      _autocomplete_grep ''${_archive_pattern_fast}
    }

    # Get date for a new archive.
    function _archive_date() {
      date +%Y%m%d%H%M
    }

    # Get names of all archives.
    function _archive_names() {
      local IFS=$'\n'
      local archives=($(_ls_archive))
      local names=()

      for archive in ''${archives[@]}; do
        local data=($(_archive_parse ''${archive}))
        names+=(''${data[0]})
      done

      # Remove copies.
      names=($(printf '%s\n' "''${names[@]}" | sort -u))

      printf '%s\n' "''${names[@]}"
    }

    # Autocomplete with names of all archives.
    function _comp_archive_names() {
      _autocomplete_first $(_archive_names)
    }

    # Check if file is an archive.
    function _is_archive() {
      local out=$(echo "''${*}" | grep -E ''${_archive_pattern})

      [[ "''${out}" != "" ]]
    }

    # Check if file is a compressed archive.
    function _is_compressed_archive() {
      local out=$(echo "''${*}" | grep -E ''${_archive_pattern_compressed})

      [[ "''${out}" != "" ]]
    }

    # List all archives.
    function _ls_archive() {
      ls | grep -E ''${_archive_pattern}
    }

    # List fast archives.
    function _ls_archive_fast() {
      ls | grep -E ''${_archive_pattern_fast}
    }

    # List fast archives.
    function _ls_archive_compressed() {
      ls | grep -E ''${_archive_pattern_compressed}
    }

    # Filter input for archives only.
    function _filter_archive() {
      grep -E ''${_archive_pattern}
    }

    function _archive_memlimit() {
      local mem_free=$(_mem_free)
      local mem_limit=$((mem_free*3/4))

      echo "''${mem_limit}MiB"
    }

    function _archive_check() {
      # Extract hash from name.
      local data=($(_archive_parse ''${target}))
      local saved=''${data[2]}

      # Calculate actual hash.
      local actual=$(pv ''${target} | sha1sum | cut -d\  -f1)

      # Compare hashes.
      [[ "''${actual}" = "''${saved}" ]] || _error "Archive check failed."
    }

    # complete -o filenames -F _comp_archive_grep        archive_check unarchive archive_rm archive_touch
    # complete -o filenames -F _comp_archive_grep_fast   archive_xz
    complete -o filenames -F _comp_archive_name        archive_name
    complete -o filenames -F _comp_archive_names       archive_prune
  '';
}