from sedona.utils.geometry_serde import serialize, deserialize
from shapely.geometry import LineString, Point, Polygon, MultiPoint, MultiLineString, MultiPolygon
from shapely.wkb import dumps, loads

import time

def run_serialize_trial(geom, number_iterations, name):
    print(f"{name} serialize trial:")

    start_time = time.perf_counter_ns()
    for _ in range(number_iterations):
        dumps(geom)
    shapely_time = time.perf_counter_ns() - start_time

    start_time = time.perf_counter_ns()
    for _ in range(number_iterations):
        serialize(geom)
    sedona_time = time.perf_counter_ns() - start_time

    print(f"\tTotal Time (seconds):")
    print(f"\t\tShapely: {shapely_time / 1e9}\n\t\tSedona: {sedona_time / 1e9}\n\t\tFactor: {(sedona_time - shapely_time) / shapely_time}\n")

def run_deserialize_trial(geom, number_iterations, name):
    print(f"{name} deserialize trial:")

    shapely_serialized_geom = dumps(geom)
    sedona_serialized_geom = serialize(geom)

    start_time = time.perf_counter_ns()
    for _ in range(number_iterations):
        loads(shapely_serialized_geom)
    shapely_time = time.perf_counter_ns() - start_time

    start_time = time.perf_counter_ns()
    for _ in range(number_iterations):
        deserialize(sedona_serialized_geom)
    sedona_time = time.perf_counter_ns() - start_time

    print(f"\tTotal Time (seconds):")
    print(f"\t\tShapely: {shapely_time / 1e9}\n\t\tSedona: {sedona_time / 1e9}\n\t\tFactor: {(sedona_time - shapely_time) / shapely_time}\n")

short_line_iterations = 200_000
short_line = LineString([(10.0, 10.0), (20.0, 20.0)])

long_line_iterations = 100_000
long_line = LineString([(float(n), float(n)) for n in range(1000)])

point_iterations = 500_000
point = Point(12.3, 45.6)

small_polygon_iterations = 200_000
small_polygon = Polygon([(10.0, 10.0), (20.0, 10.0), (20.0, 20.0), (10.0, 20.0), (10.0, 10.0)])

large_polygon_iterations = 100_000
large_polygon = Polygon(
    [(0.0, float(n * 10)) for n in range(100)]
    + [(float(n * 10), 990.0) for n in range(100)]
    + [(990.0, float(n * 10)) for n in reversed(range(100))]
    + [(float(n * 10), 0.0) for n in reversed(range(100))]
)

small_multipoint_iterations = 10_000
small_multipoint = MultiPoint([(n, n) for n in range(3)])

large_multipoint_iterations = 10_000
large_multipoint = MultiPoint([(n, n) for n in range(100)])

small_multilinestring_iterations = 10_000
small_multilinestring = MultiLineString([[(10.0, 10.0), (20.0, 20.0)] for _ in range(3)])

large_multilinestring_iterations = 5_000
large_multilinestring = MultiLineString([[(10.0, 10.0), (20.0, 20.0)] for _ in range(100)])

small_multipolygon_iterations = 10_000
small_multipolygon = MultiPolygon([small_polygon for _ in range(3)])

large_multipolygon_iterations = 5_000
large_multipolygon = MultiPolygon([small_polygon for _ in range(100)])

run_serialize_trial(short_line, short_line_iterations, "short line")
run_serialize_trial(long_line, long_line_iterations, "long line")
run_serialize_trial(point, point_iterations, "point")
run_serialize_trial(small_polygon, small_polygon_iterations, "small polygon")
run_serialize_trial(large_polygon, large_polygon_iterations, "large polygon")
run_serialize_trial(small_multipoint, small_multipoint_iterations, "small multipoint")
run_serialize_trial(large_multipoint, large_multipoint_iterations, "large multipoint")
run_serialize_trial(small_multilinestring, small_multilinestring_iterations, "small multilinestring")
run_serialize_trial(large_multilinestring, large_multilinestring_iterations, "large multilinestring")
run_serialize_trial(small_multipolygon, small_multipolygon_iterations, "small multipolygon")
run_serialize_trial(large_multipolygon, large_multipolygon_iterations, "large multipolygon")

run_deserialize_trial(short_line, short_line_iterations, "short line")
run_deserialize_trial(long_line, long_line_iterations, "long line")
run_deserialize_trial(point, point_iterations, "point")
run_deserialize_trial(small_polygon, small_polygon_iterations, "small polygon")
run_deserialize_trial(large_polygon, large_polygon_iterations, "large polygon")
run_deserialize_trial(small_multipoint, small_multipoint_iterations, "small multipoint")
run_deserialize_trial(large_multipoint, large_multipoint_iterations, "large multipoint")
run_deserialize_trial(small_multilinestring, small_multilinestring_iterations, "small multilinestring")
run_deserialize_trial(large_multilinestring, large_multilinestring_iterations, "large multilinestring")
run_deserialize_trial(small_multipolygon, small_multipolygon_iterations, "small multipolygon")
run_deserialize_trial(large_multipolygon, large_multipolygon_iterations, "large multipolygon")


import time
# Definition for singly-linked list.
class ListNode(object):
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

# First Solution
# Second Solution Do a merge sort?
def mergeKLists(lists):
    """
    :type lists: List[ListNode]
    :rtype: ListNode
    """
    ptrs = []
    for ll in lists:
        ptrs += [ll]  # create a list of all the ptrs so we can iterate through each list

    new_ll = ListNode(0)  # ptr we will return in the end
    ptr_new_ll = new_ll  # ptr we will use to build the list

    while True:  # hopefully there's never an infinite loop
        # # Debugging Purposes
        # for i in ptrs:
        #     if i:
        #         print(i.val, end=", ")
        #     else:
        #         print("None",end=", ")
        # print()
        # lul = new_ll
        # while lul:
        #     print(lul.val, end=", ")
        #     lul = lul.next
        # print()
        # time.sleep(1)

        smallest = -1  # smallest value index
        smallest_val = None  # smallest value found
        ind = 0

        while ind < len(ptrs):
            ptr = ptrs[ind]
            if ptr:  # if the ptr isn't None
                if smallest_val == None or ptr.val < smallest_val:  # checks for the smallest value between all the ptrs
                    smallest_val = ptr.val
                    smallest = ind
                ind += 1
            else:
                del(ptrs[ind])

        # If the list aren't empty
        if smallest_val != None:
            ptr_new_ll.next = ListNode(ptrs[smallest].val)
            ptr_new_ll = ptr_new_ll.next
            ptrs[smallest] = ptrs[smallest].next
        else:  # this only occurs when all the lists are empty
            break
    return new_ll.next  # I use the next because there's an empty node in the beginning

# Creating the lists [[1,4,5],[1,3,4],[2,6]]
first_list = ListNode(1, ListNode(4, ListNode(5)))
second_list = ListNode(1, ListNode(3, ListNode(4)))
third_list = ListNode(2, ListNode(6))
fourth_list  = ListNode(0, ListNode(2, ListNode(5)))

# new_head = mergeKLists([first_list, second_list, third_list]) # should come back with [1,1,2,3,4,4,5,6]

new_head = mergeKLists([fourth_list])

# print the new head
new_ptr = new_head
while new_ptr:
    print(new_ptr.val, end=", ")
    new_ptr = new_ptr.next


import logging

from ..consts import FormatField, StepField
from ..documents import DocumentFile
from ..templates.steps import create_step, Step, \
    FormatStepException

LOG = logging.getLogger(__name__)

class Format:

    FORMAT_META_REQUIRED = [FormatField.UUID,
                            FormatField.NAME,
                            FormatField.STEPS]

    STEP_META_REQUIRED = [StepField.NAME,
                          StepField.OPTIONS]

    def __init__(self, template, metadata: dict):
        self.template = template
        self._verify_metadata(metadata)
        self.uuid = self._trace = metadata[FormatField.UUID]
        self.name = metadata[FormatField.NAME]
        LOG.info(f'Setting up format "{self.name}" ({self._trace})')
        self.steps = self._create_steps(metadata)
        if len(self.steps) < 1:
            self.template.raise_exc(f'Format {self.name} has no steps')

    def _verify_metadata(self, metadata: dict):
        for required_field in self.FORMAT_META_REQUIRED:
            if required_field not in metadata:
                self.template.raise_exc(f'Missing required field {required_field} for format')
        for step in metadata[FormatField.STEPS]:
            for required_field in self.STEP_META_REQUIRED:
                if required_field not in step:
                    self.template.raise_exc(f'Missing required field {required_field} '
                                            f'for step in format "{self.name}"')

    def _create_steps(self, metadata: dict) -> list[Step]:
        steps = []
        for step_meta in metadata[FormatField.STEPS]:
            step_name = step_meta[StepField.NAME]
            step_options = step_meta[StepField.OPTIONS]
            try:
                steps.append(
                    create_step(self.template, step_name, step_options)
                )
            except FormatStepException as e:
                LOG.warning('Handling job exception', exc_info=True)
                self.template.raise_exc(f'Cannot load step "{step_name}" of format "{self.name}"\n'
                                        f'- {e.message}')
            except Exception as e:
                LOG.warning('Handling job exception', exc_info=True)
                self.template.raise_exc(f'Cannot load step "{step_name}" of format "{self.name}"\n'
                                        f'- {str(e)}')
        return steps

    @property
    def is_pdf(self) -> bool:
        return self.steps[-1].produces_only_pdf

    def requires_via_extras(self, requirement: str) -> bool:
        return any(step.requires_via_extras(requirement)
                   for step in self.steps)

    def execute(self, context: dict) -> DocumentFile:
        result = self.steps[0].execute_first(context)
        for step in self.steps[1:]:
            if result is not None:
                result = step.execute_follow(result, context)
            else:
                break
        return result


import copy
import numpy as np
class connect4:

    def __init__(self, *args, **kwargs):
        if(len(args)==0):
            self.board = [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]]
            self.turn = 1
            self.last_move = (-1,-1)
        else:
            self.initialize_from_args(args)

def initialize_from_args(self, args):
    self.board = args[0]
    self.turn = args[1]
    self.last_move = args[2]

def __copy__(self):
    #return connect4(copy.copy(self.board), self.turn, copy.copy(self.last_move))
    return connect4(copy.deepcopy(self.board), self.turn, copy.deepcopy(self.last_move))

def draw(self):
    for i in range(7):
        if(self.board[0][i] == 0):
            return False
    return True

def check_se_diagonal(self, streakSize):
    n_connected = 1
    row = self.last_move[0]
    col = self.last_move[1]
    i = 1
    while(n_connected<streakSize):
        if(row + i > 5 or col + i > 6):
            break
        if(self.board[row+i][col+i] == self.board[row][col]):
            n_connected += 1
        else:
            break
        i += 1
    i = 1
    while(n_connected<streakSize):
        if(row - i < 0 or col - i < 0):
            break
        if(self.board[row-i][col-i] == self.board[row][col]):
            n_connected += 1
        else:
            break
        i += 1
    if(n_connected == streakSize):
        return True
    return False
def check_nw_diagonal(self, streakSize):
    n_connected = 1
    row = self.last_move[0]
    col = self.last_move[1]
    i = 1
    while(n_connected<streakSize):
        if(row + i > 5 or col - i < 0):
            break
        if(self.board[row+i][col-i] == self.board[row][col]):
            n_connected += 1
        else:
            break
        i += 1
    i = 1
    while(n_connected<streakSize):
        if(row - i < 0 or col + i > 6):
            break
        if(self.board[row-i][col+i] == self.board[row][col]):
            n_connected += 1
        else:
            break
        i += 1
    if(n_connected == streakSize):
        return True
    return False

def check_vertical(self, streakSize):
    n_connected = 1
    row = self.last_move[0]
    col = self.last_move[1]
    i = 1
    while(n_connected<streakSize):
        if(row + i > 5):
            break
        if(self.board[row+i][col] == self.board[row][col]):
            n_connected += 1
        else:
            break
        i += 1
    i = 1
    while(n_connected<streakSize):
        if(row - i < 0):
            break
        if(self.board[row-i][col] == self.board[row][col]):
            n_connected += 1
        else:
            break
        i += 1

    if(n_connected == streakSize):
        return True

