text:
from operator import add, mul
import numpy as np
from scipy import sparse
import warnings

def broadcast_first(a, b, op):
    """ apply binary operation `op`, broadcast `a` over axis 1 if necessary

    Parameters
    ----------
    a : ndarray
        If a is 1D shape (N,), convert to shape (N,1) before appling `op`.  This
        has the effect of making broadcasting happen over axis 1 rather than the
        default of axis 0.
    b : ndarray
        If a is 1D shape (P,), convert to shape (N,1) before appling `op`
    op : callable
        binary operation to apply to `a`, `b`

    Returns
    -------
    res : object
        shape equal to ``b.shape``
    """
    shape = b.shape
    if a.ndim == 1:
        a = a[:,None]
    if b.ndim == 1:
        b = b[:,None]
    return op(a, b).reshape(shape)

class AffineError(Exception):
    pass

class affine_transform(object):

    def __init__(self, linear_operator, affine_offset, diag=False, input_shape=None):
        """ Create affine transform

        Parameters
        ----------
        linear_operator : None or ndarray or sparse array or affine_transform
            Linear part of affine transform implemented as array or as
            affine_transform.  None results in no linear component.
        affine_offset : None or ndarray
            offset component of affine.  Only one of `linear_operator` and
            `affine_offset` can be None, because we need an input array to
            define the shape of the transform.
        diag : {False, True}, optional
            If True, interpret 1D `linear_operator` as the main diagonal of the
            a diagonal array, so that ``linear_operator =
            np.diag(linear_operator)``
        """
        # noneD - linear_operator is None
        # sparseD - linear_operator is sparse
        # affineD - linear_operator is an affine_transform
        # diagD - linear_operator is 1D representation of diagonal
        if linear_operator is None and affine_offset is None:
            raise AffineError('linear_operator and affine_offset cannot '
                              'both be None')

        if sparse.issparse(affine_offset):
            #Convert sparse offset to an array
            self.affine_offset = affine_offset.toarray()
        else:
            self.affine_offset = affine_offset
        self.linear_operator = linear_operator

        if linear_operator is None:
            self.noneD = True
            self.sparseD = False
            self.affineD = False
            self.diagD = False
            self.input_shape = affine_offset.shape
            self.output_shape = affine_offset.shape
        else:
            self.noneD = False
            self.sparseD = sparse.isspmatrix(self.linear_operator)
            self.sparseD_csr = sparse.isspmatrix_csr(self.linear_operator)
            if self.sparseD and not self.sparseD_csr:
                warnings.warn("Linear operator matrix is sparse, but not csr_matrix. Convert to csr_matrix for faster multiplications!")
            if self.sparseD_csr:
                self.linear_operator_T = sparse.csr_matrix(self.linear_operator.T)

            # does it support the affine_transform API
            if np.alltrue([hasattr(self.linear_operator, n) for
                           n in ['linear_map',
                                 'affine_map',
                                 'affine_offset',
                                 'adjoint_map',
                                 'input_shape',
                                 'output_shape']]):
                self.input_shape = self.linear_operator.input_shape
                self.output_shape = self.linear_operator.output_shape
                self.affineD = True
                self.diagD = False
            elif linear_operator.ndim == 1 and not diag:
                self.linear_operator = self.linear_operator.reshape((1,-1))
                self.diagD = False
                self.affineD = False
                self.input_shape = (self.linear_operator.shape[1],)
                self.output_shape = (1,)
            elif linear_operator.ndim == 1 and diag:
                self.diagD = True
                self.affineD = False
                self.input_shape = (linear_operator.shape[0],)
                self.output_shape = (linear_operator.shape[0],)
            elif not input_shape is None and (len(input_shape) == 2):
                #Primal shape is a matrix
                self.input_shape = input_shape
                self.output_shape = (linear_operator.shape[0],input_shape[1])
                self.diagD = False
                self.affineD = False
            else:
                self.input_shape = (linear_operator.shape[1],)
                self.output_shape = (linear_operator.shape[0],)
                self.diagD = False
                self.affineD = False

    def linear_map(self, x, copy=True):
        r"""Apply linear part of transform to `x`

        Return :math:`Dx`

        Parameters
        ----------
        x : ndarray
            array to which to apply transform.  Can be 1D or 2D
        copy : {True, False}, optional
            If True, in situations where return is identical to `x`, ensure
            returned value is a copy.

        Returns
        -------
        Dx : ndarray
            `x` transformed with linear component

        Notes
        -----
        This routine is subclassed in affine_atom as a matrix multiplications,
        but could also call FFTs if D is a DFT matrix, in a subclass.
        """
        if self.noneD:
            # this sometimes has to be a copy
            # because the array can later be modified
            # in place -- see the smoothed_seminorm
            if copy:
                return x.copy()
            return x
        elif self.affineD:
            return self.linear_operator.linear_map(x)
        elif self.sparseD:
            return self.linear_operator * x
        elif self.diagD:
            # Deal with 1D or 2D input or linear operator
            return broadcast_first(self.linear_operator, x, mul)
        return np.dot(self.linear_operator, x)

    def affine_map(self, x, copy=True):
        r"""Apply linear and affine offset to `x`

        Return :math:`Dx+\alpha`

        Parameters
        ----------
        x : ndarray
            array to which to apply transform.  Can be 1D or 2D
        copy : {True, False}, optional
            If True, in situations where return is identical to `x`, ensure
            returned value is a copy.

        Returns
        -------
        Dx_a : ndarray
            `x` transformed with linear and offset components

        Notes
        -----
        This routine is subclassed in affine_atom as a matrix multiplications,
        but could also call FFTs if D is a DFT matrix, in a subclass.
        """
        if self.affineD:
            v = self.linear_operator.affine_map(x)
        else:
            v = self.linear_map(x, copy)
        if self.affine_offset is not None:
            # Deal with 1D and 2D input, affine_offset cases
            return broadcast_first(self.affine_offset, v, add)
        # if copy is True, v will already be a copy, so no need to check again
        return v

    def offset_map(self, x):
        r"""Apply affine offset to `x`

        Return :math:`x+\alpha`

        Parameters
        ----------
        x : ndarray
            array to which to apply transform.  Can be 1D or 2D

        Returns
        -------
        x_a : ndarray
            `x` transformed with offset components

        """
        if self.affineD:
            v = self.linear_operator.offset_map(x)
        else:
            v = x
        if self.affine_offset is not None:
            # Deal with 1D and 2D input, affine_offset cases
            return broadcast_first(self.affine_offset, v, add)
        return v

    def adjoint_map(self, u, copy=True):
        r"""Apply transpose of linear component to `u`

        Return :math:`D^Tu`

        Parameters
        ----------
        u : ndarray
            array to which to apply transposed linear part of transform. Can be
            1D or 2D array
        copy : {True, False}, optional
            If True, in situations where return is identical to `u`, ensure
            returned value is a copy.

        Returns
        -------
        DTu : ndarray
            `u` transformed with transpose of linear component

        Notes
        -----
        This routine is currently a matrix multiplication, but could
        also call FFTs if D is a DFT matrix, in a subclass.
        """
        if self.noneD:
            # this might have to be a copy but we only multiply by D.T when
            # computing gradient -- this currently doesn't happen in seminorm or
            # smoothed_seminorm
            if copy:
                return u.copy()
            return u
        if self.sparseD_csr:
            return self.linear_operator_T * u
        if self.sparseD:
            return self.linear_operator.T * u
        if self.diagD:
            # Deal with 1D or 2D input or linear operator
            return broadcast_first(self.linear_operator, u, mul)
        if self.affineD:
            return self.linear_operator.adjoint_map(u)
        return np.dot(self.linear_operator.T, u)

class linear_transform(affine_transform):
    """ A linear transform is an affine transform with no affine offset
    """
    def __init__(self, linear_operator, diag=False, input_shape=None):
        if linear_operator is None:
            raise AffineError('linear_operator cannot be None')
        affine_transform.__init__(self, linear_operator, None, diag=diag, input_shape=input_shape)

class selector(linear_transform):

    """
    Apply an affine transform after applying an
    indexing operation to the array.

    >>> X = np.arange(30).reshape((6,5))
    >>> offset = np.arange(6)
    >>> transform = affine_transform(X, offset)
    >>> apply_to_first5 = selector(slice(0,5), (20,), transform)
    >>> apply_to_first5.linear_map(np.arange(20))
    array([ 30,  80, 130, 180, 230, 280])
    >>> np.dot(X, np.arange(5))
    array([ 30,  80, 130, 180, 230, 280])

    >>> apply_to_first5.affine_map(np.arange(20))
    array([ 30,  81, 132, 183, 234, 285])
    >>> np.dot(X, np.arange(5)) + offset
    array([ 30,  81, 132, 183, 234, 285])

    >>> apply_to_first5.adjoint_map(np.arange(6))

    array([ 275.,  290.,  305.,  320.,  335.,    0.,    0.,    0.,    0.,
              0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.,
              0.,    0.])

    """

    def __init__(self, index_obj, initial_shape, affine_transform=None):
        self.index_obj = index_obj
        self.initial_shape = initial_shape

        if affine_transform == None:
            test = np.empty(initial_shape)
            affine_transform = identity(test[index_obj].shape)
        self.affine_transform = affine_transform
        self.affine_offset = self.affine_transform.affine_offset
        self.input_shape = initial_shape
        self.output_shape = self.affine_transform.output_shape

    def linear_map(self, x, copy=False):
        x_indexed = x[self.index_obj]
        return self.affine_transform.linear_map(x_indexed)

    def affine_map(self, x, copy=False):
        x_indexed = x[self.index_obj]
        return self.affine_transform.affine_map(x_indexed)

    def offset_map(self, x, copy=False):
        x_indexed = x[self.index_obj]
        return self.affine_transform.offset_map(x_indexed)

    def adjoint_map(self, u, copy=False):
        if not hasattr(self, "_output"):
            self._output = np.zeros(self.initial_shape)
        self._output[self.index_obj] = self.affine_transform.adjoint_map(u)
        return self._output

class reshape(linear_transform):

    """
    Reshape the output of an affine transform.

    """

    def __init__(self, input_shape, output_shape):
        self.input_shape = input_shape
        self.output_shape = output_shape

    def linear_map(self, x, copy=False):
        if copy:
            x = x.copy()
        return x.reshape(self.output_shape)

    def affine_map(self, x, copy=False):
        return self.linear_map(x, copy)

    def offset_map(self, x, copy=False):
        if copy:
            x = x.copy()
        return x

    def adjoint_map(self, u, copy=True):
        if copy:
            u = u.copy()
        return u.reshape(self.output_shape)

def tensor(T, first_primal_index):
    input_shape = T.shape[first_primal_index:]
    output_shape = T.shape[:first_primal_index]

    Tm = T.reshape((np.product(output_shape),
                    np.product(input_shape)))
    reshape_primal = reshape(input_shape, Tm.shape[1])
    reshape_dual = reshape(Tm.shape[0], output_shape)
    return composition(reshape_dual, Tm, reshape_primal)

