import json
from unittest.case import TestCase

import pytest
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient

from audit.models import AuditLog, RelatedObjectType
from environments.models import Environment
from features.models import Feature, FeatureSegment
from organisations.models import Organisation, OrganisationRole
from projects.models import Project
from segments.models import Segment
from util.tests import Helper

@pytest.mark.django_db
class FeatureSegmentViewSetTestCase(TestCase):
    def setUp(self) -> None:
        self.client = APIClient()
        user = Helper.create_ffadminuser()
        self.client.force_authenticate(user=user)

        organisation = Organisation.objects.create(name="Test Org")

        user.add_organisation(organisation, OrganisationRole.ADMIN)

        self.project = Project.objects.create(
            organisation=organisation, name="Test project"
        )
        self.environment_1 = Environment.objects.create(
            project=self.project, name="Test environment 1"
        )
        self.environment_2 = Environment.objects.create(
            project=self.project, name="Test environment 2"
        )
        self.feature = Feature.objects.create(project=self.project, name="Test feature")
        self.segment = Segment.objects.create(project=self.project, name="Test segment")

    def test_list_feature_segments(self):
        # Given
        base_url = reverse("api-v1:features:feature-segment-list")
        url = (
            f"{base_url}?environment={self.environment_1.id}&feature={self.feature.id}"
        )
        segment_2 = Segment.objects.create(project=self.project, name="Segment 2")
        segment_3 = Segment.objects.create(project=self.project, name="Segment 3")

        FeatureSegment.objects.create(
            feature=self.feature, segment=self.segment, environment=self.environment_1
        )
        FeatureSegment.objects.create(
            feature=self.feature, segment=segment_2, environment=self.environment_1
        )
        FeatureSegment.objects.create(
            feature=self.feature, segment=segment_3, environment=self.environment_1
        )
        FeatureSegment.objects.create(
            feature=self.feature, segment=self.segment, environment=self.environment_2
        )

        # When
        response = self.client.get(url)

        # Then
        assert response.status_code == status.HTTP_200_OK
        response_json = response.json()
        assert response_json["count"] == 3
        for result in response_json["results"]:
            assert result["environment"] == self.environment_1.id

    def test_create_feature_segment(self):
        # Given
        data = {
            "feature": self.feature.id,
            "segment": self.segment.id,
            "environment": self.environment_1.id,
        }
        url = reverse("api-v1:features:feature-segment-list")

        # When
        response = self.client.post(
            url, data=json.dumps(data), content_type="application/json"
        )

        # Then
        assert response.status_code == status.HTTP_201_CREATED
        response_json = response.json()
        assert response_json["id"]

    def test_delete_feature_segment(self):
        # Given
        feature_segment = FeatureSegment.objects.create(
            feature=self.feature, environment=self.environment_1, segment=self.segment
        )
        url = reverse(
            "api-v1:features:feature-segment-detail", args=[feature_segment.id]
        )

        # When
        response = self.client.delete(url)

        # Then
        assert response.status_code == status.HTTP_204_NO_CONTENT
        assert not FeatureSegment.objects.filter(id=feature_segment.id).exists()

    def test_audit_log_created_when_feature_segment_created(self):
        # Given
        url = reverse("api-v1:features:feature-segment-list")
        data = {
            "segment": self.segment.id,
            "feature": self.feature.id,
            "environment": self.environment_1.id,
        }

        # When
        response = self.client.post(url, data=data)

        # Then
        assert response.status_code == status.HTTP_201_CREATED
        assert (
            AuditLog.objects.filter(
                related_object_type=RelatedObjectType.FEATURE.name
            ).count()
            == 1
        )

    def test_priority_of_multiple_feature_segments(self):
        # Given
        url = reverse("api-v1:features:feature-segment-update-priorities")

        # another segment and 2 feature segments for the same feature / the 2 segments
        another_segment = Segment.objects.create(
            name="Another segment", project=self.project
        )
        feature_segment_default_data = {
            "environment": self.environment_1,
            "feature": self.feature,
        }
        feature_segment_1 = FeatureSegment.objects.create(
            segment=self.segment, **feature_segment_default_data
        )
        feature_segment_2 = FeatureSegment.objects.create(
            segment=another_segment, **feature_segment_default_data
        )

        # reorder the feature segments
        assert feature_segment_1.priority == 0
        assert feature_segment_2.priority == 1
        data = [
            {"id": feature_segment_1.id, "priority": 1},
            {"id": feature_segment_2.id, "priority": 0},
        ]

        # When
        response = self.client.post(
            url, data=json.dumps(data), content_type="application/json"
        )

        # Then the segments are reordered
        assert response.status_code == status.HTTP_200_OK
        json_response = response.json()
        assert json_response[0]["id"] == feature_segment_1.id
        assert json_response[1]["id"] == feature_segment_2.id


# -*- coding: utf-8 -*-
"""
Calculate points to each dog and make ranking lists by dog classes as given at https://esakt.eu/images/Aparim15a.pdf.
"""
import pandas as pd

# Importing the dataset
df = pd.read_csv('dogshows_bernese_est_2018.csv')

# make copy of date column and extract dates from it
df.insert(loc=1, column='date', value=[str[-10:] for str in df['naitus']], allow_duplicates=True)
try:
    df['date'] = pd.to_datetime(df['date'], dayfirst=True)
except ValueError:
    print('unable to convert to dates')
    pass

# processing judge information - separation of judge name and country
df.insert(loc=7, column='judge_Country', value=df['kohtunik'], allow_duplicates=True) # copy column with new name
df['kohtunik'] = df['kohtunik'].str.replace('Kohtunik: ','').str.split(", ").str[0] # replace strings in column and select first element
df['judge_Country'] = df['judge_Country'].str.replace('Eesti','Estonia').str.split(", ").str[1] # replace strings in column and select last element
df['judge_Country'] = df['judge_Country'].astype('category')

# divide dog class and gender to a separate columns
df.insert(loc=3, column='gender', value=df['klass'], allow_duplicates=True) # copy column with new name
df['klass'] = df['klass'].str.replace('E ','').str.replace('I ', '') # remove gender info from class
df['gender'] = df['gender'].str.split(" ").str[0] # replace strings in column and select last element

# delete inferior classes (repeating show results)
df = df[df.klass != 'Kasv'] # delete rows with value 'Kasv'
df = df[df.klass != 'Paar'] # delete rows with value 'Paar'

# delete unofficial show results
df = df[~df.naitus.str.contains("EKL Jõulushow")].reset_index(drop=True)

# remove some spaces from results and transform string to a list of results
df['tulemused'] = df['tulemused'].str.replace('SP 1','SP1').str.replace('SP 2','SP2').str.replace('SP 3','SP3').str.replace('SP 4','SP4').str.replace('VL 1','VL1').str.replace('VL 2','VL2').str.replace('VL 3','VL3').str.replace('1 EAH','1EAH').str.replace('2 EAH','2EAH').str.replace('3 EAH','3EAH').str.replace('4 EAH','4EAH').str.replace('Jun SERT','JunSERT')
df["tulemused"] = df["tulemused"].str.split(' ')

# separate dog classes to 4 levels
df_babies = df[(df['klass'] == 'Beebi')]
df_puppies = df[(df['klass'] == 'Kuts')]
df_juniors = df[(df['klass'] == 'Jun')]
df_open = df[(df['klass'] == 'Ava') | (df['klass'] == 'Ch') | (df['klass'] == 'Noo') | (df['klass'] == 'Jun') | (df['klass'] == 'Vet')] # Jun ,ust be included

# count amounts of participants per class and add column with that information to the class data frame
df_babies_per_show = df_babies.groupby('naitus').size().reset_index(name='babies_per_show')
df_babies = pd.merge(df_babies, df_babies_per_show, on=['naitus'], how='inner')
df_puppies_per_show = df_puppies.groupby('naitus').size().reset_index(name='puppies_per_show')
df_puppies = pd.merge(df_puppies, df_puppies_per_show, on=['naitus'], how='inner')
df_juniors_per_show = df_juniors.groupby('naitus').size().reset_index(name='juniors_per_show')
df_juniors = pd.merge(df_juniors, df_juniors_per_show, on=['naitus'], how='inner')
df_open_per_show = df_open.groupby('naitus').size().reset_index(name='dogs_per_show')
df_open = pd.merge(df_open, df_open_per_show, on=['naitus'], how='inner')

"""Hierarcy of titles by dog classes

All dogs (open class - dogs of Ava,Ch, Noo, Jun, Vet classes):
TP
VSP
PI2 + SK, PE2 + SK
PI3 + SK, PE3 + SK
PI4 + SK, PE4 + SK

Junior dogs(dogs of Jun class):
TPJ
VSPJ
SP2 + SK
SP3 + SK
SP4 + SK

Puppies class (dogs of Kuts, Beebi classes):
TPK või TPB
VSPK või VSPB
2EAH
3EAH
4EAH"""

# Calculate points to give
def calculate_points(row):

    bonus = 0
    points = 0
    sk = False # decide if dog is sertificate candidate

    # look for a dog count per show
    if hasattr(row, 'dogs_per_show'):
        dogscount = row['dogs_per_show']
        klass = 1
    elif hasattr(row, 'juniors_per_show'):
        dogscount = row['juniors_per_show']
        klass = 2
    elif hasattr(row, 'puppies_per_show'):
        dogscount = row['puppies_per_show']
        klass = 3
    elif hasattr(row, 'babies_per_show'):
        dogscount = row['babies_per_show']
        klass = 4

    # choose bonus points depending on amount of dogs attended
    if dogscount >= 1 and dogscount <= 5: bonus = 0
    elif dogscount >= 6 and dogscount <= 10: bonus = 1
    elif dogscount >= 11 and dogscount <= 15: bonus = 2
    elif dogscount >= 16 and dogscount <= 25: bonus = 3
    elif dogscount >= 26 and dogscount <= 50: bonus = 4
    elif dogscount >= 51 and dogscount <= 75: bonus = 5
    elif dogscount >= 76 and dogscount <= 100: bonus = 6
    elif dogscount >= 101 and dogscount <= 150: bonus = 7
    elif dogscount > 150: bonus = 8

    try:
        if 'SK' in row["tulemused"]: sk = True

        for result in row["tulemused"]:
            if (result == 'TP' and klass == 1) or (result == 'TPJ' and klass == 2) or (result == 'TPK' and klass == 3) or (result == 'TPB' and klass == 4):
                points = 10 + bonus
            elif (result == 'VSP' and klass == 1) or (result == 'VSPJ' and klass == 2) or (result == 'VSPK' and klass == 3) or (result == 'VSPB' and klass == 4):
                points = 9 + bonus
            elif (result == 'PI2' and sk == True and klass == 1) or (result == 'PE2' and sk == True and klass == 1) or (result == '2EAH' and (klass == 3 or klass == 4)) or (result == 'SP2' and sk == True and klass == 2):
                points = 7 + bonus
            elif (result == 'PI3' and sk == True and klass == 1) or (result == 'PE3' and sk == True and klass == 1) or (result == '3EAH' and (klass == 3 or klass == 4)) or (result == 'SP3' and sk == True and klass == 2):
                points = 6 + bonus
            elif (result == 'PI4' and sk == True and klass == 1) or (result == 'PE4' and sk == True and klass == 1) or (result == '4EAH' and (klass == 3 or klass == 4)) or (result == 'SP4' and sk == True and klass == 2):
                points = 5 + bonus
    except:
        return points

    return points