def check_horizontal(self, streakSize):
    n_connected = 1
    row = self.last_move[0]
    col = self.last_move[1]
    i = 1
    while(n_connected<streakSize):
        if(col + i > 6):
            break
        if(self.board[row][col+i] == self.board[row][col]):
            n_connected += 1
        else:
            break
        i += 1
    i = 1
    while(n_connected<streakSize):
        if(col - i < 0):
            break
        if(self.board[row][col-i] == self.board[row][col]):
            n_connected += 1
        else:
            break
        i += 1
    if(n_connected == streakSize):
        return True
    return False

def has_won(self, streakSize):
    if(self.last_move[0]==-1):
        return False
    if(self.check_se_diagonal(streakSize) or self.check_nw_diagonal(streakSize) or self.check_vertical(streakSize) or self.check_horizontal(streakSize)):
        return True
    return False

def legal_move(self, col):
    if(self.board[0][col] ==0):
        return True
    return False

def play(self, col):
    for i in range(6):
        if(self.board[5-i][col]==0):
            self.board[5-i][col] = self.turn
            self.last_move = (5-i, col)
            if(self.turn == 1):
                self.turn = 2
            else:
                self.turn = 1
            break
def display_board(self):
    for row in self.board:
        print(row)

def rem_last(self):
    if(self.last_move[0]!= -1):
        self.board[self.last_move[0]][self.last_move[1]] = 0


from django.shortcuts import render
from django.shortcuts import render,redirect
from django.http import HttpResponse
from django.contrib import messages
from django.core.mail import send_mail
from validate_email import validate_email
from .models import send,resume,contect,certificate,project
import datetime
# import requests
import json
import os
import requests
def index(request):
    c=certificate.objects.all()
    p=project.objects.all()
    return render(request,"index.html",{"project":p,"certificate":c})
def sendlink(request):
    tday=datetime.date.today()
    email=request.POST["email"]
    is_valid = validate_email(email)
    if(is_valid):
        q=resume.objects.all()
        url=' '
        for i in q:
            url=i.url
        mail=send_mail("Download Resume"," ",os.environ.get('send_email'),[email],html_message='''
Thanks for visit my portfolio
Please click link to download Resume
Download'''.format(url))
        if mail:
            s=send(Email=email,Date=tday)
            s.save()
            messages.info(request,"Link send to your email pelase download")
            return redirect("index")
    else:
        messages.error(request,"Please enter valid Email")
        print("asdsafdsf")
        return redirect("index")

    return render(request,"index.html")

def contectmessage(request):
    email2=''
    tday=datetime.date.today()
    if(len(request.POST["username"])==0):
        messages.error(request,"Username required")
    else:
        username=request.POST["username"]
    if(len(request.POST["email"])==0):
        messages.error(request,"Email required")
    else:
        email=request.POST["email"]
        if(validate_email(email)):
            email2=email
        else:
            messages.error(request,"Invalid Email")

    if(len(request.POST["message"])==0):
        messages.error(request,"message required")
    else:
        message=request.POST["message"]

    recaptcha_response=request.POST.get("g-recaptcha-response")
    data = {
                'secret': os.environ.get('recaptcha_secret') ,
                'response': recaptcha_response
            }
    r = requests.post('https://www.google.com/recaptcha/api/siteverify', data=data)
    result = r.json()
    if result['success']:
        if(len(username)!=0 and len(email2)!=0 and len(message)!=0):
            obj=contect(Username=username,Email=email,Message=message,Date=tday)
            obj.save()
            messages.info(request,"Thanks for contect")
            send_mail("Portfolio Contect"," ",os.environ.get('send_email'),[os.environ.get('receive_email')],html_message='''
Username: {}

Email: {}

Message: {}
'''.format(username,email,message))
            return redirect("index")
    else:
        messages.error(request,"Recaptcha error")
        return redirect("index")


import cvxpy as cp
from functools import partial
import math
import pandas as pd
import matplotlib.pyplot as plt

class product:
    def __init__(self, price, carb):
        self.price = price
        self.carb = carb

class agent:
    def __init__(self, u, product_l):
        self.u = u
        self.product_l = product_l

    def fonc(self, lmbd, product_q): #pour chaque agent, on fait le calcul de sa fonction connaissant lambda et la quantité de produit
        sum = 0
        for i in range(0, len(self.product_l)):
            sum += product_q[i]*(self.product_l[i].price + lmbd*self.product_l[i].carb)
        return sum

class commu:
    def __init__(self, agent_list, product_list):
        self.agent_list = agent_list
        self.product_list = product_list

    def fonc_i(self, lmbd, C, product_q_ai):
        sum = 0
        for k in range(0, len(self.agent_list)):
            sum += self.agent_list[k].fonc(lmbd, product_q_ai[k])
        sum = sum - lmbd*C
        return sum

    def D(self, C, lmbd):
        x = cp.Variable((len(self.agent_list), len(self.agent_list[0].product_l)))
        constraints = [x >= 0]
        #on ajoute les contraintes

        for i in range(0, len(self.agent_list)):
            constraints.append((self.agent_list[i].u(x[i]) >= 1))
            constraints.append(x[i][0] + x[i][1] + x[i][2] + x[i][3] + x[i][4] + x[i][5] == 1)

        def f(m):
            return self.fonc_i(lmbd=lmbd, C=C, product_q_ai=m)

        objective = cp.Minimize(f(x))
        prob = cp.Problem(objective, constraints)
        prob.solve()
        print(x.value)
        return f(x.value)

    #Lagrange Multiplier
    def tot_emission(self, x):
        sum = 0
        for i in range(0, len(self.agent_list)):
            for j in range(0, len(self.product_list)):
                sum += x[i][j] * self.product_list[j].carb
        return sum

    def lmbdak(self, lmbda_old, k, gam, C, x_old):
        carb_emission = self.tot_emission(x_old)
        return max(0, lmbda_old + gam(k)*(carb_emission - C))

    def xk(self, lmbda, k, C):
        #on veut argmin de D(x, lmbda_old)...
        x = cp.Variable((len(self.agent_list), len(self.agent_list[0].product_l)))
        constraints = [x >= 0]
        #on ajoute les contraintes
        for i in range(0, len(self.agent_list)):
            constraints.append((self.agent_list[i].u(x[i]) >= 1))
            constraints.append(x[i][0] + x[i][1] + x[i][2] + x[i][3] + x[i][4] + x[i][5] == 1)

        def f(m):
            sum = 0
            for i in range(0, len(self.agent_list)):
                for j in range(0, len(self.product_list)):
                    sum += m[i][j] * self.product_list[j].price
            return sum + self.tot_emission(m)*lmbda - lmbda*C

        objective = cp.Minimize(f(x))
        prob = cp.Problem(objective, constraints)
        prob.solve()
        return x.value

    def distance(self, x, y):
        sum = 0
        for i in range(0, len(x)):
            for j in range(0, len(x[0])):
                sum += abs(x[i][j] - y[i][j])
        return sum

    def lagrange_multilplier_m(self, gam, C, eps_lmbd = 0.0000001, eps_x = 0.000001):
        #on prend lmbda0 = 0

        lmbda1 = - C * gam(1)

        lmbda_old = lmbda1
        x_old = [[0 for i in range(0, len(self.product_list))] for j in range(0, len(self.agent_list))]

        k = 1

        b = True
        while b:
            x_new = self.xk(lmbda_old, k, C)
            lmbda_new = self.lmbdak(lmbda_old, k, gam, C, x_new)

            #c1 = (abs(lmbda_old-lmbda_new) <= eps_lmbd)
            c2 = (self.distance(x_new, x_old) <= eps_x)
            print(self.distance(x_new, x_old))

            if c2:
                b = False
                print(lmbda_new)
                print(x_new)
                return lmbda_old

            #print(lmbda_new)
            x_old = x_new.copy()
            lmbda_old = lmbda_new
            #print(lmbda_old)
            k = k+1

        print(lmbda_old)
        print(x_old)
        return lmbda_old

#un exemple

l1 = [1.62, 0.1, 1.2, 1, 0.5, 1, 0.2, 1, 0.2, 1, 0.2, 1]
l2 =  [1.62, 0.1, 0.6, 1, 1.2, 1, 0.4, 1, 0.2, 1, 0.2, 1]
l3 =  [1.62, 0.1, 0.4, 1, 0.6, 1, 0.1, 1, 0.1, 1, 0.1, 1]

def u(l, x):
    s_tmp = 0
    for k in range(0, 6):
        s_tmp += x[k]
    return  l[0]*(x[0] + x[1] + l[1])**(0.5) + l[2]*(x[2] + l[3])**(0.5) + l[4]*(2*x[3] + x[4] + l[5])**(0.5) + l[6]*(x[5] + l[7])**(0.5) + l[8]*(x[6] + l[9])**(0.5) - (l[0]*(l[1])**(0.5) + l[2]*(l[3])**(0.5) + l[4]*(l[5])**(0.5) + l[6]*(l[7])**(0.5) + l[8]*(l[9])**(0.5))

elec_car = product(77, 37)
petrol_car = product(50, 92)
bus = product(35, 32)
e_bike = product(15, 8)
bike = product(3, 2)
foot = product(0,0)
choc = product(2,1)

prod_l = [elec_car, petrol_car, bus, e_bike, bike, foot, choc]

agent1 = agent(partial(u, l1), prod_l)
agent2 = agent(partial(u, l2), prod_l)
agent3 = agent(partial(u, l3), prod_l)

ens = commu([agent1, agent2, agent3], prod_l)

def maxfoncf(C, maxl, minl, N_val):
    print(C)
    x = [minl + (maxl - minl)*i/N_val for i in range(0, N_val-1)]
    x_max = 0
    y_max = -10000
    y = [ens.D(C, g) for g in x]
    for i in range(0, len(y)):
        if y_max < y[i]:
            y_max = y[i]
            x_max = x[i]
    print(ens.D(C, x_max))
    return x_max

def gam(x):
    return 1/(x+10)**2

#print("\n\n\nLambda : " + str(maxfoncf(100, 0, 5, 100)))

ens.lagrange_multilplier_m(gam, 100, 0.00001, 0.00001)
#C = [x for x in range(40, 70)]
#plt.plot(C, [max(c, 50, 0, 40) for c in C])
#plt.show()


import threading
import wx
from wx.lib.utils import AdjustRectToScreen
import plover.gui.util as util
from plover.dictionary_editor_store import DictionaryEditorStore
from plover.dictionary_editor_store import COLUMNS
from plover.dictionary_editor_store import COL_STROKE
from plover.dictionary_editor_store import COL_TRANSLATION
from plover.dictionary_editor_store import COL_DICTIONARY
from plover.dictionary_editor_store import COL_SPACER
from wx.grid import EVT_GRID_LABEL_LEFT_CLICK
from wx.grid import PyGridTableBase

TITLE = 'Plover: Dictionary Editor'

FILTER_BY_STROKE_TEXT = 'Filter by stroke:'
FILTER_BY_TRANSLATION_TEXT = 'Filter by translation:'
DO_FILTER_BUTTON_NAME = 'Filter'
INSERT_BUTTON_NAME = 'New Entry'
DELETE_BUTTON_NAME = 'Delete Selected'
SAVE_BUTTON_NAME = 'Save and Close'
CANCEL_BUTTON_NAME = 'Close'

NUM_COLS = len(COLUMNS)

