text:
"""
Created on Sun Feb 28 19:06:41 2016

@name:      MultiNomial Scobit Model
@author:    Timothy Brathwaite
@summary:   Contains functions necessary for estimating multinomial scobit
            models (with the help of the "base_multinomial_cm.py" file).
            Differs from version one since it works with the shape, intercept,
            index coefficient partitioning of estimated parameters as opposed
            to the shape, index coefficient partitioning scheme of version 1.
"""
from __future__ import absolute_import

from functools import partial
import warnings
import numpy as np
from scipy.sparse import diags

from . import base_multinomial_cm_v2 as base_mcm
from .estimation import LogitTypeEstimator
from .estimation import estimate
from .display_names import model_type_to_display_name as display_name_dict

try:
    # in Python 3 range returns an iterator instead of list
    # to maintain backwards compatibility use "old" version of range
    from past.builtins import range
except ImportError:
    pass

# Define the boundary values which are not to be exceeded during computation
max_comp_value = 1e300
min_comp_value = 1e-300

max_exp = 700
min_exp = -700

# Create a warning string that will be issued if ridge regression is performed.
_msg = "NOTE: An L2-penalized regression is being performed. The "
_msg_2 = "reported standard errors and robust standard errors "
_msg_3 = "***WILL BE INCORRECT***."
_ridge_warning_msg = _msg + _msg_2 + _msg_3

# Create a warning string that will be issued if "shape_ref_pos" is passed to
# the MNSL constructor as a kwarg
_msg_4 = "The Multinomial Scobit model estimates all shape parameters"
_msg_5 = ", so shape_ref_pos will be ignored if passed."
_shape_ref_msg = _msg_4 + _msg_5

def split_param_vec(param_vec, rows_to_alts, design, return_all_types=False):
    """
    Parameters
    ----------
    param_vec : 1D ndarray.
        Elements should all be ints, floats, or longs. Should have as many
        elements as there are parameters being estimated.
    rows_to_alts : 2D scipy sparse matrix.
        There should be one row per observation per available alternative and
        one column per possible alternative. This matrix maps the rows of the
        design matrix to the possible alternatives for this dataset. All
        elements should be zeros or ones.
    design : 2D ndarray.
        There should be one row per observation per available alternative.
        There should be one column per utility coefficient being estimated. All
        elements should be ints, floats, or longs.
    return_all_types : bool, optional.
        Determines whether or not a tuple of 4 elements will be returned (with
        one element for the nest, shape, intercept, and index parameters for
        this model). If False, a tuple of 3 elements will be returned, as
        described below.

    Returns
    -------
    `(shapes, intercepts, betas)` : tuple of 1D ndarrays.
        The first element will be an array of the shape parameters for this
        model. The second element will either be an array of the "outside"
        intercept parameters for this model or None. The third element will be
        an array of the index coefficients for this model.

    Note
    ----
    If `return_all_types == True` then the function will return a tuple of four
    objects. In order, these objects will either be None or the arrays
    representing the arrays corresponding to the nest, shape, intercept, and
    index parameters.
    """
    # Figure out how many possible alternatives exist in the dataset
    num_shapes = rows_to_alts.shape[1]
    # Figure out how many parameters are in the index
    num_index_coefs = design.shape[1]

    # Isolate the initial shape parameters from the betas
    shapes = param_vec[:num_shapes]
    betas = param_vec[-1 * num_index_coefs:]

    # Get the remaining outside intercepts if there are any
    remaining_idx = param_vec.shape[0] - (num_shapes + num_index_coefs)
    if remaining_idx > 0:
        intercepts = param_vec[num_shapes: num_shapes + remaining_idx]
    else:
        intercepts = None

    if return_all_types:
        return None, shapes, intercepts, betas
    else:
        return shapes, intercepts, betas

def _scobit_utility_transform(systematic_utilities,
                              alt_IDs,
                              rows_to_alts,
                              shape_params,
                              intercept_params,
                              intercept_ref_pos=None,
                              *args, **kwargs):
    """
    Parameters
    ----------
    systematic_utilities : 1D ndarray.
        All elements should be ints, floats, or longs. Should contain the
        systematic utilities of each observation per available alternative.
        Note that this vector is formed by the dot product of the design matrix
        with the vector of utility coefficients.
    alt_IDs : 1D ndarray.
        All elements should be ints. There should be one row per obervation per
        available alternative for the given observation. Elements denote the
        alternative corresponding to the given row of the design matrix.
    rows_to_alts : 2D scipy sparse matrix.
        There should be one row per observation per available alternative and
        one column per possible alternative. This matrix maps the rows of the
        design matrix to the possible alternatives for this dataset. All
        elements should be zeros or ones.
    shape_params : None or 1D ndarray.
        If an array, each element should be an int, float, or long. There
        should be one value per shape parameter of the model being used.
    intercept_params : None or 1D ndarray.
        If an array, each element should be an int, float, or long. If J is the
        total number of possible alternatives for the dataset being modeled,
        there should be J-1 elements in the array.
    intercept_ref_pos : int, or None, optional.
        Specifies the index of the alternative, in the ordered array of unique
        alternatives, that is not having its intercept parameter estimated (in
        order to ensure identifiability). Should only be None if
        `intercept_params` is None.

    Returns
    -------
    transformations : 2D ndarray.
        Should have shape `(systematic_utilities.shape[0], 1)`. The returned
        array contains the transformed utility values for this model. All
        elements should be ints, floats, or longs.
    """
    # Figure out what indices are to be filled in
    if intercept_ref_pos is not None and intercept_params is not None:
        needed_idxs = range(intercept_params.shape[0] + 1)
        needed_idxs.remove(intercept_ref_pos)

        if len(intercept_params.shape) > 1 and intercept_params.shape[1] > 1:
            # Get an array of zeros with shape
            # (num_possible_alternatives, num_parameter_samples)
            all_intercepts = np.zeros((rows_to_alts.shape[1],
                                       intercept_params.shape[1]))
            # For alternatives having their intercept estimated, replace the
            # zeros with the current value of the estimated intercepts
            all_intercepts[needed_idxs, :] = intercept_params
        else:
            # Get an array of zeros with shape (num_possible_alternatives,)
            all_intercepts = np.zeros(rows_to_alts.shape[1])
            # For alternatives having their intercept estimated, replace the
            # zeros with the current value of the estimated intercepts
            all_intercepts[needed_idxs] = intercept_params
    else:
        # Create a full set of intercept parameters including the intercept
        # constrained to zero
        all_intercepts = np.zeros(rows_to_alts.shape[1])

    # Figure out what intercept values correspond to each row of the
    # systematic utilities
    long_intercepts = rows_to_alts.dot(all_intercepts)

    # Convert the shape parameters back into their 'natural parametrization'
    natural_shapes = np.exp(shape_params)
    natural_shapes[np.isposinf(natural_shapes)] = max_comp_value
    # Figure out what shape values correspond to each row of the
    # systematic utilities
    long_natural_shapes = rows_to_alts.dot(natural_shapes)

    # Calculate the data dependent part of the transformation
    # Also, along the way, guard against numeric underflow or overflow
    exp_neg_v = np.exp(-1 * systematic_utilities)
    exp_neg_v[np.isposinf(exp_neg_v)] = max_comp_value

    powered_term = np.power(1 + exp_neg_v, long_natural_shapes)
    powered_term[np.isposinf(powered_term)] = max_comp_value

    term_2 = np.log(powered_term - 1)
    # Guard against overvlow
    too_big_idx = np.isposinf(powered_term)
    term_2[too_big_idx] = (-1 * long_natural_shapes[too_big_idx] *
                           systematic_utilities[too_big_idx])

    transformations = long_intercepts - term_2
    # Guard against overflow
    transformations[np.isposinf(transformations)] = max_comp_value
    transformations[np.isneginf(transformations)] = -1 * max_comp_value

    # Be sure to return a 2D array since other functions will be expecting that
    if len(transformations.shape) == 1:
        transformations = transformations[:, np.newaxis]

    return transformations