# make new column with zero points to all dogs and then run calculations
df_open["points"] = 0
df_open['points'] = df_open.apply(calculate_points, axis=1)
df_juniors["points"] = 0
df_juniors['points'] = df_juniors.apply(calculate_points, axis=1)
df_puppies["points"] = 0
df_puppies['points'] = df_puppies.apply(calculate_points, axis=1)
df_babies["points"] = 0
df_babies['points'] = df_babies.apply(calculate_points, axis=1)

# filter out only 5 biggest results per dog
df_open = df_open.sort_values(['koer','points'],ascending=False).groupby('koer').head()
df_juniors = df_juniors.sort_values(['koer','points'],ascending=False).groupby('koer').head()
df_puppies = df_puppies.sort_values(['koer','points'],ascending=False).groupby('koer').head()
df_babies = df_babies.sort_values(['koer','points'],ascending=False).groupby('koer').head()

# sum dog results
res_open = df_open.groupby(['koer', 'gender'])['points'].sum().reset_index()
res_juniors = df_juniors.groupby(['koer', 'gender'])['points'].sum().reset_index()
res_puppies = df_puppies.groupby(['koer', 'gender'])['points'].sum().reset_index()
res_babies = df_babies.groupby(['koer', 'gender'])['points'].sum().reset_index()

# sort values by points
res_open = res_open.sort_values('points', ascending=False).reset_index(drop=True)
res_juniors = res_juniors.sort_values('points', ascending=False).reset_index(drop=True)
res_puppies = res_puppies.sort_values('points', ascending=False).reset_index(drop=True)
res_babies = res_babies.sort_values('points', ascending=False).reset_index(drop=True)

# filter out only estonian dogs, i.e. select only rows where column 'koer' has prefix 'EST'
res_open_EST = res_open[res_open.koer.str.match("EST-")].reset_index(drop=True)
res_juniors_EST = res_juniors[res_juniors.koer.str.match("EST-")].reset_index(drop=True)
res_puppies_EST = res_puppies[res_puppies.koer.str.match("EST-")].reset_index(drop=True)
res_babies_EST = res_babies[res_babies.koer.str.match("EST-")].reset_index(drop=True)

# join puppies and babies
frames = [res_puppies_EST, res_babies_EST]
res_puppies_EST = pd.concat(frames)
res_puppies_EST = res_puppies_EST.groupby(['koer', 'gender'])['points'].sum().reset_index()
res_puppies_EST = res_puppies_EST.sort_values('points', ascending=False).reset_index(drop=True)

# write dog of the year results data to a files
res_open_EST.to_excel('Tulemused_ava_EST_2018.xlsx', sheet_name='Tulemused avaklass')
res_juniors_EST.to_excel('Tulemused_juunior_EST_2018.xlsx', sheet_name='Tulemused juuniorklass')
res_puppies_EST.to_excel('Tulemused_kutsikad_EST_2018.xlsx', sheet_name='Tulemused kutsika klass')

df_open.to_excel('ava_2018.xlsx', sheet_name='avaklass')
df_juniors.to_excel('juunior_2018.xlsx', sheet_name='juuniorklass')
df_puppies.to_excel('kutsikad_2018.xlsx', sheet_name='kutsika klass')


import time, os
from threading import Thread, current_thread
from multiprocessing import Process, current_process, Pool
import sys

COUNT = 200000000
SLEEP = 10

def io_bound(sec):

    pid = os.getpid()
    threadName = current_thread().name
    processName = current_process().name

    #print(f"{pid} * {processName} * {threadName} ---> Start sleeping...")
    print(pid," * ",processName," * ",threadName," ---> Start sleeping...")
    time.sleep(sec)
    print(pid," * ",processName," * ",threadName," ---> Finish sleeping...")
    #print(f"{pid} * {processName} * {threadName} ---> Finished sleeping...")

def cpu_bound(n):

    pid = os.getpid()
    threadName = current_thread().name
    processName = current_process().name

    print(f"{pid} * {processName} * {threadName} ---> Start counting...")

    while n>0:
        n -= 1

    print(f"{pid} * {processName} * {threadName} ---> Finished counting...")

if __name__=="__main__":
    start = time.time()

    if len(sys.argv)!=2:
        print("USO: python lab3.py DEBUG")
        sys.exit(1)

    DEBUG=int(sys.argv[1])

    if DEBUG==1:
        io_bound(SLEEP)
        io_bound(SLEEP)
    elif DEBUG==2:
        t1 = Thread(target = io_bound, args =(SLEEP, ))
        t2 = Thread(target = io_bound, args =(SLEEP, ))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
    elif DEBUG==3:
        cpu_bound(COUNT)
        cpu_bound(COUNT)
    elif DEBUG==4:
        t1 = Thread(target = cpu_bound, args =(COUNT, ))
        t2 = Thread(target = cpu_bound, args =(COUNT, ))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
    elif DEBUG==5:
        p1 = Process(target = cpu_bound, args =(COUNT, ))
        p2 = Process(target = cpu_bound, args =(COUNT, ))
        p1.start()
        p2.start()
        p1.join()
        p2.join()
    elif DEBUG==6:
        pool = Pool(processes=2)
        pool.apply_async(cpu_bound, [COUNT])
        pool.apply_async(cpu_bound, [COUNT])
        pool.close()
        pool.join()
    elif DEBUG==7:
        p1 = Process(target = io_bound, args =(SLEEP, ))
        p2 = Process(target = io_bound, args =(SLEEP, ))
        p1.start()
        p2.start()
        p1.join()
        p2.join()

    end = time.time()
    print('Time taken in seconds -', end - start)


from __future__ import division
from copy import deepcopy
from json import load, dump
from itertools import chain
from graph.Graph import Graph
from graph.GraphBuilder import GraphBuilder
from utils.Preprocessing import preprocess_string
from sampling.graph.KMeansForUberTraces import KMeansForUber
from sampling.graph.DBScan import DBSCAN
import random
import operator

"""
A Tree is the representation of an dendrogram generated by Perch (XCluster).
"""

class Node():

    def __init__(self, id, label, data, leaf):
        self.id = id
        self.label = label
        self.parent = data
        self.leaf = leaf

    @staticmethod
    def fromFile(line):
        # Line format is "node_id parent_id   label"
        tokens = line.strip().split("\t")
        assert len(tokens) == 3
        label = tokens[2]
        leaf = False
        if label != 'None':
            leaf = True
        return Node(tokens[0], tokens[2], tokens[1], leaf)

    def __deepcopy__(self, memo):
        return self.__copy__()

    def __copy__(self):
        return Node(self.id, self.label, self.parent, self.leaf)

