code: def _multiple_conditional_join_le_lt(
      df: pd.DataFrame,
      right: pd.DataFrame,
      conditions: list,
      keep: str,
      use_numba: bool,
  ) -> tuple:
      """
      Get indices for multiple conditions,
      where `>/>=` or `</<=` is present,
      and there is no `==` operator.
  
      Returns a tuple of (df_index, right_index)
      """
      if use_numba:
          from janitor.functions._numba import (
              _numba_dual_join,
              _numba_single_join,
          )
  
          gt_lt = [
              condition
              for condition in conditions
              if condition[-1]
              in less_than_join_types.union(greater_than_join_types)
          ]
          conditions = [
              condition
              for condition in conditions
              if condition not in gt_lt
          ]
          if len(gt_lt) == 1:
              left_on, right_on, op = gt_lt[0]
              indices = _numba_single_join(
                  df[left_on], right[right_on], op, keep="all"
              )
          else:
              indices = _numba_dual_join(df, right, gt_lt)
      else:
          # there is an opportunity for optimization for range joins
          # which is usually `lower_value < value < upper_value`
          # or `lower_value < a` and `b < upper_value`
          # intervalindex is not used here, as there are scenarios
          # where there will be overlapping intervals;
          # intervalindex does not offer an efficient way to get
          # the indices for overlaps
          # also, intervalindex covers only the first option
          # i.e => `lower_value < value < upper_value`
          # it does not extend to range joins for different columns
          # i.e => `lower_value < a` and `b < upper_value`
          # the option used for range joins is a simple form
          # dependent on sorting and extensible to overlaps
          # as well as the second option:
          # i.e =>`lower_value < a` and `b < upper_value`
          # range joins are also the more common types of non-equi joins
          # the other joins do not have an optimisation opportunity
          # within this space, as far as I know,
          # so a blowup of all the rows is unavoidable.
  
          # first step is to get two conditions, if possible
          # where one has a less than operator
          # and the other has a greater than operator
          # get the indices from that
          # and then build the remaining indices,
          # using _generate_indices function
          # the aim of this for loop is to see if there is
          # the possibility of a range join, and if there is,
          # then use the optimised path
          le_lt = None
          ge_gt = None
          # keep the first match for le_lt or ge_gt
          for condition in conditions:
              *_, op = condition
              if op in less_than_join_types:
                  if le_lt:
                      continue
                  le_lt = condition
              elif op in greater_than_join_types:
                  if ge_gt:
                      continue
                  ge_gt = condition
              if le_lt and ge_gt:
                  break
  
          # optimised path
          if le_lt and ge_gt:
              conditions = [
                  condition
                  for condition in conditions
                  if condition not in (ge_gt, le_lt)
              ]
  
              indices = _range_indices(df, right, ge_gt, le_lt)
  
          # no optimised path
          # blow up the rows and prune
          else:
              if le_lt:
                  conditions = [
                      condition
                      for condition in conditions
                      if condition != le_lt
                  ]
                  left_on, right_on, op = le_lt
              else:
                  conditions = [
                      condition
                      for condition in conditions
                      if condition != ge_gt
                  ]
                  left_on, right_on, op = ge_gt
  
              indices = _generic_func_cond_join(
                  df[left_on],
                  right[right_on],
                  op,
                  multiple_conditions=False,
                  keep="all",
              )
      if not indices:
          return None
  
      if conditions:
          conditions = (
              (df[left_on], right[right_on], op)
              for left_on, right_on, op in conditions
          )
  
          indices = _generate_indices(*indices, conditions)
          if not indices:
              return None
  
      return _keep_output(keep, *indices)
  
imports: from __future__ import annotations
  import operator
  import warnings
  from typing import Any, Hashable, Literal, Optional, Union
  import numpy
  import pandas
  import pandas_flavor
  from pandas.api.types import is_datetime64_dtype, is_dtype_equal, is_extension_array_dtype, is_numeric_dtype, is_timedelta64_dtype
  from pandas.core.reshape.merge import _MergeOperation
  from janitor.functions.utils import _generic_func_cond_join, _JoinOperator, _keep_output, col, greater_than_join_types, less_than_join_types
  from janitor.utils import check, check_column, find_stack_level
label_desc: Use image node_id 9 for calling a global function with example usage: _multiple_conditional_join_le_lt(df, right, conditions, keep, use_numba) and returns: _keep_output, None, None