class normalize(object):

    '''
    Normalize column by means and possibly scale. Could make
    a class for row normalization to.

    Columns are normalized to have std equal to value.
    '''

    def __init__(self, M, center=True, scale=True, value=1, inplace=False,
                 intercept_column=None):
        '''
        Parameters
        ----------
        M : ndarray or scipy.sparse
            The matrix to be normalized. If an ndarray and inplace=True,
            then the values of M are modified in place. Sparse matrices
            are not modified in place.

        center : bool
            Center the columns?

        scale : bool
            Scale the columns?

        value : float
            Set the std of the columns to be value.

        inplace : bool
            If sensible, modify values in place. For a sparse matrix,
            this will raise an exception if True and center==True.

        intercept_column : [int,None]
            Which column is the intercept if any? This column is
            not centered or scaled.

        '''
        n, p = M.shape
        self.value = value
        self.output_shape = (n,)
        self.input_shape = (p,)

        self.sparseM = sparse.isspmatrix(M)
        self.intercept_column = intercept_column
        self.M = M

        self.center = center
        self.scale = scale

        self.inplace = inplace

        if value != 1 and not scale:
            raise ValueError('setting value when not being asked to scale')

        # we divide by n instead of n-1 in the scalings
        # so that np.std is constant

        if self.center:
            if self.inplace and self.sparseM:
                raise ValueError('resulting matrix will not be sparse if centering performed inplace')

            if not self.sparseM:
                col_means = M.mean(0)
            else:
                tmp = M.copy()
                col_means = np.asarray(tmp.mean(0)).reshape(-1)
                tmp.data **= 2

            if self.intercept_column is not None:
                col_means[self.intercept_column] = 0

            if self.scale:
                if not self.sparseM:
                    self.col_stds = np.sqrt((np.sum(M**2,0) - n * col_means**2) / n) / np.sqrt(self.value)
                else:
                    self.col_stds = np.sqrt((np.asarray(tmp.sum(0)).reshape(-1) - n * col_means**2) / n) / np.sqrt(self.value)
                if self.intercept_column is not None:
                    self.col_stds[self.intercept_column] = 1. / np.sqrt(self.value)

            if not self.sparseM and self.inplace:
                self.M -= col_means[np.newaxis,:]
                if self.scale:
                    self.M /= self.col_stds[np.newaxis,:]
                    # if scaling has been applied in place,
                    # no need to do it again
                    self.col_stds = None
                    self.scale = False
        elif self.scale:
            if not self.sparseM:
                self.col_stds = np.sqrt(np.sum(M**2,0) / n) / np.sqrt(self.value)
            else:
                tmp = M.copy()
                tmp.data **= 2
                self.col_stds = np.sqrt((tmp.sum(0)) / n) / np.sqrt(self.value)
            if self.intercept_column is not None:
                self.col_stds[self.intercept_column] = 1. / np.sqrt(self.value)
            if self.inplace:
                self.M /= self.col_stds[np.newaxis,:]
                # if scaling has been applied in place,
                # no need to do it again
                self.col_stds = None
                self.scale = False
        self.affine_offset = None

    def linear_map(self, x):
        shift = None
        if self.intercept_column is not None:
            if self.scale and self.value != 1:
                x_intercept = x[self.intercept_column] * np.sqrt(self.value)
            else:
                x_intercept = x[self.intercept_column]
        if self.scale:
            if x.ndim == 1:
                x = x / self.col_stds
            elif x.ndim == 2:
                x = x / self.col_stds[:,np.newaxis]
            else:
                raise ValueError('normalize only implemented for 1D and 2D inputs')
        if self.sparseM:
            v = self.M * x
        else:
            v = np.dot(self.M, x)
        if self.center:
            if x.ndim == 1:
                v -= v.mean()
            elif x.ndim == 2:
                v -= v.mean(0)[np.newaxis,:]
            else:
                raise ValueError('normalize only implemented for 1D and 2D inputs')
        if shift is not None: # what is this shift possibly for?
            if x.ndim == 1:
                return v + shift
            elif x.ndim == 2:
                w = v + shift[np.newaxis,:]
            else:
                raise ValueError('normalize only implemented for 1D and 2D inputs')
        if self.intercept_column is not None and self.center:
            if x.ndim == 2:
                v += x_intercept[np.newaxis,:]
            else:
                v += x_intercept
        return v

    def affine_map(self, x):
        return self.linear_map(x)

    def offset_map(self, x):
        return x

    def adjoint_map(self, u):
        v = np.empty(self.input_shape)
        if self.center:
            if u.ndim == 1:
                u_mean = u.mean()
                u = u - u_mean
            elif u.ndim == 2:
                u_mean = u.mean(0)
                u = u - u_mean[np.newaxis,:]
            else:
                raise ValueError('normalize only implemented for 1D and 2D inputs')
        if self.sparseM:
            v = (u.T * self.M).T
        else:
            v = np.dot(u.T, self.M).T
        if self.scale:
            v /= self.col_stds
        if self.intercept_column is not None:
            v[self.intercept_column] = u_mean * u.shape[0]
        return v

    def slice_columns(self, index_obj):
        """

        Parameters
        ----------

        index_obj: slice, list, np.bool
            An object on which to index the columns of self.M.
            Must be a slice object or list so scipy.sparse matrices
            can be sliced.

        Returns
        -------

        n : normalize
            A transform which agrees with self having zeroed out
            all coefficients not captured by index_obj.

        Notes
        -----

        This method does not check whether or not self.intercept_column
        is None so it must be set by hand on the returned instance.

        >>> X = np.array([1.2,3.4,5.6,7.8,1.3,4.5,5.6,7.8,1.1,3.4])
        >>> D = np.identity(X.shape[0]) - np.diag(np.ones(X.shape[0]-1),1)
        >>> nD = ra.normalize(D)
        >>> X_sliced = X.copy()
        >>> X_sliced[:4] = 0; X_sliced[6:] = 0

        >>> nD.linear_map(X_sliced)
        array([  0.        ,   0.        ,   0.        ,  -2.90688837,
                -7.15541753,  10.0623059 ,   0.        ,   0.        ,
                 0.        ,   0.        ])

        >>> nD_slice = nD.slice_columns(slice(4,6))
        >>> nD_slice.linear_map(X[slice(4,6)])
        array([  0.        ,   0.        ,   0.        ,  -2.90688837,
                -7.15541753,  10.0623059 ,   0.        ,   0.        ,
                 0.        ,   0.        ])
        >>>

        """
        if type(index_obj) not in [type(slice(0,4)), type([])]:
            # try to find nonzero indices if a boolean array
            if index_obj.dtype == np.bool:
                index_obj = np.nonzero(index_obj)[0]

        new_obj = normalize.__new__(normalize)
        new_obj.sparseM = self.sparseM

        # explicitly assumes there is no intercept column
        new_obj.intercept_column = None
        new_obj.value = self.value
        try:
            new_obj.M = self.M[:,index_obj]
        except TypeError: # sparse matrix is of wrong format
            new_obj.M = self.M.tolil()[:,index_obj].tocsc()

        new_obj.input_shape = (new_obj.M.shape[1],)
        new_obj.output_shape = (self.M.shape[0],)
        new_obj.scale = self.scale
        new_obj.center = self.center
        if self.scale:
            new_obj.col_stds = self.col_stds[index_obj]
        new_obj.affine_offset = self.affine_offset
        return new_obj

    def normalized_array(self):
        if self.inplace:
            return self.M
        else:
            raise ValueError('only possible to extract matrix if normalization was done inplace')

class identity(object):

    def __init__(self, input_shape):
        self.input_shape = self.output_shape = input_shape
        self.affine_offset = None
        self.linear_operator = None

    def affine_map(self, x, copy=True):
        return self.linear_map(x, copy)

    def offset_map(self, x, copy=True):
        if copy:
            return x.copy()
        else:
            return x

    def linear_map(self, x, copy=True):
        if copy:
            return x.copy()
        else:
            return x

    def adjoint_map(self, x, copy=True):
        return self.linear_map(x, copy)

class vstack(object):
    """
    Stack several affine transforms vertically together though
    not necessarily as a big matrix.

    """

    def __init__(self, transforms):
        self.input_shape = -1
        self.output_shapes = []
        self.transforms = []
        self.dual_slices = []
        total_dual = 0
        for transform in transforms:
            transform = astransform(transform)
            if self.input_shape == -1:
                self.input_shape = transform.input_shape
            else:
                if transform.input_shape != self.input_shape:
                    raise ValueError("primal dimensions don't agree")
            self.transforms.append(transform)
            self.output_shapes.append(transform.output_shape)
            increment = np.product(transform.output_shape)
            self.dual_slices.append(slice(total_dual, total_dual + increment))
            total_dual += increment

        self.output_shape = (total_dual,)
        self.group_dtype = np.dtype([('group_%d' % i, np.float, shape)
                                     for i, shape in enumerate(self.output_shapes)])
        self.dual_groups = self.group_dtype.names

        # figure out the affine offset
        self.affine_offset = np.empty(self.output_shape)
        x = np.zeros(self.input_shape)
        for g, t in zip(self.dual_slices, self.transforms):
            self.affine_offset[g] = t.affine_map(x)
        if np.all(np.equal(self.affine_offset, 0)):
            self.affine_offset = None

    def linear_map(self, x, copy=False):
        result = np.empty(self.output_shape)
        for g, t in zip(self.dual_slices, self.transforms):
            result[g] = t.linear_map(x)
        return result

    def affine_map(self, x, copy=False):
        result = np.empty(self.output_shape)
        for g, t in zip(self.dual_slices, self.transforms):
            result[g] = t.linear_map(x)
        if self.affine_offset is not None:
            return result + self.affine_offset
        else:
            return result

    def offset_map(self, x, copy=False):
        if self.affine_offset is not None:
            return x + self.affine_offset
        else:
            return x

    def adjoint_map(self, u, copy=False):
        result = np.zeros(self.input_shape)
        for g, t, s in zip(self.dual_slices, self.transforms,
                           self.output_shapes):
            result += t.adjoint_map(u[g].reshape(s))
        return result