class Tree():

    def __init__(self, id, nodes):
        self.id = id
        self.nodes = {}
        self.parents = {}
        self.children = {}
        self.labels = {}
        self.edgelabels = {}
        self.edge_lengths = {}

        self.leaves_per_node = {}
        self.selected_leaves_per_node = {}

        for node in nodes:
            self.nodes[node.id] = node
            self.parents[node.id] = set()
            self.children[node.id] = set()
            if node.label not in self.labels:
                self.labels[node.label] = set()
            self.labels[node.label].add(node.id)

    def edge(self, pid, cid):
        return "%s,%s" % (self.nodes[pid].label, self.nodes[cid].label)

    def link(self, pid, cid):
        if pid in self.nodes and cid in self.nodes:
            self.parents[cid].add(pid)
            self.children[pid].add(cid)
            edgelabel = self.edge(pid, cid)
            if edgelabel not in self.edgelabels:
                self.edgelabels[edgelabel] = set()
            self.edgelabels[edgelabel].add((pid, cid))
            self.edge_lengths[(pid, cid)] = 0.0000001

    def unlink(self, pid, cid):
        self.children[pid].remove(cid)
        self.parents[cid].remove(pid)
        edgelabel = self.edge(pid, cid)
        self.edgelabels[edgelabel].remove((pid, cid))
        if not self.edgelabels[edgelabel]:
            del self.edgelabels[edgelabel]
        del self.edge_lengths[(pid, cid)]

    def insert(self, node, pids, cids):
        self.nodes[node.id] = node
        self.parents[node.id] = set()
        self.children[node.id] = set()
        if node.label not in self.labels:
            self.labels[node.label] = set()
        self.labels[node.label].add(node.id)

        for p in pids:
            for c in cids:
                # Check if there is an edge between p and c
                if c in (self.iter_parent_ids(p)) and (p in
                        self.iter_child_ids(c)):
                    self.unlink(p,c)
        for p in pids:
            self.link(p,node.id)
        for c in cids:
            self.link(node.id, c)

    def remove_all(self, nodes):
        for node in nodes:
            self.remove(node)

    def remove(self, node):
        id = node.id

        # Do nothing if the node doesn't actually exist in the tree
        if id not in self.nodes:
            return

        # Link the node's parents and children together
        for pid in self.parents[id]:
            for cid in self.children[id]:
                self.link(pid, cid)

        for pid in set(self.parents[id]):
            if (pid in self.iter_parent_ids(id)) and (id in
            self.iter_child_ids(pid)):
                self.unlink(pid, id)

        for cid in set(self.children[id]):
            if (id in self.iter_parent_ids(cid)) and (cid in
            self.iter_child_ids(id)):
                self.unlink(id, cid)

        # Finally, remove the node
        label = node.label
        self.labels[label].remove(id)
        if not self.labels[label]:
            del self.labels[label]
        del self.nodes[id]
        del self.children[id]
        del self.parents[id]

    def remove_all_nodes(self, nodes):
        for node in nodes:
            self.remove_node(node["id"], node["label"])

    def remove_node(self, nodeid, nodelabel):
        id = nodeid

        # Do nothing if the node doesn't actually exist in the tree
        if id not in self.nodes:
            return

        # Link the node's parents and children together
        for pid in self.parents[id]:
            for cid in self.children[id]:
                self.link(pid, cid)

        for pid in set(self.parents[id]):
            self.unlink(pid, id)

        for cid in set(self.children[id]):
            self.unlink(id, cid)

        # Finally, remove the node
        label = nodelabel
        self.labels[label].remove(id)
        if not self.labels[label]:
            del self.labels[label]
        del self.nodes[id]
        del self.children[id]
        del self.parents[id]

    def size(self):
        return len(self.nodes)

    def num_edges(self):
        return len(self.edge_lengths)

    def has_node(self, id):
        if id in self.nodes:
            return True
        return False

    def get_node(self, id):
        return self.nodes[id]

    def get_node_label(self, id):
        return self.nodes[id].label

    def get_ids(self):
        return self.nodes.keys()

    def iter_ids(self):
        return self.nodes.keys()

    def iter_nodes(self):
        return self.nodes.values()

    def count_parents(self, id):
        return id in self.parents and len(self.parents[id]) or 0

    def count_children(self, id):
        return id in self.children and len(self.children[id]) or 0

    def count_neighbours(self, id):
        return self.count_parents(id) + self.count_children(id)

    def get_parents(self, id):
        return self.parents[id]

    def get_children(self, id):
        #return id in self.children and self.children[id]
        return self.children[id]

    def iter_parent_ids(self, id):
        return id in self.parents and iter(self.parents[id]) or iter([])

    def iter_child_ids(self, id):
        return id in self.children and iter(self.children[id]) or iter([])

    def iter_neighbour_ids(self, id):
        return chain(self.iter_parent_ids(id), self.iter_child_ids(id))

    def iter_labels(self):
        return self.labels.keys()

    def iter_nodeids_for_label(self, label):
        return label in self.labels and iter(self.labels[label]) or iter([])

    def iter_nodes_for_label(self, label):
        return list(map(lambda id: self.nodes[id], self.iter_nodeids_for_label(label)))

    def iter_edgelabels(self):
        return self.edgelabels.keys()

    def iter_edgetimings(self):
        return self.edge_lengths.values()

    def iter_lengths_for_edgelabel(self, edgelabel):
        return list(map(lambda edge: self.get_edge_length(edge), self.edgelabels[edgelabel]))

    def get_neighbour_labels(self, node):
        return [self.nodes[nid].label for nid in self.iter_neighbour_ids(node.id)]

    def get_label_count(self, label):
        return label in self.labels and len(self.labels[label]) or 0

    def get_edgelabel_count(self, edgelabel):
        return edgelabel in self.edgelabels and len(self.edgelabels[edgelabel]) or 0

    def get_edge_length(self, edge):
        return self.edge_lengths[edge]

    def get_root_node(self):
        for node in self.iter_nodes():
            if node.parent == "None":
                return node.id
        return

    def get_leaves(self):
        all_leaves = []
        for node in self.iter_nodes():
            if node.leaf:
                all_leaves.append(node)
        return all_leaves

    def num_leaves(self):
        total_leaves = 0
        for node in self.iter_nodes():
            if node.leaf:
                total_leaves += 1
        return total_leaves

    def clone(self):
        return deepcopy(self)

    def relabel(self, id, label):
        if id not in self.nodes:
            return

        node = self.nodes[id]

        # Unlink edges
        parents = set(self.parents[id])
        children = set(self.children[id])
        for pid in parents:
            self.unlink(pid, id)
        for cid in children:
            self.unlink(id, cid)

        # Remove the old labelling
        self.labels[node.label].remove(id)
        if not self.labels[node.label]:
            del self.labels[node.label]

        # Add the new labelling
        if label not in self.labels:
            self.labels[label] = set()
        self.labels[label].add(id)

        node.label = label

        # Relink edges
        for pid in parents:
            self.link(pid, id)
        for cid in children:
            self.link(id, cid)

    def toGraph(self):
        builder = GraphBuilder(self.id)
        root = self.get_root_node()

        for nodeid, node in self.nodes.items():
            #builder.node(nodeid, node.label)
            if(nodeid != root):
                builder.node(nodeid, node.label)
            else :
                builder.node(nodeid, 0)

        for (pid, cid), edgeweight in self.edge_lengths.items():
            builder.edge(pid, cid, edgeweight)

        return builder()

    # Ainda precisa ser alterado
    def toJSON(self):
        reports = []
        for nodeid in self.nodes:
            node = self.nodes[nodeid]
            report = node.parent
            parents_list = list(self.parents[nodeid])
            if not parents_list:
                report = "None"
            else:
                report = str(self.parents[nodeid])
            reports.append(report)
        return {"id": self.id, "reports": reports}

    def dumpJSON(self, filename):
        dump([self.toJSON()], open(filename, "w"), indent=2)

    @staticmethod
    def loadTree(filename):
        return Tree.fromTree(filename)

    @staticmethod
    def fromTree(treefile):
        lines = open(treefile, 'r')
        nodes = [Node.fromFile(x) for x in lines]
        tree = Tree("tree", nodes)
        for node in nodes:
            assert node.parent
            if node.parent != "None":
                tree.link(node.parent, node.id)
        # proactively remove the 'merge' nodes
        #merges = filter(lambda node: node.field_equals("Operation", "merge"), nodes)
        #for merge in merges:
        #    tree.remove(merge)
        return tree

    def update_node_leaves(self, node, leaves):
        self.leaves_per_node[node] = leaves

    def get_leaves_node(self, node):
        return self.leaves_per_node[node]

    def node_has_updated_leaves(self, node):
        if node in self.leaves_per_node:
            return True
        return False

    def get_selected_leaves_per_node(self, node):
        return self.selected_leaves_per_node[node]

    def update_selected_leaves_per_node(self, path):
        for p in path:
            if p not in self.selected_leaves_per_node:
                self.selected_leaves_per_node[p] = 0
            self.selected_leaves_per_node[p] += 1

    def count_node_leaves(self, node):
        """
            Returns the number of leaves in the subtree started at this node.
        """
        if self.node_has_updated_leaves(node):
            return self.get_leaves_node(node)

        num_leaves = 0
        visited = set()
        stack = [node]
        while stack:
            vertex = stack.pop()
            if vertex not in visited:
                visited.add(vertex)
                stack.extend(self.get_children(vertex) - visited)
                if(self.is_leaf(vertex)):
                    num_leaves += 1

        self.update_node_leaves(node, num_leaves)
        return num_leaves

    '''
    Function to delete leaf and, if necessary, it's parents
    '''
    def delete_node_for_sampling(self, nodeid):
        node = self.get_node(nodeid)

        if self.count_children(nodeid) > 0:
            return

        node_parents = deepcopy(self.get_parents(node.id))
        self.remove_node(node.id, node.label)
        for parent in node_parents:
            self.delete_node_for_sampling(parent)

    '''
    Sampling Functions
    '''
    def samplingTree(self, percentage):
        samples = set()
        num_leaves = self.num_leaves()
        num_samples = int(num_leaves * percentage)
        root = self.get_root_node()

        # Variables to control paths
        node_per_level = {}

        count_item = 0
        #for count_item in range(0, num_samples):
        while count_item < num_samples:
            (leaf, node_per_level) = self.get_new_leaf(node_per_level, samples)
            if leaf not in samples and self.is_leaf(leaf):
                samples.add(leaf)
                #self.update_selected_leaves_per_node(path)
                count_item += 1

        return samples

    def samplingTreeEqualProbability(self, percentage):
        samples = []
        num_leaves = self.num_leaves()
        num_samples = int(num_leaves * percentage)
        root = self.get_root_node()

        # Variables to control paths
        node_per_level = {}

        count_item = 0
        #for count_item in range(0, num_samples):
        while count_item < num_samples:
            (leaf, path) = self.get_new_leaf_equal_probability()
            if leaf not in samples and self.is_leaf(leaf):
                #samples.add(leaf)
                samples.append(self.get_node_label(leaf))
                self.delete_node_for_sampling(leaf)
                self.update_selected_leaves_per_node(path)
                count_item += 1

        return samples

    def samplingTreeWithProbability(self, percentage):
        samples = set()
        num_leaves = self.num_leaves()
        num_samples = int(num_leaves * percentage)
        root = self.get_root_node()

        # Variables to control paths
        node_per_level = {}

        count_item = 0
        #for count_item in range(0, num_samples):
        while count_item < num_samples:
            (leaf, path) = self.get_new_leaf_probability()
            if leaf not in samples and self.is_leaf(leaf):
                samples.add(leaf)
                self.update_selected_leaves_per_node(path)
                count_item += 1

        return samples

    '''
    Function to check if node is leaf
    '''
    def is_leaf(self, node):
        if self.count_children(node) == 0:
            return True
        return False

    """
        Returns an item from the given list based on its probabilities
    """
    def probability_pick(self, some_list, probabilities):
        x = random.uniform(0, 1)
        cumulative_probability = 0.0
        for item, item_probability in zip(some_list, probabilities):
            cumulative_probability += item_probability
            if x < cumulative_probability: break
        return item

    def get_new_leaf_equal_probability(self):
        root = self.get_root_node()
        selected_child = root
        path = []
        while(not self.is_leaf(selected_child)):
            children = []
            prob = []
            for child in self.get_children(selected_child):
                children.append(child)
                prob.append(0.5)

            # Select new child based on probability
            selected_child = self.probability_pick(children, prob)
            path.append(selected_child)

        return (selected_child, path)

    def get_new_leaf_probability(self):
        root = self.get_root_node()
        selected_child = root
        path = []
        while(not self.is_leaf(selected_child)):
            children_leaves = {}
            total_leaves = 0
            for child in self.get_children(selected_child):
                num_leaves = self.count_node_leaves(child)
                if(child in self.selected_leaves_per_node):
                    if(num_leaves > self.get_selected_leaves_per_node(child)):
                        children_leaves[child] = num_leaves
                        total_leaves += num_leaves
                else:
                    children_leaves[child] = num_leaves
                    total_leaves += num_leaves
            children = []
            prob = []
            for c in children_leaves:
                children.append(c)
                prob.append(1-(children_leaves[c]/total_leaves))

            # Select new child based on probability
            selected_child = self.probability_pick(children, prob)
            path.append(selected_child)

        return (selected_child, path)

    '''
    Function to get a new leaf considering all previous paths taken

    Params:
        node_per_level: array to control paths taken

    Return:
        leaf: new leaf
        node_per_level: array updated with new path
    '''
    def old_get_new_leaf(self, node_per_level):
        root = self.get_root_node()
        level_count = 0
        selected_child = root

        while(not self.is_leaf(selected_child)):
            min_value = float('inf')
            for child in self.get_children(selected_child):
                if level_count not in node_per_level:
                    node_per_level[level_count] = {}

                if child not in node_per_level[level_count]:
                    node_per_level[level_count][child] = 1
                    selected_child = child
                    break
                else:
                    if min_value > node_per_level[level_count][child]:
                        min_value = node_per_level[level_count][child]
                        selected_child = child
            node_per_level[level_count][selected_child] += 1
            level_count += 1

        return (selected_child, node_per_level)

    '''
    Function to get a new leaf considering all previous paths taken

    Params:
        node_per_level: array to control paths taken

    Return:
        leaf: new leaf
        node_per_level: array updated with new path
    '''
    def get_new_leaf(self, node_per_level, samples):
        root = self.get_root_node()
        level_count = 1
        selected_child = root

        #print (node_per_level)

        path = []
        visited = set()
        while(not self.is_leaf(selected_child)):
            min_value = float('inf')
            has_valid_child = False
            for child in self.get_children(selected_child):
                if child not in visited:
                    has_valid_child = True
                    if level_count not in node_per_level:
                        node_per_level[level_count] = {}

                    if child not in node_per_level[level_count]:
                        #node_per_level[level_count][child] = 1
                        selected_child = child
                        break
                    else:
                        if min_value > node_per_level[level_count][child]:
                            min_value = node_per_level[level_count][child]
                            selected_child = child
                #node_per_level[level_count][selected_child] += 1

            if not has_valid_child:
                #print (path)
                path.remove(selected_child)
                visited.add(selected_child)
                if len(path) > 0:
                    selected_child = path[-1]
                    level_count -= 1
                else:
                    if selected_child not in path:
                        path.append(selected_child)
                    #print (selected_child)
                    break

            if selected_child in samples:
                visited.add(selected_child)
                if len(path) > 0:
                    selected_child = path[-1]
                else:
                    path.append(selected_child)
            else:
                if selected_child not in path:
                    path.append(selected_child)
                level_count += 1

        # Update node_per_level based on the path
        level_count = 1
        #print (path)
        #print (node_per_level)
        for c in path:
            if level_count not in node_per_level:
                node_per_level[level_count] = {}
                node_per_level[level_count][c] = 1
            elif c not in node_per_level[level_count]:
                node_per_level[level_count][c] = 1
            else:
                node_per_level[level_count][c] += 1
            level_count += 1

        #assert (self.is_leaf(selected_child))
        return (selected_child, node_per_level)

    '''
    Function to select leaves ramdomly
    '''
    def randomSampling(self, percentage):
        samples = set()
        num_leaves = self.num_leaves()
        num_samples = int(num_leaves * percentage)

        all_leaves = self.get_leaves()

        count_item = 0
        while count_item < num_samples:
            leaf = random.choice(all_leaves).id
            if leaf not in samples:
                samples.add(leaf)
                count_item += 1

        return samples

    '''
    Function to sample the ones that have higher probability to be sampled.
    p(r) = 1 - mean{K(r,w)|w e workload}.
    '''
    def probabilitySampling(self, percentage, scoreset):
        samples = []
        num_leaves = self.num_leaves()
        num_samples = int(num_leaves * percentage)

        all_leaves = self.get_leaves()

        all_probabilities = {}
        sum_probabilities = 0
        for a in all_leaves:
            total_sim = 0
            num_items = 0
            for b in all_leaves:
                total_sim += (scoreset.get_score(a.id, b.id) * scoreset.get_score(b.id, a.id)) / (scoreset.get_score(a.id, a.id) * scoreset.get_score(b.id, b.id))
                num_items += 1
            all_probabilities[a.id] = 1 - (total_sim/num_items)
            sum_probabilities += 1 - (total_sim/num_items)

        seq, weights = [], []
        for i in all_probabilities:
            seq.append(i)
            weights.append(all_probabilities[i]/sum_probabilities)

        #sorted_probabilities = sorted(all_probabilities.items(), key=operator.itemgetter(1))

        i = 0
        while i < num_samples:
            selected_leaf = random.choice(all_leaves).id
            prob = random.random()
            if prob < all_probabilities[selected_leaf]:
                if selected_leaf not in samples:
                    samples.append(selected_leaf)
                    i += 1

        return samples

    def returnSamplingProbability(self):
        queue = [(self.get_root_node(), 1)]

        probabilities = {}
        while queue:
            p = queue.pop(0)
            node = self.get_node(p[0])

            if(self.is_leaf(p[0])):
                probabilities[p[0]] = p[1]

            for child in self.get_children(node.id):
                queue.append((child, p[1] + 1))

        return probabilities

    ##########################################
    #   Sampling functions with clustering   #
    ##########################################

    def returnSamplingProbabilityPerCluster(self, clusters):
        queue = [(self.get_root_node(), 1)]

        probabilities = {}
        while queue:
            p = queue.pop(0)
            node = self.get_node(p[0])

            if(self.is_leaf(p[0])):
                probabilities[p[0]] = p[1]

            for child in self.get_children(node.id):
                queue.append((child, p[1] + 1))

        probabilities_per_cluster = []
        for cluster in clusters:
            new_cluster = []
            for trace in cluster:
                new_cluster.append((trace, probabilities[trace]))

            probabilities_per_cluster.append(new_cluster)

        return probabilities_per_cluster

    def getMoreLikelyToBeSampled(self, cluster):
        min = float('inf')
        trace = None
        for i in cluster:
            if i[1] < min:
                min = i[1]
                trace = i
        if trace:
            cluster.remove(trace)

        return trace[0]

    def samplingTreeWithKMeans_fixed(self, percentage, k):
        "This approach will select one sample for each K-Means cluster. So, the order will be fixed."

        trace_ids = []
        for i in self.get_leaves():
            trace_ids.append(i.id)

        # Number of samples
        total_samples = int(len(trace_ids) * percentage)

        # Get K-Means clusters
        clustering = KMeansForUber(trace_ids)
        clusters = clustering.multi_kmeans(k)

        # Get probabilities per cluster
        probabilities_per_cluster = self.returnSamplingProbabilityPerCluster(clusters)

        samples = []
        count = 0
        while len(samples) < total_samples:
            c =  count%len(clusters)
            if(len(probabilities_per_cluster[c]) > 0):
                trace = self.getMoreLikelyToBeSampled(probabilities_per_cluster[c])
                samples.append(trace)
            count += 1

        return samples

    def samplingTreeWithDBSCAN(self, percentage, eps, min_pts):
        trace_ids = []
        for i in self.get_leaves():
            trace_ids.append(i.id)

        # Number of samples
        total_samples = int(len(trace_ids) * percentage)

        # Get K-Means clusters
        clustering = DBSCAN(trace_ids, eps, min_pts)
        #clusters = clustering.runDBSCAN()
        clusters = clustering.multiDBSCAN()

        # Get probabilities per cluster
        probabilities_per_cluster = self.returnSamplingProbabilityPerCluster(clusters)

        samples = []
        count = 0
        while len(samples) < total_samples:
            c =  count%len(clusters)
            if(len(probabilities_per_cluster[c]) > 0):
                trace = self.getMoreLikelyToBeSampled(probabilities_per_cluster[c])
                samples.append(trace)
            count += 1

        return samples