def _scobit_transform_deriv_v(systematic_utilities,
                              alt_IDs,
                              rows_to_alts,
                              shape_params,
                              output_array=None,
                              *args, **kwargs):
    """
    Parameters
    ----------
    systematic_utilities : 1D ndarray.
        All elements should be ints, floats, or longs. Should contain the
        systematic utilities of each observation per available alternative.
        Note that this vector is formed by the dot product of the design matrix
        with the vector of utility coefficients.
    alt_IDs : 1D ndarray.
        All elements should be ints. There should be one row per obervation per
        available alternative for the given observation. Elements denote the
        alternative corresponding to the given row of the design matrix.
    rows_to_alts : 2D scipy sparse matrix.
        There should be one row per observation per available alternative and
        one column per possible alternative. This matrix maps the rows of the
        design matrix to the possible alternatives for this dataset. All
        elements should be zeros or ones.
    shape_params : None or 1D ndarray.
        If an array, each element should be an int, float, or long. There
        should be one value per shape parameter of the model being used.
    output_array : 2D scipy sparse array.
        The array should be square and it should have
        `systematic_utilities.shape[0]` rows. It's data is to be replaced with
        the correct derivatives of the transformation vector with respect to
        the vector of systematic utilities. This argument is NOT optional.

    Returns
    -------
    output_array : 2D scipy sparse array.
        The shape of the returned array is `(systematic_utilities.shape[0],
        systematic_utilities.shape[0])`. The returned array specifies the
        derivative of the transformed utilities with respect to the systematic
        utilities. All elements are ints, floats, or longs.
    """
    # Note  the np.exp is  needed because the raw curvature params are the log
    # of the 'natural' curvature params. This is to ensure the natural shape
    # params are always positive
    curve_shapes = np.exp(shape_params)
    curve_shapes[np.isposinf(curve_shapes)] = max_comp_value
    long_curve_shapes = rows_to_alts.dot(curve_shapes)

    # Generate the needed terms for the derivative of the transformation with
    # respect to the systematic utility and guard against underflow or overflow
    exp_neg_v = np.exp(-1 * systematic_utilities)

    powered_term = np.power(1 + exp_neg_v, long_curve_shapes)

    small_powered_term = np.power(1 + exp_neg_v, long_curve_shapes - 1)

    derivs = (long_curve_shapes *
              exp_neg_v *
              small_powered_term /
              (powered_term - 1))
    # Use L'Hopitals rule to deal with overflow from v --> -inf
    # From plots, the assignment below may also correctly handle cases where we
    # have overflow from moderate v (say |v| <= 10) and large shape parameters.
    too_big_idx = (np.isposinf(derivs) +
                   np.isposinf(exp_neg_v) +
                   np.isposinf(powered_term) +
                   np.isposinf(small_powered_term)).astype(bool)
    derivs[too_big_idx] = long_curve_shapes[too_big_idx]
    # Use L'Hopitals rule to deal with underflow from v --> inf
    too_small_idx = np.where((exp_neg_v == 0) | (powered_term - 1 == 0))
    derivs[too_small_idx] = 1.0

    # Assign the calculated derivatives to the output array
    output_array.data = derivs
    assert output_array.shape == (systematic_utilities.shape[0],
                                  systematic_utilities.shape[0])

    # Return the matrix of dh_dv. Note the off-diagonal entries are zero
    # because each transformation only depends on its value of v and no others
    return output_array

def _scobit_transform_deriv_shape(systematic_utilities,
                                  alt_IDs,
                                  rows_to_alts,
                                  shape_params,
                                  output_array=None,
                                  *args, **kwargs):
    """
    Parameters
    ----------
    systematic_utilities : 1D ndarray.
        All elements should be ints, floats, or longs. Should contain the
        systematic utilities of each observation per available alternative.
        Note that this vector is formed by the dot product of the design matrix
        with the vector of utility coefficients.
    alt_IDs : 1D ndarray.
        All elements should be ints. There should be one row per obervation per
        available alternative for the given observation. Elements denote the
        alternative corresponding to the given row of the design matrix.
    rows_to_alts : 2D scipy sparse matrix.
        There should be one row per observation per available alternative and
        one column per possible alternative. This matrix maps the rows of the
        design matrix to the possible alternatives for this dataset. All
        elements should be zeros or ones.
    shape_params : None or 1D ndarray.
        If an array, each element should be an int, float, or long. There
        should be one value per shape parameter of the model being used.
    output_array : 2D scipy sparse array.
        The array should have shape `(systematic_utilities.shape[0],
        shape_params.shape[0])`. It's data is to be replaced with the correct
        derivatives of the transformation vector with respect to the vector of
        shape parameters. This argument is NOT optional.

    Returns
    -------
    output_array : 2D scipy sparse array.
        The shape of the returned array is `(systematic_utilities.shape[0],
        shape_params.shape[0])`. The returned array specifies the derivative of
        the transformed utilities with respect to the shape parameters. All
        elements are ints, floats, or longs.
    """
    # Note the np.exp is needed because the raw curvature params are the log
    # of the 'natural' curvature params. This is to ensure the natural shape
    # params are always positive.
    curve_shapes = np.exp(shape_params)
    curve_shapes[np.isposinf(curve_shapes)] = max_comp_value
    long_curve_shapes = rows_to_alts.dot(curve_shapes)

    # Generate the needed terms for the derivative of the transformation with
    # respect to the systematic utility and guard against underflow or overflow
    exp_neg_v = np.exp(-1 * systematic_utilities)

    powered_term = np.power(1 + exp_neg_v, long_curve_shapes)

    # Note the "* long_curve_shapes" accounts for the fact that the derivative
    # of the natural shape params (i.e. exp(shape_param)) with respect to the
    # shape param is simply exp(shape_param) = natural shape param. The
    # multipication comes from the chain rule.
    curve_derivs = (-1 * np.log1p(exp_neg_v) *
                    powered_term / (powered_term - 1)) * long_curve_shapes
    # Note that all of the following overflow and underflow guards are based
    # on L'Hopital's rule.
    # Guard against underflow from v --> inf. Note we end up with '-1' after
    # accounting for the jacobian.
    too_big_idx = np.where((powered_term - 1) == 0)
    curve_derivs[too_big_idx] = -1
    # Guard against overflow from v --> -inf.
    too_small_idx = np.isposinf(exp_neg_v)
    curve_derivs[too_small_idx] = max_comp_value
    # Guard against overflow from moderate v but shape --> inf.
    shape_too_big_idx = np.where((np.abs(systematic_utilities) <= 10) &
                                 np.isposinf(powered_term))
    curve_derivs[shape_too_big_idx] =\
        (-1 * np.log1p(exp_neg_v))[shape_too_big_idx]

    # Assign the calculated derivatives to the output array
    output_array.data = curve_derivs

    return output_array

def _scobit_transform_deriv_alpha(systematic_utilities,
                                  alt_IDs,
                                  rows_to_alts,
                                  intercept_params,
                                  output_array=None,
                                  *args, **kwargs):
    """
    Parameters
    ----------
    systematic_utilities : 1D ndarray.
        All elements should be ints, floats, or longs. Should contain the
        systematic utilities of each observation per available alternative.
        Note that this vector is formed by the dot product of the design matrix
        with the vector of utility coefficients.
    alt_IDs : 1D ndarray.
        All elements should be ints. There should be one row per obervation per
        available alternative for the given observation. Elements denote the
        alternative corresponding to the given row of the design matrix.
    rows_to_alts : 2D scipy sparse matrix.
        There should be one row per observation per available alternative and
        one column per possible alternative. This matrix maps the rows of the
        design matrix to the possible alternatives for this dataset. All
        elements should be zeros or ones.
    intercept_params : 1D ndarray or None.
        If an array, each element should be an int, float, or long. For
        identifiability, there should be J- 1 elements where J is the total
        number of observed alternatives for this dataset.
    output_array: None or 2D scipy sparse array.
        If a sparse array is pased, it should contain the derivative of the
        vector of transformed utilities with respect to the intercept
        parameters outside of the index. This keyword argurment will be
        returned. If there are no intercept parameters outside of the index,
        then `output_array` should equal None. If there are intercept
        parameters outside of the index, then `output_array` should be
        `rows_to_alts` with the all of its columns except the column
        corresponding to the alternative whose intercept is not being estimated
        in order to ensure identifiability.

    Returns
    -------
    output_array.
    """
    return output_array

def create_calc_dh_dv(estimator):
    """
    Return the function that can be used in the various gradient and hessian
    calculations to calculate the derivative of the transformation with respect
    to the index.

    Parameters
    ----------
    estimator : an instance of the estimation.LogitTypeEstimator class.
        Should contain a `design` attribute that is a 2D ndarray representing
        the design matrix for this model and dataset.

    Returns
    -------
    Callable.
        Will accept a 1D array of systematic utility values, a 1D array of
        alternative IDs, (shape parameters if there are any) and miscellaneous
        args and kwargs. Should return a 2D array whose elements contain the
        derivative of the tranformed utility vector with respect to the vector
        of systematic utilities. The dimensions of the returned vector should
        be `(design.shape[0], design.shape[0])`.
    """
    dh_dv = diags(np.ones(estimator.design.shape[0]), 0, format='csr')
    # Create a function that will take in the pre-formed matrix, replace its
    # data in-place with the new data, and return the correct dh_dv on each
    # iteration of the minimizer
    calc_dh_dv = partial(_scobit_transform_deriv_v, output_array=dh_dv)
    return calc_dh_dv

def create_calc_dh_d_shape(estimator):
    """
    Return the function that can be used in the various gradient and hessian
    calculations to calculate the derivative of the transformation with respect
    to the shape parameters.

    Parameters
    ----------
    estimator : an instance of the estimation.LogitTypeEstimator class.
        Should contain a `rows_to_alts` attribute that is a 2D scipy sparse
        matrix that maps the rows of the `design` matrix to the alternatives
        available in this dataset.

    Returns
    -------
    Callable.
        Will accept a 1D array of systematic utility values, a 1D array of
        alternative IDs, (shape parameters if there are any) and miscellaneous
        args and kwargs. Should return a 2D array whose elements contain the
        derivative of the tranformed utility vector with respect to the vector
        of shape parameters. The dimensions of the returned vector should
        be `(design.shape[0], num_alternatives)`.
    """
    dh_d_shape = estimator.rows_to_alts.copy()
    # Create a function that will take in the pre-formed matrix, replace its
    # data in-place with the new data, and return the correct dh_dshape on each
    # iteration of the minimizer
    calc_dh_d_shape = partial(_scobit_transform_deriv_shape,
                              output_array=dh_d_shape)
    return calc_dh_d_shape

