import pandas as pd
import copy
import viz
import numpy as np
import sklearn.linear_model as lm
import evaluation
import features
import features.prep
import trees
from matplotlib import pyplot as plt
import classifier
import seaborn as sns
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.tree._tree import TREE_LEAF
from sklearn.tree import _tree

pd.set_option('display.max_columns',30)

if __name__ == '__main__':
    data = pd.read_csv("../data/housing.csv",sep=";")
    #print(data.head())
    data = features.prep.dropnans_newidx(data)
    #print(data.shape)
    data = features.prep.convert_cats(data,"ocean_proximity")

    #####################
    data = data.sample(1000)
    #data = data[["latitude","longitude","median_income","median_house_value"]]
    ###################

    train_X, val_X, test_X, train_y, val_y, test_y = features.prep.split_train_val_test(data, "median_house_value",[0.6,0.2,0.2])
    #print(train_X.shape)
    #print(val_X.shape)
    #print(test_X.shape)
    # train_X, test_X, train_y, test_y = features.prep.split_train_test(data, "median_house_value")
    # scaling is not necessary for decision trees
    small_dTree = DecisionTreeRegressor(max_depth=2)
    small_dTree.fit(train_X[["median_income"]], train_y)
    small_dTree_pred = small_dTree.predict(train_X[["median_income"]])
    trees.tree_to_code(small_dTree, ['median_income'])
    print(f" feature: {small_dTree.tree_.feature}")
    print(f" child left: {small_dTree.tree_.children_left}")
    print(f" child left idx 4: {small_dTree.tree_.children_left[4]}")
    print(f" child right: {small_dTree.tree_.children_right}")
    print(f" tree value idx 2: {small_dTree.tree_.value[2]}")
    print(f" ")
    rss = np.sum((train_y - small_dTree_pred) ** 2)
    print(f" rss: {rss}")
    thresh_node = small_dTree.tree_.threshold[1]
    samples_in_leaves = small_dTree.apply(train_X[["median_income"]]) # gibt pro Zeile die Zugehörigkeit zum terminal node aus
    print(samples_in_leaves)
    print(pd.value_counts((samples_in_leaves)))
    #use impurity measure?
    print(small_dTree.tree_.children_left[2])
    print(f" child left idx 2: {small_dTree.tree_.children_left[2]}")
    print(f" tree leaf: {_tree.TREE_LEAF}")
    trees.depth_first(small_dTree.tree_, 0)
    print(f" node count: {small_dTree.tree_.node_count}") # total nr of nodes
    print(f" node impurity idx 0: {small_dTree.tree_.impurity[0]}")
    print(f" impurity * n samples at idx 0: {small_dTree.tree_.impurity[0]*small_dTree.tree_.n_node_samples[0]}")
    rss_mean = np.sum((train_y - np.mean(train_y))**2)
    print(f" pred error of mean: {rss_mean}")
    print(f" n node samples idx 2: {small_dTree.tree_.n_node_samples[2]}")

    print(f" n node samples idx 1: {small_dTree.tree_.n_node_samples[1]}")
    print(f" n node samples idx 3: {small_dTree.tree_.n_node_samples[3]}")

    # finding alpha --> best subtree from pruning

    dTree = DecisionTreeRegressor(min_samples_leaf=3)
    dTree.fit(train_X, train_y)

    tree_array = [dTree]

    num_nodes = dTree.tree_.capacity
    index = 0
    alpha = 0
    k = 1

    alpha_array = [alpha]
    num_nodes_array = [num_nodes]

    while num_nodes > 1:
        tree_array.append(copy.deepcopy(tree_array[k - 1]))

        min_node_idx, min_gk = trees.determine_alpha(tree_array[k].tree_)
        alpha_array.append(min_gk)
        trees.prune(tree_array[k].tree_, min_node_idx)

        num_nodes = sum(1 * (tree_array[k].tree_.n_node_samples != 0))
        num_nodes_array.append(num_nodes)
        k += 1
    print("alpha array:")
    print(alpha_array)

    error_rates = pd.DataFrame(columns=["tree", "MSE", "RMSE", "R2", "RMSE % of mean", "Cali"])
    error_rates_tr = pd.DataFrame(columns=["tree", "MSE", "RMSE", "R2", "RMSE % of mean", "Cali"])

    for t in tree_array:
        pred = t.predict(val_X)
        pred_training = t.predict(train_X)
        idx = tree_array.index(t)
        new_row = pd.concat([pd.Series(idx,name="tree"),evaluation.save_errors(val_y, pred)],axis=1)
        new_row_tr = pd.concat([pd.Series(idx,name="tree"),evaluation.save_errors(train_y, pred_training)],axis=1)
        error_rates = error_rates.append(new_row,sort=False)
        error_rates_tr = error_rates_tr.append(new_row_tr,sort=False)

    print("sorted error rates for val:\n")
    err_sorted = error_rates.sort_values(["R2","RMSE"],ascending=[False,True])
    print(err_sorted)
    best_tree_nr = err_sorted.iloc[0,0]
    best_tree = tree_array[best_tree_nr]

    fig2, axes2 = plt.subplots(3,2,figsize=(10,12))
    ax2 = axes2.flatten()
    for col in error_rates.iloc[:,1:6].columns.values:
        axnr = error_rates.columns.get_loc(col) -1
        ax2[axnr].set_title(col)
        ax2[axnr].scatter(alpha_array, error_rates[col],label="val")
        ax2[axnr].scatter(alpha_array, error_rates_tr[col],label="train")
        ax2[axnr].legend()
        ax2[axnr].set_xlim([0, 0.6e+12])
        ax2[axnr].set_xlabel("alpha")
    fig2.tight_layout()
    a = viz.ScrollableWindow(fig2)

    fig3, axes3 = plt.subplots(3, 2, figsize=(10, 12))
    ax3 = axes3.flatten()
    for col in error_rates.iloc[:, 1:6].columns.values:
        axnr = error_rates.columns.get_loc(col) - 1
        ax3[axnr].set_title(col)
        ax3[axnr].set_xlabel("subtree")
        ax3[axnr].scatter(error_rates["tree"],error_rates[col],label="val")
        ax3[axnr].scatter(error_rates_tr["tree"], error_rates_tr[col],label="train")
        ax3[axnr].legend()

    fig3.tight_layout()
    b = viz.ScrollableWindow(fig3)

    random_dTree = RandomForestRegressor(min_samples_leaf=3)
    random_dTree.fit(train_X, train_y)
    rand_pred_val = random_dTree.predict(val_X)
    rand_pred_tr = random_dTree.predict(train_X)
    rand_error_rates_val = pd.DataFrame(columns=["type", "MSE", "RMSE", "R2", "RMSE % of mean", "Cali"])
    rand_error_rates_tr = pd.DataFrame(columns=["type", "MSE", "RMSE", "R2", "RMSE % of mean", "Cali"])

    rand_new_row = pd.concat([pd.Series("val",name="type"),evaluation.save_errors(val_y, rand_pred_val)],axis=1)
    rand_new_row_tr = pd.concat([pd.Series("train",name="type"),evaluation.save_errors(train_y, rand_pred_tr)],axis=1)
    rand_error_rates = rand_error_rates_val.append(rand_new_row,sort=False)
    rand_error_rates_tr = rand_error_rates_tr.append(rand_new_row_tr,sort=False)
    print("pruned error rates val:")
    print(error_rates.loc[error_rates["tree"] == best_tree_nr,:])
    print("pruned error rates train:")
    print(error_rates_tr.loc[error_rates["tree"] == best_tree_nr,:])
    print("rand error rates val:")
    print(rand_error_rates)
    print("rand error rates train:")
    print(rand_error_rates_tr)

    fig5, axes5 = plt.subplots(3, 2, figsize=(10, 12))
    ax5 = axes5.flatten()
    for col in error_rates.iloc[:, 1:6].columns.values:
        axnr = error_rates.columns.get_loc(col) - 1
        ax5[axnr].set_title(col)
        ax5[axnr].set_xlabel("subtree")
        ax5[axnr].scatter("pruned",error_rates.loc[error_rates["tree"] == best_tree_nr,col],label="pruned val")
        ax5[axnr].scatter("pruned", error_rates_tr.loc[error_rates["tree"] == best_tree_nr,col],label="pruned train")
        ax5[axnr].scatter("rand", rand_error_rates[col], label="rand val")
        ax5[axnr].scatter("rand", rand_error_rates_tr[col], label="rand train")

        ax5[axnr].legend()

    fig5.tight_layout()
    b = viz.ScrollableWindow(fig5)

"""
    fig4, axes4 = plt.subplots(3, 2, figsize=(10, 12))
    ax4 = axes4.flatten()
    for col in error_rates.iloc[:, 1:6].columns.values:
        axnr = error_rates.columns.get_loc(col) - 1
        ax4[axnr].set_title(col)
        ax4[axnr].set_xlabel("num nodes")
        ax4[axnr].scatter(num_nodes_array,error_rates[col])

    fig4.tight_layout()
    c = viz.ScrollableWindow(fig4)

    #dForest = RandomForestRegressor(max_depth=max_depth, n_estimators=n_estimators)

    fig, axes = plt.subplots(10,2,figsize=(10, 30))
    ax = axes.flatten()
    ax[0].set_title('Real Test Values')
    ax[0].scatter(x=test_X['longitude'], y=test_X['latitude'], c=test_y, s=10, cmap='hot');
    error_rates = pd.DataFrame(columns =["max_depth","MSE","RMSE","R2","RMSE % of mean","Cali"])

    for max_depth in range(1,20):
        dTree = DecisionTreeRegressor(max_depth=max_depth)
        dTree.fit(train_X, train_y)
        pred = dTree.predict(test_X)
        title = "Tree Prediction for max_depth = " + str(max_depth)
        ax[max_depth].set_title(title)
        ax[max_depth].scatter(x=test_X['longitude'], y=test_X['latitude'], c=pred, s=10, cmap='hot');
        new_row = pd.concat([pd.Series(max_depth,name="max_depth"),evaluation.save_errors(test_y, pred)],axis=1)
        error_rates = error_rates.append(new_row,sort=False)
    fig.tight_layout()
    a = viz.ScrollableWindow(fig)
    print(error_rates)
    plt.close("all")

    fig2, axes2 = plt.subplots(3,2,figsize=(10,12))
    ax2 = axes2.flatten()
    for col in error_rates.iloc[:,1:6].columns.values:
        axnr = error_rates.columns.get_loc(col) -1
        ax2[axnr].set_title(col)
        ax2[axnr].set_xlabel("max_depth")
        ax2[axnr].plot(error_rates["max_depth"],error_rates[col])

    fig2.tight_layout()
    b = viz.ScrollableWindow(fig2)
    #plt.show()
    plt.close('all')
    """


from torch import nn

from ..builder import RECOGNIZERS
from .base import BaseRecognizer

