import numpy as np
from itertools import count
from functools import partial
from collections import defaultdict

from util import stats, to_discrete

class TreeNode:
    """
    The data structure that holds the actual tree structure for the decision tree.
    The tree is just a bunch of these nodes connected with some attributes.
    A parent is connect to 2 children via `.left` and `.right`. Children also
    have a back-reference at `.parent`. The final prediction is made based on the
    `.probability` on the node reached which has no more children.

    Attributes:
        id: a unique (per tree) identifying integer
        n: the number of examples still in consideration
        gini_impurity: the gini impurity of the examples at this node
        probability: a float [0, 1] which is the probability of the positive class
        split_feat: index of the feature this node splits on
        split_val: the value to split on. values less-then-or-equal-to the value go left, greater-than goes right
        left: the left child TreeNode. `None` for a leaf node
        right: the right child TreeNode
        parent: the parent TreeNode. `None` for the root
        ranges: Dict[int -> (int, int)] A dict that maps a feature index to its range of potential values.
            Every time a node is split, its children have a reduced potential range of values for that feature
            which is being split on. Keep track of this to narrow down candidate splits in the future.
    """

    def __init__(self, id, n, gini_impurity, probability):
        self.id = id
        self.n = n
        self.gini_impurity = gini_impurity
        self.probability = probability
        self.split_feat = None
        self.split_val = None
        self.left = None
        self.right = None
        self.parent = None
        self.ranges = None

    def is_leaf(self):
        """returns True if this node has no children"""
        return self.left is None

    def get_assigned_node_id(self, feat_vector):
        """takes a data point and returns the ID of the node it's currently assigned to"""
        if self.is_leaf():
            return self.id

        # if the split_val is int, this is a (binned) numerical feature, which is ordinal
        if isinstance(self.split_val, int):
            if feat_vector[self.split_feat] > self.split_val:
                return self.right.get_assigned_node_id(feat_vector)
            return self.left.get_assigned_node_id(feat_vector)
        # otherwise, its categorical feature, and its non-ordinal
        elif isinstance(self.split_val, set):
            if feat_vector[self.split_feat] not in self.split_val:
                return self.right.get_assigned_node_id(feat_vector)
            return self.left.get_assigned_node_id(feat_vector)
        raise ValueError("invalid split_val: {}".format(self.split_val))

    def split(self, feat, val, left, right):
        """only called on a leaf node. splits the node and adds 2 child nodes"""
        if not self.is_leaf():
            raise ValueError("tree node {} is already split".format(self.id))
        self.split_feat = feat
        self.split_val = val
        self.left = left
        self.right = right
        left.parent = self
        right.parent = self

    def get_probability(self, feat_vector):
        """takes a data point and returns its probability of being the positive class"""
        if self.is_leaf():
            return self.probability

        # if the split_val is int, this is a (binned) numerical feature, which is ordinal
        if isinstance(self.split_val, int):
            if feat_vector[self.split_feat] > self.split_val:
                return self.right.get_probability(feat_vector)
            return self.left.get_probability(feat_vector)
        # otherwise, its categorical feature, and its non-ordinal
        elif isinstance(self.split_val, set):
            if feat_vector[self.split_feat] not in self.split_val:
                return self.right.get_probability(feat_vector)
            return self.left.get_probability(feat_vector)
        raise ValueError("invalid split_val: {}".format(self.split_val))

    def feat_range(self, feat_idx):
        """
        takes a feature index and returns (int, int) which represents the range of potential
        values that this feature can take. in order to save memory, the full ranges of all
        features isn't stored at every node. instead, each child stores the range for the feature
        that its parent was split on. only the root stores ranges for every single feature.
        this makes sense because the ranges for a child differ from its direct parent only by
        a single feature. so, in order to do a lookup, you need to recursively check the parent
        until the root is reached.
        """
        if feat_idx in self.ranges:
            return self.ranges[feat_idx]
        if self.parent is None:
            raise ValueError("unable to find a range for feature: {}".format(feat_idx))
        return self.parent.feat_range(feat_idx)

    def find_node(self, id):
        """get a node by its ID. really only useful for debugging"""
        if self.id == id:
            return self
        if not self.is_leaf():
            return self.left.find_node(id) or self.right.find_node(id)

    def __str__(self):
        return self.to_str()

    def to_str(self, child_prefix="", desc_prefix=""):
        """prints a nice human-readable string"""
        if self.is_leaf():
            this_node_str = child_prefix + "Leaf(id={id}, n={n}, gini_impurity={gini_impurity}, probability={probability})".format(**self.__dict__)
            return this_node_str
        else:
            this_node_str = child_prefix + "TreeNode(id={id}, n={n}, gini_impurity={gini_impurity}, probability={probability}, split_feat={split_feat}, split_val={split_val})".format(**self.__dict__)
            return "\n".join((this_node_str, self.left.to_str(desc_prefix + "├──", desc_prefix + "│  "), self.right.to_str(desc_prefix + "└──", desc_prefix + "   ")))

class DecisionTreeBinaryClassifier:
    """
    Attributes:
        num_features: the number of features
        categorical_features_info: a dict that specifies which features are categorical (currectly unused).
            maps a feature index to the "arity" or the number of possible values. simply pass an empty dict
            if all features are numerical
        max_bins: the numerical features are quantized (binned). This is the maximum number of bins to use
        max_depth: the maximum number of levels to have on the tree
        min_per_node: splits will be pruned if it would create a node with `n` fewer than this
        feature_subset_strategy: "all" or "sqrt". The number of features to consider for splits at each tree node.
            this is useful if this tree will be part of a random forest
    """
    def __init__(self, num_features, categorical_features_info, max_bins=32, max_depth=10, min_per_node=1, feature_subset_strategy="all"):
        self.num_features = num_features
        self.categorical_features_info = categorical_features_info
        self.max_bins = max_bins
        self.max_depth = max_depth
        self.min_per_node = min_per_node
        self.feature_subset_strategy = feature_subset_strategy

    def train(self, dataRDD):
        """
        trains the model. takes an RDD of tuple (label, feature_vector). The label should be binary,
        and the feature_vector must be a sequence
        """
        # a generator for node IDs
        node_id_counter = count()

        # compute some preliminary statistics
        def seq_op(counts, row):
            label = row[0]
            counts[int(label)] += 1
            return counts
        comb_op = lambda counts1, counts2: [counts1[0] + counts2[0], counts1[1] + counts2[1]]
        label_counts = dataRDD.aggregate([0, 0], seq_op, comb_op)
        n, probability, gini = stats(label_counts)

        # sample the training data to find where the bins should be to quantize the numerical features
        fraction = sample_fraction_for_accurate_splits(n, self.max_bins)
        sample = dataRDD.sample(withReplacement=False, fraction=fraction)
        continuous_bins = sample.flatMap(partial(spread_row, self.categorical_features_info)) \
            .groupByKey() \
            .mapValues(partial(to_bins, self.max_bins)) \
            .collectAsMap()
        self.continuous_bins = continuous_bins
        treeRDD = dataRDD.map(lambda pair: (pair[0], discretize(continuous_bins, pair[1]))).persist()

        # initialize the decision tree
        tree_root = TreeNode(next(node_id_counter), n, gini, probability)
        # give every feature the full range
        tree_root.ranges = { i: set(range(self.categorical_features_info[i])) if i in self.categorical_features_info else (0, self.max_bins) for i in range(self.num_features) }
        self.tree_root = tree_root
        # grow the tree level-by-level. this holds the nodes to grow on the nexxt iteration
        frontier = [tree_root]
        depth = 0

        while len(frontier) > 0:
            category_stats = {}
            if len(self.categorical_features_info) > 0:
                category_stats = treeRDD.flatMap(partial(spread_categories, tree_root, self.categorical_features_info)) \
                    .reduceByKey(np.add) \
                    .mapValues(counts_to_prob) \
                    .map(shift_key(1)) \
                    .groupByKey() \
                    .mapValues(dict) \
                    .collect()
                category_stats = to_nested_dict(category_stats)

            # have the master determine which splits should be considered
            candidate_splits = {}
            for node in frontier:
                candidate_splits[node.id] = gen_candidate_splits(node, self.num_features, self.feature_subset_strategy, category_stats)
            # collect statistics about each of the proposed splits.
            # for each training example, take all the candidate splits and emit a key-value pair indicating
            # how that example would get classified. the key-value pair looks like this
            # (node-ID, feature-index, split-value): [[1, 0], [0, 0]]
            # then those classifications are reduced to add them up. so the values become [[negative-examples in left split, positive-examples in left split], [neg-ex in right split, pos-ex in right split]]
            # finally, the label counts are mapped to statistics in the form:
            # (node-ID, feature-index, split-value): (weighted_gini, (total_n_left, probability_positive_left, gini_left), (total_n_right, probability_positive_right, gini_right)
            statsRDD = treeRDD.flatMap(partial(split_statistics, tree_root, candidate_splits)) \
                .reduceByKey(result_adder) \
                .mapValues(to_gini)

            # find the best split for each node in the frontier (lowest gini impurity)
            # the key is converted from (node-ID, feature-index, split-value) to just node-ID
            # this allows us to reduce and get for each node ID only the split with the lowest gini impurity
            best_splits = statsRDD.map(shift_key_3_to_1) \
                .reduceByKey(get_purest_split) \
                .collectAsMap()

            # start collecting the new level of children for the next iteration
            new_frontier = []
            # for each node, do the best split we found
            for node in frontier:
                # bail on this iteration of no splits were found
                if node.id not in best_splits:
                    continue
                split_data = best_splits[node.id]
                (split_feat, split_val), _, (left_n, left_proba, left_gini), (right_n, right_proba, right_gini) = split_data
                # bail if there aren't enough data points to make the split
                if left_n < self.min_per_node or right_n < self.min_per_node:
                    continue

                # create the child nodes, and give them the correct ranges
                parent_range = node.feat_range(split_feat)
                left = TreeNode(next(node_id_counter), left_n, left_gini, left_proba)
                right = TreeNode(next(node_id_counter), right_n, right_gini, right_proba)
                if split_feat not in self.categorical_features_info:
                    left.ranges = { split_feat: (parent_range[0], split_val + 1) }
                    right.ranges = { split_feat: (split_val + 1, parent_range[1]) }
                    node.split(split_feat, split_val, left, right)
                else:
                    parent_range_list = sorted(parent_range, key=lambda el: category_stats[node.id][split_feat].get(el, 0))
                    split_val_set = set(parent_range_list[:split_val + 1])
                    left.ranges = { split_feat: split_val_set }
                    right.ranges = { split_feat: parent_range - split_val_set }
                    node.split(split_feat, split_val_set, left, right)
                # only add these to the frontier if they aren't homogenous
                if 0 < left.probability and left.probability < 1:
                    new_frontier.append(left)
                if 0 < right.probability and right.probability < 1:
                    new_frontier.append(right)

            depth += 1
            # bail if the depth exceeds the max
            if depth >= self.max_depth:
                frontier = []
            else:
                frontier = new_frontier

        # remove from cache before returning
        treeRDD.unpersist()

    def predict(self, dataRDD):
        """take a data point and get the probability of being in the positive class. only do this after training"""
        return dataRDD.map(partial(discretize, self.continuous_bins)) \
            .map(self.tree_root.get_probability)

