Recursively iterate over the (dimension, stride)
        tuples specified in dim_strides, returning the start
        and end indices for each chunk.

        For example, the following call effectively produces
        2 loops over the 'ntime' and 'nchan' dimensions
        in chunks of 10 and 4 respectively.

        .. code-block:: python

            for (ts, te), (cs, ce) in cube.endpoint_iter(('ntime', 10), ('nchan', 4))
                print 'Time range [{ts},{te}] Channel Range [{cs},{ce}]'.format(
                    ts=ts, te=te, cs=cs, ce=ce)

        Parameters
        ----------
        *dim_strides : list
            list of (dimension, stride) tuples


        Returns
        -------
        iterator
            An iterator producing lists of lower and upper extent tuples
            :code:`[(d0_low, d0_high), (d1_low, d1_high), ..., (dn_low, dn_high)]`

def endpoint_iter(self, *dim_strides, **kwargs):
        """
        Recursively iterate over the (dimension, stride)
        tuples specified in dim_strides, returning the start
        and end indices for each chunk.

        For example, the following call effectively produces
        2 loops over the 'ntime' and 'nchan' dimensions
        in chunks of 10 and 4 respectively.

        .. code-block:: python

            for (ts, te), (cs, ce) in cube.endpoint_iter(('ntime', 10), ('nchan', 4))
                print 'Time range [{ts},{te}] Channel Range [{cs},{ce}]'.format(
                    ts=ts, te=te, cs=cs, ce=ce)

        Parameters
        ----------
        *dim_strides : list
            list of (dimension, stride) tuples


        Returns
        -------
        iterator
            An iterator producing lists of lower and upper extent tuples
            :code:`[(d0_low, d0_high), (d1_low, d1_high), ..., (dn_low, dn_high)]`

        """

        def _dim_endpoints(size, stride):
            r = xrange(0, size, stride) if stride > 0 else xrange(0, size)
            return ((i, min(i+stride, size)) for i in r)

        dims = self.dimensions(copy=False)
        gens = (_dim_endpoints(dims[d].global_size, s) for d, s in dim_strides)
        return itertools.product(*gens)