@RECOGNIZERS.register_module()
class Recognizer2D(BaseRecognizer):
    """2D recognizer model framework."""

    def forward_train(self, imgs, label, **kwargs):
        """Defines the computation performed at every call when training."""

        assert self.with_cls_head
        batches = imgs.shape[0]
        imgs = imgs.reshape((-1, ) + imgs.shape[2:])
        num_segs = imgs.shape[0] // batches

        losses = dict()

        x = self.extract_feat(imgs)
        x = x.reshape((batches, num_segs) + x.shape[1:])

        cls_score = self.cls_head(x)
        gt_label = label.squeeze()
        loss_cls = self.cls_head.loss(cls_score, gt_label, **kwargs)
        losses.update(loss_cls)

        return losses

    def forward_test(self, imgs, **kwargs):
        """Defines the computation performed at every call when evaluation and testing."""
        batches = imgs.shape[0]
        imgs = imgs.reshape((-1, ) + imgs.shape[2:])

        x = self.extract_feat(imgs)
        assert 'num_segs' in self.test_cfg
        num_segs = self.test_cfg['num_segs']
        assert x.shape[0] % (batches * num_segs) == 0
        num_crops = x.shape[0] // (batches * num_segs)

        if self.test_cfg.get('feat_ext', False):
            # perform spatial pooling
            avg_pool = nn.AdaptiveAvgPool2d(1)
            x = avg_pool(x)
            # squeeze dimensions
            x = x.reshape((batches, num_crops, num_segs, -1))
            # temporal average pooling
            x = x.mean(axis=1).mean(axis=1)
            return x.cpu().numpy()

        x = x.reshape((batches * num_crops, num_segs) + x.shape[1:])
        cls_score = self.cls_head(x)
        cls_score = cls_score.reshape(batches, num_crops, cls_score.shape[-1])
        # calculate num_crops automatically
        cls_score = self.average_clip(cls_score)
        return cls_score.cpu().numpy()


import os
from collections import Counter
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from wordcloud import WordCloud

java_path = "C:/Program Files/Java/jdk1.8.0_161/bin/java.exe"
os.environ['JAVAHOME'] = java_path

def exploratory_data_analysis(df):
    print("exploratory_data_analysis")
    print("Number of reviews:", len(df))

    # Score Distribution
    ax = plt.axes()
    sns.countplot(df.score, ax=ax)
    ax.set_title('Score Distribution')
    plt.show()

    print("Average Score: ", np.mean(df.score))
    print("Median Score: ", np.median(df.score))

    # creo un nuovo attributo opinion
    # negative = review(1-3), positive=(4-5)
    df.ix[df.score == 3, 'opinion'] = "neutral"
    df.ix[df.score > 3, 'opinion'] = "positive"
    df.ix[df.score < 3, 'opinion'] = "negative"

    ## opinion distribution
    ax = plt.axes()
    sns.countplot(df.opinion, ax=ax)
    ax.set_title('Sentiment Positive vs Negative Distribution')
    plt.show()

    ## userid distribution
    # ax = plt.axes()
    # sns.countplot(df.userid, ax=ax)
    # ax.set_title('UserId Distribution')
    # plt.show()
    #
    # ## productid distribution
    # ax = plt.axes()
    # sns.countplot(df.userid, ax=ax)
    # ax.set_title('ProductId Distribution')
    # plt.show()

    print("Proportion of positive review:", len(df[df.opinion == "positive"]) / len(df))
    print("Proportion of neutral review:", len(df[df.opinion == "neutral"]) / len(df))
    print("Proportion of negative review:", len(df[df.opinion == "negative"]) / len(df))
    # 77% of the fine food reviews are considered as positive
    # and 23% of them are considered as negative.

    reviews = df.text.values
    labels = df.opinion.values

    ### TEXT REVIEWS ###

    if df.opinion[1] == "positive":
        print("positive" + "\t" + reviews[1][:90] + "...")
    else:
        print("negative" + "\t " + reviews[1][:90] + "...")

    ### Exploratory Visualization ###
    # mi creo un vocabolario di parole positive e negative

    positive_reviews = [reviews[i] for i in range(len(reviews)) if labels[i] == "positive"]
    negative_reviews = [reviews[i] for i in range(len(reviews)) if labels[i] == "negative"]

    ### positive
    cnt_positve = Counter()

    for row in positive_reviews:
        cnt_positve.update(row.split(" "))
    print("Vocabulary size for positve reviews:", len(cnt_positve.keys()))

    ### negative
    cnt_negative = Counter()

    for row in negative_reviews:
        cnt_negative.update(row.split(" "))
    print("Vocabulary size for positve reviews:", len(cnt_negative.keys()))

    cnt_total = Counter()

    for row in reviews:
        cnt_total.update(row.split(" "))

    pos_neg_ratio = Counter()
    vocab_pos_neg = (set(cnt_positve.keys())).intersection(set(cnt_negative.keys()))
    for word in vocab_pos_neg:
        if cnt_total[word] > 100:
            ratio = cnt_positve[word] / float(cnt_negative[word] + 1)
            if ratio > 1:
                pos_neg_ratio[word] = np.log(ratio)
            else:
                pos_neg_ratio[word] = -np.log(1 / (ratio + 0.01))

    positive_dict = {}
    for word, cnt in pos_neg_ratio.items():
        if (cnt > 1):
            positive_dict[word] = cnt

    #### positive WORDCLOUD #####
    # wordcloud = WordCloud()
    # wordcloud.generate_from_frequencies(frequencies=positive_dict)
    #
    # plt.figure(figsize=(10, 10))
    # plt.imshow(wordcloud, interpolation="bilinear")
    # plt.axis("off")
    # ax = plt.axes()
    # ax.set_title('Word Cloud with the Highest Positive/Negative Ratio')
    # plt.show()

    negative_dict = {}
    for word, cnt in pos_neg_ratio.items():
        if (cnt < 1) & (cnt > 0):
            negative_dict[word] = -np.log(cnt)

    #### negative WORDCLOUD #####
    wordcloud = WordCloud(background_color='black',
                          width=2500,
                          height=2000)
    wordcloud.generate_from_frequencies(frequencies=negative_dict)
    plt.figure(figsize=(10, 10))
    plt.imshow(wordcloud, interpolation="bilinear")
    plt.axis("off")
    ax = plt.axes()
    ax.set_title('Word Cloud with the Lowest Positive/Negative Ratio')
    plt.show()

    print("END EXPLORATORY ANALYSIS")

# vocabulary reduction function to reduce
# the vocabulary based on min frequency or polarity.
def vocabulary_reduction(reviews, labels, min_freq=10, polarity_cut_off=0.1):
    pos_count = Counter()
    neg_count = Counter()
    tot_count = Counter()

    for i in range(len(reviews)):
        for word in reviews[i].split():
            tot_count[word] += 1
            if labels[i] == 1:
                pos_count[word] += 1
            else:
                neg_count[word] += 1

                # Identify words with frequency greater than min_freq
    vocab_freq = []
    for word in tot_count.keys():
        if tot_count[word] > min_freq:
            vocab_freq.append(word)

            # Use polarity to reduce vocab
    pos_neg_ratio = Counter()
    vocab_pos_neg = (set(pos_count.keys())).intersection(set(neg_count.keys()))
    for word in vocab_pos_neg:
        if tot_count[word] > 100:
            ratio = pos_count[word] / float(neg_count[word] + 1)
            if ratio > 1:
                pos_neg_ratio[word] = np.log(ratio)
            else:
                pos_neg_ratio[word] = -np.log(1 / (ratio + 0.01))

    mean_ratio = np.mean(list(pos_neg_ratio.values()))

    vocab_polarity = []
    for word in pos_neg_ratio.keys():
        if (pos_neg_ratio[word] < (mean_ratio - polarity_cut_off)) or (
                pos_neg_ratio[word] > (mean_ratio + polarity_cut_off)):
            vocab_polarity.append(word)

    vocab_rm_polarity = set(pos_neg_ratio.keys()).difference(vocab_polarity)
    vocab_reduced = (set(vocab_freq)).difference(set(vocab_rm_polarity))

    reviews_cleaned = []

    for review in reviews:
        review_temp = [word for word in review.split() if word in vocab_reduced]
        reviews_cleaned.append(' '.join(review_temp))

    return reviews_cleaned

if __name__ == "__main__":
    df = pd.read_csv("Dataset/food.tsv", sep="\t", encoding='latin-1')

    # recensioni negative
    df = df.loc[df['score'] == (1 or 2)]
    df = df.groupby('productid').agg(['mean', 'count'])

    print("ciao")

    asd = df.groupby('productid').score.mean().reset_index()
    asd2 = df.productid.value_counts()
    asd3 = asd.merge(asd2.to_frame(), left_on='productid', right_index=True)
    asd4 = asd3.sort_values('score')
    df1 = df.loc[df['productid'] == "B001E96JY2"]

    # df = pd.read_csv("cleanedTextCSV.csv", sep="\t", encoding='latin-1')
    exploratory_data_analysis(df)
    # data_preprocessing(df)
    # df_train = df = df.loc[df['productid'] == "B000DZFMEQ"]
    # df_test = df[201:250]
    # # aspect_based(df_train, df_test)
    # aspect2(df_train, df_test)


x = 10
x = 'a'
try:
    print(x)
except NameError:
    print("variable does not exists! try checking variable name!")
except:
    print("Something went wrong!")
else:
    print("Things went well!")
finally:
    print("try-except block finished!")

# we can also manually throw an exception
if (type(x) is not int):
    raise Exception("x should be a integer number!")
if (x < 0):
    raise Exception("x cannot be negative!")


import string
import random
from Bio.SubsMat import MatrixInfo

aminoacid_list = "ARNDCEQGHILKMFPSTWYV"

aminoacid_prob = {
   "A": 0.0826,
   "Q": 0.0393,
   "L": 0.0965,
   "S": 0.0660,
   "R": 0.0553,
   "E": 0.0674,
   "K": 0.0582,
   "T": 0.0535,
   "N": 0.0406,
   "G": 0.0708,
   "M": 0.0241,
   "W": 0.0109,
   "D": 0.0546,
   "H": 0.0227,
   "F": 0.0386,
   "Y": 0.0292,
   "C": 0.0137,
   "I": 0.0593,
   "P": 0.0472,
   "V": 0.0686
}

def generate_string(size=10, chars=string.ascii_uppercase + string.digits):
    """
    Generates a random string.
    Taken from: http://stackoverflow.com/questions/2257441/random-string-generation-with-upper-case-letters-and-digits-in-python

    Parameters
    ----------
    size: int
        Size of the string to be generated

    chars: array-like
        Set of characters to use to generate the string

    Returns
    ----------
    string
    """
    return ''.join(random.SystemRandom().choice(chars) for _ in range(size))

def sub_matrices_distance(c1, c2, matrix=MatrixInfo.pam120):
    """
    Get the substitution score for c1 and c2
    according to the provided substitution matrix.

    Parameters
    ----------
    c1, c2: char

    matrix: Bio.SubsMat.MatrixInfo.available_matrix, optional
        The substitution matrix to be used, among the ones available in Bio.SubsMat.MatrixInfo

    Returns
    ----------
    int
        the score for substituting c1 with c2.
    """
    return matrix[(c1, c2)] if (c1, c2) in matrix else matrix[(c2, c1)]

def gap_function(gap_penalty, gap_opening_penalty, k):
    """
	Compute the cost of a gap given the input parameters.

	Parameters
    ----------
	gap_penalty: int
		Cost for extending a gap.

	gap_opening_penalty: int
		Additional cost for opening a gap.

	k: int
		Lenght of the current gap

	Returns
    ----------
    int
        the gap penalty value.
	"""
    return gap_opening_penalty + (k * gap_penalty)

class Alignment:
    """
    Class used to store an alignment of 2 sequences, stored as s1 and s2.
    It also contains a matching string, where for each aminoacid in s1 and s2, we have:\n
        ":" Perfect match of aminoacids.\n
        "." A substitution/mutation occured.\n
        " " A gap was introduced.
    It is possible to add the score of the alignment, if available.
    """

    def __init__(self, s1="", s2="", match="", score=0):
        self.s1 = str(s1)
        self.s2 = str(s2)
        self.match = match
        self.score = 0

    def __add__(self, other):
        if isinstance(other, self.__class__):
            return Alignment(s1 = self.s1 + other.s1, s2 = self.s2 + other.s2, match = self.match + other.match)
        return NotImplemented

    def __iadd__(self, other):
        if isinstance(other, self.__class__):
            self.s1 += other.s1
            self.s2 += other.s2
            self.match += other.match
        else:
             return NotImplemented

    def __str__(self):
        return self.s1 + "\n" + self.match + "\n" + self.s2 + "\n\n----- SCORE:" + str(self.score)

    def __repr__(self):
        return str(self)