class DictionaryEditor(wx.Dialog):

    BORDER = 3

    def __init__(self, parent, engine, config, on_exit):
        pos = (config.get_dictionary_editor_frame_x(),
               config.get_dictionary_editor_frame_y())
        wx.Dialog.__init__(self, parent, title=TITLE, pos=pos,
                           style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)

        self.config = config
        self.on_exit = on_exit

        # layout
        global_sizer = wx.BoxSizer(wx.VERTICAL)

        filter_sizer = wx.BoxSizer(wx.HORIZONTAL)

        filter_left_sizer = wx.FlexGridSizer(2, 2, 4, 10)

        label = wx.StaticText(self, label=FILTER_BY_STROKE_TEXT)
        filter_left_sizer.Add(label,
                              flag=wx.ALIGN_CENTER_VERTICAL,
                              border=self.BORDER)

        self.filter_by_stroke = wx.TextCtrl(self,
                                            style=wx.TE_PROCESS_ENTER,
                                            size=wx.Size(200, 20))
        self.Bind(wx.EVT_TEXT_ENTER, self._do_filter, self.filter_by_stroke)
        filter_left_sizer.Add(self.filter_by_stroke)

        label = wx.StaticText(self, label=FILTER_BY_TRANSLATION_TEXT)
        filter_left_sizer.Add(label,
                              flag=wx.ALIGN_CENTER_VERTICAL,
                              border=self.BORDER)

        self.filter_by_translation = wx.TextCtrl(self,
                                                 style=wx.TE_PROCESS_ENTER,
                                                 size=wx.Size(200, 20))
        self.Bind(wx.EVT_TEXT_ENTER,
                  self._do_filter,
                  self.filter_by_translation)
        filter_left_sizer.Add(self.filter_by_translation)

        filter_sizer.Add(filter_left_sizer, flag=wx.ALL, border=self.BORDER)

        do_filter_button = wx.Button(self, label=DO_FILTER_BUTTON_NAME)
        self.Bind(wx.EVT_BUTTON, self._do_filter, do_filter_button)

        filter_sizer.Add(do_filter_button,
                         flag=wx.EXPAND | wx.ALL,
                         border=self.BORDER)

        global_sizer.Add(filter_sizer, flag=wx.ALL, border=self.BORDER)

        self.store = DictionaryEditorStore(engine, config)

        # Grid
        self.grid = DictionaryEditorGrid(self, size=wx.Size(800, 600))
        self.grid.CreateGrid(self.store, 0, NUM_COLS)

        self.grid.SetRowLabelSize(wx.grid.GRID_AUTOSIZE)

        self.grid.SetColSize(COL_STROKE, 250)
        self.grid.SetColSize(COL_TRANSLATION, 250)
        self.grid.SetColSize(COL_DICTIONARY, 150)

        read_only_right_aligned = wx.grid.GridCellAttr()
        read_only_right_aligned.SetReadOnly(True)
        read_only_right_aligned.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE)
        self.grid.SetColAttr(COL_DICTIONARY, read_only_right_aligned)
        self.grid.SetColAttr(COL_SPACER, read_only_right_aligned)

        global_sizer.Add(self.grid, 1, wx.EXPAND)

        buttons_sizer = wx.BoxSizer(wx.HORIZONTAL)

        insert_button = wx.Button(self, label=INSERT_BUTTON_NAME)
        self.Bind(wx.EVT_BUTTON, self._insert_new, insert_button)

        buttons_sizer.Add(insert_button, flag=wx.ALL, border=self.BORDER)

        delete_button = wx.Button(self, label=DELETE_BUTTON_NAME)
        self.Bind(wx.EVT_BUTTON, self._delete, delete_button)

        buttons_sizer.Add(delete_button, flag=wx.ALL, border=self.BORDER)

        buttons_sizer.Add((0, 0), 1, wx.EXPAND)

        save_button = wx.Button(self, label=SAVE_BUTTON_NAME)
        self.Bind(wx.EVT_BUTTON, self._save_close, save_button)

        buttons_sizer.Add(save_button, flag=wx.ALL, border=self.BORDER)

        cancel_button = wx.Button(self, label=CANCEL_BUTTON_NAME)
        self.Bind(wx.EVT_BUTTON, self._cancel_close, cancel_button)

        buttons_sizer.Add(cancel_button, flag=wx.ALL, border=self.BORDER)

        global_sizer.Add(buttons_sizer,
                         0,
                         flag=wx.EXPAND | wx.ALL,
                         border=self.BORDER)

        self.Bind(wx.EVT_MOVE, self._on_move)
        self.Bind(wx.EVT_CLOSE, self._on_close)

        self.SetAutoLayout(True)
        self.SetSizer(global_sizer)
        global_sizer.Fit(self)
        global_sizer.SetSizeHints(self)
        self.Layout()
        self.SetRect(AdjustRectToScreen(self.GetRect()))

        self.last_window = util.GetForegroundWindow()

    def _do_filter(self, event=None):
        threading.Thread(target=self._do_filter_thread).start()

    def _do_filter_thread(self):
        self.store.ApplyFilter(self.filter_by_stroke.GetValue(),
                               self.filter_by_translation.GetValue())
        self.grid.RefreshView()

    def _insert_new(self, event=None):
        self.grid.InsertNew()

    def _delete(self, event=None):
        self.grid.DeleteSelected()

    def _save_close(self, event=None):
        self.store.SaveChanges()
        self.Close()

    def _cancel_close(self, event=None):
        self.Close()

    def _on_move(self, event):
        pos = self.GetScreenPositionTuple()
        self.config.set_dictionary_editor_frame_x(pos[0])
        self.config.set_dictionary_editor_frame_y(pos[1])
        event.Skip()

    def _on_close(self, event=None):
        result = wx.ID_YES
        if self.store.pending_changes:
            dlg = wx.MessageDialog(self,
                                   "You will lose your changes. Are you sure?",
                                   "Cancel",
                                   wx.YES_NO | wx.ICON_QUESTION)
            result = dlg.ShowModal()
            dlg.Destroy()
        if result == wx.ID_YES:
            try:
                util.SetForegroundWindow(self.last_window)
            except:
                pass
            self.on_exit()
            self.Destroy()

class DictionaryEditorGrid(wx.grid.Grid):
    """ Dictionary Manager's grid """
    GRID_LABEL_STROKE = "Stroke"
    GRID_LABEL_TRANSLATION = "Translation"
    GRID_LABEL_DICTIONARY = "Dictionary"
    GRID_LABEL_SPACER = " "
    sorted_labels = sorted([[COL_STROKE, GRID_LABEL_STROKE],
                            [COL_TRANSLATION, GRID_LABEL_TRANSLATION],
                            [COL_SPACER, GRID_LABEL_SPACER],
                            [COL_DICTIONARY, GRID_LABEL_DICTIONARY]])
    grid_labels = [pair[1] for pair in sorted_labels]

    def __init__(self, *args, **kwargs):
        wx.grid.Grid.__init__(self, *args, **kwargs)

        self.parent = args[0]

        self._changedRow = None

    def CreateGrid(self, store, rows, cols):
        """ Create the grid """

        wx.grid.Grid.CreateGrid(self, rows, cols)
        wx.grid.Grid.DisableDragRowSize(self)

        self.store = store

        # Set GridTable
        self._table = DictionaryEditorGridTable(self.store)
        self.SetTable(self._table)

        self._sortingColumn = 0
        self._sortingAsc = None

        self.Bind(EVT_GRID_LABEL_LEFT_CLICK, self._onLabelClick)

    def RefreshView(self):
        self._table.ResetView(self)

    def InsertNew(self):
        selected_row = self.GetGridCursorRow()
        self.store.InsertNew(selected_row)
        self._table.ResetView(self)

    def DeleteSelected(self):
        selected_row = self.GetGridCursorRow()
        self.store.DeleteSelected(selected_row)
        self._table.ResetView(self)

    def _onLabelClick(self, evt):
        """ Handle Grid label click"""

        if evt.Row == -1:
            if evt.Col >= 0:
                self.store.Sort(evt.Col)
                sort_column = self.store.GetSortColumn()
                sort_mode = self.store.GetSortMode()
                self._updateGridLabel(sort_column, sort_mode)
                self._table.ResetView(self)

        if evt.Col == -1:
            if evt.Row >= 0:
                self.SelectRow(evt.Row)
                self.SetGridCursor(evt.Row, 0)

    def _updateGridLabel(self, column, mode):
        """ Change grid's column labels """

        directionLabel = ""
        if mode is not None:
            directionLabel = " (asc)" if mode else " (desc)"
        for i in range(len(self.grid_labels)):
            label = (self.grid_labels[i] +
                     (directionLabel if column == i else ""))
            self._table.SetColLabelValue(i, label)

class DictionaryEditorGridTable(PyGridTableBase):
    """
    A custom wx.Grid Table using user supplied data
    """
    def __init__(self, store):
        """ Init GridTableBase with a Store. """

        # The base class must be initialized *first*
        PyGridTableBase.__init__(self)
        self.store = store
        cols = sorted([[COL_STROKE, "Stroke"],
                       [COL_SPACER, ""],
                       [COL_TRANSLATION, "Translation"],
                       [COL_DICTIONARY, "Dictionary"]])
        self.col_names = [pair[1] for pair in cols]

        self._rows = self.GetNumberRows()
        self._cols = self.GetNumberCols()

    def GetNumberCols(self):
        return len(self.col_names)

    def GetNumberRows(self):
        return self.store.GetNumberOfRows()

    def GetColLabelValue(self, col):
        return self.col_names[col]

    def SetColLabelValue(self, col, name):
        self.col_names[col] = name

    def GetRowLabelValue(self, row):
        return str(row + 1)

    def GetValue(self, row, col):
        return self.store.GetValue(row, col)

    def SetValue(self, row, col, value):
        self.store.SetValue(row, col, value)

    def ResetView(self, grid):

        grid.BeginBatch()

        for current, new, delmsg, addmsg in [
            (self._rows, self.GetNumberRows(),
                wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED,
                wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED),
            (self._cols, self.GetNumberCols(),
                wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED,
                wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED)
        ]:
            if new < current:
                msg = wx.grid.GridTableMessage(self,
                                               delmsg,
                                               new,
                                               current-new)
                grid.ProcessTableMessage(msg)
            elif new > current:
                msg = wx.grid.GridTableMessage(self,
                                               addmsg,
                                               new-current)
                grid.ProcessTableMessage(msg)
                self.UpdateValues(grid)

        grid.EndBatch()

        self._rows = self.GetNumberRows()
        self._cols = self.GetNumberCols()

        grid.AdjustScrollbars()
        grid.ForceRefresh()

    def UpdateValues(self, grid):
        """Update all displayed values"""
        # This sends an event to the grid table to update all of the values
        msg = (wx.grid
               .GridTableMessage(self,
                                 wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES))
        grid.ProcessTableMessage(msg)

def Show(parent, engine, config):
    if 'dialog_instance' not in Show.__dict__:
        Show.dialog_instance = None

    def clear_instance():
        Show.dialog_instance = None

    if Show.dialog_instance is None:
        Show.dialog_instance = DictionaryEditor(parent,
                                                engine,
                                                config,
                                                clear_instance)
    Show.dialog_instance.Show()
    Show.dialog_instance.Raise()
    util.SetTopApp()


# import torch
# import torch.nn as nn
# import torch.nn.functional as F
# from torch.nn.utils import weight_norm, spectral_norm
import numpy as np
import jax
import jax.numpy as jnp
import flax.linen as nn
from jax.nn.initializers import normal as normal_init
from jax.nn.initializers import constant as constant_init
from .snake import snake