from datetime import timedelta
import requests
from provider.utils import on_workdays

URL = "https://www.kajahu.com/etlap/d"
API = "https://appif.kajahu.com/jdmenu?jlang=hu&jseat=-"

@on_workdays
def getMenu(today):
    date = today.strftime("%Y-%m-%d")
    menujson = requests.get(API).json()
    menu = []
    for day in menujson['jdata']:
        if day['ddate'] == date:
            menu = [day['line1'], day['line2'], day['line3']]
            break

    return menu

menu = {
    'name': 'KAJAHU',
    'id': 'kjh',
    'url': URL,
    'get': getMenu,
    'ttl': timedelta(hours=23),
    'cards': []
}


def queens(n):
    def s(lst, diags1, diags2, row, columns):
        if row == n:
            yield lst
        else:
            for col in columns:
                diag1 = col + row
                diag2 = col - row
                if (diag1 not in diags1) and (diag2 not in diags2):
                    yield from s(lst+[(row, col)], diags1|{diag1}, diags2|{diag2}, row+1, columns-{col})
    yield from s([], set(), set(), 0, set(range(n)))

for i,e in enumerate(queens(18), start=1):
    print(i,e)


# Beginning of class to manipulate a virtual ball
class Ball():
    def __init__(self, xLoc=2, yLoc=2):
        self.xLoc = xLoc
        self.yLoc = yLoc
        self.xMax = 4
        self.yMax = 4

    def moveX(self, distance=0):
        self.distance = distance
        if self.distance > 0:
            if self.distance + self.xLoc > self.xMax:
                self.xLoc = self.xMax
        else:
            self.xLoc = self.xLoc + self.distance
        if self.distance < 0:
            if self.distance + self.xLoc < -self.xMax:
                self.xLoc = -self.xMax
            else:
                self.xLoc = self.xLoc + self.distance

def testme():
    from microbit import *
    tiltUpRight = Image("00000:""00000:""00009:""00000:""00900")
    tiltDownRight = Image("00900:""00000:""00009:""00000:""00000")
    tiltUpLeft = Image("00000:""00000:""90000:""00000:""00900")
    tiltDownLeft = Image("00900:""00000:""90000:""00000:""00000")
    while True:
        reading = accelerometer.get_values()
        sleep(100)
        if reading[0] > 0:
            if reading[1] > 0:
                display.show(tiltUpRight)
            else:
                display.show(tiltDownRight)
        else:
            if reading[1] > 0:
                display.show(tiltUpLeft)
            else:
                display.show(tiltDownLeft)
        # print(reading)
testme()


# coding: utf-8

import collections
import csv
import decimal
import logging
import numbers
import re
from io import BytesIO

from openpyxl import load_workbook
from openpyxl.utils.cell import get_column_letter
from six import string_types

from ..codes import FileParseCodes
from ..utilities import ErrorAggregator, ParseError

logger = logging.getLogger(__name__)

def _has_value(*args):
    """
    Tests whether any of the provided arguments should be treated as having a valid value
    """

    def _valid_value(arg):
        if isinstance(arg, string_types):
            return bool(arg)  # assume it's already .strip()ed
        else:
            return arg is not None

    return any(filter(_valid_value, args))