class hstack(object):
    """
    Stack several affine transforms horizontally together though
    not necessarily as a big matrix.

    """

    def __init__(self, transforms):
        self.output_shape = -1
        self.input_shapes = []
        self.transforms = []
        self.primal_slices = []
        total_primal = 0
        for transform in transforms:
            transform = astransform(transform)
            if self.output_shape == -1:
                self.output_shape = transform.output_shape
            else:
                if transform.output_shape != self.output_shape:
                    raise ValueError("dual dimensions don't agree")
            self.transforms.append(transform)
            self.input_shapes.append(transform.input_shape)
            increment = np.product(transform.input_shape)
            self.primal_slices.append(slice(total_primal, total_primal + increment))
            total_primal += increment

        self.input_shape = (total_primal,)
        self.group_dtype = np.dtype([('group_%d' % i, np.float, shape)
                                     for i, shape in enumerate(self.input_shapes)])
        self.primal_groups = self.group_dtype.names

        # figure out the affine offset
        self.affine_offset = np.zeros(self.output_shape)
        for g, s, t in zip(self.primal_slices, self.input_shapes,
                           self.transforms):
            self.affine_offset += t.affine_map(np.zeros(s))
        if np.all(np.equal(self.affine_offset, 0)):
            self.affine_offset = None

    def linear_map(self, x, copy=False):
        result = np.zeros(self.output_shape)
        for g, t, s in zip(self.primal_slices, self.transforms,
                           self.input_shapes):
            result += t.linear_map(x[g].reshape(s))
        return result

    def affine_map(self, x, copy=False):
        result = np.zeros(self.output_shape)
        for g, t, s in zip(self.primal_slices, self.transforms,
                        self.input_shapes):
            result += t.linear_map(x[g].reshape(s))
        if self.affine_offset is not None:
            return result + self.affine_offset
        else:
            return result

    def offset_map(self, x, copy=False):
        if self.affine_offset is not None:
            return x + self.affine_offset
        else:
            return x

    def adjoint_map(self, u, copy=False):
        result = np.empty(self.input_shape)
        #XXX this reshaping will fail for shapes that aren't
        # 1D, would have to view as self.group_dtype to
        # take advantange of different shapes
        for g, t, s in zip(self.primal_slices, self.transforms,
                           self.input_shapes):
            result[g] = t.adjoint_map(u).reshape(-1)
        return result

def power_L(transform, max_its=500,tol=1e-8, debug=False):
    """
    Approximate the largest singular value (squared) of the linear part of
    a transform using power iterations

    TODO: should this be the largest singular value instead (i.e. not squared?)
    """

    transform = astransform(transform)
    v = np.random.standard_normal(transform.input_shape)
    old_norm = 0.
    norm = 1.
    itercount = 0
    while np.fabs(norm-old_norm)/norm > tol and itercount < max_its:
        v = transform.adjoint_map(transform.linear_map(v))
        old_norm = norm
        norm = np.linalg.norm(v)
        v /= norm
        if debug:
            print "L", norm
        itercount += 1
    return norm

def astransform(X):
    """
    If X is an affine_transform, return X,
    else try to cast it as an affine_transform
    """
    if isinstance(X, affine_transform):
        return X
    else:
        return linear_transform(X)

class adjoint(object):

    """
    Given an affine_transform, return a linear_transform
    that is the adjoint of its linear part.
    """
    def __init__(self, transform):
        self.transform = astransform(transform)
        self.affine_offset = None
        self.input_shape = self.transform.output_shape
        self.output_shape = self.transform.input_shape

    def linear_map(self, x, copy=False):
        return self.transform.adjoint_map(x, copy)

    def affine_map(self, x, copy=False):
        return self.linear_map(x, copy)

    def offset_map(self, x, copy=False):
        return x

    def adjoint_map(self, x, copy=False):
        return self.transform.linear_map(x, copy)

class tensorize(object):

    """
    Given an affine_transform, return a linear_transform
    that expects q copies of something with transform's input_shape.

    This class effectively makes explicit that a transform
    may expect a matrix rather than a single vector.

    """
    def __init__(self, transform, q):
        self.transform = astransform(transform)
        self.affine_offset = self.transform.affine_offset
        self.input_shape = self.transform.input_shape + (q,)
        self.output_shape = self.transform.output_shape + (q,)

    def linear_map(self, x):
        return self.transform.linear_map(x)

    def affine_map(self, x):
        v = self.linear_map(x)
        if self.affine_offset is not None:
            return v + self.affine_offset[:, np.newaxis]
        return v

    def offset_map(self, x):
        return x

    def adjoint_map(self, x):
        return self.transform.adjoint_map(x)

class residual(object):

    """
    Compute the residual from an affine transform.
    """

    def __init__(self, transform):
        self.transform = astransform(transform)
        self.input_shape = self.transform.input_shape
        self.output_shape = self.transform.output_shape
        self.affine_offset = None
        if not self.input_shape == self.output_shape:
            raise ValueError('dual and primal shapes should be the same to compute residual')

    def linear_map(self, x):
        return x - self.transform.linear_map(x)

    def affine_map(self, x):
        return x - self.transform.affine_map(x)

    def adjoint_map(self, u):
        return u - self.transform.adjoint_map(u)

class composition(object):

    """
    Composes a list of affine transforms, executing right to left
    """

    def __init__(self, *transforms):
        self.transforms = [astransform(t) for t in transforms]
        self.input_shape = self.transforms[-1].input_shape
        self.output_shape = self.transforms[0].output_shape

        # compute the affine_offset
        affine_offset = self.affine_map(np.zeros(self.input_shape))
        if not np.allclose(affine_offset, 0):
            self.affine_offset = None
        else:
            self.affine_offset = affine_offset

    def linear_map(self, x):
        output = x
        for transform in self.transforms[::-1]:
            output = transform.linear_map(output)
        return output

    def affine_map(self, x):
        output = x
        for transform in self.transforms[::-1]:
            output = transform.affine_map(output)
        return output

    def offset_map(self, x):
        output = x
        for transform in self.transforms[::-1]:
            output = transform.offset_map(output)
        return output

    def adjoint_map(self, x):
        output = x
        for transform in self.transforms:
            output = transform.adjoint_map(output)
        return output

class affine_sum(object):

    """
    Creates the (weighted) sum of a list of affine_transforms
    """

    def __init__(self, transforms, weights=None):
        self.transforms = transforms
        if weights is None:
            self.weights = np.ones(len(self.transforms))
        else:
            if not len(self.transforms) == len(weights):
                raise ValueError("Must specify a weight for each transform")
            self.weights = weights
        self.input_shape = transforms[0].input_shape
        self.output_shape = transforms[0].output_shape

        # compute the affine_offset
        affine_offset = self.affine_map(np.zeros(self.input_shape))
        if np.allclose(affine_offset, 0):
            self.affine_offset = None
        else:
            self.affine_offset = affine_offset

    def linear_map(self, x):
        output = 0
        for transform, weight in zip(self.transforms[::-1], self.weights[::-1]):
            output += weight * transform.linear_map(x)
        return output

    def affine_map(self, x):
        output = 0
        for transform, weight in zip(self.transforms[::-1], self.weights[::-1]):
            output += weight * transform.affine_map(x)
        return output

    def offset_map(self, x):
        return self.affine_offset

    def adjoint_map(self, x):
        output = 0
        for transform, weight in zip(self.transforms[::-1], self.weights[::-1]):
            output += weight * transform.adjoint_map(x)
        return output

class scalar_multiply(object):

    def __init__(self, atransform, scalar):
        self.input_shape, self.output_shape = (atransform.input_shape, atransform.output_shape)
        self.scalar = scalar
        self.affine_offset = None
        self._atransform = atransform

    def affine_map(self, x, copy=True):
        if self.scalar != 1.:
            return self._atransform.linear_map(x, copy) * self.scalar
        else:
            return self._atransform.linear_map(x, copy)

    def offset_map(self, x, copy=True):
        if self.scalar != 1.:
            return self._atransform.offset_map(x, copy) * self.scalar # is this correct -- what is offset_map again?
        else:
            return self._atransform.offset_map(x, copy)

    def linear_map(self, x, copy=True):
        if self.scalar != 1.:
            return self._atransform.linear_map(x, copy) * self.scalar
        else:
            return self._atransform.linear_map(x, copy)

    def adjoint_map(self, x, copy=True):
        if self.scalar != 1.:
            return self._atransform.adjoint_map(x, copy) * self.scalar
        else:
            return self._atransform.adjoint_map(x, copy)

class posneg(affine_transform):

    def __init__(self, linear_transform):
        self.linear_transform = astransform(linear_transform)
        # where to store output so we don't recreate arrays
        self.affine_offset = None
        self.input_shape = (2,) + self.linear_transform.input_shape
        self._adjoint_output = np.zeros(self.input_shape)
        self.output_shape = self.linear_transform.output_shape

    def linear_map(self, x):
        X = self.linear_transform.linear_map
        return  X(x[0]) - X(x[1])

    def affine_map(self, x):
        return self.linear_map(x)

    def offset_map(self, x):
        return x

    def adjoint_map(self, x):
        u = self._adjoint_output
        u[0] = self.linear_transform.adjoint_map(x)
        u[1] = -u[0]
        return u


text:
#pragma once
#include <string>
#include <boost/any.hpp>
#include <boost/unordered_map.hpp>

namespace lugce
{
	/// Ò»¸öÊý¾ÝµÄ¼¯ºÏ´æ·ÅÆ÷
	class aggregate
	{
	public:
		void store( const std::string& name, const boost::any& value ){ _data[name]=value; }

		template< typename T >
		void store( const T& value ){ store( typeid(T).name(), value ); }

		template< typename T >
		const T extract( const std::string& name ) const
		{
			BOOST_AUTO( i, _data.find( name ) );
			return i==_data.end() ? T() : boost::any_cast<T>(i->second);
		}
		template< typename T >
		const T extract() const{ return extract<T>( typeid(T).name() ); }
	private:
		boost::unordered_map< std::string, boost::any > _data;
	};
};

redpajama_set_name: RedPajamaGithub


text:
task :unison, "Install and configure Unison (users/#{$conf.machine.user}/.unison/default.prf)" do
  sudo install 'unison'
  run "echo '30 18 * * * /usr/bin/unison' | crontab", check_command('crontab -l', 'unison')
end


text:
<#
.SYNOPSIS
Deploy Multiple VMs to vCenter

.DESCRIPTION
VMs are deployed asynchronously based on a pre-configured csv file (DeployVM.csv)
Designed to run from Powershell ISE

.PARAMETER csvfile
Path to DeployVM.csv file with new VM info

.PARAMETER vCenter
vCenter Server FQDN or IP

.PARAMETER auto
Will allow script to run with no review or confirmation

.PARAMETER createcsv
Generates a blank csv file - DeployVM.csv

.EXAMPLE
.\DeployVM.ps1
Runs DeployVM

.EXAMPLE
.\DeployVM.ps1 -vcenter my.vcenter.address
Runs DeployVM specifying vCenter address

.EXAMPLE
.\DeployVM.ps1 -csvfile "E:\Scripts\Deploy\DeployVM.csv" -vcenter my.vcenter.address -auto
Runs DeployVM specifying path to csv file, vCenter address and no confirmation

.EXAMPLE
.\DeployVM.ps1 -createcsv
Creates a new/blank DeployVM.csv file in same directory as script

.NOTES
Author: Shawn Masterson
Created: May 2014
Version: 1.2

