import os
from os import path
import time
import math
from abc import ABC, abstractmethod

import pandas as pd
import numpy as np
import scipy as sp
from scipy.sparse import csr_matrix, lil_matrix
import dgl
import torch
import torch.nn as nn
import networkx as nx
from networkx.algorithms import bipartite

#from snore import SNoRe
#from node2vec import Node2Vec as N2V
import fastnode2vec as fn2v
from torch.nn.modules.distance import CosineSimilarity
# from surprise import Dataset as SpDataset
# from surprise import Reader as SpReader
# from surprise import NormalPredictor, SVD
import implicit
from tqdm import tqdm

from lib.gnns.GNNs_unsupervised import GNN

from spotify_graph import SpotifyGraph
from pinsage_training import PinSage, save_embeddings

class PredictionModel(ABC):
    """Base recommender class."""

    @abstractmethod
    def __init__(self):
        pass

    @abstractmethod
    def train(self, g, ids, train_set, test_set, features):
        pass

    @abstractmethod
    def knn(self, nodeset, k):
        pass

class EmbeddingModel(PredictionModel):
    """And embedding-based recommender."""

    @abstractmethod
    def embed(self, nodeset):
        pass

# --- HELPER METHODS ---

def cosine_sim_mat(batch, eps=1e-10):
    # given a batch of vectors (n*d), return n*n matrix of pairwise similaries
    n, d = batch.shape
    dot_prod = torch.mm( batch, batch.transpose(1, 0) )
    lengths = torch.norm(batch, dim=1)
    lengths_mat = lengths.unsqueeze(1).repeat((1, n))
    lengths_mul = lengths_mat * lengths_mat.transpose(1, 0)

    cosine_sim = dot_prod / lengths_mul
    return cosine_sim

def cosine_sim_ab(a, b, eps=1e-16):
    dot_prod = torch.mm(a, b.transpose(1, 0))
    a_lengths = torch.norm(a, dim=1)
    b_lengths = torch.norm(b, dim=1)
    lengths_mat = torch.mm(a_lengths.unsqueeze(1), b_lengths.unsqueeze(0))
    lengths_mat = lengths_mat + eps

    cosine_sim = dot_prod / lengths_mat
    return cosine_sim

def knn_from_emb_slow(emb, q, k, sim_func):
    w_list = []
    n_list = []
    for i,node in enumerate(q):
        sim = sim_func(emb[node, :].unsqueeze(0), emb)
        knn_w, knn_n = sim.topk(k+1, 0, largest=True)
        # now hope garbage collection gets rid of sim
        w_list.append(knn_w[1:])
        n_list.append(knn_n[1:])

    return torch.stack(w_list, 0), torch.stack(n_list, 0)

def knn_from_emb(emb, q, k, sim_func):
    w_list = []
    n_list = []
    b_size = 128
    for i in range(0, len(q), b_size):
        nodes = q[i:min(i+b_size, len(q))]
        q_batch = emb[nodes, :]
        cosine_sim = cosine_sim_ab(q_batch, emb)
        knn_w, knn_n = cosine_sim.topk(k+1, dim=1, largest=True)
        w_list.append(knn_w[:, 1:])
        n_list.append(knn_n[:, 1:])

    return torch.cat(w_list, dim=0), torch.cat(n_list, dim=0)

class PersPageRank(PredictionModel):
    """Nearest graph neighbors via PPR aka. random walks with restarts."""

    def __init__(self):
        self.n_hops = 1000
        self.alpha = 0.85

    def visit_prob(self, g, nodeset, n_hops, alpha):

        n_nodes = nodeset.shape[0]
        trace = torch.zeros(n_nodes, n_hops, dtype=torch.int64)

        for i in range(0, n_nodes):
            if i % 100 == 0:
                print(f"{i}/{n_nodes}")
            item = nodeset[i]
            for j in range(0, n_hops):
                neighbors = g.successors(item)
                rnd = torch.randint(len(neighbors), ())
                collection = neighbors[rnd]
                neighbors = g.successors(collection)
                rnd = torch.randint(len(neighbors), ())
                item = neighbors[rnd]

                trace[i, j] = item

                if torch.rand(()) < alpha:
                    item = nodeset[i]

        n_nodes = nodeset.shape[0]
        n_all_nodes = g.number_of_nodes()
        visit_counts = torch.zeros(n_nodes, n_all_nodes, dtype=torch.float64) \
            .scatter_add_(1, trace, torch.ones_like(trace, dtype=torch.float64))
        visit_prob = visit_counts / visit_counts.sum(1, keepdim=True) # or just /n_hops
        visit_prob[range(0, n_nodes), nodeset] = 0

        return visit_prob

    def train(self, g, ids, train_set, test_set, features):
        self.g = g
        # or we could precompute here

    def knn(self, nodeset, k):
        visit_prob = self.visit_prob(self.g, nodeset, self.n_hops, self.alpha)
        return visit_prob.topk(k, 1)

class SimpleSimilarity(PredictionModel):
    """Node similarity measures from network analysis."""

    def __init__(self, projected=True):
        self.func = None #a networkx similarity function
        self.projected = projected

    def train(self, g, ids, train_set, test_set, features):
        all_nodes = np.arange(0, len(ids))
        if self.projected:
            adj = project_bipartite_graph(all_nodes, dgl_g=g)
        else:
            adj = g.adj(scipy_fmt="csr")
        self.g = nx.from_scipy_sparse_array(adj)
        self.n = len(ids)

    def knn(self, nodeset, k):
        knn_list = []
        for q in nodeset:
            pairs = [(q.item(), n2) for n2 in range(0, self.n)]
            scores = self.func(self.g, pairs)
            knn_to_q = torch.tensor( [sc[2] for sc in scores] )
            knn_list.append(knn_to_q)
        return torch.stack(knn_list, dim=0).topk(k, dim=1)

class JaccardIndex(SimpleSimilarity):
    def __init__(self, projected=True):
        self.func = nx.preferential_attachment
        self.projected = projected

class AdamicAdar(SimpleSimilarity):
    def __init__(self, projected=True):
        self.func = nx.adamic_adar_index
        self.projected = projected

class Preferential(SimpleSimilarity):
    def __init__(self, projected=True):
        self.func = nx.preferential_attachment
        self.projected = projected

class JaccardFast(PredictionModel):

    def __init__(self):
        pass

    def train(self, g, ids, train_set, test_set, features):
        self.ids = ids
        self.n = len(ids)

        ctmat = to_col_track_matrix(g, ids)

        self.intersect_sizes = ctmat.transpose() * ctmat
        self.nbh_sizes = self.intersect_sizes.diagonal()
        n = ctmat.shape[1]

    def knn(self, nodeset, k):
        intersect_tensor = torch.from_numpy(self.intersect_sizes[nodeset, :].toarray())
        nbh_tensor = torch.from_numpy(self.nbh_sizes)
        nbh_nodeset_tensor = nbh_tensor[nodeset]
        a = nbh_nodeset_tensor.repeat((nbh_tensor.shape[0], 1)).transpose(1,0)
        b = nbh_tensor.unsqueeze(0).transpose(1, 0).repeat((1, nbh_nodeset_tensor.shape[0])).transpose(1,0)
        union_tensor = a + b - intersect_tensor
        scores = intersect_tensor / (union_tensor + 1e-10)

        topk_scores, topk_nodes = torch.topk(scores, k)
        return topk_scores[:, 1:], topk_nodes[:, 1:]

class FastNode2Vec(EmbeddingModel):
    """Node2vec random walk based node embedding."""

    def __init__(self, projected=True):
        self.model = None
        self.embedding = None
        self.sim_func = nn.CosineSimilarity(dim=1)
        self.projected = projected

    def train(self, g, ids, train_set, test_set, features):
        print("TRAINING NODE2VEC")
        all_nodes = np.arange(0, len(ids))
        if self.projected:
            adj = project_bipartite_graph(all_nodes, dgl_g=g)
        else:
            adj = g.adj(scipy_fmt="csr")
        nx_g = nx.from_scipy_sparse_array(adj)
        edges = [(e[0], e[1], e[2]["weight"]) for e in nx_g.edges(data=True)]
        self.g = fn2v.Graph(edges, directed=False, weighted=self.projected)
        self.model = fn2v.Node2Vec(self.g, dim=128, walk_length=20, context=10, p=2.0, q=0.5, workers=4)
        self.model.train(epochs=10)
        self.wv = self.model.wv
        vec_list = []
        for i in range(0, len(ids)):
            vector = self.wv.get_vector(i)
            vec_list.append(torch.tensor(vector))
        self.embedding = torch.stack(vec_list, dim=0)

    def embed(self, nodeset):
        return self.embedding[nodeset, :]

    def knn(self, nodeset, k):
        return knn_from_emb(self.embedding, nodeset, k, self.sim_func)

# class Snore(EmbeddingModel):
#     """Symbolic (explainable) random walk based node embedding."""

#     def __init__(self):
#         self.model = SNoRe(dimension=256, fixed_dimension=True)
#         self.embedding = None
#         self.sim_func = nn.CosineSimilarity(dim=1)

#     def train(self, g, ids, train_set, test_set, features):
#         adj = g.adj(scipy_fmt="csr")
#         sparse_emb = self.model.embed(adj)
#         print(sparse_emb.toarray().size)
#         self.embedding = torch.from_numpy(sparse_emb.toarray())[:len(ids), :]
#         print(self.embedding.shape)
#         #print(self.embedding[0:10,0:20])

#     def embed(self, nodeset):
#         return self.embedding[nodeset, :]

#     def knn(self, nodeset, k):
#         return knn_from_emb(self.embedding, nodeset, k, self.sim_func)

def _load_embeddings(ids, load_dir):
    emb_list = []
    pbar = tqdm(total=len(ids), desc="Loading embeddings")
    bsize = 1000
    for i, track_id in enumerate(ids):
        if i % bsize == 0:
            pbar.update(bsize)
            #print(f"{i}/{len(ids)}")
        load_path = os.path.join(load_dir, track_id + ".pt")
        emb_list.append(torch.load(load_path))

    embedding = torch.stack(emb_list, dim=0)
    pbar.close()
    return embedding

class EmbLoader(EmbeddingModel):
    """Load precomputed embeddings as a recommender method."""

    def __init__(self, load_dir):
        #self.load_dir = os.path.join(run_dir, "emb")
        self.load_dir = load_dir
        self.embedding = None
        self.sim_func = nn.CosineSimilarity(dim=1)

    def train(self, g, ids, train_set, test_set, features):
        print(f"Loading embeddings from {self.load_dir} ...")

        # emb_list = []
        # pbar = tqdm(total=len(ids), desc="Loading embeddings")
        # bsize = 1000
        # for i, track_id in enumerate(ids):
        #     if i % bsize == 0:
        #         pbar.update(bsize)
        #         #print(f"{i}/{len(ids)}")
        #     load_path = os.path.join(self.load_dir, track_id + ".pt")
        #     emb_list.append(torch.load(load_path))

        # self.embedding = torch.stack(emb_list, dim=0)
        # pbar.close()

        self.embedding = _load_embeddings(ids, self.load_dir)

    def embed(self, nodeset):
        return self.embedding[nodeset, :]

    def knn(self, nodeset, k):
        return knn_from_emb(self.embedding, nodeset, k, self.sim_func)

class PinSageWrapper(EmbeddingModel):
    """A wrapper for training PinSage with the same interface as baseline methods."""

    def __init__(self, train_params=None, run_name=None, log=True):
        self.embedding = None
        self.sim_func = nn.CosineSimilarity(dim=1)
        self.train_params = train_params if train_params else {}
        self.run_name = run_name if run_name else time.strftime("%X %x")
        self.log = log

    def train(self, g, ids, train_set, test_set, features):
        print("Training PinSage with parameters:")
        print(self.train_params)

        self.trainer = PinSage(g, len(ids), features, train_set, log=self.log, load_save=False)

        for param in self.train_params:
            exec(f"self.trainer.{param} = {self.train_params[param]}")
        self.trainer.run_name = self.run_name
        self.trainer.train()
        print("Embedding...")

        # HACK: save embeddings
        track_ids = ids
        n = len(track_ids)
        bsize = 256
        emb_dir = os.path.join("temp_runs", self.run_name, "emb")
        if not os.path.isdir(emb_dir):
            os.makedirs(emb_dir)
        for i in range(0, n, bsize):
            iids = torch.arange(i, min(i+bsize, n))
            emb = self.trainer.embed(iids)
            for id in iids:
                str_id = track_ids[id]
                save_path = os.path.join(emb_dir, str_id + ".pt")
                if os.path.isfile(save_path):
                    continue
                torch.save(emb[id-i, :].clone().detach(), save_path)

        self.embedding = _load_embeddings(ids, emb_dir)

    def embed(self, nodeset):
        return self.embedding[nodeset, :]

    def knn(self, nodeset, k):
        return knn_from_emb(self.embedding, nodeset, k, self.sim_func)

