import cv2
import numpy as np
import xml.etree.ElementTree as ET

def simple_show_mask(mask):
    '''
    简单显示mask
    :param mask:
    :return:
    '''
    _, mask_binary = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY)
    return mask_binary

def draw_mask_in_img(image, mask, draw_boundingRect=True,
                draw_minAreaRect=True,draw_contour=True):
    '''
    在原图上画mask的各种图形
    :param image: 原图
    :param mask: 预测图
    :param draw_boundingRect: 是否画bbox
    :param draw_minAreaRect: 是否画最小外接矩形
    :param draw_contour: 是否画轮廓
    :return: 画好的图
    '''
    height = image.shape[0]
    width = image.shape[1]
    mask = cv2.resize(mask, (width,height),cv2.INTER_NEAREST)
    _, mask_binary = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY)
    contours,hierarchy= cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    if len(contours)>0:
        for i in range(len(contours)):
            if draw_boundingRect:
                x, y, w, h = cv2.boundingRect(contours[i])
                xmin, ymin, xmax, ymax = x, y, x + w, y + h
                cv2.rectangle(image,(xmin,ymin),(xmax,ymax),(255,0,0),5)
            if draw_minAreaRect:
                rotated_rect = cv2.minAreaRect(contours[i])
                box = cv2.boxPoints(rotated_rect)
                box = np.int0(box)
                cv2.drawContours(image, [box], 0, (0, 255, 0), 5)
            if draw_contour:
                cv2.drawContours(image, contours, i, (0,0,255),5)
    return image

def crop_imgs(image, mask):
    '''
    根据预测，将原图像中的分割物体割出来
    :param image: 原图
    :param mask: 预测图
    :return: 分割后的小图
    '''
    height = image.shape[0]
    width = image.shape[1]
    mask = cv2.resize(mask, (width, height), cv2.INTER_NEAREST)
    _, mask_binary = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY)
    contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    num_contours = len(contours)
    rotated_img=[num_contours]
    for i in range(num_contours):
        rotated_rect = cv2.minAreaRect(contours[i])# 0为中心点坐标，1为宽高

        rect_max = int(rotated_rect[1][0]) if rotated_rect[1][0] > rotated_rect[1][1] else int(rotated_rect[1][1])
        rect_min = int(rotated_rect[1][1]) if rotated_rect[1][0] > rotated_rect[1][1] else int(rotated_rect[1][0])

        angle = rotated_rect[2] if abs(rotated_rect[2])<45 else (rotated_rect[2]+90)
        M = cv2.getRotationMatrix2D((int(rotated_rect[0][0]),int(rotated_rect[0][1])),angle,1)
        rotated_img[i] = cv2.warpAffine(image, M, (width,height))
        rotated_img[i] = cv2.getRectSubPix(rotated_img[i], (rect_max, rect_min),
                                        (int(rotated_rect[0][0]), int(rotated_rect[0][1])))
    return rotated_img