def sample_fraction_for_accurate_splits(total_num_rows, max_bins):
    """
    determines how many rows to sample from the RDD in order to calculate the bins for discretizing continuous values
    uses same heuristic as Spark MLlib
    https://github.com/apache/spark/blob/ebd899b8a865395e6f1137163cb508086696879b/mllib/src/main/scala/org/apache/spark/ml/tree/impl/RandomForest.scala#L1168-L1177
    """
    required_samples = max(max_bins * max_bins, 10_000)
    if required_samples >= total_num_rows:
        return 1
    return required_samples / total_num_rows

def spread_row(categorical_features_info, row):
    """for use by flatMap to make a separate row for each feature, instead of one row per training example"""
    return [ (i, val) for i, val in enumerate(row[1]) if val != 0 and i not in categorical_features_info ]

def to_bins(max_bins, sample):
    """given a sample of values for a feature and calculates where the bins should be"""
    return np.quantile(list(sample), np.linspace(0, 1, max_bins + 1)[1:-1])

def discretize(bins, feat_vector):
    """maps a feature vector to the binned (discretized) version"""
    binned_feat_vector = []
    for i, val in enumerate(feat_vector):
        if i in bins:
            binned_feat_vector.append(to_discrete(val, bins[i]))
        else:
            binned_feat_vector.append(val)
    return binned_feat_vector

def spread_categories(tree_root, categorical_features_info, pair):
    label, feat_vector = pair
    node_assignment = tree_root.get_assigned_node_id(feat_vector)
    for i in categorical_features_info:
        yield (node_assignment, i, feat_vector[i]), [int(label == 0), int(label == 1)]

def counts_to_prob(counts):
    return (counts[1] / sum(counts),)

def shift_key(k):
    def wrapper(pair):
        tuple_key, tuple_data = pair
        return (tuple_key[:-k], tuple_key[-k:] + tuple_data)
    return wrapper

def to_nested_dict(tuple_key_pairs):
    nested_dict = defaultdict(lambda: defaultdict(dict))
    for pair in tuple_key_pairs:
        key, val = pair
        nested_dict[key[0]][key[1]] = val
    return dict(nested_dict)

def gen_candidate_splits(node, num_feats, feature_subset_strategy, category_stats):
    """generates the splits to consider. returns a dict that maps the feature index to feature values"""
    candidates = {}
    if feature_subset_strategy == "sqrt":
        loop_range = np.random.choice(num_feats, int(np.ceil(np.sqrt(num_feats))))
    elif feature_subset_strategy == "all":
        loop_range = range(num_feats)
    else:
        raise ValueError("invalid feature_subset_strategy: {}".format(feature_subset_strategy))
    for i in loop_range:
        # look up the range of potential values for this particular feature at this node. it might not be
        # the full range of values if we split on this feature already in a previous level.
        feat_range = node.feat_range(i)

        # if the range is a tuple (of length 2), its a numerical feature, and the tuple values are the start and end of the range
        if isinstance(feat_range, tuple) and feat_range[1] - feat_range[0] > 1:
            candidates[i] = feat_range
        # otherwise its a categorical feature
        elif isinstance(feat_range, set):
            candidates[i] = sorted(feat_range, key=lambda el: category_stats[node.id][i].get(el, 0))
    return candidates

def split_statistics(tree_root, candidate_splits, pair):
    """
    see which node a data point is assigned to, and see how the class assignments would be
    at each split we are considering. encodes the assignment as a nested list of length 2 each
    [[1, 0], [0, 0]] all zeros except for a 1. this means the example is negative and it was sent
    to the left split.
    """
    label, feat_vector = pair
    node_assignment = tree_root.get_assigned_node_id(feat_vector)
    # bail if we aren't trying to split the node this data point falls in.
    # happens if a node is homogenous or has too few examples
    if node_assignment not in candidate_splits:
        return []
    candidates_to_evaluate = candidate_splits[node_assignment]

    category_split = set()
    for feat_idx, split_vals in candidates_to_evaluate.items():
        # if the range is a tuple (of length 2), its a numerical feature, and the tuple values are the start and end of the range
        if isinstance(split_vals, tuple):
            for split_val in range(*split_vals):
                results = [[0, 0], [0, 0]]
                to_right = feat_vector[feat_idx] > split_val
                results[int(to_right)][int(label)] = 1
                yield (node_assignment, feat_idx, split_val), results
        # otherwise, its a list of category values that go into the left split
        elif isinstance(split_vals, list):
            for i, split_val in enumerate(split_vals):
                category_split.add(split_val)
                results = [[0, 0], [0, 0]]
                to_right = feat_vector[feat_idx] not in category_split
                results[int(to_right)][int(label)] = 1
                yield (node_assignment, feat_idx, i), results
        else:
            raise ValueError("invalid split_vals: {}".format(split_vals))

def result_adder(results1, results2):
    # just add up all the values per-split per-class
    return [[results1[0][0] + results2[0][0], results1[0][1] + results2[0][1]],
            [results1[1][0] + results2[1][0], results1[1][1] + results2[1][1]]]

def to_gini(results):
    """
    calculate the stats (including gini impurities for each split), along with the weighted average of gini impurities
    """
    results1, results2 = results
    stats1 = stats(results1)
    stats2 = stats(results2)
    if stats1[2] is np.inf or stats2[2] is np.inf:
        return np.inf, stats1, stats2
    total = stats1[0] + stats2[0]
    return stats1[0] / total * stats1[2] + stats2[0] / total * stats2[2], stats1, stats2

def shift_key_3_to_1(pair):
    """
    take a key-value pair where the key is a 3-tuple and convert to a single key.
    the other 2 former-keys get merged into the value
    """
    tuple_key, tuple_data = pair
    return (tuple_key[0], (tuple_key[1:],) + tuple_data)

def get_purest_split(data1, data2):
    """a reducer that just picks the smaller weighted gini impurity"""
    if data1[1] < data2[1]:
        return data1
    return data2


__author__ = 'Christian Donner'
__email__ = 'christian.donner(at)bccn-berlin.de'
__license__ = 'gpl-3.0'

import numpy
from pypolyagamma import PyPolyaGamma, pgdrawvpar
import time
from .basemeasures import BaseMeasure
from copy import copy
from scipy.linalg import solve_triangular