class DiscriminatorP(nn.Module):
    hp:tuple
    period:tuple
    def setup(self):
        self.LRELU_SLOPE = self.hp.mpd.lReLU_slope

        kernel_size = self.hp.mpd.kernel_size
        stride = self.hp.mpd.stride

        self.convs = [
            nn.Conv(64, (kernel_size, 1), (stride, 1)),
            nn.Conv( 128, (kernel_size, 1), (stride, 1)),
            nn.Conv( 256, (kernel_size, 1), (stride, 1)),
            nn.Conv( 512, (kernel_size, 1), (stride, 1)),
            nn.Conv( 1024, (kernel_size, 1), 1),
        ]
        self.conv_post = nn.Conv(1, (3, 1), 1)

    def __call__(self, x,train=True):
        fmap = []

        # 1d to 2d
        b, c, t = x.shape
        if t % self.period != 0: # pad first
            n_pad = self.period - (t % self.period)
            x = jnp.pad(x, [(0,0),(0,0),(0, n_pad)], "reflect")
            t = t + n_pad
        x = jnp.reshape(x,[b, c, t // self.period, self.period])

        for l in self.convs:
            x = l(x.transpose(0,2,3,1)).transpose(0,3,1,2)
            #x = nn.leaky_relu(x, self.LRELU_SLOPE)
            x = nn.swish(x)
            fmap.append(x)
        x = self.conv_post(x.transpose(0,2,3,1)).transpose(0,3,1,2)
        fmap.append(x)
        x = jnp.reshape(x,[x.shape[0],-1])

        return fmap, x

class MultiPeriodDiscriminator(nn.Module):
    hp:tuple
    def setup(self):
        self.discriminators = [DiscriminatorP(self.hp, period) for period in self.hp.mpd.periods]

    def __call__(self, x,train=True):
        ret = list()
        for disc in self.discriminators:
            ret.append(disc(x,train=train))

        return ret  # [(feat, score), (feat, score), (feat, score), (feat, score), (feat, score)]


# Search config, (defaults etc.)
# ------------------------------

max_pages_to_display = 10
default_results_per_page_search = 10
default_results_per_page_browse = 20
default_results_per_page_newest = 12
default_results_per_page_api = 10
sort_options_search = {"score desc": "Score (high-low)", "published_date desc": "Published (new-old)", "page_last_modified desc": "Modified (new-old)"}
sort_options_browse = {"date_domain_added desc": "Added (new-old)", "date_domain_added asc": "Added (old-new)", "domain asc": "Domain (A-Z)", "domain desc": "Domain (Z-A)", "indexed_inlink_domains_count desc": "Inlinks (high-low)"}
sort_options_newest = {"published_date desc": "Published (new-old)", "published_date asc": "Published (old-new)", "page_last_modified desc": "Modified (new-old)"}
default_sort_search = "score desc"
default_sort_browse = "date_domain_added desc"
default_sort_newest = "published_date desc"
mandatory_filter_queries_search = ["public:true", "!content_type:*xml", "!content_type:application*", "!content_type:binary*"]
mandatory_filter_queries_browse = ["public:true", "is_home:true"]
mandatory_filter_queries_newest = mandatory_filter_queries_search + ["contains_adverts:false", "published_date:[NOW-30YEARS TO NOW]"] # to ensure no future dates or infeasibly far past dates
split_text = '--split-here--'
solr_request_handler = "select" # The custom config in solrconfig.xml, especially the relevancy tuning, is only set for the select request handler
solr_request_headers = {'Content-Type': 'text/json'}

# Solr search queries
# -------------------

# There are 5 search queries. The main differences are the mandatory filter queries:
# 1. Main search, i.e. queries from the search box. This has to show only public content, and filters out non-web friendly results.
# 2. Browse Sites search. This has to show only public content, and only home pages.
# 3. Newest Pages search. This is as per the main search, but also filters out pages that might not be posts and sorts by date.
# 4. Random Page search. This is actually 3 sub searches, to find no of sites, no of pages in random site, and details of random page.
# 5. Site specific API. This is only returned for site where api_enabled, but will return all content in the site (it is down to users to filter).

# 1. Main search query
# Notes:
# a. defType:edismax is to use the edismax query parser, required for the relevancy tuning defined in solrconfig.xml. edismax
#    (or dismax) is required because the relevancy tuning uses qf and pf which aren't available in the default lucene query parser.
# b. mm:2 is must match two words, applicable when the query contains more than two words, so e.g. "book about antarctica"
#    (without the double quotes) will require book and antarctica but not just book.
# c. fq is to ensure the public search only contains results marked for the public search and filters out "non web friendly"
#    results like XML and binary files.
# d. group:True is set to False if the query contains domain:<domain>, i.e. someone is searching for content on a specific domain.
#    The other group params will be irrelevant when group:False.
query_params_search = {
    "q": "*:*",
    "defType": "edismax",
    "mm": 2,
    "start": 0,
    "rows": default_results_per_page_search,
    "sort": default_sort_search,
    "fl": ["id", "url", "title", "description", "contains_adverts", "published_date"],
    "q.op": "AND",
    "fq": mandatory_filter_queries_search,
    "hl": True,
    "hl.fl": ["content", "description"],
    "hl.method": "original", # default is "original" in Sol 8 but "unified" in Solr 9. Unfortunately "unified" in Solr 9.0 seems to ignore hl.fragsize
    "hl.fragsize": 100,
    "hl.simple.pre": split_text,
    "hl.simple.post": split_text,
    "group": True,
    "group.field": "domain",
    "group.limit": 3,
    "group.ngroups": True
}

query_facets_search = {
    "site_category":                { "field": "site_category",                "type": "terms", "limit":  2, "sort": "count" },
    "in_web_feed":                  { "field": "in_web_feed",                  "type": "terms", "limit":  2, "sort": "count" },
    "language_primary":             { "field": "language_primary",             "type": "terms", "limit": 20, "sort": "count" }
}

# 2. Browse query
# Notes:
# a. Don't need to specify the query parser because browse just has simple ordering with no custom config, e.g. relevancy tuning, required.
# b. The fq is the base filter query that must always be present on browse - it may be supplemented by values selected in the filters.
query_params_browse = {
    "q": "*:*",
    "start": 0,
    "rows": default_results_per_page_browse,
    "sort": default_sort_browse,
    "fl": ["id", "url", "title", "domain", "date_domain_added", "tags", "web_feed"],
    "fq": mandatory_filter_queries_browse
}
query_facets_browse = {
    "site_category":                { "field": "site_category",                "type": "terms", "limit": 2, "sort": "count" },
    "tags":                         { "field": "tags",                         "type": "terms", "limit": 8, "sort": "count" },
    "owner_verified":               { "field": "owner_verified",               "type": "terms", "limit": 2, "sort": "count" },
    "contains_adverts":             { "field": "contains_adverts",             "type": "terms", "limit": 2, "sort": "count" },
    "indexed_inlink_domains_count": { "field": "indexed_inlink_domains_count", "type": "terms", "limit": 4, "sort": "index desc" },
    "language_primary":             { "field": "language_primary",             "type": "terms", "limit": 8, "sort": "count" }
}

# 3. Newest pages query
# Notes:
# a. The fq is as per the main search, but also ensures there is a published_date and excludes pages with adverts from this feed
# b. The group is to ensure only one result per domain (to prevent any one domain from dominating the feed)
query_params_newest = {
    "q": "*:*",
    "defType": "edismax",
    "mm": 2,
    "start": 0,
    "rows": default_results_per_page_newest,
    "sort": default_sort_newest,
    "fl": ["id", "url", "title", "description", "published_date", "tags"],
    "fq": mandatory_filter_queries_newest,
    "hl": "on",
    "hl.fl": ["content", "description"],
    "hl.simple.pre": split_text,
    "hl.simple.post": split_text,
    "group": True,
    "group.field": "domain",
    "group.limit": 1,
    "group.ngroups": True
}
query_facets_newest = query_facets_search

# 4. Random result queries
query_filter_public = '&fq=public%3Atrue'
query_filter_content_type = '&fq=!content_type%3A*xml&fq=!content_type%3Aapplication*&fq=!content_type%3Abinary*'
query_groupbydomain = '&group=true&group.field=domain&group.limit={}&group.ngroups=true'
random_result_step1_get_no_of_domains = 'select?q=*%3A*&rows=0' + query_filter_public + query_groupbydomain.format('1')
random_result_step2_get_domain_and_no_of_docs_on_domain = 'select?q=*%3A*&rows=1&start={}&fl=domain' + query_filter_content_type + query_filter_public + query_groupbydomain.format('1')
random_result_step3_get_doc_from_domain = 'select?q=*%3A*&rows=1&start={}&fq=domain%3A{}' + query_filter_content_type

# 5. API query
# &fq=!relationship%3Achild added to ensure only parent pages are returned, i.e. not the content chunks used for embedding
# (can't use fq=relationship%3Aparent because not all pages will have a value for relationship initially)
solrquery = 'select?fl=id,url,title,author,description,tags,page_type,page_last_modified,published_date,language,indexed_inlinks,indexed_outlinks&q={}&start={}&rows={}&wt=json&fq=domain%3A{}&fq=!relationship%3Achild&hl=on&hl.fl=content&hl.simple.pre={}&hl.simple.post={}'

# Solr update queries
# -------------------

# Delete queries, used in adminutils
solr_delete_query = "update?commit=true"
solr_delete_headers = {'Content-Type': 'text/xml'}
solr_delete_data = "<delete><query>domain:{}</query></delete>"


'''Train Fer2013 with PyTorch.'''
# 10 crop for data enhancement
from __future__ import print_function

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import torch.backends.cudnn as cudnn
import torchvision
from torchvision import datasets, transforms
import transforms as transforms
import numpy as np
import os
import argparse
import utils
from fer import FER2013
from torch.autograd import Variable
from models import *
from tqdm import tqdm
from adversarial import fgsm, pgd, AdversarialLoader
from functools import partial

# init
Train_acc = 0.0
PublicTest_acc = 0.0
PrivateTest_acc = 0.0
best_PublicTest_acc = 0.0  # best PublicTest accuracy
best_PublicTest_acc_epoch = 0
best_PrivateTest_acc = 0  # best PrivateTest accuracy
best_PrivateTest_acc_epoch = 0
start_epoch = 0  # start from epoch 0 or last checkpoint epoch

ATTACKS = {
    'pgd': pgd,
    'fgsm': fgsm
}

class CombineLoaders():
    def __init__(self, *loaders):
        self.loaders = loaders

    def __iter__(self):
        print(self.loaders[0][0])
#	iters = [iter(loader) for loader in self.loaders]
        # while True:
            # items = [next(it) for it in self.loaders]
            # import pdb
            # pdb.set_trace()
            # items = [next(it) for it in self.loaders]
            # print(items[0])
            # images = torch.cat([i[0] for i in items])
            # labels = torch.cat([i[1] for i in items])
            # yield images, labels

    def __len__(self):
        return min([len(loader) for loader in self.loaders])

# Training
def train(epoch, finalTrainLoader):
    print('\nEpoch: %d' % epoch)
    global Train_acc, PublicTest_acc, PrivateTest_acc
    net.train()
    train_loss = 0.0
    correct = 0.0
    total = 0
    batch_idx = 0

    if epoch > learning_rate_decay_start and learning_rate_decay_start >= 0:
        frac = (epoch - learning_rate_decay_start) // learning_rate_decay_every
        decay_factor = learning_rate_decay_rate ** frac
        current_lr = opt.lr * decay_factor
        utils.set_lr(optimizer, current_lr)  # set the decayed rate
    else:
        current_lr = opt.lr
    print('learning_rate: %s' % str(current_lr))
    try:
        with tqdm(finalTrainLoader) as t:
            for inputs, targets in t:
                batch_idx += 1
                if use_cuda:
                    inputs, targets = inputs.cuda(), targets.cuda()
                if opt.adv_train_flag:
                    if batch_idx % opt.adv_train_sample:
                        inputs = attack_fn(net, inputs, targets)

                optimizer.zero_grad()
                # inputs, targets = Variable(inputs), Variable(targets)
                with torch.no_grad():
                    inputs = torch.tensor(inputs)
                    targets = torch.tensor(targets)
                    # print(inputs.shape)
                outputs = net(inputs)
                loss = criterion(outputs, targets)
                loss.backward()
                utils.clip_gradient(optimizer, 0.1)
                optimizer.step()
                train_loss += loss.item()
                _, predicted = torch.max(outputs.data, 1)
                total += targets.size(0)
                correct += predicted.eq(targets.data).cpu().sum()

                # utils.progress_bar(batch_idx, len(trainloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)'
                # % (train_loss/(batch_idx+1), 100.*correct/total, correct, total))
                tqdm.write("Loss: %.3f | Acc: %.3f %%(%d/%d)" % (train_loss/batch_idx, 100.0*float(correct)/total, correct, total))
                # print(100.0*float(correct.numpy())/total, correct.numpy(), total)
    except KeyboardInterrupt:
        t.close()
        raise
    t.close()
    Train_acc = 100.*correct/total
    state = {
        'net': net.state_dict() if use_cuda else net,
        'acc': PublicTest_acc,
        'epoch': epoch,
    }
    torch.save(state, os.path.join(path, 'PublicTest_model.t7'))
    state = {
        'net': net.state_dict() if use_cuda else net,
        'best_PublicTest_acc': best_PublicTest_acc,
        'best_PrivateTest_acc': PrivateTest_acc,
        'best_PublicTest_acc_epoch': best_PublicTest_acc_epoch,
        'best_PrivateTest_acc_epoch': epoch,
    }
    torch.save(state, os.path.join(path, 'PrivateTest_model.t7'))

def PublicTest(epoch, finalPublicTestloader):
    global PublicTest_acc
    global best_PublicTest_acc
    global best_PublicTest_acc_epoch
    net.eval()
    PublicTest_loss = 0.0
    correct = 0.0
    total = 0
    for batch_idx, (inputs, targets) in enumerate(finalPublicTestloader):
        bs, ncrops, c, h, w = np.shape(inputs)
        inputs = inputs.view(-1, c, h, w)
        if use_cuda:
            inputs, targets = inputs.cuda(), targets.cuda()

        # inputs, targets = Variable(inputs, volatile=True), Variable(targets)
        with torch.no_grad():
            inputs = torch.tensor(inputs)
            targets = torch.tensor(targets)
            print(inputs.shape, targets.shape)

        if use_cuda:
            inputs, targets = inputs.cuda(), targets.cuda()
        if opt.adv_test_flag:
            if batch_idx % opt.adv_test_sample:
                inputs = attack_fn(net, inputs, targets, bs, ncrops)

        outputs = net(inputs)
        outputs_avg = outputs.view(bs, ncrops, -1).mean(1)  # avg over crops
        loss = criterion(outputs_avg, targets)
        # PublicTest_loss += loss.data[0]
        PublicTest_loss += loss.item()
        _, predicted = torch.max(outputs_avg.data, 1)
        total += targets.size(0)
        correct += predicted.eq(targets.data).cpu().sum()

        utils.progress_bar(batch_idx, len(PublicTestloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)'
                           % (PublicTest_loss / (batch_idx + 1), 100.0 * float(correct) / total, correct, total))

    # Save checkpoint.
    PublicTest_acc = 100.0*float(correct)/total
    if PublicTest_acc > best_PublicTest_acc:
        print('Saving..')
        print("best_PublicTest_acc: %0.3f" % PublicTest_acc)
        state = {
            'net': net.state_dict() if use_cuda else net,
            'acc': PublicTest_acc,
            'epoch': epoch,
        }
        if not os.path.isdir(path):
            os.mkdir(path)
        torch.save(state, os.path.join(path, 'PublicTest_model.t7'))
        best_PublicTest_acc = PublicTest_acc
        best_PublicTest_acc_epoch = epoch

def PrivateTest(epoch, finalPrivateTestloader):
    global PrivateTest_acc
    global best_PrivateTest_acc
    global best_PrivateTest_acc_epoch
    net.eval()
    PrivateTest_loss = 0
    correct = 0
    total = 0
    for batch_idx, (inputs, targets) in enumerate(finalPrivateTestloader):
        bs, ncrops, c, h, w = np.shape(inputs)
        inputs = inputs.view(-1, c, h, w)
        if use_cuda:
            inputs, targets = inputs.cuda(), targets.cuda()

        if use_cuda:
            inputs, targets = inputs.cuda(), targets.cuda()
        if opt.adv_test_flag:
            if batch_idx % opt.adv_test_sample:
                inputs = attack_fn(net, inputs, targets, bs=bs, ncrops=ncrops)

        inputs, targets = Variable(inputs, volatile=True), Variable(targets)
        outputs = net(inputs)
        outputs_avg = outputs.view(bs, ncrops, -1).mean(1)  # avg over crops
        loss = criterion(outputs_avg, targets)
        # PrivateTest_loss += loss.data[0]
        PrivateTest_loss += loss.item()
        _, predicted = torch.max(outputs_avg.data, 1)
        total += targets.size(0)
        correct += predicted.eq(targets.data).cpu().sum().numpy()

        utils.progress_bar(batch_idx, len(PrivateTestloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)'
                           % (PrivateTest_loss / (batch_idx + 1), 100. * float(correct) / total, correct, total))
    # Save checkpoint.
    PrivateTest_acc = 100.*correct/total

    if PrivateTest_acc > best_PrivateTest_acc:
        print('Saving..')
        print("best_PrivateTest_acc: %0.3f" % PrivateTest_acc)
        state = {
            'net': net.state_dict() if use_cuda else net,
            'best_PublicTest_acc': best_PublicTest_acc,
            'best_PrivateTest_acc': PrivateTest_acc,
            'best_PublicTest_acc_epoch': best_PublicTest_acc_epoch,
            'best_PrivateTest_acc_epoch': epoch,
        }
        if not os.path.isdir(path):
            os.mkdir(path)
        torch.save(state, os.path.join(path, 'PrivateTest_model.t7'))
        best_PrivateTest_acc = PrivateTest_acc
        best_PrivateTest_acc_epoch = epoch

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='PyTorch Fer2013 CNN Training')
    parser.add_argument('--model', type=str, default='Resnet18', help='CNN architecture')
    parser.add_argument('--dataset', type=str, default='FER2013', help='CNN architecture')
    parser.add_argument('--bs', default=32, type=int, help='learning rate')
    parser.add_argument('--lr', default=0.01, type=float, help='learning rate')
    parser.add_argument('--resume', '-r', action='store_true', help='resume from checkpoint')
    parser.add_argument('--attack', type=str, default='fgsm', help='attack function')
    parser.add_argument('--epsilon', type=float, default=0.3, help='epsilon for attack function')
    parser.add_argument('--pgd_step_size', type=float, default=0.01, help='step size for pgd')
    parser.add_argument('--pgd_num_steps', type=int, default=40, help='num of steps for pgd')
    parser.add_argument('--pgd_random_start', type=bool, default=True, help='random start for pgd')
    parser.add_argument('--train', type=int, default=1, help='1 for train, 2,3 for train and val')
    parser.add_argument('--adv_train_flag', type=bool, default=False, help='flag for whether to use adversarial')
    parser.add_argument('--adv_test_flag', type=bool, default=True, help='flag for whether to use adversarial')
    parser.add_argument('--adv_train_sample', type=int, default=10, help='every # steps to generate an adversarial sample')
    parser.add_argument('--adv_test_sample', type=int, default=2, help='every # steps to generate an adversarial sample')

    opt = parser.parse_args()

    use_cuda = torch.cuda.is_available()
    best_PublicTest_acc = 0.0  # best PublicTest accuracy
    best_PublicTest_acc_epoch = 0
    best_PrivateTest_acc = 0.0  # best PrivateTest accuracy
    best_PrivateTest_acc_epoch = 0
    start_epoch = 0  # start from epoch 0 or last checkpoint epoch

    learning_rate_decay_start = 80  # 50
    learning_rate_decay_every = 5  # 5
    learning_rate_decay_rate = 0.9  # 0.9

    cut_size = 44
    total_epoch = 250

    path = os.path.join(opt.dataset + '_' + opt.model)

    # Data
    print('==> Preparing data..')
    transform_train = transforms.Compose([
        transforms.RandomCrop(44),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
    ])

    transform_test = transforms.Compose([
        transforms.TenCrop(cut_size),
        transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])),
    ])

    data_transforms = {
        'train': transform_train,
        'test': transform_test,
        'val': transform_test
    }

    trainset = FER2013(split='Training', transform=transform_train)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=opt.bs, shuffle=True, num_workers=1)

    PublicTestset = FER2013(split='PublicTest', transform=transform_test)
    PublicTestloader = torch.utils.data.DataLoader(PublicTestset, batch_size=opt.bs, shuffle=True, num_workers=1)

    PrivateTestset = FER2013(split='PrivateTest', transform=transform_test)
    PrivateTestloader = torch.utils.data.DataLoader(PrivateTestset, batch_size=opt.bs, shuffle=True, num_workers=1)

    # data_dir = r"C:\Users\lenovo\Desktop\course\ML\fer_project\data"
    # image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in
    #                   ['train', 'test', 'val']}
    # dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=opt.bs, shuffle=True, num_workers=1)
    #                for x in ['train', 'test', 'val']}
    # dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'test', 'val']}
    # class_names = image_datasets['train'].classes
    #
    # trainloader = dataloaders['train']
    # PrivateTestloader = dataloaders['test']
    # PublicTestloader = dataloaders['val']

    # Model
    if opt.model == 'VGG19':
        net = VGG('VGG19')
    elif opt.model == 'Resnet18':
        net = ResNet18()
    elif opt.model == 'Resnet34':
        net = ResNet34()
    elif opt.model == 'Resnet50':
        net = ResNet50()
    elif opt.model == 'Resnet101':
        net = ResNet101()
    elif opt.model == 'Resnet152':
        net = ResNet152()
        print('using Resnet152')

    if opt.resume:
        # Load checkpoint.
        print('==> Resuming from checkpoint..')
        assert os.path.isdir(path), 'Error: no checkpoint directory found!'
        checkpoint = torch.load(os.path.join(path, 'PrivateTest_model.t7'))

        net.load_state_dict(checkpoint['net'])
        best_PublicTest_acc = checkpoint['best_PublicTest_acc']
        best_PrivateTest_acc = checkpoint['best_PrivateTest_acc']
        best_PrivateTest_acc_epoch = checkpoint['best_PublicTest_acc_epoch']
        best_PrivateTest_acc_epoch = checkpoint['best_PrivateTest_acc_epoch']
        start_epoch = checkpoint['best_PrivateTest_acc_epoch'] + 1
    else:
        print('==> Building model..')

    if use_cuda:
        net.cuda()

    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(net.parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4)

    if opt.attack == 'pgd':
        attack_fn = partial(ATTACKS[opt.attack],
                            epsilon=opt.epsilon,
                            step_size=opt.pgd_step_size,
                            num_steps=opt.pgd_num_steps,
                            random_start=opt.pgd_random_start)
    else:
        attack_fn = partial(ATTACKS[opt.attack], epsilon=opt.epsilon)
    advTrainLoader = AdversarialLoader(net, trainloader, attack_fn)
    finalTrainLoader = CombineLoaders([trainloader, advTrainLoader])

    advPublicTestLoader = AdversarialLoader(net, PublicTestloader, attack_fn)
    finalPublicTestLoader = CombineLoaders([PublicTestloader, advPublicTestLoader])

    advPrivateTestLoader = AdversarialLoader(net, PrivateTestloader, attack_fn)
    finalPrivateTestLoader = CombineLoaders([PrivateTestloader, advPrivateTestLoader])

    # 1 to train, 2 to val, 3 to train and val
    if opt.train == 1:
        for epoch in range(start_epoch, total_epoch):
            train(epoch, trainloader)
    if opt.train == 2:
        print('==>Val the model')
        PublicTest(start_epoch, PublicTestloader)
        PrivateTest(start_epoch, PrivateTestloader)
    if opt.train == 3:
        for epoch in range(start_epoch, total_epoch):
            train(epoch, trainloader)
            PublicTest(epoch, PublicTestloader)
            PrivateTest(epoch, PrivateTestloader)

    print("best_PublicTest_acc: %0.3f" % best_PublicTest_acc)
    print("best_PublicTest_acc_epoch: %d" % best_PublicTest_acc_epoch)
    print("best_PrivateTest_acc: %0.3f" % best_PrivateTest_acc)
    print("best_PrivateTest_acc_epoch: %d" % best_PrivateTest_acc_epoch)


