docs: def up_down_by_arrival(*filters, local_dir=".",
                         remote_dir=DEFAULT_REMOTE_DIR):
      """Monitors a local directory and a remote FlashAir directory and
      generates sets of new files to be uploaded or downloaded.
      Sets to upload are generated in a tuple
      like (Direction.up, {...}), while download sets to download
      are generated in a tuple like (Direction.down, {...}). The generator yields
      before each upload or download actually takes place."""
      local_monitor = watch_local_files(*filters, local_dir=local_dir)
      remote_monitor = watch_remote_files(*filters, remote_dir=remote_dir)
      _, lfile_set = next(local_monitor)
      _, rfile_set = next(remote_monitor)
      _notify_sync_ready(len(lfile_set), local_dir, remote_dir)
      _notify_sync_ready(len(rfile_set), remote_dir, local_dir)
      processed = set()
      for new_local, new_remote in zip(local_monitor, remote_monitor):
          new_local, local_set = new_local
          local_arrivals = {f for f in new_local if f.filename not in processed}
          yield Direction.up, local_arrivals
          if local_arrivals:
              new_names.update(f.filename for f in local_arrivals)
              _notify_sync(Direction.up, local_arrivals)
              up_by_files(local_arrivals, remote_dir)
              _notify_sync_ready(len(local_set), local_dir, remote_dir)
          new_remote, remote_set = new_remote
          remote_arrivals = {f for f in new_remote if f.filename not in processed}
          yield Direction.down, remote_arrivals
          if remote_arrivals:
              new_names.update(f.filename for f in remote_arrivals)
              _notify_sync(Direction.down, remote_arrivals)
              yield Direction.down, remote_arrivals
              down_by_files(remote_arrivals, local_dir)
              _notify_sync_ready(len(remote_set), remote_dir, local_dir)