class GS_SGPD():
    """ Gibbs sampler for SGPD model.
    """

    def __init__(self, X, cov_params,
                 base_measure, lmbda=None, burnin=1000,
                 num_integration_points=1000, max_iterations=2000,
                 update_hyperparams=True, update_basemeasure=True, nthreads=1,
                 gp_mu=0, sample_hyperparams_iter=10):
        """ Initialises class of Gibbs sampler. Sampled data is saved in
        dictionary 'self.data'.

        The dictionary self.data contains all the sampled data. 'X' are the
        locations (observations and latent), 'g' the GP at these locations,
        'lmbda' the max rate of latent Poisson process, 'cov_params' the kernel
        parameters, 'M' the number of latent events, 'time' the time for
        samples, 'bm_params' the base measure parameters, 'gp_mu' the mean of
        the GP prior.

        :param X: Data.
        :type X: numpy.ndarray [instances x features]
        :param cov_params: Kernel hyperparameters. List with first entry the
        prefactor and second a D-dimensional array with length scales.
        :type cov_params: list
        :param base_measure:
        :type base_measure: BaseMeasure
        :param lmbda: Initial value for max. Poisson rate. If None
        it will be equal to number of data points. Default is None.
        :type lmbda: float
        :param burnin: Number of iteration before the posterior will be
        sampled. Default=1000.
        :type burnin: int
        :param num_integration_points: Number of integration points. Only
        used for predictive likelihood. Default=1000.
        :type num_integration_points: int
        :param max_iterations: Number of iterations the posterior is sampled.
        Default=2000.
        :type max_iterations: int
        :param update_hyperparams: Whether GP hyperparameters should be
        sampled. Default=True.
        :type update_hyperparams: bool
        :param update_basemeasure: Whether base measure parameters should be
        sampled. Can only be done for certain base measure ('normal',
        'laplace', 'standard_t'). Default=True.
        :type update_basemeasure: bool
        :param nthreads: Number of threads used for PG sampling. Default=1.
        :type nthreads: int
        :param gp_mu: Mean of GP prior.
        :type gp_mu: float
        :param sample_hyperparams_iter: Every x^th step hyperparameters are
        sampler. Default=0.
        :type sample_hyperparams_iter: float
        """
        self.max_iterations = int(max_iterations)
        self.D = X.shape[1]
        self.cov_params = cov_params
        self.X = X
        self.N = self.X.shape[0]
        self.base_measure = base_measure
        self.noise = 1e-4

        if lmbda is None:
            self.lmbda = self.N / 1.
        else:
            self.lmbda = lmbda
        seeds = numpy.random.randint(2 ** 16, size=nthreads)
        self.pg = [PyPolyaGamma(seed) for seed in seeds]
        self.M = int(self.lmbda)
        self.M_save = numpy.empty(self.max_iterations)
        # Position of all events (first N are the actual observed ones)
        self.X_all = numpy.empty([self.N+self.M, self.D])
        self.X_all[:self.N] = self.X
        self.X_all[self.N:] = base_measure.sample_density(self.M)
        self.marks = numpy.empty(self.N + self.M)
        self.K = self.cov_func(self.X_all,self.X_all)
        self.K += self.noise * numpy.eye(self.K.shape[0])
        self.L = numpy.linalg.cholesky(self.K)
        self.L_inv = solve_triangular(self.L, numpy.eye(self.L.shape[0]),
                                      lower=True,check_finite=False)
        self.K_inv = self.L_inv.T.dot(self.L_inv)
        self.gp_mu = gp_mu
        self.pred_log_likelihood = []
        self.g = numpy.zeros([self.N + self.M])
        # Probability of insertion or deletion proposal
        self.num_iterations = 0
        self.burnin = int(burnin)
        self.num_integration_points = num_integration_points
        self.place_integration_points()
        self.update_hyperparams = update_hyperparams
        self.update_basemeasure = update_basemeasure
        self.update_hyperparams_iter = sample_hyperparams_iter

        self.data = {'X':[], 'g':[], 'lmbda':[], 'cov_params':[], 'M':[],
                       'time': [], 'bm_params':[], 'gp_mu': []}

    def run(self):
        """ Runs initialised Gibbs sampler.
        """

        self.data['time'].append(time.perf_counter())

        for i in range(self.max_iterations + self.burnin):
            self.sample_marks()
            self.sample_g()
            if self.update_hyperparams and i % self.update_hyperparams_iter == 0:
                self.sample_kernel_params()
                self.sample_GP_mean_prior()
            if self.update_basemeasure and i % self.update_hyperparams_iter == 0:
                self.sample_basemeasure()
            if i % 100 == 0:
                print('%d Iterations of %d -- Currently %d latent events'
                      %(i, self.max_iterations+self.burnin, self.M))
            self.sample_lmbda()
            self.sample_latent_poisson()
            if i >= self.burnin:
                self.data['M'].append(numpy.copy(self.M))
                self.data['lmbda'].append(numpy.copy(self.lmbda))
                self.data['X'].append(numpy.copy(self.X_all))
                self.data['g'].append(numpy.copy(self.g))
                self.data['bm_params'].append(numpy.copy(
                    self.base_measure.params))
                self.data['cov_params'].append(copy(
                    self.cov_params))
                self.data['gp_mu'].append(self.gp_mu)
            self.data['time'].append(time.perf_counter())

    def sample_marks(self):
        """ Samples Polya-Gamma variables (at observed and latent events).

        :return:
        """
        self.marks = numpy.empty(self.N + self.M)
        pgdrawvpar(self.pg, numpy.ones(self.N + self.M), self.g, self.marks)

    def sample_g(self):
        """ Samples GP at Observations and latent events.

        :return:
        """
        Sigma_g_inv = numpy.diag(self.marks) + self.K_inv
        L_inv = numpy.linalg.cholesky(Sigma_g_inv)
        L = solve_triangular(L_inv, numpy.eye(L_inv.shape[0]), lower=True,
                             check_finite=False)
        Sigma_g = L.T.dot(L)
        u = numpy.empty(self.N + self.M)
        u[:self.N] = .5
        u[self.N:] = -.5
        mu_g = numpy.dot(Sigma_g, u + numpy.sum(self.K_inv*self.gp_mu, axis=0))
        self.g = mu_g + numpy.dot(L.T,numpy.random.randn(len(u)))

    def sample_lmbda(self):
        """ Samples lambda (max. intensity of Poisson process).

        :return:
        """

        alpha = self.N + self.M
        beta = 1.
        shape = 1./beta
        self.lmbda = numpy.random.gamma(alpha, shape)

    def sample_latent_poisson(self):
        """ Samples new latent Poisson process location via thinning.

        :return:
        """

        num_events = numpy.random.poisson(self.lmbda, 1)[0]
        X_unthinned = self.base_measure.sample_density(num_events)
        g_unthinned = self.sample_from_cond_GP(X_unthinned)
        inv_intensity = 1./(1. + numpy.exp(g_unthinned))
        rand_nums = numpy.random.rand(len(X_unthinned))
        thinned_idx = numpy.where(inv_intensity > rand_nums)[0]
        self.M = len(thinned_idx)
        self.X_all = numpy.empty([self.N + self.M, self.D])
        self.X_all[:self.N] = self.X
        self.X_all[self.N:] = X_unthinned[thinned_idx]
        g_X = self.g[:self.N]
        self.g = numpy.empty(self.N + self.M)
        self.g[:self.N] = g_X
        self.g[self.N:] = g_unthinned[thinned_idx]
        self.update_kernels()

    def cov_func(self, x, x_prime, only_diagonal=False, cov_params=None):
        """ Computes the covariance functions (squared exponential) between x
        and x_prime.

        :param x: Contains coordinates for points of x
        :type x: numpy.ndarray [num_points x D]
        :param x_prime: Contains coordinates for points of x_prime
        :type x_prime: numpy.ndarray [num_points_prime x D]
        :param only_diagonal: If true only diagonal is computed (Works only
        if x and x_prime are the same, Default=False)
        :type only_diagonal: bool

        :return: Kernel matrix.
        :rtype: numpy.ndarray [num_points x num_points_prime]

        """

        if cov_params is None:
            theta_1, theta_2 = self.cov_params[0], self.cov_params[1]
        else:
            theta_1, theta_2 = cov_params[0], cov_params[1]

        if only_diagonal:
            return theta_1*numpy.ones(x.shape[0])

        else:
            dx = numpy.subtract(x[:, None], x_prime[None])
            h = .5 * dx ** 2 / (theta_2[None,None]) ** 2
            return theta_1 * numpy.exp(- numpy.sum(h, axis=2))

    def update_kernels(self):
        """ Recalculates all kernel relevant parameters.

        :return:
        """
        self.K = self.cov_func(self.X_all, self.X_all)
        self.K += self.noise * numpy.eye(self.K.shape[0])
        self.L = numpy.linalg.cholesky(self.K)
        self.L_inv = solve_triangular(self.L, numpy.eye(self.L.shape[0]),
                         lower=True, check_finite=False)
        self.K_inv = self.L_inv.T.dot(self.L_inv)

    def sample_from_cond_GP(self, xprime):
        """ Samples GP conditioned on GP at observations and thinned events.

        :param xprime: Positions where GP should be sampled.
        :type xprime: numpy.ndarray [num_of_points x D]
        :return: GP values
        :rtype: numpy.ndarray [num_of_points]
        """

        k = self.cov_func(self.X_all, xprime)
        mean = self.gp_mu + k.T.dot(self.K_inv.dot(self.g - self.gp_mu))
        kprimeprime = self.cov_func(xprime, xprime)
        Sigma = (kprimeprime - k.T.dot(self.K_inv.dot(k)))
        Sigma += self.noise*numpy.eye(Sigma.shape[0])
        L = numpy.linalg.cholesky(Sigma)
        gprime = mean + numpy.dot(L.T,numpy.random.randn(xprime.shape[0]))
        return gprime

    def predictive_log_likelihood(self, X_test):
        """ Given test set, log test likelihood is sampled.

        :param X_test: Observations of test set.
        :type X_test: numpy.ndarray [num_of_points x D]

        :return: Returns the log mean likelihood
        :rtype: float
        """

        num_test_points = X_test.shape[0]
        test_log_likelihood = numpy.empty(self.max_iterations)
        for iiter in range(self.max_iterations):
            if iiter % 100 == 0:
                print('%d of %d Iterations' %(iiter, self.max_iterations))
            self.base_measure = BaseMeasure(self.D, self.base_measure.type,
                                            self.data['bm_params'][iiter])
            self.integration_points = self.base_measure.sample_density(
                self.num_integration_points)
            X = numpy.vstack([self.integration_points, X_test])
            log_base_measure = numpy.sum(numpy.log(
                self.base_measure.evaluate_density(X_test)))
            self.X_all = self.data['X'][iiter]
            self.g = self.data['g'][iiter]
            self.lmbda = self.data['lmbda'][iiter]
            if self.update_hyperparams:
                self.cov_params = self.data['cov_params'][iiter]
                self.gp_mu = self.data['gp_mu'][-1]
            self.update_kernels()
            g_sample = self.sample_from_cond_GP(X)
            integral = 1./(
                1. + numpy.exp(-g_sample[:self.num_integration_points]))
            log_denominator = num_test_points*numpy.log(numpy.mean(integral))
            log_nominator = log_base_measure - \
                            numpy.sum(numpy.log(1. + numpy.exp(
                                -g_sample[self.num_integration_points:])))
            test_log_likelihood[iiter] = log_nominator - log_denominator

        self._reset()
        mean_test_log_likelihood = numpy.log(numpy.mean(numpy.exp(
                test_log_likelihood - numpy.amax(test_log_likelihood)))) + \
                                   numpy.amax(test_log_likelihood)

        return mean_test_log_likelihood

    def predictive_posterior(self, X_grid, dx):
        """ Samples the mean predictive density.

        :param X_grid: The regular grid on the space, on which density is
        evaluated.
        :type X_grid: numpy.ndarray [num_grid_points x D]
        :param dx: Area of bins.
        :type dx: float

        :return: Sample mean density at grid points
        :rtype: numpy.ndarray [num_grid_points]
        """

        predictive_density = numpy.empty([X_grid.shape[0],
                                      self.max_iterations])
        for iiter in range(self.max_iterations):
            if iiter % 100 == 0:
                print('%d of %d Iterations' %(iiter, self.max_iterations))
            self.base_measure = BaseMeasure(self.D, self.base_measure.type,
                                            self.data['bm_params'][iiter])
            base_measure_grid = self.base_measure.evaluate_density(X_grid)
            self.X_all = self.data['X'][iiter]
            self.g = self.data['g'][iiter]
            self.lmbda = self.data['lmbda'][iiter]
            if self.update_hyperparams:
                self.cov_params = self.data['cov_params'][iiter]
                self.gp_mu = self.data['gp_mu'][iiter]
            self.update_kernels()
            g_pred = self.sample_from_cond_GP(X_grid)
            predictive_density[:,iiter] = self.lmbda * base_measure_grid / (
                1. + numpy.exp(-g_pred))

        predictive_density /= numpy.sum(predictive_density, axis=0)[None]*dx
        mean_density = numpy.mean(predictive_density, axis=1)

        self._reset()

        return mean_density

    def _reset(self):
        """ Resets the sampler to the last sample.

        :return:
        """
        self.M = self.data['M'][-1]
        self.lmbda = self.data['lmbda'][-1]
        self.X_all = self.data['X'][-1]
        self.g = self.data['g'][-1]

        if self.update_hyperparams:
            self.cov_params = self.data['cov_params'][-1]
            self.gp_mu = self.data['gp_mu'][-1]
        if self.update_basemeasure:
            self.base_measure = BaseMeasure(self.D, self.base_measure.type,
                                            self.data['bm_params'][-1])

    def place_integration_points(self):
        """ Places the integration points and updates all related kernels.

        :return:
        """
        self.integration_points = self.base_measure.sample_density(
            self.num_integration_points)

    def sample_basemeasure(self):
        """ Samples base measure parameters with Metropolis Algorithm.

        :return:
        """

        old_log_prob = numpy.sum(numpy.log(self.base_measure.evaluate_density(
            self.X_all)))
        proposed_base_measure = self._propose_new_basemeasure()
        new_log_prob = numpy.sum(
            numpy.log(proposed_base_measure.evaluate_density(self.X_all)))
        rand_log_num = numpy.log(numpy.random.rand(1))

        if rand_log_num < new_log_prob - old_log_prob:
            self.base_measure = proposed_base_measure

    def _propose_new_basemeasure(self):
        """ Proposals for Metropolis sampling.

        :return:
        """

        if self.base_measure.type is 'normal':
            old_log_params = numpy.log(self.base_measure.sigmas)
            new_log_params = old_log_params + .1*numpy.random.randn(self.D)
            new_params = numpy.exp(new_log_params)
        elif self.base_measure.type is 'laplace':
            old_log_params = numpy.log(self.base_measure.scale)
            new_log_params = old_log_params + .1*numpy.random.randn(self.D)
            new_params = numpy.exp(new_log_params)
        if self.base_measure.type is 'standard_t':
            old_log_params = numpy.log(self.base_measure.df - 1.)
            new_log_params = old_log_params + .1 * numpy.random.randn(
                self.D)
            new_params = numpy.exp(new_log_params) + 1.
        return BaseMeasure(self.D, params=new_params,
                           type=self.base_measure.type)

    def sample_GP_mean_prior(self):
        """ Samples mean of the GP prior.

        :return:
        """
        sigma_mu_gp = 1./numpy.sum(self.K_inv)
        mean_mu_gp = sigma_mu_gp*numpy.sum(self.K_inv.dot(self.g))
        self.gp_mu = mean_mu_gp + numpy.sqrt(sigma_mu_gp)*numpy.random.randn(1)

    def sample_kernel_params(self):
        """ Samples kernel parameters with Metropolis sampling.

        :return:
        """

        logp_old = self.compute_kernel_param_prop(self.K_inv, self.L)
        theta1 = numpy.exp(numpy.log(self.cov_params[0]) + .05 * \
                                                       numpy.random.randn(1))
        theta2 = numpy.exp(numpy.log(self.cov_params[1]) + .05 *
                           numpy.random.randn(self.D))
        K = self.cov_func(self.X_all, self.X_all, cov_params=[theta1, theta2])
        K += self.noise * numpy.eye(K.shape[0])
        L = numpy.linalg.cholesky(K)
        L_inv = solve_triangular(L, numpy.eye(L.shape[0]), lower=True,
                                 check_finite=False)
        K_inv = L_inv.T.dot(L_inv)
        logp_new = self.compute_kernel_param_prop(K_inv, L)
        rand_num_accept = numpy.random.rand(1)
        accept_p = numpy.exp(logp_new - logp_old)

        if rand_num_accept < accept_p:
            self.cov_params = [theta1, theta2]
            self.K = K
            self.L = L
            self.L_inv = L_inv
            self.K_inv = K_inv

    def compute_kernel_param_prop(self, K_inv, L):
        """ Computes the log probability (plus constant) given Kernel
        parameters.

        :param K_inv: Inverse kernel matrix.
        :type K_inv: numpy.ndarray [num_of_points x num_of_points]
        :param L: Cholesky decomposition of Kernel matrix.
        :type L: numpy.ndarray [num_of_points x num_of_points]
        :return: log probability plus constant
        :rtype: float
        """

        logp = -.5*(self.g.T - self.gp_mu).dot(
            K_inv.dot(self.g - self.gp_mu)) - \
            numpy.sum(numpy.log(L.diagonal()))
        return logp


