def _generate_continuous(
     self,
     uts: UTS,  # time axis for the output
     ds: Dataset,  # events
     stim_var: str,
     code: Code,
     directory: Path,
 ):
     # place multiple input files into a continuous predictor
     cache = {
         stim: self._load(uts.tstep,
                          code.with_stim(stim).nuts_file_name(self.columns),
                          directory)
         for stim in ds[stim_var].cells
     }
     # determine type
     stim_type = {type(s) for s in cache.values()}
     assert len(stim_type) == 1
     stim_type = stim_type.pop()
     # generate x
     if stim_type is Dataset:
         dss = []
         for t, stim in ds.zip('T_relative', stim_var):
             x = cache[stim].copy()
             x['time'] += t
             dss.append(x)
             if code.nuts_method:
                 x_stop_ds = t_stop_ds(x, t)
                 dss.append(x_stop_ds)
         x = self._ds_to_ndvar(combine(dss), uts, code)
     elif stim_type is NDVar:
         v = cache[ds[0, stim_var]]
         dimnames = v.get_dimnames(first='time')
         dims = (uts, *v.get_dims(dimnames[1:]))
         x = NDVar.zeros(dims, code.key)
         for t, stim in ds.zip('T_relative', stim_var):
             x_stim = cache[stim]
             i_start = uts._array_index(t + x_stim.time.tmin)
             i_stop = i_start + len(x_stim.time)
             if i_stop > len(uts):
                 raise ValueError(
                     f"{code.string_without_rand} for {stim} is longer than the data"
                 )
             x.x[i_start:i_stop] = x_stim.get_data(dimnames)
     else:
         raise RuntimeError(f"stim_type={stim_type!r}")
     return x
    def _ds_to_ndvar(self, ds: Dataset, uts: UTS, code: Code):
        if self.columns:
            column_key, mask_key = code.nuts_columns
            if column_key is None:
                column_key = 'value'
                ds[:, column_key] = 1
        else:
            column_key = 'value'
            mask_key = 'mask' if 'mask' in ds else None

        if mask_key:
            mask = ds[mask_key].x
            assert mask.dtype.kind == 'b', "'mask' must be boolean"
        else:
            mask = None

        if code.shuffle_index:
            shuffle_mask = ds[code.shuffle_index].x
            if shuffle_mask.dtype.kind != 'b':
                raise code.error("shuffle index must be boolean", -1)
            elif code.shuffle == 'permute' and mask is not None:
                assert not numpy.any(shuffle_mask[~mask])
        elif code.shuffle == 'permute':
            shuffle_mask = mask
        else:
            shuffle_mask = None

        if code.shuffle == 'remask':
            if mask is None:
                raise code.error("$remask for predictor without mask", -1)
            rng = code._get_rng()
            if shuffle_mask is None:
                rng.shuffle(mask)
            else:
                remask = mask[shuffle_mask]
                rng.shuffle(remask)
                mask[shuffle_mask] = remask
            code.register_shuffle(index=True)

        if mask is not None:
            ds[column_key] *= mask

        if code.shuffle == 'permute':
            rng = code._get_rng()
            if shuffle_mask is None:
                rng.shuffle(ds[column_key].x)
            else:
                values = ds[column_key].x[shuffle_mask]
                rng.shuffle(values)
                ds[column_key].x[shuffle_mask] = values
            code.register_shuffle(index=True)

        # prepare output NDVar
        if code.nuts_method == 'is':
            dim = Categorial('representation', ('step', 'impulse'))
            x = NDVar(numpy.zeros((2, len(uts))), (dim, uts), name=code.key)
            x_step, x_impulse = x
        else:
            x = NDVar(numpy.zeros(len(uts)), uts, name=code.key)
            if code.nuts_method == 'step':
                x_step, x_impulse = x, None
            elif not code.nuts_method:
                x_step, x_impulse = None, x
            else:
                raise code.error(f"NUTS-method={code.nuts_method!r}")

        # fill in values
        ds = ds[ds['time'] < uts.tstop]
        if x_impulse is not None:
            for t, v in ds.zip('time', column_key):
                x_impulse[t] = v
        if x_step is not None:
            t_stops = ds[1:, 'time']
            if ds[-1, column_key] != 0:
                if 'tstop' not in ds.info:
                    raise code.error(
                        "For step representation, the predictor datasets needs to contain ds.info['tstop'] to determine the end of the last step",
                        -1)
                t_stops = chain(t_stops, [ds.info['tstop']])
            for t0, t1, v in zip(ds['time'], t_stops, ds[column_key]):
                x_step[t0:t1] = v
        return x