import pickle
import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
import numpy as np

def binary_prob_plots(df):
    fig, ax = plt.subplots(1,2, figsize=(8,4))
    ax[0].plot(df.P_SLAB, df.SLAB, 'ok')
    ax[0].set_title('slab avalanche')
    ax[0].set_xlabel('p(slab)')
    ax[0].set_ylabel('events')
    ax[1].plot(df.P_WET, df.WET, 'ok')
    ax[1].set_title('wet avalanche')
    ax[1].set_xlabel('p(wet)')
    plt.tight_layout()
    plt.show()

if __name__=='__main__':
    # load data
    df = pickle.load( open( "pkl/nsanjuan_data.p", "rb"))

    # test for nans
    na_per_col = np.sum(df.isna())

    # probability plots
    binary_prob_plots(df)

    # types of features
    cols = list(df.columns)
    binary = ['SLAB', 'WET']
    continuous = [x for x in cols if x not in binary]
    # feature histograms: binary
    for col in binary:
        data = df[col].dropna()
        plt.hist(data)
        plt.title(col)
        plt.savefig('feature_hists/{}.png'.format(col),dpi=250)
        plt.close()

    # feature histograms: continuous,data w/o nan
    for col in continuous:
        data = df[col].dropna()
        plt.hist(data, bins=20)
        plt.title(col)
        plt.savefig('feature_hists_nsj/{}.png'.format(col),dpi=250)
        plt.close()


#!/usr/bin/env python3
import sys
import crawler
import build_graph
import plot_graph
import os

#crawl the web
testfile = open("testfile.txt", "w")

tempgraph = {'a': {'1', '2', '3', '4'}, 'b': {'1', '2', '3'}, 'c': {'1', '2'}, 'd': {'1'}}
search = "test suite"

testfile.write("Output of crawler function:")
testfile.write(str(tempgraph)+'\n')
testfile.write('\n')
#turn the graph into dictionary json format for the plot
graph = build_graph.build(tempgraph)
testfile.write("Output of build function:")
testfile.write(str(graph)+'\n')

#plot graph
plot_graph.make_plot(graph, search)

#print success
testfile.write('\n')
testfile.write('Your search was a success! See plotly for results.\n')
testfile.close()
os.system("diff testfile.txt correctoutput.txt")


"""
Given the head of a linked list with an odd number of nodes head, return the value of the node in the middle.

For example, given a linked list that represents 1 -> 2 -> 3 -> 4 -> 5, return 3.
"""

def getMiddle(head: ListNode) -> ListNode:

    slow = head
    fast = head

    while fast and fast.next:

        slow = slow.next
        fast = fast.next.next

    return slow.val


pole = 20
time = 1800
timeP = 3
j = {"t": 20, "a": 40}
z = {"t": 100, "a": 200}
zp = 10
t = {"z": 6, "j": 5, "t": 10}
tp = 250

for x in range(pole+1):
    poleZiemniaka = x
    poleJeczmienia = pole - x

    iloscZiemniaka = poleZiemniaka * z["a"]
    iloscJeczmienia = poleJeczmienia * j["a"]
    iloscTucznika = 0
    while iloscJeczmienia > 0 and iloscZiemniaka > 0:
        iloscZiemniaka -= t["z"]
        iloscJeczmienia -= t["j"]
        iloscTucznika += 1

    czas = poleJeczmienia * j["t"] + poleZiemniaka * z["t"] + iloscTucznika * t["t"]
    kasa = iloscZiemniaka * zp + iloscTucznika * tp
    if czas > time:
        kasa -= (czas - time) * timeP
    print("Pole ziemniaka: " + str(poleZiemniaka) + " Pole jeczmienia: " + str(poleJeczmienia) + " Czas: " + str(czas) + " Kasa: " + str(kasa))


from collections import deque

materials = [int(el) for el in input().split()]
magic_levels = deque(int(el) for el in input().split())

total_gifts = {"Diamond Jewellery": 0, "Gemstone": 0, "Gold": 0, "Porcelain Sculpture": 0}

def checker(total):
    if 100 <= total <= 199:
        total_gifts["Gemstone"] += 1
    elif 200 <= total <= 299:
        total_gifts["Porcelain Sculpture"] += 1
    elif 300 <= total <= 399:
        total_gifts["Gold"] += 1
    elif 400 <= total <= 499:
        total_gifts["Diamond Jewellery"] += 1
    else:
        return False
    materials.pop()
    magic_levels.popleft()
    return True

while materials and magic_levels:
    current_sum = materials[-1] + magic_levels[0]
    if not checker(current_sum):
        if current_sum < 100:
            if current_sum % 2 == 0:
                current_sum = materials[-1] * 2 + magic_levels[0] * 3
                if not checker(current_sum):
                    materials.pop()
                    magic_levels.popleft()
            else:
                current_sum = materials[-1] * 2 + magic_levels[0] * 2
                if not checker(current_sum):
                    materials.pop()
                    magic_levels.popleft()
        elif current_sum > 499:
            current_sum = (materials[-1] + magic_levels[0]) / 2
            if not checker(current_sum):
                materials.pop()
                magic_levels.popleft()
        else:
            materials.pop()
            magic_levels.popleft()

if (total_gifts["Gemstone"] > 0 and total_gifts["Porcelain Sculpture"] > 0) or (
        total_gifts["Gold"] > 0 and total_gifts["Diamond Jewellery"] > 0):
    print("The wedding presents are made!")
else:
    print("Aladdin does not have enough wedding presents.")
if materials:
    print(f"Materials left: {', '.join(map(str, materials))}")
if magic_levels:
    print(f"Magic left: {', '.join(map(str, magic_levels))}")

for key, value in total_gifts.items():
    if not value == 0:
        print(f"{key}: {value}")


import json

import pytest

import demistomock as demisto
from lxml import etree
from unittest.mock import patch, MagicMock
from panos.device import Vsys
from panos.panorama import Panorama, DeviceGroup, Template
from panos.firewall import Firewall
from CommonServerPython import DemistoException

integration_params = {
    'port': '443',
    'vsys': 'vsys1',
    'server': 'https://1.1.1.1',
    'key': 'thisisabogusAPIKEY!',
}

mock_demisto_args = {
    'threat_id': "11111",
    'vulnerability_profile': "mock_vuln_profile"
}

@pytest.fixture(autouse=True)
def set_params(mocker):
    mocker.patch.object(demisto, 'params', return_value=integration_params)
    mocker.patch.object(demisto, 'args', return_value=mock_demisto_args)

@pytest.fixture
def patched_requests_mocker(requests_mock):
    """
    This function mocks various PANOS API responses so we can accurately test the instance
    """
    base_url = "{}:{}/api/".format(integration_params['server'], integration_params['port'])
    # Version information
    mock_version_xml = """
    <response status = "success">
        <result>
            <sw-version>9.0.6</sw-version>
            <multi-vsys>off</multi-vsys>
            <model>Panorama</model>
            <serial>FAKESERIALNUMBER</serial>
        </result>
    </response>
    """
    version_path = "{}{}{}".format(base_url, "?type=version&key=", integration_params['key'])
    requests_mock.get(version_path, text=mock_version_xml, status_code=200)
    mock_response_xml = """
    <response status="success" code="20">
    <msg>command succeeded</msg>
    </response>
    """
    requests_mock.post(base_url, text=mock_response_xml, status_code=200)
    return requests_mock

def test_panorama_get_os_version(patched_requests_mocker):
    from Panorama import get_pan_os_version
    import Panorama
    Panorama.URL = 'https://1.1.1.1:443/api/'
    Panorama.API_KEY = 'thisisabogusAPIKEY!'
    r = get_pan_os_version()
    assert r == '9.0.6'

def test_panorama_override_vulnerability(patched_requests_mocker):
    from Panorama import panorama_override_vulnerability
    import Panorama
    Panorama.URL = 'https://1.1.1.1:443/api/'
    r = panorama_override_vulnerability(mock_demisto_args['threat_id'], mock_demisto_args['vulnerability_profile'],
                                        'reset-both')
    assert r['response']['@status'] == 'success'

def test_add_argument_list():
    from Panorama import add_argument_list
    list_argument = ["foo", "bar"]

    response_with_member = add_argument_list(list_argument, "test", True)
    expected_with_member = '<test><member>foo</member><member>bar</member></test>'
    assert response_with_member == expected_with_member

    response_with_member_field_name = add_argument_list(list_argument, "member", True)
    expected_with_member_field_name = '<member>foo</member><member>bar</member>'
    assert response_with_member_field_name == expected_with_member_field_name

def test_add_argument():
    from Panorama import add_argument
    argument = "foo"

    response_with_member = add_argument(argument, "test", True)
    expected_with_member = '<test><member>foo</member></test>'
    assert response_with_member == expected_with_member

    response_without_member = add_argument(argument, "test", False)
    expected_without_member = '<test>foo</test>'
    assert response_without_member == expected_without_member

def test_add_argument_yes_no():
    from Panorama import add_argument_yes_no
    arg = 'No'
    field = 'test'
    option = True

    response_option_true = add_argument_yes_no(arg, field, option)
    expected_option_true = '<option><test>no</test></option>'
    assert response_option_true == expected_option_true

    option = False
    response_option_false = add_argument_yes_no(arg, field, option)
    expected_option_false = '<test>no</test>'
    assert response_option_false == expected_option_false

def test_add_argument_target():
    from Panorama import add_argument_target
    response = add_argument_target('foo', 'bar')
    expected = '<bar><devices><entry name=\"foo\"/></devices></bar>'
    assert response == expected

def test_prettify_addresses_arr():
    from Panorama import prettify_addresses_arr
    addresses_arr = [{'@name': 'my_name', 'fqdn': 'a.com'},
                     {'@name': 'my_name2', 'fqdn': 'b.com'},
                     {'@name': 'test', 'ip-netmask': '1.1.1.1', 'tag': None}]
    response = prettify_addresses_arr(addresses_arr)
    expected = [{'Name': 'my_name', 'FQDN': 'a.com'},
                {'Name': 'my_name2', 'FQDN': 'b.com'},
                {'Name': 'test', 'IP_Netmask': '1.1.1.1'}]
    assert response == expected

def test_prettify_address():
    from Panorama import prettify_address
    address = {'@name': 'my_name', 'ip-netmask': '1.1.1.1', 'description': 'lala'}
    response = prettify_address(address)
    expected = {'Name': 'my_name', 'IP_Netmask': '1.1.1.1', 'Description': 'lala'}
    assert response == expected

def test_prettify_address_tag_none():
    from Panorama import prettify_address
    address = {'@name': 'test', 'ip-netmask': '1.1.1.1', 'tag': None}
    response = prettify_address(address)
    expected = {'Name': 'test', 'IP_Netmask': '1.1.1.1'}
    assert response == expected