Author: JJ Vidanez
Created: Nov 2014
Version: 1.3
Add creation onthefly for customization Spec for linux systems
Ability to create machines names and guest hostname using different names
Added a value to find out the kind of disk because powercli bug for SDRS reported at https://communities.vmware.com/message/2442684#2442684
Remove the dependency for an already created OScustomization Spec

Author: JJ Vidanez
Created: Jul 2015
Version: 1.4
Adding domain credential request for Windows systems

Author : Simon Davies - Everything-Virtual.com
Created :  May 2016
Version: 1.5
Adding AD Computer Account Creation in specified OU's for VM's at start of deployment - Yes even Linux as that was a requirement
It's possible to restrict this to just Windows VM's by removing the comment at line #261

Author: JJ Vidanez & Robert Rowan
Created: Jun 2016
Version: 1.6
Fixed issue to deploy just one VM
Adding banner for each credential to show the domain where credentials are set
If OU parameter is defined at the OU create the object on AD where the machine is register Linux and Windows

REQUIREMENTS
PowerShell v3 or greater
vCenter (tested on 5.1/5.5)
PowerCLI 5.5 R2 or later
CSV File - VM info with the following headers
    NameVM, Name, Boot, OSType, Template, CustSpec, Folder, ResourcePool, CPU, RAM, Disk2, Disk3, Disk4, SDRS, Datastore, DiskStorageFormat, NetType, Network, DHCP, IPAddress, SubnetMask, Gateway, pDNS, sDNS, Notes, Domain, OU
    Must be named DeployVM.csv
    Can be created with -createcsv switch
CSV Field Definitions
    NameVM - Name of VM
	Name - Name of guest OS VM
	Boot - Determines whether or not to boot the VM - Must be 'true' or 'false'
	OSType - Must be 'Windows' or 'Linux'
	Template - Name of existing template to clone
	Folder - Folder in which to place VM in vCenter (optional)
	ResourcePool - VM placement - can be a reasource pool, host or a cluster
	CPU - Number of vCPU
	RAM - Amount of RAM in GB
	Disk2 - Size of additional disk to add (GB)(optional)
	Disk3 - Size of additional disk to add (GB)(optional)
	Disk4 - Size of additional disk to add (GB)(optional)
    SDRS - Mark to use a SDRS or not - Must be 'true' or 'false'
	Datastore - Datastore placement - Can be a datastore or datastore cluster
	DiskStorageFormat - Disk storage format - Must be 'Thin', 'Thick' or 'EagerZeroedThick' - Only funcional when SDRS = true
	NetType - vSwitch type - Must be 'vSS' or 'vDS'
	Network - Network/Port Group to connect NIC
	DHCP - Use DHCP - Must be 'true' or 'false'
	IPAddress - IP Address for NIC
	SubnetMask - Subnet Mask for NIC
	Gateway - Gateway for NIC
	pDNS - Primary DNS must be populated
	sDNS - Secondary NIC must be populated
	Notes - Description applied to the vCenter Notes field on VM
    Domain - DNS Domain must be populated
    OU - OU to create new computer accounts, must be the distinguished name eg "OU=TestOU1,OU=Servers,DC=my-homelab,DC=local"

CREDITS
Handling New-VM Async - LucD - @LucD22
http://www.lucd.info/2010/02/21/about-async-tasks-the-get-task-cmdlet-and-a-hash-table/
http://blog.smasterson.com/2014/05/21/deploying-multiple-vms-via-powercli-updated-v1-2/
http://blogs.vmware.com/PowerCLI/2014/05/working-customization-specifications-powercli-part-1.html
http://blogs.vmware.com/PowerCLI/2014/06/working-customization-specifications-powercli-part-2.html
http://blogs.vmware.com/PowerCLI/2014/06/working-customization-specifications-powercli-part-3.html

USE AT YOUR OWN RISK!

.LINK
http://blog.smasterson.com/2014/05/21/deploying-multiple-vms-via-powercli-updated-v1-2/
http://www.vidanez.com/2014/11/02/crear-multiples-linux-vms-de-un-fichero-csv-usando-powercli-deploying-multiple-linux-vms-using-powercli/
#>

#requires -Version 3

#--------------------------------------------------------------------
# Parameters
param (
    [parameter(Mandatory=$false)]
    [string]$csvfile,
    [parameter(Mandatory=$false)]
    [string]$vcenter,
    [parameter(Mandatory=$false)]
    [switch]$auto,
    [parameter(Mandatory=$false)]
    [switch]$createcsv
    )

#--------------------------------------------------------------------
# User Defined Variables

#--------------------------------------------------------------------
# Static Variables

$scriptName = "DeployVM"
$scriptVer = "1.6"
$scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
$starttime = Get-Date -uformat "%m-%d-%Y %I:%M:%S"
$logDir = $scriptDir + "\Logs\"
$logfile = $logDir + $scriptName + "_" + (Get-Date -uformat %m-%d-%Y_%I-%M-%S) + "_" + $env:username + ".txt"
$deployedDir = $scriptDir + "\Deployed\"
$deployedFile = $deployedDir + "DeployVM_" + (Get-Date -uformat %m-%d-%Y_%I-%M-%S) + "_" + $env:username  + ".csv"
$exportpath = $scriptDir + "\DeployVM.csv"
$headers = "" | Select-Object NameVM, Name, Boot, OSType, Template, Folder, ResourcePool, CPU, RAM, Disk2, Disk3, Disk4, SDRS, Datastore, DiskStorageFormat, NetType, Network, DHCP, IPAddress, SubnetMask, Gateway, pDNS, sDNS, Notes, Domain, OU
$taskTab = @{}
$credentials = @{}
$localAdminPassword = ""

#--------------------------------------------------------------------
# Load Snap-ins

# Add VMware snap-in if required
If ((Get-PSSnapin -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) -eq $null) {add-pssnapin VMware.VimAutomation.Core} {add-pssnapin ActiveDirectory}

#--------------------------------------------------------------------
# Functions

Function Out-Log {
    Param(
        [Parameter(Mandatory=$true)][string]$LineValue,
        [Parameter(Mandatory=$false)][string]$fcolor = "White"
    )

    Add-Content -Path $logfile -Value $LineValue
    Write-Host $LineValue -ForegroundColor $fcolor
}

Function Read-OpenFileDialog([string]$WindowTitle, [string]$InitialDirectory, [string]$Filter = "All files (*.*)|*.*", [switch]$AllowMultiSelect)
{
    Add-Type -AssemblyName System.Windows.Forms
    $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $openFileDialog.Title = $WindowTitle
    if (![string]::IsNullOrWhiteSpace($InitialDirectory)) { $openFileDialog.InitialDirectory = $InitialDirectory }
    $openFileDialog.Filter = $Filter
    if ($AllowMultiSelect) { $openFileDialog.MultiSelect = $true }
    $openFileDialog.ShowHelp = $true    # Without this line the ShowDialog() function may hang depending on system configuration and running from console vs. ISE.
    $openFileDialog.ShowDialog() > $null
    if ($AllowMultiSelect) { return $openFileDialog.Filenames } else { return $openFileDialog.Filename }
}

#--------------------------------------------------------------------
# Main Procedures

# Start Logging
Clear-Host
If (!(Test-Path $logDir)) {New-Item -ItemType directory -Path $logDir | Out-Null}
Out-Log "**************************************************************************************"
Out-Log "$scriptName`tVer:$scriptVer`t`t`t`tStart Time:`t$starttime"
Out-Log "**************************************************************************************`n"

# If requested, create DeployVM.csv and exit
If ($createcsv) {
    If (Test-Path $exportpath) {
        Out-Log "`n$exportpath Already Exists!`n" "Red"
        Exit
    } Else {
        Out-Log "`nCreating $exportpath`n" "Yellow"
        $headers | Export-Csv $exportpath -NoTypeInformation
		Out-Log "Done!`n"
        Exit
    }
}

# Ensure PowerCLI is at least version 5.5 R2 (Build 1649237)
If ((Get-PowerCLIVersion).Build -lt 1649237) {
    Out-Log "Error: DeployVM script requires PowerCLI version 5.5 R2 (Build 1649237) or later" "Red"
	Out-Log "PowerCLI Version Detected: $((Get-PowerCLIVersion).UserFriendlyVersion)" "Red"
    Out-Log "Exiting...`n`n" "Red"
    Exit
}

# Test to ensure csv file is available
If ($csvfile -eq "" -or !(Test-Path $csvfile) -or !$csvfile.EndsWith("DeployVM.csv")) {
    Out-Log "Path to DeployVM.csv not specified...prompting`n" "Yellow"
    $csvfile = Read-OpenFileDialog "Locate DeployVM.csv" "C:\" "DeployVM.csv|DeployVM.csv"
}

If ($csvfile -eq "" -or !(Test-Path $csvfile) -or !$csvfile.EndsWith("DeployVM.csv")) {
    Out-Log "`nStill can't find it...I give up" "Red"
    Out-Log "Exiting..." "Red"
    Exit
}

Out-Log "Using $csvfile`n" "Yellow"
# Make copy of DeployVM.csv
If (!(Test-Path $deployedDir)) {New-Item -ItemType directory -Path $deployedDir | Out-Null}
Copy-Item $csvfile -Destination $deployedFile | Out-Null

# Import VMs from csv
$newVMs = Import-Csv $csvfile
$newVMs = $newVMs | Where {$_.Name -ne ""}
[INT]$totalVMs = @($newVMs).count
Out-Log "New VMs to create: $totalVMs" "Yellow"

# Check to ensure csv is populated
If ($totalVMs -lt 1) {
    Out-Log "`nError: No enough entries found in DeployVM.csv" "Red"
    Out-Log "Exiting...`n" "Red"
    Exit
}

# Show input and ask for confirmation, unless -auto was used
If (!$auto) {
    $newVMs | Out-GridView -Title "VMs to be Created"
    $continue = Read-Host "`nContinue (y/n)?"
    If ($continue -notmatch "y") {
        Out-Log "Exiting..." "Red"
        Exit
    }
}

# Reading VMs to deploy and if they are windows asking to load credentials per Domain
Foreach ($VM in $newVMs) {
    $Error.Clear()
    $credentialDomain =  $VM.Domain

    If ($VM.OSType -eq "Windows") {
        If ( !$credentials.ContainsKey($credentialDomain)) {
              $new_cred = Get-Credential -Message "Admin credentials for domain - $credentialDomain use format DOMAIN\USERNAME"
              $credentials.Add($VM.domain,$new_cred)
              $localAdminPassword = Read-Host "`r`n`r`nEnter a password for the Windows local 'Administrator' account:"
        }
    }
 }

# Connect to vCenter server
If ($vcenter -eq "") {$vcenter = Read-Host "`nEnter vCenter server FQDN or IP"}

    $credential = $credentials.Get_Item("mydomain.com")

    Try {
        Out-Log "`nConnecting to vCenter - $vcenter`n`n" "Yellow"
        Connect-VIServer $vcenter -EA Stop -Credential $credential | Out-Null
    } Catch {
        Out-Log "`r`n`r`nUnable to connect to $vcenter" "Red"
        Out-Log "Exiting...`r`n`r`n" "Red"
        Exit
}

