<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_if_newer( 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, checking times. If both source and destination files exist, the copy is executed only if the source file is newer than the destination file. In case modification times of source or destination files are not available, copy is always executed. 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)
                namespace = ("details", "modified")
                dst_state = {
                    path: info
                    for path, info in walker.info(_dst_fs, _dst_path, namespace)
                    if info.is_file
                }
                src_state = [
                    (path, info)
                    for path, info in walker.info(_src_fs, _src_path, namespace)
                ]
                for dir_path, copy_info in src_state:
                    copy_path = combine(_dst_path, frombase(_src_path, dir_path))
                    if copy_info.is_dir:
                        _dst_fs.makedir(copy_path, recreate=True)
                    elif copy_info.is_file:
                        # dst file is present, try to figure out if copy
                        # is necessary
                        try:
                            src_modified = copy_info.modified
                            dst_modified = dst_state[dir_path].modified
                        except KeyError:
                            do_copy = True
                        else:
                            do_copy = (
                                src_modified is None
                                or dst_modified is None
                                or src_modified > dst_modified
                            )

                        if do_copy:
                            copier.copy(_src_fs, dir_path, _dst_fs, copy_path)
                            on_copy(_src_fs, dir_path, _dst_fs, copy_path)