from django.urls import path, include
from .views import LoginView, RegisterView, ListView
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)
urlpatterns = [
    path('register', RegisterView.as_view()),
    path('get-token', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('refresh-token', TokenRefreshView.as_view(), name='token_refresh'),
]


import os
import pytz
import time
import rrdtool
import logging
import datetime

from scalrpy.util import helper

LOG = logging.getLogger('ScalrPy')

SOURCE = {
    'cpu': [
        'DS:user:COUNTER:600:U:U',
        'DS:system:COUNTER:600:U:U',
        'DS:nice:COUNTER:600:U:U',
        'DS:idle:COUNTER:600:U:U',
        ],
    'la': [
        'DS:la1:GAUGE:600:U:U',
        'DS:la5:GAUGE:600:U:U',
        'DS:la15:GAUGE:600:U:U',
        ],
    'mem': [
        'DS:swap:GAUGE:600:U:U',
        'DS:swapavail:GAUGE:600:U:U',
        'DS:total:GAUGE:600:U:U',
        'DS:avail:GAUGE:600:U:U',
        'DS:free:GAUGE:600:U:U',
        'DS:shared:GAUGE:600:U:U',
        'DS:buffer:GAUGE:600:U:U',
        'DS:cached:GAUGE:600:U:U',
        ],
    'net': [
        'DS:in:COUNTER:600:U:21474836480',
        'DS:out:COUNTER:600:U:21474836480',
        ],
    'snum': [
        'DS:s_running:GAUGE:600:U:U'],
    'io': [
        'DS:read:COUNTER:600:U:U',
        'DS:write:COUNTER:600:U:U',
        'DS:rbyte:COUNTER:600:U:U',
        'DS:wbyte:COUNTER:600:U:U'],
    }

ARCHIVE = {
    'cpu': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    'la': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    'mem': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    'net': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    'snum': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    'io': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    }

GRAPH_OPT = {
    'daily':{
        'start':'-1d5min',
        'end':'-5min',
        'step':'180',
        'update_every':'600',
        'x_grid':'HOUR:1:HOUR:2:HOUR:2:0:%H',
        },
    'weekly':{
        'start':'-1wk5min',
        'end':'-5min',
        'step':'1800',
        'update_every':'7200',
        'x_grid':'HOUR:12:HOUR:24:HOUR:24:0:%a',
        },
    'monthly':{
        'start':'-1mon5min',
        'end':'-5min',
        'step':'7200',
        'update_every':'43200',
        'x_grid':'DAY:2:WEEK:1:WEEK:1:0:week %V',
        },
    'yearly':{
        'start':'-1y',
        'end':'-5min',
        'step':'86400',
        'update_every':'86400',
        'x_grid':'MONTH:1:MONTH:1:MONTH:1:0:%b',
        },
    }

def create_db(file_path, metric):
    if not os.path.exists(os.path.dirname(file_path)):
        os.makedirs(os.path.dirname(file_path))
    rrdtool.create(file_path, SOURCE[metric], ARCHIVE[metric])

def get_data_to_write(metric_name, metric_data):
    data_to_write = 'N'
    for source in SOURCE[metric_name]:
        data_type = {'COUNTER': int, 'GAUGE': float}[source.split(':')[2]]
        try:
            data_to_write += ':%s' % (data_type)(metric_data[source.split(':')[1]])
        except:
            data_to_write += ':U'
    return data_to_write

def update(file_path, data):
    LOG.debug('%s, %s, %s' % (time.time(), file_path, data))
    try:
        rrdtool.update(file_path, '--daemon', 'unix:/var/run/rrdcached.sock', data)
    except rrdtool.error:
        LOG.error('%s rrdtool update error: %s' % (file_path, helper.exc_info()))

def write(base_dir, data):
    try:
        for metric_name, metric_data in data.iteritems():
            if metric_name == 'snum':
                file_path = os.path.join(base_dir, 'SERVERS', 'db.rrd')
                if not os.path.isfile(file_path):
                    create_db(file_path, metric_name)
                data_to_write = get_data_to_write(metric_name, metric_data)
                update(file_path, data_to_write)
            elif metric_name == 'io':
                for device_name, device_data in metric_data.iteritems():
                    file_path = os.path.join(base_dir, 'IO', '%s.rrd' % device_name)
                    if not os.path.isfile(file_path):
                        create_db(file_path, metric_name)
                    data_to_write = get_data_to_write(metric_name, device_data)
                    update(file_path, data_to_write)
            else:
                name_upper = metric_name.upper()
                file_path = os.path.join(base_dir, '%sSNMP' % name_upper, 'db.rrd')
                if not os.path.isfile(file_path):
                    create_db(file_path, metric_name)
                data_to_write = get_data_to_write(metric_name, metric_data)
                update(file_path, data_to_write)
    except:
        LOG.error(helper.exc_info())

def plot_cpu(img_path, rrd_path, opt, tz=None):
    color_cpu_user_line = '#00DF00FF'
    color_cpu_user_area = '#00DF0044'
    color_cpu_syst_line = '#DF0000FF'
    color_cpu_syst_area = '#DF000044'
    color_cpu_nice_line = '#DFDF00FF'
    color_cpu_nice_area = '#DFDF0044'
    color_cpu_idle_line = '#0051AAFF'
    color_cpu_idle_area = '#0051AA22'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Percent CPU Utilization',
            '--title', 'CPU Utilization (%s)' % time_string,
            '--upper-limit', '100',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '160',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',
            'DEF:a=%s:user:AVERAGE' % rrd_path,
            'DEF:b=%s:system:AVERAGE' % rrd_path,
            'DEF:c=%s:nice:AVERAGE' % rrd_path,
            'DEF:d=%s:idle:AVERAGE' % rrd_path,
            'CDEF:total=a,b,c,d,+,+,+',
            'CDEF:a_perc=a,total,/,100,*',
            'VDEF:a_perc_last=a_perc,LAST',
            'VDEF:a_perc_avg=a_perc,AVERAGE',
            'VDEF:a_perc_max=a_perc,MAXIMUM',
            'CDEF:b_perc=b,total,/,100,*',
            'VDEF:b_perc_last=b_perc,LAST',
            'VDEF:b_perc_avg=b_perc,AVERAGE',
            'VDEF:b_perc_max=b_perc,MAXIMUM',
            'CDEF:c_perc=c,total,/,100,*',
            'VDEF:c_perc_last=c_perc,LAST',
            'VDEF:c_perc_avg=c_perc,AVERAGE',
            'VDEF:c_perc_max=c_perc,MAXIMUM',
            'CDEF:d_perc=d,total,/,100,*',
            'VDEF:d_perc_last=d_perc,LAST',
            'VDEF:d_perc_avg=d_perc,AVERAGE',
            'VDEF:d_perc_max=d_perc,MAXIMUM',

            'COMMENT:<tt>                Current   Average   Maximum</tt>\l',

            'LINE1:a_perc%s:<tt>user  </tt>\\t' % color_cpu_user_line,
            'AREA:a_perc%s:' % color_cpu_user_area,
            'GPRINT:a_perc_last:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:a_perc_avg:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:a_perc_max:<tt>%3.0lf%% </tt>\l',

            'LINE1:b_perc%s:<tt>system</tt>\\t' % color_cpu_syst_line,
            'AREA:b_perc%s:' % color_cpu_syst_area,
            'GPRINT:b_perc_last:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:b_perc_avg:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:b_perc_max:<tt>%3.0lf%% </tt>\l',

            'LINE1:c_perc%s:<tt>nice  </tt>\\t' % color_cpu_nice_line,
            'AREA:c_perc%s:' % color_cpu_nice_area,
            'GPRINT:c_perc_last:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:c_perc_avg:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:c_perc_max:<tt>%3.0lf%% </tt>\l',

            'LINE1:d_perc%s:<tt>idle  </tt>\\t' % color_cpu_idle_line,
            'AREA:d_perc%s:' % color_cpu_idle_area,
            'GPRINT:d_perc_last:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:d_perc_avg:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:d_perc_max:<tt>%3.0lf%% </tt>\l'
            )

def plot_la(img_path, rrd_path, opt, tz=None):
    color_la1_line  = '#CF0000FF'
    color_la1_area  = '#CF000030'
    color_la5_line  = '#0000CFFF'
    color_la5_area  = '#0000CF30'
    color_la15_line = '#00CF00FF'
    color_la15_area = '#00CF0030'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Load averages',
            '--title', 'Load averages (%s)' % time_string,
            '--lower-limit', '0',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--alt-y-grid',
            '--units-exponent', '0',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '140',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:la1=%s:la1:AVERAGE' % rrd_path,
            'DEF:la5=%s:la5:AVERAGE' % rrd_path,
            'DEF:la15=%s:la15:AVERAGE' % rrd_path,
            'VDEF:la1_min=la1,MINIMUM',
            'VDEF:la1_last=la1,LAST',
            'VDEF:la1_avg=la1,AVERAGE',
            'VDEF:la1_max=la1,MAXIMUM',
            'VDEF:la5_min=la5,MINIMUM',
            'VDEF:la5_last=la5,LAST',
            'VDEF:la5_avg=la5,AVERAGE',
            'VDEF:la5_max=la5,MAXIMUM',
            'VDEF:la15_min=la15,MINIMUM',
            'VDEF:la15_last=la15,LAST',
            'VDEF:la15_avg=la15,AVERAGE',
            'VDEF:la15_max=la15,MAXIMUM',

            'COMMENT:<tt>                            Minimum   Current    Average   Maximum</tt>\l',

            'LINE1:la15%s:<tt>15 Minutes system load   </tt>' % color_la15_line,
            'AREA:la15%s:' % color_la15_area,
            'GPRINT:la15_min:<tt>%3.2lf</tt>\\t',
            'GPRINT:la15_last:<tt>%3.2lf</tt>\\t',
            'GPRINT:la15_avg:<tt>%3.2lf</tt>\\t',
            'GPRINT:la15_max:<tt>%3.2lf</tt>\l',

            'LINE1:la5%s:<tt> 5 Minutes system load   </tt>' % color_la5_line,
            'AREA:la5%s:' % color_la5_area,
            'GPRINT:la5_min:<tt>%3.2lf</tt>\\t',
            'GPRINT:la5_last:<tt>%3.2lf</tt>\\t',
            'GPRINT:la5_avg:<tt>%3.2lf</tt>\\t',
            'GPRINT:la5_max:<tt>%3.2lf</tt>\l',

            'LINE1:la1%s:<tt> 1 Minute  system load   </tt>' % color_la1_line,
            'AREA:la1%s:' % color_la1_area,
            'GPRINT:la1_min:<tt>%3.2lf</tt>\\t',
            'GPRINT:la1_last:<tt>%3.2lf</tt>\\t',
            'GPRINT:la1_avg:<tt>%3.2lf</tt>\\t',
            'GPRINT:la1_max:<tt>%3.2lf</tt>\l'
            )