# import openpyxl and tkinter modules
from tkinter import filedialog

from openpyxl import load_workbook
from tkinter import *
from Main import my_logic

# globally declare wb and sheet variable

# opening the existing excel file

wb = load_workbook('data.xlsx')

# create the sheet object
sheet = wb.active

def excel():
    # resize the width of columns in
    # excel spreadsheet
    sheet.column_dimensions['A'].width = 30
    sheet.column_dimensions['B'].width = 50
    sheet.column_dimensions['C'].width = 30
    sheet.column_dimensions['D'].width = 30
    sheet.column_dimensions['E'].width = 10
    sheet.column_dimensions['F'].width = 10
    sheet.column_dimensions['G'].width = 10

    # write given data to an excel spreadsheet
    # at particular location
    sheet.cell(row=1, column=1).value = "Meeting Title"
    sheet.cell(row=1, column=2).value = "Meeting Transcript"
    sheet.cell(row=1, column=3).value = "Enterprise ID"
    sheet.cell(row=1, column=4).value = "Email ID"
    sheet.cell(row=1, column=5).value = "Meeting Minutes"
    sheet.cell(row=1, column=6).value = "Participant List"
    sheet.cell(row=1, column=7).value = "Follow-Up Meeting"

# Function to set focus (cursor)
def focus1(event):
    # set focus on the transcript_field box
    transcript_field.focus_set()