def test_prettify_address_group():
    from Panorama import prettify_address_group
    address_group_static = {'@name': 'foo', 'static': {'member': 'address object'}}
    response_static = prettify_address_group(address_group_static)
    expected_address_group_static = {'Name': 'foo', 'Type': 'static', 'Addresses': 'address object'}
    assert response_static == expected_address_group_static

    address_group_dynamic = {'@name': 'foo', 'dynamic': {'filter': '1.1.1.1 and 2.2.2.2'}}
    response_dynamic = prettify_address_group(address_group_dynamic)
    expected_address_group_dynamic = {'Name': 'foo', 'Type': 'dynamic', 'Match': '1.1.1.1 and 2.2.2.2'}
    assert response_dynamic == expected_address_group_dynamic

    address_group_dynamic_tag_none = {'@name': 'foo', 'dynamic': {'filter': '1.1.1.1 or 2.2.2.2'}, 'tag': None}
    response_dynamic_tag_none = prettify_address_group(address_group_dynamic_tag_none)
    expected_address_group_dynamic_tag_none = {'Name': 'foo', 'Type': 'dynamic', 'Match': '1.1.1.1 or 2.2.2.2'}
    assert response_dynamic_tag_none == expected_address_group_dynamic_tag_none

def test_prettify_service():
    from Panorama import prettify_service
    service = {'@name': 'service_name', 'description': 'foo', 'protocol': {'tcp': {'port': '443'}}}
    response = prettify_service(service)
    expected = {'Name': 'service_name', 'Description': 'foo', 'Protocol': 'tcp', 'DestinationPort': '443'}
    assert response == expected

def test_prettify_service_tag_none():
    from Panorama import prettify_service
    service = {'@name': 'service_name', 'description': 'foo', 'protocol': {'tcp': {'port': '443'}}, 'tag': None}
    response = prettify_service(service)
    expected = {'Name': 'service_name', 'Description': 'foo', 'Protocol': 'tcp', 'DestinationPort': '443'}
    assert response == expected

def test_prettify_service_group():
    from Panorama import prettify_service_group
    service_group = {'@name': 'sg', 'members': {'member': ['service1', 'service2']}}
    response = prettify_service_group(service_group)
    expected = {'Name': 'sg', 'Services': ['service1', 'service2']}
    assert response == expected

def test_prettify_service_group_tag_none():
    from Panorama import prettify_service_group
    service_group = {'@name': 'sg_group', 'members': {'member': ['service1', 'service2']}, 'tag': None}
    response = prettify_service_group(service_group)
    expected = {'Name': 'sg_group', 'Services': ['service1', 'service2']}
    assert response == expected

def test_prettify_custom_url_category():
    from Panorama import prettify_custom_url_category
    custom_url_category = {'@name': 'foo', 'list': {'member': ['a', 'b', 'c']}}
    response = prettify_custom_url_category(custom_url_category)
    expected = {'Name': 'foo', 'Sites': ['a', 'b', 'c']}
    assert response == expected

def test_panorama_create_custom_url_category_8_x(mocker):
    """
    Given:
     - an only > 9.x valid argument for custom url category creation

    When:
     - running the panorama_create_custom_url_category function
     - mocking the pan-os version to be 8.x

    Then:
     - a proper error is raised
    """
    from Panorama import panorama_create_custom_url_category
    mocker.patch('Panorama.get_pan_os_major_version', return_value=8)
    custom_url_category_name = 'name'
    description = 'test_desc'
    type_ = 'URL List'

    with pytest.raises(DemistoException,
                       match='The type and categories arguments are only relevant for PAN-OS 9.x versions.'):
        panorama_create_custom_url_category(custom_url_category_name, type_=type_, description=description)

def test_panorama_create_custom_url_category_9_x(mocker):
    """
    Given:
     - a non valid argument for custom url category creation

    When:
     - running the panorama_create_custom_url_category function
     - mocking the pan-os version to be 9.x

    Then:
     - a proper error is raised
    """
    from Panorama import panorama_create_custom_url_category
    mocker.patch('Panorama.get_pan_os_major_version', return_value=9)
    custom_url_category_name = 'name'
    type_ = 'URL List'
    categories = 'phishing'
    sites = 'a.com'
    description = 'test_desc'

    with pytest.raises(DemistoException,
                       match='The type argument is mandatory for PAN-OS 9.x versions.'):
        panorama_create_custom_url_category(custom_url_category_name, sites=sites, description=description)

    with pytest.raises(DemistoException,
                       match='Exactly one of the sites and categories arguments should be defined.'):
        panorama_create_custom_url_category(custom_url_category_name, type_=type_, sites=sites, categories=categories)

    with pytest.raises(DemistoException,
                       match='URL List type is only for sites, Category Match is only for categories.'):
        panorama_create_custom_url_category(custom_url_category_name, type_=type_, categories=categories)

def test_create_url_filter_params_8_x(mocker):
    """
    Given:
     - a valid argument for url filter creation

    When:
     - running the create_url_filter_params utility function
     - mocking the pan-os version to be 8.x

    Then:
     - a proper xml element is generated
    """
    from Panorama import create_url_filter_params
    mocker.patch('Panorama.get_pan_os_major_version', return_value=8)
    url_filter_name = 'name'
    action = 'alert'
    url_category_list = 'adult'
    description = 'test_desc'

    url_filter_params = create_url_filter_params(url_filter_name, action, url_category_list=url_category_list,
                                                 description=description)
    assert url_filter_params['element'].find('<action>block</action>') != -1  # if not -1, then it is found

def test_create_url_filter_params_9_x(mocker):
    """
    Given:
     - a valid argument for url filter creation

    When:
     - running the create_url_filter_params utility function
     - mocking the pan-os version to be 9.x

    Then:
     - a proper xml element is generated
    """
    from Panorama import create_url_filter_params
    mocker.patch('Panorama.get_pan_os_major_version', return_value=9)
    url_filter_name = 'name'
    action = 'alert'
    url_category_list = 'adult'
    description = 'test_desc'

    url_filter_params = create_url_filter_params(url_filter_name, action, url_category_list=url_category_list,
                                                 description=description)
    assert url_filter_params['element'].find('<action>block</action>') == -1  # if  -1, then it is not found

def test_edit_url_filter_non_valid_args_8_x(mocker):
    """
    Given:
     - a non valid argument for edit url filter

    When:
     - running the edit_url_filter function
     - mocking the pan-os version to be 8.x

    Then:
     - a proper error is raised
    """
    from Panorama import panorama_edit_url_filter
    url_filter_object = {
        "@name": "fw_test_pb_dont_delete",
        "action": "block",
        "allow": {
            "member": [
                "Demisto- block sites",
                "test3"
            ]
        },
        "allow-list": {
            "member": "www.thepill2.com"
        },
        "block": {
            "member": [
                "abortion",
                "abused-drugs"
            ]
        },
        "block-list": {
            "member": "www.thepill.com"
        },
        "credential-enforcement": {
            "allow": {
                "member": [
                    "Demisto- block sites",
                    "test3"
                ]
            },
            "block": {
                "member": [
                    "abortion",
                    "abused-drugs"
                ]
            },
            "log-severity": "medium",
        },
        "description": "gogo"
    }
    mocker.patch('Panorama.get_pan_os_major_version', return_value=8)
    mocker.patch('Panorama.panorama_get_url_filter', return_value=url_filter_object)
    url_filter_name = 'fw_test_pb_dont_delete'
    element_to_change = 'allow_categories'
    element_value = 'gambling'
    add_remove_element = 'remove'

    err_msg = 'Only the override_allow_list, override_block_list, description properties can be' \
              ' changed in PAN-OS 8.x or earlier versions.'
    with pytest.raises(DemistoException, match=err_msg):
        panorama_edit_url_filter(url_filter_name, element_to_change, element_value, add_remove_element)

def test_edit_url_filter_non_valid_args_9_x(mocker):
    """
    Given:
     - a non valid argument for edit url filter

    When:
     - running the edit_url_filter function
     - mocking the pan-os version to be 9.x

    Then:
     - a proper error is raised
    """
    from Panorama import panorama_edit_url_filter
    url_filter_object = {
        "@name": "fw_test_pb_dont_delete",
        "allow": {
            "member": "Test_pb_custom_url_DONT_DELETE"
        },
        "credential-enforcement": {
            "block": {
                "member": [
                    "gambling",
                    "abortion"
                ]
            },
            "log-severity": "medium",
        },
        "description": "wowo"
    }
    mocker.patch('Panorama.get_pan_os_major_version', return_value=9)
    mocker.patch('Panorama.panorama_get_url_filter', return_value=url_filter_object)
    url_filter_name = 'fw_test_pb_dont_delete'
    element_to_change = 'override_block_list'
    element_value = 'gambling'
    add_remove_element = 'remove'

    err_msg = 'Only the allow_categories, block_categories, description properties can be changed in PAN-OS 9.x or' \
              ' later versions.'
    with pytest.raises(DemistoException, match=err_msg):
        panorama_edit_url_filter(url_filter_name, element_to_change, element_value, add_remove_element)

def http_mock(url: str, method: str, body: dict = {}):
    return body

@pytest.mark.parametrize('category_name, items', [('category_name', ['www.good.com'],)])
def test_remove_from_custom_url_category(category_name, items, mocker):
    """
    Given:
     - a valid argument for edit custom url group

    When:
     - running the custom_url_category_remove_items function

    Then:
     - checks an assertion
    """
    import Panorama
    from Panorama import panorama_custom_url_category_remove_items

    return_results_mock = mocker.patch.object(Panorama, 'return_results')

    mocker.patch('Panorama.panorama_get_custom_url_category', return_value={'description': 'description',
                                                                            'list': {'member': "www.test.com"}
                                                                            })
    mocker.patch('Panorama.get_pan_os_major_version', return_value=9)
    mocker.patch('Panorama.http_request', side_effect=http_mock)

    panorama_custom_url_category_remove_items(category_name, items, "URL List")
    demisto_result_got = return_results_mock.call_args.args[0]['Contents']
    assert "www.test.com" in demisto_result_got['element']

def test_prettify_edl():
    from Panorama import prettify_edl
    edl = {'@name': 'edl_name', 'type': {'my_type': {'url': 'abc.com', 'description': 'my_desc'}}}
    response = prettify_edl(edl)
    expected = {'Name': 'edl_name', 'Type': 'my_type', 'URL': 'abc.com', 'Description': 'my_desc'}
    assert response == expected

def test_build_traffic_logs_query():
    """
    Given:
     - a valid arguments for traffic logs query generation

    When:
     - running the build_traffic_logs_query utility function

    Then:
     - a proper query is generated
        (addr.src in 192.168.1.222) and (app eq netbios-dg) and (action eq allow) and (port.dst eq 138)
    """
    from Panorama import build_traffic_logs_query
    source = '192.168.1.222'
    application = 'netbios-dg'
    action = 'allow'
    to_port = '138'
    response = build_traffic_logs_query(source, None, None, application, to_port, action)
    expected = '(addr.src in 192.168.1.222) and (app eq netbios-dg) and (port.dst eq 138) and (action eq allow)'
    assert response == expected

def test_prettify_traffic_logs():
    from Panorama import prettify_traffic_logs
    traffic_logs = [{'action': 'my_action1', 'category': 'my_category1', 'rule': 'my_rule1'},
                    {'action': 'my_action2', 'category': 'my_category2', 'rule': 'my_rule2'}]
    response = prettify_traffic_logs(traffic_logs)
    expected = [{'Action': 'my_action1', 'Category': 'my_category1', 'Rule': 'my_rule1'},
                {'Action': 'my_action2', 'Category': 'my_category2', 'Rule': 'my_rule2'}]
    assert response == expected

def test_build_logs_query():
    """
    Given:
     - a valid arguments for logs query generation

    When:
     - running the build_logs_query utility function

    Then:
     - a proper query is generated
        ((url contains 'demisto.com') or (url contains 'paloaltonetworks.com'))
    """
    from Panorama import build_logs_query

    urls_as_string = "demisto.com, paloaltonetworks.com"
    response = build_logs_query(None, None, None, None, None, None, None, None, None, urls_as_string, None)
    expected = "((url contains 'demisto.com') or (url contains 'paloaltonetworks.com'))"
    assert response == expected