class TableParser(object):
    """
    A parser for the tabular import files that allows supports semi-tolerant parsing of
    user-provided spreadsheets. Basic conditions for parsing are:

    1) Required columns can be provided in any order
    2) Optional columns will be identified if present
    3) Column headers are case-insensitive
    4) Any column whose header doesn't match those specified by the file format will be
        ignored (with a warning)
    5) Whitespace parsing is tolerant, e.g. different number and type of whitespace is allowed in
        column headers than what's suggested, though space is still needed in between words if
        column headers are defined with internal whitespace.
    """

    # TODO: capture common method parameters as a class to simplify interface
    def __init__(
        self,
        req_cols,
        opt_cols=None,
        value_opt_cols=None,
        numeric_cols=None,
        supported_units=None,
        aggregator=None,
    ):
        """
        Initializes the parser using client-provided lists of required and optional column headers.

        :param req_cols: an iterable of human-readable strings containing required column
            headers. The parser will take care of tolerating variations in optional leading,
            trailing, and internal whitespace.
        :param opt_cols: an iterable of human-readable strings with optional column headers.
            Subject to the same processing as req_cols.
        :param value_opt_cols: an optional iterable of column headers from either or both of
            req_cols & opt_cols. Any col header in value_opt_cols will have missing
            values tolerated in any row.  Any column headers not listed here are by default
            required to have a value in every row, assuming the column is present.
        :param numeric_cols: an  optional list of column names for columns that will be verified
            during parsing to have numeric content.
        :param aggregator: an optional main.importer2.ErrorAggregator instance to report errors
            and warnings to
        """
        super(TableParser, self).__init__()

        # TODO: add support for vector input
        # TODO: add optional column aliases?
        self.aggregator = aggregator if aggregator else ErrorAggregator()

        # keep inputs to use as keys and as human-readable for use in err messages
        self.req_cols = req_cols
        self.opt_cols = opt_cols if opt_cols is not None else set()
        self.value_opt_cols = value_opt_cols if value_opt_cols is not None else set()
        self.numeric_cols = numeric_cols if numeric_cols is not None else set()
        self.supported_units = supported_units if supported_units is not None else {}

        # maps canonical col name -> observed text (e.g. maybe including whitespace, mixed case,
        # alias)
        self.obs_col_names = {}
        self.obs_col_units = {}

        self._is_excel = None

        # build up regex patterns for each supported column header that allow us to do
        # semi-tolerant matching against user-provided values.
        # maps human-readable col name => pattern
        self.req_col_patterns = self._build_col_header_patterns(req_cols)

        if opt_cols:
            self.opt_col_patterns = self._build_col_header_patterns(self.opt_cols)
        else:
            self.opt_col_patterns = []

        self._build_unit_patterns()

    @property
    def has_all_times(self):
        """
        Tests whether the parsed file contained time values for all measurements.  Incomplete time
        values should be treated as a parse error.
        """
        return False  # children should override

    def has_all_units(self):
        """
        Tests whether the parsed file contained units for all measurements
        Partial units should be treated as a parse error.
        """
        return False  # children should override

    def _build_col_header_patterns(self, col_headers):
        """
        Builds patterns to facilitate reasonably tolerant parsing of fixed string values expected
        to match during parsing.  Patterns are constructed to match case-insensitive input and
        are tolerant of leading and trailing whitespace insertions, or of added internal
        whitespace.  Internal whitespace in the input is required, but may use different
        whitespace characters or have additional whitespace added.
        """
        reg = r"^\s*{title}\s*$"
        return [
            re.compile(
                reg.format(title=TableParser._process_label(col_header)), re.IGNORECASE
            )
            for col_header in col_headers
        ]

    def _build_unit_patterns(self):
        self._unit_patterns = {}
        for col, units in self.supported_units.items():
            logger.debug(f'Building unit patterns for column "{col}": {units}')
            # note : maintaining case-sensitivity is important! SI units use case!
            vals = "|".join([TableParser._process_label(unit) for unit in units])
            pat = re.compile(r"^\s*({vals})\s*$".format(vals=vals))
            self._unit_patterns[col] = pat

    @staticmethod
    def _process_label(s):
        tokens = re.split(r"\s+", s)  # tokenize label on whitespace
        escaped_tokens = (re.escape(part) for part in tokens)  # escape each part
        return r"\s+".join(escaped_tokens)  # gather together with whitespace regex

    def parse_excel(self, file):
        """
        Parses the input file as an Excel workbook.
        :param file: a path-like object identifying the file location
        :return: if parsing was successful, the number of valid rows read from file, otherwise None
        :raise: OSError If the file can't be opened or ParseError if the file format or content
        is bad
        """
        self._is_excel = True
        wb = load_workbook(BytesIO(file.read()), read_only=True, data_only=True)
        logger.debug("In parse(). workbook has %d sheets" % len(wb.worksheets))
        if not wb.worksheets:
            self.aggregator.add_error(FileParseCodes.EMPTY_FILE)
            raise ParseError(self.aggregator)
        elif len(wb.worksheets) > 1:
            sheet_name = wb.sheetnames[0]
            msg = (
                f'Only the first sheet in your workbook, "{sheet_name}", was processed.  '
                f"All other sheets will be ignored."
            )
            self.aggregator.add_warning(
                FileParseCodes.IGNORED_WORKSHEET, occurrence=msg
            )
        worksheet = wb.worksheets[0]
        return self._parse(worksheet.iter_rows())

    def parse_csv(self, file):
        """
        Parses the input file as CSV.
        :param file: a path-like object identifying the file location
        :return: if parsing was successful, the number of valid rows read from file, otherwise None
        :raise: OSError If the file can't be opened, or ParseError if the file format or content is
        bad
        """
        self._is_excel = False
        reader = csv.reader(file)
        return self._parse(reader)

    def _parse(self, rows_iter):
        """
        A workhorse method that performs parsing, independent of how the file content is stored
        (CSV or Excel).
        :return: the number of non-whitespace rows parsed
        :raise ParseError: if the file format or content was bad
        """
        # Clear out state from any previous use of this parser instance
        self.column_layout = None
        obs_required_cols = set()

        # loop over rows
        for row_index, cols_list in enumerate(rows_iter):
            logger.debug(f"Parsing row {row_index+1}")

            # identify columns of interest first by looking for required labels
            if not self.column_layout:
                self.column_layout = self._parse_col_layout(
                    cols_list, row_index, obs_required_cols
                )

                if self.column_layout:
                    self._verify_layout(self.aggregator, row_index)

            # if column labels have been identified, look for data
            else:
                self._parse_row(cols_list, row_index)

        # if we got all the way through the file without finding a single required column header,
        # it's badly formatted
        if not self.column_layout:
            logger.debug(f"Required columns were not read {self.req_cols}")
            self.aggregator.add_error(
                FileParseCodes.MISSING_REQ_COL_HEADER, ", ".join(self.req_cols)
            )

        if self.aggregator.errors:
            raise ParseError(self.aggregator)

        return self.measurement_count

    def cell_content_desc(self, content, row_index, col_index):
        """
        Builds a succinct, human-readable description of the cell content and location
        :param content: the cell content
        :param row_index: index into the file where this row is located
        :param col_index: index into the file where this column is located
        :return: a string description of the cell content and location
        """
        return f'"{content}" ({self.cell_coords(row_index, col_index)})'

    def _parse_col_layout(self, row, row_index, obs_required_cols):
        """
        Scans a row of the file to see if it contains required column headers that define the file
        layout.
        :param row: the row to inspect for column headers
        :param row_index: the index into the file of the row being checked for required col headers
        :param obs_required_cols: a set to populate with required col names observed so far in the
            file.  Since detection of any required column header counts as a match, this parameter
            is essentially just an optimization to prevent creating a new set each time we try
            to read a row in poorly-formatted files.
        :return: the column layout if required columns were found, or None otherwise
        """
        layout = {}  # maps col name to col index
        importer = self.aggregator
        req_cols_set = set(self.req_cols)

        ###########################################################################################
        # loop over columns in the current row
        ###########################################################################################
        obs_opt_cols = set()
        non_header_vals = []
        for col_index, cell in enumerate(row):
            cell_content = self._raw_cell_value(cell)

            # skip this cell if it has no non-whitespace content
            # (strings are stripped by _get_raw_value())
            if not cell_content:
                continue

            # ignore non-string cells since they can't be the column headers we're looking for
            if not isinstance(cell_content, string_types):
                if cell_content is not None:
                    col_desc = self.cell_content_desc(
                        cell_content, row_index, col_index
                    )
                    non_header_vals.append(col_desc)
                continue

            #######################################################################################
            # check whether column label matches one of the canonical column names specified by
            # the format
            #######################################################################################
            self._process_col_name(
                cell_content,
                row_index,
                col_index,
                non_header_vals,
                obs_required_cols,
                obs_opt_cols,
                layout,
            )

        # if at least the required columns were found, consider this a successful read
        if obs_required_cols == req_cols_set:
            for bad_val in non_header_vals:
                importer.add_warning(FileParseCodes.COLUMN_IGNORED, occurrence=bad_val)
            logger.debug(
                f"Found all {len(self.req_cols)} required column headers in row "
                f"{row_index+1}"
            )
            return layout

        # if some--but not all--required columns were found in this row, consider this a
        # poorly-formatted file
        if obs_required_cols:
            missing_cols = req_cols_set.difference(obs_required_cols)
            logger.debug(f"Required column headers missing: {missing_cols}")
            importer.raise_errors(
                FileParseCodes.MISSING_REQ_COL_HEADER, occurrences=missing_cols
            )
        else:
            importer.add_warnings(
                FileParseCodes.IGNORED_VALUE_BEFORE_HEADERS, non_header_vals
            )

        return None

    def _process_col_name(
        self,
        cell_content,
        row_index,
        col_index,
        non_header_vals,
        obs_req_cols,
        obs_opt_cols,
        layout,
    ):
        """
        Process the string content of a cell when looking for columns
        :param cell_content: the string content (non empty, non-whitespace)
        :param non_header_vals: a list of non column header values read from the file before
        any valid column header is found
        :param obs_req_cols: a set of required column headers already observed in the row
        :param obs_opt_cols: a set of optional columns headers already observed in the row
        :param layout: a dict that maps col name to the column index where it was observed
        """
        req_name = self._parse_col_header(
            self.req_col_patterns, self.req_cols, row_index, col_index, cell_content
        )
        opt_name = self._parse_col_header(
            self.opt_col_patterns, self.opt_cols, row_index, col_index, cell_content
        )
        agg = self.aggregator
        if req_name:
            logger.debug(
                f'Found required column "{req_name}"'
                f"({self.cell_coords(row_index, col_index)})"
            )

            if req_name in obs_req_cols:
                col_desc = self.cell_content_desc(cell_content, row_index, col_index)
                agg.add_error(FileParseCodes.DUPLICATE_COL_HEADER, occurrence=col_desc)
            else:
                obs_req_cols.add(req_name)
                layout[req_name] = col_index
                if req_name != cell_content:
                    self.obs_col_names[req_name] = cell_content
        elif opt_name:
            logger.info(
                f'Found optional column "{opt_name}".'
                f"({self.cell_coords(row_index, col_index)})"
            )
            if opt_name in obs_opt_cols:
                col_desc = self.cell_content_desc(cell_content, row_index, col_index)
                agg.add_error(FileParseCodes.DUPLICATE_COL_HEADER, occurrence=col_desc)
            else:
                obs_opt_cols.add(opt_name)
                layout[opt_name] = col_index
                if cell_content != opt_name:
                    self.obs_col_names[opt_name] = cell_content
        else:
            col_desc = self.cell_content_desc(cell_content, row_index, col_index)
            non_header_vals.append(col_desc)

    def _raw_cell_value(self, cell):
        """
        Gets the raw cell value in whatever format it was stored in the file
        :param cell: the cell
        :return: the cell value, with leading and trailing whitespace stripped if the content
        was a string
        """
        if self._is_excel:
            val = cell.value
        else:
            val = cell

        if isinstance(val, string_types):
            return val.strip()

        return val

    def _get_raw_value(self, row, col_name):
        """
        Gets the raw value from the table, regardless of file format.
        :param row: an iterable of columns in this row of the file
        :param col_name: the canonical name of the column whose value should be read
        :return: the value, or None if the col with col_name isn't in the file
        """
        col_index = self.column_layout.get(col_name, None) if col_name else None

        if col_index is None:
            return None

        cell = row[col_index]
        return self._raw_cell_value(cell)

    @property
    def measurement_count(self):
        """
        Gets the number of valid measurements read from the file
        """
        # children must implement
        raise NotImplementedError()

    def obs_col_name(self, canonical_name):
        """
        Gets the observed column label from the file corresponding to the canonical name understood
        by the parser.
        :param canonical_name: the canonical column name.
        :return: the observed column name, or the canonical column name if the column wasn't found
            in the file.
        """
        return self.obs_col_names.get(canonical_name, canonical_name)

    # TODO: consider (optional) mtype ID pattern verification
    def _parse_and_verify_val(self, val, row_index, col_name):
        """
        Tests a parsed value, and logs an error message if it the observed value doesn't meet
        expectations. Verifies that:
        1) The value is present if required
        2) It's a scalar number, if required
        3) If it's a unit, that it falls within the set of supported units
        :param val: the value read from file
        :param row_index: the index of the file row the value is from
        :param col_name: the canonical name for this column, rather than the one observed in
        the file.
        :return: the value, if it was valid, or None if it failed one ore more validation criteria
        """
        importer = self.aggregator
        col_index = self.column_layout.get(col_name, None)

        # if parser is asking for a column not found in the file, end early.
        # if it's required, an error will already have been recorded
        if col_index is None:
            logger.warning(f'Column "{col_name}" not found in file')
            return None

        # if value is missing, but required, log an error
        if val is None:
            if col_name not in self.value_opt_cols:
                importer.add_error(
                    FileParseCodes.MISSING_REQ_VALUE,
                    subcategory=self.obs_col_name(col_name),
                    occurrence=self.cell_coords(row_index, col_index),
                )
            return val

        # if observed value is a string,
        if isinstance(val, string_types):
            if (not val) and col_name not in self.value_opt_cols:
                importer.add_error(
                    FileParseCodes.MISSING_REQ_VALUE,
                    subcategory=self.obs_col_name(col_name),
                    occurrence=self.cell_coords(row_index, col_index),
                )
                return None

            # parse / verify expected numeric values... when read from CSV, they'll have to be
            # parsed
            if col_name in self.numeric_cols:
                return self._parse_num(val, col_name, row_index, col_index)

            return val

        # assumption (for now) is that value is numeric. should work for both vector (
        # 1-dimensional) and numeric inputs
        if not isinstance(val, numbers.Number):
            importer.add_error(
                FileParseCodes.INVALID_VALUE,
                subcategory=self.obs_col_name(col_name),
                occurrence=self.cell_coords(row_index, col_index),
            )

        return val

    def _parse_num(self, token, col_name, row_index, col_index):
        try:
            return decimal.Decimal(token)
        except (decimal.InvalidOperation, decimal.Clamped):
            self.aggregator.add_error(
                FileParseCodes.INVALID_VALUE,
                subcategory=self.obs_col_name(col_name),
                occurrence=self.cell_content_desc(token, row_index, col_index),
            )
            return None

    def _parse_col_header(
        self, col_patterns, col_names, row_index, col_index, cell_content
    ):
        """
        Tests the cell content against the canonical column definitions, and extracts the
        canonical column name and optional observed units if it matches.
        :param col_patterns: the iterable of column name patterns to match against
        :param col_names: an iterable of canonical column names, parallel structure to
        col_patterns
        :param row_index: the row index currently being parsed
        :param col_index: the column index currently being parsed
        :param cell_content: the content of the current cell
        """
        # loop over all column patterns, even those already matched.  Otherwise we can't detect
        # duplicates.
        for col_pattern, col_name in zip(col_patterns, col_names):
            if col_pattern.match(cell_content):
                return col_name

        return None

    def _verify_layout(self, importer, header_row_index):
        pass  # children may optionally implement

    def _parse_row(self, cols_list, row_index):
        raise NotImplementedError()  # children must implement

    @property
    def series_data(self):
        raise NotImplementedError()  # children must implement

    @property
    def units(self):
        raise NotImplementedError()  # children must implement

    @property
    def mtypes(self):
        raise NotImplementedError()  # children must implement

    @property
    def line_or_assay_names(self):
        raise NotImplementedError()

    @staticmethod
    def cell_coords(row_index, col_index):
        col_letter = get_column_letter(col_index + 1)
        return f"{col_letter}{row_index+1}"

    def _verify_required_val(self, value, row_index, col_index, col_title):
        if value is None or (isinstance(value, string_types) and not value.strip()):
            self.aggregator.add_error(
                FileParseCodes.MISSING_REQ_VALUE,
                subcategory=col_title,
                occurrence=self.cell_coords(row_index, col_index),
            )