# Function to set focus
def focus2(event):
    # set focus on the eid_field box
    eid_field.focus_set()

# Function to set focus
def focus3(event):
    # set focus on the email_field box
    email_field.focus_set()

# Function to set focus
def focus4(event):
    # set focus on the minutes_field box
    minutes_field.focus_set()

# Function to set focus
def focus5(event):
    # set focus on the participants_field box
    participants_field.focus_set()

# Function to set focus
def focus6(event):
    # set focus on the followup_field box
    followup_field.focus_set()

# Function for clearing the
# contents of text entry boxes
def clear():
    # clear the content of text entry box
    title_field.delete(0, END)
    # transcript_field.delete(0, END)
    eid_field.delete(0, END)
    email_field.delete(0, END)
    # minutes_field.delete(0, END)
    # participants_field.delete(0, END)
    minutes_field.deselect()
    participants_field.deselect()
    followup_field.deselect()

# Function to take data from GUI
# window and write to an excel file
def insert():
    # if user not fill any entry
    # then print "empty input"
    if (title_field.get() == "" and
            textfile.get() == "" and
            eid_field.get() == "" and
            email_field.get() == ""):
        # minutes_field.get() == "" and
        # participants_field.get() == ""):

        print("empty input")

    else:

        # assigning the max row and max column
        # value upto which data is written
        # in an excel sheet to the variable
        current_row = sheet.max_row
        current_column = sheet.max_column

        # get method returns current text
        # as string which we write into
        # excel spreadsheet at particular location
        sheet.cell(row=current_row + 1, column=1).value = title_field.get()
        sheet.cell(row=current_row + 1, column=2).value = textfile
        sheet.cell(row=current_row + 1, column=3).value = eid_field.get()
        sheet.cell(row=current_row + 1, column=4).value = email_field.get()
        sheet.cell(row=current_row + 1, column=5).value = Checkbutton1.get()
        sheet.cell(row=current_row + 1, column=6).value = Checkbutton2.get()
        sheet.cell(row=current_row + 1, column=7).value = Checkbutton3.get()

        my_logic(textfile, Checkbutton1.get(), Checkbutton2.get(), Checkbutton3.get())

        # save the file
        wb.save('data.xlsx')

        # set focus on the name_field box
        title_field.focus_set()

        # call the clear() function
        clear()

# File Explorer to Upload File
def openFile():
    global textfile
    filename = filedialog.askopenfilename(initialdir="/", title="Upload File",
                                          filetypes=(("Text files", "*.txt"), ("all files", "*.*")))
    upload_label.configure(text="Uploaded: " + filename)
    file = open(filename, "r")
    tf = file.read()
    textfile = tf

    file.close()

# Driver code
if __name__ == "__main__":
    # create a GUI window
    root = Tk()

    # set the background colour of GUI window
    root.configure(background='lavender')

    # set the title of GUI window
    root.title("registration form")

    # set the configuration of GUI window
    root.geometry("1000x1000")

    excel()

    # create a Form label
    heading = Label(root, text="Meeting Manager", bg="lavender")

    # create a Meeting Title label
    title = Label(root, text="Meeting Title", bg="lavender")

    # create a Meeting Transcript label
    transcript = Label(root, text="Meeting Transcript", bg="lavender")

    # create a Enterprise ID label
    eid = Label(root, text="Enterprise ID", bg="lavender")

    # create a Email ID label
    email = Label(root, text="Email ID", bg="lavender")

    # create a Meeting Minutes label
    minutes = Label(root, text=" ", bg="lavender")

    # create a Participant List label
    participants = Label(root, text=" ", bg="lavender")

    # create a Follow-Up Meeting Label
    followup = Label(root, text=" ", bg="lavender")

    # Upload Label
    upload_label = Label(root, text="Upload Pending", bg="lavender")

    # saveButton = Button(root, text="Save Choices", width=20, height=2, command=savecheck)
    Checkbutton1 = IntVar()
    Checkbutton2 = IntVar()
    Checkbutton3 = IntVar()
    textfile = StringVar()

    # grid method is used for placing
    # the widgets at respective positions
    # in table like structure .
    heading.grid(row=0, column=1)
    title.grid(row=1, column=0)
    transcript.grid(row=2, column=0)
    eid.grid(row=3, column=0)
    email.grid(row=4, column=0)
    minutes.grid(row=5, column=0)
    # saveButton.grid(row=7, column=0)
    participants.grid(row=6, column=0)
    followup.grid(row=7, column=0)
    # saveButton.grid(row=7, column=1)
    upload_label.grid(row=14, column=1)

    # create a text entry box
    # for typing the information
    title_field = Entry(root)
    transcript_field = Button(root, text="Upload Transcript", command=openFile)
    eid_field = Entry(root)
    email_field = Entry(root)
    minutes_field = Checkbutton(root, text="Generate Meeting Minutes", variable=Checkbutton1, onvalue=1, offvalue=0,
                                height=2, width=10)
    participants_field = Checkbutton(root, text="Generate Participant List", variable=Checkbutton2, onvalue=1,
                                     offvalue=0, height=2, width=10)
    followup_field = Checkbutton(root, text="Schedule Follow-Up Meeting", variable=Checkbutton3, onvalue=1,
                                 offvalue=0, height=2, width=10)
    # bind method of widget is used for
    # the binding the function with the events

    # whenever the enter key is pressed
    # then call the focus1 function
    title_field.bind("<Return>", focus1)

    # whenever the enter key is pressed
    # then call the focus2 function
    transcript_field.bind("<Return>", focus2)

    # whenever the enter key is pressed
    # then call the focus5 function
    eid_field.bind("<Return>", focus3)

    # whenever the enter key is pressed
    # then call the focus3 function
    minutes_field.bind("<Return>", focus4)

    # whenever the enter key is pressed
    # then call the focus4 function
    participants_field.bind("<Return>", focus5)

    # whenever the enter key is pressed
    # then call the focus5 function
    followup_field.bind("<Return>", focus6)

    # grid method is used for placing
    # the widgets at respective positions
    # in table like structure.
    title_field.grid(row=1, column=1, ipadx="100")
    transcript_field.grid(row=2, column=1, ipadx="100")
    eid_field.grid(row=3, column=1, ipadx="100")
    email_field.grid(row=4, column=1, ipadx="100")
    minutes_field.grid(row=5, column=1, ipadx="100")
    participants_field.grid(row=6, column=1, ipadx="100")
    followup_field.grid(row=7, column=1, ipadx="100")

    # call excel function
    excel()

    # create a Submit Button and place into the root window
    submit = Button(root, text="Submit", fg="Black",
                    bg="light green", command=insert)
    submit.grid(row=8, column=1)

    # start the GUI
    root.mainloop()


# -*- coding: utf-8 -*-
# 函数形为y=kx+b ,leastsq
import numpy as np

import matplotlib.pyplot as plt
from scipy.optimize import leastsq

def readData(fileName):
    xcord=[]
    ycord=[]
    fr=open(fileName)
    for line in fr.readlines():
        lineArr = line.strip().split(',')
        xcord.append(float(lineArr[0]))
        ycord.append(float(lineArr[1]))

    return xcord,ycord

X_raw,Y_raw=readData("lsm_data.csv")

#y=k*x + b
def func(params,x):
    k,b=params
    return k*x+b

def error(params,x,y,s):
    print(s)
    return func(params,x)-y

init_params = [1,1];
###主函数从此开始###

#这里要用np.array
X=np.array(X_raw)
Y=np.array(Y_raw)

s="The number of iteration" #试验最小二乘法函数leastsq得调用几次error函数才能找到使得均方误差之和最小的k、b
Para=leastsq(error,init_params,args=(X,Y,s)) #把error函数中除了p以外的参数打包到args中
k,b=Para[0]
print("k="+str(k)+ ";b="+str(b))

#点图
plt.scatter(X_raw,Y_raw,s=30,c='red',marker='s')

#拟合线
x=np.linspace(100,240,20)
y=k*x+b
plt.plot(x,y,'b--')
plt.show()


#!/usr/bin/env python3
import argparse
import sys

from keras.models import Sequential
from keras.layers import Dense, Flatten

from ncaa_predict.data_loader import load_data_multiyear, N_PLAYERS, N_FEATURES
from ncaa_predict.util import list_arg

DEFAULT_BATCH_SIZE = 10000
DEFAULT_STEPS = sys.maxsize

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--batch_size",
        "-b",
        default=DEFAULT_BATCH_SIZE,
        type=int,
        help="The training batch size. Smaller numbers will train faster but "
        "may not converge. (default: %(default)s)",
    )
    parser.add_argument(
        "--model-out",
        "-o",
        default=None,
        help="File to save the model to. This will be an entire Keras model, "
        "which can be loaded and used without needing to keep track of the "
        "architecture. Warning: Keras will overwrite existing models. "
        "(default: don't save)",
    )
    parser.add_argument(
        "--steps",
        "-s",
        default=DEFAULT_STEPS,
        type=int,
        help="The maximum number of training steps. Note that you can stop "
        "training at any time and save the output with ctrl+c. (default: "
        "%(default)s)",
    )
    parser.add_argument(
        "--train-years",
        "-y",
        default=list(range(2002, 2017)),
        type=list_arg(type=int, container=frozenset),
        help="A comma-separated list of years to train on.",
    )
    args = parser.parse_args()

    model = Sequential(
        [
            Flatten(),
            Dense(16, activation="relu", kernel_regularizer="L1L2"),
            Dense(2, activation="softmax"),
        ]
    )
    model.compile(
        loss="categorical_crossentropy",
        optimizer="rmsprop",
        metrics=["accuracy", "AUC", "Precision", "Recall"],
    )

    features, labels = load_data_multiyear(args.train_years)
    try:
        model.fit(
            x=features,
            y=labels,
            batch_size=args.batch_size,
            epochs=args.steps // args.batch_size,
            shuffle=True,
            validation_split=0.1,
        )
    except KeyboardInterrupt:
        print("Stopped training due to keyboard interrupt")
    if args.model_out is not None:
        model.save(args.model_out)

    # Workaround for TensorFlow bug:
    # https://github.com/tensorflow/tensorflow/issues/3388
    import gc

    gc.collect()


"""
Functional tests for the Model Web API
"""
from base import FunctionalTestBase

from pprint import PrettyPrinter
pp = PrettyPrinter(indent=2)

class DistinctTests(FunctionalTestBase):
    def test_get_distinct(self):
        resp = self.testapp.get('/distinct')
        distinct = resp.json_body

        assert 'location' in [f['column'] for f in distinct]
        assert 'field_name' in [f['column'] for f in distinct]
        assert 'product_type' in [f['column'] for f in distinct]

        for v in [f['values'] for f in distinct]:
            assert len(v) > 0


