code: def _shocks_to_epsilons(model, shocks, T):
      
      n_e = len(model.calibration['exogenous'])
  
      # if we have a DataFrame, convert it to a dict and rely on the method below
      if isinstance(shocks, pd.DataFrame):
          shocks = {k: shocks[k].tolist() for k in shocks.columns}
  
      # handle case where shocks might be a dict. Be careful to handle case where
      # value arrays are not the same length
      if isinstance(shocks, dict):
          epsilons = np.zeros((T + 1, n_e))
          for (i, k) in enumerate(model.symbols["exogenous"]):
              if k in shocks:
                  this_shock = shocks[k]
                  epsilons[:len(this_shock), i] = this_shock
                  epsilons[len(this_shock):, i] = this_shock[-1]
              else:
                  # otherwise set to value in calibration
                  epsilons[:, i] = model.calibration["exogenous"][i]
  
          return epsilons
  
      # read from calibration if not given
      if shocks is None:
          shocks = model.calibration["exogenous"]
  
      # now we just assume that shocks is array-like and try using the output of
      # np.asarray(shocks)
      shocks = np.asarray(shocks)
      shocks = shocks.reshape((-1, n_e))
  
      # until last period, exogenous shock takes its last value
      epsilons = np.zeros((T + 1, n_e))
      epsilons[:(shocks.shape[0] - 1), :] = shocks[1:, :]
      epsilons[(shocks.shape[0] - 1):, :] = shocks[-1:, :]
  
      return epsilons
docs: Helper function to support input argument `shocks` being one of many
      different data types. Will always return a `T, n_e` matrix.