def test_prettify_logs():
    from Panorama import prettify_logs
    traffic_logs = [{'action': 'my_action1', 'category': 'my_category1', 'rule': 'my_rule1', 'natdport': '100',
                     'bytes': '12'},
                    {'action': 'my_action2', 'category': 'my_category2', 'rule': 'my_rule2', 'natdport': '101',
                     'bytes_sent': '11'}]
    response = prettify_logs(traffic_logs)
    expected = [{'Action': 'my_action1', 'CategoryOrVerdict': 'my_category1', 'Rule': 'my_rule1',
                 'NATDestinationPort': '100', 'Bytes': '12'},
                {'Action': 'my_action2', 'CategoryOrVerdict': 'my_category2', 'Rule': 'my_rule2',
                 'NATDestinationPort': '101', 'BytesSent': '11'}]
    assert response == expected

prepare_security_rule_inputs = [
    ('top', 'test_rule_name'),
    ('bottom', 'test_rule_name'),
]

@pytest.mark.parametrize('where, dst', prepare_security_rule_inputs)
def test_prepare_security_rule_params(where, dst):
    """
    Given:
     - a non valid arguments for the prepare_security_rule_params function

    When:
     - running the prepare_security_rule_params utility function

    Then:
     - a proper exception is raised
    """
    from Panorama import prepare_security_rule_params
    err_msg = 'Please provide a dst rule only when the where argument is before or after.'
    with pytest.raises(DemistoException, match=err_msg):
        prepare_security_rule_params(api_action='set', action='drop', destination=['any'], source=['any'],
                                     rulename='test', where=where, dst=dst)

def test_build_policy_match_query():
    """
    Given:
     - a valid arguments for policy match query generation

    When:
     - running the build_policy_match_query utility function

    Then:
     - a proper xml is generated
    """
    from Panorama import build_policy_match_query
    source = '1.1.1.1'
    destination = '6.7.8.9'
    protocol = '1'
    application = 'gmail-base'
    response = build_policy_match_query(application, None, destination, None, None, None, protocol, source)
    expected = '<test><security-policy-match><source>1.1.1.1</source><destination>6.7.8.9</destination>' \
               '<protocol>1</protocol><application>gmail-base</application></security-policy-match></test>'
    assert response == expected

def test_panorama_register_ip_tag_command_wrongful_args(mocker):
    """
    Given:
     - a non valid arguments for the panorama_register_ip_tag_command function

    When:
     - running the panorama_register_ip_tag_command function

    Then:
     - a proper exception is raised
    """
    from Panorama import panorama_register_ip_tag_command
    args = {'IPs': '1.1.1.1', 'tag': 'test_tag', 'persistent': 'true', 'timeout': '5'}

    mocker.patch('Panorama.get_pan_os_major_version', return_value=9)
    with pytest.raises(DemistoException,
                       match='When the persistent argument is true, you can not use the timeout argument.'):
        panorama_register_ip_tag_command(args)

    args['persistent'] = 'false'
    mocker.patch('Panorama.get_pan_os_major_version', return_value=8)
    with pytest.raises(DemistoException,
                       match='The timeout argument is only applicable on 9.x PAN-OS versions or higher.'):
        panorama_register_ip_tag_command(args)

def test_prettify_matching_rule():
    from Panorama import prettify_matching_rule
    matching_rule = {'action': 'my_action1', '@name': 'very_important_rule', 'source': '6.7.8.9', 'destination': 'any'}
    response = prettify_matching_rule(matching_rule)
    expected = {'Action': 'my_action1', 'Name': 'very_important_rule', 'Source': '6.7.8.9', 'Destination': 'any'}
    assert response == expected

def test_prettify_static_route():
    from Panorama import prettify_static_route
    static_route = {'@name': 'name1', 'destination': '1.2.3.4', 'metric': '10', 'nexthop': {'fqdn': 'demisto.com'}}
    virtual_router = 'my_virtual_router'
    response = prettify_static_route(static_route, virtual_router)
    expected = {'Name': 'name1', 'Destination': '1.2.3.4', 'Metric': 10,
                'NextHop': 'demisto.com', 'VirtualRouter': 'my_virtual_router'}
    assert response == expected

def test_validate_search_time():
    from Panorama import validate_search_time
    assert validate_search_time('2019/12/26')
    assert validate_search_time('2019/12/26 00:00:00')
    with pytest.raises(Exception):
        assert validate_search_time('219/12/26 00:00:00')
        assert validate_search_time('219/10/35')

def test_show_user_id_interface_config_command():
    """
    Given:
     - missing template and template_stack arguments for the show_user_id_interface_config_command command

    When:
     - running the show_user_id_interface_config_request function

    Then:
     - a proper exception is raised
    """
    from Panorama import show_user_id_interface_config_command
    args = {}
    str_match = 'In order to show the User Interface configuration in your Panorama, ' \
                'supply either the template or the template_stack arguments.'
    with pytest.raises(DemistoException, match=str_match):
        show_user_id_interface_config_command(args)

def test_prettify_user_interface_config():
    from Panorama import prettify_user_interface_config
    raw_response = [{'@name': 'internal', 'network': {'layer3': {'member': 'ethernet1/2'},
                                                      'log-setting': 'ToLoggingService'},
                     'enable-user-identification': 'yes'},
                    {'@name': 'External', 'network': {'tap': {'member': 'ethernet1/1'},
                                                      'log-setting': 'ToLoggingService'}}]
    response = prettify_user_interface_config(raw_response)
    expected = [{'Name': 'ethernet1/2', 'Zone': 'internal', 'EnableUserIdentification': 'yes'},
                {'Name': 'ethernet1/1', 'Zone': 'External', 'EnableUserIdentification': 'no'}]
    assert response == expected

def test_list_configured_user_id_agents_command(mocker):
    """
    Given:
     - missing template and template_stack arguments for the list_configured_user_id_agents_command command

    When:
     - running the list_configured_user_id_agents_request function

    Then:
     - a proper exception is raised
    """
    from Panorama import list_configured_user_id_agents_command
    mocker.patch('Panorama.get_pan_os_major_version', return_value=9)
    args = {}
    str_match = 'In order to show the the User ID Agents in your Panorama, ' \
                'supply either the template or the template_stack arguments.'
    with pytest.raises(DemistoException, match=str_match):
        list_configured_user_id_agents_command(args)

def test_prettify_configured_user_id_agents__multi_result():
    from Panorama import prettify_configured_user_id_agents
    raw_response = [{'@name': 'testing2', 'serial-number': 'panorama2'},
                    {'@name': 'fullinfo', 'host-port': {'port': '67', 'ntlm-auth': 'yes',
                                                        'ldap-proxy': 'yes', 'collectorname': 'demisto',
                                                        'secret': 'secret', 'host': 'what'}, 'ip-user-mappings': 'yes'}]
    response = prettify_configured_user_id_agents(raw_response)
    expected = [{'Name': 'testing2', 'Host': None, 'Port': None, 'NtlmAuth': 'no', 'LdapProxy': 'no',
                 'CollectorName': None, 'Secret': None, 'EnableHipCollection': 'no', 'SerialNumber': 'panorama2',
                 'IpUserMapping': 'no', 'Disabled': 'no'},
                {'Name': 'fullinfo', 'Host': 'what', 'Port': '67', 'NtlmAuth': 'yes', 'LdapProxy': 'yes',
                 'CollectorName': 'demisto', 'Secret': 'secret', 'EnableHipCollection': 'no', 'SerialNumber': None,
                 'IpUserMapping': 'yes', 'Disabled': 'no'}]
    assert response == expected

def test_prettify_configured_user_id_agents__single_result():
    from Panorama import prettify_configured_user_id_agents
    raw_response = {'@name': 'fullinfo', 'host-port': {'port': '67', 'ntlm-auth': 'yes',
                                                       'ldap-proxy': 'yes', 'collectorname': 'demisto',
                                                       'secret': 'secret', 'host': 'what'}, 'ip-user-mappings': 'yes'}
    response = prettify_configured_user_id_agents(raw_response)
    expected = {'Name': 'fullinfo', 'Host': 'what', 'Port': '67', 'NtlmAuth': 'yes', 'LdapProxy': 'yes',
                'CollectorName': 'demisto', 'Secret': 'secret', 'EnableHipCollection': 'no', 'SerialNumber': None,
                'IpUserMapping': 'yes', 'Disabled': 'no'}
    assert response == expected

def test_prettify_rule():
    from Panorama import prettify_rule
    with open("test_data/rule.json") as f:
        rule = json.load(f)

    with open("test_data/prettify_rule.json") as f:
        expected_prettify_rule = json.load(f)

    prettify_rule = prettify_rule(rule)

    assert prettify_rule == expected_prettify_rule

class TestPanoramaEditRuleCommand:
    EDIT_SUCCESS_RESPONSE = {'response': {'@status': 'success', '@code': '20', 'msg': 'command succeeded'}}

    @staticmethod
    def test_sanity(mocker):
        import Panorama
        args = {
            'rulename': 'TestRule',
            'element_to_change': 'source',
            'element_value': '2.3.4.5,3.3.3.3',
            'behaviour': 'add',
        }
        commited_rule_item = {
            'response': {
                '@status': 'success',
                '@code': '19',
                'result': {
                    '@total-count': '1',
                    '@count': '1',
                    'source': {
                        'member': ['1.1.1.1', '3.3.3.3', '2.3.4.5'],
                    }
                }
            }
        }
        mocker.patch('Panorama.http_request', return_value=commited_rule_item)
        Panorama.panorama_edit_rule_command(args)

    @staticmethod
    def test_add_to_element_on_uncommited_rule(mocker):
        import Panorama
        args = {
            'rulename': 'TestRule',
            'element_to_change': 'source',
            'element_value': '2.3.4.5',
            'behaviour': 'add',
        }
        uncommited_rule_item = {
            'response': {
                '@status': 'success',
                '@code': '19',
                'result': {
                    '@total-count': '1',
                    '@count': '1',
                    'source': {
                        '@admin': 'admin',
                        '@dirtyId': '1616',
                        '@time': '2021/11/27 10:55:18',
                        'member': {
                            '@admin': 'admin',
                            '@dirtyId': '1616',
                            '@time': '2021/11/27 10:55:18',
                            '#text': '3.3.3.3',
                        }
                    }
                }
            }
        }
        mocker.patch('Panorama.http_request', return_value=uncommited_rule_item)

        with pytest.raises(DemistoException):
            Panorama.panorama_edit_rule_command(args)

class MockedResponse:
    def __init__(self, text, status_code, reason):
        self.status_code = status_code
        self.text = text
        self.reason = reason