# TODO: in a later version, resolve with RawImportRecord from the older import...only significant
# differences here are that "kind" is removed, no deep copying, and units & src have been added.
# Best to keep things separate for now.  TODO: update this comment prior to commit
class MeasurementParseRecord(object):
    """
    A record resulting from parsing a single Measurement from an import file.  This object should
    be flexible enough to capture the full level of detail needed to construct a Measurement from
    any file, though many formats won't require this level of detail.

    Compare with RawImportRecord from the legacy import.  Major differences are:
    1. "Kind" is removed
    2. No deep copying -- client code retains control
    3. Units have been added
    4. src_id is added
    """

    def __init__(self, **kwargs):
        self.line_or_assay_name = kwargs.get("line_or_assay_name", None)
        self.mtype_name = kwargs.get("mtype_name", None)
        self.data = kwargs.get("data", None)
        self.metadata_by_name = kwargs.get("meta", None)
        self.units_name = kwargs.get("units_name", None)

        # data source for this measurement...often a row num if input is Excel
        self.src_id = kwargs.get("src_id", None)

    def to_json(self):
        return {
            "line_or_assay_name": self.line_or_assay_name,
            "measurement_name": self.mtype_name,
            "metadata_by_name": self.metadata_by_name,
            "units_name": self.units_name,
            "data": self.data,
        }

class GenericImportParser(TableParser):
    """
    Parser for EDD's "Generic" import file, a normalized, a simple, accessible,
    and machine-readable tabular format designed for automated data import.
    """

    def __init__(self, aggregator=None):

        super(GenericImportParser, self).__init__(
            req_cols=["Line Name", "Time", "Measurement Type", "Value", "Units"],
            numeric_cols=["Time", "Value"],
            aggregator=aggregator,
        )
        self._measurements = []
        self.unique_units = set()
        self.unique_mtypes = set()
        self.unique_line_or_assay_names = set()

    def _verify_layout(self, importer, header_row_index):
        pass

    def _parse_row(self, cells_list, row_index):
        # extract raw values from in-use cols in this row
        # TODO: should rename col header for clarity if this could actually be assay name
        line_or_assay_name = self._get_raw_value(cells_list, "Line Name")
        mtype = self._get_raw_value(cells_list, "Measurement Type")
        val = self._get_raw_value(cells_list, "Value")
        time = self._get_raw_value(cells_list, "Time")
        units = self._get_raw_value(cells_list, "Units")

        # skip the row entirely if no in-use column has a value in it
        any_value = _has_value(line_or_assay_name, mtype, val, time, units)
        if not any_value:
            return None

        # now that we've seen at least a single value in the row, do more rigorous parsing /
        # verification of the values
        line_or_assay_name = self._parse_and_verify_val(
            line_or_assay_name, row_index, "Line Name"
        )
        mtype = self._parse_and_verify_val(mtype, row_index, "Measurement Type")
        val = self._parse_and_verify_val(val, row_index, "Value")
        time = self._parse_and_verify_val(time, row_index, "Time")
        units = self._parse_and_verify_val(units, row_index, "Units")

        if isinstance(val, collections.Iterable):
            data = [time]
            for item in val:
                data.append(item)
        else:
            data = [time, val]

        m = MeasurementParseRecord(
            line_or_assay_name=line_or_assay_name,
            mtype_name=mtype,
            data=data,
            units_name=units,
            src_id=f"row {row_index+1}",
        )
        self._measurements.append(m)

        # track unique observed values
        if line_or_assay_name:
            self.unique_line_or_assay_names.add(line_or_assay_name)
        if val:
            self.unique_mtypes.add(mtype)
        if units:
            self.unique_units.add(units)

    @property
    def mtypes(self):
        return self.unique_mtypes

    @property
    def line_or_assay_names(self):
        return self.unique_line_or_assay_names

    @property
    def units(self):
        return self.unique_units

    @property
    def series_data(self):
        return self._measurements

    @property
    def measurement_count(self):
        return len(self._measurements)

    @property
    def has_all_times(self):
        """
        Tests whether the parsed file contained time values for all measurements.
        """
        return (
            True
        )  # overrides default False.  Time is a required column in this format.

    def has_all_units(self):
        """
        Tests whether the parsed file contained units for all measurements
        Partial units should be treated as a parse error.
        """
        return (
            True
        )  # overrides default False.  Units is a required column in this format


import pathlib

from setuptools import setup

# The directory containing this file
HERE = pathlib.Path(__file__).parent

# The text of the README file
README = (HERE / "README.md").read_text()

# This call to setup() does all the work
setup(
    name="pyPreservicaSearch",
    version="0.1.0",
    description="Simple Report Designer for Preservica",
    long_description=README,
    long_description_content_type="text/markdown",
    url="",    author="James Carr",
    author_email="james.carr@preservica.com",
    license="Apache License 2.0",
    packages=["pyPreservicaSearch"],
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: Apache Software License",
        "Operating System :: OS Independent",
        "Topic :: System :: Archiving",
    ],
    install_requires=["requests", "certifi", "pyPreservica >= 0.7.3", "PySide2 == 5.15.0", "shiboken2 == 5.15.0"]
)


Import('rtconfig')
from building import *

cwd = GetCurrentDir()

# add the startup files

src = Split('''
   startup.c
   trap.c
''')

if rtconfig.PLATFORM == 'gcc':
    src += [os.path.join('toolchains', 'gcc', 'start.S')]
    src += [os.path.join('toolchains', 'gcc', 'port_gcc.S')]

CPPPATH = [cwd]
CPPDEFINES=['D45', rtconfig.CHIP_NAME]

group = DefineGroup('Startup', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES)

