code: def _less_than_indices(
      left: pd.Series,
      right: pd.Series,
      strict: bool,
      multiple_conditions: bool,
      keep: str,
  ) -> tuple:
      """
      Use binary search to get indices where left
      is less than or equal to right.
  
      If strict is True, then only indices
      where `left` is less than
      (but not equal to) `right` are returned.
  
      A tuple of integer indexes
      for left and right is returned.
      """
  
      # no point going through all the hassle
      if left.min() > right.max():
          return None
  
      outcome = _null_checks_cond_join(left=left, right=right)
      if not outcome:
          return None
      (
          left,
          right,
          left_index,
          right_index,
          right_is_sorted,
          any_nulls,
      ) = outcome
  
      search_indices = right.searchsorted(left, side="left")
  
      # if any of the positions in `search_indices`
      # is equal to the length of `right_keys`
      # that means the respective position in `left`
      # has no values from `right` that are less than
      # or equal, and should therefore be discarded
      len_right = right.size
      rows_equal = search_indices == len_right
  
      if rows_equal.any():
          left = left[~rows_equal]
          left_index = left_index[~rows_equal]
          search_indices = search_indices[~rows_equal]
  
      # the idea here is that if there are any equal values
      # shift to the right to the immediate next position
      # that is not equal
      if strict:
          rows_equal = right[search_indices]
          rows_equal = left == rows_equal
          # replace positions where rows are equal
          # with positions from searchsorted('right')
          # positions from searchsorted('right') will never
          # be equal and will be the furthermost in terms of position
          # example : right -> [2, 2, 2, 3], and we need
          # positions where values are not equal for 2;
          # the furthermost will be 3, and searchsorted('right')
          # will return position 3.
          if rows_equal.any():
              replacements = right.searchsorted(left, side="right")
              # now we can safely replace values
              # with strictly less than positions
              search_indices = np.where(
                  rows_equal, replacements, search_indices
              )
          # check again if any of the values
          # have become equal to length of right
          # and get rid of them
          rows_equal = search_indices == len_right
  
          if rows_equal.any():
              left = left[~rows_equal]
              left_index = left_index[~rows_equal]
              search_indices = search_indices[~rows_equal]
  
          if not search_indices.size:
              return None
  
      if multiple_conditions:
          return left_index, right_index, search_indices
      if right_is_sorted and (keep == "first"):
          if any_nulls:
              return left_index, right_index[search_indices]
          return left_index, search_indices
      right = [right_index[ind:len_right] for ind in search_indices]
      if keep == "first":
          right = [arr.min() for arr in right]
          return left_index, right
      if keep == "last":
          right = [arr.max() for arr in right]
          return left_index, right
      right = np.concatenate(right)
      left = np.repeat(left_index, len_right - search_indices)
      return left, right
  
imports: from __future__ import annotations
  import fnmatch
  import inspect
  import re
  import warnings
  from collections.abc import Callable
  from dataclasses import dataclass
  from enum import Enum
  from functools import singledispatch
  from typing import Any, Callable, Hashable, Iterable, List, Literal, Optional, Pattern, Union
  import numpy
  import pandas
  from multipledispatch import dispatch
  from pandas.api.types import is_bool_dtype, is_datetime64_dtype, is_list_like, is_scalar, is_string_dtype, union_categoricals
  from pandas.core.common import is_bool_indexer
  from pandas.core.groupby.generic import DataFrameGroupBy, SeriesGroupBy
  from janitor.utils import _expand_grid, check, check_column, find_stack_level
label_desc: Use image node_id 23 for calling a global function with example usage: _less_than_indices(left, right, strict, multiple_conditions, keep) and returns: left,  right, None, None, left_index,  right_index,  search_indices, left_index,  search_indices, left_index,  right, left_index,  right, None, left_index,  right_index