class Random(PredictionModel):
    """Gives random recommendations."""

    def __init__(self):
        pass

    def train(self, g, ids, train_set, test_set, features):
        self.ids = ids
        self.n = len(ids)

    def knn(self, nodeset, k):
        #nodes_list = torch.randint(0, self.n-1, size=(nodeset.shape[0], k))
        nodes_list = [torch.randperm(self.n)[0:k] for i in range(0, nodeset.shape[0])]
        nodes = torch.stack(nodes_list, dim=0)
        #print(nodes)
        weights = torch.ones_like(nodes)
        #print(weights)
        return weights, nodes

# --- MORE HELPER METHODS ---

def to_col_track_matrix(g, ids):
    n_tracks = len(ids)
    n_cols = len(g) - n_tracks

    #mat = np.zeros((n_cols, n_tracks))
    mat = lil_matrix((n_cols, n_tracks), dtype=np.int32)
    for col in range(n_tracks, n_tracks+n_cols):
        neighbors = list( set(g.successors(col)) | set(g.predecessors(col)) )
        neighbors = sorted(neighbors)
        mat[col-n_tracks, neighbors] = 1
    mat = mat.tocsr(copy=True)
    return mat

def to_track_track_matrix(ids, positives):
    n = len(ids)
    pos_tuples = [(positives[i, 0], positives[i, 1]) for i in range(positives.shape[0])]
    pos_tuples.sort(key=lambda x: x[1])
    mat = lil_matrix((n, n), dtype=np.int32)
    for (a, b) in pos_tuples:
        if mat[a, b]:
            mat[a, b] += 1
        else:
            mat[a, b] = 1
    mat = mat.tocsr(copy=True)
    return mat

def to_ratings_df(mat):
    ratings = []
    for col in range(mat.shape[0]):
        for tr in range(mat.shape[1]):
            if mat[col, tr] > 0:
                ratings.append({"userID": col, "itemID": tr, "rating": mat[col, tr]})
    #df = pd.DataFrame.from_dict(ratings, orient="index")
    df = pd.DataFrame(ratings)
    print("df built")
    return df

def project_bipartite_graph(bottom_nodes, dgl_g=None, nx_g=None, adj_mat=None):
    assert dgl_g or nx_g or adj_mat

    print("Projecting bipartite graph...")

    if dgl_g:
        adj_mat = dgl_g.adj(scipy_fmt="csr")
    elif nx_g:
        print(nx_g.nodes())
        adj_mat = nx.adjacency_matrix(nx_g)

    nx_graph = nx.from_scipy_sparse_array(adj_mat)
    proj_graph = bipartite.weighted_projected_graph(nx_graph, bottom_nodes)
    proj_adj_mat = nx.to_scipy_sparse_array(proj_graph, nodelist=None, format="csr")

    return proj_adj_mat

class TrackTrackCF(PredictionModel):
    """Matrix factorization of the track-track co-occurence matrix."""

    def __init__(self, algo="als", factors=128):
        #os.system("export OPENBLAS_NUM_THREADS=1")
        #os.system("export MKL_NUM_THREADS=1")
        self.algo = algo
        self.factors = factors

    def train(self, g, ids, train_set, test_set, features):
        self.ids = ids
        self.n = len(ids)

        ttmat = to_track_track_matrix(ids, train_set)

        if self.algo == "als":
            self.model = implicit.cpu.als.AlternatingLeastSquares(factors=self.factors)
        elif self.algo == "lmf":
            self.model = implicit.cpu.lmf.LogisticMatrixFactorization(factors=self.factors)
        else:
            self.model = implicit.cpu.bpr.BayesianPersonalizedRanking(factors=self.factors)

        self.model.fit(ttmat)

    def knn(self, nodeset, k):

        topn_nodes, topn_scores = self.model.similar_items(nodeset, N=k+1)
        #print(topn_scores)
        #print(topn_nodes)
        return torch.from_numpy(topn_scores)[:, 1:], torch.from_numpy(topn_nodes)[:, 1:]

class ColTrackCF(PredictionModel):
    """Matrix factorization of the playlist-track membership matrix."""

    def __init__(self, algo="als", factors=128):
        self.algo = algo
        self.factors = factors

    def train(self, g, ids, train_set, test_set, features):
        self.ids = ids
        self.n = len(ids)

        ctmat = to_col_track_matrix(g, ids)

        if self.algo == "als":
            self.model = implicit.cpu.als.AlternatingLeastSquares(factors=self.factors)
        elif self.algo == "lmf":
            self.model = implicit.cpu.lmf.LogisticMatrixFactorization(factors=self.factors)
        else:
            self.model = implicit.cpu.bpr.BayesianPersonalizedRanking(factors=self.factors)

        self.model.fit(ctmat)

    def knn(self, nodeset, k):

        topn_nodes, topn_scores = self.model.similar_items(nodeset, N=k+1)
        return torch.from_numpy(topn_scores)[:, 1:], torch.from_numpy(topn_nodes)[:, 1:]

class GraphSAGE(EmbeddingModel):
    """Unsupervised GraphSAGE GCN node embedding."""

    def __init__(self, projected=True):
        self.projected = projected

    def train(self, g, ids, train_set, test_set, features):
        self.ids = ids
        self.n = len(ids)

        all_nodes = np.arange(0, len(ids))
        self.features = features.clone().detach().numpy()

        if self.projected:
            adj = project_bipartite_graph(all_nodes, dgl_g=g)
        else:
            adj = g.adj(scipy_fmt="csr")

        self.model = GNN(self.proj_adj_mat, features=self.features, supervised=False, model="graphsage", device="cuda")
        self.model.fit()
        self.embedding = self.mode.generate_embeddings()

    def embed(self, nodeset):
        #nn.CosineSimilarity(dim=1)
        return torch.from_numpy(self.embedding[nodeset, :])

    def knn(self, nodeset, k):
        return knn_from_emb(self.embedding, nodeset, k, nn.CosineSimilarity(dim=1))

if __name__ == "__main__":

    dataset = SpotifyGraph("dataset_micro", None)
    g, track_ids, col_ids, features = dataset.to_dgl_graph()
    #pos = dataset.load_positives("dataset_small/positives_lfm_large.json")

    jaccard = JaccardFast()
    jaccard.train(g, track_ids, None, None, None)
    print(jaccard.knn([1,4,5,6,7,8,12,333], 3))


# 510. Maximal Rectangle
# 中文English
# Given a 2D boolean matrix filled with False and True, find the largest rectangle containing all True and return its area.
#
# 510. 最大矩形
# 中文English
# 给你一个二维矩阵，权值为False和True，找到一个最大的矩形，使得里面的值全部为True，输出它的面积

# Example
# Example 1
#
# Input:
# [
#   [1, 1, 0, 0, 1],
#   [0, 1, 0, 0, 1],
#   [0, 0, 1, 1, 1],
#   [0, 0, 1, 1, 1],
#   [0, 0, 0, 0, 1]
# ]
# Output: 6
# Example 2
#
# Input:
# [
#     [0,0],
#     [0,0]
# ]
# Output: 0

# 利用题 122 的直方图算法。
# 枚举每一行为直方图的底部，通过1确定每个柱形的高度。

class Solution:
    """
    @param matrix: a boolean 2D matrix
    @return: an integer
    """

    def maximalRectangle(self, matrix):
        if not matrix:
            return 0

        max_rectangle = 0
        heights = [0] * len(matrix[0])
        for row in matrix:
            for index, num in enumerate(row):
                heights[index] = heights[index] + 1 if num else 0
            max_rectangle = max(
                max_rectangle,
                self.find_max_rectangle(heights),
            )

        return max_rectangle

    def find_max_rectangle(self, heights):
        indices_stack = []
        max_rectangle = 0
        for index, height in enumerate(heights + [-1]):
            while indices_stack and heights[indices_stack[-1]] >= height:
                popped = indices_stack.pop(-1)
                left_bound = indices_stack[-1] if indices_stack else -1
                max_rectangle = max(
                    max_rectangle,
                    (index - left_bound - 1) * heights[popped],
                )
            indices_stack.append(index)
            print(indices_stack)

        return max_rectangle


from pyprojroot import here
from sklearn.metrics import roc_auc_score
from tqdm import tqdm, trange

from MIDAS import FilteringCore, NormalCore, RelationalCore

if __name__ == '__main__':
	prefix = here()  # Detect your project root
	pathData = prefix / 'data/DARPA/darpa_processed.csv'
	pathLabel = prefix / "data/DARPA/darpa_ground_truth.csv"
	pathScore = prefix / 'out/Score.txt'

	data = [[int(item) for item in line.split(b',')] for line in tqdm(pathData.read_bytes().splitlines(), 'Load Dataset', unit_scale=True)]
	label = list(map(int, pathLabel.read_bytes().splitlines()))
	midas = NormalCore(2, 1024)
	# midas = RelationalCore(2, 1024)
	# midas = FilteringCore(2, 1024, 1e3)
	score = [0.0] * len(label)
	for i in trange(len(label), desc=midas.nameAlg, unit_scale=True):
		score[i] = midas.Call(*data[i])
	print(f"ROC-AUC = {roc_auc_score(label, score):.4f}")
	print(f"# Raw scores will be exported to")  # Comment this line and below if you don't need to export
	print(f"# {prefix / 'out/Score.txt'}")
	pathScore.parent.mkdir(exist_ok=True)
	with pathScore.open('w', newline='\n') as file:
		for line in tqdm(score, 'Export Scores', unit_scale=True):
			file.write(f'{line}\n')
	pass


n = []
nn = []
nnn = []
for i in range(0, 3):
    ele = int(input('number: '))
    n.append(ele)

for i in range(0, len(n)):
    for j in range(i-1, len(n)):
        print(n[i])
        print(n[j])
        print('check')
        if n[i] < n[j]:
            print('found one')
            nn.append(n[i])
            break
        elif n[i] > n[j]:
            print('found one')
            nnn.append(n[i])
            break
print(nn)
print(nnn)


#This file does nothing but house the calc function
#this is good. If we need anything related to calc
#we know exactly where to look.
def calc(op,x,y):
    if(op == "sum"):
        return x + y
    elif(op == "mult"):
        return x * y

#Python also comes with it's owns modules
#That means, it has a "core" which is the stuff
#that automatically comes with the python command
    #variables
    #lists
    #print/loops
print(math.pi)

#python has a 3rd party module "package manager"
#called pip
    #pandas - is not part of core. It has to be installed
    #pygame - is not part of core. It has to be installed


from odoo import fields, models, api, _

class SaleOrder(models.Model):
    _inherit = "sale.order"

    state = fields.Selection(selection_add=[('stock_to_approve', 'Stock Confirmation'), ('draft',)], ondelete={'stock_to_approve': lambda recs: recs.write({'state': 'sale'})})
    was_stock_approved = fields.Boolean('Stock Approved', readonly=True, default=False)

    def needs_confirmation(self):
        """Check if the sale order needs to be approved"""
        if any(self.order_line.mapped('blocking')):
            return True
        return False

    def _block_sale_order(self):
        """Block the Sale Order and send a message to the Stock Managers"""
        self.state = 'stock_to_approve'
        odoobot_id = self.env['ir.model.data'].xmlid_to_res_id("base.partner_root")
        stock_managers = self.env.company.stock_warning_notify
        if stock_managers:
            for stock_manager in stock_managers:
                note = '
One or more of the products in this Sale Order ({}) has exceeded the limit on big sales.
' \
                       '
Lines are the following:
' \
                       '
'.format(self.name)
                for line in self.order_line.filtered(lambda r: r.blocking is True):
                    note += '
{} {} {}
'.format(line.name, line.product_uom_qty, line.product_uom.name)
                note += '
