<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def copy_dir( src_fs, # type: Union[FS, Text] src_path, # type: Text dst_fs, # type: Union[FS, Text] dst_path, # type: Text walker=None, # type: Optional[Walker] on_copy=None, # type: Optional[_OnCopy] workers=0, # type: int ):
 """Copy a directory from one filesystem to another. Arguments: src_fs (FS or str):
 Source filesystem (instance or URL). src_path (str):
 Path to a directory on the source filesystem. dst_fs (FS or str):
 Destination filesystem (instance or URL). dst_path (str):
 Path to a directory on the destination filesystem. walker (~fs.walk.Walker, optional):
 A walker object that will be used to scan for files in ``src_fs``. Set this if you only want to consider a sub-set of the resources in ``src_fs``. on_copy (callable, optional):
 A function callback called after a single file copy is executed. Expected signature is ``(src_fs, src_path, dst_fs, dst_path)``. workers (int):
 Use ``worker`` threads to copy data, or ``0`` (default) for a single-threaded copy. """

    on_copy = on_copy or (lambda *args: None)
    walker = walker or Walker()
    _src_path = abspath(normpath(src_path))
    _dst_path = abspath(normpath(dst_path))

    def src():
        return manage_fs(src_fs, writeable=False)

    def dst():
        return manage_fs(dst_fs, create=True)

    from ._bulk import Copier

    with src() as _src_fs, dst() as _dst_fs:
        with _src_fs.lock(), _dst_fs.lock():
            _thread_safe = is_thread_safe(_src_fs, _dst_fs)
            with Copier(num_workers=workers if _thread_safe else 0) as copier:
                _dst_fs.makedir(_dst_path, recreate=True)
                for dir_path, dirs, files in walker.walk(_src_fs, _src_path):
                    copy_path = combine(_dst_path, frombase(_src_path, dir_path))
                    for info in dirs:
                        _dst_fs.makedir(info.make_path(copy_path), recreate=True)
                    for info in files:
                        src_path = info.make_path(dir_path)
                        dst_path = info.make_path(copy_path)
                        copier.copy(_src_fs, src_path, _dst_fs, dst_path)
                        on_copy(_src_fs, src_path, _dst_fs, dst_path)