code: def merge_asof(
      left,
      right,
      on=None,
      left_on=None,
      right_on=None,
      left_index=False,
      right_index=False,
      by=None,
      left_by=None,
      right_by=None,
      suffixes=("_x", "_y"),
      tolerance=None,
      allow_exact_matches=True,
      direction="backward",
  ):
      if direction not in ["backward", "forward", "nearest"]:
          raise ValueError(
              "Invalid merge_asof direction. Choose from 'backward'"
              " 'forward', or 'nearest'"
          )
  
      kwargs = {
          "on": on,
          "left_on": left_on,
          "right_on": right_on,
          "left_index": left_index,
          "right_index": right_index,
          "by": by,
          "left_by": left_by,
          "right_by": right_by,
          "suffixes": suffixes,
          "tolerance": tolerance,
          "allow_exact_matches": allow_exact_matches,
          "direction": direction,
      }
  
      if left is None or right is None:
          raise ValueError("Cannot merge_asof on None")
  
      # if is_dataframe_like(left) and is_dataframe_like(right):
      if isinstance(left, pd.DataFrame) and isinstance(
          right, pd.DataFrame
      ):
          return pd.merge_asof(left, right, **kwargs)
  
      if on is not None:
          if left_on is not None or right_on is not None:
              raise ValueError(
                  "Can only pass argument 'on' OR 'left_on' and 'right_on', not a "
                  "combination of both."
              )
          left_on = right_on = on
  
      for o in [left_on, right_on]:
          if isinstance(o, _Frame):
              raise NotImplementedError(
                  "Dask collections not currently allowed in merge columns"
              )
  
      if not is_dask_collection(left):
          left = from_pandas(left, npartitions=1)
      ixname = ixcol = divs = None
      if left_on is not None:
          if right_index:
              divs = left.divisions if left.known_divisions else None
              ixname = left.index.name
              left = left.reset_index()
              ixcol = left.columns[0]
          left = left.set_index(left_on, sorted=True)
  
      if not is_dask_collection(right):
          right = from_pandas(right, npartitions=1)
      if right_on is not None:
          right = right.set_index(
              right_on, drop=(left_on == right_on), sorted=True
          )
  
      if by is not None:
          if left_by is not None or right_by is not None:
              raise ValueError(
                  "Can only pass argument 'by' OR 'left_by' and 'right_by', not a combination of both."
              )
          kwargs["left_by"] = kwargs["right_by"] = by
      if left_by is None and right_by is not None:
          raise ValueError(
              "Must specify both left_on and right_on if one is specified."
          )
      if left_by is not None and right_by is None:
          raise ValueError(
              "Must specify both left_on and right_on if one is specified."
          )
  
      del (
          kwargs["on"],
          kwargs["left_on"],
          kwargs["right_on"],
          kwargs["by"],
      )
      kwargs["left_index"] = kwargs["right_index"] = True
  
      if not left.known_divisions or not right.known_divisions:
          raise ValueError("merge_asof input must be sorted!")
  
      result = merge_asof_indexed(left, right, **kwargs)
      if left_on or right_on:
          result = result.reset_index()
          if ixcol is not None:
              if divs is not None:
                  result = result.set_index(
                      ixcol, sorted=True, divisions=divs
                  )
              else:
                  result = result.map_partitions(M.set_index, ixcol)
              result = result.map_partitions(M.rename_axis, ixname)
  
      return result
  
imports: from __future__ import annotations
  import math
  import pickle
  import warnings
  from functools import partial, wraps
  import numpy
  import pandas
  from pandas.api.types import is_dtype_equal
  from tlz import merge_sorted, unique
  from dask.base import is_dask_collection, tokenize
  from dask.dataframe import methods
  from dask.dataframe.core import DataFrame, Index, Series, _concat, _deprecated_kwarg, _Frame, _maybe_from_pandas, is_broadcastable, map_partitions, new_dd_object, prefix_reduction, suffix_reduction
  from dask.dataframe.dispatch import group_split_dispatch, hash_object_dispatch
  from dask.dataframe.io import from_pandas
  from dask.dataframe.shuffle import partitioning_index, rearrange_by_divisions, shuffle, shuffle_group
  from dask.dataframe.utils import asciitable, check_meta, is_dataframe_like, is_series_like, make_meta, strip_unknown_categories
  from dask.highlevelgraph import HighLevelGraph
  from dask.layers import BroadcastJoinLayer
  from dask.utils import M, apply, get_default_shuffle_method
label_desc: Use image node_id 20 for calling a global function with example usage: merge_asof(left, right, on, left_on, right_on, left_index, right_index, by, left_by, right_by, suffixes, tolerance, allow_exact_matches, direction) and returns: result, pd