def plot_mem(img_path, rrd_path, opt, tz=None):
    color_mem_shrd = '#00FFFF'
    color_mem_buff_line = '#FF0000FF'
    color_mem_buff_area = '#FF000055'
    color_mem_cach_line = '#0000FFFF'
    color_mem_cach_area = '#0000FF30'
    color_mem_free_line = '#00CF00FF'
    color_mem_free_area = '#00CF0030'
    color_mem_swap_line = '#EFEF00FF'
    color_mem_swap_area = '#EFEF0030'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Memory Usage',
            '--title', 'Memory Usage (%s)' % time_string,
            '--lower-limit', '0',
            '--base', '1024',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '180',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:mem1=%s:swap:AVERAGE' % rrd_path,
            'DEF:mem2=%s:swapavail:AVERAGE' % rrd_path,
            'DEF:mem3=%s:total:AVERAGE' % rrd_path,
            'DEF:mem4=%s:avail:AVERAGE' % rrd_path,
            'DEF:mem5=%s:free:AVERAGE' % rrd_path,
            'DEF:mem6=%s:shared:AVERAGE' % rrd_path,
            'DEF:mem7=%s:buffer:AVERAGE' % rrd_path,
            'DEF:mem8=%s:cached:AVERAGE' % rrd_path,
            'CDEF:swap_total=mem1,1024,*',
            'VDEF:swap_total_min=swap_total,MINIMUM',
            'VDEF:swap_total_last=swap_total,LAST',
            'VDEF:swap_total_avg=swap_total,AVERAGE',
            'VDEF:swap_total_max=swap_total,MAXIMUM',
            'CDEF:swap_avail=mem2,1024,*',
            'VDEF:swap_avail_min=swap_avail,MINIMUM',
            'VDEF:swap_avail_last=swap_avail,LAST',
            'VDEF:swap_avail_avg=swap_avail,AVERAGE',
            'VDEF:swap_avail_max=swap_avail,MAXIMUM',
            'CDEF:swap_used=swap_total,swap_avail,-',
            'VDEF:swap_used_min=swap_used,MINIMUM',
            'VDEF:swap_used_last=swap_used,LAST',
            'VDEF:swap_used_avg=swap_used,AVERAGE',
            'VDEF:swap_used_max=swap_used,MAXIMUM',
            'CDEF:mem_total=mem3,1024,*',
            'VDEF:mem_total_min=mem_total,MINIMUM',
            'VDEF:mem_total_last=mem_total,LAST',
            'VDEF:mem_total_avg=mem_total,AVERAGE',
            'VDEF:mem_total_max=mem_total,MAXIMUM',
            'CDEF:mem_avail=mem4,1024,*',
            'VDEF:mem_avail_min=mem_avail,MINIMUM',
            'VDEF:mem_avail_last=mem_avail,LAST',
            'VDEF:mem_avail_avg=mem_avail,AVERAGE',
            'VDEF:mem_avail_max=mem_avail,MAXIMUM',
            'CDEF:mem_free=mem5,1024,*',
            'VDEF:mem_free_min=mem_free,MINIMUM',
            'VDEF:mem_free_last=mem_free,LAST',
            'VDEF:mem_free_avg=mem_free,AVERAGE',
            'VDEF:mem_free_max=mem_free,MAXIMUM',
            'CDEF:mem_shared=mem6,1024,*',
            'VDEF:mem_shared_min=mem_shared,MINIMUM',
            'VDEF:mem_shared_last=mem_shared,LAST',
            'VDEF:mem_shared_avg=mem_shared,AVERAGE',
            'VDEF:mem_shared_max=mem_shared,MAXIMUM',
            'CDEF:mem_buffer=mem7,1024,*',
            'VDEF:mem_buffer_min=mem_buffer,MINIMUM',
            'VDEF:mem_buffer_last=mem_buffer,LAST',
            'VDEF:mem_buffer_avg=mem_buffer,AVERAGE',
            'VDEF:mem_buffer_max=mem_buffer,MAXIMUM',
            'CDEF:mem_cached=mem8,1024,*',
            'VDEF:mem_cached_min=mem_cached,MINIMUM',
            'VDEF:mem_cached_last=mem_cached,LAST',
            'VDEF:mem_cached_avg=mem_cached,AVERAGE',
            'VDEF:mem_cached_max=mem_cached,MAXIMUM',

            'COMMENT:<tt>                  Minimum   Current    Average   Maximum</tt>\l',

            'LINE1:mem_shared%s:<tt>Shared        </tt>' % color_mem_shrd,
            'GPRINT:swap_total_min:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_total_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_total_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_total_max:<tt>%4.1lf%s</tt>\l',

            'LINE1:mem_buffer%s:<tt>Buffer        </tt>' % color_mem_buff_line,
            'AREA:mem_buffer%s:' % color_mem_buff_area,
            'GPRINT:mem_buffer_min:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_buffer_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_buffer_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_buffer_max:<tt>%4.1lf%s</tt>\l',

            'LINE1:mem_cached%s:<tt>Cached        </tt>' % color_mem_cach_line,
            'AREA:mem_cached%s:' % color_mem_cach_area,
            'GPRINT:mem_cached_min:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_cached_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_cached_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_cached_max:<tt>%4.1lf%s</tt>\l',

            'LINE1:mem_free%s:<tt>Free          </tt>' % color_mem_free_line,
            'AREA:mem_free%s:' % color_mem_free_area,
            'GPRINT:mem_free_min:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_free_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_free_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_free_max:<tt>%4.1lf%s</tt>\l',

            'LINE1:swap_used%s:<tt>Swap In Use   </tt>' % color_mem_swap_line,
            'AREA:swap_used%s:' % color_mem_swap_area,
            'GPRINT:swap_used_min:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_used_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_used_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_used_max:<tt>%4.1lf%s</tt>\l'
            )

def plot_net(img_path, rrd_path, opt, tz=None):
    color_ibound_line = '#CF0000FF'
    color_ibound_area = '#CF000030'
    color_obound_line = '#0000CFFF'
    color_obound_area = '#0000CF30'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Bits per second',
            '--title', 'Network usage (%s)' % time_string,
            '--lower-limit', '0',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '100',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:in=%s:in:AVERAGE' % rrd_path,
            'DEF:out=%s:out:AVERAGE' % rrd_path,
            'CDEF:in_bits=in,8,*',
            'CDEF:out_bits=out,8,*',
            'VDEF:in_last=in_bits,LAST',
            'VDEF:in_avg=in_bits,AVERAGE',
            'VDEF:in_max=in_bits,MAXIMUM',
            'VDEF:out_last=out_bits,LAST',
            'VDEF:out_avg=out_bits,AVERAGE',
            'VDEF:out_max=out_bits,MAXIMUM',

            'COMMENT:<tt>          Current   Average   Maximum</tt>\\l',

            'LINE1:in_bits%s:<tt>In    </tt>' % color_ibound_line,
            'AREA:in_bits%s:' % color_ibound_area,
            'GPRINT:in_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:in_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:in_max:<tt>%4.1lf%s</tt>\l',

            'LINE1:out_bits%s:<tt>Out   </tt>' % color_obound_line,
            'AREA:out_bits%s:' % color_obound_area,
            'GPRINT:out_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:out_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:out_max:<tt>%4.1lf%s</tt>\l'
            )

def plot_snum(img_path, rrd_path, opt, tz=None):
    color_running_servers_line = '#00CF00FF'
    color_running_servers_area = '#00CF0044'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Servers',
            '--title', 'Servers count (%s)' % time_string,
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--lower-limit', '0',
            '--y-grid', '1:1',
            '--units-exponent', '0',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '100',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:s_running=%s:s_running:AVERAGE' % rrd_path,
            'VDEF:s_running_last=s_running,LAST',
            'VDEF:s_running_avg=s_running,AVERAGE',
            'VDEF:s_running_max=s_running,MAXIMUM',
            'VDEF:s_running_min=s_running,MINIMUM',

            'COMMENT:<tt>                      Current    Average   Maximum   Minimum</tt>\l',

            'LINE1:s_running%s:<tt>Running servers    </tt>' % color_running_servers_line,
            'AREA:s_running%s:' % color_running_servers_area,
            'GPRINT:s_running_last:<tt>%3.0lf</tt>\\t',
            'GPRINT:s_running_avg:<tt>%3.0lf</tt>\\t',
            'GPRINT:s_running_max:<tt>%3.0lf</tt>\\t',
            'GPRINT:s_running_min:<tt>%3.0lf</tt>\l'
            )

def plot_io_bits(img_path, rrd_path, opt, tz=None):
    color_r = '#ff0000'
    color_w = '#0000ff'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Bits per second',
            '--title', 'Disk I/O (%s)' % time_string,
            '--lower-limit', '0',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '100',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:rbyte=%s:rbyte:AVERAGE' % rrd_path,
            'DEF:wbyte=%s:wbyte:AVERAGE' % rrd_path,
            'CDEF:rbits=rbyte,8,*',
            'CDEF:wbits=wbyte,8,*',
            'VDEF:rbits_last=rbits,LAST',
            'VDEF:rbits_avg=rbits,AVERAGE',
            'VDEF:rbits_max=rbits,MAXIMUM',
            'VDEF:wbits_last=wbits,LAST',
            'VDEF:wbits_avg=wbits,AVERAGE',
            'VDEF:wbits_max=wbits,MAXIMUM',

            'COMMENT:<tt>                Current    Average   Maximum</tt>\\l',

            'AREA:wbits%s:<tt>Write bits   </tt>' % color_w,
            'GPRINT:wbits_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:wbits_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:wbits_max:<tt>%4.1lf%s</tt>\l',

            'AREA:rbits%s:<tt>Read  bits   </tt>' % color_r,
            'GPRINT:rbits_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:rbits_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:rbits_max:<tt>%4.1lf%s</tt>\l'
            )

def plot_io_ops(img_path, rrd_path, opt, tz=None):
    color_r = '#ff0000'
    color_w = '#0000ff'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Operations per second',
            '--title', 'Disk I/O (%s)' % time_string,
            '--lower-limit', '0',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '100',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:read=%s:read:AVERAGE' % rrd_path,
            'DEF:write=%s:write:AVERAGE' % rrd_path,
            'VDEF:read_last=read,LAST',
            'VDEF:read_avg=read,AVERAGE',
            'VDEF:read_max=read,MAXIMUM',
            'VDEF:write_last=write,LAST',
            'VDEF:write_avg=write,AVERAGE',
            'VDEF:write_max=write,MAXIMUM',

            'COMMENT:<tt>             Current    Average   Maximum</tt>\\l',

            'AREA:write%s:<tt>Writes     </tt>' % color_w,
            'GPRINT:write_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:write_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:write_max:<tt>%4.1lf%s</tt>\l',

            'AREA:read%s:<tt>Reads     </tt>' % color_r,
            'GPRINT:read_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:read_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:read_max:<tt>%4.1lf%s</tt>\l'
            )


from map_helpers import parse_save_file, write_save_file, ascii_to_hex

import json

base_grimoires, base_hex = parse_save_file("backups/base")

with open("base.json", 'w') as out_file:
    json.dump(base_grimoires, out_file, indent=2)

# with open("override.json", 'r') as in_file:
#     override_grimoires = json.load(in_file)

## Test out the hex writing
counter = 0
names = ["Ali", "Doot", "Pew", "Raquna", "Simon", "Ricky", "Jack"]
for grim_data in base_grimoires:
    grim_data["name"] = names[counter]
    grim_data["name_hex"] = ascii_to_hex(names[counter])
    counter = (counter + 1) % len(names)