# Start provisioning VMs
$v = 0
Out-Log "Deploying VMs`n" "Yellow"
Foreach ($VM in $newVMs) {
    $Error.Clear()
	$vmName = $VM.Name
    $v++
	$vmStatus = "[{0} of {1}] {2}" -f $v, $newVMs.count, $vmName
	Write-Progress -Activity "Deploying VMs" -Status $vmStatus -PercentComplete (100*$v/($newVMs.count + 1))
    # Create custom OS Custumization spec
   If ($vm.DHCP -match "TRUE") {
        If ($VM.OSType -eq "Windows") {
            $credential = $credentials.Get_Item($VM.domain)
            $fullname = "MYORG"
            $orgname = "MYORG"
            $tempSpec = New-OSCustomizationSpec -Name temp$vmName -NamingScheme fixed `
            -NamingPrefix $VM.Name -Domain $VM.domain  -FullName $fullname -OrgName $orgname `
            -DomainCredentials $credential -TimeZone 085 -ChangeSid -OSType Windows -AdminPassword $localAdminPassword
	        $tempSpec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping `
	        -IpMode UseDhcp | Out-Null
            If ( !$VM.OU -eq "") {
                New-ADComputer -Name $VM.Name-Path  $VM.OU -credential $credential -server $VM.pDNS
            }
	    } ElseIF ($VM.OSType -eq "Linux") {
            $tempSpec = New-OSCustomizationSpec -Name temp$vmName -NamingScheme fixed `
            -NamingPrefix $VM.Name -Domain $VM.domain -OSType Linux -DnsServer $VM.pDNS,$VM.sDNS
            $tempSpec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping `
            -IpMode UseDhcp | Out-Null
            If ( !$VM.OU -eq "") {
                New-ADComputer -Name $VM.Name-Path  $VM.OU -credential $credential -server $VM.pDNS
            }
          }
	} Else {
		If ($VM.OSType -eq "Windows") {
            $credential = $credentials.Get_Item($VM.domain)
            $fullname = "MYORG"
            $orgname = "MYORG"
            $tempSpec = New-OSCustomizationSpec -Name temp$vmName -NamingScheme fixed `
            -NamingPrefix $VM.Name -Domain $VM.domain -FullName $fullname -OrgName $orgname `
            -DomainCredentials $credential -TimeZone 085 -ChangeSid -OSType Windows -AdminPassword $localAdminPassword
            $tempSpec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping `
	        -IpMode UseStaticIP -IpAddress $VM.IPAddress -SubnetMask $VM.SubnetMask `
	        -Dns $VM.pDNS,$VM.sDNS -DefaultGateway $VM.Gateway | Out-Null
            If ( !$VM.OU -eq "") {
                New-ADComputer -Name $VM.Name-Path  $VM.OU -credential $credential -server $VM.pDNS
            }
        } ElseIF ($VM.OSType -eq "Linux") {
            $tempSpec = New-OSCustomizationSpec -Name temp$vmName -NamingScheme fixed `
            -NamingPrefix $VM.Name -Domain $VM.domain -OSType Linux -DnsServer $VM.pDNS,$VM.sDNS
            $tempSpec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping `
            -IpMode UseStaticIP -IpAddress $VM.IPAddress -SubnetMask $VM.SubnetMask -DefaultGateway $VM.Gateway | Out-Null
            If ( !$VM.OU -eq "") {
                New-ADComputer -Name $VM.Name-Path  $VM.OU -credential $credential -server $VM.pDNS
            }
          }
	}

    # Create VM depeding on the parameter SDRS true or false
    Out-Log "Deploying $vmName"
    If ($VM.SDRS -match "TRUE") {
        Out-Log "SDRS Cluster disk on $vmName - removing DiskStorageFormat parameter " "Yellow"
        $taskTab[(New-VM -Name $VM.NameVM -ResourcePool $VM.ResourcePool -Location $VM.Folder -Datastore $VM.Datastore `
    -Notes $VM.Notes -Template $VM.Template -OSCustomizationSpec temp$vmName -RunAsync -EA SilentlyContinue).Id] = $VM.Name
      } Else {
       Out-Log "NON SDRS Cluster disk on $vmName - using DiskStorageFormat parameter " "Yellow"
        $taskTab[(New-VM -Name $VM.NameVM -ResourcePool $VM.ResourcePool -Location $VM.Folder -Datastore $VM.Datastore `
        -DiskStorageFormat $VM.DiskStorageFormat -Notes $VM.Notes -Template $VM.Template -OSCustomizationSpec temp$vmName -RunAsync -EA SilentlyContinue).Id] = $VM.Name
    }
    # Remove temp OS Custumization spec
    Remove-OSCustomizationSpec -OSCustomizationSpec temp$vmName -Confirm:$false
    # Log errors
    If ($Error.Count -ne 0) {
        If ($Error.Count -eq 1 -and $Error.Exception -match "'Location' expects a single value") {
            $vmLocation = $VM.Folder
            Out-Log "Unable to place $vmName in desired location, multiple $vmLocation folders exist, check root folder" "Red"
        } Else {
            Out-Log "`n$vmName failed to deploy!" "Red"
            Foreach ($err in $Error) {
                Out-Log "$err" "Red"
            }
            $failDeploy += @($vmName)
        }
    }
}

Out-Log "`n`nAll Deployment Tasks Created" "Yellow"
Out-Log "`n`nMonitoring Task Processing" "Yellow"

# When finsihed deploying, reconfigure new VMs
$totalTasks = $taskTab.Count
$runningTasks = $totalTasks
while($runningTasks -gt 0){
    $vmStatus = "[{0} of {1}] {2}" -f $runningTasks, $totalTasks, "Tasks Remaining"
	Write-Progress -Activity "Monitoring Task Processing" -Status $vmStatus -PercentComplete (100*($totalTasks-$runningTasks)/$totalTasks)
	Get-Task | % {
    if($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success"){
      #Deployment completed
      $Error.Clear()
      $vmName = $taskTab[$_.Id]
      Out-Log "`n`nReconfiguring $vmName" "Yellow"
      $VM = Get-VM $vmName
      $VMconfig = $newVMs | Where {$_.Name -eq $vmName}

	  # Set CPU and RAM
      Out-Log "Setting vCPU(s) and RAM on $vmName" "Yellow"
      $VM | Set-VM -NumCpu $VMconfig.CPU -MemoryGB $VMconfig.RAM -Confirm:$false | Out-Null

	  # Set port group on virtual adapter
      Out-Log "Setting Port Group on $vmName" "Yellow"
      If ($VMconfig.NetType -match "vSS") {
		  $network = @{
			  'NetworkName' = $VMconfig.network
			  'Confirm' = $false
		  }
	  } Else {
		  $network = @{
			  'Portgroup' = $VMconfig.network
			  'Confirm' = $false
		  }
	  }
	  $VM | Get-NetworkAdapter | Set-NetworkAdapter @network | Out-Null

	  # Add additional disks if needed
      If ($VMConfig.Disk2 -gt 1) {
        Out-Log "Adding additional disk on $vmName - don't forget to format within the OS" "Yellow"
        $VM | New-HardDisk -CapacityGB $VMConfig.Disk2 -StorageFormat $VMConfig.DiskStorageFormat -Persistence persistent | Out-Null
      }
      If ($VMConfig.Disk3 -gt 1) {
        Out-Log "Adding additional disk on $vmName - don't forget to format within the OS" "Yellow"
        $VM | New-HardDisk -CapacityGB $VMConfig.Disk3 -StorageFormat $VMConfig.DiskStorageFormat -Persistence persistent | Out-Null
      }
      If ($VMConfig.Disk4 -gt 1) {
        Out-Log "Adding additional disk on $vmName - don't forget to format within the OS" "Yellow"
        $VM | New-HardDisk -CapacityGB $VMConfig.Disk4 -StorageFormat $VMConfig.DiskStorageFormat -Persistence persistent | Out-Null
      }

	  # Boot VM
	  If ($VMconfig.Boot -match "true") {
      	Out-Log "Booting $vmName" "Yellow"
      	$VM | Start-VM -EA SilentlyContinue | Out-Null
	  }
      $taskTab.Remove($_.Id)
      $runningTasks--
      If ($Error.Count -ne 0) {
        Out-Log "$vmName completed with errors" "Red"
        Foreach ($err in $Error) {
            Out-Log "$Err" "Red"
        }
        $failReconfig += @($vmName)
      } Else {
        Out-Log "$vmName is Complete" "Green"
        $successVMs += @($vmName)
      }
    }
    elseif($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error"){
      # Deployment failed
      $failed = $taskTab[$_.Id]
      Out-Log "`n$failed failed to deploy!`n" "Red"
      $taskTab.Remove($_.Id)
      $runningTasks--
      $failDeploy += @($failed)
    }
  }
  Start-Sleep -Seconds 10
}

#--------------------------------------------------------------------
# Close Connections

Disconnect-VIServer -Server $vcenter -Force -Confirm:$false

#--------------------------------------------------------------------
# Outputs

Out-Log "`n**************************************************************************************"
Out-Log "Processing Complete" "Yellow"

If ($successVMs -ne $null) {
    Out-Log "`nThe following VMs were successfully created:" "Yellow"
    Foreach ($success in $successVMs) {Out-Log "$success" "Green"}
}
If ($failReconfig -ne $null) {
    Out-Log "`nThe following VMs failed to reconfigure properly:" "Yellow"
    Foreach ($reconfig in $failReconfig) {Out-Log "$reconfig" "Red"}
}
If ($failDeploy -ne $null) {
    Out-Log "`nThe following VMs failed to deploy:" "Yellow"
    Foreach ($deploy in $failDeploy) {Out-Log "$deploy" "Red"}
}

$finishtime = Get-Date -uformat "%m-%d-%Y %I:%M:%S"
Out-Log "`n`n"
Out-Log "**************************************************************************************"
Out-Log "$scriptName`t`t`t`t`tFinish Time:`t$finishtime"
Out-Log "**************************************************************************************"


text:
<!doctype html>

    <meta charset="utf-8">
    <title>Ulmart newsletter subscription</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="">
    <link href="css/style.css" media="screen, projection" rel="stylesheet" type="text/css" />

ULMART.RU

Ваши персональные предложения

Уверены, что хотите отписаться от рассылки «Ваши персональные предложения»?

Отписавшись, вы не сможете получать:

индивидуальные купоны на скидку и подарки Юлмарта,

приглашения на закрытые распродажи,

информацию о конкурсах,

информацию о программе лояльности.

Всё равно отписаться?

        Да, подписаться
        Настроить подписку


text:
Subclassing the Array object

1. Create a function MyArray
2. Subclass with Array by extending the prototype of MyArray


text:
description: Nous avons créé deux cas « de tests », je vous propose de le mettre en place dans un code existant.
---