@pytest.mark.parametrize('args, expected_request_params, request_result, expected_demisto_result',
                         [pytest.param({'device-group': 'some_device', 'admin_name': 'some_admin_name'},
                                       {'action': 'partial',
                                        'cmd': '<commit><device-group><entry '
                                               'name="some_device"/></device-group><partial><admin>'
                                               '<member>some_admin_name</member></admin></partial></commit>',
                                        'key': 'thisisabogusAPIKEY!',
                                        'type': 'commit'},
                                       MockedResponse(text='<response status="success" code="19"><result><msg>'
                                                           '<line>Commit job enqueued with jobid 19420</line></msg>'
                                                           '<job>19420</job></result></response>', status_code=200,
                                                      reason=''),
                                       {'Panorama.Commit(val.JobID == obj.JobID)': {'Description': None,
                                                                                'JobID': '19420',
                                                                                'Status': 'Pending'}},
                                       id='only admin changes commit'),
                          pytest.param({'device-group': 'some_device', 'force_commit': 'true'},
                                       {'cmd': '<commit><device-group><entry name="some_device"/></device-group><force>'
                                               '</force></commit>',
                                        'key': 'thisisabogusAPIKEY!',
                                        'type': 'commit'},
                                       MockedResponse(text='<response status="success" code="19"><result><msg>'
                                                           '<line>Commit job enqueued with jobid 19420</line></msg>'
                                                           '<job>19420</job></result></response>', status_code=200,
                                                      reason=''),
                                       {'Panorama.Commit(val.JobID == obj.JobID)': {'Description': None,
                                                                                'JobID': '19420',
                                                                                'Status': 'Pending'}},
                                       id="force commit"),
                          pytest.param({'device-group': 'some_device', 'exclude_device_network_configuration': 'true'},
                                       {'action': 'partial',
                                        'cmd': '<commit><device-group><entry name="some_device"/></device-group>'
                                               '<partial><device-and-network>excluded</device-and-network></partial>'
                                               '</commit>',
                                        'key': 'thisisabogusAPIKEY!',
                                        'type': 'commit'},
                                       MockedResponse(text='<response status="success" code="19"><result><msg>'
                                                           '<line>Commit job enqueued with jobid 19420</line></msg>'
                                                           '<job>19420</job></result></response>', status_code=200,
                                                      reason=''),
                                       {'Panorama.Commit(val.JobID == obj.JobID)': {'Description': None,
                                                                                'JobID': '19420',
                                                                                'Status': 'Pending'}},
                                       id="device and network excluded"),
                          pytest.param({'device-group': 'some_device', 'exclude_shared_objects': 'true'},
                                       {'action': 'partial',
                                        'cmd': '<commit><device-group><entry name="some_device"/></device-group>'
                                               '<partial><shared-object>excluded</shared-object></partial></commit>',
                                        'key': 'thisisabogusAPIKEY!',
                                        'type': 'commit'},
                                       MockedResponse(text='<response status="success" code="19"><result><msg>'
                                                           '<line>Commit job enqueued with jobid 19420</line></msg>'
                                                           '<job>19420</job></result></response>', status_code=200,
                                                      reason=''),
                                       {'Panorama.Commit(val.JobID == obj.JobID)': {'Description': None,
                                                                                'JobID': '19420',
                                                                                'Status': 'Pending'}},
                                       id="exclude shared objects"),
                          pytest.param({'device-group': 'some_device'},
                                       {'cmd': '<commit><device-group><entry name="some_device"/></device-group>'
                                               '</commit>',
                                        'key': 'thisisabogusAPIKEY!',
                                        'type': 'commit'},
                                       MockedResponse(text='<response status="success" code="19"><result><msg>'
                                                           '<line>Commit job enqueued with jobid 19420</line></msg>'
                                                           '<job>19420</job></result></response>', status_code=200,
                                                      reason=''),
                                       {'Panorama.Commit(val.JobID == obj.JobID)': {'Description': None,
                                                                                'JobID': '19420',
                                                                                'Status': 'Pending'}},
                                       id="no args")
                          ])
def test_panorama_commit_command(mocker, args, expected_request_params, request_result, expected_demisto_result):
    """
    Given:
        - command args
        - request result
    When:
        - Running panorama-commit command
    Then:
        - Assert the request url is as expected
        - Assert demisto results contain the relevant result information
    """
    import Panorama
    import requests
    from Panorama import panorama_commit_command

    Panorama.API_KEY = 'thisisabogusAPIKEY!'
    return_results_mock = mocker.patch.object(Panorama, 'return_results')
    request_mock = mocker.patch.object(requests, 'request', return_value=request_result)
    panorama_commit_command(args)

    called_request_params = request_mock.call_args.kwargs['data']  # The body part of the request
    assert called_request_params == expected_request_params

    demisto_result_got = return_results_mock.call_args.args[0]['EntryContext']
    assert demisto_result_got == expected_demisto_result

@pytest.mark.parametrize('args, expected_request_params, request_result, expected_demisto_result',
                         [pytest.param({},
                                       {'action': 'all',
                                        'cmd': '<commit-all><shared-policy><device-group><entry name="some_device"/>'
                                               '</device-group></shared-policy></commit-all>',
                                        'key': 'thisisabogusAPIKEY!',
                                        'type': 'commit'},
                                       MockedResponse(text='<response status="success" code="19"><result><msg>'
                                                           '<line>Commit job enqueued with jobid 19420</line></msg>'
                                                           '<job>19420</job></result></response>', status_code=200,
                                                      reason=''),
                                       {'Panorama.Push(val.JobID == obj.JobID)': {'DeviceGroup': 'some_device',
                                                                                'JobID': '19420',
                                                                                'Status': 'Pending'}},
                                       id='no args'),
                          pytest.param({'serial_number': '1337'},
                                       {'action': 'all',
                                        'cmd': '<commit-all><shared-policy><device-group><entry name="some_device">'
                                               '<devices><entry name="1337"/></devices></entry></device-group>'
                                               '</shared-policy></commit-all>',
                                        'key': 'thisisabogusAPIKEY!',
                                        'type': 'commit'},
                                       MockedResponse(text='<response status="success" code="19"><result><msg>'
                                                           '<line>Commit job enqueued with jobid 19420</line></msg>'
                                                           '<job>19420</job></result></response>', status_code=200,
                                                      reason=''),
                                       {'Panorama.Push(val.JobID == obj.JobID)': {'DeviceGroup': 'some_device',
                                                                                'JobID': '19420',
                                                                                'Status': 'Pending'}},
                                       id='serial number'),
                          pytest.param({'include-template': 'false'},
                                       {'action': 'all',
                                        'cmd': '<commit-all><shared-policy><device-group><entry name="some_device"/>'
                                               '</device-group><include-template>no</include-template></shared-policy>'
                                               '</commit-all>',
                                        'key': 'thisisabogusAPIKEY!',
                                        'type': 'commit'},
                                       MockedResponse(text='<response status="success" code="19"><result><msg>'
                                                           '<line>Commit job enqueued with jobid 19420</line></msg>'
                                                           '<job>19420</job></result></response>', status_code=200,
                                                      reason=''),
                                       {'Panorama.Push(val.JobID == obj.JobID)': {'DeviceGroup': 'some_device',
                                                                                'JobID': '19420',
                                                                                'Status': 'Pending'}},
                                       id='do not include template')
                          ])
def test_panorama_push_to_device_group_command(mocker, args, expected_request_params, request_result,
                                               expected_demisto_result):
    """
    Given:
        - command args
        - request result
    When:
        - Running panorama-push-to-device-group command
    Then:
        - Assert the request url is as expected
        - Assert demisto results contain the relevant result information
    """
    import Panorama
    import requests
    from Panorama import panorama_push_to_device_group_command

    return_results_mock = mocker.patch.object(Panorama, 'return_results')
    request_mock = mocker.patch.object(requests, 'request', return_value=request_result)
    Panorama.DEVICE_GROUP = 'some_device'
    Panorama.API_KEY = 'thisisabogusAPIKEY!'
    panorama_push_to_device_group_command(args)

    called_request_params = request_mock.call_args.kwargs['data']  # The body part of the request
    assert called_request_params == expected_request_params

    demisto_result_got = return_results_mock.call_args.args[0]['EntryContext']
    assert demisto_result_got == expected_demisto_result

def test_get_url_category__url_length_gt_1278(mocker):
    """
    Given:
        - Error in response indicating the url to get category for is over the allowed length (1278 chars)

    When:
        - Run get_url_category command

    Then:
        - Validate a commandResult is returned with detailed readable output
    """

    # prepare
    import Panorama
    import requests
    from Panorama import panorama_get_url_category_command
    Panorama.DEVICE_GROUP = ''
    mocked_res_dict = {
        'response': {
            '@status': 'error',
            '@code': '20',
            'msg': {'line': 'test -> url Node can be at most 1278 characters, but current length: 1288'}
        }}
    mocked_res_obj = requests.Response()
    mocked_res_obj.status_code = 200
    mocked_res_obj._content = json.dumps(mocked_res_dict).encode('utf-8')
    mocker.patch.object(requests, 'request', return_value=mocked_res_obj)
    mocker.patch.object(Panorama, 'xml2json', return_value=mocked_res_obj._content)
    return_results_mock = mocker.patch.object(Panorama, 'return_results')

    # run
    panorama_get_url_category_command(url_cmd='url', url='test_url', additional_suspicious=[], additional_malicious=[])

    # validate
    assert 'URL Node can be at most 1278 characters.' == return_results_mock.call_args[0][0][1].readable_output

class TestDevices:

    def test_with_fw(self):
        import Panorama
        Panorama.VSYS = 'this is a FW instance'
        assert list(Panorama.devices()) == [(None, None)]

    def test_with_specific_target_and_vsys(self):
        import Panorama
        Panorama.VSYS = None  # this a Panorama instance
        assert list(Panorama.devices(targets=['target'], vsys_s=['vsys1', 'vsys2'])) == [('target', 'vsys1'),
                                                                                ('target', 'vsys2')]

    def test_with_specific_target_only(self, requests_mock):
        import Panorama
        with open('test_data/devices_list.xml', 'r') as data_file:
            requests_mock.get(Panorama.URL, text=data_file.read())
        Panorama.VSYS = None  # this a Panorama instance
        assert list(Panorama.devices(targets=['target1'])) == [('target1', 'vsys1'), ('target1', 'vsys2')]

    def test_without_specify(self, requests_mock):
        import Panorama
        with open('test_data/devices_list.xml', 'r') as data_file:
            requests_mock.get(Panorama.URL, text=data_file.read())
        Panorama.VSYS = None  # this a Panorama instance
        assert list(Panorama.devices()) == [('target1', 'vsys1'), ('target1', 'vsys2'), ('target2', None)]

def load_xml_root_from_test_file(xml_file: str):
    """Given an XML file, loads it and returns the root element XML object."""
    return etree.parse(xml_file).getroot()

MOCK_PANORAMA_SERIAL = "111222334455"
MOCK_FIREWALL_1_SERIAL = "111111111111111"
MOCK_FIREWALL_2_SERIAL = "222222222222222"
MOCK_FIREWALL_3_SERIAL = "333333333333333"

@pytest.fixture
def mock_firewall():
    mock_firewall = MagicMock(spec=Firewall)
    mock_firewall.serial = MOCK_FIREWALL_1_SERIAL
    mock_firewall.hostname = None

    return mock_firewall

@pytest.fixture
def mock_panorama():
    mock_panorama = MagicMock(spec=Panorama)
    mock_panorama.serial = MOCK_PANORAMA_SERIAL
    mock_panorama.hostname = None
    return mock_panorama

def mock_device_groups():
    mock_device_group = MagicMock(spec=DeviceGroup)
    mock_device_group.name = "test-dg"
    return [mock_device_group]

def mock_templates():
    mock_template = MagicMock(spec=Template)
    mock_template.name = "test-template"
    return [mock_template]

def mock_vsys():
    mock_vsys = MagicMock(spec=Vsys)
    mock_vsys.name = "vsys1"
    return [mock_vsys]

@pytest.fixture
def mock_topology(mock_panorama, mock_firewall):
    from Panorama import Topology
    topology = Topology()
    topology.panorama_objects = {
        MOCK_PANORAMA_SERIAL: mock_panorama,
    }
    topology.firewall_objects = {
        MOCK_FIREWALL_1_SERIAL: mock_firewall
    }
    topology.ha_active_devices = {
        MOCK_PANORAMA_SERIAL: mock_panorama,
        MOCK_FIREWALL_1_SERIAL: mock_firewall
    }
    return topology