'
                self.env['mail.activity'].create({
                    'activity_type_id': self.env.ref('mail.mail_activity_data_warning').id,
                    'summary': 'Sale Order {} needs confirmation'.format(self.name),
                    'note': note,
                    'user_id': stock_manager.id,
                    'res_id': self.id,
                    'res_model_id': self.env.ref('sale.model_sale_order').id,
                    'automated': True,
                    'create_uid': odoobot_id,
                    'is_stock_confirmation': True,
                })
        else:
            for user in self.env.ref('stock.group_stock_manager').users:
                if user.partner_id:
                    channel_id = self.with_user(user.id).env['mail.channel'].search([('name', '=', 'OdooBot')], limit=1)
                    message = "
One or more of the products in this Sale Order ({}) has exceeded the limit on big sales.
" \
                              "However, at this moment there's no reposible assigned to manage this kind of situation, so the sale order will stay locked.
" \
                              "
Please, be ware that it's very important to set some responsible in Sales/Configuration/Settings/Warning/Create activity for solve this problem.
".format(self.name)
                    if not channel_id:
                        channel_id = self.env['mail.channel'].with_context({"mail_create_nosubscribe": True}).create({
                            'channel_partner_ids': [(4, odoobot_id, False), (4, user.partner_id.id, False)],
                            'public': 'private',
                            'channel_type': 'chat',
                            'email_send': False,
                            'name': 'OdooBot'
                        })
                    channel_id.sudo().message_post(body=message,
                                                   author_id=odoobot_id,
                                                   message_type="comment",
                                                   subtype_xmlid="mail.mt_comment")

    def warning_action_confirm(self):
        """Check if the sale order can be confirmed"""
        if self.needs_confirmation():
            self._block_sale_order()
            return False
        return self.action_confirm()

    @api.model
    def create(self, vals):
        """Check if the sale order needs confirmation before creating it"""
        sale = super(SaleOrder, self).create(vals)
        if sale.needs_confirmation():
            sale._block_sale_order()
        return sale

    def action_stock_approve(self):
        """Approve the sale order and set it's state to draft"""
        self.sudo().order_line.write({
            'blocking': False,
        })  # Sudo used here because maybe user doing this task doesn't have any permission on sale order or lines.
        stock_activity_ids = self.env['mail.activity'].search([('res_id', '=', self.id), ('res_model_id', '=', self.env.ref('sale.model_sale_order').id)])
        if stock_activity_ids:
            stock_activity_ids.action_done()
        self.sudo().write({'state': 'draft', 'was_stock_approved': True})

class SaleOrderLine(models.Model):
    _inherit = 'sale.order.line'

    blocking = fields.Boolean('Blocking')

    @api.onchange('product_uom_qty', 'product_uom')
    def _onchange_product_uom_qty(self):
        """Check the quantity as well as the product's uom in order to apply the limits"""
        res = super(SaleOrderLine, self)._onchange_product_uom_qty()
        if self.product_id and self.product_id.type == 'product':
            need_check_warning = self.env['ir.config_parameter'].sudo().get_param('odoo_order_confirmation.percentage_warning')
            if need_check_warning:
                if self.product_id.uom_id.category_id.id in [1, 2]:  # Units and Weight
                    qty = self.product_uom_qty
                    if self.product_id.uom_id.category_id.id == 1:
                        ref_unit = self.env['uom.uom'].browse(1)
                        if self.product_uom.id != 1:  # Not Units, maybe Dozens or whatever
                            qty = self.product_uom._compute_quantity(qty, ref_unit)
                        limit = self.env['ir.config_parameter'].sudo().get_param('odoo_order_confirmation.units_onsale_warning')
                    else:
                        ref_unit = self.env['uom.uom'].browse(3)
                        if self.product_uom.id != 3:  # Not Kg, maybe g or whatever
                            qty = self.product_uom._compute_quantity(qty, ref_unit)
                        limit = self.env['ir.config_parameter'].sudo().get_param('odoo_order_confirmation.kg_onsale_warning')
                    if limit:
                        limit = float(limit)
                    if qty > limit:
                        message = _("Selling {} {} of {} exceeds the limit for this product, which is set to {} {}.\n\n"
                                    "If you save or confirm this sale order with the present amounts, it will remain blocked until one of the stock managers"
                                    " will confirm it.").format(self.product_uom_qty, self.product_uom.name, self.product_id.name, limit, ref_unit.name)
                        if res.get('warning', False) and res['warning'].get('message', False):
                            message += '\n\n' + res['warning'].get('message')
                        warning_mess = {
                            'title': _('Limit on SO quantities surpassed!'),
                            'message': message
                        }
                        self.blocking = True
                        return {'warning': warning_mess}

        self.blocking = False
        return res


import paho.mqtt.client as mqtt_cli
from random import uniform
import time

mqtt_broker = "mqtt.eclipseprojects.io"
client = mqtt_cli.Client("Temperature_Outside")
client.connect(mqtt_broker)

while True:
    number = uniform(10, 15)

    client.publish("temperature", number)

    print("Just published " + str(number) + " to Topic temperature")

    time.sleep(1)


import pymongo
import keys  # .gitgnored file
from bson.objectid import ObjectId

PAGESIZE = 25

def get_from_path(path_string, response):
    fields = path_string.split(".")

    for field in fields:
        response = response.get(field, None)
        if response is None:
            return response
    return response

def flatten(l, path):
    """Flattens a list of dicts into a list"""
    return [get_from_path(path, el) for el in l]

def get_connection():
    "Return mongodb connection"
    return pymongo.MongoClient(keys.mongodb_url)

def get_species_colors():
    """Get a dict with ncbi species name and color"""
    with get_connection() as connection:
        db = connection.get_database()
        species_col = db.species
        colors = {}
        for species in species_col.find():
            colors[species["organism"]] = species["color"]
    return colors

def get_species_plot_data(species_list, id_list, component="assemblatron"):
    """Get plot data for many samples using a list of Ids"""
    with get_connection() as connection:
        db = connection.get_database()
        samples = db.samples
        plot_data = {}
        id_list = list(map(lambda x: ObjectId(x), id_list))
        runs = list(db.runs.find({"type": "routine"}, {"samples": 1}))
        routine_ids = set()
        for run in runs:
            for sample in run["samples"]:
                routine_ids.add(sample["_id"])
        routine_list = list(routine_ids)
        res = list(db.samples.aggregate([
            {
                "$match": {
                    "_id": {"$in": routine_list, "$nin": id_list},
                    "properties.species": {"$in": species_list},
                    # NOTE change stamp structure from list to dict to keep only latest.
                    "stamps" : {"$elemMatch": {"name": "ssi_stamper", "value": "pass:OK"}}
                }
            },
            {
                "$lookup": {
                    "from": "sample_components",
                    "let": {"sample_id": "$_id"},
                    "pipeline": [
                        {"$match": {
                            "component.name": component,
                            "summary.bin_length_at_1x": {"$exists": True}
                        }},
                        {"$match": {
                            "$expr": {"$eq": ["$sample._id", "$$sample_id"]}
                        }
                        },
                        {"$project": {"summary.bin_length_at_1x": 1}},
                        {"$sort": {"_id": -1}},
                        {"$limit": 1}
                    ],
                    "as": "sample_components"
                }
            },
            {
                "$unwind": "$sample_components"
            },
            {
                "$group": {
                    "_id": "$properties.species",
                    "bin_coverage_at_1x": {"$push": "$sample_components.summary.bin_length_at_1x"}
                }
            }
        ]))
    return res

def check_run_name(name):
    with get_connection() as connection:
        db = connection.get_database()
        # Fastest.
        run = db.runs.find({"name": name}).limit(1).count(True)
    return run is not 0

def get_run_list():
    with get_connection() as connection:
        db = connection.get_database()
        # Fastest.
        runs = list(db.runs.find({"type": "routine"}, #Leave in routine
                                 {"name": 1,
                                  "_id": 0,
                                  "samples": 1}).sort([['name', pymongo.DESCENDING]]))
    return runs

def get_group_list(run_name=None):
    with get_connection() as connection:
        db = connection.get_database()
        if run_name is not None:
            run = db.runs.find_one(
                {"name": run_name},
                {
                    "_id": 0,
                    "samples._id": 1
                }
            )
            if run is None:
                run_samples = []
            else:
                run_samples = run["samples"]
            sample_ids = [s["_id"] for s in run_samples]
            groups = list(db.samples.aggregate([
                {
                    "$match": {
                        "_id": {"$in": sample_ids},
                    }
                },
                {
                    "$group": {
                        "_id": "$sample_sheet.group",
                        "count": {"$sum": 1}
                    }
                }
            ]))
        else:
            groups = list(db.samples.aggregate([
                {
                    "$group": {
                        "_id": "$sample_sheet.group",
                        "count": { "$sum":1 }
                    }
                }
            ]))

    return groups

def get_species_list(run_name=None):
    with get_connection() as connection:
        db = connection.get_database()
        if run_name is not None:
            run = db.runs.find_one(
                {"name": run_name},
                {
                    "_id": 0,
                    "samples._id": 1
                }
            )
            if run is None:
                run_samples = []
            else:
                run_samples = run["samples"]
            sample_ids = [s["_id"] for s in run_samples]
            species = list(db.samples.aggregate([
                {
                    "$match": {
                        "_id": {"$in": sample_ids}
                    }
                },
                {
                    "$group": {
                        "_id": "$properties.species",
                        "count": {"$sum": 1}
                    }
                },
                {
                    "$sort": {"_id": 1}
                }
            ]))
        else:
            species = list(db.samples.aggregate([
                {
                    "$group": {
                        "_id": "$properties.species",
                        "count": {"$sum": 1}
                    }
                },
                {
                    "$sort": {"_id": 1}
                }
            ]))

    return species

def get_qc_list(run_name=None):
    with get_connection() as connection:
        db = connection.get_database()
        if run_name is not None:
            run = db.runs.find_one(
                {"name": run_name},
                {
                    "_id": 0,
                    "samples._id": 1
                }
            )
            if run is None:
                run_samples = []
            else:
                run_samples = run["samples"]
            sample_ids = [s["_id"] for s in run_samples]
            qcs = list(db.sample_components.aggregate([
                {
                    "$match": {
                        "sample._id": {"$in": sample_ids},
                        #"status": "Success",
                        "component.name": "ssi_stamper"
                    }
                },
                {"$sort": {"sample._id": 1, "_id": 1}},
                {
                    "$group": {
                        "_id": "$sample._id",
                        "action": {"$last": "$summary.assemblatron:action"}
                    }
                },
                {
                    "$group": {
                        "_id": "$action",
                        "count": {"$sum": 1}
                    }
                },
                {
                    "$sort": {"_id": 1}
                }
            ]))
        else:
            runs = list(db.runs.find({"type": "routine"}, {"samples": 1}))
            sample_ids = set()
            for run in runs:
                for sample in run["samples"]:
                    sample_ids.add(sample["_id"])
            sample_list = list(sample_ids)
            qcs = list(db.samples.aggregate([
                {
                    "$match": {
                        "_id": {"$in": sample_list}
                    }
                },
                {
                    "$lookup": {
                        "from": "sample_components",
                        "let": {"sample_id": "$_id"},
                        "pipeline": [
                            {"$match": {
                                "component.name": "ssi_stamper",
                                "summary.assemblatron:action" : {"$exists" : True}
                                }},
                            { "$match": {
                                    "$expr": {"$eq": ["$sample._id", "$$sample_id"]}
                                }
                            },
                            {"$project": {"summary.assemblatron:action" : 1}},
                            {"$sort": {"_id": -1}},
                            {"$limit": 1}
                        ],
                        "as": "sample_components"
                    }
                },
                {
                    "$unwind": "$sample_components"
                },
                {
                    "$group": {
                        "_id": "$sample_components.summary.assemblatron:action",
                        "count": {"$sum": 1}
                    }
                },
                {
                    "$sort": {"_id": 1}
                }
            ]))

    return qcs