def create_calc_dh_d_alpha(estimator):
    """
    Return the function that can be used in the various gradient and hessian
    calculations to calculate the derivative of the transformation with respect
    to the outside intercept parameters.

    Parameters
    ----------
    estimator : an instance of the estimation.LogitTypeEstimator class.
        Should contain a `rows_to_alts` attribute that is a 2D scipy sparse
        matrix that maps the rows of the `design` matrix to the alternatives
        available in this dataset. Should also contain an `intercept_ref_pos`
        attribute that is either None or an int. This attribute should denote
        which intercept is not being estimated (in the case of outside
        intercept parameters) for identification purposes.

    Returns
    -------
    Callable.
        Will accept a 1D array of systematic utility values, a 1D array of
        alternative IDs, (shape parameters if there are any) and miscellaneous
        args and kwargs. Should return a 2D array whose elements contain the
        derivative of the tranformed utility vector with respect to the vector
        of outside intercepts. The dimensions of the returned vector should
        be `(design.shape[0], num_alternatives - 1)`.
    """
    if estimator.intercept_ref_pos is not None:
        needed_idxs = range(estimator.rows_to_alts.shape[1])
        needed_idxs.remove(estimator.intercept_ref_pos)
        dh_d_alpha = (estimator.rows_to_alts
                               .copy()
                               .transpose()[needed_idxs, :]
                               .transpose())
    else:
        dh_d_alpha = None
    # Create a function that will take in the pre-formed matrix, replace its
    # data in-place with the new data, and return the correct dh_dalpha on each
    # iteration of the minimizer
    calc_dh_d_alpha = partial(_scobit_transform_deriv_alpha,
                              output_array=dh_d_alpha)

    return calc_dh_d_alpha

class ScobitEstimator(LogitTypeEstimator):
    """
    Estimation Object used to enforce uniformity in the estimation process
    across the various logit-type models.

    Parameters
    ----------
    model_obj : a pylogit.base_multinomial_cm_v2.MNDC_Model instance.
        Should contain the following attributes:

          - alt_IDs
          - choices
          - design
          - intercept_ref_position
          - shape_ref_position
          - utility_transform
    mapping_res : dict.
        Should contain the scipy sparse matrices that map the rows of the long
        format dataframe to various other objects such as the available
        alternatives, the unique observations, etc. The keys that it must have
        are `['rows_to_obs', 'rows_to_alts', 'chosen_row_to_obs']`
    ridge : int, float, long, or None.
            Determines whether or not ridge regression is performed. If a
            scalar is passed, then that scalar determines the ridge penalty for
            the optimization. The scalar should be greater than or equal to
            zero..
    zero_vector : 1D ndarray.
        Determines what is viewed as a "null" set of parameters. It is
        explicitly passed because some parameters (e.g. parameters that must be
        greater than zero) have their null values at values other than zero.
    split_params : callable.
        Should take a vector of parameters, `mapping_res['rows_to_alts']`, and
        model_obj.design as arguments. Should return a tuple containing
        separate arrays for the model's shape, outside intercept, and index
        coefficients. For each of these arrays, if this model does not contain
        the particular type of parameter, the callable should place a `None` in
        its place in the tuple.
    constrained_pos : list or None, optional.
        Denotes the positions of the array of estimated parameters that are
        not to change from their initial values. If a list is passed, the
        elements are to be integers where no such integer is greater than
        `num_params` Default == None.
    weights : 1D ndarray or None, optional.
        Allows for the calculation of weighted log-likelihoods. The weights can
        represent various things. In stratified samples, the weights may be
        the proportion of the observations in a given strata for a sample in
        relation to the proportion of observations in that strata in the
        population. In latent class models, the weights may be the probability
        of being a particular class.
    """
    def set_derivatives(self):
        self.calc_dh_dv = create_calc_dh_dv(self)
        self.calc_dh_d_alpha = create_calc_dh_d_alpha(self)
        self.calc_dh_d_shape = create_calc_dh_d_shape(self)

    def check_length_of_initial_values(self, init_values):
        """
        Ensures that `init_values` is of the correct length. Raises a helpful
        ValueError if otherwise.

        Parameters
        ----------
        init_values : 1D ndarray.
            The initial values to start the optimization process with. There
            should be one value for each index coefficient, outside intercept
            parameter, and shape parameter being estimated.

        Returns
        -------
        None.
        """
        # Calculate the expected number of shape and index parameters
        # Note the scobit model has one shape parameter per alternative.
        num_alts = self.rows_to_alts.shape[1]
        num_index_coefs = self.design.shape[1]

        if self.intercept_ref_pos is not None:
            assumed_param_dimensions = num_index_coefs + 2 * num_alts - 1
        else:
            assumed_param_dimensions = num_index_coefs + num_alts

        if init_values.shape[0] != assumed_param_dimensions:
            msg_1 = "The initial values are of the wrong dimension."
            msg_2 = "It should be of dimension {}"
            msg_3 = "But instead it has dimension {}"
            raise ValueError(msg_1 +
                             msg_2.format(assumed_param_dimensions) +
                             msg_3.format(init_values.shape[0]))

        return None