class TestTopology:
    """Tests the Topology class and all of it's methods"""
    SHOW_HA_STATE_ENABLED_XML = "test_data/show_ha_state_enabled.xml"
    SHOW_HA_STATE_DISABLED_XML = "test_data/show_ha_state_disabled.xml"
    SHOW_DEVICES_ALL_XML = "test_data/panorama_show_devices_all.xml"

    @patch("Panorama.Topology.get_all_child_firewalls")
    @patch("Panorama.run_op_command")
    def test_add_firewall_device_object(self, patched_run_op_command, _, mock_firewall):
        """
        Given the XML output of show ha state and a firewall object, test it is correctly added to the topology.
        """
        from Panorama import Topology
        patched_run_op_command.return_value = load_xml_root_from_test_file(TestTopology.SHOW_HA_STATE_DISABLED_XML)
        topology = Topology()
        topology.add_device_object(mock_firewall)

        assert MOCK_FIREWALL_1_SERIAL in topology.firewall_objects

    @patch("Panorama.Topology.get_all_child_firewalls")
    @patch("Panorama.run_op_command")
    def test_add_panorama_device_object(self, patched_run_op_command, _, mock_panorama):
        """
        Given the output of show_ha_state with no entries, assert that the Panorama device has been added to the topolog
        as a panorama type device.
        """
        from Panorama import Topology
        patched_run_op_command.return_value = load_xml_root_from_test_file(TestTopology.SHOW_HA_STATE_DISABLED_XML)
        topology = Topology()
        topology.add_device_object(mock_panorama)

        assert MOCK_PANORAMA_SERIAL in topology.panorama_objects
        assert MOCK_PANORAMA_SERIAL in topology.ha_active_devices
        assert MOCK_PANORAMA_SERIAL not in topology.firewall_objects

    @patch("Panorama.run_op_command")
    def test_get_all_child_firewalls(self, patched_run_op_command, mock_panorama):
        """
        Given the output of show devices all, assert that all the devices are added correctly to the topology with the correct
        HA State information.
        """
        from Panorama import Topology
        patched_run_op_command.return_value = load_xml_root_from_test_file(TestTopology.SHOW_DEVICES_ALL_XML)
        topology = Topology()

        topology.get_all_child_firewalls(mock_panorama)
        # 222... firewall should be Active, with 111... as it's peer
        assert MOCK_FIREWALL_2_SERIAL in topology.ha_active_devices
        assert topology.ha_active_devices.get(MOCK_FIREWALL_2_SERIAL) == MOCK_FIREWALL_1_SERIAL

        # 333... is standalone
        assert MOCK_FIREWALL_3_SERIAL in topology.ha_active_devices
        assert topology.ha_active_devices.get(MOCK_FIREWALL_3_SERIAL) == "STANDALONE"

    @patch("Panorama.run_op_command")
    def test_get_active_devices(self, patched_run_op_command, mock_panorama):
        """
        Given a topology with a mixture of active and passive devices, assert that active_devices() returns the correct lists
        of objects.
        """
        from Panorama import Topology
        patched_run_op_command.return_value = load_xml_root_from_test_file(TestTopology.SHOW_DEVICES_ALL_XML)
        topology = Topology()
        topology.add_device_object(mock_panorama)

        result_list = list(topology.active_devices())
        # Should be 3; panorama, one active firewall in a pair, and one stanadlone firewall (from panorama_show_devices_all.xml)
        assert len(result_list) == 3

        # Same as above by try filtering by serial number
        result_list = list(topology.active_devices(filter_str=MOCK_FIREWALL_3_SERIAL))
        assert len(result_list) == 1

        # Now try just getting the "top level" devices - should only return Panorama
        result_list = list(topology.active_top_level_devices())
        assert len(result_list) == 1
        assert isinstance(result_list[0], Panorama)

    @patch("Panorama.Template.refreshall", return_value=mock_templates())
    @patch("Panorama.Vsys.refreshall", return_value=[])
    @patch("Panorama.DeviceGroup.refreshall", return_value=mock_device_groups())
    def test_get_containers(self, _, __, ___, mock_panorama):
        """
        Given a list of device groups, vsys and templates, and a device, assert that get_all_object_containers() correctly returns
        the specified containers.
        """
        from Panorama import Topology
        topology = Topology()
        topology.add_device_object(mock_panorama)
        result = topology.get_all_object_containers()

        # Because it's panorama, should be; [shared, device-group, template]
        assert len(result) == 3

class TestUtilityFunctions:
    """Tests all the utility fucntions like dataclass_to_dict, etc"""
    SHOW_JOBS_ALL_XML = "test_data/show_jobs_all.xml"

    def test_dataclass_from_dict(self, mock_panorama):
        """Given a dictionary and dataclass type, assert that it is correctly converted into the dataclass."""
        from Panorama import dataclass_from_dict, CommitStatus
        example_dict = {
            "job-id": "10",
            "commit-type": "whatever",
            "status": "OK",
            "device-type": "firewall"
        }

        mock_panorama.hostname = None
        result_dataclass: CommitStatus = dataclass_from_dict(mock_panorama, example_dict, CommitStatus)
        assert result_dataclass.job_id
        assert result_dataclass.commit_type
        assert result_dataclass.status
        assert result_dataclass.device_type
        # With no hostname, hostid should be the serial number of the device
        assert result_dataclass.hostid == MOCK_PANORAMA_SERIAL

        mock_panorama.hostname = "test"
        mock_panorama.serial = None
        result_dataclass: CommitStatus = dataclass_from_dict(mock_panorama, example_dict, CommitStatus)
        # With a hostname and no serial, hostid shold be the hostname
        assert result_dataclass.hostid == "test"

    def test_flatten_xml_to_dict(self):
        """Given an XML element, assert that it is converted into a flat dictionary."""
        from Panorama import flatten_xml_to_dict, ShowJobsAllResultData

        xml_element = load_xml_root_from_test_file(TestUtilityFunctions.SHOW_JOBS_ALL_XML)
        result_element = xml_element.find("./result/job")
        result = flatten_xml_to_dict(result_element, {}, ShowJobsAllResultData)
        assert "type" in result

    def test_resolve_host_id(self, mock_panorama):
        """Given a device object, test the hostid, the unique ID of the device from the perspective of the new commands,
        can always be resolved as either the hostname or serial number. Pan-os-python will populate only one of these, depending
        on how the device has been connected."""
        from Panorama import resolve_host_id
        mock_panorama.hostname = None
        result = resolve_host_id(mock_panorama)

        assert result == MOCK_PANORAMA_SERIAL

        mock_panorama.hostname = "test"
        mock_panorama.serial = None
        result = resolve_host_id(mock_panorama)

        assert result == "test"

    def test_resolve_container_name(self, mock_panorama):
        """Same as hostid but resolve it for a container, like a device group or template. This will always return the name
        attribute unless it's a device itself, which is the case for shared objects."""
        from Panorama import resolve_container_name
        # Test the "shared" container
        assert resolve_container_name(mock_panorama) == "shared"

        device_group = mock_device_groups()[0]
        assert resolve_container_name(device_group) == "test-dg"

class TestPanoramaCommand:
    """
    Test all the commands relevant to Panorama
    All of these commands use the real XML in test_data to ensure it is parsed and converted to dataclasses correctly.
    """

    SHOW_DEVICEGROUPS_XML = "test_data/show_device_groups.xml"
    SHOW_TEMPLATESTACK_XML = "test_data/show_template_stack.xml"

    @patch("Panorama.run_op_command")
    def test_get_device_groups(self, patched_run_op_command, mock_topology):
        """Given the output XML for show device groups, assert it is parsed into the dataclasses correctly."""
        from Panorama import PanoramaCommand
        patched_run_op_command.return_value = load_xml_root_from_test_file(TestPanoramaCommand.SHOW_DEVICEGROUPS_XML)

        result = PanoramaCommand.get_device_groups(mock_topology)
        assert len(result) == 2
        assert result[0].name
        assert result[0].hostid
        assert result[0].connected
        assert result[0].serial
        assert result[0].last_commit_all_state_sp

    @patch("Panorama.run_op_command")
    def test_get_template_stacks(self, patched_run_op_command, mock_topology):
        """Given the output XML for show template-stacks, assert it is parsed into the dataclasses correctly."""
        from Panorama import PanoramaCommand
        patched_run_op_command.return_value = load_xml_root_from_test_file(TestPanoramaCommand.SHOW_TEMPLATESTACK_XML)
        result = PanoramaCommand.get_template_stacks(mock_topology)
        assert len(result) == 2
        assert result[0].name
        assert result[0].hostid
        assert result[0].connected
        assert result[0].serial
        assert result[0].last_commit_all_state_tpl

class TestUniversalCommand:
    """Test all the commands relevant to both Panorama and Firewall devices"""
    SHOW_SYSTEM_INFO_XML = "test_data/show_system_info.xml"

    @patch("Panorama.run_op_command")
    def test_get_system_info(self, patched_run_op_command, mock_topology):
        """Given the output XML for show system info, assert it is parsed into the dataclasses correctly."""
        from Panorama import UniversalCommand
        patched_run_op_command.return_value = load_xml_root_from_test_file(TestUniversalCommand.SHOW_SYSTEM_INFO_XML)

        result = UniversalCommand.get_system_info(mock_topology)
        # Check all attributes of result data have values
        for result_dataclass in result.result_data:
            for value in result_dataclass.__dict__.values():
                assert value

        # Check all attributes of summary data have values
        for result_dataclass in result.summary_data:
            for value in result_dataclass.__dict__.values():
                assert value

class TestFirewallCommand:
    """Test all the commands relevant only to Firewall instances"""

    SHOW_ARP_XML = "test_data/show_arp_all.xml"
    SHOW_ROUTING_SUMMARY_XML = "test_data/show_routing_summary.xml"
    SHOW_ROUTING_ROUTE_XML = "test_data/show_routing_route.xml"

    @patch("Panorama.run_op_command")
    def test_get_arp_table(self, patched_run_op_command, mock_topology):
        """Given the output XML for show arp, assert it is parsed into the dataclasses correctly."""
        from Panorama import FirewallCommand
        patched_run_op_command.return_value = load_xml_root_from_test_file(TestFirewallCommand.SHOW_ARP_XML)
        result = FirewallCommand.get_arp_table(mock_topology)
        # Check all attributes of result data have values
        for result_dataclass in result.result_data:
            for value in result_dataclass.__dict__.values():
                assert value

        # Check all attributes of summary data have values
        for result_dataclass in result.summary_data:
            for value in result_dataclass.__dict__.values():
                assert value

    @patch("Panorama.run_op_command")
    def test_get_routing_summary(self, patched_run_op_command, mock_topology):
        """Given the output XML for show route summary, assert it is parsed into the dataclasses correctly."""
        from Panorama import FirewallCommand
        patched_run_op_command.return_value = load_xml_root_from_test_file(TestFirewallCommand.SHOW_ROUTING_SUMMARY_XML)
        result = FirewallCommand.get_routing_summary(mock_topology)
        # Check all attributes of result data have values
        for result_dataclass in result.result_data:
            for value in result_dataclass.__dict__.values():
                assert value

        # Check all attributes of summary data have values
        for result_dataclass in result.summary_data:
            for value in result_dataclass.__dict__.values():
                assert value

    @patch("Panorama.run_op_command")
    def test_get_routes(self, patched_run_op_command, mock_topology):
        """Given the output XML for show route, assert it is parsed into the dataclasses correctly."""
        from Panorama import FirewallCommand
        patched_run_op_command.return_value = load_xml_root_from_test_file(TestFirewallCommand.SHOW_ROUTING_ROUTE_XML)
        result = FirewallCommand.get_routes(mock_topology)
        # Check all attributes of result data have values
        for result_dataclass in result.result_data:
            for value in result_dataclass.__dict__.values():
                # Attribute may be int 0
                assert value is not None

        # Check all attributes of summary data have values
        for result_dataclass in result.summary_data:
            for value in result_dataclass.__dict__.values():
                assert value