def filter_qc(db, qc_list, query):
    qc_query = [{"sample_components.summary.assemblatron:action": {"$in": qc_list}} ]
    if "Not checked" in qc_list:
        qc_query += [
            {"$and": [
                {"reads.R1": {"$exists": True}},
                {"$or": [
                    {"sample_components": {"$size": 0}}
                    # Should probably uncomment after Undetermined check is finished
                    # {"sample_components.status": {"$ne": "Success"}}
                ]}
            ]}
        ]
    if "skipped" in qc_list:
        qc_query += [
            {"sample_components.status": "initialized"}
        ]
        # Uncomment when we implement skipped for Undetermined
        # qc_query += [
        #     {"sample_components.status": "skipped"}
        # ]
    if "core facility" in qc_list:
        qc_query += [
            {"reads.R1": {"$exists": False}}
        ]

    result = db.samples.aggregate([
        {
            "$match": {"$and" :query},
        },
        {
            "$lookup": {
                "from": "sample_components",
                "let": {"sample_id": "$_id"},
                "pipeline": [
                    {
                        "$match": {
                            "$expr": {
                                "$and": [
                                    { "$eq" : ["$component.name", "ssi_stamper"]},
                                    {"$eq": ["$sample._id", "$$sample_id"]}
                                ]
                            }
                        }
                    }
                ],
                "as": "sample_components"
            }
        },
        {
            "$match": {"$or": qc_query}

        }
    ])
    return list(result)

def filter(projection=None, run_name=None,
           species=None, group=None, qc_list=None, samples=None):
    if qc_list == ["OK", "core facility", "supplying lab", "skipped", "Not checked"]:
        qc_list = None
    with get_connection() as connection:
        db = connection.get_database()
        query = []
        sample_set = set()
        if samples is not None:
            sample_set = {ObjectId(id) for id in samples}
            query.append({"_id": {"$in": list(sample_set)}})
        if run_name is not None and run_name != "":
            run = db.runs.find_one(
                {"name": run_name},
                {
                    "_id": 0,
                    "samples._id": 1
                }
            )
            if run is None:
                run_sample_set = set()
            else:
                run_sample_set = {s["_id"] for s in run['samples']}

            if len(sample_set):
                inter = run_sample_set.intersect(sample_set)
                query.append({"_id": {"$in": list(inter)}})
            else:
                query.append({"_id": {"$in": list(run_sample_set)}})
        if species is not None and len(species) != 0:
            if "Not classified" in species:
                query.append({"$or":
                    [
                        {"properties.species": None},
                        {"properties.species": {"$in": species}},
                        {"properties.species": {"$exists": False}}
                    ]
                })
            else:
                query.append({"properties.species": {"$in": species}})
        if group is not None and len(group) != 0:
            if "Not defined" in group:
                query.append({"$or":
                    [
                        {"sample_sheet.group": None},
                        {"sample_sheet.group": {"$in": group}},
                        {"sample_sheet.group": {"$exists": False}}
                    ]
                })
            else:
                query.append({"sample_sheet.group": {"$in": group}})

        if qc_list is not None and run_name is not None and len(qc_list) != 0:
            #pass
            query_result = filter_qc(db, qc_list, query)
        else:
            query_result = list(db.samples.find({"$and": query}, projection)
                            .sort([("properties.species", pymongo.ASCENDING), ("name", pymongo.ASCENDING)]))
        return query_result

def get_results(sample_ids):
    with get_connection() as connection:
        db = connection.get_database()
        return list(db.sample_components.find({
            "sample._id": {"$in": sample_ids},
            "summary": {"$exists": True},
            "status": "Success",
            "component.name": {"$ne": "qcquickie"} #Saving transfers
        }, {"summary": 1, "sample._id": 1, "component.name" : 1, "setup_date": 1}).sort([("setup_date", 1)]))

def get_sample_runs(sample_ids):
    with get_connection() as connection:
        db = connection.get_database()
        return list(db.runs.find({"samples": {"$elemMatch": {"_id": {"$in": sample_ids}}}}))

def get_read_paths(sample_ids):
    with get_connection() as connection:
        db = connection.get_database()
        return list(db.samples.find({"_id": {"$in": list(map(lambda x:ObjectId(x), sample_ids))}}, {"reads": 1, "name": 1}))

# Run_checker.py
def get_sample_component_status(run_name):
    with get_connection() as connection:
        db = connection.get_database()
        run = db.runs.find_one({"name": run_name})
        samples_ids = list(map(lambda x:x["_id"], run["samples"]))
        components_ids = list(map(lambda x: x["_id"], run["components"]))
        s_c_list = db.sample_components.find({
            "sample._id": {"$in": samples_ids},
            "component._id": {"$in": components_ids}
        })
        output = {}
        for s_c in s_c_list:
            sample = output.get(s_c["sample"]["name"], {})
            status = s_c["status"]
            if status == "Success":
                status_code = 2
            elif status == "Running":
                status_code = 1
            elif status == "initialized":
                status_code = 0
            elif status == "Failure":
                status_code = -1
            elif status == 'queued to run':
                status_code = 0
            else:
                status_code = float('nan')
            sample[s_c["component"]["name"]] = (status_code, status)
            output[s_c["sample"]["name"]] = sample
        return output

def get_species_QC_values(ncbi_species):
    with get_connection() as connection:
        db = connection.get_database()
        if ncbi_species != "default":
            return db.species.find_one({"ncbi_species": ncbi_species}, {"min_length": 1, "max_length": 1})
        else:
            return db.species.find_one({"organism": ncbi_species}, {"min_length": 1, "max_length": 1})


#-*- coding: utf-8 -*-

'''

문제
세준시에는 고층 빌딩이 많다. 세준시의 서민 김지민은 가장 많은 고층 빌딩이 보이는 고층 빌딩을 찾으려고 한다. 빌딩은 총 N개가 있는데, 빌딩은 선분으로 나타낸다. i번째 빌딩 (1부터 시작)은 (i,0)부터 (i,높이)의 선분으로 나타낼 수 있다. 고층 빌딩 A에서 다른 고층 빌딩 B가 볼 수 있는 빌딩이 되려면, 두 지붕을 잇는 선분이 A와 B를 제외한 다른 고층 빌딩을 지나거나 접하지 않아야 한다. 가장 많은 고층 빌딩이 보이는 빌딩을 구하고, 거기서 보이는 빌딩의 수를 출력하는 프로그램을 작성하시오.

입력
첫째 줄에 빌딩의 수 N이 주어진다. N은 50보다 작거나 같은 자연수이다. 둘째 줄에 1번 빌딩부터 그 높이가 주어진다. 높이는 1,000,000,000보다 작거나 같은 자연수이다.

출력
첫째줄에 문제의 정답을 출력한다.
'''

def ccw(x1,y1,x2,y2,x3,y3):
    temp = x1*y2+x2*y3+x3*y1
    temp = temp - y1*x2-y2*x3-y3*x1
    if (temp > 0):
        return 1
    elif (temp < 0):
        return -1
    else:
        return 0

# 빌딩 개수

buildingCount = input()

# 빌딩 높이
buildingHeight = raw_input().split()

i = 0
while buildingCount > i:
    buildingHeight[i] = int(buildingHeight[i])
    i = i + 1

ViewCountArr = []
i = 0
while buildingCount > i:
    now = buildingHeight[i]
    left = i-1
    right = i+1
    ViewCount = 0
    print(i,"===========")

    max = [0,0]
    while 0 <= left:
        if max[1] < buildingHeight[left]:
            max = [ left , buildingHeight[left] ]
            ViewCount = ViewCount + 1
            print("left",0,buildingHeight[left])
        elif ccw(i , buildingHeight[i] , max[0] , max[1] , left , buildingHeight[left]) == -1 and max[1] != buildingHeight[left]:
            ViewCount = ViewCount + 1
            print("left",1,buildingHeight[left])

        left = left - 1

    max = [0,0]
    while buildingCount-1 >= right:
        if max[1] < buildingHeight[right]:
            max = [ right , buildingHeight[right]]
            ViewCount = ViewCount + 1
            print("right",buildingHeight[right])
        elif ccw(i , buildingHeight[i] , max[0] , max[1] , right , buildingHeight[right]) == 1 and max[1] != buildingHeight[right]:
            ViewCount = ViewCount + 1
            print("right",buildingHeight[right])
        right = right + 1

    print(buildingHeight[i],"ViewCount : ",ViewCount)
    ViewCountArr.append(ViewCount)
    i = i + 1

max = 0
for data in ViewCountArr:
    if max < data:
        max = data

print(max)

# 1 5 3 2 6 3 2 6 4 2 5 7 3 1 5


from src.utils.Board import Board
from src.solver.grille_solver.BranchAndBound import GrilleBranchAndBound

b = Board('grille', 3)
for piece in b.pieces:
    print(piece.id, piece.position)
grille = GrilleBranchAndBound(3)
while not grille.solvable(grille.get_initial_list(b)):
    b = Board('grille', 3)
    for piece in b.pieces:
        print(piece.id, piece.position)
    grille = GrilleBranchAndBound(3)
initial, goal = grille.get_initial_goal(b)
grille.start(b)


import time
import numpy as np
import tflite_runtime.interpreter as tflite
from tflite_runtime.interpreter import load_delegate

# Replace 'model.tflite' with the path to your model file
model_path = '/home/mendel/safety-vision/model/model_edgetpu.tflite'

# Load the TFLite model and allocate tensors
interpreter = tflite.Interpreter(model_path, experimental_delegates=[load_delegate('libedgetpu.so.1')])
interpreter.allocate_tensors()

# Get input and output tensors
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

# Set up a sample input
input_shape = input_details[0]['shape']
input_data = np.array(np.random.random_sample(input_shape), dtype=np.uint8)

# Warm-up runs (optional)
for _ in range(5):
    interpreter.set_tensor(input_details[0]['index'], input_data)
    interpreter.invoke()

# Run the benchmark
num_runs = 50
start_time = time.time()

for _ in range(num_runs):
    interpreter.set_tensor(input_details[0]['index'], input_data)
    interpreter.invoke()

elapsed_time = time.time() - start_time

# Calculate the average inference latency
average_latency = elapsed_time / num_runs * 1000
print(f'Average inference latency for {num_runs} runs: {average_latency:.2f} ms')


import cv2
import argparse
import numpy as np

arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(arg_parser.parse_args())

# load the image and convert to grayscale
img = cv2.imread(args["image"])
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("Original", img)