write_save_file(base_hex, base_grimoires)
# write_save_file(base_hex, override_grimoires)


import pandas as pd
from File import File
from docx import Document
import Utilities as ut

class DOCXFile(File):
  def __init__(self, path):
    super().__init__(path)
    self.read()

  def read(self):
    '''
    convert docx file contents to a list of strings
    '''
    f = open(self.path, 'rb')
    document = Document(f)
    contents = []
    for para in document.paragraphs:
      contents.append(para.text.strip())
    self.contents = ut.removeEmptyElements(contents)
    # self.contents = ut.removeNonASCIICharsList(contents)
    f.close()


# -*- coding: utf-8 -*-
import lxml.html as html
import urllib.request
import csv
from lxml import etree

FILENAME = 'iata.csv'
url = 'http://g-avia.ru/kody_gorodov_vseh_stran_'
my_dict = {}
content = urllib.request.urlopen(url).read()
doc = html.fromstring(content)
table = etree.HTML(html.tostring(doc.find_class('table1')[0]))
cities = table.getchildren()[0].getchildren()[0].getchildren()[0].getchildren()
for i in range(1, len(cities)):
    fields = cities[i].getchildren()
    if fields[5].text != ' ':
        iata = fields[5].text
        if fields[1].text != ' ':
            my_dict[fields[1].text] = iata
        if fields[2].text != ' ':
            my_dict[fields[2].text] = iata
print(my_dict)
with open(FILENAME, 'w', newline='') as file:
    writer = csv.DictWriter(file, fieldnames=['city', 'IATA'])
    writer.writeheader()
    for city in my_dict:
        writer.writerow({'city': city, 'IATA': my_dict[city]})
file.close()


import re
import os

RE_OUI = "([\da-f]{2}:){2}[\da-f]{2}$"
MANUFACTURERS = None

# To install manufacturer database: apt-get install libwireshark-data

def load():
    fh = open("/usr/share/wireshark/manuf")
    global MANUFACTURERS
    while True:
        line = fh.readline()
        if not line:
            break
        line = line.strip()
        if not line:
            continue
        if line.startswith("#"):
            continue

        oui, remainder = line.split("\t", 1)
        oui = oui.lower()
        if not re.match(RE_OUI, oui):
            continue
        if "#" in remainder:
            _, remainder = remainder.split("#", 1)
            remainder = remainder.strip()
        MANUFACTURERS[oui] = remainder

def get(hardware_address, fallback="Unknown"):
    if MANUFACTURERS == None:
        try:
            load()
        except OSError:
            MANUFACTURERS = {}
    return MANUFACTURERS.get(hardware_address[:8], fallback)


import sys
import math
sys.stdin = open("input.txt")

ordNumber,newNumber = input().split(" ")
newNumber= int(newNumber+ordNumber)
ordNumber = int(ordNumber)
arr = [0 for _ in range(newNumber+1)]
for i in range(2, int(math.sqrt(newNumber))+1):
    if(arr[i]):
        continue
    for j in range(2*i,newNumber+1,i):
        if(arr[j]):
            continue
        arr[j] = 1
if (arr[ordNumber] or arr[newNumber]):
    print("No")
else:
    print("Yes")


#!/usr/bin/env python
# ml_pipeline_27/tests/test_parse_input_data.py
import unittest
import json
import copy
#from data_handling.input_args_handler import parse_input_data
from data_handling.input_args_handler_fg import parse_input_data

class TestParse_input_data(unittest.TestCase):
    """ Unit Testing /data_handling/input_args_handler:parse_input_data """

    # prepare test
    def setUp(self):
        """ Setup for test, instantiate object / cycle method(s) for test object creation """
        print("TestParse_input_data:setup_:begin")
        # Instantiate instances/values from classes/functions being tested
        test_input = {"training_file": "/ml_pipeline_27/unit_testing/dummy_value1.csv",
                      "file_for_testing": "/ml_pipeline_27/unit_testing/dummy_value2.csv",
                      "model_name": "ml_pipeline_27_unit_testing_dummy_value",
                      "model_path": "/ml_pipeline_27/unit_testing/dummy_path1",
                      "output_json_path": "/ml_pipeline_27/unit_testing/dummy_path2",
                      "csv_accuracy_report_path": "/ml_pipeline_27/unit_testing/dummy_path3",
                      "category": "SHAVING_PRODUCTS",
                      "country": "UK",
                      "target_global_char": "GLOBAL_BRAND_1",
                      "predicted_results_path": "/ml_pipeline_27/unit_testing/dummy_path4",
                      "test_train_split": "50"
                      }
        json_input_raw = json.dumps(test_input)
        self.validate_output = copy.deepcopy(test_input)
        self.test_output = parse_input_data(json_input_raw)
        print("TestParse_input_data:setup_:end")

    # ending test
    def tearDown(self):
        """ Post-test cleanup """
        # Do something based on test complexity/objectives/options
        print("TestParse_input_data:tearDown_")

    def test_parse_input_data(self):
        """ Test parse_input_data function """
        self.assertEqual(first=self.validate_output['training_file'],
                         second=self.test_output['training_file_path'], msg=None)
        self.assertEqual(first=self.validate_output['csv_accuracy_report_path'],
                         second=self.test_output['accuracy_output_path'], msg=None)
        self.assertEqual(first=0.0,
                         second=self.test_output['test_percentage'], msg=None)

    # @unittest.skip("Skip over integrity test")
    def test_parse_input_data_integrity(self):
        """ Testing parse_input_data returns a dictionary """
        self.assertTrue(isinstance(self.test_output, dict))


#ipv6 shortener by Thomas Cascais Nisterenko

ADDRESS_LENGTH = 39
HEX = "0123456789ABCDEFabcdef"
ZERO = 0
ONE = 1
TWO = 2
FIVE = 5

def is_valid_address(ip_address):
    chars_seen = ZERO
    if len(ip_address) != ADDRESS_LENGTH:
        return False

    for char in ip_address:
        chars_seen += ONE

        if not (chars_seen % FIVE):
            if char != ":":
                return False
        else:
            if char not in HEX:
                return False
    return True

def split_address(ip_address):
    ip_address_lst = ip_address.split(":")
    return ip_address_lst

def remove_leading_zeroes(ip_address_lst):
    i = ZERO
    while i < len(ip_address_lst):
        if ip_address_lst[i] == "0000":
            ip_address_lst[i] = "0"
        else:
            ip_address_lst[i] = ip_address_lst[i].lstrip("0")
        i += ONE

    return ip_address_lst

def zero_sequence(ip_address_lst_no_leading):
    seq_len = ZERO
    i = ZERO
    start, end = ZERO, ZERO
    longest = ONE
    sequences = []
    while i < len(ip_address_lst_no_leading):
        if ip_address_lst_no_leading[i] == "0":
            if not seq_len:
                start = i
            else:
                end = i
            seq_len += ONE
        else:
            seq_len = ZERO
            if end - start >= longest:
                longest = end - start
                sequences.append((start, end))
        i += ONE

    if end - start >= longest:
        longest = end - start
        sequences.append((start, end))

    seq_lengths = [end - start for (start, end) in sequences]

    if not sequences:
        return (-ONE, -ONE)
    return sequences[seq_lengths.index(max(seq_lengths))]

def remove_zero_sequence(ip_address_lst, zero_sequence):
    if zero_sequence == (-ONE, -ONE):
        return ip_address_lst
    else:
        start, end = zero_sequence
        ip_address_lst = ip_address_lst[:start] + [""] + ip_address_lst[end + ONE:]

    return ip_address_lst

def merge_address_lst(shortened_address_lst):
    short_address = ":".join(shortened_address_lst)
    if not short_address:
        return "::"
    if shortened_address_lst[ZERO] == "":
        short_address = ":" + short_address
    elif shortened_address_lst[-ONE] == "":
        short_address += ":"
    return short_address

def shorten_ip_address():
    valid = False
    while not valid:
        ip_address = input("Please provide a valid, full-length IPv6 address> ")
        valid = is_valid_address(ip_address)

    ip_address_lst = split_address(ip_address)
    no_leading = remove_leading_zeroes(ip_address_lst)
    sequence = zero_sequence(no_leading)
    short_lst = remove_zero_sequence(no_leading, sequence)
    shortened_address = merge_address_lst(short_lst)

    print()
    print("Full address>", ip_address)
    print("Shortened address>", shortened_address)
    print()

def main():
    print("Welcome to the IPv6 address shortener in python!\n")
    quit = False
    while not quit:
        shorten_ip_address()
        usr_choice = input("Press 'q' to quit, press any other key to run the shortener again> ")
        print()
        if usr_choice.lower() == "q":
            quit = True
    print("Goodbye!")

if __name__ == "__main__":
    main()


from os import name
from core.views import actualizartema, agregarcapacitacion, agregartema, buscar, capacitaciones, cargar_anexos, cargar_asistencia, cargar_invitados, cerrar, cerrar_hito, eliminar_adjunto, eliminar_adjunto_capacitacion, eliminar_adjunto_hito, eliminar_asistente, eliminar_capa, eliminar_hito, eliminar_invitado_capacitacion, eliminar_tema, index, login, temas, ver_hito, ver_invitados_hitos, vercapacitacion, vertema
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('', index, name='index'),
    path('temas', temas, name='temas'),
    path('agregartema', agregartema, name='agregartema'),
    path('login', login, name='login'),
    path('cerrar', cerrar, name='cerrar'),
    path('tema/<int:id>', vertema, name='tema'),
    path('actualizartema', actualizartema, name='actualizartema'),
    path('tema/eliminar_tema', eliminar_tema, name='eliminartema'),
    path('eliminar_capa', eliminar_capa, name='eliminarcapa'),
    path('capacitacion/eliminar_capa',
         eliminar_capa, name='eliminarcapacitacion'),
    path('tema/eliminar_adjunto', eliminar_adjunto, name='eliminaradjunto'),
    path('capacitacion/eliminar_adjunto_capa',
         eliminar_adjunto_capacitacion, name='eliminaraadjunto'),
    path('invitadoshitos/eliminar_invitado',
         eliminar_invitado_capacitacion, name='eliminarinvitado'),
    path('buscar', buscar, name='buscar'),
    path('agregarcapacitacion', agregarcapacitacion, name='agregarcapacitacion'),
    path('capacitaciones', capacitaciones, name='capacitaciones'),
    path('capacitacion/<int:id>', vercapacitacion, name='capacitacion'),
    path('invitadoshitos/hito/<int:id>', ver_hito, name='verhito'),
    path('cargarinvitados', cargar_invitados, name="cargarinvitados"),
    path('cargarasistencia', cargar_asistencia, name="cargarasistencia"),
    path('cargaranexos', cargar_anexos, name="cargaranexos"),
    path('invitadoshitos/<int:id>', ver_invitados_hitos,
         name='detalle_capacitacion'),
    path('invitadoshitos/hito/eliminar_adjunto_hito',
         eliminar_adjunto_hito, name='eliminaradjuntohito'),
    path('invitadoshitos/hito/eliminar_hito',
         eliminar_hito, name='eliminarhito'),
    path('invitadoshitos/hito/cerrar_hito',
         cerrar_hito, name='cerrarhito'),
    path('invitadoshitos/hito/eliminar_asistente',
         eliminar_asistente, name='eliminarasistente')
]


from collections import deque
from sys import stdin

deq = deque()
commands = []
answer = []