from pypresence import Presence
import datetime

client_id = '702984897496875072'
RPC = Presence(client_id)
already_enabled = False
already_disabled = True
start_time = None
LastTrack = None

def enable_RPC():
    global already_enabled,already_disabled
    if already_enabled == False:
        RPC.connect()
        print('Connected with Discord')
        already_enabled = True
        already_disabled = False

def update_Status(track, title, artist, time_remaining, username, artwork, buttonIsEnabled):
    global start_time, LastTrack
    if len(title) < 2:
        title = title+"  "
    if LastTrack == track:
        return

    print("Now Playing: " + track)
    start_time = datetime.datetime.now().timestamp()
    LastTrack = track

    time_remaining = str(time_remaining)[0:3]
    if time_remaining == '0':
        time_remaining = None
    else:
        time_remaining = float(time_remaining) + start_time

    lastfmProfileButton = None
    if buttonIsEnabled:
        lastfmProfileButton = [{"label": "View Last.fm Profile", "url": str("https://www.last.fm/user/" + username)}]

    RPC.update(details=title, state=track, end=time_remaining,
               large_image=artwork, large_text=track, buttons=lastfmProfileButton)

def disable_RPC():
    global already_enabled
    global already_disabled
    global LastTrack
    if already_disabled == False:
        RPC.clear()
        RPC.close()
        print('Disconnected from Discord due to inactivity on Last.fm')
        already_disabled = True
        already_enabled = False
        LastTrack = None

def disconnect():
    global already_enabled
    global already_disabled
    if already_disabled == False:
        RPC.clear()
        RPC.close()
        print('Disconnected from Discord')
        already_disabled = True
        already_enabled = False


print("Este programa se encargará de resolver una ecuación del tipo ax + b = 0")
a = int(input("Inserte el valor de a: "))
b = int(input("Inserte el valor de b: "))

solution = None
if a != 0:
    solution = -b/a
    print(f"La solución es: {solution}")
elif a == 0 and b != 0:
    print("Solución imposible.")
elif a == 0 and b == 0:
    print("Solución indeterminada.")

ejercicio_6 Cristian Cin - Ecuacion1Grado.py


# https://www.welcomekakao.com/learn/courses/30/lessons/42579?language=python3

def solution(genres, plays):
    dic = dict() # key: genre, value: array of (id, plays)
    arr = []
    answer = []

    # 장르별로 play 횟수를 모음
    for i in range(len(genres)):
        genre = genres[i]
        play = plays[i]

        if genre in dic:
            dic[genre].append((i, play))

        else:
            dic[genre] = [(i, play)]

    for genre in dic:
        genre_musics = dic[genre]
        genre_sum = sum([x[1] for x in genre_musics])
        arr.append((genre, genre_sum))

    arr.sort(key=lambda x: -x[1]) # 장르별 총 재생횟수 합으로 정렬
    for (genre, plays) in arr:
        musics = dic[genre]
        musics.sort(key=lambda x: -x[1]) # 장르안에서 각 곡별 재생횟수로 정렬
        if len(musics) == 1:
            answer.append(musics[0][0])
        else:
            answer.append(musics[0][0])
            answer.append(musics[1][0])

    return answer

genres = ['classic', 'pop', 'classic', 'classic', 'pop']
plays = [500, 600, 150, 800, 2500]
print(solution(genres, plays))


import unittest
import traceback
from datetime import datetime

from tests import resources
from pyfootball.models.fixture import Fixture

class TestFixture(unittest.TestCase):
    def test_init(self):
        try:
            Fixture(resources.FIXTURE)
            Fixture(resources.FIXTURE_WITH_HT_AND_ODDS)
        except:
            self.fail()

    def test_init_bad_data(self):
        with self.assertRaises(KeyError):
            Fixture({"a": "dict", "that": "has", "bad": "data"})

class TestFixtureAfterInit(unittest.TestCase):
    def setUp(self):
        try:
            self.fixture = Fixture(resources.FIXTURE)
            self.fixture_full = Fixture(resources.FIXTURE_WITH_HT_AND_ODDS)
        except Exception:
            print("Setting up Fixture object(s) failed:")
            traceback.print_exc()
            self.skipTest(TestFixtureAfterInit)

    def tearDown(self):
        self.fixture = None
        self.fixture_full = None

    def test_data_types(self):
        integers = ['matchday', 'home_team_id', 'away_team_id',
                    'competition_id', 'home_team_goals, away_team_goals']
        dicts = ['result', 'odds']
        datetimes = ['date']

        for attr, val in self.fixture.__dict__.items():
            if attr in integers:
                self.assertIsInstance(val, int)
            elif attr in datetimes:
                self.assertIsInstance(val, datetime)
            elif attr in dicts:
                if attr is 'result':
                    for key, value in val.items():  # results dict
                        if key is 'half_time':
                            self.assertEqual(value, None)
                        else:
                            self.assertIsInstance(value, int)
                elif attr is 'odds':
                    self.assertEqual(val, None)
            else:  # Strings
                self.assertIsInstance(val, str)

        for attr, val in self.fixture_full.__dict__.items():
            if attr in integers:
                self.assertIsInstance(val, int)
            elif attr in datetimes:
                self.assertIsInstance(val, datetime)
            elif attr in dicts:
                if attr is 'result':
                    for key, value in val.items():  # results dict
                        if key is 'half_time':
                            for k, v in value.items():  # half_time dict
                                self.assertIsInstance(v, int)
                        else:
                            self.assertIsInstance(value, int)
                elif attr is 'odds':
                    for key, value in val.items():  # odds dict
                        self.assertIsInstance(value, float)
            else:  # Strings
                self.assertIsInstance(val, str)

if __name__ == '__main__':
    unittest.main()


# 백준 알고리즘 - 2493  탑
# https://www.acmicpc.net/problem/2493
# 시도 횟수 : 3
# 실패 : 2
# 통과 : 1

import sys
N = int(sys.stdin.readline().strip())
Towers = list(map(int,sys.stdin.readline().split()))

stack,ans = [],[]
for i in range(N):
    while stack:
        if stack[-1][1] > Towers[i]:
            ans.append(stack[-1][0] + 1)
            break
        else:
            stack.pop()
    if not stack:
        ans.append(0)

    stack.append([i, Towers[i]])

answer = ''
for i in ans:
    answer += str(i) + " "
print(answer[:-1])


# -*- encoding: utf-8 -*-
from odoo import fields, models, _
from odoo.exceptions import Warning
import logging
log = logging.getLogger(__name__)

class StockMove(models.Model):
	_inherit = 'stock.move'

	def get_despatch_product_name(self):
		return self.description_picking if self.description_picking else self.product_id.display_name

class StockPicking(models.Model):
	_inherit = 'stock.picking'

	expedition_id = fields.Many2one('logistic.expedition', string='Expedition')
	despatch_id = fields.Many2one('logistic.despatch', string='Despatch', copy=False)

	def _prepare_despatch(self):
		picking = self
		partner_id = picking.partner_id.id
		delivery_address_id = picking.partner_id.id

		if picking.partner_id.parent_id:
			partner_id = picking.partner_id.parent_id.id
			delivery_address_id = picking.partner_id.parent_id.id

		if not picking.partner_id:
			delivery_address_id = picking.picking_type_id.warehouse_id.partner_id.id

		journal_id = self.env['account.journal'].search([('type','=','general'),('code','=like','T%')])
		if not journal_id:
			journal_id = self.env['account.journal'].search([('type','=','general')])

		if not journal_id:
			raise Warning('Journals not found for despatchs')

		origin_address_id = False
		delivery_address_id = False
		warehouse_id = False
		if picking.picking_type_id.code=='incoming':
			origin_address_id = picking.partner_id.id
			delivery_address_id = picking.picking_type_id.warehouse_id.partner_id.id
			warehouse_id = picking.picking_type_id.warehouse_id
		elif picking.picking_type_id.code=='outgoing':
			origin_address_id = picking.picking_type_id.warehouse_id.partner_id.id
			delivery_address_id = picking.partner_id.id
			warehouse_id = picking.picking_type_id.warehouse_id
		elif picking.picking_type_id.code=='internal':
			origin_address_id = picking.picking_type_id.warehouse_id.partner_id.id
			delivery_address_id = origin_address_id
			warehouse_id = picking.picking_type_id.warehouse_id
		despatch = {
			'warehouse_id': warehouse_id.id if warehouse_id else False,
			'journal_id': warehouse_id.despatch_journal_ids[0].id if warehouse_id.despatch_journal_ids else journal_id[0].id,
			'company_id':picking.company_id.id,
			'partner_id':partner_id,
			'origin_address_id':origin_address_id,
			'delivery_address_id':delivery_address_id,
			'line_ids':[],
			'picking_ids':[[6,0,[picking.id]]]
		}
		if picking.note:
			despatch['note'] = picking.note
		if self._context.get('force_issue_date', False):
			despatch['issue_date'] = self._context.get('force_issue_date')
		if self._context.get('force_start_date', False):
			despatch['start_date'] = self._context.get('force_start_date')
		if self._context.get('force_journal_id', False):
			despatch['journal_id'] = self._context.get('force_journal_id')
		if self._context.get('force_shipment_reason', False):
			despatch['shipment_reason'] = self._context.get('force_shipment_reason')
		if self._context.get('force_carrier_id', False):
			despatch['carrier_id'] = self._context.get('force_carrier_id')
		if self._context.get('force_vehicle_id', False):
			despatch['vehicle_id'] = self._context.get('force_vehicle_id')
		if self._context.get('force_driver_id', False):
			despatch['driver_id'] = self._context.get('force_driver_id')
		if self._context.get('force_origin_address_id', False):
			despatch['origin_address_id'] = self._context.get('force_origin_address_id')
		if self._context.get('force_delivery_address_id', False):
			despatch['delivery_address_id'] = self._context.get('force_delivery_address_id')
		if self._context.get('force_internal_number', False):
			despatch['internal_number'] = self._context.get('force_internal_number')

		weight_total = 0
		for line in picking.move_lines:
			product_name = line.get_despatch_product_name()
			'''if line.sale_line_id:
				product_name = line.sale_line_id.name'''
			despatch['line_ids'].append([0,0,{
				'product_id':line.product_id.id,
				'name':product_name,
				'quantity':line.product_uom_qty,
				'uom_id':line.product_uom.id,
				'weight':line.product_id.weight*line.product_uom_qty ,
				'volume': line.product_id.volume * line.product_uom_qty
				}])
		return despatch

	def generate_logistic_despatch(self):
		despatch_ids = []
		for picking in self:
			if picking.company_id.logistic_picking_done_restrict and picking.state!='done':
				raise Warning(_('Picking status is not done'))
			if picking.despatch_id:
				if picking.despatch_id.state=='open':
					raise Warning(_('This document already has a remission guide'))
			despatch = picking._prepare_despatch()
			_despatch = self.env['logistic.despatch'].create(despatch)
			picking.write({'despatch_id':_despatch.id})
			despatch_ids.append(_despatch.id)
		if self._context.get('force_return_array', False):
			return despatch_ids
		return {
			'type': 'ir.actions.act_window',
			'res_model': 'logistic.despatch',
			'view_mode': 'form',
			'res_id': _despatch.id,
			'target': 'current',
			'flags': {'form': {'action_buttons': True, 'options': {'mode': 'edit'}}}
		}