# find all contours in the image and draw all contours on the image
# for OpenCV 3, the returned tuple is (image, contours, contour hierarchy)
(_, contours, _) = cv2.findContours(gray.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
clone = img.copy()
cv2.drawContours(clone, contours, contourIdx=-1, color=(0, 255, 0), thickness=2)
print("Found {} contours.".format(len(contours)))

cv2.imshow("All Contours", clone)
cv2.waitKey(0)

# re-clone the image and close all windows
clone = img.copy()
cv2.destroyAllWindows()

# loop over the contours individually and draw each of them
for (i, c) in enumerate(contours):
    print("Drawing contour #{}".format(i+1))
    cv2.drawContours(clone, [c], contourIdx=-1, color=(0, 255, 0), thickness=2)
    cv2.imshow("Single Contour", clone)
    cv2.waitKey(0)

# re-clone the image and close all windows
clone = img.copy()
cv2.destroyAllWindows()

# find external contours
(_, contours, _) = cv2.findContours(gray.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(clone, contours, contourIdx=-1, color=(0, 255, 0), thickness=2)
cv2.imshow("All Contours", clone)
cv2.waitKey(0)

# re-clone the image and close all windows
clone = img.copy()
cv2.destroyAllWindows()

# loop over the contours and apply masks
for c in contours:
    mask = np.zeros(gray.shape, dtype=np.uint8)
    cv2.drawContours(mask, [c], contourIdx=-1, color=255, thickness=-1)

    cv2.imshow("Image + Mask", cv2.bitwise_and(img, img, mask=mask))
    cv2.waitKey(0)


import random

def randomCoord(a,b):
    return random.randrange(0,a), random.randrange(0,b)

def genField(width, height, nmines):
    f = []
    for i in range(width):
        f.append([0 for x in range(height)])

    for m in range(nmines):
        x,y = randomCoord(width, height)
        while f[x][y] == 1:
            x,y = randomCoord(width, height)
        f[x][y] = 1
    return f

""" The coordinate plane increases downward (y) and to the right (x)
"""

def neighbors(x,y,width,height,f):
    n = []
    # Top Left
    if y > 0 and x > 0:
        n.append(f[x-1][y-1])
    else:
        n.append(None)
    # Top
    if y > 0:
        n.append(f[x][y-1])
    else:
        n.append(None)
    # Top Right
    if y > 0 and x < width-1:
        n.append(f[x+1][y-1])
    else:
        n.append(None)
    # Left
    if x > 0:
        n.append(f[x-1][y])
    else:
        n.append(None)
    # Right
    if x < width-1:
        n.append(f[x+1][y])
    else:
        n.append(None)
    # Bottom Left
    if x > 0 and y < height-1:
        n.append(f[x-1][y+1])
    else:
        n.append(None)
    # Bottom
    if y < height-1:
        n.append(f[x][y+1])
    else:
        n.append(None)
    # Bottom Right
    if x < width-1 and y < height-1:
        n.append(f[x+1][y+1])
    else:
        n.append(None)
    return n

w = 8
h = 10

f = genField(w,h,20)

print()

f[0][0] = 4

print(neighbors(0,0,w,h,f))

for l in f:
    print(l)


from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from flask_login import current_user, LoginManager

from app import config

login_manager = LoginManager()
login_manager.session_protection = "strong"

# We want to rate limit based on:
# - If the user is not logged in: request source IP
# - If the user is logged in: user_id
def __key_func():
    if current_user.is_authenticated:
        return f"userid:{current_user.id}"
    else:
        ip_addr = get_remote_address()
        return f"ip:{ip_addr}"

# Setup rate limit facility
limiter = Limiter(key_func=__key_func)

@limiter.request_filter
def disable_rate_limit():
    return config.DISABLE_RATE_LIMIT

# @limiter.request_filter
# def ip_whitelist():
#     # Uncomment line to test rate limit in dev environment
#     # return False
#     # No limit for local development
#     return request.remote_addr == "127.0.0.1"


import requests
from requests.adapters import HTTPAdapter, Retry

def get_response_from_generic_url(url: str, MaxRetries: int = 5) -> requests.Response:
    session = requests.Session()

    retries = Retry(total=MaxRetries,
                    backoff_factor=0.1,
                    status_forcelist=[ 500, 502, 503, 504 ],
                    raise_on_status=True,
                )

    session.mount('http://', HTTPAdapter(max_retries=retries))
    session.mount('https://', HTTPAdapter(max_retries=retries))
    session.cookies.set("gid", value="59aec12f3ade7fd1f103decf", domain="forums.warframe.com", path="/") # type: ignore
    session.cookies.set("ips4_noCache", value="1", domain="forums.warframe.com", path="/") # type: ignore

    try:
        return session.get(url, timeout=20)
    except Exception as e:
        raise Exception("HTTP failure for '{}'.".format(url)) from e


from multiprocessing import Process

import typer

from .rewind import rewind_audio
from .cleanup import schedule_cleanup
from .daemon import initiate_daemon

app = typer.Typer()

@app.command()
def daemon():
    initiate_daemon_process = Process(target=initiate_daemon, args=())
    initiate_cleanup_process = Process(target=schedule_cleanup, args=())
    initiate_daemon_process.start()
    initiate_cleanup_process.start()
    initiate_daemon_process.join()
    initiate_cleanup_process.join()

@app.command()
def rewind(minutes_to_backtrack: int):
    rewind_audio(minutes_to_backtrack)


import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import plotly.express as px

df_apps = pd.read_csv('apps.csv')

# [1] describe the dataframes
# >>> print(df_apps.describe())
# >>> print(df_apps.shape)
# (10841, 12)
# [1.1] take a random sample of 5 rows
# >>> print(df_apps.sample(5))

# [2] drop unnecessary columns
df_apps.drop(columns=['Last_Updated', 'Android_Ver'], axis=1, inplace=True)
# [2.1] clean from NaN values
df_apps.dropna(inplace=True)
# (9767, 10)
# [2.2] drop duplicates - subset defines the criteria for two entries being a duplicate
df_apps.drop_duplicates(subset=['App', 'Type', 'Price'], inplace=True)
# (8199, 10)

# [3] preliminary exploration
# [3.1] app with the highest ratings
highest_rating_apps = df_apps[df_apps['Rating'] == df_apps['Rating'].max()]
# >>> print(highest_rating_apps.shape)
# (271, 10)
# [3.2] apps with the largest file size
largest_apps = df_apps[df_apps['Size_MBs'] == df_apps['Size_MBs'].max()]
# >>> print(largest_apps.shape)
# (14, 10)
# [3.3] 50 most reviewed apps
most_reviewed = df_apps.nlargest(50, 'Reviews')
# print(most_reviewed[['App', 'Reviews']])
most_reviewed_paid = most_reviewed[most_reviewed['Type'] == 'Paid']
# >>> print(most_reviewed_paid.shape)
# (0, 10)
# top 50 most reviewed apps are free

# [4] visualize Ratings values in a pie-chart
ratings = df_apps.Content_Rating.value_counts()
chart = px.pie(labels=ratings.index,
               values=ratings.values,
               title='Content Rating',
               names=ratings.index,
               hole=0.6)
# ^ hole argument turns the pie chart into a donut chart
chart.update_traces(textposition='inside', textfont_size=15, textinfo='percent')
# ^ alternative: textinfo='label+percent'; textposition='outside'
# chart.show()

# [5] type conversion for the installations & price data
# [5.1] apps with over 1 billion installs and apps with 1 install
df_apps.Installs = df_apps.Installs.astype(str).str.replace(',', '')
df_apps.Installs = pd.to_numeric(df_apps.Installs)
bln_installs = df_apps[df_apps.Installs >= 1000000000]
# >>> print(bln_installs[['App', 'Installs']])
# >>> print(bln_installs.shape)
# (20, 10)
one_install = df_apps[df_apps.Installs == 1]
# >>> print(one_install[['App', 'Installs']])
# >>> print(one_install.shape)
# (3, 10)
# [5.2] top 20 most expensive apps
df_apps.Price = df_apps.Price.astype(str).str.replace('$', '')
df_apps.Price = pd.to_numeric(df_apps.Price)
# >>> print(df_apps.sort_values('Price', ascending=False).head(20))
# [5.3] remove apps more expensive than 250$ and create a revenue projection column
df_apps = df_apps[df_apps['Price'] < 250]
# >>> print(df_apps.sort_values('Price', ascending=False).head(5)[['App', 'Price']])
# # 2281  Vargo Anesthesia Mega App  79.99
# # 1407               LTC AS Legal  39.99
# # 2629           I am Rich Person  37.99
df_apps['Revenue_Estimate'] = df_apps.Installs.mul(df_apps.Price)
# >>> print(df_apps.sort_values('Revenue_Estimate', ascending=False)[:10][['App', 'Revenue_Estimate']])
# # 9220                      Minecraft        69900000.0
# # 8825                  Hitman Sniper         9900000.0
# # 7151  Grand Theft Auto: San Andreas         6990000.0

# [6] Analyze different app categories
# >>> print(df_apps.Category.nunique())
# # 33
# [6.1] top 10 categories
top_10_category = df_apps.Category.value_counts()[:10]
# >>> print(top_10_category)
# # FAMILY             1606
# # GAME                910
# # TOOLS               719
# # ...
bar = px.bar(x=top_10_category.index, y=top_10_category.values)
# bar.show()
# [6.2] group apps by category and sum the number of installations
category_installs = df_apps.groupby('Category').agg({'Installs': pd.Series.sum})
category_installs.sort_values('Installs', ascending=False, inplace=True)
# >>> print(category_installs)
h_bar = px.bar(x=category_installs.Installs,
               y=category_installs.index,
               orientation='h',
               title='Category Popularity', )

h_bar.update_layout(xaxis_title='Number of Downloads',
                    yaxis_title='Category')

# h_bar.show()

# [6.3] create a scatter plot to show number of apps and number of installs for different categories
cat_number = df_apps.groupby('Category').agg({'App': pd.Series.count})
cat_merged_df = pd.merge(cat_number, category_installs, on='Category', how='inner')
cat_merged_df.sort_values('Installs', ascending=False)

scatter = px.scatter(cat_merged_df,
                     x='App',
                     y='Installs',
                     title='Category Concentration',
                     size='App',
                     hover_name=cat_merged_df.index,
                     color='Installs')

scatter.update_layout(xaxis_title='Number of Apps (Lower=More Concentrated)',
                      yaxis_title='Installs',
                      yaxis=dict(type='log'))

# scatter.show()

# [7] extracting nested column data and .stack()
# >>> print(df_apps.Genres.value_counts().sort_values(ascending=True)[:5])
# Lifestyle;Pretend Play      1
# Strategy;Education          1
# Adventure;Education         1
# . . .
# [7.1] spit the strings on the semicolon and then .stack them
stack = df_apps.Genres.str.split(';', expand=True).stack()
# >>> print(f'We now have a single column with shape: {stack.shape}')
# We now have a single column with shape: (8564,)
num_genres = stack.value_counts()
# >>> print(f'Number of genres: {len(num_genres)}')
# Number of genres: 53
# [7.2] display the number of apps for each genre
genre_bar = px.bar(x=num_genres.index[:15],
                   y=num_genres.values[:15],
                   title='Top Genres',
                   hover_name=num_genres.index[:15],
                   color=num_genres.values[:15],
                   color_continuous_scale='Agsunset')

genre_bar.update_layout(xaxis_title='Genre',
                        yaxis_title='Number of Apps',
                        coloraxis_showscale=False)

# genre_bar.show()

# [8] grouped bar charts and box plots with plotly
# [8.1] make a split between paid and free apps
# >>> print(df_apps.Type.value_counts())
# # Free    7595
# # Paid     589
df_free_vs_paid = df_apps.groupby(['Category', 'Type'], as_index=False).agg({'App': pd.Series.count})
# >>> print(df_free_vs_paid.head())
#             Category  Type  App
# 0     ART_AND_DESIGN  Free   58
# 1     ART_AND_DESIGN  Paid    3
# 2  AUTO_AND_VEHICLES  Free   72
# 3  AUTO_AND_VEHICLES  Paid    1
# . . .
# [8.2] form a grouped bar chart
g_bar = px.bar(df_free_vs_paid,
               x='Category',
               y='App',
               title='Free vs Paid Apps by Category',
               color='Type',
               barmode='group')

g_bar.update_layout(xaxis_title='Category',
                    yaxis_title='Number of Apps',
                    xaxis={'categoryorder': 'total descending'},
                    yaxis=dict(type='log'))

# g_bar.show()

# [8.2] form a box chart to show number of installs of free versus paid apps
# compare the median number of installations
type_box = px.box(df_apps,
             y='Installs',
             x='Type',
             color='Type',
             notched=True,
             points='all',
             title='How Many Downloads are Paid Apps Giving Up?')

type_box.update_layout(yaxis=dict(type='log'))

# type_box.show()

# [8.3] display app revenue per category
df_paid_apps = df_apps[df_apps['Type'] == 'Paid']
rev_box = px.box(df_paid_apps,
                 x='Category',
                 y='Revenue_Estimate',
                 title='How Much Can Paid Apps Earn?')

rev_box.update_layout(xaxis_title='Category',
                  yaxis_title='Paid App Ballpark Revenue',
                  xaxis={'categoryorder': 'min ascending'},
                  yaxis=dict(type='log'))

# rev_box.show()

# [8.4] median price for a paid app by category
# >>> print(df_paid_apps.Price.median())
# # 2.99$
price_box = px.box(df_paid_apps,
                   x='Category',
                   y='Price',
                   title='Price per Category')

price_box.update_layout(xaxis_title='Category',
                        yaxis_title='Paid App Price',
                        xaxis={'categoryorder': 'max descending'},
                        yaxis=dict(type='log'))

price_box.show()


# (bez nizova,lista, mapa,...)
#
# Три аутомобила крећу са стартне позиције у тренуцима 0 ≤ t1 ≤ t2 ≤ t3 константним брзинама v1, v2 и
# v3. Приказати стартне бројеве аутомобила који су на водећој позицији у тренутку t (t ≥ 0). Ако ни један
# аутомобил још није кренуо, сва три су у водећој позицији.
#
# Улаз: Са стандардног улаза учитава се седам целих бројева, сваки у засебној линији t1, v1, t2, v2, t3, v3, t где
# t1, t2, t3, t представљају времена у секундама, а v1, v2, v3 брзине у метрима по секунди.
#
# Излаз: На стандардни излаз исписати један или више целих бројева (сваки у посебном реду)
# који представљају редне бројеве аутомобила (1, 2 или 3) који су на водећој позицији.
# Ако је више аутомобила истовремено у вођству, њихове редне бројеве исписати у растућем редоследу.

# Пример
# Улаз
# 10
# 5
# 5
# 4
# 0
# 2
# 30
# Излаз
# 1
# 2

t1 = int(input("Unesi vreme prvog vozila: "))
v1 = int(input("Unesi brzinu prvog vozila: "))
t2 = int(input("Unesi vreme drugog vozila: "))
v2 = int(input("Unesi brzinu drugog vozila: "))
t3 = int(input("Unesi vreme treceg vozila: "))
v3 = int(input("Unesi brzinu treceg vozila: "))

t = int(input("Unesi kontrolno vreme: "))

def vreme(t, tx):
    if t <= tx:
        return t
    else:
        return tx

poz1 = v1 * vreme(t, t1)
k3 = 3

if v2 * vreme(t, t2) > poz1:
    poz2 = poz1
    poz1 = v2 * vreme(t, t2)
    k1 = 2
    k2 = 1
else:
    poz2 = v2 * vreme(t, t2)
    k1 = 1
    k2 = 2

if v3 * vreme(t, t3) > poz1:
    poz2 = poz1
    poz1 = v3 * vreme(t, t3)
    k3 = k2
    k2 = k1
    k1 = 3
elif v3 * vreme(t, t3) > v2 * vreme(t, t2):
    k3 = k2
    k2 = 3
else:
    k3 = 3

print(k1)
print(k2)
print(k3)


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import torch.nn as nn
import logging
from torch.nn import functional as tf

def finitialize_msra(modules, small=False):
    logging.info("Initializing MSRA")
    for layer in modules:
        if isinstance(layer, nn.Conv2d):  # convolution: bias=0, weight=msra
            nn.init.kaiming_normal_(layer.weight)
            if small:
                layer.weight.data.mul_(0.001)
            if layer.bias is not None:
                nn.init.constant_(layer.bias, 0)

def finitialize_xavier(modules, small=False):
    logging.info("Initializing Xavier")
    for layer in modules:
        if isinstance(layer, nn.Conv2d):  # convolution: bias=0, weight=msra
            nn.init.xavier_normal_(layer.weight)
            if small:
                layer.weight.data.mul_(0.001)
            if layer.bias is not None:
                nn.init.constant_(layer.bias, 0)

def make_conv(inchannels, outchannels, kernel_size, stride, nonlinear=True):
    padding = kernel_size // 2
    if nonlinear:
        return nn.Sequential(
            nn.Conv2d(
                inchannels, outchannels, kernel_size=kernel_size, padding=padding, stride=stride, bias=True),
            nn.ReLU()
        )
    else:
        return nn.Conv2d(
            inchannels, outchannels, kernel_size=kernel_size, padding=padding, stride=stride, bias=True)

class AllConvNetProbOut(nn.Module):
    def __init__(self, args, initialize_msra=False):
        super(AllConvNetProbOut, self).__init__()

        self.conv1   = make_conv(3, 96, kernel_size=3, stride=1)
        self.conv1_1 = make_conv(96, 96, kernel_size=3, stride=1)
        self.conv1_2 = make_conv(96, 96, kernel_size=3, stride=2, nonlinear=False)
        self.dropout1 = nn.Dropout(0.5)
        self.conv2   = make_conv( 96, 192, kernel_size=3, stride=1)
        self.conv2_1 = make_conv(192, 192, kernel_size=3, stride=1)
        self.conv2_2 = make_conv(192, 192, kernel_size=3, stride=2, nonlinear=False)
        self.dropout2 = nn.Dropout(0.5)
        self.conv3   = make_conv(192, 192, kernel_size=3, stride=1)
        self.conv3_1 = make_conv(192, 192, kernel_size=1, stride=1)
        self.conv3_2_mu = make_conv(192,  10, kernel_size=1, stride=1, nonlinear=False)
        self.conv3_2_vr = make_conv(192,  10, kernel_size=1, stride=1, nonlinear=False)

        if initialize_msra:
            finitialize_msra(self.modules(), small=False)
            finitialize_msra([self.conv3_2_vr], small=True)
        else:
            finitialize_xavier(self.modules(), small=False)
            finitialize_xavier([self.conv3_2_vr], small=True)

    def forward(self, example_dict):
        x = example_dict["input1"]

        x = self.conv1(x)
        x = self.conv1_1(x)
        x = self.conv1_2(x)
        x = self.dropout1(x)
        x = self.conv2(x)
        x = self.conv2_1(x)
        x = self.conv2_2(x)
        x = self.dropout2(x)
        x = self.conv3(x)
        x = self.conv3_1(x)
        mu = self.conv3_2_mu(x)
        log_vr = self.conv3_2_vr(x)

        variance = tf.softplus(log_vr)
        batch_size = x.size(0)
        mu = mu.contiguous().view(batch_size, 10, -1).mean(dim=2)
        variance = variance.contiguous().view(batch_size, 10, -1).mean(dim=2)

        return {"mean1": mu, "variance1": variance }


# matplotlib
# 파이썬에서 데이터과학 관련 시각화 패키지

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

# %matplotlib inline # 주피터노트북에서 show() 호출없이도
                     # 그래프를 그릴 수 있게 해줌
data = np.arange(10)
plt.plot(data)
# plt.show()

# 산점도 - 100의 표준정규분포 난수 생성
list = []
for i in range(100):           # 0 ~ 99
    x = np.random.normal(0, 1) # 표준정규분포 난수
    y = x + 0.1 + 0.2 + np.random.normal(0, 1)
    list.append([x, y])

# print(list)

x_data = [ v[0] for v in list ]
y_data = [ v[1] for v in list ]

plt.plot(x_data, y_data, 'ro')
# plt.show()

# 성적데이터 읽어오기
df = pd.read_excel('D:/빅데이터/data/pdf/빅데이터/데이터분석통계/data/sungjuk.xlsx')
# xlrd 패키지 설치 필요! - 엑셀 파일을 읽어 dataframe 으로 생성

# 총점, 평균 게산후 df 에 추가
subj = ['국어', '영어', '수학', '과학']
df['총점'] = df[subj].sum(axis = 1)
df['평균'] = df['총점'] / len(subj)
df.sort_values(['평균'], ascending = [False]) # 평균으로 정렬

import matplotlib as mpl
# font_name = mpl.font_manager.FontProperties(
#     fname = 'c:/windows/fonts/malgun.ttf').get_name()
# mpl.rc('font', family = font_name) # 그래프 한글 설정

mpl.rc('font', family = 'Malgun Gothic') # 그래프 한글 설정

sj = df.sort_values(['평균'], ascending=[False])
sj.index = sj['이름']
sj['평균'].plot(kind = 'bar', figsize = (8, 4))

# 성적 비교 - 어느 반이 잘했나?
ban1 = df[df['반'] == 1]
ban2 = df[df['반'] == 2]
ban1_mean = ban1['총점'].sum() / (len(ban1) * 4)
ban2_mean = ban2['총점'].sum() / (len(ban2) * 4)
print(ban1_mean, ban2_mean) # 79.042 vs 77.125

# 두집단 간의 평균은 유의미하게 차이 나는것인가? (t검증)
# p-value 값이 0.005 이하일때 - 차이가 난다고 할 수 있음
import scipy.stats as stats
result = stats.ttest_ind(ban1['평균'], ban2['평균'])
print(result) # pvalue = 0.755583336185639

# 그럼, 과목별 평균은 차이가 나는가? (t검증)
for sub in subj:
    print(sub, stats.ttest_ind(ban1[sub], ban2[sub]))

# 국어 pvalue=0.031982494983816424
# 영어 pvalue=0.5518533781528807
# 수학 pvalue=0.1654958420079056
# 과학 pvalue=0.0014931977711732465

# 전체 성적데이터에 대한 그래프 출력
sj.plot(kind = 'bar', figsize = (10, 6))

# 과목별 점수 분포 - 박스수염 그래프 작정
df[subj].boxplot(return_type='axes')

# 일반, 이반 과목별 점수 분포
ban1[subj].boxplot(return_type = 'axes') # 일반
ban2[subj].boxplot(return_type = 'axes') # 이반

# 과목별 상관관계 - '수학:과학' 과 '국어:영어'
df.plot(kind='scatter', x='수학', y='과학')
print(stats.pearsonr( df['수학'], df['과학'] ) ) # 피어슨 상관계수
# 0.5632890597067751(상관계수), 0.05650580486155532(p검증값)

df.plot(kind='scatter', x='국어', y='영어')
print(stats.pearsonr( df['국어'], df['영어'] ) ) # 피어슨 상관계수
# 0.10566562777973997(상관계수), 0.7437959551857836(p검증값)


import pandas as pd
import os
import pickle
from lightgbm import LGBMClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import recall_score

# noinspection PyUnresolvedReferences
from ML_Pipeline.categorical_encoder import CategoricalEncoder
# noinspection PyUnresolvedReferences
from ML_Pipeline.feature_extraction import AddFeatures

def data_split(df, target_variable, size, seed):
    """
        df: dataframe
        target_variable: target feature name
        size: test size ratio
        seed: random state
    """
    try:
        X = df.drop(target_variable, axis=1)
        y = df[target_variable].values
        x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=size, random_state=seed)
    except Exception as e:
        print('Error in model_training.data_split function', e)
    else:
        return x_train, x_test, y_train, y_test

def training_model_pipeline(x_train, x_test, y_train, y_test):
    try:
        lgbm_model = LGBMClassifier(boosting_type='dart', num_leaves=45, max_depth=6,
                                    learning_rate=0.1, n_estimators=90, class_weight={0: 1, 1: 3},
                                    min_child_samples=20, colsample_bytree=0.6, reg_alpha=0.3,
                                    reg_lambda=1.0, n_jobs=-1, importance_type='gain', force_col_wise=True)

        lgbm_model_pipeline = Pipeline(steps=[('Feature_Encoding', CategoricalEncoder()),
                                              ('Feature_Extraction', AddFeatures()),
                                              ('classifiers', lgbm_model)
                                              ]
                                       )

        # Fit pipeline with training data
        lgbm_model_pipeline.fit(x_train, y_train)

        # Random Forest Classification Models
        RF_model = RandomForestClassifier(max_depth=7, max_features=5, min_samples_leaf=10, min_samples_split=25,
                                          n_estimators=40,
                                          class_weight='balanced', random_state=1)

        rf_model_pipeline = Pipeline(steps=[('Feature_Encoding', CategoricalEncoder()),
                                            ('Feature_Extraction', AddFeatures()),
                                            ('classifiers', RF_model)
                                            ]
                                     )

        # Fit pipeline with training data
        rf_model_pipeline.fit(x_train, y_train)

        # Decision Tree Classification Model
        dt_model = DecisionTreeClassifier(class_weight='balanced', criterion='entropy', max_depth=10,
                                          min_samples_leaf=24, min_samples_split=9)

        dt_model_pipeline = Pipeline(steps=[('Feature_Encoding', CategoricalEncoder()),
                                            ('Feature_Extraction', AddFeatures()),
                                            ('classifiers', dt_model)
                                            ]
                                     )

        # Fit pipeline with training data
        dt_model_pipeline.fit(x_train, y_train)

        models = [
            ('lightGBM', lgbm_model_pipeline),
            ('random_forest_classification', rf_model_pipeline),
            ('decision_tree', dt_model_pipeline)
        ]

        output_df = pd.DataFrame()
        columns_for_comparison = ['Model', 'Training_Recall', 'Test_Recall', 'Diff b/w Train & Test Score']

        for name, model in models:
            # Model training
            model.fit(x_train, y_train)
            y_prediction_training = model.predict(x_train)
            y_prediction_test = model.predict(x_test)

            # Evaluating Models - On Recall Scores
            training_recall = recall_score(y_train, y_prediction_training)
            test_recall = recall_score(y_test, y_prediction_test)

            difference_train_test = (training_recall - test_recall)/training_recall

            # comparison dataframe
            metrics_score = [name, training_recall, test_recall, difference_train_test]
            score_dict = dict(zip(columns_for_comparison, metrics_score))
            df_score = pd.DataFrame([score_dict])
            output_df = pd.concat([output_df, df_score], ignore_index=True)

        print(output_df.sort_values(by=['Training_Recall', 'Test_Recall'], ascending=False))

        # Saving model to disk for prediction
        filename = '../output/BankingCustomerChurnPrediction.pkl'
        os.makedirs(os.path.dirname(filename), exist_ok=True)
        with open(filename, 'wb+') as f:
            pickle.dump(rf_model_pipeline, f)

    except Exception as e:
        print('Error in model_training.model_evaluation function', e)
    else:
        return models, output_df


# 特征金字塔：FPN
import numpy as np
import torch.nn as nn
import torch.nn.functional as F
import math
import torch
from torch.nn import Softmax, Conv2d, Parameter
from torch.autograd import Variable

class PAFEM(nn.Module):
    def __init__(self, dim, in_dim):
        super(PAFEM, self).__init__()
        self.down_conv = nn.Sequential(nn.Conv2d(dim, in_dim, 3, padding=1), nn.BatchNorm2d(in_dim),
                                       nn.PReLU())
        down_dim = in_dim // 2

        self.conv1 = nn.Sequential(
            nn.Conv2d(in_dim, down_dim, kernel_size=1), nn.BatchNorm2d(down_dim), nn.PReLU()
        )

        self.conv2 = nn.Sequential(
            nn.Conv2d(in_dim, down_dim, kernel_size=3, dilation=2, padding=2), nn.BatchNorm2d(down_dim), nn.PReLU()
        )
        self.query_conv2 = Conv2d(in_channels=down_dim, out_channels=down_dim // 8, kernel_size=1)
        self.key_conv2 = Conv2d(in_channels=down_dim, out_channels=down_dim // 8, kernel_size=1)
        self.value_conv2 = Conv2d(in_channels=down_dim, out_channels=down_dim, kernel_size=1)
        self.gamma2 = Parameter(torch.zeros(1))

        self.conv3 = nn.Sequential(
            nn.Conv2d(in_dim, down_dim, kernel_size=3, dilation=4, padding=4), nn.BatchNorm2d(down_dim), nn.PReLU()
        )
        self.query_conv3 = Conv2d(in_channels=down_dim, out_channels=down_dim // 8, kernel_size=1)
        self.key_conv3 = Conv2d(in_channels=down_dim, out_channels=down_dim // 8, kernel_size=1)
        self.value_conv3 = Conv2d(in_channels=down_dim, out_channels=down_dim, kernel_size=1)
        self.gamma3 = Parameter(torch.zeros(1))

        self.conv4 = nn.Sequential(
            nn.Conv2d(in_dim, down_dim, kernel_size=3, dilation=6, padding=6), nn.BatchNorm2d(down_dim), nn.PReLU()
        )
        self.query_conv4 = Conv2d(in_channels=down_dim, out_channels=down_dim // 8, kernel_size=1)
        self.key_conv4 = Conv2d(in_channels=down_dim, out_channels=down_dim // 8, kernel_size=1)
        self.value_conv4 = Conv2d(in_channels=down_dim, out_channels=down_dim, kernel_size=1)
        self.gamma4 = Parameter(torch.zeros(1))

        self.conv5 = nn.Sequential(
            nn.Conv2d(in_dim, down_dim, kernel_size=1), nn.BatchNorm2d(down_dim), nn.PReLU()
            # 如果batch=1 ，进行batchnorm会有问题
        )

        self.fuse = nn.Sequential(
            nn.Conv2d(5 * down_dim, in_dim, kernel_size=1), nn.BatchNorm2d(in_dim), nn.PReLU()
        )
        self.softmax = Softmax(dim=-1)

    def forward(self, x):
        x = self.down_conv(x)
        conv1 = self.conv1(x)
        conv2 = self.conv2(x)
        m_batchsize, C, height, width = conv2.size()
        proj_query2 = self.query_conv2(conv2).view(m_batchsize, -1, width * height).permute(0, 2, 1)
        proj_key2 = self.key_conv2(conv2).view(m_batchsize, -1, width * height)
        energy2 = torch.bmm(proj_query2, proj_key2)
        attention2 = self.softmax(energy2)
        proj_value2 = self.value_conv2(conv2).view(m_batchsize, -1, width * height)
        out2 = torch.bmm(proj_value2, attention2.permute(0, 2, 1))
        out2 = out2.view(m_batchsize, C, height, width)
        out2 = self.gamma2 * out2 + conv2
        conv3 = self.conv3(x)
        m_batchsize, C, height, width = conv3.size()
        proj_query3 = self.query_conv3(conv3).view(m_batchsize, -1, width * height).permute(0, 2, 1)
        proj_key3 = self.key_conv3(conv3).view(m_batchsize, -1, width * height)
        energy3 = torch.bmm(proj_query3, proj_key3)
        attention3 = self.softmax(energy3)
        proj_value3 = self.value_conv3(conv3).view(m_batchsize, -1, width * height)
        out3 = torch.bmm(proj_value3, attention3.permute(0, 2, 1))
        out3 = out3.view(m_batchsize, C, height, width)
        out3 = self.gamma3 * out3 + conv3
        conv4 = self.conv4(x)
        m_batchsize, C, height, width = conv4.size()
        proj_query4 = self.query_conv4(conv4).view(m_batchsize, -1, width * height).permute(0, 2, 1)
        proj_key4 = self.key_conv4(conv4).view(m_batchsize, -1, width * height)
        energy4 = torch.bmm(proj_query4, proj_key4)
        attention4 = self.softmax(energy4)
        proj_value4 = self.value_conv4(conv4).view(m_batchsize, -1, width * height)
        out4 = torch.bmm(proj_value4, attention4.permute(0, 2, 1))
        out4 = out4.view(m_batchsize, C, height, width)
        out4 = self.gamma4 * out4 + conv4
        conv5 = F.upsample(self.conv5(F.adaptive_avg_pool2d(x, 1)), size=x.size()[2:],
                           mode='bilinear')  # 如果batch设为1，这里就会有问题。

        return self.fuse(torch.cat((conv1, out2, out3, out4, conv5), 1))

if __name__ == '__main__':
    ts = torch.Tensor(16, 3, 64, 64)
    vr = Variable(ts)
    net = PAFEM(dim=3, in_dim=3)
    print(net)


import math
import numpy as np
from paths import *

class Economics:

    def __init__(self,input,policy,optimize):
        self.__InputSetter = input
        self.__Policy = policy
        self.__Optimize = optimize
        self.PV = self.__InputSetter.PV
        self.Battery = self.__InputSetter.Battery
        self.__IRR = None
        self.__NPV = None
        self._autarky = None
        self._selfConsumption = None
        self._avoidedNetworkFees= None
        self._isOptimizeYear=False
        self._set_economic_parameters_from_file()

    def _set_economic_parameters_from_file(self, path=None):
        ''' reads PV parameter from file in Path and updates attributes '''
        if path is None:
            path = gen_Path(path_parameters)
        parameters = read_parameters(path)['Economics']
        self.__discount = float(parameters['discount'])
        self.__lifetime = int(parameters['lifetime'])
        self._invest_PV =float(parameters['invest_PV'])
        self._invest_Bat = float(parameters['invest_Bat'])
        self.__oAndM_PV = float(parameters['oAndM_PV'])
        self.__oAndM_Bat = float(parameters['oAndM_Bat'])
        self.__VAT = float(parameters['VAT'])
        self.__scalingFactorPV = float(parameters['scalingFactorPV'])
        self.__scalingFactorBattery = float(parameters['scalingFactorBattery'])
        self.__optimizationForesightHours=int(parameters['optimizationForesightHours'])

    def __pvInitialCost(self):
        ''' Calculates initial cost of PV '''
        if self.PV.size == 0:
            initialCostperKW = 0
        else:
            initialCostperKW = self._invest_PV * (self.PV.size / 10) ** self.__scalingFactorPV
        initialCostPV = self.PV.size * initialCostperKW
        return initialCostPV

    def __batteryInitialCost(self):
        ''' Calculates initial cost of Battery '''
        if self.Battery.size == 0:
            initialCostperKW = 0
        else:
            initialCostperKW = self._invest_Bat * (self.Battery.size / 10) ** self.__scalingFactorBattery
        initialCostBattery = self.Battery.size * initialCostperKW
        return initialCostBattery

    def _calculateAvoidedNetworkFees(self):
        ''' calculates avoided network fees'''
        if self.__Policy.isFixedNetworkCharges: #all capacity-based network charges are conserved
            avoidedNetworkFees = 0
            return avoidedNetworkFees

        elif self.__Optimize._optimizationStatus == 1: #BAU #TODO Enums
            selfProduced = self.__InputSetter.loadList - self.__Optimize.energyFromGridBAU
            avoidedNetworkFees = sum(selfProduced) * self.__Policy.networkCharge
            return avoidedNetworkFees
        elif self.__Optimize._optimizationStatus == 2:  #Non-BAU
            selfProduced = self.__InputSetter.loadList - self.__Optimize.sumEnergyFromGrid
            avoidedNetworkFees = sum(selfProduced) * self.__Policy.networkCharge
            return avoidedNetworkFees

    def _calculateNPV(self, discount=None):
        if discount is None:
            discount = self.__discount
        PV = self.__pvInitialCost()
        Bat = self.__batteryInitialCost()
        cost = (-PV - Bat) * self.__VAT   #initial investment in year 0
        logging.info('Net Present Value for {} years calculated'.format(self.__lifetime))
        if self.numOfCycles==0:
            batteryYear=100
        else:
            batteryYear = self.Battery.totalBatteryCycles / self.numOfCycles  # number of years to change battery.
            batteryYear = int(batteryYear)
        for year in range(1, int(self.__lifetime+1)):
            refYearCost = self.referenceTotal/math.pow(1.0+discount, year)
            if year == batteryYear:
                logging.warning('Battery is Changed')
                yearCost = self.revenueTotal - self.__oAndM_PV * PV - Bat * self.__VAT * self.Battery.replacementCostFactor
            else:
                yearCost = self.revenueTotal - self.__oAndM_PV * PV - self.__oAndM_Bat * Bat
            yearCost = yearCost/math.pow(1.0 + discount, year)
            cost += yearCost-refYearCost
        return cost

    def _calculateIRR(self):
        x0 = -0.05
        x1 = -0.2
        x2 = -1
        i = 0
        threshold = 0.5
        solDelta = 100 * threshold
        validRun = False
        for i in range(100):
            try:
                x2 = x1 - (x1 - x0) / (self._calculateNPV(discount=x1) -
                                       self._calculateNPV(discount=x0)) * self._calculateNPV(discount=x1)
                solDelta = self._calculateNPV(discount=x2)
                x0 = x1
                x1 = x2
                if (abs(solDelta) < threshold):
                    validRun=True
                    return x2
            except OverflowError:
                logging.warning("IRR Divergent")
                break
        if not validRun:
            return -0.25

    def _calculate_battery_counts(self):
        '''    calculates battery counts   '''
        tot = np.array(self.batteryTotal)
        tot1 = np.insert(tot, 0, self.Battery.initialBatteryCapacity)
        tot1 = np.delete(tot1, -1)
        diff = tot-tot1
        numOfCycles = 0
        z = 0
        for i in diff:
            z += abs(i)
            if z >= 2 * self.Battery.size:
                z = z - 2 * self.Battery.size
                numOfCycles += 1
        return numOfCycles

    def _calculate_CSC(self): #charging State Correlator
        ''' calculates system friendliness indicator. After optimization of existing case the arbitrage case is optimized for entire year'''
        day=self.__InputSetter.day
        self.__InputSetter.day = 1
        time = self.__InputSetter.timeDuration
        self.__InputSetter.timeDuration=8760
        self.__Optimize._optimize_arbitrage()
        if not self._isOptimizeYear:
            self.optimizeYear()
        arbitrageCharging = self._calculate_battery_state(self.__Optimize.energyStorageArbitrage)
        optimizeCharging = self._calculate_battery_state(self.energyStorage)
        logging.info(
            'System Friendliness Indicator for Arbitrage and {} calculated '.format(self.__Optimize.optimizationState))
        assert len(arbitrageCharging) == len(optimizeCharging)
        diff = 1 - sum(
            (arbitrageCharging[i] - optimizeCharging[i]) ** 2 for i in range(len(arbitrageCharging))) / (
                       2 * len(arbitrageCharging))
        self.__InputSetter.timeDuration = time
        self.__InputSetter.day=day
        return diff

    def _calculate_MAI(self):
        day = self.__InputSetter.day
        self.__InputSetter.day = 1
        time = self.__InputSetter.timeDuration
        self.__InputSetter.timeDuration=8760
        self.__Optimize._optimize_arbitrage()
        if not self._isOptimizeYear:
            self.optimizeYear()
        self.welfareBattery=self.welfareBatteryPV-self.welfarePV-self.welfareConsumption
        self.welfareRef=np.dot(self.__Optimize.energyToGridArbitrage-self.__Optimize.energyFromGridArbitrage
                               ,self.__InputSetter.get_price_list(day=1, duration=8760))
        self.__InputSetter.timeDuration = time
        self.__InputSetter.day = day
        return self.welfareBattery/self.welfareRef

    def optimizeYear(self):
        self.revenueTotal=0
        self.referenceTotal=0
        self.batteryTotal=[]
        self.pvTotal=0
        self.fedin=0
        self.fromGrid=0
        self.consumptionYear=0
        self.totalDirectUse=0
        self.totalAvoidedNetworkFees=0
        self.maximumBATT=0
        self.deltaBattGrid=[]
        self.welfarePV = 0
        self.welfareConsumption = 0
        self.welfareBatteryPV = 0
        if not self.__Policy.isRTP and not self.__Policy.isVFIT: #BAU Case
            time=self.__InputSetter.timeDuration
            self.__InputSetter.timeDuration=8760
            self.__Optimize.optimize()
            self.revenueTotal=self.__Optimize.revenue
            self.referenceTotal=self.__Optimize.referenceRevenue
            self.totalAvoidedNetworkFees=self._calculateAvoidedNetworkFees()
            self.batteryTotal=self.__Optimize.energyStorage
            self.pvTotal=sum(self.__InputSetter.pvGenList)
            self.consumptionYear=sum(self.__InputSetter.loadList)
            self.welfarePV+=np.dot(self.__InputSetter.pvGenList,self.__InputSetter.get_price_list())
            self.welfareConsumption -= np.dot(self.__InputSetter.loadList, self.__InputSetter.get_price_list())
            self.welfareBatteryPV+=-np.dot(self.__Optimize.energyFromGridBAU,self.__InputSetter.get_price_list())+\
                np.dot(self.__Optimize.energyToGridBAU,self.__InputSetter.get_price_list())
            self.__InputSetter.timeDuration=time
        else:
            for d in range(1,366):
                self.__InputSetter.timeDuration=24
                self.__InputSetter.day=d
                self.__Optimize.optimize()
                self.deltaBattGrid.append(self.__Optimize.deltaBatt)
                self.fedin+=self.__Optimize.PVtoGrid
                self.fromGrid+=self.__Optimize.GridtoLoad
                self.revenueTotal+=self.__Optimize.revenue
                self.referenceTotal+=self.__Optimize.referenceRevenue
                self.batteryTotal+=(self.__Optimize.energyStorage)
                self.totalAvoidedNetworkFees+=self._calculateAvoidedNetworkFees()
                self.pvTotal+=sum(self.__InputSetter.pvGenList)
                self.consumptionYear+=sum(self.__InputSetter.loadList)
                self.welfarePV+=np.dot(self.__InputSetter.pvGenList,self.__InputSetter.get_price_list())
                self.welfareConsumption-=np.dot(self.__InputSetter.loadList, self.__InputSetter.get_price_list())
                self.welfareBatteryPV+=-np.dot(self.__Optimize.sumEnergyFromGrid,self.__InputSetter.get_price_list())+\
                np.dot(self.__Optimize.sumEnergyToGrid, self.__InputSetter.get_price_list())
            self.energyStorage=self.batteryTotal
        self.numOfCycles=self._calculate_battery_counts()
        self.revenueTotal-=self.__Policy.fixedCapacity
        self.referenceTotal-=self.__Policy.fixedCapacity

    def _calculate_battery_state(self,energyStorage):
        energyStorage = np.array(energyStorage)
        energyStorage = np.insert(energyStorage, 0, self.Battery.size)
        stateDiff = np.diff(energyStorage)
        for i in range(len(stateDiff)):
            stateDiff[i] = round(stateDiff[i], 3)
            if stateDiff[i] > 0:
                stateDiff[i] = 1
            elif stateDiff[i] < -self.Battery.selfDischarge * self.Battery.size * 1.05:
                stateDiff[i] = -1
            else:
                stateDiff[i] = 0
        return stateDiff


import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
from dash import dcc, html
from dashboard.layout.workflow import tab_workflow

from dashboard.index import app

@app.callback(Output("page-content", "children"), [Input("url", "pathname")])
def render_page_content(pathname):
    if pathname in ["/", "/1-intro"]:
        return html.P("Welcome, please navigate to the training page!")
    elif pathname == "/2-training":
        return tab_workflow
    else:
        # If the user tries to reach a different page, return a 404 message
        return dbc.Jumbotron(
            [
                html.H1("404: Not found", className="text-danger"),
                html.Hr(),
                html.P(f"The pathname {pathname} was not recognised..."),
            ]
        )


import click
import os
import vk.config as config
import vk.utils as utils

class RecordSession:

    def __init__(self, app_name):
        self.app_name = app_name

    def __enter__(self):
        self.old_global_layers = utils.get_debug_vulkan_layers()
        self.old_app_name = utils.get_gpu_debug_app()
        self.old_app_layers = utils.get_gpu_debug_layers()
        self.old_enable_app_layers = utils.get_enable_gpu_debug_layers()

        utils.enable_gpu_debug_layers(True)
        utils.set_debug_vulkan_layers(None)
        utils.set_gpu_debug_app(self.app_name)
        utils.set_gpu_debug_layers(['VK_LAYER_LUNARG_gfxreconstruct'])

    def __exit__(self, exc_type, exc_value, exc_tb):
        utils.set_debug_vulkan_layers(self.old_global_layers)
        utils.enable_gpu_debug_layers(self.old_enable_app_layers)
        utils.set_gpu_debug_app(self.old_app_name)
        utils.set_gpu_debug_layers(self.old_app_layers)

@click.command()
@click.argument('app_name', type=str, default='?')
@click.option('-f', '--filename', default='capture.gfxr', metavar='<trace_name>', help='Set trace name.')
@click.option('--pull', 'pull_folder', type=click.Path(), metavar='<local_folder>',
              help='Pull output files from device to <local_folder>.')
@click.option('--log', 'enable_log', is_flag=True, default=False, help='Write log messages.')
def record(app_name, filename, enable_log, pull_folder):
    """Record API trace of APP_NAME.

    \b
    APP_NAME could be set to:
        ? Select entity from prompt menu later
        ! Use last used APP_NAME
        Any other string

    \b
    >> Example 1: Launch com.foo.bar and then record a trace as test.gfxr.
    $ vk record -f test.gfxr com.foo.bar

    \b
    >> Example 2: Launch app from selection, and then record a trace as test.gfxr.
    $ vk record -f test.gfxr ?
    """
    app_name = config.get_valid_app_name(app_name)
    settings = config.GfxrConfigSettings(app_name)
    utils.stop_app(app_name)
    # utils.adb_cmd(f'shell am kill {app_name}')

    if not filename.endswith('gfxr'):
        filename = f'{filename}.gfxr'

    with RecordSession(app_name) as rec:
        settings.set_capture_options(filename, enable_log=enable_log)

        click.echo(f'Start recording {app_name}...')
        utils.create_folder_if_not_exists(settings.get_trace_folder_on_device())
        utils.start_app(app_name)
        utils.wait_until_app_launch(app_name)
        utils.wait_until_app_exit(app_name)

    click.echo('Finish recording {}'.format(settings.trace_path))

    if pull_folder:
        if not os.path.exists(pull_folder):
            os.makedirs(pull_folder)

        utils.adb_pull(settings.trace_path, pull_folder)
        if enable_log:
            utils.adb_pull(settings.log_path, pull_folder)

        click.echo(f'Finish copying output files to host: "{pull_folder}"')


from collections import deque

def solution(grid):
    k = 1
    n, m = len(grid), len(grid[0])
    if k >= n+m-3:
        return n+m-2

    q = deque([(0,0,k)])
    used = [[-1 for _ in range(m)] for _ in range(n)]

    step, sdist = 1, n + m - 2
    while q:
        dsdist = sdist
        for _ in range(len(q)):
            i, j, b = q.popleft()
            if used[i][j] > b: continue

            for i, j in (i-1, j), (i, j-1), (i, j+1), (i+1, j):
                if not (n > i >= 0 <= j < m): continue

                nb = b - grid[i][j]
                if used[i][j] >= nb: continue

                dist = n + m - i - j - 2
                if (dist-1 <= nb and dist == sdist-1): return step + dist + 1

                dsdist = min(dist, dsdist)
                q.append((i, j, nb))
                used[i][j] = nb

        sdist, step = dsdist, step + 1
    return -1

print(solution([[0,0,0],[1,1,0],[0,0,0],[0,1,1],[0,0,0]]))


import duckdb
import os
import pytest

def get_tables(con):
    tbls = con.execute("SHOW TABLES").fetchall()
    tbls = [x[0] for x in tbls]
    tbls.sort()
    return tbls

def test_multiple_writes():
    try:
        os.remove("test.db")
    except:
        pass
    con1 = duckdb.connect("test.db")
    con2 = duckdb.connect("test.db")
    con1.execute("CREATE TABLE foo1 as SELECT 1 as a, 2 as b")
    con2.execute("CREATE TABLE bar1 as SELECT 2 as a, 3 as b")
    con2.close()
    con1.close()
    con3 = duckdb.connect("test.db")
    tbls = get_tables(con3)
    assert tbls == ['bar1', 'foo1']
    del con1
    del con2
    del con3

    try:
        os.remove("test.db")
    except:
        pass

def test_multiple_writes_memory():
    con1 = duckdb.connect()
    con2 = duckdb.connect()
    con1.execute("CREATE TABLE foo1 as SELECT 1 as a, 2 as b")
    con2.execute("CREATE TABLE bar1 as SELECT 2 as a, 3 as b")
    con3 = duckdb.connect(":memory:")
    tbls = get_tables(con1)
    assert tbls == ['foo1']
    tbls = get_tables(con2)
    assert tbls == ['bar1']
    tbls = get_tables(con3)
    assert tbls == []
    del con1
    del con2
    del con3

def test_multiple_writes_named_memory():
    con1 = duckdb.connect(":memory:1")
    con2 = duckdb.connect(":memory:1")
    con1.execute("CREATE TABLE foo1 as SELECT 1 as a, 2 as b")
    con2.execute("CREATE TABLE bar1 as SELECT 2 as a, 3 as b")
    con3 = duckdb.connect(":memory:1")
    tbls = get_tables(con3)
    assert tbls == ['bar1', 'foo1']
    del con1
    del con2
    del con3

def test_diff_config():
    con1 = duckdb.connect("test.db", False)
    with pytest.raises(
        duckdb.ConnectionException,
        match="Can't open a connection to same database file with a different configuration than existing connections",
    ):
        con2 = duckdb.connect("test.db", True)
    con1.close()
    del con1


import plotly
import plotly.plotly as py
import plotly.graph_objs as go

# setup credientials file
plotly.tools.set_credentials_file(username='rebkey', api_key='Fvu85NRvro7m5kPgE4QQ')

trace0 = go.Scatter(
    x=[1, 2, 3, 4],
    y=[10, 15, 13, 17]
)
trace1 = go.Scatter(
    x=[1, 2, 3, 4],
    y=[16, 5, 11, 9]
)
data = [trace0, trace1]

py.plot(data, filename = 'basic-line')


#!/usr/bin/python2

from pypixel import *

import sys

show()

w, h = 200, 200
x, y = WIDTH/2, 0

v_y = 0.1
a_y = 1
while not (v_y == 0):
    ix = int(x)
    iy = int(y)
    ellipse(RED, ((ix, iy), (w, h)), center=True)
    update()
    ellipse(BLACK, ((ix, iy), (w, h)), center=True)
    y   += v_y
    v_y += a_y
    if y > HEIGHT:
        v_y *= -0.9
    if abs(v_y) < 0.05 and (HEIGHT - h) < y < HEIGHT:
        v_y = 0

pause()