from typing import List
class Solution:
    def maximalRectangle(self, matrix: List[List[str]]) -> int:
        if not matrix:
            return 0
        m = len(matrix)
        n = len(matrix[0])
        dp_u = [0] * n
        dp_l = [0] * n
        dp_r = [n] * n
        res = 0
        cur_left, cur_right = 0, n-1
        for i in range(m):
            for j in range(n):
                if matrix[i][j] == "0":
                    dp_u[j] = 0
                    dp_l[j] = 0
                    cur_left = j + 1
                else:
                    dp_u[j] += 1
                    dp_l[j] = max(cur_left, dp_l[j])
            for j in range(n-1, -1, -1):
                if matrix[i][j] == "0":
                    dp_r[j] = n
                    cur_right = j
                else:
                    dp_r[j] = min(cur_right, dp_r[j])
                    res = max(res, dp_u[j] * (dp_r[j] - dp_l[j]))
        return res

class Solution:
    # Get the maximum area in a histogram given its heights
    def leetcode84(self, heights):
        stack = [-1]
        maxarea = 0
        for i in range(len(heights)):

            while stack[-1] != -1 and heights[stack[-1]] >= heights[i]:
                maxarea = max(maxarea, heights[stack.pop()] * (i - stack[-1] - 1))
            stack.append(i)

        while stack[-1] != -1:
            maxarea = max(maxarea, heights[stack.pop()] * (len(heights) - stack[-1] - 1))
        return maxarea

    def maximalRectangle(self, matrix: List[List[str]]) -> int:
        if not matrix: return 0

        maxarea = 0
        dp = [0] * len(matrix[0])
        for i in range(len(matrix)):
            for j in range(len(matrix[0])):
                dp[j] = dp[j] + 1 if matrix[i][j] == '1' else 0
            maxarea = max(maxarea, self.leetcode84(dp))
        return maxarea

rec = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
print(Solution().maximalRectangle(rec))


from transitions import Machine
import random
import itertools
from loggers import dbot_online_logger
from dialogue_state.domain import is_intent_rule
import json
from path_config import  *
## non_branched fsa
class buy_tv_state(object):
    pass

intents = ["buy_tv","inform_size","inform_resolution","inform_brandname"]
states=["start",'how can i help you' ]+[str(n+1)+"after_"+u for n,u in enumerate(intents)]
#print(states)

def get_states_from_transitions(transtions):
    states = []
    for t in transtions:
        states.append(t['source'])
        states.append(t['dest'])
    return list(set(states))

def load_edge2rule_by_taskname(taskname):
    edgename2condition = None
    with open(fsm_edge_rule_config.format(taskname)) as json_file:
        edgename2condition = json.load(json_file)
    return edgename2condition

def load_state2action_by_taskname(taskname):
    with open(fsm_state_action_config.format(taskname)) as json_file:
        state_action_mapper = json.load(json_file)
    return state_action_mapper

def load_transition_by_taskname(taskname):
    with open(fsm_transition_config.format(taskname)) as json_file:
        transition = json.load(json_file).get("transitions")
    return transition

def load_fsm_config_by_taskname(taskname):
    transition = load_transition_by_taskname(taskname)
    edgename2condition = load_edge2rule_by_taskname(taskname)
    state_action_mapper = load_state2action_by_taskname(taskname)
    states = get_states_from_transitions(transition)
    return transition,states,edgename2condition,state_action_mapper

tv_transition = [
    { 'trigger': 'buy_tv', 'source': 'start', 'dest': '1after_buy_tv' },
    { 'trigger': 'inform_size', 'source': '1after_buy_tv', 'dest': '2after_inform_size' },
    { 'trigger': 'inform_resolution', 'source': '2after_inform_size', 'dest': '3after_inform_resolution' },
    { 'trigger': 'inform_brandname', 'source': '3after_inform_resolution', 'dest': '4after_inform_brandname' },
    { 'trigger': 'greet', 'source': 'start', 'dest': 'how can i help you' },
    { 'trigger': 'buy_tv2', 'source': 'how can i help you' , 'dest': '1after_buy_tv' },
]
for i,state in enumerate(states):
    if state == "3after_inform_resolution" or state == "4after_inform_brandname":
        continue
    d = { 'trigger': "all_filled_"+str(i), 'source': state, 'dest': '4after_inform_brandname' }
    tv_transition.append(d)

def ask_next_slot_task_fsm(slots,start_state='start',end_state = 'end',slot_unfilled_reask = True):
    '''
    ask next unfilled slot
    :param slots:
    :param start_state:
    :param end_state:
    :param slot_unfilled_reask:
    :return:
    '''
    transition = []
    states = []
    n = len(slots)
    for i in range(n):
        d = {'trigger': 'any unfilled', 'source': "ask_next_one" + str(i - 1), 'dest': "ask_next_one" + str(i)}
        if i == 0:
            d = {'trigger': 'any unfilled', 'source': start_state , 'dest': "ask_next_one" + str(i)}

        transition.append(d)
        states.append(d['source'])
        states.append(d['dest'])
    for s in states[:]:
        d = {'trigger': 'all filled', 'source': s, 'dest': end_state}
        transition.append(d)
    states.append(end_state)
    states = list(set(states))
    states.sort()
    return transition,states

def ask_next_buy_tv():
    slots =["size", "brandname", "resolution"]
    transition,states = ask_next_slot_task_fsm(["size", "brandname", "resolution"])
    edge2condition = {
        'any unfilled':['any unfilled'],
        'all filled':[slot + " filled" for slot in slots],
    }
    state_action_map = {
        'ask_next_one0': ['action_ask_next_slot'],
        'ask_next_one1': ['action_ask_next_slot'],
        'ask_next_one2': ['action_ask_next_slot'],
        'ask_next_one3': ['action_ask_next_slot'],
        'end': ["utter_tv_summary","utter_send_tv_order"]}
    return states, None, transition, edge2condition, state_action_map

def n_edges_with_affirm_task_fsm(slots):
    filled = "filled"
    filled = "已填充"
    unfilled = "unfilled"
    unfilled = "未填充"
    chinese_affirm = "向用户确认槽位{}的值"
    english_affirm = "ask user whether the slot {} is xxx"
    transition = []
    states = []
    n = len(slots)
    for slot_index,slot in enumerate(slots):
        condition = slot + " "+filled
        if slot_index == n-1:
            dest_state = "finish"
            continue
        else:
            next_slot= slots[slot_index+1]

            dest_state ="ask_" + next_slot
        d = {'trigger': condition+"{} unfilled".format(next_slot), 'source': "ask_" + slot, 'dest': dest_state}
        d2 = {'trigger': slot + " "+filled, 'source': "ask_" + slot, 'dest': english_affirm.format(slot)}
        transition.append(d)
        transition.append(d2)
        states.append(d['source'])
        states.append(d2['source'])
        states.append(d['dest'])
        states.append(d2['dest'])

    states = list(set(states))
    states.sort()
    return transition, states

def n_edges_task_fsm(slots,start_state='start',end_state = 'end',slot_unfilled_reask = True):
    '''
    n edges design
    in one turn,the agent can move more than one node
    :param slots:
    :param start_state:
    :param end_state:
    :param slot_unfilled_reask:if a slot is unfilled,ask again
    :return:
    '''
    transition = []
    states = []
    n = len(slots)
    # slot a to slot b
    for slot_index,slot in enumerate(slots):
        condition = slot + " filled"
        if slot_index == n-1:
            dest_state = "finish"
            continue
        else:
            next_slot= slots[slot_index+1]

            dest_state ="ask_" + next_slot
        d = {'trigger': condition, 'source': "ask_" + slot, 'dest': dest_state}
        transition.append(d)
        states.append(d['source'])
        states.append(d['dest'])
    # check slot is filled or not
    for slot_index, slot in enumerate(slots):
        condition = slot + " unfilled"
        d = {'trigger': condition, 'source': "ask_" + slot, 'dest': "ask_" + slot}
        transition.append(d)
        states.append(d['source'])
        states.append(d['dest'])
    d = {'trigger': "any unfilled or intent is buy tv", 'source': start_state, 'dest': "ask_" + slots[0]}
    states.append(d['source'])
    states.append(d['dest'])
    transition.append(d)
    d = {'trigger': "all filled", 'source': "ask_" + slots[-1], 'dest':end_state }
    states.append(d['source'])
    states.append(d['dest'])

    transition.append(d)
    states = list(set(states))
    states.sort()
    return transition, states

def unfilled_fsm_policy(slots,start_state='start',end_state = 'end',add_start2nodes = True,add_nodes2end = True):
    '''
    n *(n-1) edges design
    :param slots:
    :param start_state:
    :param end_state:
    :param add_start2nodes: unfill one slot then ask
    :param add_nodes2end:  if fill all , then finish
    :return:
    '''
    transition = []
    states = []
    n = len(slots)
    perms = list(itertools.permutations([int(i) for i in range(n)], 2))
    for perm in perms:
        end_i = perm[1]
        miss_slotname = slots[end_i]
        last_miss_slotname = slots[perm[0]]
        condition = miss_slotname + " unfilled"
        d = {'trigger':condition , 'source': "ask_"+last_miss_slotname, 'dest': "ask_"+miss_slotname}
        transition.append(d)
        states.append(d['source'])
        states.append(d['dest'])
    states = list(set(states))
    if add_nodes2end:
        for source_node in states:
            d = {'trigger': "all filled", 'source': source_node, 'dest': end_state}
            transition.append(d)
    if add_start2nodes:
        for end_node in states:
            slot = end_node.split("_")[-1]
            d = {'trigger': slot+" unfilled", 'source': start_state, 'dest': end_node}
            transition.append(d)
    states += [start_state,end_state]
    return transition,states

def edge_rule_maker(slots):
    '''
    unfilled form policy ,
    make the rules for every possible edge
    :param slots:
    :return: dict
    '''
    edge2rules_dict = {}
    for slot in slots:
        edge2rules_dict[slot+" unfilled"] = [slot+" unfilled"]
    edge2rules_dict['all filled'] = [slot + " filled" for slot in slots]
    return edge2rules_dict

def n_edges_rule_maker(slots):
    '''
    unfilled form policy ,
    make the rules for every possible edge
    :param slots:
    :return: dict
    '''
    edge2rules_dict = {}
    for slot in slots:
        edge2rules_dict[slot+" filled"] = [slot+" filled"]
    edge2rules_dict["any unfilled"] = ["any unfilled"]
    edge2rules_dict['all filled'] = [slot + " filled" for slot in slots]
    return edge2rules_dict

def merge_dict(dicts):
    '''
    merge multiple dicts into one dict
    :param dicts: list[dict]
    :return: dict
    '''
    new = dict()
    for d in dicts:
        for k,v in d.items():
            new[k] = v
    return new

def simulate_form_policy(slots):
    transition = []
    states = []
    n = len(slots)
    string = "".join([str(i) for i in range(n)])
    a = list(itertools.permutations(string, n))
    #print(a)
    ##[('0', '1', '2'), ('0', '2', '1'), ('1', '0', '2'), ('1', '2', '0'), ('2', '0', '1'), ('2', '1', '0')]
    for perm in a:
        for i,slot_index_str in enumerate(perm):
            slot_index = int(slot_index_str)
            cur_slot = slots[slot_index]
            source_state = "ask_"
            slot_i_s = list(perm[:i])
            slot_i_s = [int(j) for j in slot_i_s]
            slotnames = [slots[j] for j in slot_i_s]
            #source_state+="".join(list(perm[:i]))
            source_state+="_".join(slotnames)
            if source_state == "ask_":
                dest_state = source_state+ slots[slot_index]
            else:
                dest_state = source_state+"_"+ slots[slot_index]
            states.append(source_state)
            states.append(dest_state)
            d = {'trigger': cur_slot+" unfilled " , 'source': source_state, 'dest':dest_state }
            transition.append(d)
    states = list(set(states))+["end"]
    for perm in a:
        slot_i_s = list(perm[:])
        slot_i_s = [int(j) for j in slot_i_s]
        slot_i_s = [slots[j] for j in slot_i_s]
        slot_i_s_str = "_".join(slot_i_s)
        for s in states:
            if slot_i_s_str in s:
                d = {'trigger': " all filled ", 'source': s, 'dest': "end"}
                transition.append(d)
    for state in states:
        if state!="end":
            d = {'trigger': " all filled ", 'source': state, 'dest': "end"}
            if d not in transition:
                transition.append(d)
    return transition,states

