code: def block_design(
      block_spec,
      t,
      order=2,
      hrfs=(glover,),
      convolution_padding=5.0,
      convolution_dt=0.02,
      hrf_interval=(0.0, 30.0),
      level_contrasts=False,
  ):
      """Create design matrix at times `t` for blocks specification `block_spec`
  
      Create design matrix for linear model from a block specification
      `block_spec`,  evaluating design rows at a sequence of time values `t`.
      Each column in the design matrix will be convolved with each HRF in `hrfs`.
  
      Parameters
      ----------
      block_spec : np.recarray
         A recarray having at least a field named 'start' and a field named 'end'
         signifying the block onset and offset times. All other fields will be
         treated as factors in an ANOVA-type model.  If there is no field other
         than 'start' and 'end', add a single-level placeholder block type
         ``_block_``.
      t : np.ndarray
         An array of np.float64 values at which to evaluate the design. Common
         examples would be the acquisition times of an fMRI image.
      order : int, optional
         The highest order interaction to be considered in constructing the
         contrast matrices.
      hrfs : sequence, optional
         A sequence of (symbolic) HRFs that will be convolved with each block.
         Default is ``(glover,)``.
      convolution_padding : float, optional
         A padding for the convolution with the HRF. The intervals
         used for the convolution are the smallest 'start' minus this
         padding to the largest 'end' plus this padding.
      convolution_dt : float, optional
         Time step for high-resolution time course for use in convolving the
         blocks with each HRF.
      hrf_interval: length 2 sequence of floats, optional
         Interval over which the HRF is assumed supported, used in the
         convolution.
      level_contrasts : bool, optional
         If true, generate contrasts for each individual level
         of each factor.
  
      Returns
      -------
      X : np.ndarray
         The design matrix with ``X.shape[0] == t.shape[0]``. The number of
         columns will depend on the other fields of `block_spec`.
      contrasts : dict
         Dictionary of contrasts that are expected to be of interest from the
         block specification. Each interaction / effect up to a given order will
         be returned. Also, a contrast is generated for each interaction / effect
         for each HRF specified in `hrfs`.
      """
      fields = list(block_spec.dtype.names)
      if "start" not in fields or "end" not in fields:
          raise ValueError('expecting fields called "start" and "end"')
      fields.pop(fields.index("start"))
      fields.pop(fields.index("end"))
      if len(fields) == 0:  # No factors specified, make generic block
          block_spec = make_recarray(
              zip(
                  block_spec["start"],
                  block_spec["end"],
                  itertools.cycle([1]),
              ),
              ("start", "end", "_block_"),
          )
          fields = ["_block_"]
      e_formula, e_contrasts = _build_formula_contrasts(
          block_spec, fields, order
      )
      # Design and contrasts in block space
      # TODO: make it so I don't have to call design twice here
      # to get both the contrasts and the e_X matrix as a recarray
      e_X = e_formula.design(block_spec)
      e_dtype = e_formula.dtype
  
      # Now construct the design in time space
      block_times = np.array(
          list(zip(block_spec["start"], block_spec["end"]))
      )
      convolution_interval = (
          block_times.min() - convolution_padding,
          block_times.max() + convolution_padding,
      )
  
      t_terms = []
      t_contrasts = {}
      for l, h in enumerate(hrfs):
          for n in e_dtype.names:
              B = blocks(block_times, amplitudes=e_X[n])
              term = convolve_functions(
                  B,
                  h(T),
                  convolution_interval,
                  hrf_interval,
                  convolution_dt,
              )
              t_terms += [term]
              if level_contrasts:
                  t_contrasts["%s_%d" % (n, l)] = Formula([term])
          for n, c in e_contrasts.items():
              F = []
              for i, nn in enumerate(c.dtype.names):
                  B = blocks(block_times, amplitudes=c[nn])
                  F.append(
                      convolve_functions(
                          B,
                          h(T),
                          convolution_interval,
                          hrf_interval,
                          convolution_dt,
                      )
                  )
              t_contrasts["%s_%d" % (n, l)] = Formula(F)
      t_formula = Formula(t_terms)
  
      tval = make_recarray(t, ["t"])
      X_t, c_t = t_formula.design(tval, contrasts=t_contrasts)
      return X_t, c_t
  
imports: import itertools
  from functools import reduce
  from operator import mul
  import numpy
  from nipy.algorithms.statistics.formula import formulae
  from nipy.algorithms.statistics.formula.formulae import Factor, Formula, Term, make_recarray
  from nipy.algorithms.statistics.utils import combinations
  from .hrf import glover
  from .utils import T, blocks, convolve_functions, events
  from .utils import fourier_basis
label_desc: Use image node_id 5 for calling a global function with example usage: block_design(block_spec, t, order, hrfs, convolution_padding, convolution_dt, hrf_interval, level_contrasts) and returns: X_t,  c_t