def push_back(value):
    deq.append(value)

def push_front(value):
    deq.appendleft(value)

def pop_front():
    if(deq):
        answer.append(deq.popleft())
    else:
        answer.append(-1)

def pop_back():
    if(deq):
        answer.append(deq.pop())
    else:
        answer.append(-1)

def front():
    if(deq):
        answer.append(deq[0])
    else:
        answer.append(-1)

def back():
    if(deq):
        answer.append(deq[-1])
    else:
        answer.append(-1)

def size():
    answer.append(len(deq))

def empty():
    if(deq):
        answer.append(0)
    else:
        answer.append(1)

n = int(stdin.readline())

for i in range(n):
    command = list(stdin.readline().split())
    commands.append(command)

for i in range(n):
    if(commands[i][0] == "push_back"):
        push_back(int(commands[i][1]))
    elif(commands[i][0] == "push_front"):
        push_front(int(commands[i][1]))
    elif(commands[i][0] == "pop_front"):
        pop_front()
    elif(commands[i][0] == "pop_back"):
        pop_back()
    elif(commands[i][0] == "size"):
        size()
    elif(commands[i][0] == "empty"):
        empty()
    elif(commands[i][0] == "front"):
        front()
    elif(commands[i][0] == "back"):
        back()

for i in range(len(answer)):
    print(answer[i])


#reverse a string
def reverseString(str1):
    return str1[::-1]

def reverseString2(str1):
    strList = list(str1)
    strList.reverse()
    revStr = "".join(strList)
    return revStr

def reverseString3(str1):
    revStr = ""
    for c in str1:
        revStr = c + revStr
    return revStr

def reverseString4(str1):
    revStr = ""
    for c in reversed(str1):
        revStr += c
    return revStr

#reverse the word order
def reverseString5(str1):
    strList = str1.split(" ")
    strList.reverse()
    return " ".join(strList)

print(reverseString("mother"))
print(reverseString2("hello"))
print(reverseString3("backwards"))
print(reverseString4("again"))
print(reverseString5("what the heck"))


"""The following functions are all intended to check whether a string contains any lowercase
letters, but at least some of them are wrong. For each function, describe what the
function actually does (assuming that the parameter is a string)."""

def any_lowercase1(s):
    """If there is at least one lower case, return True,
    elif the case are all upper cases, return False"""
    for c in s:
        if c.islower():
            return True
    else:
        return False
# test
# print(any_lowercase1('Hello'))

def any_lowercase2(s):
    """The answer is always 'True', because string 'c' is a lower letter """
    for c in s:
        if 'c'.islower():
            return 'True'
    else:
        return 'False'
# test
# print(any_lowercase2('HELLO'))

def any_lowercase3(s):
    """Only check the first case whether it is a lower letter,
    'return' stops the for loop"""
    for c in s:
        flag = c.islower()
        return flag

# test
# print(any_lowercase3("hELLO"))
# print(any_lowercase3("Hello"))

def any_lowercase4(s):
    """If the first letter is upper case, it is False. elif the first letter is lower case, it is True.
    While there are multiple letters, if there is at least a lower letter follows the upper letter, it is True.
    if there is at least two upper letters follows the lower letter, it is False"""
    flag = False
    for c in s:
        flag = flag or c.islower()
    return flag

# test
# print(any_lowercase4("h")) # False or True is True
# print(any_lowercase4("H")) # False or False is False
# print(any_lowercase4("Hello")) # True or True is True

def any_lowercase5(s):
    """If there is at least a upper letter, return False, if always lower cases, return true"""
    for c in s:
        if not c.islower(): # to check all if it is upper
            return False
    return True
# test
# print(any_lowercase4("HELLO"))
# print(any_lowercase4("He"))


import click
import cv2
import os
import torch
import tqdm

from utils import get_test_dataset_function

from detectron2 import model_zoo
from detectron2.data import DatasetCatalog, MetadataCatalog
from detectron2.utils.visualizer import Visualizer
from detectron2.engine import DefaultPredictor
from detectron2.config import get_cfg

def save_labelme_json(image_path, output_path, predictions):
    # Get the image dimensions
    image = cv2.imread(image_path)
    height, width, _ = image.shape

    # Create the JSON dictionary
    json_dict = {
        "version": "4.5.6",
        "flags": {},
        "shapes": [],
        "imagePath": os.path.basename(image_path),
        "imageData": None,
        "imageHeight": height,
        "imageWidth": width
    }

    # Add the shapes
    for prediction in predictions:
        class_name = prediction["class_name"]
        bbox = prediction["bbox"]
        xmin, ymin, xmax, ymax, angle = bbox

        shape_dict = {
            "label": class_name,
            "points": [
                [xmin, ymin],
                [xmax, ymax]
            ],
            "group_id": None,
            "shape_type": "rectangle",
            "flags": {}
        }
        json_dict["shapes"].append(shape_dict)

    # Save the JSON file
    json_path = os.path.join(output_path, os.path.basename(image_path).replace(".jpg", ".json"))
    with open(json_path, "wt") as f:
        json.dump(json_dict, f, indent=2)

    print(f"Saved {json_path}")

def convert_jpgs_to_video(jpg_folder, output_video_path, fps):
    # Get the list of JPG files in the folder
    jpg_files = [f for f in os.listdir(jpg_folder) if (f.endswith('.jpg') or f.endswith('.png'))]

    # Sort the files in ascending order
    jpg_files.sort()

    # Get the first image dimensions
    first_image = cv2.imread(os.path.join(jpg_folder, jpg_files[0]))
    height, width, _ = first_image.shape

    # Initialize the video writer
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')  # Use appropriate codec (e.g., 'XVID', 'MJPG')
    video_writer = cv2.VideoWriter(output_video_path, fourcc, fps, (width, height))

    # Write each image to the video writer
    for jpg_file in jpg_files:
        image_path = os.path.join(jpg_folder, jpg_file)
        image = cv2.imread(image_path)
        video_writer.write(image)

    # Release the video writer
    video_writer.release()

    print("Video created successfully.")

@click.command()
@click.argument('directory', nargs=1)
@click.option('--weights', default="model_final.pth", help='Path to the model to use')
def main(directory, weights):
    class_labels = ['Balls', 'Bottlebrush', 'Branching 3D', 'Colonial', 'Crustaceans', 'Cups', 'Fan 2D', 'Feather stars', 'Hydrocorals', 'Mushroom', 'Other', 'Other anemones', 'Pale', 'Prawns / Shrimps / Mysids', 'Sea cucumbers', 'Sea stars', 'Spider crabs', 'Squat lobsters', 'Stalked', 'Three-dimensional branching', 'True crabs', 'Tube-like forms', 'Two-dimensional lamellate', 'Unbranched', 'Yellow', 'biogenic + sediment', 'biogenic rubble', 'coral rubble', 'lost+found', 'rubble', 'volcanic', 'volcanic + sediment', 'volcanic, sediment + biogenic rubble']

    color_palette = {
        'Balls': (15, 78, 117),
        'Bottlebrush': (48, 170, 121),
        'Branching 3D': (180, 82, 205),
        'Colonial': (211, 54, 130),
        'Crustaceans': (223, 123, 48),
        'Cups': (255, 190, 11),
        'Fan 2D': (38, 186, 133),
        'Feather stars': (97, 60, 123),
        'Hydrocorals': (236, 84, 50),
        'Mushroom': (115, 50, 82),
        'Other': (179, 162, 199),
        'Other anemones': (82, 122, 173),
        'Pale': (242, 184, 149),
        'Prawns / Shrimps / Mysids': (205, 48, 135),
        'Sea cucumbers': (113, 197, 199),
        'Sea stars': (242, 130, 43),
        'Spider crabs': (24, 99, 143),
        'Squat lobsters': (147, 188, 71),
        'Stalked': (245, 209, 66),
        'Three-dimensional branching': (92, 146, 87),
        'True crabs': (211, 65, 36),
        'Tube-like forms': (38, 101, 153),
        'Two-dimensional lamellate': (162, 209, 73),
        'Unbranched': (242, 166, 50),
        'Yellow': (255, 235, 59),
        'biogenic + sediment': (63, 81, 125),
        'biogenic rubble': (194, 205, 230),
        'coral rubble': (147, 178, 204),
        'lost+found': (122, 96, 161),
        'rubble': (206, 152, 232),
        'volcanic': (226, 128, 64),
        'volcanic + sediment': (83, 98, 103),
        'volcanic, sediment + biogenic rubble': (226, 158, 74)
    }

    dataset_name = "dive8file4"

    dataset_function = get_test_dataset_function(directory)
    MetadataCatalog.get(dataset_name).thing_classes = class_labels
    MetadataCatalog.get(dataset_name).thing_colors = {
        i: color_palette[k] for i, k in enumerate(class_labels)
    }

    DatasetCatalog.register(dataset_name, dataset_function)
    metadata = MetadataCatalog.get(dataset_name)

    cfg = get_cfg()
    cfg.merge_from_file(model_zoo.get_config_file(
        "COCO-Detection/faster_rcnn_X_101_32x8d_FPN_3x.yaml"))  # Base model
    # cfg.merge_from_file(model_zoo.get_config_file(
    #     "COCO-Detection/faster_rcnn_R_50_FPN_3x.yaml"))  # Base model

    # Rotated bbox specific config in the same directory as this file
    cfg.merge_from_file(os.path.join(os.path.dirname(
        os.path.abspath(__file__)), "rotated_bbox_config.yaml"))
    cfg.DATASETS.TRAIN = (dataset_name,)
    cfg.DATASETS.TEST = (dataset_name,)
    cfg.MODEL.ROI_HEADS.NUM_CLASSES = len(class_labels)

    cfg.MODEL.WEIGHTS = weights
    cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.1  # Preiction confidence threshold,
    cfg.MODEL.ROI_HEADS.NMS_THRESH_TEST = 0.05

    predictor = DefaultPredictor(cfg)
    iteration = torch.load(weights)["iteration"]
    output_dir = os.path.join(directory, "predictions", f"{iteration:06d}")
    os.makedirs(output_dir, exist_ok=True)
    for i, d in enumerate(tqdm.tqdm(dataset_function())):
        img = cv2.imread(d["file_name"])
        outputs = predictor(img)

        # Save predictions in labelme format

        v = Visualizer(img[:, :, ::-1], metadata, scale=1.0)
        out = v.draw_instance_predictions(outputs["instances"].to("cpu"))
        # cv2.imshow("Predictions", out.get_image()[:, :, ::-1])

        cv2.imwrite(f"{output_dir}/{d['id']}.jpg", out.get_image()[:, :, ::-1])
        # cv2.waitKey(1000)

    root_directory_name = os.path.basename(os.path.normpath(directory))
    convert_jpgs_to_video(output_dir, os.path.join(output_dir, f"{root_directory_name}.mp4"), 5)

if __name__ == "__main__":
    main()


from django.contrib.auth.models import User

def get_user_permissions(data):
    navList = []
    for i in range(len(data)):
        if "生产" in data[i]:
            navList.append('produced')
            navList.append('onsiteDash')
        # if '配置缺件' in data[i]:
        #     navList.append('plans')
        if '报工平台' in data[i]:
            navList.append('report')
        if '班组长' in data[i]:
            navList.append('reporAnalysis')
            navList.append('onsiteDash')
            navList.append('produced')

    navList = list(set(navList))
    navList.sort(reverse=True)
    return navList