def seg_map_iou(image, mask, xml_path=None, png_path=None):
    '''
    单张图像分割效果评估，标注IOU
    :param image: 图像
    :param mask: 预测的mask
    :param xml_path: xml标注路径
    :param png_path: png标注路径
    :return:
    '''
    img_h = image.shape[0]
    img_w = image.shape[1]
    mask_h = mask.shape[0]
    mask_w = mask.shape[1]
    if not (img_h==mask_h and img_w==mask_w):
        mask = cv2.resize(mask, (img_w,img_h),interpolation=cv2.INTER_NEAREST)
    _, seg_mask = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY)
    truth_mask = []
    if xml_path:
        tree = ET.parse(xml_path)
        objs = tree.findall('object')
        truth_mask = np.zeros([img_h, img_w], dtype=np.uint8)
        for obj in objs:
            points_x = obj.find('polygen').find('points_x').text.split(',')
            points_y = obj.find('polygen').find('points_y').text.split(',')
            if points_x[-1] == '':
                point_num = len(points_x) - 1
            else:
                point_num = len(points_x)
            ps = np.zeros([point_num, 2], dtype=np.int32)
            for i in range(point_num):
                if points_x[i] == '':
                    continue
                ps[i] = (int(float(points_x[i])), int(float(points_y[i])))
            cv2.polylines(truth_mask, [ps], 1, 0, 1)  # img:图像,顶点集，是否闭合，颜色，线宽度
            cv2.fillPoly(truth_mask, [ps], 255)
    elif png_path:
        truth_mask = cv2.imdecode(np.fromfile(png_path,dtype=np.uint8),-1)
    else:
        print('没有标注')
    Union_mask = cv2.bitwise_or(truth_mask, seg_mask)
    Union_contours, hierarchy = cv2.findContours(Union_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    Union_area = 0
    if len(Union_contours) > 0:
        for i in range(len(Union_contours)):
            Union_area += cv2.contourArea(Union_contours[i])

    Intersection_mask = cv2.bitwise_and(truth_mask, seg_mask)
    Intersection_contours, hierarchy = cv2.findContours(Intersection_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    Intersection_area = 0
    if len(Intersection_contours) > 0:
        for i in range(len(Intersection_contours)):
            Intersection_area += cv2.contourArea(Intersection_contours[i])

    return float(Intersection_area)/Union_area


import re

from django.db import models
from django.urls import reverse
from django_extensions.db.fields import AutoSlugField
from easy_thumbnails.files import get_thumbnailer

class GlobalTags(models.Model):
    tags = models.TextField(
        blank=True,
        null=True,
        help_text='Tags to be added to every picture published on social '
        'media
'
        '(#AddHashes #ManuallyCapitaliseWords #AddSpacesBetweenTags)',
    )

    class Meta:
        verbose_name = "Global tags"
        verbose_name_plural = "Global tags"

    def __str__(self):
        return self.tags

class Tag(models.Model):
    tag = models.CharField(max_length=200)
    description = models.TextField(
        blank=True,
        null=True,
    )
    extra_tags = models.TextField(
        blank=True,
        null=True,
        help_text='Tags to be added to every picture in this category '
        'published on social media
'
        '(#AddHashes #ManuallyCapitaliseWords #AddSpacesBetweenTags)',
    )
    slug = AutoSlugField(populate_from='tag',
                         help_text='This is used as the URL for this tag',
                         unique=True,
                         overwrite=True,
                         max_length=200)

    def slugify_function(self, content):
        content = re.sub('[^0-9a-zA-Z ]+', '', content)
        content = content.title()
        content = content.replace(' ', '')
        return content

    def __str__(self):
        return self.tag

class PublishedPictureManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(published_date__isnull=False)

class Picture(models.Model):
    order = models.PositiveIntegerField(
        default=1000,
        help_text=(
            'The lower the number, the sooner this picture will be published'))
    title = models.CharField(max_length=200)
    slug = AutoSlugField(
        populate_from='title',
        help_text='This is used as the URL for this picture',
        max_length=200,
    )
    description = models.TextField(
        blank=True,
        null=True,
    )
    published_id = models.PositiveIntegerField(
        blank=True,
        null=True,
    )
    published_date = models.DateTimeField(
        blank=True,
        null=True,
    )
    tags = models.ManyToManyField(
        Tag,
        blank=True,
        help_text='Main categories used on website',
    )
    extra_tags = models.TextField(
        blank=True,
        null=True,
        help_text='Tags to be added to this picture when published on social '
        'media
'
        '(#AddHashes #ManuallyCapitaliseWords #AddSpacesBetweenTags)',
    )
    created_date = models.DateTimeField(auto_now_add=True)
    modified_date = models.DateTimeField(auto_now=True)

    # Managers
    objects = models.Manager()
    published_pictures = PublishedPictureManager()

    def get_url(self):
        return reverse(
            'picture-slug',
            kwargs={
                'id': self.published_id,
                'slug': self.slug,
            },
        )

    def get_tags(self):
        if GlobalTags.objects.first():
            global_tags = GlobalTags.objects.first().tags
        else:
            global_tags = ""

        tag_extra_tags = " ".join(tag.extra_tags for tag in self.tags.all()
                                  if tag.extra_tags is not None)
        picture_extra_tags = (self.extra_tags
                              if self.extra_tags is not None else "")
        picture_tags = " ".join(f"#{tag.slug}" for tag in self.tags.all()
                                if tag.slug is not None)

        return (f"{picture_tags} {tag_extra_tags} {picture_extra_tags}"
                f" {global_tags}").strip()

    def get_image(self):
        # generate a smaller image to avoid Twitter 5mb file limit
        thumbnailer = get_thumbnailer(self.image.image)
        thumbnail_options = {'size': (2000, 2000)}
        return thumbnailer.get_thumbnail(
            thumbnail_options,
            save=True,
            generate=True,
        )

    # Metadata
    class Meta:
        ordering = ['-published_id', 'order']

    def __str__(self):
        return self.title

class Image(models.Model):
    def get_upload_path(self, filename):
        id = self.picture_id
        return f"pictures/{id}/image/{filename}"

    picture = models.OneToOneField(
        Picture,
        on_delete=models.CASCADE,
        related_name='image',
    )
    image = models.ImageField(upload_to=get_upload_path)

    def __str__(self):
        return self.picture.title


"""Functions for generating multilayer and multiplex networks using various network models.
"""

##### Compatibility for Python 2/3
try:
    xrange
except NameError:
    xrange = range
######

from .net import MultilayerNetwork,MultiplexNetwork
import math,random

def single_layer_conf(net,degs,degstype="distribution"):
    """Generates a realization of configuration model network.

    Parameters
    ----------
    net : MultilayerNetwork with aspects=0
       Empty network object that is to be filled.
    degs : dict
       Degrees of the network. See degstype parameter.
    degstype : string
       If 'distribution', then degs parameter gives the degree distribution. I.e.,
       keys are degrees, and corresponding values are number of nodes with the given degree.
       If 'nodes', then degs parameter gives node degrees. I.e, keys are node names and
       corresponding values are degrees of those nodes.

    Notes
    -----
    The algorithm used here is similar to the one in article:
    B.D McKay, N.C Wormald 'Uniform Generation of Random Regular Graphs of Moderate Degree'
    Journal of Algorithms 11, pages 52-67 (1990)

    The difference between the algorithm presented in the article and the one in this
    function is that the random restarts are not implemented here. This means that the
    sampled networks are not exactly statistically uniform. However, if the degrees
    are small compared to the number of nodes the error is likely to be small.
    """
    stubs=[]
    selfedges={}
    multiedges=set()
    edgetoindex={}

    if degstype=="distribution":
        nstubs=sum(map(lambda x:x[0]*x[1],degs.items()))
        nodes=sum(degs.values())
        shuffled_node_indices=list(range(nodes))
        random.shuffle(shuffled_node_indices)
        node=0
        for k,num in degs.items():
            if k==0:
                for i in range(num):
                    net.add_node(shuffled_node_indices[node])
                    node+=1
            else:
                for i in range(num):
                    for j in range(k):
                        stubs.append(shuffled_node_indices[node])
                    node+=1
    elif degstype=="nodes":
        nstubs=sum(degs.values())
        nodes=len(degs)
        #for node,k in degs.iteritems():
        for node in degs:
            k=degs[node]
            for i in range(k):
                stubs.append(node)
            if k==0:
                net.add_node(node)
    else:
        raise Exception("Invalid degstype: '"+str(degstype)+"'")

    # Here we should do the Erdos-Gallai test
    assert nstubs%2==0
    assert (nodes*(nodes-1)) >= nstubs

    random.shuffle(stubs)

    for s in range(int(len(stubs)/2)):
        node1,node2=sorted([stubs[2*s],stubs[2*s+1]])

        edgetoindex[(node1,node2)]=edgetoindex.get((node1,node2),[])+[2*s]

        if net[node1,node2]!=0:
            multiedges.add((node1,node2))

        if node1==node2:
            selfedges[node1]=selfedges.get(node1,[])+[2*s]
        else:
            net[node1,node2]=1

    for node,sis in selfedges.items():
        for si in sis:
            repeat=True
            while repeat:
                #select two edges at random
                e1i,e2i=map(lambda x:2*x,random.sample(xrange(int(len(stubs)/2)),2))
                c=[node,stubs[e1i],stubs[e1i+1],stubs[e2i],stubs[e2i+1]]
                n2,n3=sorted([c[1],c[2]])
                n4,n5=sorted([c[3],c[4]])
                if len(set(c))==len(c):
                    if (n2,n3) not in multiedges and (n4,n5) not in multiedges:
                        if net[node,n2]==0 and net[node,n4]==0 and net[n3,n5]==0:
                            net[n2,n3]=0
                            net[n4,n5]=0
                            net[node,n2]=1
                            net[node,n4]=1
                            net[n3,n5]=1
                            stubs[si],stubs[si+1]=sorted([n3,n5])
                            stubs[e1i],stubs[e1i+1]=sorted([node,n2])
                            stubs[e2i],stubs[e2i+1]=sorted([node,n4])
                            repeat=False

    # Uncomment to check that everything ok so far:
    #import diagnostics
    #assert sum(map(lambda x:x[0]*x[1],diagnostics.degs(net).items()))/2.+sum(map(lambda x:len(edgetoindex[x[0],x[1]])-1,multiedges))==sum(map(lambda x:x[0]*x[1],degs.items()))/2.

    #for s in range(len(stubs)/2):
    #    n1,n2=stubs[2*s],stubs[2*s+1]
    #    assert net[n1,n2]==1,str(2*s)

    for n1,n2 in multiedges:
        for dummy in range(int(math.floor(len(edgetoindex[(n1,n2)])/2.))):
            repeat=True
            while repeat:
                #select two edges at random
                e1i,e2i=map(lambda x:2*x,random.sample(xrange(int(len(stubs)/2)),2))
                c=[n1,n2,stubs[e1i],stubs[e1i+1],stubs[e2i],stubs[e2i+1]]
                n3,n4=sorted([c[2],c[3]])
                n5,n6=sorted([c[4],c[5]])
                if len(set(c))==len(c):
                    if (n3,n4) not in multiedges and (n5,n6) not in multiedges:
                        if net[n1,n3]==0 and net[n2,n4]==0 and net[n1,n5]==0 and net[n2,n6]==0:
                            if len(edgetoindex[n1,n2])==2:
                                net[n1,n2]=0
                            assert net[n3,n4]==1
                            assert net[n5,n6]==1
                            net[n3,n4]=0
                            net[n5,n6]=0
                            net[n1,n3]=1
                            net[n2,n4]=1
                            net[n1,n5]=1
                            net[n2,n6]=1
                            si1,si2=sorted([edgetoindex[n1,n2].pop(),edgetoindex[n1,n2].pop()])
                            stubs[si1],stubs[si1+1]=sorted([n1,n3])
                            stubs[si2],stubs[si2+1]=sorted([n2,n4]) #stubs[si1],stubs[si1+1]=sorted([n2,n4])
                            stubs[e1i],stubs[e1i+1]=sorted([n1,n5])
                            stubs[e2i],stubs[e2i+1]=sorted([n2,n6])
                            repeat=False

def single_layer_er(net,nodes,p=None,edges=None):
    """Generates a realization of a monoplex Erdos-Renyi network.

    Parameters
    ----------
    net : MultilayerNetwork with aspects=0
       Empty network object that is to be filled.
    nodes : iterable
       Sequence of node labels.
    p : float
       Probability that edges is present.
    edges : int
       Number of edges that are present.

    References
    ----------
    Efficient generation of large random networks. PRE 71, 036113 (2005)
    """

    if (p==None and edges==None) or (p!=None and edges!=None):
        raise Exception("Give one of the parameters: p or edges.")

    n=len(nodes)
    for node in nodes:
        net.add_node(node)

    if p!=None:
        if p==1.0:
            for node1 in nodes:
                for node2 in nodes:
                    if node1!=node2:
                        net[node1,node2]=1
        else:
            v,w=1,-1
            while (v < n):
                r=random.random()
                w=w+1+int(math.floor(math.log(1-r)/math.log(1-p)))
                while ((w >= v) and (v < n)):
                    w = w-v
                    v = v+1
                if (v < n):
                    net[nodes[v],nodes[w]]=1
    else:
        for edge_index in random.sample(xrange(int((n*(n-1))/2)),edges):
            v=int(1+math.floor(-0.5+math.sqrt(0.25+2*edge_index)))
            w=edge_index-int((v*(v-1))/2)
            net[nodes[v],nodes[w]]=1

def conf(degs,degstype="distribution",couplings=("categorical",1.0)):
    """Independent configuration model for multiplex networks.

    Parameters
    ----------
    degs : dict, dict of dicts, list of dicts, MultiplexNetwork, MultilayerNetwork
       Degrees. If dict, a monoplex network is returned. If dict of dicts, a multiplex network with
       keys as layer names is returned. If list of dicts, then a multiplex network with a layer for
       each element in the list is returned. See degstype parameter for the description of the dict
       used for describing intra-layer networks. If MultiplexNetwork (with 1 aspect) or MultilayerNetwork
       (with 0 aspects) object is given then a copy of that network is produced with configuration
       model.

    degstype : string
       If 'distribution', then degs dicts give the degree distributions. I.e.,
       keys are degrees, and corresponding values are number of nodes with the given degree.
       If 'nodes', then degs dicts give node degrees. I.e, keys are node names and
       corresponding values are degrees of those nodes.

    couplings : tuple
       The coupling types of the multiplex network object.

    Returns
    -------
    net : MultiplexNetwork
       The (multiplex) network produced with the configuration model.

    See also
    --------
    single_layer_conf : the function used to generate a network on each layer

    """
    if isinstance(degs,MultiplexNetwork):
        assert degs.aspects==1
        d={}
        for layer in degs.iter_layers():
            dd={}
            d[layer]=dd
            for node in degs.A[layer]:
                dd[node]=degs.A[layer][node].deg()
        return conf(d,degstype="nodes")
    elif isinstance(degs,MultilayerNetwork):
        assert degs.aspects==0
        d={}
        for node in degs:
            d[node]=degs[node].deg()
        return conf(d,degstype="nodes")
    #elif isinstance(degs,dict) and not isinstance(degs.itervalues().next(),dict):
    elif isinstance(degs,dict) and not isinstance(degs[(k for k in degs).send(None)],dict):
        net=MultilayerNetwork(aspects=0)
        single_layer_conf(net,degs,degstype=degstype)
    else:
        #check if the network is going to be node-aligned
        namedlayers=isinstance(degs,dict)
        if namedlayers:
            degslist=degs.values()
        else:
            degslist=degs
        nnodes=None
        nodeAligned=True
        if degstype=="distribution":
            for ldegs in degslist:
                lnnodes=sum(ldegs.values())
                if nnodes!=None and lnnodes!=nnodes:
                    nodeAligned=False
                nnodes=lnnodes
        elif degstype=="nodes":
            for ldegs in degslist:
                lnnodes=set(ldegs.keys())
                if nnodes!=None and lnnodes!=nnodes:
                    nodeAligned=False
                nnodes=lnnodes
        else:
            raise Exception()

        net=MultiplexNetwork(couplings=[couplings],fullyInterconnected=nodeAligned)
        if namedlayers:
            #layers=degs.iteritems()
            layers = ((node, degs[node]) for node in degs )
        else:
            layers=enumerate(degs)
        for l,ldegs in layers:
            net.add_layer(l)
            single_layer_conf(net.A[l],ldegs,degstype=degstype)

    return net

def er(n,p=None,edges=None):
    """Multiplex Erdos-Renyi model.

    Parameters
    ----------
    n : int, list of lists of nodes
       Number of nodes, or lists of nodes in each layer if network is not fully
       interconnected.
    p : float or list of floats
       Connection probability, or list of connection probabilities for each layer.
    edges : int or list of int
       Number of edges, or list of number of edges in each layer.

    Returns
    -------
    net : MultiplexNetwork
       The (multiplex) network produced.

    See also
    --------
    single_layer_er : the function used to generate a network on each layer
    """
    # What kind of network?
    fic = not hasattr(n,'__iter__') #fully interconnected
    monoplex = (not hasattr(p,'__iter__')) and (not hasattr(edges,'__iter__')) and fic

    # Sanity check for parameters
    if (p==None and edges==None) or (p!=None and edges!=None):
        raise Exception("Give one of the parameters: p or edges.")
    if not fic:
        if hasattr(p,'__iter__'):
            assert len(n)==len(p)
        elif hasattr(edges,'__iter__'):
            assert len(n)==len(edges)

    # Create the network
    if monoplex:
        net=MultilayerNetwork(aspects=0)
    else:
        net=MultiplexNetwork(couplings=[('categorical',1.0)],fullyInterconnected=fic)
        if not hasattr(n,'__iter__'):
            if p!=None:
                nodes=list(map(lambda x:xrange(n),p))
                layers=xrange(len(p))
            else:
                nodes=list(map(lambda x:xrange(n),edges))
                layers=xrange(len(edges))
        else:
            nodes=n
            layers=xrange(len(n))
            if p!=None and (not hasattr(p,'__iter__')):
                p=list(map(lambda x:p,layers))
            if edges!=None and (not hasattr(edges,'__iter__')):
                edges=list(map(lambda x:edges,layers))

    # Fill in the edges
    if p!=None:
        if monoplex:
            single_layer_er(net,range(n),p=p)
        else:
            for l,lp,lnodes in zip(layers,p,nodes):
                net.add_layer(l)
                single_layer_er(net.A[l],lnodes,p=lp)
    else:
        if monoplex:
            single_layer_er(net,range(n),edges=edges)
        else:
            for l,ledges,lnodes in zip(layers,edges,nodes):
                net.add_layer(l)
                single_layer_er(net.A[l],lnodes,edges=ledges)

    return net

def er_partially_interconnected(nodes,ps,couplings=('categorical',1.0)):
    """Generate multiplex Erdos-Renyi network which is not fully interconnected.

    The produced multiplex network has a single aspect.

    Parameters
    ----------
    nodes : list of lists
       List of lists of nodes, where each list corresponds to
       nodes in one layer.
    ps : list
       List of edge occupation probabilities for layers
    couplings : tuple
       The coupling types of the multiplex network object.

    Returns
    -------
    net : MultiplexNetwork
       The multiplex network that is produced.
    """
    assert len(nodes)==len(ps)
    net=MultiplexNetwork(couplings=[couplings],fullyInterconnected=False)
    for layer,lnodes in enumerate(nodes):
        net.add_layer(layer)
        single_layer_er(net.A[layer],lnodes,ps[layer])
    return net

def full(nodes,layers,couplings=('categorical',1.0)):
    """Generate a full multiplex network.

    The produced multiplex network has a single aspect and is fully
    interconnected. Can also produce a full monoplex network.

    Parameters
    ----------
    nodes : int
       Number of nodes in the network
    layers : int, sequence or None
       Number of layers in the network, a sequence of layer names, or
       None for monoplex networks.
    couplings : tuple
       The coupling types of the multiplex network object.

    Returns
    -------
    net : MultiplexNetwork or MultilayerNetwork
       The multiplex network that is produced, or the monoplex
       network (which is of type MultilayerNetwork).
    """
    if layers==None:
        n=MultilayerNetwork(aspects=0)
        for node1 in range(nodes):
            for node2 in range(nodes):
                if node1!=node2:
                    n[node1,node2]=1
    elif not hasattr(layers,'__iter__'): #is not sequence
        n=MultiplexNetwork(couplings=[couplings])
        for layer in range(layers):
            for node1 in range(nodes):
                for node2 in range(nodes):
                    if node1!=node2:
                        n[node1,node2,layer,layer]=1
    else: #it's a sequence
        n=MultiplexNetwork(couplings=[couplings])
        for layer in layers:
            for node1 in range(nodes):
                for node2 in range(nodes):
                    if node1!=node2:
                        n[node1,node2,layer,layer]=1

    return n

def full_multilayer(nodes,layers):
    """Generate a full multilayer network.

    The generated network has a single aspect, and all the inter-layer
    and intra-layer edges.

    Parameters
    ----------
    nodes : int
       Number of nodes in the network
    layers : int or sequence
       Number of layers in the network, or a sequence of layer names

    Returns
    -------
    net : MultilayerNetwork
       The multilayer network that is produced.
    """
    if not hasattr(layers,'__iter__'): #is not sequence
        layers=range(layers)

    n=MultilayerNetwork(aspects=1)
    for layer1 in layers:
        for layer2 in layers:
            for node1 in range(nodes):
                for node2 in range(nodes):
                    if node1!=node2 or layer1!=layer2:
                        n[node1,node2,layer1,layer2]=1
    return n

def er_multilayer(nodes,layers,p,randomWeights=False):
    """Generate multilayer Erdos-Renyi network.

    The produced multilayer network has a single aspect.

    Parameters
    ----------
    nodes : int
       Number of nodes in the network
    layers : int or sequence
       Number of layers in the network, or a sequence of layer names
    p : float
       The edge probability
    randomWeights : bool
       If true the weights are uniformly random between (0,1].

    Returns
    -------
    net : MultilayerNetwork
       The multilayer network that is produced.
    """

    if not hasattr(layers,'__iter__'): #is not sequence
        layers=range(layers)

    n=MultilayerNetwork(aspects=1)
    for layer1 in layers:
        for layer2 in layers:
            for node1 in range(nodes):
                for node2 in range(node1+1,nodes):
                    if node1!=node2 or layer1!=layer2:
                        if random.random()<p:
                            if randomWeights:
                                n[node1,node2,layer1,layer2]=random.random()
                            else:
                                n[node1,node2,layer1,layer2]=1

    return n

def conf_overlaps(ol_degs, couplings=None):
    """
    Generate multiplex configuration model network with given overlap degree
    sequences.

    One can specify the 'overlap degree sequences', as defined in overlap_degs.

    Parameters
    ----------
    ol_degs : dict of dicts
        The overlap degrees. Keys are tuples containing layer combinations
        (including the trivial combination of a single layer) and
        values are the overlap degree distributions with nodes as keys. See
        overlap_degs.
    couplings : None or tuple
        The coupling types passed directly to multiplex network object
        constructor.

    Returns
    -------
    net : MultiplexNetwork
       The multiplex network produced with the configuration model.

    Notes
    -----
    The algorithm to produce the multiplex network is a modified version of the
    one implemented in single_layer_conf (McKay et al). The modification tries
    link swapping in cases where edges in another layer combination already
    exists.

    References
    ----------
    Marceau, Vincent, et al. "Modeling the dynamical interaction between
    epidemics on overlay networks." Physical Review E 84.2 (2011): 026105.
    """

    net = MultiplexNetwork(couplings=couplings)
    used_edges = set()

    for layer_comb in ol_degs:
        degs = ol_degs[layer_comb]

        # mostly modified from single_layer_conf
        stubs=[]
        selfedges={}
        multiedges=set()
        takenedges=set()
        edgetoindex={}

        net_temp = MultilayerNetwork()

        nstubs=sum(degs.values())
        n_nodes=len(degs)
        for node in degs:
            k=degs[node]
            for i in range(k):
                stubs.append(node)
            if k==0:
                net_temp.add_node(node)

        # Here we should do the Erdos-Gallai test
        assert nstubs%2==0
        assert (n_nodes*(n_nodes-1)) >= nstubs

        random.shuffle(stubs)

        for s in range(int(len(stubs)/2)):
            node1,node2=sorted([stubs[2*s],stubs[2*s+1]])

            edgetoindex[(node1,node2)]=edgetoindex.get((node1,node2),[])+[2*s]

            if node1==node2:
                selfedges[node1]=selfedges.get(node1,[])+[2*s]
            elif net_temp[node1,node2]!=0:
                multiedges.add((node1,node2))
            elif (node1, node2) in used_edges:
                takenedges.add((node1,node2))
            else:
                net_temp[node1,node2]=1
                used_edges.add((node1, node2))

        for node,sis in selfedges.items():
            for si in sis:
                repeat=True
                while repeat:
                    #select two edges at random
                    e1i,e2i=map(lambda x:2*x,random.sample(xrange(int(len(stubs)/2)),2))
                    c=[node,stubs[e1i],stubs[e1i+1],stubs[e2i],stubs[e2i+1]]
                    n2,n3=sorted([c[1],c[2]])
                    n4,n5=sorted([c[3],c[4]])
                    if len(set(c))==len(c):
                        if (n2,n3) not in multiedges and (n4,n5) not in multiedges and (n2,n3) not in takenedges and (n4,n5) not in takenedges:
                            e1 = tuple(sorted([node, n2]))
                            e2 = tuple(sorted([node, n4]))
                            e3 = tuple(sorted([n3, n5]))
                            if e1 not in used_edges and e2 not in used_edges and e3 not in used_edges:
                                net_temp[n2,n3]=0
                                net_temp[n4,n5]=0
                                net_temp[node,n2]=1
                                net_temp[node,n4]=1
                                net_temp[n3,n5]=1
                                stubs[si],stubs[si+1]=sorted([n3,n5])
                                stubs[e1i],stubs[e1i+1]=sorted([node,n2])
                                stubs[e2i],stubs[e2i+1]=sorted([node,n4])
                                repeat=False

                                used_edges.remove((n2,n3))
                                used_edges.remove((n4,n5))
                                used_edges.add(e1)
                                used_edges.add(e2)
                                used_edges.add(e3)

        for n1,n2 in multiedges:
            for dummy in range(int(math.floor(len(edgetoindex[(n1,n2)])/2.))):
                repeat=True
                while repeat:
                    #select two edges at random
                    e1i,e2i=map(lambda x:2*x,random.sample(xrange(int(len(stubs)/2)),2))
                    c=[n1,n2,stubs[e1i],stubs[e1i+1],stubs[e2i],stubs[e2i+1]]
                    n3,n4=sorted([c[2],c[3]])
                    n5,n6=sorted([c[4],c[5]])
                    if len(set(c))==len(c):
                        if (n3,n4) not in multiedges and (n5,n6) not in multiedges and (n3,n4) not in takenedges and (n5,n6) not in takenedges:
                            e1 = tuple(sorted([n1,n3]))
                            e2 = tuple(sorted([n2,n4]))
                            e3 = tuple(sorted([n1,n5]))
                            e4 = tuple(sorted([n2,n6]))
                            if e1 not in used_edges and e2 not in used_edges and e3 not in used_edges and e4 not in used_edges: #net[n1,n3]==0 and net[n2,n4]==0 and net[n1,n5]==0 and net[n2,n6]==0:
                                if len(edgetoindex[n1,n2])==2:
                                    net_temp[n1,n2]=0
                                    used_edges.remove((n1,n2))
                                net_temp[n3,n4]=0
                                net_temp[n5,n6]=0
                                net_temp[n1,n3]=1
                                net_temp[n2,n4]=1
                                net_temp[n1,n5]=1
                                net_temp[n2,n6]=1
                                si1,si2=sorted([edgetoindex[n1,n2].pop(),edgetoindex[n1,n2].pop()])
                                stubs[si1],stubs[si1+1]=sorted([n1,n3])
                                stubs[si2],stubs[si2+1]=sorted([n2,n4])#stubs[si1],stubs[si1+1]=sorted([n2,n4])
                                stubs[e1i],stubs[e1i+1]=sorted([n1,n5])
                                stubs[e2i],stubs[e2i+1]=sorted([n2,n6])
                                repeat=False

                                used_edges.remove((n3,n4))
                                used_edges.remove((n5,n6))
                                used_edges.add(e1)
                                used_edges.add(e2)
                                used_edges.add(e3)
                                used_edges.add(e4)

        for n1,n2 in takenedges:
            for si1 in edgetoindex[(n1,n2)]:
                repeat=True
                while repeat:
                    #select two edges at random
                    e1i,e2i=map(lambda x:2*x,random.sample(xrange(int(len(stubs)/2)),2))
                    c=[n1,n2,stubs[e1i],stubs[e1i+1],stubs[e2i],stubs[e2i+1]]
                    n3,n4=sorted([c[2],c[3]])
                    n5,n6=sorted([c[4],c[5]])
                    if len(set(c))==len(c):
                        if (n3,n4) not in takenedges and (n5,n6) not in takenedges:
                            e1 = tuple(sorted([n1,n3]))
                            e2 = tuple(sorted([n2,n5]))
                            e3 = tuple(sorted([n4,n6]))
                            if e1 not in used_edges and e2 not in used_edges and e3 not in used_edges:
                                assert net_temp[n3,n4]==1
                                assert net_temp[n5,n6]==1
                                net_temp[n3,n4]=0
                                net_temp[n5,n6]=0
                                net_temp[n1,n3]=1
                                net_temp[n2,n5]=1
                                net_temp[n4,n6]=1

                                stubs[si1],stubs[si1+1]=sorted([n1,n3])
                                stubs[e1i],stubs[e1i+1]=sorted([n2,n5])
                                stubs[e2i],stubs[e2i+1]=sorted([n4,n6])
                                repeat=False

                                used_edges.remove((n3,n4))
                                used_edges.remove((n5,n6))
                                used_edges.add(e1)
                                used_edges.add(e2)
                                used_edges.add(e3)

        for e in net_temp.edges:
            for layer in layer_comb:
                net[e[0], e[1], layer] = 1

    return net

def er_overlaps_match_aggregated(n, edges, ps, couplings=None):
    '''
    Generates a multiplex Erdos-Renyi networks which produces an aggregated
    network with given number of edges. The target it that the aggregated
    network of the resulting network has edges * n_layers edges.

    The algorithm goes through each of the user-given layer combinations with
    2 or more layers. It generates an ER graph which does not include any edges
    that are already in any of the layers of the combination. It then copies
    the edges of that ER graph to all of the layers of the combination.

    Parameters
    ----------
    n : int
        Number of nodes
    edges : int
        Number of edges in each layer
    ps : dict
        Proportions of overlapping edges in each layer combination given as
        keys (note that the sum of these proportions should not exceed 1 for
        any one layer). The trivial combinations including only a single layer
        do not need to be given (and if they are given, the given proportions
        are ignored).
    couplings : None or tuple
        The coupling types of the multiplex network object.

    Returns
    -------
    net : MultiplexNetwork
       The multiplex network produced
    '''

    net = MultiplexNetwork(couplings=couplings)
    used_edges = set()

    e_left = {}
    for layer_comb in ps:
        if len(layer_comb) == 1:
            e_left[layer_comb[0]] = e_left.get(layer_comb[0], edges)
            continue
        p = ps[layer_comb]
        m = int(round(p*edges))
        k = len(layer_comb)
        if k > 1:
            for layer in layer_comb:
                e_left[layer] = e_left.get(layer, edges) - m
            i = 0
            while i < (k * m):
                edge_index = random.choice(xrange(int((n*(n-1))/2)))
                v=int(1+math.floor(-0.5+math.sqrt(0.25+2*edge_index)))
                w=edge_index-int((v*(v-1))/2)
                edge = (w, v)
                if edge not in used_edges:
                    used_edges.add(edge)
                    i += 1
                    for layer in layer_comb:
                        net[edge[0], edge[1], layer] = 1

    for layer in e_left:
        m = e_left[layer]
        i = 0
        while i < m:
            edge_index = random.choice(xrange(int((n*(n-1))/2)))
            v=int(1+math.floor(-0.5+math.sqrt(0.25+2*edge_index)))
            w=edge_index-int((v*(v-1))/2)
            edge = (w, v)
            if edge not in used_edges:
                used_edges.add(edge)
                i += 1
                net[edge[0], edge[1], layer] = 1

    return net

def ba_total_degree(n, ms, couplings=None):
    """
    Generates a Barabasi-Albert multiplex network, where the preferential
    attachment process is run for each layer separately and concurrently
    in a way that the total degree of the node is used for the preferential
    attachment. That is, the new nodes attach preferentially to nodes that
    have high total degree (sum of degree in all layers).

    Parameters
    ----------
    n : int
        number of nodes
    ms : list of ints
        the numbers of links added to each new node for each layer
    couplings : None or tuple
        The coupling types of the multiplex network object.

    Returns
    -------
    net : MultiplexNetwork
       The multiplex network produced

    References
    ----------
    Kim, Jung Yeol, and K-I. Goh. "Coevolution and correlated multiplexity in
    multiplex networks." Physical review letters 111.5 (2013): 058702.
    """

    net = MultiplexNetwork(couplings=couplings)
    links = []

    for i in range(n):
        net.add_node(i)
        link_sets = []
        for layer, m in enumerate(ms):
            if i == m:
                link_set = set(range(i))

            elif i > m:
                link_set = set()
                while len(link_set) < m:
                    link_set = link_set | set(random.sample(links, m - len(link_set)))

            else:
                link_set = set()

            link_sets.append(link_set)

            for j in link_set:
                net[i,j,layer] = 1

        for link_set in link_sets:
            links += list(link_set)
            links += [i]*(len(link_set))

    return net

try:
    from . import nxwrap as nx
    import networkx

    def ws(n, edges, p=0.3, couplings=None):
        """
        Generates a multiplex network where each layer is generated
        using the same Watts-Strogatz model.

        Parameters
        ----------
        n : int
            Number of nodes
        edges : list of ints
            Number of edges in each layer
        p : float
            Probability of rewiring an edge
        couplings : None or tuple
            The coupling types of the multiplex network object.

        Returns
        -------
        net : MultiplexNetwork
           The multiplex network produced
        """

        net = MultiplexNetwork(couplings=couplings)
        for layer, m in enumerate(edges):
            net.add_layer(layer)
            net.A[layer] = nx.watts_strogatz_graph(n, int(math.ceil(2*m / float(n))), p=p)

        return net

    def geo(n, edges, couplings=None):
        """
        Generates a multiplex network where each layer is generated using the
        same soft geometric network model.

        The intra-layer networks are generated using the networkx function
        soft_random_geometeric_graph.

        Parameters
        ----------
        n : int
            Number of nodes
        edges : list of ints
            Approximate number of edges in each layer
        couplings : None or tuple
            The coupling types of the multiplex network object.

        Returns
        -------
        net : MultiplexNetwork
           The multiplex network produced

        Notes
        -----
        Works only with networkX2
        """

        net = MultiplexNetwork(couplings=couplings)
        pos = None
        for layer, m in enumerate(edges):
            net.add_layer(layer)
            r = math.sqrt(2.2 * float(m) / ((n - 1.0) * n) / math.pi)
            netX = networkx.soft_random_geometric_graph(n, r, pos=pos)
            pos = networkx.get_node_attributes(netX, 'pos')
            for node in netX.nodes:
                net.add_node(node)

            for e in netX.edges:
                net[e[0], e[1], layer] = 1

        return net
except ImportError:
    pass


#
# ps9pr1.py (Problem Set 9, Problem 1)
#
# A Connect Four Board class
#
# Computer Science 111
#

class Board:
    """ a data type for a Connect Four board with arbitrary dimensions
    """
    ### add your constructor here ###
    def __init__(self, height, width):
        self. height = height
        self. width = width
        self. slots= [[' ']* self.width for row in range(self.height)]

    def __repr__(self):
        """ Returns a string that represents a Board object.
        """
        s = ''         #  begin with an empty string

        # add one row of slots at a time to s
        for row in range(self.height):
            s += '|'   # one vertical bar at the start of the row

            for col in range(self.width):
                s += self.slots[row][col] + '|'

            s += '\n'  # newline at the end of the row

        ### add your code here ###

        s+=(self.width*2+1)*'-'+'\n'
        for i in range(self.width):
            if i>9:
                i=str(i)[-1]
            s+=" "+str(i)
        return s

    def add_checker(self, checker, col):
        """ adds the specified checker (either 'X' or 'O') to the
            column with the specified index col in the called Board.
            inputs: checker is either 'X' or 'O'
                    col is a valid column index
        """
        assert(checker == 'X' or checker == 'O')
        assert(col >= 0 and col < self.width)

        ### put the rest of the method here ###
        i=0
        while i < self.height:
            if self.slots[self.height-1-i][col]==' ':
                self.slots[self.height-1-i][col]=checker
                i = self.height
            else:
                i+=1

    ### add your reset method here ###
    def reset(self):
        """ reset the Board object by setting all slots to contain
            a spsce character
        """
        self. slots= [[' ']* self.width for row in range(self.height)]

    def add_checkers(self, colnums):
        """ takes a string of column numbers and places alternating
            checkers in those columns of the called Board object,
            starting with 'X'.
            input: colnums is a string of valid column numbers
        """
        checker = 'X'   # start by playing 'X'

        for col_str in colnums:
            col = int(col_str)
            if 0 <= col < self.width:
                self.add_checker(checker, col)

            if checker == 'X':
                checker = 'O'
            else:
                checker = 'X'

    ### add your remaining methods here
    def can_add_to(self, col):
        """this function returns True if it is valid to place a checker in the
            column col on the calling Board object. If the column number is too
            high, too low, or full of checkers, it should return False. Otherwise,
            it should return True.
        """
        if col<0 or col>=self.width:
            return False
        else:
            for i in range(self.height):
                if self.slots[i][col]==" ":
                    return True
        return False

    def is_full(self):
        """this functions return True is every slot is full with 'X' or 'O'
        """
        for i in range(self.width):
            if self.can_add_to(i):
                return False
        return True

    def remove_checker(self, col):
        """removes the ttop of checker from col if this column is not empty.
        """
        i=0
        while i < self.height:
            if self.slots[i][col] !=' ':
                self.slots[i][col]=' '
                i = self.height
            else:
                i+=1

#Question 9
    def is_horizontal_win(self, checker):
        """ the funtion returns true if there are at least four consecutive
            slots containing checker on the horizontal line
        """
        for i in range(self.height):
            for j in range(self.width-3):
                if self.slots[i][j]==checker:
                    if self.slots[i][j:j+4]==[checker]*4:
                        return True
        return False

    def is_vertical_win(self, checker):
        """the funtion returns true if there are at least four consecutive
            slots containing checker on the vertical line
        """
        for i in range(self.width):
            for j in range(self.height-3):
                if self.slots[j][i] ==checker and \
                    self.slots[j+1][i] ==checker and \
                    self.slots[j+2][i] ==checker and \
                    self.slots[j+3][i] ==checker:
                    return True
        return False

    def is_down_diagonal_win(self, checker):
        """the funtion returns true if there are at least four consecutive
            slots containing checker on the diagonal line from up of left
            to down of right
        """
        for i in range(self.width-3):
            for j in range(self.height-3):
                if self.slots[j][i]==checker and \
                   self.slots[j+1][i+1]==checker and \
                   self.slots[j+2][i+2]==checker and \
                   self.slots[j+3][i+3]==checker:
                       return True
        return False

    def is_up_diagonal_win(self, checker):
        """the funtion returns true if there are at least four consecutive
            slots containing checker on the diagonal line from down of left
            to up of right
        """
        for i in range(self.height-3):
            for j in range(3,self.width):
                if self.slots[i][j]==checker and \
                   self.slots[i+1][j-1]==checker and \
                   self.slots[i+2][j-2]==checker and \
                   self.slots[i+3][j-3]==checker:
                    return True
        return False

    def is_win_for(self, checker):
        """this function returns true if one of the four function about for one
        specific checker is ture. Otherwise, return false
        """
        assert(checker == 'X' or checker == 'O')
        if self.is_horizontal_win(checker) or \
            self.is_vertical_win(checker) or \
            self.is_down_diagonal_win(checker) or \
            self.is_up_diagonal_win(checker):
                return True
        return False


# 7 Even Odd Series. Given a string and it contains the digits as well as non-digits. We have to find the largest even number
# from available digits after removing the duplicates. If not possible, print -1.

from itertools import permutations as perm

def even_no(ar):
    return ["".join(str(j) for j in i) for i in list(perm(ar))]

def odd_series(s, n):
    ar = [int(i) for i in s if i.isdigit()]
    res = max(even_no(set(ar)))
    return res if res else -1

if __name__ == "__main__":
    s = input()
    print(odd_series(s, n))


import numpy as np
import json

with open("data.json") as f:
    data = np.array(json.load(f))

trees = 0

for i, d in enumerate(data):
    if d[i * 3 % len(d)] == '#':
        trees += 1

print(trees)


# function to scrape top ten news stories from bbc.com

import requests
from bs4 import BeautifulSoup

url = 'http://www.bbc.com/news'
r = requests.get(url)
soup = BeautifulSoup(r.text, 'html.parser')
top_stories = soup.find_all('a', class_='gs-c-promo-heading')
for story in top_stories:
    print(story.text)


from collections import Counter
from data_tools.connection_init import acc, act, acu
from data_tools.functions import is_all_properties_available
from docx import Document
import ifcopenshell
from uuid import UUID

precision = 1
needed_properties = ['Zone_ZoneName', 'Zone_NetArea', ['Dane pomieszczenia', 'Kolor ścian'],
                    ['Specyfikacja produktu', 'Nazwa']]
all_properties = acc.GetAllPropertyNames()
run = is_all_properties_available(all_properties, needed_properties)

if run:
    ifc_file = ifcopenshell.open("others\ifc_files\model_testowy.ifc")

    def unpack_ifc_property(ifc_dict):
        values = []
        for ifc_type, ifc_keys in ifc_dict.items():
            parameters = ifc_file.by_type(ifc_type)[0]
            params_dict = parameters.get_info()
            values.append([params_dict[key] for key in ifc_keys])
        return values

    ifc_objects_to_get = {
        'IFCPROJECT' : ['Name', 'Phase'],
        'IFCSITE': ['SiteAddress'],
        'IFCPERSON': ['PrefixTitles', 'GivenName', 'FamilyName'],
        'IFCPROPERTYSET': ['HasProperties'] # stworzona przez autora grupa właściwości przydzielona do projektu
    }

    ifc_values = unpack_ifc_property(ifc_objects_to_get)

    # rozpakowywanie wartości
    project_params, address_params, person_params, custom_params = ifc_values
    project_name, phase = project_params
    address = ', '.join(address_params[0].get_info()['AddressLines'])
    if person_params[0] is None:
        designer = ' '.join(person_params[1:])
    else:
        person_params[0] = ' '.join(person_params[0])
        designer = ' '.join(person_params)

    unwrapped_customs = [param.get_info()['NominalValue'].get_info()['wrappedValue'] for param in custom_params[0]]
    project_number, start_date, end_date = unwrapped_customs

    # przygotowywanie listy pomieszczeń wraz z przydzielonymi do nich obiektami
    zone_properties = needed_properties[:3]
    object_properties = [needed_properties[3]]
    zone_properties_ids = [acu.GetBuiltInPropertyId(name) if type(name) is str else acu.GetUserDefinedPropertyId(*name)
                      for name in zone_properties]
    object_properties_ids = [acu.GetBuiltInPropertyId(name) if type(name) is str else acu.GetUserDefinedPropertyId(*name)
                      for name in object_properties]
    zones_ids = acc.GetElementsByType('Zone')
    zones = acc.GetElementsRelatedToZones(zones_ids, ['Object'])
    zones_descriptions = {}

    for i, zone in enumerate(zones):
        elements = zone.elements
        elements_values = [property.propertyValues[0].propertyValue.value for property in
                           acc.GetPropertyValuesOfElements(elements, object_properties_ids)]
        elements_counter = Counter(elements_values).items()
        elements_values = [element if times == 1 else f"{element} x {times}"
                           for element, times in elements_counter]
        cells_set = acc.GetPropertyValuesOfElements([zones_ids[i]], zone_properties_ids)
        zones_values = [act.ElementId(UUID(cell.value))for row in cells_set for cell in row][0]
        zones_values[1] = round(zones_values[1], precision)
        raport_values = zones_values[1:] + [elements_values]
        zones_descriptions[zones_values[0]] = raport_values

    # przygotowanie informacji do postaci gotowej do wyświetlenia w raporcie
    projects_data = [
    f"Raport z projektu nr {project_number}",
    f"Nazwa projektu: {project_name}",
    f"Faza projektu: {phase}",
    f"Lokalizacja: {address}",
    f"Data rozpoczęcia projektu: {start_date}",
    f"Data planowanego zakończenia projektu: {end_date}",
    f"Projektant: {designer}"]

    ''' Tworzenie raportu '''
    doc = Document()
    doc.add_heading(projects_data[0], level=1)

    # Dodawanie informacji ogólnych o projekcie
    doc.add_heading('1. Informacje ogólne o projekcie:', level=2)
    for row in projects_data[1:]:
        doc.add_paragraph(row)

    # Dodawanie informacji o pomieszczeniach
    doc.add_heading('2. Informacje o pomieszczeniach:', level=2)
    for zone, values in zones_descriptions.items():
        doc.add_paragraph(f"{zone}", style='List Number')
        doc.add_paragraph(f"Powierzchnia: {values[0]} m²")
        doc.add_paragraph(f"Kolor ścian: {values[1]}")
        doc.add_paragraph(f"Wyposażenie:")
        for object in values[2]:
            doc.add_paragraph(object, style='List Bullet')

    # Zapisywanie dokumentu do pliku .docx
    doc.save('raport_archicad.docx')
    acu.OpenFile('raport_archicad.docx')


from django.urls import path
from django.views.generic import TemplateView
from .views import TestCaseView, TestStepDetail, TestStepStats

app_name = "testcase"

urlpatterns = [
    path("", TemplateView.as_view(template_name="testcase/tchome.html"), name="tchome"),
    # path("success/", TemplateView.as_view(template_name="testcase/success.html"), name="tc_success"),
    path("success/", TestCaseView.as_view(), name="success"),
    path("teststep_detail/<int:pk>/", TestStepDetail.as_view(), name="teststep_detail"),
    path("teststep_stats/", TestStepStats.as_view(), name="teststep_stats"),

]


#
# Your previous Plain Text content is preserved below:
#
# This is just a simple shared plaintext pad, with no execution capabilities.
#
#
# Enjoy your interview!
#
# Problem Statement:
# -----
#
# Below is a piece of code which we want to run to get the output similar to as mentioned after the code as comment.
# Read the code and understand the requirement.
# Write all the required code which is missing here. Don;t
# The code will be evaluated on below aspects:
# 1. Output correctness.
# 2. Usage of OOPs concepts
# 3. Code should be divided in smaller and meaningfull modules.
# 4. Code should be self understandable. No comments are required. No docstrings required.
# 4. No code changes should be made to the code provided here.
# 5. Python coding standards should be maintained.
# 6. Time elapsed to complet. the code.
#
# Brief intro:
# There are students and there is professor. Professor include students in his subject lecture.
# Students will get only those assignments which are floated after their admission.

### Best of Luck!!!

###### Your code starts here ######

class Assignment:

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

class Student:

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

    def retreive_details(self):
        new_lis = []
        for key in self.total_students:
            new_str = f"{key}:{self.total_students[key]}"
            new_lis.append(new_str)
        return new_lis

class Professor(Student):

    def __init__(self, prof_name):
        self.prof_name = prof_name
        self.total_students = {}

    def add_students(self, student_obj):
        self.total_students[student_obj.student_name] = [list]

    def float_assignment(self,assignment_obj):
        for key in self.total_students.keys():
            self.total_students[key] = self.total_students[key].append(assignment_obj.assignment_name)

###### Your code ends here ######

if __name__ == "__main__":
    my_prof = Professor("Prof. Ajit Singh")

    students = [
        Student("Nikhil"),
        Student("Suresh"),
        Student("Aaditya"),
        Student("Ajay"),
    ]

    my_prof.add_students(students[0])
    my_prof.add_students(students[1])

    my_prof.float_assignment(Assignment("Motion"))
    my_prof.float_assignment(Assignment("Thermodynamics"))

    my_prof.add_students(students[2])
    my_prof.float_assignment(Assignment("Quantam Physics"))

    my_prof.add_students(students[3])
    my_prof.float_assignment(Assignment("Heat"))

    for stud in students:
        print(stud)

    """
    The output should be in below format:

    Nikhil: Motion, Thermodynamics, Quantam Physics, Heat
    Suresh: Motion, Thermodynamics, Quantam Physics, Heat
    Aaditya: Quantam Physics, Heat
    Ajay: Heat

    """
#


import pytest
from pytest import CaptureFixture

from data_structures.binary_tree import AVLTree

class TestBalancedTree:

  @pytest.fixture
  def avl_tree(self) -> AVLTree:
    avl_tree = AVLTree()
    avl_tree.insert(16)
    avl_tree.insert(8)
    avl_tree.insert(20)
    avl_tree.insert(4)
    avl_tree.insert(12)
    avl_tree.insert(10)
    avl_tree.insert(18)
    return avl_tree

  @pytest.fixture
  def avl_tree2(self) -> AVLTree:
    avl_tree = AVLTree()
    avl_tree.insert(16)
    avl_tree.insert(8)
    avl_tree.insert(20)
    avl_tree.insert(4)
    avl_tree.insert(12)
    avl_tree.insert(10)
    avl_tree.insert(18)
    return avl_tree

  @pytest.fixture
  def avl_tree3(self) -> AVLTree:
    avl_tree = AVLTree()
    avl_tree.insert(15)
    avl_tree.insert(8)
    avl_tree.insert(20)
    avl_tree.insert(4)
    avl_tree.insert(12)
    avl_tree.insert(10)
    avl_tree.insert(18)
    return avl_tree

  @pytest.fixture
  def new_tree(self) -> AVLTree:
    return AVLTree()

  def format_print(self, avl_tree_values: list[int]):
    strings: list[str] = []
    for value in avl_tree_values:
      strings.append(str(value))
      strings.append("\n")

    return "".join(strings)

  def test_avl_tree_insert(self, avl_tree: AVLTree):
    avl_tree.insert(1)

  def test_avl_tree_bfs(self, avl_tree: AVLTree, new_tree: AVLTree,
                        capsys: CaptureFixture[str]):
    avl_tree.bfs()
    captured = capsys.readouterr()
    # bfs = [16, 8, 20, 4, 12, 18, 10]
    bfs = [12, 8, 18, 4, 10, 16, 20]
    assert captured.out == self.format_print(bfs)

  def test_avl_tree_pre_order_dfs(self, avl_tree: AVLTree,
                                  capsys: CaptureFixture[str]):
    avl_tree.pre_order_dfs()
    captured = capsys.readouterr()
    # pre_order_dfs = [16, 8, 4, 12, 10, 20, 18]
    pre_order_dfs = [12, 8, 4, 10, 18, 16, 20]
    assert captured.out == self.format_print(pre_order_dfs)

  def test_avl_tree_in_order_dfs(self, avl_tree: AVLTree,
                                 capsys: CaptureFixture[str]):
    avl_tree.in_order_dfs()
    captured = capsys.readouterr()
    # in_order_dfs = [4, 8, 10, 12, 16, 18, 20]
    in_order_dfs = [4, 8, 10, 12, 16, 18, 20]
    assert captured.out == self.format_print(in_order_dfs)

  def test_avl_tree_post_order_dfs(self, avl_tree: AVLTree,
                                   capsys: CaptureFixture[str]):
    avl_tree.post_order_dfs()
    captured = capsys.readouterr()
    # post_order_dfs = [4, 10, 12, 8, 18, 20, 16]
    post_order_dfs = [4, 10, 8, 16, 20, 18, 12]
    assert captured.out == self.format_print(post_order_dfs)

  def test_empty_avl_tree_traversal(self, new_tree: AVLTree,
                                    capsys: CaptureFixture[str]):
    new_tree.bfs()
    new_tree.pre_order_dfs()
    new_tree.in_order_dfs()
    new_tree.post_order_dfs()
    captured = capsys.readouterr()
    assert captured.out == ""

  def test_avl_tree_equality(self, avl_tree: AVLTree, avl_tree2: AVLTree):
    assert avl_tree == avl_tree2

  def test_avl_tree_inequality(self, avl_tree: AVLTree, avl_tree3: AVLTree):
    assert avl_tree != avl_tree3

  def test_avl_tree_leaf(self, avl_tree: AVLTree):
    node = avl_tree.root
    while node and node.left:
      assert avl_tree.is_leaf(node) == False
      node = node.left
    assert avl_tree.is_leaf(node)

  def test_avl_tree_height(self, new_tree: AVLTree):

    height = -1
    assert new_tree.height() == height
    for i in range(16):
      new_tree.insert(i)
      if i in [0, 1, 3, 7, 15]:
        height += 1
        assert new_tree.height() == height

    node = new_tree.root
    assert new_tree.subtree_height_difference(node) == 1
    while node:
      node = node.left
    assert new_tree.subtree_height_difference(node) == 0

  def test_min_value(self, new_tree: AVLTree):
    assert new_tree.min_value() == float("inf")
    for i in range(16, -1, -1):
      new_tree.insert(i)
      assert new_tree.min_value() == i

  def test_find_value(self, new_tree: AVLTree):
    for i in range(16):
      assert new_tree.find(i) == False
      new_tree.insert(i)
      assert new_tree.find(i)

  def test_avl_tree_string_and_repr(self, new_tree: AVLTree):
    new_tree.insert(2)
    new_tree.insert(1)
    new_tree.insert(3)
    new_tree.insert(4)

    assert f"{new_tree.root}" == "2"
    assert f"{new_tree.root!r}" == "AVLNode(value = 2, left = AVLNode(value = 1), right = AVLNode(value = 3, right = AVLNode(value = 4)))"

if __name__ == "__main__":
  pytest.main([__file__])


from datetime import datetime

from django.conf import settings

import pytest
from freezegun import freeze_time

from olympia import amo
from olympia.amo.tests import addon_factory, user_factory, version_factory
from olympia.constants.promoted import LINE, NOT_PROMOTED, NOTABLE
from olympia.promoted.models import PromotedAddon
from olympia.reviewers.models import UsageTier
from olympia.versions.utils import get_staggered_review_due_date_generator
from olympia.zadmin.models import set_config

from ..tasks import NOTABLE_TIER_SLUG, add_high_adu_extensions_to_notable

@pytest.mark.django_db
def test_add_high_adu_extensions_to_notable_tier_absent_or_no_threshold():
    user_factory(pk=settings.TASK_USER_ID)
    set_config(amo.EXTRA_REVIEW_TARGET_PER_DAY_CONFIG_KEY, 999)

    extension_with_high_adu = addon_factory(
        average_daily_users=42, file_kw={'is_signed': True}
    )

    add_high_adu_extensions_to_notable()

    assert (
        extension_with_high_adu.reload().promoted_group(currently_approved=False)
        == NOT_PROMOTED
    )

    UsageTier.objects.create(slug=NOTABLE_TIER_SLUG, lower_adu_threshold=None)

    add_high_adu_extensions_to_notable()

    assert (
        extension_with_high_adu.reload().promoted_group(currently_approved=False)
        == NOT_PROMOTED
    )

@pytest.mark.django_db
def test_add_high_adu_extensions_to_notable():
    user_factory(pk=settings.TASK_USER_ID)
    # Arbitrary_lower_adu_threshold
    lower_adu_threshold = 1234
    UsageTier.objects.create(
        slug=NOTABLE_TIER_SLUG, lower_adu_threshold=lower_adu_threshold
    )
    # arbitrary target per day
    target_per_day = 12
    set_config(amo.EXTRA_REVIEW_TARGET_PER_DAY_CONFIG_KEY, target_per_day)

    extension_with_low_adu = addon_factory(
        average_daily_users=lower_adu_threshold - 1, file_kw={'is_signed': True}
    )
    extension_with_high_adu = addon_factory(
        average_daily_users=lower_adu_threshold, file_kw={'is_signed': True}
    )
    ignored_theme = addon_factory(
        average_daily_users=lower_adu_threshold + 1, type=amo.ADDON_STATICTHEME
    )
    already_promoted = addon_factory(
        average_daily_users=lower_adu_threshold + 1, file_kw={'is_signed': True}
    )
    PromotedAddon.objects.create(addon=already_promoted, group_id=LINE.id)
    promoted_record_exists = addon_factory(
        average_daily_users=lower_adu_threshold + 1, file_kw={'is_signed': True}
    )
    PromotedAddon.objects.create(addon=promoted_record_exists, group_id=NOT_PROMOTED.id)
    unlisted_only_extension = addon_factory(
        average_daily_users=lower_adu_threshold + 1,
        version_kw={'channel': amo.CHANNEL_UNLISTED},
        file_kw={'is_signed': True},
    )
    mixed_extension = addon_factory(
        average_daily_users=lower_adu_threshold + 1, file_kw={'is_signed': True}
    )
    mixed_extension_listed_version = mixed_extension.current_version
    mixed_extension_listed_version.delete()
    mixed_extension_unlisted_version = version_factory(
        addon=mixed_extension, channel=amo.CHANNEL_UNLISTED, file_kw={'is_signed': True}
    )
    deleted_extension = addon_factory(
        average_daily_users=lower_adu_threshold + 1, file_kw={'is_signed': True}
    )
    deleted_extension_version = deleted_extension.current_version
    deleted_extension.delete()

    with freeze_time():
        now = datetime.now()
        add_high_adu_extensions_to_notable()

    assert (
        extension_with_low_adu.reload().promoted_group(currently_approved=False)
        == NOT_PROMOTED
    )
    assert (
        extension_with_high_adu.reload().promoted_group(currently_approved=False)
        == NOTABLE
    )
    assert (
        ignored_theme.reload().promoted_group(currently_approved=False) == NOT_PROMOTED
    )
    already_promoted.reload().promotedaddon.reload()
    assert already_promoted.promoted_group(currently_approved=False) == LINE
    promoted_record_exists.reload().promotedaddon.reload()
    assert promoted_record_exists.promoted_group(currently_approved=False) == NOTABLE
    assert unlisted_only_extension.promoted_group(currently_approved=False) == NOTABLE
    assert mixed_extension.promoted_group(currently_approved=False) == NOTABLE
    assert deleted_extension.promoted_group(currently_approved=False) == NOTABLE

    generator = get_staggered_review_due_date_generator(starting=now)

    assert extension_with_high_adu.current_version.needshumanreview_set.filter(
        is_active=True
    ).exists()
    assert extension_with_high_adu.current_version.due_date == next(generator)
    assert promoted_record_exists.current_version.needshumanreview_set.filter(
        is_active=True
    ).exists()
    assert promoted_record_exists.current_version.due_date == next(generator)
    unlisted_latest_version = unlisted_only_extension.find_latest_version(channel=None)
    assert unlisted_latest_version.needshumanreview_set.filter(is_active=True).exists()
    assert unlisted_latest_version.due_date == next(generator)
    assert mixed_extension_unlisted_version.needshumanreview_set.filter(
        is_active=True
    ).exists()
    assert mixed_extension_unlisted_version.reload().due_date == next(generator)
    assert mixed_extension_listed_version.needshumanreview_set.filter(
        is_active=True
    ).exists()
    # same as due due is per addon
    assert (
        mixed_extension_listed_version.reload().due_date
        == mixed_extension_unlisted_version.due_date
    )
    assert deleted_extension_version.needshumanreview_set.filter(
        is_active=True
    ).exists()
    assert deleted_extension_version.reload().due_date == next(generator)


from datetime import date

from django.core.exceptions import ValidationError

from legal.common.forms import Form
from legal.common.fields import CharField, AmountField, CurrencyField, DateField, ChoiceField
from legal.common.widgets import TextWidget, DateWidget, RadioWidget

OPTS = (
    ('none', 'sine'),
    ('epr', 'elektronický platební rozkaz'),
    ('nmu', 'nemajetková újma'),
    ('vyz', 'výživné'),
    ('vyk', 'výkon rozhodnutí'),
    ('sm', 'smír'),
    ('inc', 'incidence'),
    ('usch', 'úschova'),
)

class MainForm(Form):

    basis = AmountField(
        widget=TextWidget(15),
        min_value=1,
        label='Základ',
        localize=True)
    basis.rounding = 2

    curr = CurrencyField(
        label='Měna',
        czk=True,
        initial='CZK')

    today = date.today()
    fx_date = DateField(
        widget=DateWidget(),
        required=False,
        label='ke dni',
        initial=date(today.year, today.month, 1))

    model = CharField(
        label='Úprava',
        initial='4')

    opt = ChoiceField(
        widget=RadioWidget(),
        choices=OPTS,
        label='Zvláštní případy',
        initial='none')

    def clean_fx_date(self):
        data = self.cleaned_data['fx_date']
        if self.data['curr_0'] != 'CZK' and not data:
            raise ValidationError('Date is required')
        return data


# 訓練神經網路模型，並存起來
import pandas as pd
import numpy as np
import tensorflow as tf
import math

# --------------------- Tensorflow -------------------------- #
def add_layer(inputs, in_size, out_size, activation_function = None):

    Weights = tf.Variable(tf.random_normal([in_size, out_size]), name="w")
    biases = tf.Variable(tf.zeros([1, out_size]) + 0.1, name="b")
    Wx_plus_b = tf.matmul(inputs, Weights) + biases

    if activation_function is None:
        outputs = Wx_plus_b
    else:
        outputs = activation_function(Wx_plus_b)
    return outputs

def normalize(data):
    normalized = (data-min(data)) / (max(data) - min(data))
    return normalized

training_data = pd.read_csv('studentData/studentInfo/100_cleanData.csv', encoding="big5", header=0)
training_data.dropna(inplace=True)
training_data = pd.get_dummies(training_data)

rowLength = len(training_data)
colLength = len(training_data.iloc[0])
print(training_data.iloc[0])
term1 = []
reg_no =[]
term2_calculus = []
term2_logical = []

for i in range(rowLength):
    term1.append([])

for i in range(rowLength):
    for j in range(1, 6):
        if training_data.iloc[i, j] < 0 :
            term1[i].append(0)
        else:
            term1[i].append(training_data.iloc[i,j])
    for s in range(23, colLength):
        term1[i].append(training_data.iloc[i, s])

    reg_no.append(training_data.iloc[i, 0])

    if training_data.iloc[i, 6] < 0:
        term2_calculus.append(0)
    else:
        term2_calculus.append(training_data.iloc[i, 6])
    term2_logical.append(training_data.iloc[i, 7])

term1 = np.array(term1).astype(float)
term2_calculus = np.array(term2_calculus).astype(float)
term2_logical = np.array(term2_logical).astype(float)
#
# for s in range(5):
#     term1[:, s] = normalize(term1[:, s])
# #
# term2_logical = normalize(term2_logical)
# term2_calculus = normalize(term2_calculus)

# --------------------- Tensorflow -------------------------- #
#
# # 建立 Feeds
# x_feeds = tf.placeholder(tf.float32, [None, len(term1[0])], name='x_input')
# y_feeds = tf.placeholder(tf.float32, [len(term1)], name='y_input')
#
# # add hidden layer
# l1 = add_layer(x_feeds,len(term1[0]),256, activation_function=tf.nn.relu)
# # l2 = add_layer(l1,256,128, activation_function=tf.nn.relu)
# # l3 = add_layer(l2,512,256, activation_function=tf.nn.relu)
#
#
# prediction = add_layer(l1, 256, len(term1), activation_function=None)
# # the error between prediction and real data
# loss = tf.sqrt(tf.reduce_mean(tf.square(y_feeds - prediction)))
# optimizer =  tf.train.AdamOptimizer(learning_rate=0.001)
# train_step = optimizer.minimize(loss)
# # losss = tf.sqrt(loss)
#
# #上面都是建立規則
# # 初始化所有變數
# # Can only save variables
# saver = tf.train.Saver()
# # Launch the graph
# with tf.Session() as sess:
#     # writer = tf.summary.FileWriter("./tensorBoard/", graph=sess.graph)
#     sess.run(tf.global_variables_initializer())
#     # 跑 for 迴圈 更新Weight200次 然後每訓練20次 印出一次Weight
#     for step in range(1000):
#         t, l, p = sess.run([train_step, loss, prediction], feed_dict={x_feeds: term1, y_feeds: term2_calculus})
#         # t2, l2, p2 = sess.run([train_step, loss, prediction], feed_dict={x_feeds: term1, y_feeds: term2_logical})
#
#         if step % 100 ==0:
#             print(sess.run(loss, feed_dict={x_feeds: term1, y_feeds: term2_calculus}))
#
#             # print( sess.run(prediction, feed_dict={x_feeds: term1}))
#             # print(l)
#             # print(l2)
#
#     print(p[259])
#     # saver.save(sess, './my_net/save_net.ckpt')
#
#     print(sess.run(y_feeds, feed_dict={y_feeds: term2_calculus}))
#     # writer.close()
# # print(reg_no)

# # --------------------------------- Regression ------------------------------------

W_calculus = np.zeros(len(term1[0])).astype(float)
W_logical = np.zeros(len(term1[0])).astype(float)

lr = 0.05
iteration = 100
batch_size = 200
step_num = int(math.floor(len(term1) / batch_size))
x_t = term1.transpose()
sum_gradient = np.zeros(len(term1[0]))
print(W_calculus.shape)
#
# for epoch in range(iteration):
#     # Train with batch
#     sum_gradient = np.zeros(len(term1[0]))
#
#     for i in range(step_num):
#         X = term1[i * batch_size:(i + 1) * batch_size]
#         Y = term2_calculus[i * batch_size:(i + 1) * batch_size]
#         hypothesis = np.dot(X, W_calculus)
#         loss = (hypothesis - Y)
#         # gradient_W = 2 * np.dot(x_t, (hypothesis - train_y))
#         # gradient_W = np.sum(2 * (hypothesis - term2_calculus))
#         cost = np.sum(loss ** 2) / len(X)
#         cost_a = math.sqrt(cost)
#         gradient_W = np.dot(X.transpose(), loss)
#         print(0, gradient_W)
#         sum_gradient += gradient_W ** 2
#         print(1, sum_gradient)
#
#         # W_calculus = W_calculus - lr*gradient_W/len(term1)
#         W_calculus = W_calculus - lr * gradient_W / np.sqrt(sum_gradient)
#         print(2, W_calculus)
#     # b = b - lr*gradient_b/len(train_x)
#     print("Iteration %d | Cost: %f" % (epoch, cost_a))

for epoch in range(iteration):
    hypothesis = np.dot(term1, W_calculus)
    loss = (hypothesis - term2_calculus)

    # gradient_W = 2 * np.dot(x_t, (hypothesis - train_y))
    # gradient_W = np.sum(2 * (hypothesis - term2_calculus))
    cost = np.sum(loss**2) / len(term1)
    cost_a = math.sqrt(cost)
    gradient_W = np.dot(x_t, loss)
    sum_gradient += gradient_W**2

    # W_calculus = W_calculus - lr*gradient_W/len(term1)
    W_calculus = W_calculus - lr*gradient_W/np.sqrt(sum_gradient)

    # b = b - lr*gradient_b/len(train_x)
    print("Iteration %d | Cost: %f" % (epoch, cost_a))
#
# for i in range(iteration):
#     hypothesis = np.dot(term1, W_logical)
#     loss = (hypothesis - term2_logical) ** 2
#
#     # gradient_W = 2 * np.dot(x_t, (hypothesis - train_y))
#     gradient_W = np.sum(2 * (hypothesis - term2_logical))
#     cost = np.sum(loss) / len(term1)
#     cost_a = math.sqrt(cost)
#     W_logical = W_logical - lr*gradient_W/len(term1)
#     # b = b - lr*gradient_b/len(train_x)
#     print("2. Iteration %d | Cost: %f" % (i, cost_a))

print(W_calculus)
print(hypothesis)


import bpy

##################################################################

path_tox3d='C:/Users/xxx/Documents/blender/'
path_toimage='C:/Users/xxx/Documents/blender/'
filename_ofx3d='projectname_'
filename_ofimage='newimage_'
startframe_ofx3d=0
endframe_ofx3d=10

##################################################################
#---------------------------------------------------------------#
##  Delete everything from scene before importing              ##

#bpy.ops.object.select_all(action='TOGGLE')
#bpy.ops.object.delete()

#---------------------------------------------------------------#
##  Add a text                                                  #
#bpy.ops.object.text_add()
#bpy.ops.object.editmode_toggle()
#bpy.ops.font.delete()
#bpy.ops.font.text_insert(text="Frame: ")
#bpy.ops.object.editmode_toggle()
#bpy.ops.object.select_all(action='TOGGLE')
#bpy.data.objects['Text'].name="Frametext"

#---------------------------------------------------------------#
#bpy.context.scene.frame_set(currentframe)
bpy.ops.object.add()
bpy.data.objects['Empty'].select=True
bpy.data.objects['Empty'].name="Aux_Empty"
#bpy.ops.anim.keyframe_insert(type='Location', confirm_success=True)
bpy.context.active_object.location =(0.0, 0.0, 0.0)
bpy.data.objects['Aux_Empty'].select=False

for currentframe in range(startframe_ofx3d,endframe_ofx3d):
    bpy.context.scene.frame_set(currentframe)
    #bpy.ops.object.add()
    bpy.data.objects['Aux_Empty'].select=True
    bpy.context.scene.objects.active = bpy.data.objects['Aux_Empty']
    #bpy.data.objects['Empty'].name="MyEmpty"
    obj = bpy.context.object
    obj.location[2] = 0.0
    #obj.keyframe_insert()
    obj.keyframe_insert(data_path='location')
    #bpy.context.active_object.location =(0.0, 0.0, 0.0)
    bpy.data.objects['Aux_Empty'].select=False

    #---------------------------------------------------------------#
    ## import the x3d file
    bpy.ops.import_scene.x3d(filepath=path_tox3d+filename_ofx3d+str(currentframe)+'.x3d', filter_glob="*.x3d;*.wrl", axis_forward='Z', axis_up='Y')
    #---------------------------------------------------------------#
    ## add the frame number to the text
    #bpy.data.objects["Frametext"].select=True
    #bpy.ops.object.editmode_toggle()
    #bpy.ops.font.delete()
    #bpy.ops.font.text_insert(text="Frame: "+str(currentframe))
    #bpy.ops.object.editmode_toggle()
    #bpy.data.objects["Frametext"].select=False

    #---------------------------------------------------------------#
    ## rename the geometry to "imported geometry"
    bpy.data.objects['ShapeIndexedFaceSet'].name="imported_geometry"
    bpy.data.objects['imported_geometry'].select=True
    bpy.context.scene.objects.active = bpy.data.objects['imported_geometry']
    bpy.context.active_object.material_slots[0].material.use_vertex_color_paint=True
    #bpy.ops.anim.keyframe_insert(type='Location', confirm_success=True)
    bpy.data.objects['imported_geometry'].select=False
    ## rename the default lamp to imported_lamp and delete right away
    bpy.data.objects['TODO'].name="imported_lamp"
    bpy.data.objects['imported_lamp'].select=True
    bpy.ops.object.delete()
    ## rename the default camera to imported_camera and delete right away
    bpy.data.objects['Viewpoint'].name="imported_camera"
    bpy.data.objects['imported_camera'].select=True
    bpy.ops.object.delete()

    #bpy.context.active_object.location = position

    #for object_name in candidate_list:
    #      bpy.data.objects[object_name].select = True
    #     bpy.context.active_object.location = position
    #  bpy.ops.anim.keyframe_insert(type='Location', confirm_success=True)

    bpy.data.scenes['Scene'].render.resolution_percentage=100

    bpy.ops.render.render(write_still=True)

    bpy.data.images['Render Result'].file_format='PNG'
    bpy.data.images['Render Result'].save_render(filepath=path_toimage+filename_ofimage+str(currentframe)+'.png')
    bpy.data.objects['imported_geometry'].select=True
    bpy.ops.object.delete()

bpy.data.objects['Aux_Empty'].select=True
bpy.ops.object.delete()


import glob
import os
import sys

import process_labels
from PIL import Image
import numpy as np
import concurrent.futures

from pathlib import Path

# convert labels in PRETTY colours (or PRETTY_FILMIC...) to greyscale 8 bits for mmseg

def to_greyscale_labels(png_file, out_folder):

    print (png_file)
    output_path = os.path.join(out_folder, os.path.basename(Path(png_file).name) )
    if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
        return # already done, skip

    pretty = Image.open(png_file, "r")
    label = np.asarray ( pretty )[:,:,0:3]

    tol = 10

    pretty_map = process_labels.colours_for_mode(process_labels.PRETTY)
    output = np.zeros(pretty.size, dtype=int)

    for i, label_name in enumerate (process_labels.LABEL_SEQ_NO_DOOR):

        colour = np.array ( pretty_map[label_name] )
        equality = np.logical_and ( np.greater(label, colour-tol), np.less(label, colour+tol) )
        class_map = np.all(equality, axis=-1)
#        print (f"{label_name} - {colour} :: {class_map.sum()}")
        output = output * (1- class_map) # zero out any previous labels
        output = output + class_map * i  # set greyscale label

    print ("saving to %s"%output_path)
    Image.fromarray(np.uint8(output)).save( output_path )

def to_color_labels(png_file, out_folder):

    print(png_file)
    output_path = os.path.join(out_folder, os.path.basename(Path(png_file).name))
    if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
        return  # already done, skip

    grey = Image.open(png_file, "r")
    label = np.asarray(grey)#[:, :, 0:3]
    color_seg = np.zeros((grey.size[0], grey.size[1], 3), dtype=np.uint8)

    for i, l_name in enumerate ( process_labels.LABEL_SEQ_NO_DOOR ):
        color = process_labels.colours_for_mode(process_labels.PRETTY)[l_name]
        color_seg[i == label, :] = color

    print("saving to %s" % output_path)
    Image.fromarray(color_seg).save(output_path)
    # Image.fromarray(np.uint8(color_seg)).save(output_path)

if __name__ == "__main__":

    _pool = concurrent.futures.ThreadPoolExecutor(max_workers=16)

    labels = []

    labels.extend(glob.glob(os.path.join( sys.argv[1], "labels", "*.png")))

    if True: # rgb to greyscale
        out_dir = os.path.join(sys.argv[1], "labels_8bit")
        fn = to_greyscale_labels
    else: # greyscale to rgb
        fn = to_color_labels
        out_dir = os.path.join(sys.argv[1], "labels_pretty")

    os.makedirs(out_dir, exist_ok=True)

    for lab in labels:
        fn (lab, out_dir )
        _pool.submit ( fn, lab, out_dir, )


import base64
import datetime
import io

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table
import plotly.express as px
import plotly.graph_objects as go
import seismic as sei

import pandas as pd

df1 = pd.DataFrame()

def parse_contents(contents, filename):
    print(filename)
    content_type, content_string = contents.split(",")

    decoded = base64.b64decode(content_string)
    try:
        global df1
        df1 = pd.read_csv(io.StringIO(decoded.decode("utf-8")), sep="\t")
        df1["label"] = 1

    except Exception as e:
        print(e)
        return html.Div(["There was an error processing this file."])

    print("chargé")
    result1 = dcc.RangeSlider(
        id="slid",
        min=df1["sec"].min(),
        max=df1["sec"].max(),
        step=100000,
        value=[df1["sec"].min(), df1["sec"].max()],
    )
    print("time")

    result2 = dcc.Dropdown(
        id="drop",
        options=[{"label": i, "value": i} for i in df1.label.unique()],
        multi=True,
    )
    print("drop")
    result3 = html.Button("extract", id="export", style={"color": "#FF0000"})
    print("ok11")
    return (result1, result2, result3)

    #     dcc.RangeSlider(
    #         id="slid",
    #         min=df1["sec"].min(),
    #         max=df1["sec"].max(),
    #         step=1000,
    #         value=[df1["sec"].min(), df1["sec"].max()],
    #     )
    # )

def grphcreate(valmin, valmax, values):
    a = [
        {
            "data": [
                dict(
                    x=df1[
                        (df1["sec"] > valmin)
                        & (df1["sec"] < valmax)
                        & (df1["label"].isin(values))
                        & (df1["type"].isin(["mainshock", "correlated sismicity"]))
                    ]["p0"],
                    y=df1[
                        (df1["sec"] > valmin)
                        & (df1["sec"] < valmax)
                        & (df1["label"].isin(values))
                        & (df1["type"].isin(["mainshock", "correlated sismicity"]))
                    ]["p1"],
                    mode="markers",
                    hovertext=df1[
                        (df1["sec"] > valmin)
                        & (df1["sec"] < valmax)
                        & (df1["label"].isin(values))
                        & (df1["type"].isin(["mainshock", "correlated sismicity"]))
                    ]["label"],
                    hoverinfo="text",
                    opacity=0.7,
                    marker={
                        "color": df1[
                            (df1["sec"] > valmin)
                            & (df1["sec"] < valmax)
                            & (df1["label"].isin(values))
                            & (df1["type"].isin(["mainshock", "correlated sismicity"]))
                        ]["label"],
                        "size": 8,
                        "line": {"width": 0.5, "color": "white"},
                    },
                )
            ],
            "layout": dict(
                xaxis={"title": "latitude"},
                yaxis={"title": "longitude"},
                legend={"x": 0, "y": 1},
                hovermode="closest",
                margin={"l": 45, "r": 10},
            ),
        },
        {
            "data": [
                dict(
                    x=df1[
                        (df1["sec"] > valmin)
                        & (df1["sec"] < valmax)
                        & (df1["label"].isin(values))
                        & (df1["type"].isin(["mainshock", "correlated sismicity"]))
                    ]["sec"],
                    y=df1[
                        (df1["sec"] > valmin)
                        & (df1["sec"] < valmax)
                        & (df1["label"].isin(values))
                        & (df1["type"].isin(["mainshock", "correlated sismicity"]))
                    ]["mag"],
                    mode="markers",
                    hovertext=df1[
                        (df1["sec"] > valmin)
                        & (df1["sec"] < valmax)
                        & (df1["label"].isin(values))
                        & (df1["type"].isin(["mainshock", "correlated sismicity"]))
                    ]["label"],
                    hoverinfo="text",
                    opacity=0.7,
                    marker={
                        "color": df1[
                            (df1["sec"] > valmin)
                            & (df1["sec"] < valmax)
                            & (df1["label"].isin(values))
                            & (df1["type"].isin(["mainshock", "correlated sismicity"]))
                        ]["label"],
                        "size": 8,
                        "line": {"width": 0.5, "color": "white"},
                    },
                )
            ],
            "layout": dict(
                xaxis={"title": "temps"},
                yaxis={"title": "magnitude"},
                legend={"x": 0, "y": 1},
                hovermode="closest",
                margin={"l": 25, "r": 25},
            ),
        },
    ]

    return a

def clustering(delta_d, delta_t, min_clust):
    global df1
    df1 = sei.seismic_clust(df1, delta_d, delta_t, min_clust)
    print("ok")
    back1 = df1[df1["type"] == "background"]
    cor = df1[df1["type"] == "correlated sismicity"]
    main1 = df1[df1["type"] == "mainshock"]
    # sei.GraphInterEventTime2(main1.sec, back1.sec)

# sei.GraphInterEventTime2(main.sec, back.sec)
path = "./seq/"

def export(clusters):
    sei.get_seq(df1, clusters, path)

def graphMain():
    return [
        {
            "data": [
                {
                    "x": df1[(df1["type"].isin(["mainshock"]))]["sec"],
                    "y": df1[(df1["type"].isin(["mainshock"]))]["mag"],
                    "mode": "markers",
                    "hovertext": df1[(df1["type"].isin(["mainshock"]))]["label"],
                    "hoverinfo": "text",
                    "opacity": 0.7,
                    "name": "mainshock",
                    "mode": "markers",
                },
                {
                    "x": df1[(df1["type"].isin(["background"]))]["sec"],
                    "y": df1[(df1["type"].isin(["background"]))]["mag"],
                    "mode": "markers",
                    "hovertext": "background",
                    "hoverinfo": "text",
                    "opacity": 0.7,
                    "name": "background",
                },
            ],
            "layout": dict(
                xaxis={"title": "latitude"},
                yaxis={"title": "longitude"},
                legend={"x": 0, "y": 1},
                hovermode="closest",
                margin={"l": 25, "r": 25},
            ),
        },
    ]


import openai
import tiktoken
import numpy as np
import os
import time
import logging
import re

import utils.langchain_helpers.simple_prompt

from utils import openai_helpers
from utils import redis_helpers
from utils import helpers

from langchain.prompts.chat import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    MessagesPlaceholder,
    SystemMessagePromptTemplate,
)

from utils.env_vars import *

system_message = "The assistant is a super helpful assistant that plays the role of a linguistic professor and has ultra high attention to details."

instruction = """From the above Question and Current Conversation, output search keywords to use in a search engine to get an answer for the Question. If the Question is not related to the Current Conversation, then do not use the Current Conversation when generating the Search Keywords.
Search Keywords:"""

body = """
Current Conversation:
{history}

Question: {question}
"""

context_prompt = """
<|im_start|>
{system_message}
<|im_end|>
<|im_start|>user

Current Conversation:
{history}

Question: {question}

{instruction}
<|im_end|>
<|im_start|>assistant
"""

class OldSchoolSearch():

    def search(self, query, history, pre_context, filter_param=None,  enable_unified_search=False,
                lc_agent = None, enable_cognitive_search=False, evaluate_step=True,
                topK=NUM_TOP_MATCHES, stream = False, verbose = False):

        redis_conn = redis_helpers.get_new_conn()

        completion_model = CHOSEN_COMP_MODEL
        embedding_model = CHOSEN_EMB_MODEL
        completion_enc = openai_helpers.get_encoder(completion_model)
        embedding_enc = openai_helpers.get_encoder(embedding_model)

        if verbose: print("Old Query: ", query)
        gen = openai_helpers.get_generation(completion_model)

        if history != '':

            if (gen == 4) or (gen == 3.5):
                messages = [
                    SystemMessagePromptTemplate.from_template(system_message).format(),
                    HumanMessagePromptTemplate.from_template(body).format(history=history, question=query),
                    HumanMessagePromptTemplate.from_template(instruction).format(),
                ]
                messages = openai_helpers.convert_messages_to_roles(messages)
                query = openai_helpers.contact_openai(messages)
            else:
                prompt = context_prompt.format(system_message=system_message,
                                                history=history,
                                                question=query,
                                                instruction=instruction)
                query = openai_helpers.contact_openai(prompt)

        if (gen == 4) or (gen == 3.5):
            p = ''
            for m in utils.langchain_helpers.simple_prompt.get_simple_prompt('', '', '', ''): p += m['content']
            empty_prompt_length = len(completion_enc.encode(p))
        else:
            empty_prompt_length = len(completion_enc.encode(utils.langchain_helpers.simple_prompt.get_simple_prompt('', '', '', '')))

        if verbose: print("New Query: ", query)

        max_comp_model_tokens = openai_helpers.get_model_max_tokens(completion_model)
        max_emb_model_tokens = openai_helpers.get_model_max_tokens(embedding_model)

        if lc_agent.enable_unified_search:
            context = lc_agent.unified_search(query)
        elif enable_cognitive_search:
            context = lc_agent.agent_cog_search(query)
        # elif lc_agent.use_bing:
        #     context = lc_agent.agent_bing_search(query)
        else:
            context = lc_agent.agent_redis_search(query)

        query   = completion_enc.decode(completion_enc.encode(query)[:MAX_QUERY_TOKENS])
        history = completion_enc.decode(completion_enc.encode(history)[:MAX_HISTORY_TOKENS])
        pre_context = completion_enc.decode(completion_enc.encode(pre_context)[:PRE_CONTEXT])

        context_length      = len(completion_enc.encode(context))
        query_length        = len(completion_enc.encode(query))
        history_length      = len(completion_enc.encode(history))
        pre_context_length  = len(completion_enc.encode(pre_context))

        max_context_len = max_comp_model_tokens - query_length - MAX_OUTPUT_TOKENS - empty_prompt_length - history_length - pre_context_length - 1

        context = completion_enc.decode(completion_enc.encode(context)[:max_context_len])

        prompt = utils.langchain_helpers.simple_prompt.get_simple_prompt(context, query, history, pre_context)

        if verbose:
            print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")
            print(prompt)
            print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")

        if verbose: print("OSS OAI Call")
        answer = openai_helpers.contact_openai(prompt, completion_model, MAX_OUTPUT_TOKENS, stream=stream, verbose=verbose)

        return answer


"""
Plot bulk fluxes as a time series, including all chemical tracers
if present.

"""
import matplotlib.pyplot as plt
import numpy as np
import pickle

from lo_tools import Lfun, zfun
from lo_tools import plotting_functions as pfun
import tef_fun
import flux_fun

Ldir = Lfun.Lstart()

in_dir00 = Ldir['LOo'] / 'extract'
gtagex = Lfun.choose_item(in_dir00)
in_dir0 = in_dir00 / gtagex / 'tef'
ext_name = Lfun.choose_item(in_dir0, tag='bulk', exclude_tag='bulk_plots')
in_dir = in_dir0 / ext_name

sect_list = [item.name for item in in_dir.glob('*.p')]

out_dir = in_dir0 / ext_name.replace('bulk', 'bulk_plots')
Lfun.make_dir(out_dir, clean=True)

# =================================
# get the DataFrame of all sections
gridname=gtagex.split('_')[0]
sect_df = tef_fun.get_sect_df(gridname)

testing = False

if testing:
    from importlib import reload
    reload(flux_fun)

if testing:
    sect_list = ['jdf1']
else:
    sect_list = list(sect_df.index)

# PLOTTING
fs = 12
plt.close('all')
pfun.start_plot(fs=fs, figsize=(21,10))

for sect_name in sect_list:

    tef_df, in_sign, dir_str, sdir = flux_fun.get_two_layer(in_dir, sect_name, gridname)
    cols = list(tef_df.columns)

    # Check if we have chemical variables, or just salt
    vn_list = tef_fun.vn_list
    do_chem = True
    for vn in vn_list:
        if vn+'_in' not in cols:
            do_chem = False

    if do_chem:
        vn_list = vn_list = ['Q', 'salt', 'temp', 'NO3', 'phytoplankton', 'detritus', 'oxygen', 'TIC', 'alkalinity']
        vn_list_long = vn_list + ['zooplankton', 'Ldetritus']
        NR = 3; NC = 3 # rows and columns for subplots
    else:
        vn_list = ['Q', 'salt']
        vn_list_long = vn_list
        NR = 2; NC = 1

    # filter more in time (requires that Q be the first item in vn_list)
    nhan = 1 # length of Hanning window in days (use 1 for no filtering)
    for vn in vn_list_long:
        if vn == 'Q':
            tef_df['Q_in'] = zfun.lowpass(tef_df['Qin'].to_numpy(), n=nhan)
            tef_df['Q_out'] = zfun.lowpass(tef_df['Qout'].to_numpy(), n=nhan)
        else:
            tef_df[vn+'_in'] = zfun.lowpass((tef_df[vn+'_in']*tef_df['Qin']).to_numpy(), n=nhan)/tef_df['Q_in']
            tef_df[vn+'_out'] = zfun.lowpass((tef_df[vn+'_out']*tef_df['Qout']).to_numpy(), n=nhan)/tef_df['Q_out']

    # adjust units
    tef_df['Q_in'] = tef_df['Q_in']/1000
    tef_df['Q_out'] = tef_df['Q_out']/1000

    # labels and colors
    ylab_dict = {'Q': r'Transport $[10^{3}\ m^{3}s^{-1}]$',
                'salt': r'Salinity',
                'temp': r'Pot. Temp. $[^{o}C]$',
                'NO3': r'Nitrate $[\mu mol\ N\ L^{-1}]$',
                'phytoplankton': r'phytoplankton $[\mu mol\ N\ L^{-1}]$',
                'detritus': r'detritus $[\mu mol\ N\ L^{-1}]$',
                'oxygen': r'oxygen $[\mu mol\ O_{2}\ L^{-1}]$',
                'TIC': r'TIC $[\mu mol\ C\ L^{-1}]$',
                'alkalinity': r'Alkalinity $[\mu equiv\ L^{-1}]$'}
    import string
    abc = list(string.ascii_lowercase)
    incolor = 'r'
    outcolor = 'b'
    lw = 2

    fig, axes = plt.subplots(nrows=NR, ncols=NC, squeeze=False)

    ii = 0
    for vn in vn_list:
        ir, ic = zfun.get_irc(ii, NC)
        ax = axes[ir, ic]
        tef_df[[vn+'_in',vn+'_out']].plot(ax=ax, legend=False, color=[incolor, outcolor], grid=True, lw=lw)
        ax.set_ylabel(ylab_dict[vn])
        ax.text(.03, .95, '('+abc[ii]+')', va='top', weight='bold', transform=ax.transAxes,
            bbox=dict(facecolor='w', edgecolor='None', alpha=0.5))
        if ir < NR-1:
            ax.set_xticklabels([])
        if vn == 'Q':
            ax.set_title(gtagex + ' : ' + sect_name + ' : Positive is ' + dir_str)
            ax.text(.97, .95, 'Inflow', ha='right', va='top', weight='bold', c=incolor,
                transform=ax.transAxes, size=1.2*fs,
                bbox=dict(facecolor='w', edgecolor='None', alpha=0.5))
            ax.text(.97, .05, 'Outflow', ha='right', va='bottom', weight='bold', c=outcolor,
                transform=ax.transAxes, size=1.2*fs,
                bbox=dict(facecolor='w', edgecolor='None', alpha=0.5))
        if vn == 'phytoplankton':
            tef_df[['zooplankton_in','zooplankton_out']].plot(ax=ax, legend=False, color=[incolor, outcolor],
                grid=True, alpha=.5, lw=lw)
            ax.text(.97, .95, 'Transparent = zooplankton', ha='right', va='top', weight='bold', c='k',
                transform=ax.transAxes, size=fs, alpha=.5,
                bbox=dict(facecolor='w', edgecolor='None', alpha=0.5))
        if vn == 'detritus':
            tef_df[['Ldetritus_in','Ldetritus_out']].plot(ax=ax, legend=False, color=[incolor, outcolor],
                grid=True, alpha=.5, lw=lw)
            ax.text(.97, .95, 'Transparent = Ldetritus', ha='right', va='top', weight='bold', c='k',
                transform=ax.transAxes, size=fs, alpha=.5,
                bbox=dict(facecolor='w', edgecolor='None', alpha=0.5))
        ii += 1

    fig.tight_layout()

    if testing:
        plt.show()
    else:
        plt.savefig(out_dir / (sect_name + '.png'))
        plt.close()

pfun.end_plot()


n = 3 # number of elements to sort in ascending order
a = [1, 2, 3] # elements to sort

def bubbleSort(a):
    # Time O(n2)
    # Memory O(1)
    # a: array of length n
    n = len(a)
    numSwaps = 0
    for i in range(n):
        numberOfSwaps = 0
        for j in range(n-1):
            if a[j] > a[j+1]:
                a[j], a[j+1] = a[j+1], a[j]
                numberOfSwaps += 1
                numSwaps += 1
        if numberOfSwaps == 0:
            break

print("Array is sorted in %d swaps." % numSwaps)
print("First Element: %d" % a[0])
print("Last Element: %d" % a[-1])