# Pratiquer l'Ajax, adaptons un code existant

Nous avons créé deux cas « de tests », je vous propose de le mettre en place dans un code existant. Nous avons réalisé un site la GRETA TV, ce site comportait **«deux pages** :

- Une page d'accueil `home.php`, qui affiche la liste des vidéos.
- Une page `tv.php` ayant pour but l'affichage de la vidéo souhaité.

::: tip Vous n'avez pas le code source ?
Celui-ci est [disponible ici](/demo/php/greta-tv/refactor-structure.zip). Il pourra vous servir de base de travail. (c'est une version sans base de données, pour simplifier l'installation locale)
:::

::: tip Vous préférez une approche MVC ?
La première version du code source fourni est très simple. En tant que développeur, on préfère une approche un peu plus complète que celle-ci. C'est pour ça que je vous propose plutôt d'utiliser la version MVC du projet.

Celui-ci est [disponible ici](https://github.com/c4software/demo-structure-mvc-video/archive/refs/tags/1.1.zip). La [documentation est disponible ici](/tp/php/mvc/tp1.md)

**Attention**, la suite du TP repose sur la première version du code source. Les nommages sont différents, mais globalement le fonctionnement reste le même. Si vous voulez jouer, tentez la version MVC.
:::

Comment allons-nous procéder ?

- Dans un premier temps, nous allons regarder le fonctionnement du site actuel.
- Puis, nous allons supprimer les parties PHP « qui affichent les vidéos ». Nous testerons que notre code fonctionne toujours, mais en n'affichant aucune vidéo.
- Nous allons par la suite créer une API. Son but ? Retourner uniquement le contenu (au format JSON bien entendu)
- Puis nous appellerons notre API en Ajax grâce à Fetch depuis notre page.

## La page `home.php`

Nous allons rendre dynamique la page d'accueil `home.php`, dans le sens où :

- Notre serveur va générer une page « Vide » (c'est-à-dire sans la liste de vidéos).
- Notre navigateur va, via un appel Ajax charger la liste des vidéos, et se charger en JavaScript de l'affichage de la liste.

Avant tout, **pourquoi faire ça ?** L'avantage de découper le traitement comme ça. C'est que nous pourrions très simplement créer un client « Mobile », et ça sans toucher au code de notre serveur. Pleins d'avantages :

- Code unique pour le Web et les autres plateformes
- Centralisation de la logique dans un code dédié à la récupération « du contenu » (les vidéos en l'occurrence).
- Approche microservices, nous pouvons donc héberger notre site Internet sur une autre plateforme que l'API.

::: danger Un INSTANT !
Une API ? What ? Alors, une API dans le fond c'est « comme un site web ». Mais, cette page web ne produit pas du HTML et n'a pas pour vocation d'être lue par un humain.

C'est donc du code (PHP ou autre) qui va permettre de faire parler deux ordinateurs (le client et le serveur) dans un langage spécifique (XML, JSON …)
:::

### Étape 1 : Analyse du code

La première étape va être de créer l'API, nous allons donc regarder comment fonctionne le code que vous avez téléchargé. Je vous laisse regarder, une fois analysé nous allons en parler ensemble.

::: details Analyse du code

Le code qui nous intéresse est présent dans le fichier `home.php` ; celui-ci contient quelques lignes de code, mais si nous y regardons de plus près seules quelques lignes sont intéressantes :

```php
<?php
$videos = array("BcgsOgjHgWA","lcOxhH8N3Bo","jTuBnZrLbq0", "M2VtfZDOcHQ", "i1iIaSbK9bg", "MTaHw-S6IDo", "KfMCApWc5xE", "igtN49I1CtM");
$i = 0;
foreach ($videos as $id) {
    $i++;
?>
    <div class="col-sm-12 col-md-3 p-3">
        <div class="card">
            <div class="card-body text-center">
                    <a href="index.php?page=tv&id=<?=$id?>" class="btn btn-outline-primary">Video <?= $i ?></a>
            </div>
        </div>
    </div>
<?php
}
?>
```

Nous pouvons y voir un exemple de code PHP très simple à savoir :

- Une variable `$videos`, celle-ci contient la liste des vidéos à afficher. _C'est notre source de données_.
- `$i` est une variable qui permettra d'afficher `Video X` (1… X). _Note, cette variable peut-être remplacée par une boucle foreach différente `foreach $videos as $i => $id`_
- Du code HTML, celui-ci permet d'afficher une liste de Card à la suite avec dedans un bouton permettant d'accéder à la page `tv.php`.

:::

---

Une autre partie du code est intéressante, le fichier `index.php` ; ce fichier est un entrypoint, c'est une bonne pratique que je vous encourage vraiment à pratiquer. Regardons le fichier ensemble ! Et plus particulièrement la variable `$whitelist` celle-ci contient la liste des pages **autorisées**.

::: tip Whitelist ?

La sécurité vous connaissez ? J'espère, quand vous développez un site Internet, vous êtes par définition « en short » sur la toile. Votre site peut-être et sera certainement (je vous le garantis pour l'avoir vécue) piraté par une personne malveillante. Comment s'en prémunir alors ? Tout simplement empêchant au maximum l'exploitation de problème connut.

Créer une `whitelist` va nous permettre de dormir paisiblement, nous allons contrôler finement ce que l'utilisateur va pouvoir inclure. Vous retrouverez cette pratique dans différents langages sous différent nom (Un `router` peut-être assimilé à ce genre de pratique).

:::

---

Le précédent développeur a visiblement travaillé pour vous… :wink: :wink:. Vous trouverez également dans le projet un fichier `api.php` ainsi qu'un dossier `api` celui-ci contient le code permettant de :

- Déclarer des API. (dossier `api/`)
- Sécuriser les API.
- Centraliser la gestion de celle-ci. (`api.php`)

::: tip 👀 Vous pouvez tester dès maintenant 👀

Vous avez une API de disponible dans le projet. Celle-ci contient du contenu fictif, vous pouvez l'appeler avec le lien :

- http://localhost/leDossierDeVotreProjet/api.php?page=sample

🤓 Je vous laisse tester.
:::

### Étape 2 : Créer l'API

Nous avons maintenant analysé le code actuellement fonctionnel. Nous allons donc créer une API qui devra retourner « seulement la liste des vidéos ». Nous allons utiliser la fonction `json_encode` fournie **de base** en PHP.

Cette fonction permet :

> Retourne une chaine de caractères contenant la représentation JSON de la valeur value.
>
> L'encodage est affecté par les flags fournis. De plus, l'encodage des valeurs flottantes dépend de la valeur de serialize_precision.

_Source:_ https://www.php.net/manual/fr/function.json-encode.php

Cette fonction nous permet donc de transformer une `variable` en quelque chose de transférable simplement vers un autre système. Ce quelque chose est du JSON :

> JSON est un format de données textuelles dérivé de la notation des objets du langage JavaScript. Il permet de représenter de l'information structurée comme le permet XML par exemple.

_Source:_ Wikipédia

#### Place au code

Nous devons donc écrire une API… Une API c'est **juste un fichier PHP** comme un autre ; à la seule différence que celui-ci ne retourne pas du HTML, mais du JSON. Vous avez un exemple d'API dans le projet avec le fichier `sample.php`, je vous laisse le regarder…

Une fois celui-ci analysé, je vous laisse créer votre fichier, exemple `videos.php` **dans le dossier `api/`** ça sera notre futur API ! Nous avons maintenant une API **vide** ! Mais que mettre dedans ?

- À votre avis ?
- Du code PHP :-O
- La réponse D ?

Je vous aide! Nous allons y mettre du code PHP… Et plus particulièrement le contenu de **notre source de données** ! Mais quel code à votre avis ?

- Vous allez devoir créer la variable `$videos` (comme sur la home).
- Utiliser la fonction `json_encode` et `echo` pour envoyer le contenu de la variable au client au format JSON.

::: details En panne d'inspiration ?

Je vous aide :

```php
    <?php
        $videos = array("BcgsOgjHgWA","lcOxhH8N3Bo","jTuBnZrLbq0", "M2VtfZDOcHQ", "i1iIaSbK9bg", "MTaHw-S6IDo", "KfMCApWc5xE", "igtN49I1CtM");
        echo json_encode($videos);
    ?>
```

:::

Je vous laisse mettre en place l'API dans votre code. **N'oubliez pas de la tester !**

::: tip L'astuce du chef
Pour tester votre API, vous avez la possibilité d'utiliser le logiciel PostMan. PostMan va vous permettre de tester vos API simplement avec une interface graphique.

Téléchargez-le [ici](https://www.getpostman.com/)
:::

### Étape 2 : Modifier le code existant

Je vous laisse modifier le code PHP de la page `home.php` pour le vider de tout `PHP` celui-ci doit-être vide ! Il ne va contenir que le minimum à savoir la structure interne de la page :

```html
<div class="container">
  <div class="container">
    <div class="row pt-5" id="content">
      <!-- Nous allons insérer ICI le contenu grace à l'AJAX -->
    </div>
  </div>
</div>

<script>
  // Vous ajouterez ici prochainement le code JavaScript permettant de faire l'appel Ajax (avec fetch)
</script>
```

### Étape 3 : Appeler l'API en Ajax

Comme nous l'avons fait précédemment je vous laisse reprendre le code. Mais le code va ressembler à :

```javascript
fetch("./api.php?page=videos")
  .then((response) => response.json())
  .then((datas) => {
      // Votre code ICI, vous devez parcourir les vidéos (comme dans l'exemple précédent) pour les ajouter dans le #content (comme dans l'exemple précédent)
    });
  });
```

::: details à court d'idées sur le code à écrire ?

NON ? Vous n'allez pas tricher comme ça… Non pas vous ?

```js
// À mettre dans le then
let i = 0;
datas.forEach((el) => {
    document.getElementById("content").insertAdjacentHTML(
    "beforeend",
    `
    <div class="col-sm-12 col-md-3 p-3">
        <div class="card">
            <div class="card-body text-center">
                <a href="index.php?page=tv&id=${el}" class="btn btn-outline-primary">Video ${i}</a>
            </div>
        </div>
    </div>
    `
    );
```

⚠ Non… Ce n'est pas la seule façon de faire. Maintenant que vous avez vu MA solution. Je vous laisse écrire la vôtre.

:::

🤓 Je vous laisse travailler à la mise en place du code en question. Tester ensuite que la page s'affiche comme précédemment.

### Étape 4 : Évolution de la page

Ajouter un bouton rafraichir dans la page. Le bouton rafraichir doit permettre de récupérer à nouveau la liste des vidéos pour les mettre à jour dans la page.

- Ajouter une icône à droite dans l'interface.
- Utiliser les icônes fournies par bootstrap.
- Ajouter une action `onClick` permettant de déclencher l'action (`function`) permettant d'obtenir les vidéos en Ajax (c'est le code que vous avez déjà écrit)

Voilà la maquette :

![Maquette rendu](./res/maquette.png)

## Allons plus loin

Nous avons fait la page `home.php` ensemble. Actuellement, nous avons un fond « brick » sur la page TV (`tv.php`) ; je vous propose de changer cette page ! Pour ça vous allez devoir procéder à différents ajustements :

- Ajouter dans la structure de données la notion de thème. (un thème différent par vidéo)
- Retourner dans **une nouvelle** API (`getVideoDetails`), les informations nécessaires au bon affichage du thème.
- Utiliser le retour dans votre page.

::: details Quelques éléments en plus pour vous aider

- Vous allez avoir besoin évidemment de `fetch` (ou de jQuery) afin de faire l'appel Ajax.
- Votre API doit retourner la class CSS à appliquer au `body`.
- Vous pouvez appliquer la class CSS via : `document.body.classList.add("votreClass")`.

Comme dans le premier exemple, vous devez utiliser le résultat de votre API, cette fois-ci le JSON n'est pas obligatoire, voilà une piste de réponse :

```javascript
fetch("lurldevotreapi")
  .then((r) => r.text())
  .then((resultat) => document.body.classList.add(resultat));
```

:::

Voilà quelques exemples du résultat :

![Base](./res/theme/base.png)
![Space](./res/theme/space.png)
![Random](./res/theme/random.png)
![Bretagne](./res/theme/bretagne.png)

## L'étape bonus

Je vous ai indiqué en introduction que le but de créer des API était de permettre de créer simplement plusieurs clients avec comme source de données la même information. Je vous propose donc de mettre ça en pratique ! Nous allons donc créer un autre client web qui consommera nos données. Voilà les éléments que vous devrez réaliser :

- Le client Web devra être hébergé sur [Netlify](https://www.netlify.com).
- Avoir un visuel différent de votre page (home.php) actuelle. (Vous pouvez vous inspirer de YouTube par exemple ou Twitch).
- Avoir une information indiquant chargement pendant la récupération de la liste des vidéos.

::: warning Un instant !
Lors de votre développement, vous allez rencontrer un problème de Cross Origin. Le Cross Origin Resource Sharing (CORS) est une protection intégrée dans votre navigateur qui vous empêche depuis le domaine A d'appeler une ressource sur le domaine B. La raison ? Elle est simple empêcher le partage non désiré d'information entre deux sites.

En tant que développeur (si si), vous pouvez contrôler comment fonctionne cette protection. Vous pouvez dans vos API décider qui vous appellera (quel domaine), de manière fine ou de manière complètement ouverte (`*`). Pour rendre votre code le plus permissif possible vous pouvez ajouter dans votre API PHP le code suivant (tout en haut) :

```php
header('Access-Control-Allow-Origin: *');
```

Vous pouvez évidemment être plus précis, en indiquant un domaine spécifique :

```php
header('Access-Control-Allow-Origin: https://www.example.com');
```

:::


text:
namespace edb
{

class CalcImageArea : public ICommand
{
public:
	CalcImageArea() {}

	//
	// interface ICommand
	//
	virtual std::string Command() const override;
	virtual std::string Description() const override;
	virtual std::string Usage() const override;
	virtual int Run(int argc, char *argv[]) override;

	static ICommand* Create() { return new CalcImageArea(); }

private:
	void Run(const std::string& dir) const;

}; // CalcImageArea

}

#endif // _EASYDB_CALC_IMAGE_AREA_H_


text:
.class Lcom/ub/main/movie/MoviePlayer$1;
.super Ljava/lang/Object;
.source "MoviePlayer.java"

# interfaces
.implements Landroid/media/MediaPlayer$OnPreparedListener;

# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
    value = Lcom/ub/main/movie/MoviePlayer;->onCreate(Landroid/os/Bundle;)V
.end annotation

.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x0
    name = null
.end annotation

# instance fields
.field final synthetic this$0:Lcom/ub/main/movie/MoviePlayer;

# direct methods
.method constructor <init>(Lcom/ub/main/movie/MoviePlayer;)V
    .locals 0
    .parameter

    .prologue
    .line 1
    iput-object p1, p0, Lcom/ub/main/movie/MoviePlayer$1;->this$0:Lcom/ub/main/movie/MoviePlayer;

    .line 65
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method

# virtual methods
.method public onPrepared(Landroid/media/MediaPlayer;)V
    .locals 2
    .parameter "mp"

    .prologue
    .line 67
    iget-object v0, p0, Lcom/ub/main/movie/MoviePlayer$1;->this$0:Lcom/ub/main/movie/MoviePlayer;

    #getter for: Lcom/ub/main/movie/MoviePlayer;->videoView:Landroid/widget/VideoView;
    invoke-static {v0}, Lcom/ub/main/movie/MoviePlayer;->access$0(Lcom/ub/main/movie/MoviePlayer;)Landroid/widget/VideoView;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/VideoView;->start()V

    .line 68
    iget-object v0, p0, Lcom/ub/main/movie/MoviePlayer$1;->this$0:Lcom/ub/main/movie/MoviePlayer;

    #getter for: Lcom/ub/main/movie/MoviePlayer;->progressBar:Landroid/widget/ProgressBar;
    invoke-static {v0}, Lcom/ub/main/movie/MoviePlayer;->access$1(Lcom/ub/main/movie/MoviePlayer;)Landroid/widget/ProgressBar;

    move-result-object v0

    const/16 v1, 0x8

    invoke-virtual {v0, v1}, Landroid/widget/ProgressBar;->setVisibility(I)V

    .line 69
    return-void
.end method


text:
cask "font-shalimar" do
  version :latest
  sha256 :no_check

  url "https://github.com/google/fonts/raw/main/ofl/shalimar/Shalimar-Regular.ttf",
      verified: "github.com/google/fonts/"
  name "Shalimar"
  desc "Upright script inspired by the calligraphic strokes of a flat nib pen"
  homepage "https://fonts.google.com/specimen/Shalimar"

  font "Shalimar-Regular.ttf"
end


text:
using namespace std;

//
//  CLR Message unknown exception
//
struct CLRUnknownMessageException : std::exception
{
  public:
    explicit CLRUnknownMessageException (char mtype)
      : _mtype (mtype) {}

    char const* what() const throw()
    {
      sprintf((char*)_msg, "CLRMessage: unknown message type: %d", (int)((unsigned char)_mtype));
        return _msg;
    }

  private:
    char     _mtype;
    char     _msg[64];
};

//
// create message based on incoming message ID
//
CLRMessage* CLRFactory::messageById (char mtype)
{
    switch (mtype)
    {
    case CLRMessage::TypeNull:
        return new CLRNull (_api);
    case CLRMessage::TypeBool:
        return new CLRBool (_api);
   case CLRMessage::TypeByte:
       return new CLRByte (_api);
    case CLRMessage::TypeInt32:
        return new CLRInt32 (_api);
    case CLRMessage::TypeInt64:
        return new CLRInt64 (_api);
    case CLRMessage::TypeFloat64:
        return new CLRFloat64 (_api);
    case CLRMessage::TypeString:
        return new CLRString (_api);
    case CLRMessage::TypeObject:
        return new CLRObjectRef (_api);

    case CLRMessage::TypeVector:
        return new CLRVector (_api);
    case CLRMessage::TypeMatrix:
        return new CLRMatrix (_api);
    case CLRMessage::TypeException:
        return new CLRException (_api);

    case CLRMessage::TypeBoolArray:
        return new CLRBoolArray (_api);
    case CLRMessage::TypeByteArray:
        throw std::runtime_error ("CLRMessage: R does not support byte arrays");
    case CLRMessage::TypeInt32Array:
        return new CLRInt32Array (_api);
    case CLRMessage::TypeInt64Array:
        throw std::runtime_error ("CLRMessage: R does not support int64 arrays");
    case CLRMessage::TypeFloat64Array:
        return new CLRFloat64Array (_api);
    case CLRMessage::TypeStringArray:
        return new CLRStringArray (_api);
    case CLRMessage::TypeObjectArray:
      return new CLRObjectArray (_api);

    case CLRMessage::TypeCallMethod:
        throw std::runtime_error ("CLRMessage: should never receive a CLRCallMethod msg");

    default:
        throw CLRUnknownMessageException (mtype);
    }
}

//
//  create message for string(1) class
//
static CLRMessage* messageForString1 (CLRApi* api, const RObject& robj)
{
    std::string* v = new std::string (Rcpp::as<std::string>(robj));
    return new CLRString (api, v);
}

//
//  create message for string(*) class
//
static CLRMessage* messageForStrings (CLRApi* api, const RObject& robj)
{
    CharacterVector vec (robj.get__());
    if (vec.size() == 1)
        return new CLRString (api, new std::string(vec[0]));
    else
        return new CLRStringArray(api, new CharacterVector(vec));
}

//
//  create message for bool(*) class
//
static CLRMessage* messageForLogicals (CLRApi* api, const RObject& robj)
{
    LogicalVector vec (robj.get__());
    if (vec.size() == 1)
    {
        bool* v = new bool;
	*v = vec[0];
        return new CLRBool (api, v);
    } else
        return new CLRBoolArray(api, new LogicalVector(vec));
}

//
//  create message for int(*) class
//
static CLRMessage* messageForIntegers (CLRApi* api, const RObject& robj)
{
    IntegerVector vec (robj.get__());
    if (vec.size() == 1)
    {
        int* v = new int;
	*v = vec[0];
        return new CLRInt32 (api, v);
    } else
        return new CLRInt32Array(api, new IntegerVector(vec));
}

//
//  create message for matrix
//
static CLRMessage* messageForMatrix (CLRApi* api, const RObject& robj)
{
    NumericMatrix* mat = new NumericMatrix(robj.get__());
    return new CLRMatrix(api, mat);
}

//
//  create message for double(*) class
//
static CLRMessage* messageForFloats (CLRApi* api, const RObject& robj)
{
    SEXP edim = robj.attr("dim");
    if (!Rf_isNull(edim))
        return messageForMatrix (api, robj);

    NumericVector vec (robj.get__());
    if (vec.size() == 1)
    {
        double* v = new double;
	*v = vec[0];
        return new CLRFloat64 (api, v);
    } else
        return new CLRVector(api, new NumericVector(vec));
}

//
//  determine if object reference
//
static bool isObjectRef (CLRApi* api, const RObject& robj)
{
    SEXP objid = robj.attr("ObjectId");
    return !Rf_isNull(objid);
}

//
//  create message for object
//
static CLRMessage* messageForObject (CLRApi* api, const RObject& robj)
{
    return new CLRObjectRef(api, robj.get__());
}

//
//  create message for object list
//
static CLRMessage* messageForObjectList (CLRApi* api, const RObject& robj)
{
    return new CLRObjectArray(api, new List(robj.get__()));
}

//
// create message based on R object type
//
CLRMessage* CLRFactory::messageByValue (const RObject& robj)
{
    int stype = robj.sexp_type();
    switch (stype)
    {
    case NILSXP:
        return new CLRNull(_api);
    case CHARSXP:
      return messageForString1 (_api, robj);
    case LGLSXP:
        return messageForLogicals (_api, robj);
    case INTSXP:
        return messageForIntegers (_api, robj);
    case REALSXP:
        return messageForFloats (_api, robj);
    case STRSXP:
        return messageForStrings (_api, robj);
    case SYMSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R symbol type");
    case LISTSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R dotted pairs type");
    case CLOSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R closure type");
    case ENVSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R environ type");
    case PROMSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R promise type");
    case LANGSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R language construct type");
    case SPECIALSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R special form type");
    case BUILTINSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R built-in special type");
    case CPLXSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R complex type");
    case DOTSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R dot-dot-dot type");
    case ANYSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R ANY type");
    case VECSXP:
        if (isObjectRef (_api, robj))
            return messageForObject(_api, robj);
	else
	    return messageForObjectList(_api, robj);
    case EXPRSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R expression type");
    case BCODESXP:
        throw std::runtime_error ("CLRMessage: cannot handle R bytecode type");
    case EXTPTRSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R external-pointer type");
    case WEAKREFSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R weak-reference type");
    case RAWSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R raw-bytes type");
    case S4SXP:
        throw std::runtime_error ("CLRMessage: cannot handle R S4 type");
    case FUNSXP:
        throw std::runtime_error ("CLRMessage: cannot handle R closure type");
    default:
        throw std::runtime_error ("CLRMessage: unknown R type");
    }
}


text:
/* __START_OF_JASPER_LICENSE__
 *
 * JasPer License Version 2.0
 *
 * Copyright (c) 1999-2000 Image Power, Inc.
 * Copyright (c) 1999-2000 The University of British Columbia
 * Copyright (c) 2001-2003 Michael David Adams
 *
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person (the
 * "User") obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the
 * following conditions:
 *
 * 1.  The above copyright notices and this permission notice (which
 * includes the disclaimer below) shall be included in all copies or
 * substantial portions of the Software.
 *
 * 2.  The name of a copyright holder shall not be used to endorse or
 * promote products derived from the Software without specific prior
 * written permission.
 *
 * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
 * LICENSE.  NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 * THIS DISCLAIMER.  THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
 * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  NO ASSURANCES ARE
 * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
 * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
 * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
 * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
 * PROPERTY RIGHTS OR OTHERWISE.  AS A CONDITION TO EXERCISING THE RIGHTS
 * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
 * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY.  THE SOFTWARE
 * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
 * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
 * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
 * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
 * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
 * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
 * RISK ACTIVITIES").  THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
 * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
 *
 * __END_OF_JASPER_LICENSE__
 */

/******************************************************************************\
* Includes.
\******************************************************************************/

#include <assert.h>

#include "jasper/jas_tvp.h"
#include "jasper/jas_stream.h"
#include "jasper/jas_image.h"
#include "jasper/jas_string.h"
#include "jasper/jas_debug.h"

#include "pgx_cod.h"
#include "pgx_enc.h"

/******************************************************************************\
* Local functions.
\******************************************************************************/

static int pgx_puthdr(jas_stream_t *out, pgx_hdr_t *hdr);
static int pgx_putdata(jas_stream_t *out, pgx_hdr_t *hdr, jas_image_t *image, int cmpt);
static int pgx_putword(jas_stream_t *out, bool bigendian, int prec,
  uint_fast32_t val);
static uint_fast32_t pgx_inttoword(int_fast32_t val, int prec, bool sgnd);

/******************************************************************************\
* Code for save operation.
\******************************************************************************/

/* Save an image to a stream in the the PGX format. */

int pgx_encode(jas_image_t *image, jas_stream_t *out, char *optstr)
{
	pgx_hdr_t hdr;
	uint_fast32_t width;
	uint_fast32_t height;
	bool sgnd;
	int prec;
	pgx_enc_t encbuf;
	pgx_enc_t *enc = &encbuf;

	/* Avoid compiler warnings about unused parameters. */
	optstr = 0;

	switch (jas_clrspc_fam(jas_image_clrspc(image))) {
	case JAS_CLRSPC_FAM_GRAY:
		if ((enc->cmpt = jas_image_getcmptbytype(image,
		  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y))) < 0) {
			jas_eprintf("error: missing color component\n");
			return -1;
		}
		break;
	default:
		jas_eprintf("error: BMP format does not support color space\n");
		return -1;
		break;
	}

	width = jas_image_cmptwidth(image, enc->cmpt);
	height = jas_image_cmptheight(image, enc->cmpt);
	prec = jas_image_cmptprec(image, enc->cmpt);
	sgnd = jas_image_cmptsgnd(image, enc->cmpt);

	/* The PGX format is quite limited in the set of image geometries
	  that it can handle.  Here, we check to ensure that the image to
	  be saved can actually be represented reasonably accurately using the
	  PGX format. */
	/* There must be exactly one component. */
	if (jas_image_numcmpts(image) > 1 || prec > 16) {
		fprintf(stderr, "The PNM format cannot be used to represent an image with this geometry.\n");
		return -1;
	}

	hdr.magic = PGX_MAGIC;
	hdr.bigendian = true;
	hdr.sgnd = sgnd;
	hdr.prec = prec;
	hdr.width = width;
	hdr.height = height;

#ifdef PGX_DEBUG
	pgx_dumphdr(stderr, &hdr);
#endif

	if (pgx_puthdr(out, &hdr)) {
		return -1;
	}

	if (pgx_putdata(out, &hdr, image, enc->cmpt)) {
		return -1;
	}

	return 0;
}

/******************************************************************************\
\******************************************************************************/

static int pgx_puthdr(jas_stream_t *out, pgx_hdr_t *hdr)
{
	jas_stream_printf(out, "%c%c", hdr->magic >> 8, hdr->magic & 0xff);
	jas_stream_printf(out, " %s %s %d %ld %ld\n", hdr->bigendian ? "ML" : "LM",
	  hdr->sgnd ? "-" : "+", hdr->prec, (long) hdr->width, (long) hdr->height);
	if (jas_stream_error(out)) {
		return -1;
	}
	return 0;
}

static int pgx_putdata(jas_stream_t *out, pgx_hdr_t *hdr, jas_image_t *image, int cmpt)
{
	jas_matrix_t *data;
	uint_fast32_t x;
	uint_fast32_t y;
	int_fast32_t v;
	uint_fast32_t word;

	data = 0;

	if (!(data = jas_matrix_create(1, hdr->width))) {
		goto error;
	}
	for (y = 0; y < hdr->height; ++y) {
		if (jas_image_readcmpt(image, cmpt, 0, y, hdr->width, 1, data)) {
			goto error;
		}
		for (x = 0; x < hdr->width; ++x) {
			v = jas_matrix_get(data, 0, x);
			word = pgx_inttoword(v, hdr->prec, hdr->sgnd);
			if (pgx_putword(out, hdr->bigendian, hdr->prec, word)) {
				goto error;
			}
		}
	}
	jas_matrix_destroy(data);
	data = 0;
	return 0;

error:
	if (data) {
		jas_matrix_destroy(data);
	}
	return -1;
}

static int pgx_putword(jas_stream_t *out, bool bigendian, int prec,
  uint_fast32_t val)
{
	int i;
	int j;
	int wordsize;

	val &= (1 << prec) - 1;
	wordsize = (prec + 7) /8;
	for (i = 0; i < wordsize; ++i) {
		j = bigendian ? (wordsize - 1 - i) : i;
		if (jas_stream_putc(out, (val >> (8 * j)) & 0xff) == EOF) {
			return -1;
		}
	}
	return 0;
}

static uint_fast32_t pgx_inttoword(jas_seqent_t v, int prec, bool sgnd)
{
	uint_fast32_t ret;
	ret = ((sgnd && v < 0) ? ((1 << prec) + v) : v) & ((1 << prec) - 1);
	return ret;
}


text:
package org.diorite.inventory.slot;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import org.diorite.inventory.item.ItemStack;
import org.diorite.material.FuelMat;
import org.diorite.material.items.tool.ArmorMat;

/**
 * Represent slot properties, multiple inventory slots may use this same instance of slot object as it don't
 * represent some slot, but properties of it.
 */
public abstract class Slot
{
    public static final Slot BASE_CONTAINER_SLOT = new Slot(SlotType.CONTAINER)
    {
        @Override
        public ItemStack canHoldItem(final ItemStack item)
        {
            return item;
        }
    };
    public static final Slot BASE_HOTBAR_SLOT    = new Slot(SlotType.HOTBAR)
    {
        @Override
        public ItemStack canHoldItem(final ItemStack item)
        {
            return item;
        }
    };
    public static final Slot BASE_ARMOR_SLOT     = new Slot(SlotType.ARMOR)
    {
        @Override
        public ItemStack canHoldItem(final ItemStack item)
        {
            if (item == null)
            {
                return null;
            }
            return (item.getMaterial() instanceof ArmorMat) ? item : null;
        }
    };
    public static final Slot BASE_CRAFTING_SLOT  = new Slot(SlotType.CRAFTING)
    {
        @Override
        public ItemStack canHoldItem(final ItemStack item)
        {
            return item;
        }
    };
    public static final Slot BASE_FUEL_SLOT      = new Slot(SlotType.FUEL)
    {
        @Override
        public ItemStack canHoldItem(final ItemStack item)
        {
            if (item == null)
            {
                return null;
            } // TODO: add special handle for recipe-enabled fuel items
            return (item.getMaterial() instanceof FuelMat) ? item : null;
        }
    };
    public static final Slot BASE_RESULT_SLOT    = new Slot(SlotType.RESULT)
    {
        @Override
        public ItemStack canHoldItem(final ItemStack item)
        {
            return null;
        }
    };
    public static final Slot BASE_OUTSIDE_SLOT   = new Slot(SlotType.OUTSIDE)
    {
        @Override
        public ItemStack canHoldItem(final ItemStack item)
        {
            return item;
        }
    };

    protected final SlotType slotType;

    public Slot(final SlotType slotType)
    {
        this.slotType = slotType;
    }

    /**
     * Returns base slot type.
     *
     * @return base slot type.
     */
    public SlotType getSlotType()
    {
        return this.slotType;
    }

    /**
     * Method will check if this item can be inserted to this slot-type,
     * it will return this same item stack if it can be inserted or null
     * if it can't be inserted here.

     * It may also return other itemstack with this same data but other
     * amount if only part of item can be inserted. (returned itemstack is
     * item stack that can be inserted). Like Beacon block, only one item
     * from item stack can be inserted.

     *

     * WARNING: it will not check if there is space in this slot, it only
     * check if this slot can hold this type of item.
     *
     * @param item item stack to check.
     *
     * @return item stack that can be inserted here or null.
     */
    public abstract ItemStack canHoldItem(ItemStack item);

    @Override
    public String toString()
    {
        return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).appendSuper(super.toString()).append("slotType", this.slotType).toString();
    }
}