def get_update_list(data):

    update_list = {}
    for i in range(len(data)):
        #生产制造
        if 'produced' in data[i]:
            update_list['produced']='生产制造'
        #配置缺件
        if 'plans' in data[i]:
            update_list['shortage']='配置缺件'

    return update_list

def get_all_logs(logs):
    list_logs=[]
    for i in range(len(logs)):
        a={}
        a['date']=logs[i].action_time.strftime("%Y-%m-%d %H:%M:%S")
        a['message'] = logs[i].change_message
        a['object'] = logs[i].object_repr
        a['id'] = User.objects.get(id=logs[i].user_id).username
        list_logs.append(a)
    return list_logs


import sys
from collections import deque

r, c=map(int, sys.stdin.readline().strip().split())
maze=[list(input()) for _ in range(r)]
hQueue, fQueue=deque(), deque()
dx, dy=[1, -1, 0, 0], [0, 0, 1, -1]
hGraph, fGraph=[[0]*c for _ in range(r)], [[0]*c for _ in range(r)]

# 지훈이와 불 위치 확인
for i in range(r):
    for j in range(c):
        if maze[i][j]=='F':
            fQueue.append((i, j))

        elif maze[i][j]=='J':
            hQueue.append((i, j))

def bfs():
    # 불에 대해 BFS
    while fQueue:
        x, y=fQueue.popleft()
        for i in range(4):
            nx=x+dx[i]
            ny=y+dy[i]
            # 좌표를 벗어나지 않았고 / 벽이 아니고 / 불이 아직 번지지 않음 == 불이 나야할 곳
            if 0<=nx<r and 0<=ny<c:
                if maze[nx][ny]!='#' and fGraph[nx][ny]==0:
                    fGraph[nx][ny]=fGraph[x][y]+1
                    fQueue.append((nx, ny))

    # 지훈이 BFS
    while hQueue:
        x, y=hQueue.popleft()
        for i in range(4):
            nx=x+dx[i]
            ny=y+dy[i]
            # 좌표 안 벗어남 == 아직 탈출 못함
            if 0<=nx<r and 0<=ny<c:
                # 벽이 아니고 / 불이 나지 않았거나 / 아직 가지 않은 곳 == 이동할 수 있는곳
                # 불이 번지는 데 걸린 시간 보다 먼저 도달할 수 있는 곳
                # --> 이동할 수 있는 곳
                if maze[nx][ny]!='#' and hGraph[nx][ny]==0:
                    if fGraph[nx][ny]==0 or fGraph[nx][ny]>hGraph[x][y]+1:
                        hGraph[nx][ny]=hGraph[x][y]+1
                        hQueue.append((nx, ny))
            # 좌표를 벗어남 == 탈출!
            else:
                return hGraph[x][y]+1

    # 이동할 수 있는 경우의 수를 모두 시도 했으나 (= 큐가 빔)
    # 좌표를 벗어나지 못함
    return 'IMPOSSIBLE'

print(bfs())


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 28 12:33:00 2022

@author: poire
"""
import tkinter as tk

def show_entry_fields():
    Pil_tot = str(int(Pil_av) + int(Pil_ar))
    print("Immat: %s\nMasse pilotes totale: %s" % (Planeur_input.get(), Pil_tot.get()))

T77 = [398, -1.140, -0.011, 0.685] #[Poids à vide (kg), bras de levier pilote avant(m), bras de levier pilote arrière(mm), bras de levier CG vide]
T41 = [409, -1.140, -0.011, 0.71265]
JI = [409, -1.350, -0.270, 0.783]
LK = [412.8, -1.350, -0.270, 0.803]
PAP = [310, -5, 10]
C4 = [310, -5, 10]
Planeur_list = [T77, T41, JI, LK, PAP, C4]
Planeur_list_str = ["T77", "T41", "JI", "LK", "PAP", "C4"]

# Top level window
frame = tk.Tk()
frame.title("Masse et Centrage BUNO")
frame.config(bg = 'gray50')
#frame.geometry('400x200')
#Immat planeur
tk.Label(frame, text="Entrez l'immat concours du planeur :").grid(row=0)
Planeur_input = tk.Entry(frame)
Planeur_input.grid(row=0, column=1)
#Poids pil avant
tk.Label(frame, text="Masse du pilote avant en kilos :").grid(row=1)
Pil_av = tk.Entry(frame)
Pil_av.grid(row=1, column=1)
#Poids pil arriere
tk.Label(frame, text="Masse du pilote arrière en kilos (0 si  pas de pilote arrière):").grid(row=2)
Pil_ar = tk.Entry(frame)
Pil_ar.grid(row=2, column=1)

tk.Button(frame,
            text='Quitter',
            command=frame.quit).grid(row=3,
                                    column=0,
                                    sticky=tk.W,
                                    pady=4)
tk.Button(frame,
            text='Calculer',
            command=show_entry_fields).grid(row=3,
                                    column=1,
                                    sticky=tk.W,
                                    pady=4)

frame.mainloop()
#("Entrez l'immat concours du planeur :")

#Pil_av = int(input ("Masse du pilote avant en kilos :"))
#Pil_ar = int(input ("Masse du pilote arrière en kilos (0 si  pas de pilote arrière):"))
#pl_index = Planeur_list_str.index(Planeur_input)
#Masse = Planeur_list[pl_index][0] + Pil_av + Pil_ar
#Moment = Planeur_list[pl_index][1]*Pil_av + Planeur_list[pl_index][2]*Pil_ar + Planeur_list[pl_index][3]*Planeur_list[pl_index][0]
#CG = round(Moment/Masse, 4)*1000
#print("Centre de gravité en mm:", CG)


import datetime
from django.db import models

class Institution(models.Model):
    name = models.CharField(max_length=256)
    owner = models.ForeignKey('kid_auth.User', on_delete=models.CASCADE)
    address = models.ForeignKey('Address', on_delete=models.CASCADE)

    def child_in_institution_today(self, date=datetime.datetime.today()):
        in_inst = 0
        out_inst = 0
        none_inst = 0
        for child in self.children_set.all():
            in_inst += 1 if child.presence_on_day(date) else 0
            out_inst += 1 if not child.presence_on_day(date) else 0
            none_inst += 1 if child.presence_on_day(date) is None else 0

        return {'in_inst': in_inst, 'out_inst': out_inst, 'none_inst': none_inst}

class ChildrenGroup(models.Model):
    name = models.CharField(max_length=256)

class Address(models.Model):
    street = models.CharField(max_length=256)
    zip_code = models.CharField(max_length=10)
    town = models.CharField(max_length=64)

class Children(models.Model):
    class Meta:
        ordering = ['last_name']

    first_name = models.CharField(max_length=128)
    last_name = models.CharField(max_length=128)

    mother_inv = models.OneToOneField('kid_auth.ParentInvitation', related_name='mother_inv', null=True,
                                      on_delete=models.SET_NULL)
    father_inv = models.OneToOneField('kid_auth.ParentInvitation', related_name='father_inv', null=True,
                                      on_delete=models.SET_NULL)

    mother = models.OneToOneField('kid_auth.User', related_name='mother', on_delete=models.CASCADE, null=True)
    father = models.OneToOneField('kid_auth.User', related_name='father', on_delete=models.CASCADE, null=True)

    groups = models.ForeignKey(ChildrenGroup, on_delete=models.SET_NULL, null=True)
    institution = models.ForeignKey(Institution, on_delete=models.CASCADE)

    def __str__(self):
        return self.first_name + ' ' + self.last_name

    def presence_today(self):
        presence = self.presences_set.filter(date=datetime.date.today()).first()
        return presence.is_present if presence else None

    def presence_on_day(self, date=datetime.datetime.today()):
        presence = self.presences_set.filter(date=date)
        return presence.first().is_present if presence else None

    def is_girl(self):
        return self.first_name[-1] == 'a'

    def is_parent(self, user):
        return 'mother' if self.mother == user else 'father' if self.father == user else None

class Presences(models.Model):
    children = models.ForeignKey(Children, on_delete=models.CASCADE)
    date = models.DateField()
    is_present = models.NullBooleanField()

class Message(models.Model):
    date = models.DateTimeField(auto_now_add=True)
    children = models.ForeignKey(Children, on_delete=models.CASCADE)
    sender = models.ForeignKey('kid_auth.User', on_delete=models.CASCADE)
    text = models.TextField()


# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
from pandas import Series, DataFrame
import matplotlib
from matplotlib import style
style.use('ggplot')
'''
 SVC 简单小例子.
    重点  SVM 的直线结果 各参数解释.
    How svm works
Created on April , 2015
@author: stevey
@python love love love, you can make your best.!!
'''

x = [1,5, 1.5, 8, 1.9]
y = [2, 8, 1.8, 0.6, 11]

# plt.plot(x, y)
# plt.scatter(x, y)

x = np.array([ [1,2],
            [5, 8],
            [1.5, 1.8],
            [8, 8],
            [1, 0.6],
            [9, 11]])
y = [0,1, 0,1,0, 1]
# create classfier
from sklearn import svm
clf = svm.SVC(kernel='linear', C=1.0)
clf.fit(x, y)
print(clf.predict([ 0.58, 0.76])) # 0 it locates in small area.

w = clf.coef_[0]
print(w)

# graphs
a = -w[0] / w[1]
xx = np.linspace(0, 12)
yy = a * xx - clf.intercept_[0] / w[1]

h0 = plt.plot(xx, yy, 'k-', label='non weighted div')
plt.scatter(x[:, 0], x[:, 1], c=y)
plt.legend()
plt.show()


import requests

res = requests.get('https://automatetheboringstuff.com/files/rj.txt')

try:
	res.raise_for_status()

	playFile = open('RomeoAndJuliet.txt', 'wb')
	for chunk in res.iter_content(100000):
		playFile.write(chunk)
	playFile.close()

except Exception as e:
	print('Error encountered:', e)


"""Aprimore o desafio 93 para que ele funcione com vários jogadores,
incluindo um sistema de visualização de detalhes do aproveitamento de cada jogador."""
time = []
jogador = {}
gols = []

while True:
    jogador.clear()
    jogador['nome'] = input('Nome do jogador: ').title().strip()
    partidas = int(input(f'Quantas partidas {jogador["nome"]} jogou? '))
    gols.clear()
    for i in range(0, partidas):
        gols.append(int(input(f'  Quantos gols na partida {i+1}? ')))
    jogador['gols'] = gols[:]
    jogador['total'] = sum(gols)
    time.append(jogador.copy())
    while True:
        opcao = input('Deseja continuar? [S/N] ').strip().upper()[0]
        if opcao in 'SN':
            break
        print('Opção invalida!! Informe Sim ou Não [S/N]')
    if opcao == 'N':
        break

print('-' *40)
print('Cod  ', end= '')
for i in jogador.keys():
    print(f'{i:<15}', end='')
print()
print('-' * 40)
for k, v in enumerate(time):
    print(f'{k:>3}  ', end='')
    for d in v.values():
        print(f'{str(d):<15}', end='')
    print()
print('-' * 40)
while True:
    busca = int(input('Mostrar dados de qual jogador? (999 p/ parar) '))
    if busca == 999:
        break
    if busca > len(time):
        print(f'ERRO! Não existe jogador de código {busca}!')
    else:
        print(f'--- LEVATAMENTO DO JOGADOR {time[busca]["nome"]} ---')
        for p, g in enumerate(time[busca]['gols']):
            print(f'    No jogo {p+1} fez {g} gols.')
    print('-' * 40)
print('<< FIM >>')

Curso de Python 3 - Mundo 3 - Curso em Video/ex095.py