Return('group')


from turtle import *

def create_ball(x, y):
    t = Turtle()
    t.speed(0)
    t.shape('circle')
    t.up()
    t.goto(x, y)

    return t

def move(something):
    global speed_x
    global speed_y
    pos = something.position()
    x = pos[0]
    y = pos[1]

    if x >= 465 or x <= -465:
        speed_x = -speed_x
    if y >= 395 or y <= -395:
        speed_y = -speed_y

    something.goto(x + speed_x, y + speed_y)

def create_player(x, y):
    t = Turtle()
    t.speed(0)
    t.shape('square')
    t.shapesize(5, 1)
    t.up()
    t.goto(x, y)

    return t

def move_up_1():
    global player_1
    pos = player_1.position()
    x = pos[0]
    y = pos[1]

    player_1.goto(x, y + 10)

def move_down_1():
    global player_1
    pos = player_1.position()
    x = pos[0]
    y = pos[1]

    player_1.goto(x, y - 10)

def move_up_2():
    global player_2
    pos = player_2.position()
    x = pos[0]
    y = pos[1]

    player_2.goto(x, y + 10)

def move_down_2():
    global player_2
    pos = player_2.position()
    x = pos[0]
    y = pos[1]

    player_2.goto(x, y - 10)

def check_collisions_1(ball, player):
    global speed_x
    pos = player.position()  # Получаем позицию игрока
    x_player = pos[0]
    y_player = pos[1]
    pos = ball.position()  # Получаем позицию мячика
    x_ball = pos[0]
    y_ball = pos[1]

    if x_player-10 <= x_ball <= x_player+10 and y_player-50 <= y_ball <= y_player+50:
        speed_x = -speed_x

def check_collisions_2(ball, player):
    global speed_x
    pos = player.position()  # Получаем позицию игрока
    x_player = pos[0]
    y_player = pos[1]
    pos = ball.position()  # Получаем позицию мячика
    x_ball = pos[0]
    y_ball = pos[1]

    if x_player-10 <= x_ball <= x_player+10 and y_player-50 <= y_ball <= y_player+50:
        speed_x = -speed_x

window = Screen()
window.listen()  # Окно, слушай события!
window.onkeypress(move_up_1, 'w')
window.onkeypress(move_down_1, 's')
window.onkeypress(move_up_2, 'Up')
window.onkeypress(move_down_2, 'Down')

player_1 = create_player(-400, 0)
player_2 = create_player(400, 0)

ball = create_ball(-100, 100)
speed_x = 4
speed_y = 4

while True:  # Бесконечный цикл
    move(ball)
    check_collisions_1(ball, player_1)
    check_collisions_1(ball, player_2)


# -*- coding: utf-8 -*-
import json
import logging

from django.db.models.expressions import Window
from django.db.models.functions import RowNumber
from django.db.models import F

from django.shortcuts import render, get_object_or_404
from django.template import loader
from django.http import HttpResponse, JsonResponse, Http404
from django.views.decorators.csrf import csrf_exempt
from django.core import serializers
# from pip._vendor.requests import Response
from django.views.generic import ListView
from django.views.generic .edit import CreateView
from django.views import View
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from rest_framework.response import Response

from sakila.forms import CustomerForm
from sakila.models_views import CustomerList
from sakila.permissions import UserIsOwnerTodo, IsOwnerOrReadOnly
from .models import Customer

from .models import Film

from .serializers import FilmSerializer, CustomerListSerializer
from rest_framework import generics

logger = logging.getLogger('default')
# logger = logging.getLogger(__name__)
# logging.disable(logging.NOTSET)
# logger.setLevel(logging.DEBUG)

def index(request):
    print('@@@@@@@@@@@@@@@@ sakila')
    context = {}
    template = loader.get_template('sakila/index.html')
    return HttpResponse(template.render(context, request))

def gentella_html(request):
    print('@@@@@@@@@@@@@@@@')
    context = {}
    # The template to be loaded as per gentelella.
    # All resource paths for gentelella end in .html.

    # Pick out the html file name from the url. And load that template.
    load_template = request.path.split('/')[-1]
    logger.debug(' function name gentella_html : %s ' % load_template)
    if load_template == 'tables_dynamic.html':
        list = Film.objects.all()
        list_cnt = Film.objects.count()
        logger.debug(' function name list_cnt : %s ' % list_cnt)
        context = {'list': list}
    elif load_template == 'tables_dynamic_customer_list.html':
        # list = CustomerList.objects.all()
        # sqlite3 3.25 버전이상에서 Window 함수를 사용할수 있음.
        list = CustomerList.objects.annotate(row_number=Window(
            expression=RowNumber(),
            partition_by=[F('sid')],
            order_by=F('id').desc())
        ).order_by('row_number', 'id')
        # ).order_by('row_number', 'client')

        list_cnt = CustomerList.objects.count()
        logger.debug(' function name list_cnt : %s ' % list_cnt)
        context = {'list': list}
    elif load_template == 'tables_dynamic_customer_list2.html':
        # # list = CustomerList.objects.all()
        # # sqlite3 3.25 버전이상에서 Window 함수를 사용할수 있음.
        # list = CustomerList.objects.annotate(row_number=Window(
        #     expression=RowNumber(),
        #     partition_by=[F('sid')],
        #     order_by=F('id').desc())
        # ).order_by('row_number', 'id')
        # # ).order_by('row_number', 'client')
        # list_cnt = CustomerList.objects.count()
        # logger.debug(' function name list_cnt : %s ' % list_cnt)
        # context = {'list': list}
        pass

    template = loader.get_template('sakila/' + load_template)
    return HttpResponse(template.render(context, request))

# 여기서에서 @csrf_exempt 는 csrf 보안을 사용 하기 않겠다는 의미 입니다.  참조사이트 [ django csrf 문서 ]
# @csrf_exempt
def film_modify(request):
    logger.debug(' function name : %s ' % 'film_modify')
    film_id = request.POST['film_id']
    description = request.POST['description']
    special_features = request.POST['special_features']

    film = get_object_or_404(Film, pk=film_id)
    film.description = description
    film.special_features = special_features
    film.save()
    # tmpJson = serializers.serialize("json",film)
    # tmpObj = json.loads(tmpJson)
    context = {
        "msg": "성공",
    }
    # return HttpResponse(context, content_type="application/json; charset=utf-8")
    # return HttpResponse(json.dumps(context), content_type="application/json; charset=utf-8")
    # return JsonResponse({
    #     'message': '안녕 파이썬 장고',
    #     'items': ['파이썬', '장고', 'AWS', 'Azure'],
    # }, json_dumps_params={'ensure_ascii': True})
    # 한글 잘 보임
    return HttpResponse(json.dumps(context, ensure_ascii=False), content_type="application/json")
    # return JsonResponse(json.dumps(context, ensure_ascii=False), safe=False)
    # return Response(context, content_type='application/json; charset=utf-8')

def list_staff(request):
    print('@@@@@@@@@@@@@@@@')
    load_template = request.path.split('/')[-1]
    logger.debug(' function name load_template : %s ' % load_template)
    context = {}
    # list = Staff.objects.all()
    # list_cnt = Staff.objects.count()
    # logger.debug(' function name list_cnt : %s ' % list_cnt)
    # context = {'list': list}
    template = loader.get_template('sakila/tables_dynamic.html')
    return HttpResponse(template.render(context, request))

class CustomerListView(ListView):
    """
    클래스 뷰
    """
    model = Customer
    template_name = 'sakila/tables_dynamic_customer.html'
    context_object_name = 'list'

class CustomerAjaxView(View):
    """
    Ajax 처리
    """

    form_class = CustomerForm
    initial = {'key': 'value'}

    def post(self, request):
        if request.is_ajax():
            # data = {"lat":20.586, "lon":-89.530}
            # print(request.POST.get('value'))
            logger.debug(' class name : %s ' % 'CustomerAjaxView')
            logger.debug(' function name : %s ' % 'post')
            # film_id = request.POST['film_id']
            # description = request.POST['description']
            # special_features = request.POST['special_features']

            form = self.form_class(request.POST)

            if form.is_valid():
                data = {
                    "msg": "성공",
                }
                form.save()
                return JsonResponse(data, json_dumps_params={'ensure_ascii': False})

            logger.debug(' error msg : %s ' % form.errors)
            # film = get_object_or_404(Film, pk=film_id)
            # form = CustomerForm(request.P)
            # film.description = description
            # film.special_features = special_features
            # film.save()
            # tmpJson = serializers.serialize("json",film)
            # tmpObj = json.loads(tmpJson)
            data = {
                "msg": "실패",
                "errors": str(form.errors) # str() 자동형 변환 하지 못하게 함 그러면 html 로 생성됨.
                # "errors": form.errors
            }
            return JsonResponse(data,  json_dumps_params={'ensure_ascii': False})

    def get(self, request):
        form = self.form_class(initial=self.initial)
        return render(request, 'landing.html', {'form': form})

class AjaxableResponseMixin:
    """
    Mixin to add AJAX support to a form.
    Must be used with an object-based FormView (e.g. CreateView)
    """
    def form_invalid(self, form):
        response = super().form_invalid(form)
        if self.request.is_ajax():
            return JsonResponse(form.errors, status=400)
        else:
            return response

    def form_valid(self, form):
        # We make sure to call the parent's form_valid() method because
        # it might do some processing (in the case of CreateView, it will
        # call form.save() for example).
        response = super().form_valid(form)
        if self.request.is_ajax():
            data = {
                'pk': self.object.pk,
            }
            return JsonResponse(data)
        else:
            return response

# class CustomerAjaxCreateView(AjaxableResponseMixin, CreateView):
class CustomerAjaxCreateView(CreateView):
    """
    Ajax 처리 Create
    """
    model = Customer
    # fields = ['first_name']
    # initial={'date_of_death':'05/01/2018',}
    # initial = {'key': 'value'}
    # # form_class = Customer
    # #
    def get(self, request):
        form = CustomerForm()
        # form = self.form_class()
        # form = self.form_class(initial=self.initial)
        data = {
            'form_as_table': form.as_table(),
        }
        return JsonResponse(data,  json_dumps_params={'ensure_ascii': False})

    def post(self, request):
        self.form_class = CustomerForm
        # initial = {'key': 'value'}
        if request.is_ajax():
            # data = {"lat":20.586, "lon":-89.530}
            # print(request.POST.get('value'))
            logger.debug(' class name : %s ' % 'CustomerAjaxCreateView')
            logger.debug(' function name : %s ' % 'post')
            # film_id = request.POST['film_id']
            # description = request.POST['description']
            # special_features = request.POST['special_features']

            form = self.form_class(request.POST)

            if form.is_valid():
                data = {
                    "msg": "성공",
                }
                form.save()
                return JsonResponse(data, json_dumps_params={'ensure_ascii': False})

            logger.debug(' error msg : %s ' % form.errors)
            # film = get_object_or_404(Film, pk=film_id)
            # form = CustomerForm(request.P)
            # film.description = description
            # film.special_features = special_features
            # film.save()
            # tmpJson = serializers.serialize("json",film)
            # tmpObj = json.loads(tmpJson)
            data = {
                "msg": "실패",
                "errors": str(form.errors) # str() 자동형 변환 하지 못하게 함 그러면 html 로 생성됨.
                # "errors": form.errors
            }
            return JsonResponse(data,  json_dumps_params={'ensure_ascii': False})

