code: def bootstrap_isc(
      iscs,
      pairwise=False,
      summary_statistic="median",
      n_bootstraps=1000,
      ci_percentile=95,
      side="right",
      random_state=None,
  ):
      """One-sample group-level bootstrap hypothesis test for ISCs
  
      For ISCs from one more voxels or ROIs, resample subjects with replacement
      to construct a bootstrap distribution. Input is a list or ndarray of
      ISCs for a single voxel/ROI, or an ISCs-by-voxels ndarray. ISC values
      should be either N ISC values for N subjects in the leave-one-out appraoch
      (pairwise=False), N(N-1)/2 ISC values for N subjects in the pairwise
      approach (pairwise=True). In the pairwise approach, ISC values should
      correspond to the vectorized upper triangle of a square correlation matrix
      (see scipy.stats.distance.squareform). Shifts bootstrap distribution by
      actual summary statistic (effectively to zero) for null hypothesis test
      (Hall & Wilson, 1991). Uses subject-wise (not pair-wise) resampling in the
      pairwise approach. Returns the observed ISC, the confidence interval, and
      a p-value for the bootstrap hypothesis test, as well as the bootstrap
      distribution of summary statistics. The p-value corresponds to either a
      'two-sided', 'left'-, or 'right'-sided (default) test, as specified by
      side. According to Chen et al., 2016, this is the preferred nonparametric
      approach for controlling false positive rates (FPRs) for one-sample tests
      in the pairwise approach. Note that the bootstrap hypothesis test may not
      strictly control FPRs in the leave-one-out approach.
  
      The implementation is based on the work in [Chen2016]_ and
      [HallWilson1991]_.
  
      .. [HallWilson1991] "Two guidelines for bootstrap hypothesis testing.",
         P. Hall, S. R., Wilson, 1991, Biometrics, 757-762.
         https://doi.org/10.2307/2532163
  
      Parameters
      ----------
      iscs : list or ndarray, ISCs by voxels array
          ISC values for one or more voxels
  
      pairwise : bool, default: False
          Indicator of pairwise or leave-one-out, should match ISCs structure
  
      summary_statistic : str, default: 'median'
          Summary statistic, either 'median' (default) or 'mean'
  
      n_bootstraps : int, default: 1000
          Number of bootstrap samples (subject-level with replacement)
  
      ci_percentile : int, default: 95
           Percentile for computing confidence intervals
  
      side : str
          Perform one-sided ('left' or 'right') or 'two-sided' test
  
      random_state = int or None, default: None
          Initial random seed
  
      Returns
      -------
      observed : float, median (or mean) ISC value
          Summary statistic for actual ISCs
  
      ci : tuple, bootstrap confidence intervals
          Confidence intervals generated from bootstrap distribution
  
      p : float, p-value
          p-value based on bootstrap hypothesis test
  
      distribution : ndarray, n_bootstraps by voxels
          Bootstrap distribution
  
      """
  
      # Standardize structure of input data
      iscs, n_subjects, n_voxels = _check_isc_input(
          iscs, pairwise=pairwise
      )
  
      # Check for valid summary statistic
      if summary_statistic not in ("mean", "median"):
          raise ValueError(
              "Summary statistic must be 'mean' or 'median'"
          )
  
      # Compute summary statistic for observed ISCs
      observed = compute_summary_statistic(
          iscs, summary_statistic=summary_statistic, axis=0
      )
  
      # Set up an empty list to build our bootstrap distribution
      distribution = []
  
      # Loop through n bootstrap iterations and populate distribution
      for i in np.arange(n_bootstraps):
          # Random seed to be deterministically re-randomized at each iteration
          if isinstance(random_state, np.random.RandomState):
              prng = random_state
          else:
              prng = np.random.RandomState(random_state)
  
          # Randomly sample subject IDs with replacement
          subject_sample = sorted(
              prng.choice(np.arange(n_subjects), size=n_subjects)
          )
  
          # Squareform and shuffle rows/columns of pairwise ISC matrix to
          # to retain correlation structure among ISCs, then get triangle
          if pairwise:
              # Loop through voxels
              isc_sample = []
              for voxel_iscs in iscs.T:
                  # Square the triangle and fill diagonal
                  voxel_iscs = squareform(voxel_iscs, force="tomatrix")
                  np.fill_diagonal(voxel_iscs, 1)
  
                  # Shuffle square correlation matrix and get triangle
                  voxel_sample = voxel_iscs[subject_sample, :][
                      :, subject_sample
                  ]
                  voxel_sample = squareform(voxel_sample, checks=False)
  
                  # Censor off-diagonal 1s for same-subject pairs
                  voxel_sample[voxel_sample == 1.0] = np.NaN
  
                  isc_sample.append(voxel_sample)
  
              isc_sample = np.column_stack(isc_sample)
  
          # Get simple bootstrap sample if not pairwise
          elif not pairwise:
              isc_sample = iscs[subject_sample, :]
  
          # Compute summary statistic for bootstrap ISCs per voxel
          # (alternatively could construct distribution for all voxels
          # then compute statistics, but larger memory footprint)
          distribution.append(
              compute_summary_statistic(
                  isc_sample,
                  summary_statistic=summary_statistic,
                  axis=0,
              )
          )
  
          # Update random state for next iteration
          random_state = np.random.RandomState(
              prng.randint(0, MAX_RANDOM_SEED)
          )
  
      # Convert distribution to numpy array
      distribution = np.array(distribution)
  
      # Compute CIs of median from bootstrap distribution (default: 95%)
      ci = (
          np.percentile(
              distribution, (100 - ci_percentile) / 2, axis=0
          ),
          np.percentile(
              distribution,
              ci_percentile + (100 - ci_percentile) / 2,
              axis=0,
          ),
      )
  
      # Shift bootstrap distribution to 0 for hypothesis test
      shifted = distribution - observed
  
      # Get p-value for actual median from shifted distribution
      p = p_from_null(observed, shifted, side=side, exact=False, axis=0)
  
      return observed, ci, p, distribution
  
imports: import numpy
  import logging
  from scipy.spatial.distance import squareform
  from itertools import combinations, permutations, product
  from brainiak.fcma.util import compute_correlation
  from brainiak.utils.utils import array_correlation, phase_randomize, p_from_null, _check_timeseries_input
label_desc: Use image node_id 8 for calling a global function with example usage: bootstrap_isc(iscs, pairwise, summary_statistic, n_bootstraps, ci_percentile, side, random_state) and returns: observed,  ci,  p,  distribution