code: def _multiple_conditional_join_eq(
      df: pd.DataFrame,
      right: pd.DataFrame,
      conditions: list,
      keep: str,
      use_numba: bool,
      force: bool,
  ) -> tuple:
      """
      Get indices for multiple conditions,
      if any of the conditions has an `==` operator.
  
      Returns a tuple of (left_index, right_index)
      """
  
      if force:
          return _multiple_conditional_join_le_lt(
              df=df,
              right=right,
              conditions=conditions,
              keep=keep,
              use_numba=use_numba,
          )
  
      if use_numba:
          from janitor.functions._numba import _numba_equi_join
  
          eqs = None
          for left_on, right_on, op in conditions:
              if op == _JoinOperator.STRICTLY_EQUAL.value:
                  eqs = (left_on, right_on, op)
                  break
  
          le_lt = None
          ge_gt = None
  
          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
          if not le_lt and not ge_gt:
              raise ValueError(
                  "At least one less than or greater than "
                  "join condition should be present when an equi-join "
                  "is present, and use_numba is set to True."
              )
          rest = [
              condition
              for condition in conditions
              if condition not in {eqs, le_lt, ge_gt}
          ]
  
          right_columns = [eqs[1]]
          df_columns = [eqs[0]]
          if ge_gt:
              if ge_gt[1] not in right_columns:
                  right_columns.append(ge_gt[1])
              if ge_gt[0] not in df_columns:
                  df_columns.append(ge_gt[0])
          if le_lt:
              if le_lt[1] not in right_columns:
                  right_columns.append(le_lt[1])
              if le_lt[0] not in df_columns:
                  df_columns.append(le_lt[0])
  
          right_df = right.loc(axis=1)[right_columns]
          left_df = df.loc(axis=1)[df_columns]
          any_nulls = left_df.isna().any(axis=1)
          if any_nulls.all(axis=None):
              return None
          if any_nulls.any():
              left_df = left_df.loc[~any_nulls]
          any_nulls = right_df.isna().any(axis=1)
          if any_nulls.all(axis=None):
              return None
          if any_nulls.any():
              right_df = right.loc[~any_nulls]
          equi_col = right_columns[0]
          # check if the first column is sorted
          # if sorted, check if the second column is sorted
          # per group in the first column
          right_is_sorted = right_df[equi_col].is_monotonic_increasing
          if right_is_sorted:
              grp = right_df.groupby(equi_col, sort=False)
              non_equi_col = right_columns[1]
              # groupby.is_monotonic_increasing uses apply under the hood
              # this circumvents the Series creation (which isn't required here)
              # and just gets a sequence of booleans, before calling `all`
              # to get a single True or False.
              right_is_sorted = all(
                  arr.is_monotonic_increasing
                  for _, arr in grp[non_equi_col]
              )
          if not right_is_sorted:
              right_df = right_df.sort_values(right_columns)
          indices = _numba_equi_join(
              left_df, right_df, eqs, ge_gt, le_lt
          )
  
          if not rest or (indices is None):
              return indices
  
          rest = (
              (df[left_on], right[right_on], op)
              for left_on, right_on, op in rest
          )
  
          indices = _generate_indices(*indices, rest)
  
          if not indices:
              return None
  
          return _keep_output(keep, *indices)
  
      eqs = [
          (left_on, right_on)
          for left_on, right_on, op in conditions
          if op == _JoinOperator.STRICTLY_EQUAL.value
      ]
      left_on, right_on = zip(*eqs)
      left_on = [*left_on]
      right_on = [*right_on]
  
      left_index, right_index = _MergeOperation(
          df,
          right,
          left_on=left_on,
          right_on=right_on,
          sort=False,
      )._get_join_indexers()
  
      if not left_index.size:
          return None
  
      rest = [
          (df[left_on], right[right_on], op)
          for left_on, right_on, op in conditions
          if op != _JoinOperator.STRICTLY_EQUAL.value
      ]
  
      if not rest:
          return _keep_output(keep, left_index, right_index)
  
      indices = _generate_indices(left_index, right_index, rest)
      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 8 for calling a global function with example usage: _multiple_conditional_join_eq(df, right, conditions, keep, use_numba, force) and returns: _keep_output, _multiple_conditional_join_le_lt, _keep_output, None, _keep_output, None, None, None, indices, None