class FilmListApi(generics.ListCreateAPIView):
    logger.debug('@@@@@@@@@@ FilmListApi ')
    # queryset = Film.objects.all()
    serializer_class = FilmSerializer
    permission_classes = [IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly]
    # permission_classes = (IsAuthenticated, UserIsOwnerTodo)

    def get_queryset(self, request):
        logger.debug('@@@@@@@@@@ FilmListApi.get_queryset ')
        # OFFSET 5 / LIMIT 5
        req_draw = int(request.GET['draw'])
        req_start = int(request.GET['start'])
        req_length = int(request.GET['length'])
        req_search_value = str(request.GET['search[value]'])
        logger.debug('req_search_value : %s' % req_search_value)
        return Film.objects.filter(title__icontains=req_search_value)[req_start:req_length + req_start]

    def list(self, request):
        # Note the use of `get_queryset()` instead of `self.queryset`
        queryset = self.get_queryset(request)
        serializer = FilmSerializer(queryset, many=True)
        return Response({'data': serializer.data})

# class FilmDetailApi(generics.RetrieveAPIView):
class FilmDetailApi(generics.RetrieveUpdateDestroyAPIView):
    logger.debug('@@@@@@@@@@ FilmDetailApi ')
    queryset = Film.objects.all()
    serializer_class = FilmSerializer

    # def get_queryset(self, pk):
    #     logger.debug('@@@@@@@@@@ FilmDetailApi.get_queryset ')
    #     return Film.objects.all(pk)

class CustomerListListApi(generics.ListCreateAPIView):
    logger.debug('@@@@@@@@@@ FilmListApi ')
    # queryset = Film.objects.all()
    serializer_class = CustomerListSerializer
    permission_classes = [IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly]
    # permission_classes = (IsAuthenticated, UserIsOwnerTodo)

    def get_queryset(self, request):
        logger.debug('@@@@@@@@@@ FilmListApi.get_queryset ')
        # OFFSET 5 / LIMIT 5
        req_draw = int(request.GET['draw'])
        req_start = int(request.GET['start'])
        req_length = int(request.GET['length'])
        req_search_value = str(request.GET['search[value]'])
        logger.debug('req_search_value : %s' % req_search_value)
        req_order_column = str(request.GET['order[0][column]'])
        logger.debug('req_order_column : %s' % req_order_column)
        req_order_dir = str(request.GET['order[0][dir]'])

        req_order_column_nm = None
        logger.debug('req_order_dir : %s' % req_order_dir)
        if req_order_column:
            req_order_column_nm = CustomerList._meta.fields[int(req_order_column)].attname
            logger.debug('req_order_column_nm : %s' % req_order_column_nm)

        if req_order_dir == 'desc':
            return CustomerList.objects.filter(name__icontains=req_search_value).order_by('-'+req_order_column_nm)[req_start:req_length + req_start]
        elif req_order_dir == 'asc':
            return CustomerList.objects.filter(name__icontains=req_search_value).order_by(req_order_column_nm)[req_start:req_length + req_start]

        return CustomerList.objects.filter(name__icontains=req_search_value)[req_start:req_length + req_start]

    def list(self, request):
        # Note the use of `get_queryset()` instead of `self.queryset`
        queryset = self.get_queryset(request)
        serializer = CustomerListSerializer(queryset, many=True)
        return Response({'data': serializer.data})


#!/usr/bin/python
# coding: utf-8
__author__ = 'lhfcws'

from setuptools import setup, find_packages

setup(
      name="rdir",
      version="0.52",
      description="More powerful recursive dir. Support HTML pretty view in tree structure.",
      long_description="Documentation and bug repot: http://www.github.com/Lhfcws/rdir\n \
                       Sorry for the deploy bugs in the previous versions\n \
                       If you came across ImportError or NoScriptError, please `rm /usr/local/bin/rdir*`",
      author="Lhfcws Wu",
      author_email="lhfcws@gmail.com",
      url="http://www.github.com/Lhfcws/rdir",
      license="MIT",
      packages=["rdir", "rdir/core", "rdir/generateHTML"],
      include_package_data=True,
      package_data={"rdir": ["rdir/generateHTML/template/*.html", "rdir/generateHTML/bin/*.js"]},
      install_requires=['colorama', 'pyquery'],
      keywords=["dir", "doc", "pydoc", "html"],
)


import time

def app(environ, start_response):
    if environ['PATH_INFO'] == '/sleepy':
        time.sleep(2)
        body = b'sleepy returned'
    else:
        body = b'notsleepy returned'
    cl = str(len(body))
    start_response(
        '200 OK',
        [('Content-Length', cl), ('Content-Type', 'text/plain')]
        )
    return [body]

if __name__ == '__main__':
    from waitress.tests.support import start_server
    start_server(app)


import collections

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def widthOfBinaryTree(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """

        res = 0
        value_list = collections.deque([(root, 0)])

        if not root:

            return res

        while value_list:
            temp_value = len(value_list)
            res = max(res, value_list[-1][1] - value_list[0][1] + 1)

            for _ in range(temp_value):
                root, cost = value_list.popleft()

                if root.left:
                    value_list.append((root.left, cost * 2))

                if root.right:
                    value_list.append((root.right, cost * 2 + 1))

        return res


"""Fire up the browser to search for missing images."""

import os
import sys
import urllib.parse
import webbrowser
import unicodedata

import pyperclip

duckduckgo = 'https://duckduckgo.com/?t=canonical&q=%s&iax=images&ia=images&iaf=type%%3Aclipart'

images = {
    unicodedata.normalize('NFC', os.path.splitext(f)[0])
    for f in os.listdir('img')
}

with open(sys.argv[1]) as fin:
    for line in fin:
        try:
            syllable, word = line.strip().split(' ')
        except ValueError:
            continue

        word = unicodedata.normalize('NFC', word)
        if word not in images:
            pyperclip.copy(word)
            url = duckduckgo % urllib.parse.quote(word)
            webbrowser.open(url)
            input('searched for %r, press Enter to continue or Ctrl+C to exit' % word)


"""
.. module:: testpack
    :platform: Darwin, Linux, Unix, Windows
    :synopsis: Module that is contains the :class:`TestPack` class which is utilized as the collection point
               which associates a set of tests with their execution scopes.

.. moduleauthor:: Myron Walker <myron.walker@gmail.com>
"""

__author__ = "Myron Walker"
__copyright__ = "Copyright 2020, Myron W Walker"
__credits__ = []
__version__ = "1.0.0"
__maintainer__ = "Myron Walker"
__email__ = "myron.walker@gmail.com"
__status__ = "Development" # Prototype, Development or Production
__license__ = "MIT"

import inspect

from akit.mixins.scope import ScopeMixIn, inherits_from_scope_mixin

from akit.xlogging.foundations import getAutomatonKitLogger

logger = getAutomatonKitLogger()

class TestPack(ScopeMixIn):
    """
              --------------
              |  TestPack  |
        -------------------------
        |  Scope A  |  Scope B  |
        -------------------------
        |         Scope C       |
        -------------------------

        Pack:
            * Single instance
            * Collect or Group tests
            * Associates scopes of execution with the tests
            * Allows for the customization of the Setup and TearDown of scopes

        Scopes:
            * Collect Resources utilized in a Scope of Execution for a group of tests
            * Setup and TearDown of scope
    """

    name = ""           # TestPack Friendly Name
    description = ""    # TestPack Description

    # Includes and excludes can be added to a TestPack in order to help the test framework reduce
    # the amount of resources that need to be expended in order to scan for the tests that are linked
    # to a TestPack
    searchin = None

    context = None # The scopes associated with a testpack, scopes
    test_references = None

    def acclimate(self, testlandscape): # pylint: disable=no-self-use, unused-argument
        """
            API called by the test framework in order to acclimate the :class:`TestPack` to the :class:`TestLandscape`.
            When this method is called on a :class:`TestPack` it can analyze the testlandscape and configure
            internal state that can be used to determine which tests are applicable to the given test
            landscape.
        """
        return

    def expectations(self): # pylint: disable=no-self-use
        """
            Method that can be implemented by derived classes or updated dynamically to reflect the
            expected torun and skipped test counts for a given testlandscape.  The test framework will call the 'acclimate'
            method prior to calling this method in order to let the 'TestPack' analyze the testlandscape
            and determine which tests are applicable to the test

            (torun, skipped)
        """
        return

    def scopes_enter(self): # pylint: disable=no-self-use
        """
            Called to enter the scopes to setup for running the :class:`TestPack`.
        """

        rev_mro = list(TestPack.mro())
        rev_mro.reverse()

        for nxt_cls in rev_mro:
            if inherits_from_scope_mixin(nxt_cls):
                nxt_cls.scope_enter()
                if not hasattr(nxt_cls, "scope_enter_count"):
                    nxt_cls.scope_enter_count = 1
                else:
                    nxt_cls.scope_enter_count += 1 # pylint: disable=no-member

        return

    def scopes_exit(self): # pylint: disable=no-self-use
        """
            Called to exit the scopes to cleanup after running the :class:`TestPack`.
        """

        norm_mro = list(TestPack.mro())

        for nxt_cls in norm_mro:
            if inherits_from_scope_mixin(nxt_cls):
                nxt_cls.scope_exit()
                if hasattr(nxt_cls, "scope_enter_count"):
                    nxt_cls.scope_enter_count -= 1 # pylint: disable=no-member
                else:
                    logger.error("ERROR: Every scope should have a 'scope_enter_count' class variable.")

        return

class DefaultTestPack(TestPack):
    """
        The :class:`DefaultTestPack` is utilized to provide a package container for collections of tests
        that either share a common collection of foundation scopes or do not explicitly mixin a parent class
        that is a subclass of :class:`ScopeMixIn`.
    """
    pathname = ""

def inherits_from_testpack(cls) -> bool:
    """
        Helper method that detects if an objects type inherits from :class:`TestPack` but ensures
        that the object is not a :class:`TestPack` type from this file.
    """
    istp = False
    if inspect.isclass(cls) and cls is not TestPack and issubclass(cls, TestPack):
        istp = True
    return istp

def testpack_compare(tpack):
    """
        Used to provide a key for comparing :class:`TestPack` objects.
    """
    return tpack.weight