def reminder_data():
    transition ,states = unfilled_fsm_policy(["date","time","event"],end_state="end_add_new_event")
    d = {'trigger': 'intent is ask_reminder', 'source': 'start', 'dest': 'end_search_event'}
    transition.append(d)
    states += ['end_search_event']
    edgename2condition = edge_rule_maker(["date","time","event"])
    edgename2condition['intent is ask_reminder'] = ['intent is ask_reminder']
    state_action_map = {
        'ask_date': ["utter_ask_newevent_date"],
        'ask_time': ['utter_ask_newevent_time'],
        'ask_event': ["utter_ask_event"],
        'end_add_new_event': ["action_set_reminder"],
        'end_search_event':["action_report_event"]
    }
    return states, get_transition_data(transition), transition, edgename2condition, state_action_map

def n_edges_tv_data():
    form_policy, states = n_edges_task_fsm(["size", "brandname", "resolution"])
    edge2condition = n_edges_rule_maker(["size", "brandname", "resolution"])
    state_action_map = {
        'ask_brandname': ["utter_list_brand","utter_ask_brand"],
        'ask_resolution': ['utter_ask_resolution'],
        'ask_size': ["utter_list_size","utter_ask_size"],
        'end': ["utter_tv_summary","utter_send_tv_order"]}
    return states, get_transition_data(form_policy), form_policy, edge2condition, state_action_map

def new_tv_data():
    form_policy, states = unfilled_fsm_policy(["size", "brandname", "resolution"])
    edgename2condition = {'size unfilled': ['size unfilled'],
                          'brandname unfilled': ['brandname unfilled'],
                          'resolution unfilled': ['resolution unfilled'],
                          'all filled': ['size filled', 'brandname filled', 'resolution filled']}
    state_action_map = {
        'ask_brandname': ["utter_list_brand","utter_ask_brand"],
        'ask_resolution': ['utter_ask_resolution'],
        'ask_size': ["utter_list_size","utter_ask_size"],
        'end': ["utter_tv_summary","utter_send_tv_order"]}
    return states, get_transition_data(form_policy), form_policy, edgename2condition, state_action_map

def tv_data():
    form_policy, states = simulate_form_policy(["size", "brand", "resolution"])
    #print({k["trigger"]:[] for k in form_policy})
    edgename2condition = {'size unfilled ': ['size unfilled'],
                          'brand unfilled ': ['brandname unfilled'],
                          'resolution unfilled ': ['resolution unfilled'],
                          ' all filled ': ['size filled','brandname filled','resolution filled']}
    #print({k: [] for k in states})

    state_action_map = {
        'ask_size_brand_resolution': ['utter_ask_resolution'],
        'ask_brand': ["utter_list_brand","utter_ask_brand"],
        'ask_size_brand': ["utter_list_brand","utter_ask_brand"],
        'ask_resolution': ['utter_ask_resolution'],
        'ask_resolution_brand': ["utter_list_brand","utter_ask_brand"],
        'ask_resolution_brand_size': ["utter_list_size","utter_ask_size"],
        'ask_resolution_size': ["utter_list_size","utter_ask_size"],
        'ask_size_resolution_brand': ["utter_list_brand","utter_ask_brand"],
        'ask_brand_resolution': ['utter_ask_resolution'],
        'ask_resolution_size_brand': ["utter_list_brand","utter_ask_brand"],
        'ask_brand_size': ["utter_list_size","utter_ask_size"],
        'ask_size': ["utter_list_size","utter_ask_size"],
        'ask_size_resolution': ['utter_ask_resolution'],
        'ask_brand_resolution_size': ["utter_list_size","utter_ask_size"],
        'ask_brand_size_resolution': ['utter_ask_resolution'],
        'end': ["utter_tv_summary","utter_send_tv_order"]}

    return states,get_transition_data(form_policy) ,form_policy,edgename2condition,state_action_map

#tv_data()
#form_policy ,states = simulate_form_policy(["size","brand","resolution"])
condition2edge_name = dict()

## edge name --> rule set

edgename2condition = {
    "buy_tv":["size unfilled"],
    "greet":["intent is greet"],
    "buy_tv2":["size unfilled"],
    "inform_size":["resolution unfilled"],
    "inform_resolution":["brandname unfilled"],
    "inform_brandname":["size filled","resolution filled","brandname filled"],
}
state_action_map ={
    'how can i help you':["utter_offer_help"],
    "1after_buy_tv":["utter_list_size","utter_ask_size"],
    "2after_inform_size":["utter_receive_size","utter_ask_resolution"],
    "3after_inform_resolution":["utter_receive_resolution","utter_list_brand","utter_ask_brand"],
    "4after_inform_brandname":["utter_receive_brand","utter_tv_summary","utter_send_tv_order"],
}

def export_js_code(transition):
    datas = []
    for row in transition:
        start,end,edge = row["source"],row["dest"],row["trigger"]
        code = "g.setEdge(\""+ start+"\", \""+ end+"\", {label: \""+ edge+"\"});"
        #print(code)
        datas.append(code)
        #print(code)
    return (datas)

def get_transition_data(transition):
    datas = []
    for row in transition:
        start,end,edge = row["source"],row["dest"],row["trigger"]
        code = "g.setEdge(\""+ start+"\", \""+ end+"\", {label: \""+ edge+"\"});"
        data = [start,end,edge]
        datas.append(data)
        #print(code)
    return datas
# export_js_code(form_policy)
# print(states)

def cam_rest_data():
    '''
    开发人员读取预定义  fsm配置文件
    :return:
    '''

    transition = load_transition_by_taskname('camrest')
    states = get_states_from_transitions(transition)
    edgename2condition = load_edge2rule_by_taskname('camrest')
    state_action_map = load_state2action_by_taskname('camrest')
    return states, transition, edgename2condition, state_action_map

def weather_fsm_data():
    '''
    transition ,states,state-utters mapper,
    :return:
    '''
    states = []
    transition =load_transition_by_taskname('weather')

    states = get_states_from_transitions(transition)
    edgename2condition = load_edge2rule_by_taskname('weather')
    state_action_map = load_state2action_by_taskname('weather')

    return states,get_transition_data(transition),transition,edgename2condition,state_action_map
# print("----------------")
# weather_fsm_data()
# print("----------------")
class Fsm():
    def __init__(self,task):
        self.task = task
        states, data, transition, edgename2condition, state_action_map = 0,0,0,0,0
        if self.task == "buy_tv":
            states, data, transition, edgename2condition, state_action_map = ask_next_buy_tv()
            self.start_node = 'start'
        elif self.task == "camrest":
            states, transition, edgename2condition, state_action_map = cam_rest_data()
            self.start_node = 'state_ask_area'
        elif self.task == "weather":
        #states, data, transition, edgename2condition, state_action_map = weather_fsm_data()
            states, data, transition, edgename2condition, state_action_map = weather_fsm_data()
            self.start_node = 'start'
        elif self.task == "reminder":
            states, data, transition, edgename2condition, state_action_map = reminder_data()
            self.start_node = 'start'
        else:
            states, data, transition, edgename2condition, state_action_map = new_tv_data()
        # Initialize
        self.end_node = "4after_inform_brandname"

        self.buy_tv_task = buy_tv_state()
        self.transitions = transition
        self.states = states
        self.machine = Machine(self.buy_tv_task, states=self.states, transitions=self.transitions, initial=self.start_node)
        self.edgename2condition = edgename2condition
        self.state_action_map = state_action_map

    def return_start_node(self):
        self.set_current_state(self.start_node)

    def is_start_node(self):
        return self.current_state()==self.start_node

    def is_end_node(self,node):
        if node in ["1all filled","2all filled","end","end_search_event","end_add_new_event"]:
            return True
        return False

    def current_state(self):
        return self.buy_tv_task.state

    def set_current_state(self,state):
        self.buy_tv_task.state = state

    def is_current_state_end(self):
        return self.is_end_node(self.buy_tv_task.state)
    @staticmethod
    def get_edges_from_starting_state(transitions,start):
        ends = []
        for tran in transitions:
            if tran["source"] == start:
                ends.append(tran["trigger"])
        return  list(set(ends))

    def predict(self,edge_condition):
        if not edge_condition:
            dbot_online_logger.debug("there are not any edges")
            s = self.buy_tv_task.state
            return self.state_action_map.get(s)
        self.buy_tv_task.trigger(edge_condition)
        s = self.buy_tv_task.state
        dbot_online_logger.debug("current state is {}".format(s))
        return self.state_action_map.get(s)

    def get_matched_condition_edge(self,domain):
        if self.is_current_state_end():
            self.return_start_node()
        dest = []
        ends = Fsm.get_edges_from_starting_state(self.transitions,self.buy_tv_task.state)
        print("next step you can reach ",",".join(ends))
        for key in self.edgename2condition.keys():
            if key not in ends:
                #print(key , "not in dests ")
                continue
                #print(key, " in dests ")
            ruleset = self.edgename2condition[key]
            #print(ruleset)
            if domain.rule_set_evaluate(ruleset):
                dest.append(key)
        if len(dest)>1:
            for key in dest:
                ruleset = self.edgename2condition[key]
                for rule in ruleset:
                    if is_intent_rule(rule):
                        return key
            #print("your nlu condition matches {} edges".format(len(dest)))
            return dest[0]
        elif len(dest)==1:
            return dest[0]
        #print("your nlu condition does not match any edge with condition")
        return None

# F = Fsm()
# r = F.machine.get_transitions(source="start")
# print(r)
#
#


import logging

from cubicweb_francearchives.dataimport import es_bulk_index

from cubicweb_elasticsearch.es import get_connection

def get_es_connection(cnx, index_name, log):
    es = get_connection(
        {
            "elasticsearch-locations": cnx.vreg.config["elasticsearch-locations"],
            "index-name": index_name,
            "elasticsearch-verify-certs": cnx.vreg.config["elasticsearch-verify-certs"],
            "elasticsearch-ssl-show-warn": cnx.vreg.config["elasticsearch-ssl-show-warn"],
        }
    )
    if es:
        return es
    if log:
        log.error("-> no es connection.abort")
    else:
        print("-> no es connection.abort")

def delete_autority_from_es(cnx, eids, log=None):
    """Delete authorities from all es indexes"""

    def docs_to_delete(es, eids, index_name):
        if log:
            log.info("es [%s]: deleting %s", index_name, eids)
        else:
            print(f"es [{index_name}]: deleting {eids}")
        for eid in eids:
            yield {
                "_op_type": "delete",
                "_index": index_name,
                "_type": "_doc",
                "_id": eid,
            }

    config = cnx.vreg.config
    indexes = [f"{config['index-name']}_suggest"]
    if config.get("published-index-name"):  # only in cms
        indexes.append(f"{config['published-index-name']}_suggest")
    if config["enable-kibana-indexes"]:
        indexes.append(config["kibana-authorities-index-name"])
    for index_name in indexes:
        es = get_es_connection(cnx, index_name, log)
        if not es:
            return
        es_docs = docs_to_delete(es, eids, index_name)
        es_bulk_index(es, es_docs, raise_on_error=False)

def update_index_mapping(cnx, index_name, mapping, log=None):
    if not log:
        log = logging.getLogger("update_index_mapping")
    es = get_es_connection(cnx, index_name, log)
    es.indices.put_mapping(index=index_name, body=mapping, doc_type="_doc", include_type_name=True)