class MNSL(base_mcm.MNDC_Model):
    """
    Parameters
    ----------
    data : string or pandas dataframe.
        If string, data should be an absolute or relative path to a CSV file
        containing the long format data for this choice model. Note long format
        is has one row per available alternative for each observation. If
        pandas dataframe, the dataframe should be the long format data for the
        choice model.
    alt_id_col :str.
        Should denote the column in data which contains the alternative
        identifiers for each row.
    obs_id_col : str.
        Should denote the column in data which contains the observation
        identifiers for each row.
    choice_col : str.
        Should denote the column in data which contains the ones and zeros that
        denote whether or not the given row corresponds to the chosen
        alternative for the given individual.
    specification : OrderedDict.
        Keys are a proper subset of the columns in `data`. Values are either a
        list or a single string, "all_diff" or "all_same". If a list, the
        elements should be:
            - single objects that are in the alternative ID column of `data`
            - lists of objects that are within the alternative ID column of
              `data`. For each single object in the list, a unique column will
              be created (i.e. there will be a unique coefficient for that
              variable in the corresponding utility equation of the
              corresponding alternative). For lists within the
              `specification` values, a single column will be created for all
              the alternatives within the iterable (i.e. there will be one
              common coefficient for the variables in the iterable).
    intercept_ref_pos : int, optional.
         Valid only when the intercepts being estimated are not part of the
         index. Specifies the alternative in the ordered array of unique
         alternative ids whose intercept or alternative-specific constant is
         not estimated, to ensure model identifiability. Default == None.
    names : OrderedDict, optional.
        Should have the same keys as `specification`. For each key:
            - if the corresponding value in `specification` is "all_same", then
              there should be a single string as the value in names.
            - if the corresponding value in `specification` is "all_diff", then
              there should be a list of strings as the value in names. There
              should be one string in the value in names for each possible
              alternative.
            - if the corresponding value in `specification` is a list, then
              there should be a list of strings as the value in names. There
              should be one string the value in names per item in the value in
              `specification`.
        Default == None.
    intercept_names : list, or None, optional.
        If a list is passed, then the list should have the same number of
        elements as there are possible alternatives in data, minus 1. Each
        element of the list should be a string--the name of the corresponding
        alternative's intercept term, in sorted order of the possible
        alternative IDs. If None is passed, the resulting names that are shown
        in the estimation results will be
        `["Outside_ASC_{}".format(x) for x in shape_names]`. Default = None.
    shape_names : list, or None, optional.
        If a list is passed, then the list should have the same number of
        elements as there are possible alternative IDs in data. Each element of
        the list should be a string denoting the name of the corresponding
        shape parameter for the given alternative, in sorted order of the
        possible alternative IDs. The resulting names which are shown in the
        estimation results will be ["shape_{}".format(x) for x in shape_names].
        Default == None.
    """
    def __init__(self,
                 data,
                 alt_id_col,
                 obs_id_col,
                 choice_col,
                 specification,
                 intercept_ref_pos=None,
                 names=None,
                 intercept_names=None,
                 shape_names=None,
                 **kwargs):
        ##########
        # Print a helpful message if shape_ref_pos has been included
        ##########
        if "shape_ref_pos" in kwargs and kwargs["shape_ref_pos"] is not None:
            warnings.warn(_shape_ref_msg)

        ##########
        # Carry out the common instantiation process for all choice models
        ##########
        super(MNSL, self).__init__(data,
                                   alt_id_col,
                                   obs_id_col,
                                   choice_col,
                                   specification,
                                   intercept_ref_pos=intercept_ref_pos,
                                   names=names,
                                   intercept_names=intercept_names,
                                   shape_names=shape_names,
                                   model_type=display_name_dict["Scobit"])

        ##########
        # Store the utility transform function
        ##########
        self.utility_transform = partial(_scobit_utility_transform,
                                         intercept_ref_pos=intercept_ref_pos)

        return None

    def fit_mle(self,
                init_vals,
                init_shapes=None,
                init_intercepts=None,
                init_coefs=None,
                print_res=True,
                method="BFGS",
                loss_tol=1e-06,
                gradient_tol=1e-06,
                maxiter=1000,
                ridge=None,
                constrained_pos=None,
                just_point=False,
                **kwargs):
        """
        Parameters
        ----------
        init_vals : 1D ndarray.
            The initial values to start the optimization process with. There
            should be one value for each index coefficient and shape
            parameter being estimated. Shape parameters should come before
            intercept parameters, which should come before index coefficients.
            One can also pass None, and instead pass `init_shapes`, optionally
            `init_intercepts` if `"intercept"` is not in the utility
            specification, and `init_coefs`.
        init_shapes : 1D ndarray or None, optional.
            The initial values of the shape parameters. All elements should be
            ints, floats, or longs. There should be one parameter per possible
            alternative id in the dataset. This keyword argument will be
            ignored if `init_vals` is not None. Default == None.
        init_intercepts : 1D ndarray or None, optional.
            The initial values of the intercept parameters. There should be one
            parameter per possible alternative id in the dataset, minus one.
            The passed values for this argument will be ignored if `init_vals`
            is not None. This keyword argument should only be used if
            `"intercept"` is not in the utility specification. Default == None.
        init_coefs : 1D ndarray or None, optional.
            The initial values of the index coefficients. There should be one
            coefficient per index variable. The passed values for this argument
            will be ignored if `init_vals` is not None. Default == None.
        print_res : bool, optional.
            Determines whether the timing and initial and final log likelihood
            results will be printed as they they are determined.
            Default `== True`.
        method : str, optional.
            Should be a valid string for scipy.optimize.minimize. Determines
            the optimization algorithm that is used for this problem.
            Default `== 'bfgs'`.
        loss_tol : float, optional.
            Determines the tolerance on the difference in objective function
            values from one iteration to the next that is needed to determine
            convergence. Default `== 1e-06`.
        gradient_tol : float, optional.
            Determines the tolerance on the difference in gradient values from
            one iteration to the next which is needed to determine convergence.
            Default `== 1e-06`.
        maxiter : int, optional.
            Determines the maximum number of iterations used by the optimizer.
            Default `== 1000`.
        ridge : int, float, long, or None, optional.
            Determines whether or not ridge regression is performed. If a
            scalar is passed, then that scalar determines the ridge penalty for
            the optimization. The scalar should be greater than or equal to
            zero. Default `== None`.
        constrained_pos : list or None, optional.
            Denotes the positions of the array of estimated parameters that are
            not to change from their initial values. If a list is passed, the
            elements are to be integers where no such integer is greater than
            `init_vals.size.` Default == None.
        just_point : bool, optional.
            Determines whether (True) or not (False) calculations that are non-
            critical for obtaining the maximum likelihood point estimate will
            be performed. If True, this function will return the results
            dictionary from scipy.optimize. Default == False.

        Returns
        -------
        None. Estimation results are saved to the model instance.
        """
        # Store the optimization method
        self.optimization_method = method

        # Store the ridge parameter
        self.ridge_param = ridge
        if ridge is not None:
            warnings.warn(_ridge_warning_msg)

        # Construct the mappings from alternatives to observations and from
        # chosen alternatives to observations
        mapping_res = self.get_mappings_for_fit()
        rows_to_alts = mapping_res["rows_to_alts"]

        # Create init_vals from init_coefs, init_intercepts, and init_shapes if
        # those arguments are passed to the function and init_vals is None.
        if init_vals is None and all([x is not None for x in [init_shapes,
                                                              init_coefs]]):
            ##########
            # Check the integrity of the parameter kwargs
            ##########
            num_alternatives = rows_to_alts.shape[1]
            try:
                assert init_shapes.shape[0] == num_alternatives
            except AssertionError:
                msg = "init_shapes is of length {} but should be of length {}"
                raise ValueError(msg.format(init_shapes.shape,
                                            num_alternatives))

            try:
                assert init_coefs.shape[0] == self.design.shape[1]
            except AssertionError:
                msg = "init_coefs has length {} but should have length {}"
                raise ValueError(msg.format(init_coefs.shape,
                                            self.design.shape[1]))

            try:
                if init_intercepts is not None:
                    assert init_intercepts.shape[0] == (num_alternatives - 1)
            except AssertionError:
                msg = "init_intercepts has length {} but should have length {}"
                raise ValueError(msg.format(init_intercepts.shape,
                                            num_alternatives - 1))

            # The code block below will limit users to only having 'inside'
            # OR 'outside' intercept parameters but not both.
            # try:
            #     condition_1 = "intercept" not in self.specification
            #     condition_2 = init_intercepts is None
            #     assert condition_1 or condition_2
            # except AssertionError as e:
            #     msg = "init_intercepts should only be used if 'intercept' is"
            #     msg_2 = " not in one's index specification."
            #     msg_3 = "Either make init_intercepts = None or remove "
            #     msg_4 = "'intercept' from the specification."
            #     print(msg + msg_2 )
            #     print(msg_3 + msg_4)
            #     raise e

            if init_intercepts is not None:
                init_vals = np.concatenate((init_shapes,
                                            init_intercepts,
                                            init_coefs), axis=0)
            else:
                init_vals = np.concatenate((init_shapes,
                                            init_coefs), axis=0)
        elif init_vals is None:
            msg = "If init_vals is None, then users must pass both init_coefs "
            msg_2 = "and init_shapes."
            raise ValueError(msg + msg_2)

        # Create the estimation object
        zero_vector = np.zeros(init_vals.shape)
        scobit_estimator = ScobitEstimator(self,
                                           mapping_res,
                                           ridge,
                                           zero_vector,
                                           split_param_vec,
                                           constrained_pos=constrained_pos)
        # Set the derivative functions for estimation
        scobit_estimator.set_derivatives()

        # Perform one final check on the length of the initial values
        scobit_estimator.check_length_of_initial_values(init_vals)

        # Get the estimation results
        estimation_res = estimate(init_vals,
                                  scobit_estimator,
                                  method,
                                  loss_tol,
                                  gradient_tol,
                                  maxiter,
                                  print_res,
                                  just_point=just_point)

        if not just_point:
            # Store the estimation results
            self.store_fit_results(estimation_res)

            return None
        else:
            return estimation_res


text:
using namespace seqan;
//![includes]

//![count-one-mers-define-function]
template <typename TString>
void countOneMers(TString const sequence)
{
    typedef typename Size<TString>::Type TSize;
    typedef typename Value<TString>::Type TAlphabet;
//![count-one-mers-define-function]

//![count-one-mers-initialize-table]
    typedef String<TSize> TCounterString;
    TSize alphSize = ValueSize<TAlphabet>::VALUE;
    TCounterString counter;
    resize(counter, alphSize, 0);
//![count-one-mers-initialize-table]

//![count-one-mers-count-chars]
    typedef typename Iterator<TString const>::Type TIter;
    TIter itEnd = end(sequence);
    for (TIter it = begin(sequence); it != itEnd; goNext(it))
        value(counter, ordValue(value(it))) += 1;
//![count-one-mers-count-chars]

//![count-one-mers-print-chars]
    typedef typename Iterator<TCounterString>::Type TCounterIter;
    TCounterIter countIt = begin(counter);
    TCounterIter countItEnd = end(counter);
    for (TSize pos = 0; countIt != countItEnd; ++countIt, ++pos)
        if (value(countIt) > 0)
            std::cout << TAlphabet(pos) << ':' << value(countIt) << std::endl;
}
//![count-one-mers-print-chars]

//![main]
int main()
{
    std::cout << "ASCII String: Hello world!" << std::endl;
    countOneMers<CharString>("Hello world!");

    std::cout << "DNA String: TATACGCTA" << std::endl;
    countOneMers<DnaString>("TATACGCTA");

    std::cout << "Peptide String: MQDRVKRPMNAFIVWSRDQRRKMALEN" << std::endl;
    countOneMers<Peptide>("MQDRVKRPMNAFIVWSRDQRRKMALEN");

    return 0;
}
//![main]

redpajama_set_name: RedPajamaGithub


text:
{-# LANGUAGE RecordWildCards #-}

-- | Specification of Pos.Chain.Ssc

module Test.Pos.Ssc.Toss.BaseSpec
       ( spec
       ) where

import           Universum

import           Control.Lens (ix, _Wrapped)
import qualified Crypto.Random as Rand
import qualified Data.HashMap.Strict as HM
import qualified Data.HashSet as HS
import           Data.List.Extra (nubOrdOn)
import           System.Random (mkStdGen, randomR)
import           Test.Hspec (Spec, describe)
import           Test.Hspec.QuickCheck (prop)
import           Test.QuickCheck (Arbitrary (..), Gen, NonEmptyList (..),
                     Property, elements, listOf, property, sublistOf, suchThat,
                     vector, (.&&.), (===), (==>))

import           Pos.Binary (AsBinary)
import           Pos.Chain.Lrc (RichmenStakes)
import           Pos.Chain.Ssc (Commitment, CommitmentSignature,
                     CommitmentsMap (..), InnerSharesMap, MultiRichmenStakes,
                     Opening, OpeningsMap, PureTossWithEnv, SharesMap,
                     SignedCommitment, SscGlobalState (..),
                     SscVerifyError (..), VssCertData (..),
                     VssCertificate (..), VssCertificatesMap (..),
                     checkCertificatesPayload, checkCommitmentsPayload,
                     checkOpeningsPayload, checkSharesPayload,
                     deleteSignedCommitment, insertVss, mkCommitmentsMapUnsafe,
                     runPureToss, sgsCommitments, sgsOpenings, sgsShares,
                     sgsVssCertificates, supplyPureTossEnv, verifyCommitment,
                     verifyCommitmentSignature, verifyOpening, _vcVssKey)
import           Pos.Core (Coin, EpochIndex, EpochOrSlot (..), StakeholderId,
                     addressHash, crucialSlot, mkCoin)
import           Pos.Crypto (DecShare, ProtocolMagic, PublicKey, SecretKey,
                     SignTag (SignCommitment), sign, toPublic)
import           Test.Pos.Chain.Lrc.Arbitrary (GenesisMpcThd,
                     ValidRichmenStakes (..))
import           Test.Pos.Util.QuickCheck.Property (qcElem, qcFail, qcIsRight)

import           Test.Pos.Chain.Genesis.Dummy (dummyBlockVersionData,
                     dummyConfig, dummyK)
import           Test.Pos.Chain.Ssc.Arbitrary (BadCommAndOpening (..),
                     BadSignedCommitment (..), CommitmentOpening (..))

spec :: Spec
spec = describe "Ssc.Base" $ do
    describe "verifyCommitment" $ do
        prop description_verifiesOkComm verifiesOkComm
    describe "verifyCommitmentSignature" $ do
        prop description_verifiesOkCommSig verifiesOkCommSig
        prop description_notVerifiesBadSig notVerifiesBadCommSig
    describe "verifyOpening" $ do
        prop description_verifiesOkOpening verifiesOkOpening
        prop description_notVerifiesBadOpening notVerifiesBadOpening
    describe "checkCommitmentsPayload" $ do
        prop description_emptyPayload emptyPayloadComms
        prop description_checksGoodCommsPayload checksGoodCommsPayload
        prop description_checksBadCommsPayload checksBadCommsPayload
    describe "checkOpeningsPayload" $ do
        prop description_emptyPayload (emptyPayload checkOpeningsPayload)
        prop description_checksGoodOpensPayload checksGoodOpeningsPayload
        prop description_checksBadOpeningsPayload checksBadOpeningsPayload
    describe "checkSharesPayload" $ do
        prop description_emptyPayload
            (\e mrs hm -> emptyPayload (checkSharesPayload dummyConfig e) $ HM.insert e hm mrs)
        prop description_checksGoodSharesPayload checksGoodSharesPayload
        prop description_checksBadSharesPayload checksBadSharesPayload
    describe "checkCertificatesPayload" $ do
        prop description_emptyPayload
            (\e mrs hm -> emptyPayload (checkCertificatesPayload e) $ HM.insert e hm mrs)
        prop description_checksGoodCertsPayload checksGoodCertsPayload
        prop description_checksBadCertsPayload checksBadCertsPayload
  where
    description_verifiesOkComm =
        "successfully verifies a correct commitment commitment"
    description_verifiesOkCommSig =
        "successfully verifies a signed commitment for a given epoch and secret key"
    description_notVerifiesBadSig =
        "unsuccessfully verifies a commitment signature and a mismatching epoch"
    description_verifiesOkOpening =
        "successfully verifies that an opening corresponding to the given commitment\
\ does indeed belong to it"
    description_notVerifiesBadOpening =
        "unsuccessfully verifies a mismatching commitment and opening"
    description_emptyPayload =
        "an empty payload always leads to successful verification"
    description_checksGoodCommsPayload =
        "successfully checks payload of commitments with a proper epoch index"
    description_checksBadCommsPayload =
        "unsuccessfully checks payload of commitments with the right exception for each\
        \ failure case"
    description_checksGoodOpensPayload =
        "successfully checks payload of openings when the global state is correct"
    description_checksBadOpeningsPayload =
        "unsuccessfully checks payload of openings with the right exception for each\
        \ failure case"
    description_checksGoodSharesPayload =
        "successfully checks payload of shares"
    description_checksBadSharesPayload =
        "unsuccessfully checks payload of shares with the right exception for each\
        \ failure case"
    description_checksGoodCertsPayload =
        "successfully checks valid payload of VSS certificates"
    description_checksBadCertsPayload =
        "unsuccessfully checks payload of certificates with the right exception for each\
        \ failure case"

verifiesOkComm :: CommitmentOpening -> Bool
verifiesOkComm CommitmentOpening{..} =
    verifyCommitment coCommitment

verifiesOkCommSig :: ProtocolMagic -> SecretKey -> Commitment -> EpochIndex -> Bool
verifiesOkCommSig pm sk comm epoch =
    let commSig =
            ( toPublic sk
            , comm
            , sign pm SignCommitment sk (epoch, comm)
            )
    in  verifyCommitmentSignature pm epoch commSig

notVerifiesBadCommSig :: ProtocolMagic -> BadSignedCommitment -> EpochIndex -> Bool
notVerifiesBadCommSig pm (getBadSignedC -> badSignedComm) epoch =
    not $ verifyCommitmentSignature pm epoch badSignedComm

verifiesOkOpening :: CommitmentOpening -> Bool
verifiesOkOpening CommitmentOpening{..} =
    verifyOpening coCommitment coOpening

notVerifiesBadOpening :: BadCommAndOpening -> Bool
notVerifiesBadOpening (getBadCAndO -> badCommsAndOp) =
    not . uncurry verifyOpening $ badCommsAndOp

emptyPayload
    :: (Monoid container, Show e)
    => (container -> ExceptT e PureTossWithEnv a)
    -> MultiRichmenStakes
    -> SscGlobalState
    -> Property
emptyPayload pureToss mrs sgs =
    qcIsRight $ tossRunner mrs sgs $ pureToss mempty

emptyPayloadComms
    :: GoodCommsPayload
    -> SscGlobalState
    -> Property
    -- The 'checkCommitmentsPayload' function will never pass without a valid
    -- multirichmen hashmap, meaning we can't use entirely arbitrary data.
    -- As such, one from a 'GoodCommsPayload' is fetched instead since the
    -- 'Arbitrary' instance ensures validity.
emptyPayloadComms GoodPayload {..} =
    let e :: EpochIndex
        validMrs :: MultiRichmenStakes
        (e, validMrs) = (gpEpoch, gpMultiRichmenStakes)
    in emptyPayload (checkCommitmentsPayload dummyConfig e) validMrs

data GoodPayload p = GoodPayload
    { gpEpoch              :: !EpochIndex
    , gpGlobalState        :: !SscGlobalState
    , gpPayload            :: p
    , gpMultiRichmenStakes :: !MultiRichmenStakes
    } deriving (Show, Eq)

type GoodCommsPayload = GoodPayload CommitmentsMap

instance Arbitrary GoodCommsPayload where
    arbitrary = do
        -- These fields won't be needed for anything, so they can be entirely arbitrary.
        _sgsOpenings <- arbitrary
        _sgsShares <- arbitrary

        -- The epoch used in the tests is generated separately to make sure it exists.
        (gpEpoch, m) <- arbitrary :: Gen (EpochIndex, MultiRichmenStakes)
        richmen <- getValid <$> (arbitrary :: Gen (ValidRichmenStakes GenesisMpcThd))
        let richmenIds = HM.keys richmen
            gpMultiRichmenStakes = HM.insert gpEpoch richmen m

        -- This is the list of richmen which will be used to make keys for commitments
        -- in the argument 'CommitmentsMap'.
        richmenWithCerts <- sublistOf richmenIds
        richmenWithComms <- sublistOf richmenWithCerts

        -- TODO: this generates an invalid VssCertificatesMap because the
        -- stakeholders don't match the certificates
        stableCerts <- UnsafeVssCertificatesMap . HM.fromList <$>
            mapM (\r -> (,) <$> pure r <*> (arbitrary :: Gen VssCertificate))
                 richmenWithCerts

        -- Only the simplest case is considered w.r.t. the 'lastKnownEoS' field:
        -- 'checkCommitmentsPayload' is called with the same epoch as the 'lastKnownEoS'
        -- in 'gsVssCertificate'.
        -- This is because rolling back slots is and should be tested elsewhere.
        _sgsVssCertificates <- VssCertData
            <$> (pure . EpochOrSlot . Right . crucialSlot dummyK $ gpEpoch)
            <*> pure stableCerts
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary

        gpPayload <- mkCommitmentsMapUnsafe . HM.fromList <$>
                mapM (\k -> (,) <$> pure k <*> arbitrary) richmenWithComms
        _sgsCommitments <- mkCommitmentsMapUnsafe <$> customHashMapGen
            (arbitrary `suchThat` (not . flip elem richmenWithComms))
            arbitrary
        let gpGlobalState = SscGlobalState {..}

        return GoodPayload {..}

-- TODO: Account for 'CommSharesOnWrongParticipants' failure
checksGoodCommsPayload :: GoodCommsPayload -> Bool
checksGoodCommsPayload (GoodPayload epoch sgs commsMap mrs) =
    case tossRunner mrs sgs $ checkCommitmentsPayload dummyConfig epoch commsMap of
        Left (CommSharesOnWrongParticipants _) -> True
        Right _                                -> True
        _                                      -> False

-- TODO: Account for 'CommSharesOnWrongParticipants' failure
checksBadCommsPayload
    :: GoodCommsPayload
    -> StakeholderId
    -> SignedCommitment
    -> Int
    -> Property
checksBadCommsPayload
    (GoodPayload epoch sgs@SscGlobalState {..} commsMap mrs)
    sid
    comm
    seed =
    let mrsWithMissingEpoch = HM.delete epoch mrs
        noRichmen = tossRunner mrsWithMissingEpoch sgs
            $ checkCommitmentsPayload dummyConfig epoch commsMap
        res1 = case noRichmen of
            Left (NoRichmen e) -> e == epoch
            _                  -> False

        wrapCMap f = mkCommitmentsMapUnsafe . f . getCommitmentsMap
        commMember k = HM.member k . getCommitmentsMap

        newCommsMap = wrapCMap (HM.insert sid comm) commsMap
        committingNoParticipants = tossRunner mrs sgs
            $ checkCommitmentsPayload dummyConfig epoch newCommsMap
        res2 = case committingNoParticipants of
            Left (CommittingNoParticipants (s :| [])) -> s == sid
            _                                         -> False

        -- Inserting a random stakeholder would perturb the valid richmen stake we already
        -- have, so an existing one must be picked to avoid failing to calculate the
        -- shares distribution.
        someRichman =
            case res of
                Just s -> s
                _ -> error "Test.Pos.Ssc.Toss.BaseSpec.checkBadCommsPayload:\
                           \ empty commitments payload"
          where holders = HM.keys . getCommitmentsMap $ commsMap
                randomIndex = fst $ randomR (0, length holders - 1) $ mkStdGen seed
                res = holders ^? ix randomIndex

        sgs' = sgs & sgsCommitments %~ wrapCMap (HM.insert someRichman comm)
        commitmentAlreadySent = tossRunner mrs sgs'
            $ checkCommitmentsPayload dummyConfig epoch commsMap
        res3 = case commitmentAlreadySent of
            Left (CommitmentAlreadySent (s :| [])) -> s == someRichman
            _                                      -> False

    in not (commMember sid _sgsCommitments) &&
       not (commMember sid commsMap) &&
       not (null _sgsCommitments) &&
       not (null commsMap) ==> res1  && res2 && res3

newtype GoodOpeningPayload = GoodOpens
    { getGoodOpens :: (SscGlobalState, OpeningsMap)
    } deriving (Show, Eq)

instance Arbitrary GoodOpeningPayload where
    arbitrary = GoodOpens <$> do

      -- These fields won't be used, so they can be entirely arbitrary
        _sgsShares <- arbitrary :: Gen SharesMap
        _sgsVssCertificates <- arbitrary :: Gen VssCertData

        -- Because 'Opening's and 'Commitment's in the openings payload map and
        -- '_sgsCommitments' resp. will need to be matched succesfully by
        -- 'checkOpeningsPayload', they must be generated in tandem, along with their
        -- respective keys in both maps and the dummy 'CommitmentSignature' to be used in
        -- the commitments map.
        commsAndOpens <- arbitrary
            :: Gen [(StakeholderId, (PublicKey, CommitmentOpening, CommitmentSignature))]
        let fun (s, (pk, p, cs)) = (s, ((pk, coCommitment p, cs), coOpening p))

            -- The stakeholders in this assoc list are paired with a tuple, the first
            -- component of which will be their value in '_sgsCommitments' and the second
            -- the value in '_sgsOpenings'.
            stakeHoldersAndCOs
                :: [(StakeholderId,
                    ((PublicKey, Commitment, CommitmentSignature), Opening))]
            stakeHoldersAndCOs = map fun commsAndOpens
            _sgsCommitments =
                mkCommitmentsMapUnsafe .
                -- over _2 (view _1) (a,(b,c)) = (a,b)
                HM.fromList $ fmap (over _2 $ view _1) stakeHoldersAndCOs
        openingPldList <- sublistOf stakeHoldersAndCOs

        -- For the test data to be correct, none of the stakeholders with an opening in
        -- openings payload can have an opening in the global state i.e. be a key in
        -- '_sgsOpenings'.
        _sgsOpenings <- customHashMapGen
            (arbitrary `suchThat` (not . flip elem (map fst openingPldList)))
            (arbitrary :: Gen Opening)
        -- over _2 (view _2) (a,(b,c)) = (a,c)
        let opensPayload = HM.fromList $ fmap (over _2 $ view _2) openingPldList

        return (SscGlobalState {..}, opensPayload)

checksGoodOpeningsPayload :: MultiRichmenStakes -> GoodOpeningPayload -> Property
checksGoodOpeningsPayload mrs (getGoodOpens -> (sgs, openPayload)) =
    qcIsRight . tossRunner mrs sgs $ checkOpeningsPayload openPayload

checksBadOpeningsPayload
    :: StakeholderId
    -> Opening
    -> SignedCommitment
    -> MultiRichmenStakes
    -> GoodOpeningPayload
    -> Property
checksBadOpeningsPayload
    sid
    op
    sig@(_, comm, _)
    mrs
    (getGoodOpens -> (sgs@SscGlobalState {..}, openPayload)) =
    let newOpenPayload = HM.insert sid op openPayload

        openingAlreadySent =
            tossRunner mrs (sgs & sgsOpenings %~ HM.insert sid op) $
            checkOpeningsPayload newOpenPayload
        res1 = case openingAlreadySent of
            Left (OpeningAlreadySent _) -> True
            _                           -> False

        openingWithoutComm =
            tossRunner mrs sgs $ checkOpeningsPayload newOpenPayload
        res2 = case openingWithoutComm of
            Left (OpeningWithoutCommitment _) -> True
            _                                 -> False

        alterCommitsMap = mkCommitmentsMapUnsafe . HM.insert sid sig . getCommitmentsMap
        payloadWithBadOpening = HM.insert sid op openPayload
        openingNotMatchComm =
            tossRunner mrs (sgs & sgsCommitments %~ alterCommitsMap) $
            checkOpeningsPayload payloadWithBadOpening
        res3 = case openingNotMatchComm of
            Left (OpeningNotMatchCommitment _) -> True
            _                                  -> False

    in (not (HM.member sid _sgsOpenings) &&
        not (verifyOpening comm op)) ==> res1 && res2 && res3

type GoodSharesPayload = GoodPayload SharesMap

instance Arbitrary GoodSharesPayload where
    arbitrary = do
        -- These openings won't be needed for anything, so they can be entirely arbitrary.
        _sgsOpenings <- arbitrary

        -- The richmen for the epoch used in the tests is generated separately to make
        -- sure it exists.
        (gpEpoch, richmen, m) <-
            arbitrary :: Gen (EpochIndex, RichmenStakes, MultiRichmenStakes)
        let richmenIds = HM.keys richmen
            gpMultiRichmenStakes = HM.insert gpEpoch richmen m
        -- This is the list of richmen which will be used to make keys for the stable
        -- 'VssCertificates' that will be in the 'certs' field of '_sgsVssCertificates'.
        richmenWithCerts <- sublistOf richmenIds
        -- These richmen will be used to make keys for the shares that will be in the
        -- 'SharesMap' which will be used as the second argument of 'checkSharesPayload'
        -- in tests.
        richmenWithShares <- sublistOf richmenWithCerts
        let n = length richmenWithShares

        stableCerts <- UnsafeVssCertificatesMap . HM.fromList <$>
            mapM (\r -> (,) <$> pure r <*> (arbitrary :: Gen VssCertificate))
                 richmenWithCerts

        -- Like with 'GoodCommsPayload', only the simplest case is considered w.r.t. the
        -- 'lastKnownEoS' field: 'checkSharesPayload' is called with the same epoch as the
        -- 'lastKnownEoS' in 'gsVssCertificate'.
        _sgsVssCertificates <- VssCertData
            <$> (pure . EpochOrSlot . Right . crucialSlot dummyK $ gpEpoch)
            <*> pure stableCerts
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary

        innerMaps <- (vector n) :: Gen [InnerSharesMap]
        let gpPayload = HM.fromList $ zip richmenWithShares innerMaps
            -- Every key from every inner shares map must have a commitment in the global
            -- state i.e. be a key in '_sgsCommitments'.
            necessaryKeys = concatMap HM.keys innerMaps

        _sgsCommitments <- mkCommitmentsMapUnsafe <$> do
            necessaryMap <- HM.fromList <$>
                mapM (\k -> (,) <$> pure k <*> arbitrary) necessaryKeys
            fillerMap <- arbitrary :: Gen (HashMap StakeholderId SignedCommitment)
            return $ HM.union necessaryMap fillerMap
        -- The keys in the shares map with which 'checkSharesPayload' is ran must not
        -- exist in '_sgsShares' for the global data to be correct.
        _sgsShares <-
            customHashMapGen (arbitrary `suchThat` (not . flip elem richmenWithShares))
                             arbitrary
        let gpGlobalState = SscGlobalState {..}

        return GoodPayload {..}

-- NOTE: this test does not care for 'DecrSharesNotMatchCommitment' failure. This would
--make the already non-trivial arbitrary instance for 'GoodSharesPayload' unmanageable.
checksGoodSharesPayload :: GoodSharesPayload -> Bool
checksGoodSharesPayload (GoodPayload epoch sgs sharesMap mrs) =
    case tossRunner mrs sgs $ checkSharesPayload dummyConfig epoch sharesMap of
        Left (DecrSharesNotMatchCommitment _) -> True
        Right _                               -> True
        _                                     -> False

-- | Checks that when the data 'checkSharesPayload' is passed is incorrect w.r.t.
-- 'checkSharesPayload', said function fails.
-- NOTE: does not check for 'DecrSharesNotMatchCommitment' failure. This would make the
-- already non-trivial arbitrary instance for 'GoodSharesPayload' unmanageable.
checksBadSharesPayload
    :: GoodSharesPayload
    -> PublicKey
    -> NonEmpty (AsBinary DecShare)
    -> VssCertificate
    -> Property
checksBadSharesPayload (GoodPayload epoch g@SscGlobalState {..} sm mrs) pk ne cert =
    let sid = addressHash pk

        -- This property assumes the existence of a stakeholder not present in neither the
        -- commitments nor shares map. Instead of writing a new 'Arbitrary' type which
        -- will only be useful here, this condition is just enforced by deleting it from
        -- where it shouldn't be.
        sgs = g & sgsShares %~ HM.delete sid
                 & sgsCommitments %~ deleteSignedCommitment sid
        sharesMap = fmap (HM.delete sid) . HM.delete sid $ sm

        mrsWithMissingEpoch = HM.delete epoch mrs
        noRichmen = tossRunner mrsWithMissingEpoch sgs
            $ checkSharesPayload dummyConfig epoch sharesMap
        res1 = noRichmen === Left (NoRichmen epoch)

        newSharesMap = HM.insert sid mempty sharesMap
        sharesNotRichmen = tossRunner mrs sgs
            $ checkSharesPayload dummyConfig epoch newSharesMap
        res2 = case sharesNotRichmen of
            Left (SharesNotRichmen nes) -> sid `qcElem` nes
            _ -> qcFail $ "expected " <> show sharesNotRichmen <>
                          " to be a Left (SharesNotRichmen ...)"

        newerSharesMap = fmap (HM.insert sid ne) sharesMap
        internalShareWithoutComm = tossRunner mrs sgs
            $ checkSharesPayload dummyConfig epoch newerSharesMap
        res3 = case internalShareWithoutComm of
            Left (InternalShareWithoutCommitment nes) -> sid `qcElem` nes
            _ -> qcFail $ "expected " <> show internalShareWithoutComm <>
                          " to be a Left (InternalShareWithoutCommitment ...)"

        -- The expiry epoch has to be big, otherwise the cert won't get
        -- inserted. However, making it 'maxBound' doesn't work because then
        -- it gets incremented internally and overflows
        cert' = cert { vcSigningKey = pk, vcExpiryEpoch = pred maxBound }
        newestSharesMap = HM.insert sid mempty sharesMap
        sgs' = sgs & sgsShares %~ HM.insert sid mempty
                   & sgsVssCertificates %~ \vcd@VssCertData{..} ->
                         vcd { certs = fst $ insertVss cert' certs}
        mrs' = HM.update (Just . HM.insert sid (mkCoin 0)) epoch mrs
        sharesAlreadySent = tossRunner mrs' sgs'
            $ checkSharesPayload dummyConfig epoch newestSharesMap
        res4 = case sharesAlreadySent of
            Left (SharesAlreadySent nes) -> sid `qcElem` nes
            _ -> qcFail $ "expected " <> show sharesAlreadySent <>
                          " to be a Left (SharesAlreadySent ...)"

        allCerts = toList . getVssCertificatesMap $
                   certs (sgs ^. sgsVssCertificates)

    in not (null sharesMap) &&
       not (vcVssKey cert `elem` map vcVssKey allCerts) &&
       not (pk `elem` map vcSigningKey allCerts)
       ==> res1 .&&. res2 .&&. res3 .&&. res4

type GoodCertsPayload = GoodPayload VssCertificatesMap

instance Arbitrary GoodCertsPayload where
    arbitrary = do

        -- These fields of 'SscGlobalState' are irrelevant for the
        -- 'checkCertificatesPayload' function.
        _sgsShares <- arbitrary
        _sgsOpenings <- arbitrary
        _sgsCommitments <- arbitrary

        -- We'll need an 'EpochIndex' to run 'checkCertificatesPayload'. This epoch index
        -- will also need an accompanying 'RichmenStakes', but because we'll need the
        -- public keys to generate valid 'VssCertificates' w.r.t.
        -- 'checkCertificatesPayload', a list with public keys in tuples is generated
        -- as an intermediate step.
        (gpEpoch, NonEmpty richKeys, m) <-
            arbitrary
                :: Gen (EpochIndex, NonEmptyList (PublicKey, Coin), MultiRichmenStakes)
        let richmenPks :: [PublicKey]
            richmenPks = map fst richKeys
            richmen :: RichmenStakes
            richmen = HM.fromList $ map (over _1 addressHash) richKeys
            -- The 'epoch' epoch is guaranteed to exist in 'richmen', so we
            -- can use '(!)' to search for it in later tests.
            gpMultiRichmenStakes :: MultiRichmenStakes
            gpMultiRichmenStakes = HM.insert gpEpoch richmen m

        -- This is the list of participants in SSC that will have a
        -- certificate in the 'VssCertificatesMap' which'll be returned.
        participants <- sublistOf $ HM.keys richmen

        -- This 'VssCertificatesMap' satisfies:
        --   * Every 'vcSigningKey' in all its certificates has a corresponding
        --    'StakeholderId' in 'mrs HM.! epoch'
        --   * The set of its 'StakeholderId' keys is a subset of all the
        --    'StakeholderId's in 'mrs'
        gpPayload <- UnsafeVssCertificatesMap <$> do
            let vssGen :: Gen VssCertificate
                vssGen = do
                    -- This list is guaranteed to be non-empty
                    richman <- elements richmenPks
                    vssCert <- arbitrary
                    return $ vssCert {vcSigningKey = richman}
                gen :: StakeholderId -> Gen (StakeholderId, VssCertificate)
                gen sid = (,) <$> pure sid <*> vssGen
            participantsMap <- HM.fromList <$> mapM gen participants
            fillerMap <- customHashMapGen arbitrary vssGen
            return $
                -- remove certs with duplicate VSS keys
                HM.fromList . nubOrdOn (vcVssKey . snd) . HM.toList $
                HM.union participantsMap fillerMap

        -- The 'VssCertificatesMap' field of this 'VssCertData' value satisfies:
        --   * None of its 'StakeholderId' keys is a richman
        --    (i.e. is a member of 'richmen')
        --   * None of the VSS keys from 'gpPayload' are present here
        -- TODO: this generates an invalid VssCertificatesMap because the
        -- stakeholders don't match the certificates
        let payloadVssKeys = HS.fromList $ map vcVssKey $
                toList (getVssCertificatesMap gpPayload)
        _sgsVssCertificates <- do
            certs <- UnsafeVssCertificatesMap <$> customHashMapGen
                (arbitrary `suchThat` (not . flip HM.member richmen))
                (arbitrary `suchThat` (not . flip HS.member payloadVssKeys . vcVssKey))
            vssData <- arbitrary
            return $ vssData {certs = certs}
        let gpGlobalState = SscGlobalState {..}

        return GoodPayload {..}

checksGoodCertsPayload :: GoodCertsPayload -> Property
checksGoodCertsPayload (GoodPayload epoch sgs certsMap mrs) =
    qcIsRight . tossRunner mrs sgs $ checkCertificatesPayload epoch certsMap

checksBadCertsPayload :: GoodCertsPayload -> PublicKey -> VssCertificate -> Property
checksBadCertsPayload (GoodPayload epoch sgs certsMap mrs) pk cert =
    let sid = addressHash pk

        mrsWithMissingEpoch = HM.delete epoch mrs
        noRichmen =
            tossRunner mrsWithMissingEpoch sgs $ checkCertificatesPayload epoch certsMap
        res1 = noRichmen === Left (NoRichmen epoch)

        -- The expiry epoch has to be big, otherwise the cert won't get
        -- inserted. However, making it 'maxBound' doesn't work because then
        -- it gets incremented internally and overflows
        cert' = cert { vcSigningKey = pk, vcExpiryEpoch = pred maxBound }
        (certsMap2, _) = insertVss cert' certsMap
        newSgs = sgs & sgsVssCertificates %~
            \vcd -> vcd { certs = fst $ insertVss cert' (certs vcd) }
        certAlreadySent =
            tossRunner mrs newSgs $ checkCertificatesPayload epoch certsMap2
        res2 = case certAlreadySent of
            Left (CertificateAlreadySent nes) -> sid `qcElem` nes
            _ -> qcFail $ "expected " <> show certAlreadySent <>
                          " to be a Left (CertificateAlreadySent ...)"

        certSid = addressHash . vcSigningKey $ cert
        (certsMap3, _) = insertVss cert certsMap
        certNoRichmen =
            tossRunner mrs sgs $ checkCertificatesPayload epoch certsMap3
        res3 = case certNoRichmen of
            Left (CertificateNotRichmen nes) -> certSid `qcElem` nes
            _ -> qcFail $ "expected " <> show certNoRichmen <>
                          " to be a Left (CertificateNotRichmen ...)"

        -- We take the VSS key of some cert from 'sgs' and replace a key of
        -- some cert in 'certsMap' with it
        res4 = fromMaybe (property True) $ do
            c1 <- (fmap fst . uncons . toList) (certs (sgs ^. sgsVssCertificates))
            let c1id = addressHash . vcSigningKey $ c1
            c2id <- (fmap fst . uncons) (HM.keys (getVssCertificatesMap certsMap))
            let certsMap4 = certsMap
                    & _Wrapped . ix c2id . _vcVssKey .~ vcVssKey c1
                certDuplicateVss =
                    tossRunner mrs sgs $
                    checkCertificatesPayload epoch certsMap4
            pure $ c1id /= c2id ==> case certDuplicateVss of
                Left (CertificateDuplicateVssKey nes) -> c2id `qcElem` nes
                _ -> qcFail $ "expected " <> show certDuplicateVss <>
                              " to be a Left (CertificateDuplicateVssKey ...)"

        allVssKeys = map vcVssKey (toList (getVssCertificatesMap certsMap))

    in (not (HM.member certSid $ mrs HM.! epoch) &&
        not (vcVssKey cert `elem` allVssKeys))
       ==> res1 .&&. res2 .&&. res3 .&&. res4

----------------------------------------------------------------------------
-- Utility functions for this module
----------------------------------------------------------------------------

-- Going to use fake randomness here because threading MonadRandom through
-- everything is annoying
tossRunner :: MultiRichmenStakes
           -> SscGlobalState
           -> ExceptT e PureTossWithEnv a
           -> Either e a
tossRunner mrs sgs =
    view _1 .
    fst . Rand.withDRG (Rand.drgNewTest (123,456,789,12345,67890)) .
    runPureToss sgs .
    supplyPureTossEnv (mrs, dummyBlockVersionData) .
    runExceptT

customHashMapGen
    :: (Hashable k, Eq k)
    => Gen k -> Gen v -> Gen (HM.HashMap k v)
customHashMapGen keyGen valGen = HM.fromList <$> (listOf $ (,) <$> keyGen <*> valGen)


text:
using System;

namespace Org.BouncyCastle.Asn1.X509
{
	/// <remarks>
	/// <pre>
	/// PrivateKeyUsagePeriod ::= SEQUENCE
	/// {
	/// notBefore       [0]     GeneralizedTime OPTIONAL,
	/// notAfter        [1]     GeneralizedTime OPTIONAL }
	/// </pre>
	/// </remarks>
	public class PrivateKeyUsagePeriod
		: Asn1Encodable
	{
		public static PrivateKeyUsagePeriod GetInstance(
			object obj)
		{
			if (obj is PrivateKeyUsagePeriod)
			{
				return (PrivateKeyUsagePeriod) obj;
			}

			if (obj is Asn1Sequence)
			{
				return new PrivateKeyUsagePeriod((Asn1Sequence) obj);
			}

			if (obj is X509Extension)
			{
				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
			}

			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
		}

		private DerGeneralizedTime _notBefore, _notAfter;

		private PrivateKeyUsagePeriod(
			Asn1Sequence seq)
		{
			foreach (Asn1TaggedObject tObj in seq)
			{
				if (tObj.TagNo == 0)
				{
					_notBefore = DerGeneralizedTime.GetInstance(tObj, false);
				}
				else if (tObj.TagNo == 1)
				{
					_notAfter = DerGeneralizedTime.GetInstance(tObj, false);
				}
			}
		}

		public DerGeneralizedTime NotBefore
		{
			get { return _notBefore; }
		}

		public DerGeneralizedTime NotAfter
		{
			get { return _notAfter; }
		}

		public override Asn1Object ToAsn1Object()
		{
			Asn1EncodableVector v = new Asn1EncodableVector();

			if (_notBefore != null)
			{
				v.Add(new DerTaggedObject(false, 0, _notBefore));
			}

			if (_notAfter != null)
			{
				v.Add(new DerTaggedObject(false, 1, _notAfter));
			}

			return new DerSequence(v);
		}
	}
}


text:
 make based on https://github.com/haiwen/seafile/wiki/Seafile-web-API

## Installation

Add this line to your application's Gemfile:

    gem 'seafile-api'

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install seafile-api
## Tests
For tests need update tests/spec_helper.rb with your data
after this run:
    rspec tests
## Usage

### Initialize
    require 'seafile-api'
    sf = SeafileApi::Connect.new(user_name,password,host,default_repo)

### Configuration
    sf.user_name = email
    sf.password = password
    sf.host = https://seafile.com
    sf.repo = repo id

## Seafile-Api Methods
### Work with account
#### List Accounts
    sf.list_accounts

#### Check Account info
    sf.account_info

#### Create Account
+ email
+ password
        sf.create_accounts(email,pass)

#### Update Account
+ email
+ password

        sf.update_account(email,pass)

#### Delete Account

        sf.del_account(email)

### Starred Files
#### List starred files
#### Star a File
+ file
+ repo_id -> default value = default repo

        sf.star_a_file(file,repo_id)

#### UnStar a File
+ file
+ repo_id -> default value = default repo

        sf.unstar_a_file(file,repo_id)

### User Messages
#### List User Messages
+ to email

        sf.list_user_message(to_email)

#### Reply A User Message
        sf.unread_message

#### Count Unseen Message
+ to email
+ message

        sf.reply_user_message(to_email,message)

### Group
#### List Groups
    sf.list_groups

#### Add A Group
+ group name

        sf.add_group(group_name)

#### Group Member
##### Add a Group Member
+ user email
+ group id

        sf.add_group_member(user_email,group_id)

##### Delete a Group Member
+ user email
+ group id

        sf.del_group_member(user_email,group_id)

#### Group Message

##### Get Group Messages
+ group id

        sf.group_messages(group_id)

##### Get Group Messages Detail
+ group id
+ message id

        sf.group_message_detail(group_id,msg_id)

##### Send A Group Message
+ group id
+ message
+ repo id -> default value = default repo
+ path -> default value = '/'

        sf.send_group_message(group_id,message,repo_id,path)

##### Reply A Group Message
+ group id
+ message
+ message id

        sf.reply_group_message(group_id,message,msg_id)

##### Get Group Message Replies
        sf.group_messages_replies

### Share
#### File Share Link
##### List File Share Links
        sf.list_file_share_link

##### Create File Share Link
+ file
+ repo_id -> default value = default repo

        sf.create_file_share_link(file,repo_id=self.repo)

##### Delete File Share Link
+ shared token

        sf.delete_share_link(shared_t)

#### Shared Libraries
##### List Shared Libraries
        sf.list_shared_libraries
##### List Be Shared Libraries (need know what it do)
        sf.list_beshared_libraries
##### Share A Libraries
+ repo_id
+ share_type -> default value = group
+ user
+ permission -> default value = rw
+ group_id

        sf.share_library(repo_id,user,group_id,permission,share_type)
##### Unshared Libraries
+ repo id
+ share type
+ user
+ group id

        sf.unshare_library(repo_id,share_type,user,group_id)
#### Shared Files
##### List Shared Files
        sf.list_shared_files
##### Download Shared File
+ file token

        sf.shared_file_link(file_t)
##### Get Shared File Detail
+ file token

        sf.shared_file_detail(file_t)
##### Delete Shared File
+ file token

        sf.del_shared_file(file_t)
##### Download Private Shared File (need know what is private shared file)
+ file token

        sf.download_private_shared_file(file_t)
##### Get Private Shared File Detail
+ file token

        sf.private_shared_file_detail(file_t)

### Library
#### Library
##### Get Default Library
        sf.default_library

##### Create Default Library
        sf.create_default_library
##### List Libraries
        sf.list_libraries

##### Get Library Info
+ repo id

        sf.library_info(repo_id)

##### Get Library Owner
+ repo id

        sf.library_owner(repo_id)

##### Get library History
+ repo id

        sf.library_history(repo_id)

##### Create Library
+ name
+ desc -> default value = "new repo"
+ pwd -> default value = nil

        sf.create_library(name,desc="new repo",pwd=nil)

##### Check/Create Sub Library
+ repo id
+ name
+ path -> default value = '/'

        sf.create_sub_library(repo_id,name,p)

##### Delete Library
+ repo id

        sf.del_library(repo_id)

##### Decrypt Library
+ name
+ password

        sf.decrypt_library(repo_id,password)

##### Create Public Library
+ repo id

        sf.create_public_library(repo_id)

##### Remove Public Library
+ repo id

        sf.remove_public_library(repo_id)

##### Fetch library download info
+ repo id

        sf.fetch_library_info(repo_id)

##### List Virtual Libraries
        sf.list_virtual_libraries

##### Search Libraries (test on 3.0.3 server , doesn't support it)
+ keyword

        sf.search_libraries(keyword)

#### File
##### Download File
+ filename
+ repo -> default value = default repo

        sf.file_link(filename,repo)

##### Get File Detail
+ filename
+ repo -> default value = default repo

        sf.file_detail(filename,repo)

##### Get File History
+ filename
+ repo -> default value = default repo

        sf.file_history(filename,repo)

##### Download File From a Revision
+ filename
+ commit id
+ repo -> default value = default repo

        sf.link_revision(filename,commit_id,repo)

##### Create File
+ filename
+ repo -> default value = default repo

        sf.create_file(filename,repo=self.repo)

##### Rename File
+ old name
+ new name
+ repo -> default value = default repo

        sf.rename_file(old_name,new_name,repoo)

##### Move File
+ filename
+ destination dir -> default value = '/'
+ destination repo -> default value = default repo
+ source repo -> default value = default repo

        sf.move_file(filename,dst_dir,dest_repo,src_repo)

##### Copy File (at 3.0.0 - working , but at 3,0,4 not working -missing arguments)
+ filename
+ destination dir -> default value = '/'
+ destination repo -> default value = default repo
+ source repo -> default value = default repo

        sf.copy_file(filename,dst_dir,dest_repo,src_repo)

##### Delete File
+ filename
+ repo -> default value = default repo

        sf.del_file(filename,repo)

##### Upload File
+ filename
+ path -> default value = '/'
+ repo -> default value = default repo

        sf.upload_file(file,path='/',repo=self.repo)

##### Update File
+ filename
+ target file -> default value = as filename
+ repo -> default value = default repo

        sf.update_file(file,target_file,repo)

##### Get Upload Blocks link
+ repo -> default value = default repo

        sf.block_link(repo)

#### Directory
##### List Directory Entries
+ path -> default value = '/'
+ repo -> default value = default repo

        sf.list_dir_entry(path,repo)

##### Create New Directory
+ path
+ repo -> default value = default repo

        sf.create_dir(path,repo)

##### Delete Directory
+ path
+ repo -> default value = default repo

        sf.del_dir(path,repo)

##### Download Directory
+ path
+ repo -> default value = default repo

        sf.download_dir(path,repo)

##### Share Directory
+ email
+ path
+ repo -> default value = default repo
+ perm -> default value = 'r'
+ s type -> default value = 'd'

        sf.share_dir(email,path,perm,repo,s_type)

## Contributing

1. Fork it ( http://github.com/NingenUA/seafile-api/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request


text:
package skinny.controller.feature

import org.scalatra.test.scalatest.ScalatraFlatSpec
import skinny._
import skinny.controller.SkinnyApiController

class ChunkedResponseFeatureSpec extends ScalatraFlatSpec {

  behavior of "ChunkedResponseFeature"

  class Controller extends SkinnyApiController with ChunkedResponseFeature {
    def index = {
      writeChunk("abc".getBytes)
    }
  }
  val controller = new Controller with Routes {
    get("/")(index).as("index")
  }

  addFilter(controller, "/*")

  it should "return chunked response" in {
    get("/") {
      status should equal(200)
      body should equal("abc")
    }
  }

}