from llm.openai.model import OpenAIModel
import time
import json
import os
from typing import Optional
from parse import parse_json, flatten

def start_history(system_seed: str, user_seed: str, path: str = "./llm/openai/chat_history.json") -> Optional[int]:
    if os.path.exists(path):
        return None

    print(f"\n\033[33mCreating a new chat history at {path}\033[0m")
    with open(path, 'w') as file:
        json.dump([{"role": "system", "content": system_seed},{"role": "user", "content": user_seed}], file)

    print(f"\n\033[32mCreated a new chat history at {path}\033[0m")

    return 1

def destroy_history(path: str = "./llm/openai/chat_history.json") -> None:
    if os.path.exists(path):
        os.remove(path)
        print(f"\n\033[32mSuccessfully removed chat history at {path}\033[0m")
        return None

    print(f"\n\033[33mNo chat history exists at {path}\033[0m")
    return None

def read_history(path: str = "./llm/openai/chat_history.json") -> Optional[list]:
    if not os.path.exists(path):
        print(f"\n\033[31mNo chat history at {path}\033[0m")
        return None

    with open(path, 'r') as file:
        return json.load(file)

def append_history(messages: list, path: str = "./llm/openai/chat_history.json") -> None:
    chat_history: list = read_history()
    if not chat_history:
        print(f"\n\033[31mFailed to read the chat history at {path}\033[0m")
        return None

    chat_history.extend(messages)

    with open(path, 'w') as file:
        json.dump(chat_history, file)
        return None

def chat(new_message: str, role: str = "user") -> Optional[str]:

    llm = OpenAIModel()

    if not start_history(system_seed="You are an assistant and will answer any questions asked of you", user_seed=new_message):
        append_history([{"role": role, "content": new_message}])

    history = read_history()

    response = llm.get_chat_response(history)

    assistant_response = flatten(parse_json(response, "content"))[0]

    append_history([{"role": "assistant", "content": assistant_response}])

    return assistant_response


import numpy as np
from numpy import nan
from numpy.linalg import norm as norm
import matplotlib.pyplot as plt
import time
import pinocchio as pin
import tsid
import gepetto.corbaserver
import subprocess
import os
from example_robot_data.robots_loader import getModelPath
from pinocchio.robot_wrapper import RobotWrapper
from mat4py import loadmat
import math
from IPython import embed
import sys

import plotly.graph_objects as go

#Fichiers perso
import load #fichier load.py
import marches
import read_data_kinematics
import read_data_moments

###### DEFINITIONS DE FONCTIONS ######

def degrees2radians(degrees):
    return degrees*math.pi/180

def radians2degrees(radians):
    return radians*180/math.pi

####### FIN DE DEFINITION DE FONCTION ######

######################################################################### READ DATA (kinematics, moments, events) ##########################################################################################

studied_walk=1

# PATH & URD
path = os.path.dirname(os.path.realpath(__file__))
urdf = path + '/urdf_augmented.urdf'

## Read data
data_kinematics= read_data_kinematics.read_data(path+"/Données_marche/fichiers txt/marche sans attelle "+str(studied_walk)+".txt", path + "/Données_marche/fichiers txt/marche sans attelle "+str(studied_walk)+".csv")
right=[data_kinematics.hip_flexion_r, data_kinematics.knee_angle_r, data_kinematics.ankle_angle_r]
left=[data_kinematics.hip_flexion_l, data_kinematics.knee_angle_l, data_kinematics.ankle_angle_l]

#Read Moments
data_moment=read_data_moments.read_data_moments(path + "/Données_marche/InverseDynamics/résultats sto & txt/marche sans attelle "+str(studied_walk)+".txt",path + "/Données_marche/InverseDynamics/résultats sto & txt/marche sans attelle "+str(studied_walk)+".csv")
right_moments=[data_moment.hip_flexion_r_moment, data_moment.knee_angle_r_moment, data_moment.ankle_angle_r_moment]
left_moments=[data_moment.hip_flexion_l_moment, data_moment.knee_angle_l_moment, data_moment.ankle_angle_l_moment]

#Walk construction
marche=marches.Marche('marche'+str(studied_walk),data_kinematics.time,left,right,data_moment.time,left_moments,right_moments)

#Read events
path_events= path + "/Données_marche/dataEvents/"
events= loadmat(path_events+'marche sans attelle '+str(studied_walk)+'Events.mat')
marche.toesoff(data_kinematics.time,events["Left_Foot_Off"],events["Right_Foot_Off"])
marche.heelstrike(data_kinematics.time,events["Left_Foot_Strike"],events["Right_Foot_Strike"])
#marche.printMarche() #print l'ensemble des données de la marche
#print('Heel strike', marche.heelstrike_right)
#Read FirstFoot
firstFoot=marche.firstFoot()

#delay = 255 * 0.005
delay = 0

t_hs_left = np.array(marche.heelstrike_left) - delay
t_hs_left = np.append(t_hs_left, np.zeros(1))
#print(t_hs_left)
i_hs_left = 0

t_hs_right = np.array(marche.heelstrike_right) - delay
t_hs_right = np.append(t_hs_right, np.zeros(1))
#print(t_hs_right)
i_hs_right = 0

t_to_left = np.array(marche.toesoff_left) - delay
t_to_left = np.append(t_to_left, np.zeros(1))
#print(t_to_left)
i_to_left = 0

t_to_right = np.array(marche.toesoff_right) - delay
t_to_right = np.concatenate((np.array([0.18]), t_to_right, np.zeros(1)))
#print(t_to_right)
i_to_right = 0

to_left_list = []
to_right_list = []
hs_left_list = []
hs_right_list = []
for i, t_event in enumerate(data_kinematics.time):
    print(t_event)
    if (t_hs_left[i_hs_left]<=t_event<t_hs_left[i_hs_left]+0.005):
        hs_left_list.append(i)
        i_hs_left += 1
    if (t_hs_right[i_hs_right]<=t_event<t_hs_right[i_hs_right]+0.005):
        hs_right_list.append(i)
        i_hs_right += 1
    if (t_to_left[i_to_left]<=t_event<t_to_left[i_to_left]+0.005):
        to_left_list.append(i)
        i_to_left += 1
    if (t_to_right[i_to_right]<=t_event<t_to_right[i_to_right]+0.005):
        to_right_list.append(i)
        i_to_right += 1

#Read markers
data_markers=loadmat(path + "/Données_marche/markers_data_patho.mat")
data_markers=data_markers['output']['marker_data']['Markers']
#print(data_markers.keys())

RLM = 1e-3 * np.array(data_markers['RLM']) # /!\ l'ordre du repère est -y, x, z
LLM = 1e-3 * np.array(data_markers['LLM']) # /!\ l'ordre du repère est -y, x, z

RGT = 1e-3 * np.array(data_markers['RGT']) # /!\ l'ordre du repère est -y, x, z
LGT = 1e-3 * np.array(data_markers['LGT']) # /!\ l'ordre du repère est -y, x, z

RASIS = 1e-3 * np.array(data_markers['RASIS']) # /!\ l'ordre du repère est -y, x, z
LASIS = 1e-3 * np.array(data_markers['LASIS']) # /!\ l'ordre du repère est -y, x, z

RPSIS = 1e-3 * np.array(data_markers['RPSIS']) # /!\ l'ordre du repère est -y, x, z
LPSIS = 1e-3 * np.array(data_markers['LPSIS']) # /!\ l'ordre du repère est -y, x, z

x_com = (1/4) * (RASIS[:,1] + LASIS[:,1] + RPSIS[:,1] + LPSIS[:,1])
y_com = -(1/4) * (RASIS[:,0] + LASIS[:,0] + RPSIS[:,0] + LPSIS[:,0])
z_com = (1/4) * (RASIS[:,2] + LASIS[:,2] + RPSIS[:,2] + LPSIS[:,2])

trace_right_foot = go.Scatter3d(x=RLM[:,1], y=-RLM[:,0], z=RLM[:,2],
                                   mode='lines', name= 'Right Foot')
trace_left_foot = go.Scatter3d(x=LLM[:,1], y=-LLM[:,0], z=LLM[:,2],
                                   mode='lines', name= 'Left Foot')
trace_com = go.Scatter3d(x=x_com, y=y_com, z=z_com,
                                   mode='lines', name= 'CoM')

x_start = [RLM[0,1], LLM[0,1], x_com[0]]
y_start = [-RLM[0,0], -LLM[0,0], y_com[0]]
z_start = [RLM[0,2], LLM[0,2], z_com[0]]

#x_start = [RLM[0,1], LLM[0,1]]
#y_start = [-RLM[0,0], -LLM[0,0]]
#z_start = [RLM[0,2], LLM[0,2]]

x_hs = []
y_hs = []
z_hs = []
for iter in (hs_right_list):
    x_hs.append(RLM[iter, 1])
    y_hs.append(-RLM[iter, 0])
    z_hs.append(RLM[iter, 2])
for iter in (hs_left_list):
    x_hs.append(LLM[iter, 1])
    y_hs.append(-LLM[iter, 0])
    z_hs.append(LLM[iter, 2])

x_to = []
y_to = []
z_to = []
for iter in (to_right_list):
    x_to.append(RLM[iter, 1])
    y_to.append(-RLM[iter, 0])
    z_to.append(RLM[iter, 2])
for iter in (to_left_list):
    x_to.append(LLM[iter, 1])
    y_to.append(-LLM[iter, 0])
    z_to.append(LLM[iter, 2])

trace_start = go.Scatter3d(x=x_start, y=y_start, z=z_start,
                                   mode='markers', name= 'Start')

trace_heel_strike = go.Scatter3d(x=x_hs, y=y_hs, z=z_hs,
                                   mode='markers', name= 'Heel Strike')

trace_toes_off = go.Scatter3d(x=x_to, y=y_to, z=z_to,
                                   mode='markers', name= 'Toes Off')

name = 'eye = (x:0., y:2.5, z:0.)'
camera = dict(
    up=dict(x=0, y=0., z=1.),
    eye=dict(x=0, y=-3, z=0.3),
    center=dict(x=0, y=0., z=-0.5)
)

#fig = go.Figure(data=[trace_right_foot, trace_left_foot, trace_start, trace_heel_strike, trace_toes_off])
fig = go.Figure(data=[trace_right_foot, trace_left_foot, trace_com, trace_start, trace_heel_strike, trace_toes_off])
fig.update_layout(scene_aspectmode='manual',
                  scene_aspectratio=dict(x=2, y=1, z=1), scene_camera=camera, legend=dict(font=dict(size=20), yanchor="top",
    y=0.8,
    xanchor="right",
    x=0.75)) #, xaxis = dict(tickfont = dict(size=20)), yaxis = dict(tickfont = dict(size=20)))
fig.update_yaxes(tickfont=dict(size=50))
fig.update_traces(marker=dict(size=3))
fig.show()


'''В файле task6/en-ru.txt находятся строки англо-русского словаря в таком формате:

cat - кошка
dog - собака
home - домашняя папка, дом
mouse - мышь, манипулятор мышь
to do - делать, изготавливать
to make - изготавливать
Здесь английское слово (выражение) и список русских слов (выражений) разделены двумя табуляциями и минусом: '\t-\t'.

Требуется создать русско-английский словарь и вывести его в файл ru-en.txt в таком формате:

делать - to do
дом - home
домашняя папка - home
изготавливать - to do, to make
кошка - cat
манипулятор мышь - mouse
мышь - mouse
собака - dog
Порядок строк в выходном файле должен быть словарным с человеческой точки зрения (так называемый лексикографический порядок слов). То есть выходные строки нужно отсортировать.'''

left = set() #чтобы слова не повторялись
dictionary = {}

# чтение из файла
with open('en-ru7.txt', encoding='utf-8') as f:
    for line in f:
        line = line.split('\t-\t')
        line[1] = line[1].strip(',=\n-')
        left.add(line[1])
        dictionary[line[1]] = line[0]

# преобразование в массив и сортировка
right = list(left)
right = sorted(right)

# убрал какой то мусор
for i in range(len(right)):
    if right[i] == 'Авадон':
        right = right[i:]
        break

# запись в файл
with open('ru-en7.txt', 'a', encoding='utf-8') as r:
    for rus in right:
        s =  rus + '\t-\t' + dictionary[rus] + '\n'
        r.write(s)


import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np

## Scroll down for the part where your code belongs

class Dataset():
    def __init__(self, n_items, config={}):
        'Initialization'
        default = {
            "seed":0,
            "size":(14,14),
            "channels":1,
            "square_size":(2,2)
        }
        config = {**default,**config}
        self.config = config
        self.n_items = n_items
        self.list_IDs, self.labels, self.seeds = self.__gen_init__()

    def __len__(self):
        'Denotes the total number of samples'
        return len(self.list_IDs)

    def __getitem__(self, index):
        'Generates one sample of data'
        # Select sample
        ID = self.list_IDs[index]

        # Load data and get label
        X, y = self.__gen_sample__(ID)
        return X, y

    def __gen_init__(self):
        'Generates the init data'
        ids = list(range(self.n_items))
        ids = {i:i for i in ids}
        lbs = {i:i for i in ids}
        seeds = np.random.uniform(size=self.n_items)
        seeds = {i:seeds[i] for i in ids}
        return ids, lbs, seeds

    def __gen_sample__(self, ID):
        'Generates a single sample'
        # generate size

        # generate y
        dh = np.random.randint(
            self.config["square_size"][0],
            self.config["square_size"][1]+1
        )
        dw = np.random.randint(
            self.config["square_size"][0],
            self.config["square_size"][1]+1
        )
        h, w = self.config["size"]
        px = int(dw + (w - 2*dw) * int(str(self.seeds[ID])[2:4])/100)
        py = int(dh + (h - 2*dh) * int(str(self.seeds[ID])[4:6])/100)
        # generate X
        X = np.random.rand(*[h, w])*0.9
        X[py:py+dh, px:px+dw] = 1.0
        y = [1, (px+dw/2)/w, (py+dh/2)/h, dw/w, dh/h]
        return X, y

def plot_image(X, y, ax=None):
    if ax is None:
        fig, ax = plt.subplots()
    # plot image
    ax.imshow(X, cmap="gray")
    ax.set_aspect(1)
    ax.set_yticks([i-0.5 for i in range(X.shape[0])], minor='True')
    ax.set_xticks([i-0.5 for i in range(X.shape[1])], minor='True')
    ax.yaxis.grid(True, which='minor')
    ax.xaxis.grid(True, which='minor')
    # plot y
    ax.axvline(x=y[1]*X.shape[1]-0.5, c="r")
    ax.axhline(y=y[2]*X.shape[0]-0.5, c="r")
    return ax

######################################
# YOUR CODE GOES HERE
######################################


# to run script: `sudo python3 led.py`
#
# written by Boris Yakubchik
#
# Edit these:

NUM_OF_LED = 144
BRIGHTNESS = 0.2 # maximum 1 -- best when 1/n is an integer
PIANO_STARTS_WITH = 'B2'

# =========================================================
# DO NOT EDIT BELOW

from time import sleep
from time import time
import math
import threading

import board
import neopixel

import mido

import keyboard

pixels = neopixel.NeoPixel(board.D18, NUM_OF_LED, brightness=BRIGHTNESS, auto_write=False)

devices = mido.get_input_names()
piano = []

for device in devices:
  if device.startswith(PIANO_STARTS_WITH):
    piano.append(device)

if len(piano) == 0:
  print('\nIs the piano connected / turned on?\n')
  quit()
else:
  print('Listening for MIDI from', piano[0])

# =======================================================================
# Variables

# array for all BLOBS
all_blobs = {}

min_bright = math.ceil(1 / BRIGHTNESS)

# array for pixel color computation - to be written to the LED strip later
rgb = [1] * NUM_OF_LED # fill all of them with 1

# to throttle keyboard events
throttle_left = 0
throttle_right = 0
throttle_f12 = 0

# each Blob is a key pressed that evolves over time via its `update` method
class Blob:
  def __init__(self, x, r, v, s):
    self.x = x # x - location on x axis
    self.r = r # radius
    self.v = v # value == brightness
    self.s = s # status: `down`, `legato`, or `decay`

  def update(self):
    if self.s == 'down' or self.s == 'legato':
      self.r = min(self.r + 1, 5)
      self.v = math.floor(self.v * 0.98)
    else:
      self.r = self.r + 1
      self.v = math.floor(self.v * 0.75) # dim it

def add_note_to_workspace(key, velocity):
  all_blobs[key] = Blob(map_key_to_x(key), 1, velocity, 'down')

def thread_function(name):
  while True:

    global rgb

    # print(len(all_blobs)) # to check that blobs disappear after some time

    rgb = [min_bright] * NUM_OF_LED # reset array to min

    for blob_key in all_blobs:

      blob = all_blobs[blob_key]

      blob.update()

      for x in range(math.floor(blob.x - blob.r), math.ceil(blob.x + blob.r)):

        if (x >= 0 and x < NUM_OF_LED):
          scaler = (1 - abs(blob.x - x) / blob.r) ** 2
          rgb[x] = min(rgb[x] + scaler * blob.v, 255) # never let it go above 255
                                           # this can happen because we add many blobs together

    for idx, val in enumerate(rgb):
      # make sure these are integers
      pixels[idx] = (math.floor(val), math.floor(val), math.floor(val))

    pixels.show()

    sleep(0.05)

    to_delete = []

    # only keep blobs that are above brightness of 1
    for blob_key in all_blobs:
      if all_blobs[blob_key].v < 2:
        to_delete.append(blob_key)

    for key in to_delete:
      all_blobs.pop(key)

thread = threading.Thread(target=thread_function, args=(1,))
thread.start()

legato_pedal = 0 # 0 - not pressed, 1 - pressed

def unlegato_all_keys():
  for key in all_blobs:
    if all_blobs[key].s == 'legato':
      all_blobs[key].s = 'decay'

def handle_pedal(pedal, value):
  global legato_pedal
  if pedal == 67:
    throttle_key('left')
  elif pedal == 66:
    throttle_key('right')
  elif pedal == 64:
    if legato_pedal == 0 and value != 0:
      legato_pedal = 1
      print('legato ON')
    if value == 0:
      legato_pedal = 0
      print('legato OFF')
      unlegato_all_keys()

  else:
    print('unknown!')
    print(msg)

def throttle_key(key):
  global throttle_left
  global throttle_right
  global throttle_f12
  now = time()

  if key == 'left':

    if now < throttle_right + 1 and now > throttle_f12 + 0.5:
      throttle_f12 = now
      keyboard.press_and_release('f12')
    elif now > throttle_left + 0.5:
      throttle_left = now
      keyboard.press_and_release(key)

  elif key == 'right':

    if now < throttle_left + 1 and now > throttle_f12 + 0.5:
      throttle_f12 = now
      keyboard.press_and_release('f12')
    elif now > throttle_right + 0.5:
      throttle_right = now
      keyboard.press_and_release(key)

# takes raw key (21 - 108) and returns x coordinate
def map_key_to_x(key):
  # 65 = center between 21 and 108
  # 72 = NUM_OF_LEDS / 2 + fudge factor
  return (key - 65) * 2 + 72

with mido.open_input(piano[0]) as inport:
  for msg in inport:
    # print(msg)
    if hasattr(msg, 'velocity'):
      # print(msg.velocity)
      if msg.velocity == 64: # represents key-up velocity
        if msg.note in all_blobs: # key may have decayed and been removed already
          if legato_pedal == 1:
            all_blobs[msg.note].s = 'legato'
          else:
            all_blobs[msg.note].s = 'decay'
      else:
        add_note_to_workspace(msg.note, msg.velocity)

    elif hasattr(msg, 'control'):
      # pedal numbers 64, 65, 66
      handle_pedal(msg.control, msg.value)

    else:
      pring('something new and unknown!')
      print(msg)


def judge(val):
    # スコアvalで達成できるかどうか
    length = 0
    count = 0
    for i in range(N):
        if i == 0:
            length += A[0]
        else:
            length += A[i]  - A[i-1]
        if length >= val:
            count += 1
            length = 0
        if count == K:
            if L - A[i] >= val:
                return True
            else:
                return False
    return False

N ,L = map(int, input().split())
K = int(input())
A = list(map(int, input().split()))

ok = 0
ng = L
while(ng  -ok > 1):
    mid = (ok + ng) //2
    if judge(mid):
        ok = mid
    else:
        ng = mid

print(ok)


"""Sample behavior."""

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

import memory
import time
import numpy as np
import math
import core
import pose
import head
import commands
import cfgstiff
from task import Task
from state_machine import Node, C, T, S, LoopingStateMachine, StateMachine, EventNode, Event, NegationEvent

class GetReady(Node):
  def __init__(self):
    super(GetReady, self).__init__()
    memory.planning.coverageStarted = False
    # memory.planning.planningIdx = 0
    # memory.planning.nodesLeft = memory.planning.nodesInPath
    # memory.planning.RestartPath()

  def run(self):
    commands.stand()
    commands.setHeadPanTilt(0.0,0.0,1.5)
    if self.getTime() > 4.5:
      location = memory.planning.getDestPose()
#      print("[%f,%f,%f]" % (location.translation.x, location.translation.y, location.rotation))
      self.finish()

class FollowPath(Node):
  """Face the ball"""
  def __init__(self, robot):
    super(FollowPath, self).__init__()
    memory.planning.coverageStarted = True
    self.destloc = memory.planning.getDestPose()
    self.pathidx = memory.planning.pathIdx
    self.robot = robot
    self.k_x = (0.002, 0.005, 0.000)
    self.k_y = (0.002, 0.005, 0.000)
    self.k_t = (0.7, 0.01, 0.1)
    # self.k_t = (0.008, 0.01, 0.2)
    self.x_int = 0.0
    self.y_int = 0.0
    self.t_int = 0.0
    self.x_prev = 0.0
    self.y_prev = 0.0
    self.t_prev = 0.0
    self.id_prev = self.pathidx
    self.tkm1 = time.clock()
    self.tk = time.clock()
    self.listy_thing = [core.LHipYawPitch, core.LHipRoll, core.LHipPitch, core.LKneePitch, core.LAnklePitch, core.LAnkleRoll, core.RHipYawPitch, core.RHipRoll, core.RHipPitch, core.RKneePitch, core.RAnklePitch, core.RAnkleRoll]

  def calc_int(self, e_x, e_y, e_t, dt):
    self.x_int = self.x_int + dt*e_x
    self.y_int = self.y_int + dt*e_y
    self.t_int = self.t_int + dt*e_t
    if abs(self.x_int) >= 35.0:
      self.x_int = 35.0*np.sign(self.x_int)
    if abs(self.y_int) >= 35.0:
      self.y_int = 35.0*np.sign(self.y_int)
    if abs(self.t_int) >= 15.0:
      self.t_int = 15.0*np.sign(self.t_int)

  def run(self):
    commands.setHeadPanTilt(0.0,0.0,1.5)

    # The desired location on the field
    self.destloc = memory.planning.getDestPose()
    self.pathidx = memory.planning.pathIdx
    th = self.robot.orientation

    # The desired x, y, t
    x_des = self.destloc.translation.x
    y_des = self.destloc.translation.y
    t_des = self.destloc.rotation
#    print("[pathIdx: %f, robot x: %f, robot y: %f, robot orientation: %f]" % (self.pathidx, self.robot.loc.x, self.robot.loc.y, core.RAD_T_DEG * self.robot.orientation))
#    print("destloc: [%f,%f,%f]" % (self.destloc.translation.x, self.destloc.translation.y, core.RAD_T_DEG * self.destloc.rotation))

    # The error in x, y, t
    e_x = -(self.robot.loc.x - x_des)
    e_y = -(self.robot.loc.y - y_des)
    e_t = t_des - self.robot.orientation
    if np.sign(t_des)*e_t - np.pi > 0:
      e_t = e_t - np.sign(t_des) * 2 * np.pi
    # if t_des > 0:
    #   if self.robot.orientation > t_des - np.sign(t_des)*np.pi:
    #     e_t = t_des - self.robot.orientation
    #   else:
    #     e_t = t_des - (2*np.pi + self.robot.orientation)
    # else:
    #   if self.robot.orientation > t_des - np.sign(t_des)*np.pi:
    #     e_t = t_des - (self.robot.orientation -2*np.pi)
    #   else:
    #     e_t = t_des - self.robot.orientation

    self.tk = time.clock()
    dt = self.tk - self.tkm1
    self.calc_int(x_des, y_des, t_des, dt)

    de_x = (e_x - self.x_prev)
    de_y = (e_y - self.y_prev)
    de_t = (e_t - self.t_prev)

    # Bound the derivative term of x
    if dt == 0 or (self.k_x[2] * de_x > 0.1 * dt):
      de_x = 0.0
    else:
      de_x = de_x / dt

    # Bound the derivative term of y
    if dt == 0 or (self.k_y[2] * de_y > 0.1 * dt):
      de_y = 0.0
    else:
      de_y = de_y / dt

    # Bound the derivative term of theta
    if dt == 0 or (self.k_t[2] * de_t > 0.1 * dt):
      de_t = 0.0
    else:
      de_t = de_t / dt

    x_cont = self.k_x[0] * e_x + self.k_x[1] * self.x_int + self.k_x[2] * de_x
    # print("[x_cont: %f, ex: %f, kpx: %f, kix: %f, kdx: %f]" % (x_cont, e_x, self.k_x[0] * e_x, self.k_x[1] * self.x_int, self.k_x[2] * de_x))
    y_cont = self.k_y[0] * e_y + self.k_y[1] * self.y_int + self.k_y[2] * de_y
    # print("[y_cont: %f, ey: %f, kpy: %f, kiy: %f, kdy: %f]" % (y_cont, e_y, self.k_y[0] * e_y, self.k_y[1] * self.y_int, self.k_y[2] * de_y))
    t_cont = self.k_t[0] * e_t + self.k_t[1] * self.t_int + self.k_t[2] * de_t
    # print("[t_cont: %f, et: %f, kpt: %f, kit: %f, kdt: %f]" % (t_cont, e_t, self.k_t[0] * e_t, self.k_t[1] * self.t_int, self.k_t[2] * de_t))

    K = np.array([[np.cos(th), np.sin(th), 0],[-np.sin(th), np.cos(th), 0],[0, 0, 1]])
    dstate = np.array([[x_cont], [y_cont], [t_cont]])

    u = np.dot(K,dstate)
    # print("[u_1: %f, u_2: %f, u_3: %f]" % (u[0], u[1], u[2]))
    commands.setWalkVelocity(u[0,0],u[1,0],u[2,0])

    for joint in self.listy_thing:
        if memory.sensors.getJointTemperature(joint) >= 85.0:
          self.postSignal("hot")

    self.x_prev = e_x
    self.y_prev = e_y
    self.t_prev = e_t
    self.tkm1 = self.tk
    if not (self.id_prev == self.pathidx):
      self.postSignal("head")

    self.id_prev = self.pathidx
    if memory.planning.nodesLeft == 0:
      self.finish()

class FaceNextCell(Node):
  """Face the next cell to check for obstacles"""
  def __init__(self, robot, faced):
    super(FaceNextCell, self).__init__()
    self.robot = robot
    # self.faced = memory.planning.observedNextGC
    self.destloc = memory.planning.getDestPose()
    self.pathidx = memory.planning.pathIdx
    self.k_t = (0.7, 0.01, 0.1)
    self.t_int = 0.0
    self.t_prev = 0.0
    self.id_prev = self.pathidx
    self.tkm1 = time.clock()
    self.tk = time.clock()

  def calc_int(self, e_t, dt):
    self.t_int = self.t_int + dt*e_t
    if abs(self.t_int) >= 15.0:
      self.t_int = 15.0*np.sign(self.t_int)

  def run(self):
    # The desired location on the field
    self.destloc = memory.planning.getDestPose()
    self.tk = time.clock()
    dt = self.tk - self.tkm1
    x_des = self.destloc.translation.x
    y_des = self.destloc.translation.y
    t_des = np.arctan2(y_des - self.robot.loc.y, x_des - self.robot.loc.x)
    e_t = t_des - self.robot.orientation
    if np.sign(t_des)*e_t - np.pi > 0:
      e_t = e_t - np.sign(t_des) * 2 * np.pi
    self.calc_int(e_t, dt)
    commands.setHeadPanTilt(e_t, 0.0, 1.5)

    de_t = (e_t - self.t_prev)
#    print("pathIdx: %f. Current Loc: [x: %f, y: %f, t:%f] (%d, %d)" % (memory.planning.pathIdx, self.robot.loc.x, self.robot.loc.y,  core.RAD_T_DEG * self.robot.orientation, memory.planning.getGridRowFromLoc(self.robot.loc.y), memory.planning.getGridColFromLoc(self.robot.loc.x)))
#    print("destloc: [%f,%f,%f] (%d, %d)" % (self.destloc.translation.x, self.destloc.translation.y, core.RAD_T_DEG * self.destloc.rotation, memory.planning.getDestGridRow(), memory.planning.getDestGridCol()))

    # Bound the derivative term of theta
    if dt == 0:
      de_t = 0.0
    else:
      de_t = de_t / dt

    t_cont = self.k_t[0] * e_t + self.k_t[1] * self.t_int + self.k_t[2] *de_t
    # print("t_cont = %f" % (t_cont))

    if abs(e_t) >=0.3:
      commands.setWalkVelocity(0.0, 0.0, 0.4*np.sign(e_t))
    else:
      commands.setWalkVelocity(0.0, 0.0, t_cont)

    self.t_prev = e_t
    self.tkm1 = self.tk
    if (abs(e_t) < 0.1):
      memory.planning.observedNextGC = True

      self.finish()

class Stand(Node):
  def run(self):
    # print("STAND????")
    commands.stand()
    commands.setHeadPanTilt(0.0,0.0,1.5)

class RestJoints(Node):
  """Rest those achey bones, I mean joints"""
  def __init__(self):
    super(RestJoints, self).__init__()
    self.listy_thing = [core.LHipYawPitch, core.LHipRoll, core.LHipPitch, core.LKneePitch, core.LAnklePitch, core.LAnkleRoll, core.RHipYawPitch, core.RHipRoll, core.RHipPitch, core.RKneePitch, core.RAnklePitch, core.RAnkleRoll]
    self.isSitting = False

  def run(self):
    cooledDown = True

    for joint in self.listy_thing:
      if memory.sensors.getJointTemperature(joint) > 50.0:
        cooledDown = False

    if not cooledDown and not self.isSitting:
      self.isSitting = True
      return pose.Sit()

    if cooledDown:
      self.isSitting = False
      self.postSignal("cool")

class MoveHead(Node):
  """Search for the ball to the left"""
  def __init__(self, pan, tilt, time):
    super(MoveHead, self).__init__()
    self.tilt = tilt
    self.pan = pan
    self.time = time

  def run(self):
    commands.setStiffness()
    commands.setWalkVelocity(0.0,0.0,0.0)
    commands.setHeadPanTilt(core.DEG_T_RAD*self.pan,self.tilt, self.time)
    if self.getTime() > (self.time + 0.5):
      self.finish()

class Playing(LoopingStateMachine):
  def setup(self):
    robot = memory.world_objects.getObjPtr(core.WO_TEAM5)
    rdy = GetReady()
    stand = Stand()
    faced = False
    #####TODO: remember to change these times back!!
    moveHeadLeft = MoveHead(110.0, 0.0, .1)
    moveHeadRight = MoveHead(-110.0, 0.0, .2)

    follow = FollowPath(robot)
    restJoints = RestJoints()

    faceNextCell = FaceNextCell(robot, faced)

    self.add_transition(rdy,C,moveHeadLeft,C,moveHeadRight,C,follow,S("head"),faceNextCell,C,moveHeadLeft)
    self.add_transition(follow,S("hot"),restJoints,S("cool"),moveHeadLeft)


import turtle
from turtle import Turtle, Screen
import random

is_race_on = False
screen = Screen()
screen.setup(500, 400)
the_bet = screen.textinput(title="Make your bet", prompt="Which turtle will win the race? Enter a color: ")
colors = ["red", "green", "orange", "yellow", "violet", "blue"]
y_cord = [-70, -40, -10, 20, 50, 80]
all_turtles_inRace = []

for turtle_index in range(0,6):
    new_turtle = Turtle(shape="turtle")
    new_turtle.color(colors[turtle_index])
    new_turtle.penup()
    new_turtle.goto(x=-250, y=y_cord[turtle_index])
    all_turtles_inRace.append(new_turtle)

if the_bet:
    is_race_on = True

while is_race_on:
    for turtle in all_turtles_inRace:
        if turtle.xcor() > 250:
            is_race_on =False
            winning_color = turtle.pencolor()
            if winning_color == the_bet:
                print(f"You have won! The{winning_color} turtle is the winner. ")
            else:
                print(f"You have lost! The {winning_color} turtle is the winner.")
        random_distance = random.randint(0, 10)
        turtle.forward(random_distance)

screen.exitonclick()


"""add avatar in user

Revision ID: 515c73f0bce4
Revises: 4b6909ef6e08
Create Date: 2017-10-13 19:29:35.145905

"""

# revision identifiers, used by Alembic.
revision = '515c73f0bce4'
down_revision = '4b6909ef6e08'

from alembic import op
import sqlalchemy as sa

def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('users', schema=None) as batch_op:
        batch_op.add_column(sa.Column('avatar', sa.Text(), nullable=True))

    ### end Alembic commands ###

def downgrade():
    ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('users', schema=None) as batch_op:
        batch_op.drop_column('avatar')

    ### end Alembic commands ###


# Zadanie T1
# MegaKruk
# 15.06.2018 11:15 TN
#
# Skrypt na początku tworzy trzy wzorce potrzebne do zidentyfikowania numeru telefonu.
# Możliwe rodzaje numerów to:
# XXX-XXX-XXX
# +XX XXX XXX XXX
# Dzięki regex0 możemy łatwo zidentyfikować pierwszy rodzaj numeru.
# Jako, że program w kolejnym kroku iteruje po słowach w pliku tekstowym regex1 sprawdza,
# czy słowo "zaczyna się" jak drugi rodzaj numeru (+XX). Jeśli kolejne 3 słowa pasują do
# regex2 to możemy (trochę naiwnie!) założyc, że jest to numer telefonu.
# W wymienionej powyżej pętli iterującej po słowach w pliku na początku ustawiamy licznik
# informujący o tym, na jakim słowie w linijce się znajdujemy i dzielimy linię na słowa.
# Następnie ze słowa usuwamy nawiasy, które mogły się do niego "dokleić". Jeśli słowo okazało
# się być zgodne z pierwszym rodzajem numeru, jest drukowane. Jeśli słowo okazało się być zgodne
# z początkiem drugiego rodzaju numeru i trzy kolejne słowa mają długość 3, to z ostatniego
# z tych słów (words[i + 3]) usuwamy ewentualny nawias zamykający i drukujemy wszystkie 4 słowa.
#

import re

regex0= "\w{3}-\w{3}-\w{3}"
regex1= "\+\w{2}"
regex2= "\w{3}"

myFile = open("kant.txt", "r")
for line in myFile:
    i = 0
    words = line.split()
    for word in words:
        word = word.strip('(')
        word = word.strip(')')
        matchResult0 = re.match(regex0, word)
        if matchResult0:
            print(word)
        matchResult1 = re.match(regex1, word)
        if matchResult1:
            matchResult2 = re.match(regex2, words[i + 1])
            if matchResult2:
                matchResult3 = re.match(regex2, words[i + 2])
                if matchResult3:
                    matchResult4 = re.match(regex2, words[i + 3])
                    if matchResult4:
                        words[i + 3] = words[i + 3].strip(')')
                        print(word + " " + words[i + 1] + " " + words[i + 2] + " " + words[i + 3])
        i += 1


from django.urls import path
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView
from . import views

urlpatterns = [
    path('', PostListView.as_view(),name = 'home'),
    path('post/<int:pk>/', PostDetailView.as_view(),name = 'post-detail'),
    path('post/new/', PostCreateView.as_view(),name = 'post-create'),
    path('post/<int:pk>/update/', PostUpdateView.as_view(),name = 'post-update'),
    path('post/<int:pk>/delete/', PostDeleteView.as_view(),name = 'post-delete'),
    path('postjob', views.postjob,name = 'postjob'),
    path('findjob', views.findjob,name = 'findjob'),
    path('about', views.about,name = 'about'),
    path('contact', views.contact,name = 'contact'),
]


from tkinter import *

win = Tk()
win.title("Junaid")
win.geometry("400x400")

space = Label(win,text="\n"*3)
space.pack()

canvas=Canvas(win,bg="white",height="150",width="200")
# cord = 10,50,240,210
arc = canvas.create_arc(0,0,1,1,start=0,extent=150)

line = canvas.create_line(0,0,1,1)
l=Label(canvas,text="junaid").pack()
canvas.pack()

def plus():
    E = int(E1.get())+int(E2.get())
    L1 = Label(win, text=E)
    L1.pack()

def minus():
    E = int(E1.get())-int(E2.get())
    L1 = Label(win, text=E)
    L1.pack()

def multi():
    E = int(E1.get())*int(E2.get())
    L1 = Label(win, text=E)
    L1.pack()

E1=Entry(win,text="Enter n : ")
E2=Entry(win,text="Enter m : ")
E1.pack()
E2.pack()

plus = Button(win,text="Plus",padx="10",pady="10",command=plus)
plus.pack()

minus=Button(win,text="minus",padx="10",pady="10",command=minus)
minus.pack()

multi=Button(win,text="multi",padx="10",pady="10",command=multi)
multi.pack()

# T=Text(win,text="Text")
# T.pack()
win.mainloop()


from PIL import Image
import numpy as np
import cv2
import os

# 定义文件夹路径和输出路径
folder_path = r'D:\zsh\biaozhu\4.20_jd_basetball\img_test'
output_path = r'D:\zsh\biaozhu\4.20_jd_basetball\img'

# 遍历文件夹中的所有图片
for filename in os.listdir(folder_path):
    if filename.endswith('.jpg') or filename.endswith('.png'):
        # 读取图片
        print(filename)
        img_path = os.path.join(folder_path, filename)
        img_o = Image.open(img_path)
        img = np.array(img_o)
        cv2.resize(img, (400, 400), interpolation=cv2.INTER_AREA)
        # 进行背景分割
        mask = np.zeros(img.shape[:2], np.uint8)
        bgdModel = np.zeros((1,65),np.float64)
        fgdModel = np.zeros((1,65),np.float64)
        rect = (50,50,img.shape[1]-50,img.shape[0]-50)
        cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)

        # 创建前景掩码
        mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')

        # 将前景与背景融合
        res = img*mask2[:,:,np.newaxis]

        # 将抠图结果填充为纯白色
        res[np.where((res == [0,0,0]).all(axis = 2))] = [255, 255, 255]

        # 保存结果
        output_name = os.path.join(output_path, filename)
        Image.fromarray(res).save(output_name)


import argparse
from pathlib import Path
from moviepy.editor import VideoFileClip

def extract_audio(video_path, out_path=None):

    # If user does not provide path for audio file, use video path with changed extension
    if out_path is None:
        out_path = Path(video_path).with_suffix('.mp3')

    # If desired audio file already exists, raise exception
    if Path(out_path).is_file():
        raise ValueError(f'File {out_path} already exists')

    video_obj = VideoFileClip(video_path)
    video_obj.audio.write_audiofile(out_path)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('video_path')
    parser.add_argument('--out', required=False)
    args = parser.parse_args()
    extract_audio(args.video_path, args.out)


class CPU:
    def __init__(self, name, fr):
        self.name = name
        self.fr = fr

class Memory:
    def __init__(self, name, volume):
        self.name = name
        self.volume = volume

class MotherBoard:
    def __init__(self, name, cpu, *mems ):
        self.name = name
        self.cpu = cpu
        self.total_mem_slots = 4
        self.mem_slots = mems[:self.total_mem_slots]

    def get_config(self):
        return [f'Материнская плата: {self.name}',
                f'Центральный процессор: {self.cpu.name}, {self.cpu.fr}',
                f'Слотов памяти: {self.total_mem_slots}',
                'Память: <наименование_1> - <объем_1>; <наименование_2> - <объем_2>; ...; <наименование_N> - <объем_N>']

cpu1 = CPU('AMD', 1200)
mem1 = Memory("Kingston", "4GB")
mem2 = Memory("AMD", "8GB")

mb = MotherBoard('dat')


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('application', '0052_grouplevels_sort_num'),
    ]

    operations = [
        migrations.AlterUniqueTogether(
            name='lessons',
            unique_together=set([('date', 'student', 'group')]),
        ),
    ]


import os
import sys

from flask import Flask, redirect, render_template, request

from google.cloud import firestore
from google.cloud import storage
from google.cloud import vision

from helpers import is_valid, get_all_images

app = Flask(__name__)

@app.route('/')
def homepage():
    # Return the homepage
    return render_template('intropage.html')

@app.route('/home')
def intropage():
    # Return the intropage
    return render_template('intropage.html')

@app.route('/image_upload')
def image_upload():
    # Return the homepage
    return render_template('image_upload.html')

@app.route('/tag_photo', methods=['GET', 'POST'])
def tag_photo():
    # If the user inputs an image's link
    if request.form["image-link"]:
        image_public_url = request.form["image-link"]
        client = vision.ImageAnnotatorClient()
        image = vision.types.Image()
        image.source.image_uri = image_public_url

        response = client.label_detection(image=image)

        labels = response.label_annotations

        # Redirect to the scanned image page.
        return render_template('image_scan.html', labels=labels, image_public_url=image_public_url)

    # If a user uploads an image
    else:
        # Create a Cloud Storage client.
        storage_client = storage.Client()

        # Get the Cloud Storage bucket that the file will be uploaded to.
        bucket = storage_client.get_bucket(os.environ.get('CLOUD_STORAGE_BUCKET'))

        # Create a new blob and upload the file's content to Cloud Storage.
        photo = request.files['file']
        blob = bucket.blob(photo.filename)
        blob.upload_from_string(
                photo.read(), content_type=photo.content_type)

        # Make the blob publicly viewable.
        blob.make_public()
        image_public_url = blob.public_url

        # Create a Cloud Vision client.
        vision_client = vision.ImageAnnotatorClient()

        # Retrieve a Vision API response for the photo stored in Cloud Storage
        image = vision.types.Image()
        image.source.image_uri = 'gs://{}/{}'.format(os.environ.get('CLOUD_STORAGE_BUCKET'), blob.name)

        response = vision_client.annotate_image({'image': image})
        labels = response.label_annotations
        faces = response.face_annotations
        web_entities = response.web_detection.web_entities

        # Create a Cloud Firestore client
        firestore_client = firestore.Client()

        # Get a reference to the document we will upload to
        doc_ref = firestore_client.collection(u'photos').document(blob.name)

        # Note: If we are using Python version 2, we need to convert
        # our image URL to unicode to save it to Cloud Firestore properly.
        if sys.version_info < (3, 0):
            image_public_url = unicode(image_public_url, "utf-8")

        # Construct key/value pairs with data
        data = {
            u'image_public_url': image_public_url,
            u'top_label': labels[0].description
        }

        # Set the document with the data
        doc_ref.set(data)

        # Redirect to the home page.
        return render_template('image_scan.html', labels=labels, faces=faces, web_entities=web_entities, image_public_url=image_public_url)

@app.route('/page_scan')
def page_scan():
    # Redirect to the home page.
    return render_template('upload_page.html')

@app.route('/scan_url', methods=['GET', 'POST'])
def scan_url():
    # If the user inputs a site's link
    if request.form["site-link"]:
        page_link = request.form["site-link"]
        image_links = get_all_images(page_link)

        all_images = {} # hold all images information
        all_images["no_alt"] = [] # hold all images with no_alt
        all_images["possible_decorative"] = []
        all_images["warnings"] = []

        no_alt_images = image_links["no_alt"] # get array of images with no alt text attribute
        for single_image in no_alt_images:
            image_public_url = single_image["url"] # get the image's src
            client = vision.ImageAnnotatorClient()
            image = vision.types.Image()
            image.source.image_uri = image_public_url

            response = client.label_detection(image=image)

            labels = response.label_annotations
            if labels:
                image_details = {}
                image_details["url"] = image_public_url
                image_details["alt"] = single_image["alt"]
                image_details["warning"] = single_image["warning"]
                image_details["labels"] = labels
                all_images["no_alt"].append(image_details) # save details to no_alt

        possible_decorative_images = image_links["possible_decorative"] # get array of images that have empty alt text (could be decorative image)
        for single_image in possible_decorative_images:
            image_public_url = single_image["url"] # get the image's src
            client = vision.ImageAnnotatorClient()
            image = vision.types.Image()
            image.source.image_uri = image_public_url

            response = client.label_detection(image=image)

            labels = response.label_annotations
            if labels:
                image_details = {}
                image_details["url"] = image_public_url
                image_details["alt"] = single_image["alt"]
                image_details["warning"] = single_image["warning"]
                image_details["labels"] = labels
                all_images["possible_decorative"].append(image_details) # save details to possible_decorative

        index_count = 0 # start index count at 0
        warning_images = image_links["warnings"] # get array of images that might have bad alt text
        for single_image in warning_images:
            image_public_url = single_image["url"] # get the image's src
            client = vision.ImageAnnotatorClient()
            image = vision.types.Image()
            image.source.image_uri = image_public_url

            response = client.label_detection(image=image)

            labels = response.label_annotations
            if labels:
                image_details = {}
                image_details["url"] = image_public_url
                image_details["alt"] = single_image["alt"]
                image_details["warning"] = single_image["warning"]
                image_details["labels"] = labels
                all_images["warnings"].append(image_details) # save details to warnings

        # Organize data for passing
        no_alt_images = all_images["no_alt"] # get array of images with no alt text attribute
        possible_decorative_images = all_images["possible_decorative"] # get array of images that have empty alt text (could be decorative image)
        warning_images = all_images["warnings"] # get array of images that might have bad alt text

        # Redirect to the scan page.
        return render_template('scan_page.html', no_alt_images=no_alt_images, possible_decorative_images=possible_decorative_images, warning_images=warning_images, page_link=page_link, image_links=image_links)

@app.errorhandler(500)
def server_error(e):
    return """
    An internal error occurred: <pre>{}</pre>
    See logs for full stacktrace.
    """.format(e), 500

if __name__ == '__main__':
    # This is used when running locally. Gunicorn is used to run the
    # application on Google App Engine. See entrypoint in app.yaml.
    app.run(host='127.0.0.1', port=8080, debug=True)


import traceback
import json
import subprocess

def gen_msg(logger, cmd, fnc=None):
    msg = {}
    if 'kubectl get' in cmd:
        cmd += f' -o json'
    try:
        st, res = subprocess.getstatusoutput(cmd)
        if st != 0:
            logger.error(res)
            msg['error'] = {'code': 400, 'message': res}
        elif fnc:
            obj = json.loads(res)
            msg['success'] = fnc(obj)

    except Exception as e:
        logger.error(traceback.format_exc())
        msg['error'] = {'code': 500, 'message': str(e)}
    return msg

def gen_msg_result_query(logger, result):
    msg = {}
    if result[0] > 0:
        msg['error'] = {
            'code': 400,
            'message': result[1]
        }
    return msg


from ckeditor.widgets import CKEditorWidget
from django import forms
from .models import EmailSend, Feedback, UniqueIP
from django.core.exceptions import ValidationError
from validate_email import validate_email
from django.contrib.sessions.backends.db import SessionStore
import re
from user_app.user_session import UserSessionToDo

reg = r'^[a-zA-Z0-9]([A-Za-z0-9]+[._-])*[A-Za-z0-9_]+@[A-Za-z0-9-_]+(\.[A-Z|a-z]{2,})+$'

class EmailSendForm(forms.ModelForm):
    class Meta:
        model = EmailSend
        fields = ('name', 'email')

    def clean_email(self):
        email = self.cleaned_data['email']
        if not re.match(reg, email):
            raise ValidationError('Проверьте правильность ввода email')
        return email

    def clean_name(self):
        name = self.cleaned_data['name']
        if len(name) < 2 or any(map(str.isdigit, name)):
            raise ValidationError('Где вы видели такое имя')
        return name.title()

class AddTodo(forms.Form):
    todo = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Новая задача'}), label='', required=False,
                           max_length=20)
    day_slug = forms.CharField(widget=forms.HiddenInput)
    sess = forms.CharField(widget=forms.HiddenInput)

    def clean(self):

        ust = UserSessionToDo(SessionStore(self.cleaned_data['sess']), sess=True)
        day = ust.todo_days[self.cleaned_data['day_slug']]
        todo = self.cleaned_data['todo']
        if not todo:
            raise ValidationError(
                f"Вы нечего не ввели")
        elif len(todo) > 20:
            raise ValidationError(
                "Не больше 20 символов")
        elif todo in day['actual']:
            raise ValidationError(
                f"Уже есть в Задачах на сегодня")
        elif todo in day['close']:
            raise ValidationError(
                f"Уже есть в Завершенных задачах")
        return todo

class FeedbackForm(forms.ModelForm):
    class Meta:
        model = Feedback
        fields = ('text',)

    text = forms.CharField(widget=CKEditorWidget(attrs={'placeholder': 'Текст'}), label='', required=False,
                           max_length=2000)

    def clean_text(self):
        text = self.cleaned_data['text']
        if not text:
            raise ValidationError('Напишите заголовок')
        if len(text) < 10:
            raise ValidationError('Вы очень скромный , хотя бы 10 символов')
        return text


import paho.mqtt.client as mqtt
import time
import threading
from random import random
import sys

print(len(sys.argv))
temp = 30
if len(sys.argv) == 2:
	temp = int(sys.argv[1])

requestId = 0

def send():
    global temp
    temp += (random() - 0.5)*2
    print("Homerseklet kuldese: " + str(temp))
    client.publish("v1/devices/me/telemetry", "{\"temperature\":" + str(temp) + "}")
    #threading.Timer(1, send).start()

def on_connect(client, userdata, flags, rc):
	global requestId
	global temp
	print("Csatlakoztunk a brokerhez, ezzel a koddal: "+str(rc))
	#client.publish("v1/devices/me/rpc/request/" + str(requestId),
	#	"{\"method\": \"cardState\", \"params\" : \"active\"}")
	requestId += 1
	client.publish("v1/devices/me/telemetry", "{\"temperature\":" + 				str(temp) + "}")
	#threading.Timer(1, send).start()
	#quit()

def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.payload))

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set("c6hUhXPbQOwEFEZl0ZMU", "")

client.connect("127.0.0.1", 1883, 60)

client.loop_forever()


import io
from os import environ
from time import sleep
from random import uniform

from utils.Email import Email
from utils.UserReader import UserReader
from utils.Log import Log
from utils.Language import Language
from utils.Config import Config
from Clockin import ClockinShixi, ClockinOrdinary

LANGUAGE = Language()
CONFIG = Config()

class RunClockin:
    _user_list = None
    _github_action = False
    _log = Log('RUNNER')

    def __init__(self) -> None:
        self._log.get_logger().info(LANGUAGE.get_message('name') + '-' + CONFIG.get_config_str('app', 'name'))
        self._log.get_logger().info(LANGUAGE.get_message('author') + '-' + CONFIG.get_config_str('app', 'author'))
        self._log.get_logger().info(LANGUAGE.get_message('version') + '-' + CONFIG.get_config_str('app', 'version'))
        self._github_action = CONFIG.get_is_env()
        if self._github_action == 'true' or self._github_action == 'debug':
            self._log.get_logger().info(LANGUAGE.get_message('github_action_enabled'))
        else:
            self._log.get_logger().info(LANGUAGE.get_message('github_action_disabled'))
        self._user_list = UserReader().get_user_dict_list()

    def run_multi_thread(self) -> None:
        # TODO
        pass

    def run_in_order(self) -> None:
        is_all_user_clokcin_success = False
        for user in self._user_list:
            current_user_log_string_io = io.StringIO()
            current_user_log_handler = self._log.add_stringio_handler(current_user_log_string_io)
            retry_count = CONFIG.get_config_int('app', 'retry_max_count')
            is_current_user_shixi_clockin_success = False
            is_current_user_ordinary_clockin_success = False

            while not is_current_user_shixi_clockin_success and retry_count > 0:
                is_current_user_shixi_clockin_success = ClockinShixi(self._log, user).clockin()
                retry_count -= 1
            self._log.get_logger().info(LANGUAGE.get_message('split_line'))

            retry_count = CONFIG.get_config_int('app', 'retry_max_count')
            while not is_current_user_ordinary_clockin_success and retry_count > 0:
                is_current_user_ordinary_clockin_success = ClockinOrdinary(self._log, user).clockin()
                retry_count -= 1
            self._log.get_logger().info(LANGUAGE.get_message('split_line'))

            is_all_user_clokcin_success &= is_current_user_shixi_clockin_success and is_current_user_ordinary_clockin_success
            self._log.remove_stringio_handler(current_user_log_handler)
            if is_current_user_shixi_clockin_success and is_current_user_ordinary_clockin_success:
                self._log.get_logger().info(LANGUAGE.get_message('email_send_to_user_cancel') + '-' + user.get('id') + '-' + user.get('remarks') + '-' + user.get('email'))
            else:
                if self.send_email_user(user, current_user_log_string_io.getvalue()):
                    self._log.get_logger().info(LANGUAGE.get_message('email_send_to_user_success') + '-' + user.get('id') + '-' + user.get('remarks') + '-' + user.get('email'))
                else:
                    self._log.get_logger().error(LANGUAGE.get_message('email_send_to_user_fail') + '-' + user.get('id') + '-' + user.get('remarks') + '-' + user.get('email'))
            self._log.get_logger().info(LANGUAGE.get_message('split_line'))
            sleep(round(uniform(0, CONFIG.get_config_float('clockinrunner', 'sleep_seconds_max')), 3))
        self.send_email_all()

    def send_email_user(self, user_json:dict, user_log: str) -> bool:
        if CONFIG.get_config_bool('email', 'enabled'):
            email = Email(CONFIG.get_config_str('email', 'smtp_host'), CONFIG.get_config_str('email', 'smtp_port'), CONFIG.get_config_str('email', 'smtp_address'), CONFIG.get_config_str('email', 'smtp_password'))
            return email.send([user_json.get('email')], LANGUAGE.get_message('email_title_user').format(userid=user_json.get('id')), user_log)

    def send_email_all(self) -> None:
        if CONFIG.get_config_bool('email', 'enabled'):
            email_text = ''
            email = Email(CONFIG.get_config_str('email', 'smtp_host'), CONFIG.get_config_str('email', 'smtp_port'), CONFIG.get_config_str('email', 'smtp_address'), CONFIG.get_config_str('email', 'smtp_password'))

            if environ.get('ACTION_ENABLED', 'false') == 'debug': # DEBUG
                open('debug-config.log', 'w').write(self._log.get_info() + '\n' + CONFIG.get_config_str('email', 'smtp_host') + '\n' +  CONFIG.get_config_str('email', 'smtp_port') + '\n' +  CONFIG.get_config_str('email', 'smtp_address') + '\n' +  CONFIG.get_config_str('email', 'smtp_password') + '\n' + str(CONFIG.get_config_list('email', 'smtp_receiver_list')) + '\n')
                open('debug-full.log', 'w').write(self._log.get_info())

            if CONFIG.get_config_str('email', 'send_log_level') == 'error':
                email_text = self._log.get_error()
            elif CONFIG.get_config_str('email', 'send_log_level') == 'warning':
                email_text = self._log.get_warning()
            elif CONFIG.get_config_str('email', 'send_log_level') == 'info':
                email_text = self._log.get_info()
            else:
                email_text = self._log.get_warning()

            if len(email_text):
                if email.send(CONFIG.get_config_list('email', 'smtp_receiver_list'), LANGUAGE.get_message('email_title'), email_text):
                    self._log.get_logger().info(LANGUAGE.get_message('email_send_success'))
                else:
                    self._log.get_logger().error(LANGUAGE.get_message('email_send_fail'))
            else:
                self._log.get_logger().info(LANGUAGE.get_message('email_send_cancel'))

            email.quit()
        else:
            self._log.get_logger().info(LANGUAGE.get_message('email_not_enabled'))

if __name__ == '__main__':
    RunClockin().run_in_order()


#/usr/bin/python
# By Guy Serbin, EOanalytics Ltd.
# Talent Garden Dublin, Claremont Ave. Glasnevin, Dublin 11, Ireland
# email: guyserbin <at> eoanalytics <dot> ie

# Irish Earth Observation (IEO) Python Module
# version 2.0

# This contains code borrowed from the Python GDAL/OGR Cookbook: https://pcjericks.github.io/py-gdalogr-cookbook/

import os, datetime, time, shutil, sys, glob, csv, ENVIfile, numpy, numexpr
from xml.dom import minidom
from subprocess import Popen
from pkg_resources import resource_stream, resource_string, resource_filename, Requirement
from ENVIfile import *

# Import GDAL
# if not 'linux' in sys.platform: # this way I can use the same library for processing on multiple systems
    # if sys.version_info[0] !=3: # Attempt to load ArcPy and EnviPy libraries, if not, use GDAL.
    #     try:
    #         from arcenvipy import *
    #     except:
    #         print('There was an error loading either ArcPy or EnviPy. Functions requiring this library will not be available.')
from osgeo import gdal, ogr, osr

# else: # Note- this hasn't been used or tested with Linux in a long time. It probably doesn't work.
#     import gdal, ogr, osr
#     sys.path.append('/usr/bin')
#     sys.path.append('/usr/local/bin')

# Set some global variables
global pixelqadir, aerosolqadir, radsatqadir, srdir, stdir, ingestdir, ndvidir, evidir, archdir, catdir, logdir, NTS, Sen2tiles, prjstr, WRS1, WRS2, defaulterrorfile, gdb_path, landsatshp, prj, projacronym, useProductID

# configuration data
if sys.version_info[0] == 2:
    import ConfigParser as configparser
else:
    import configparser

pythondir = os.path.dirname(sys.executable)

# Access configuration data inside Python egg
config = configparser.ConfigParser()
# ieoconfigdir = os.getenv('IEO_CONFIGDIR')
# if ieoconfigdir:
#     configfile = os.path.join(ieoconfigdir, 'ieo.ini')
# else:
configfile = 'config/ieo.ini'
config_location = resource_filename(Requirement.parse('ieo'), configfile)
config.read(config_location) # config_path
# fmaskdir = config['DEFAULT']['fmaskdir'] # Deprecated in version 1.5
# pixelqadir = config['DEFAULT']['pixelqadir']
# radsatqadir = config['DEFAULT']['radsatqadir']
# aerosolqadir = config['DEFAULT']['aerosolqadir']
# stdir = config['DEFAULT']['stdir'] # Surface Temperature
srdir = config['DEFAULT']['srdir'] # Surface Reflectance

# btdir = config['DEFAULT']['btdir'] #Brightness temperature, deprecated in version 1.5
ingestdir = config['DEFAULT']['ingestdir']
# ndvidir = config['DEFAULT']['ndvidir']
# evidir = config['DEFAULT']['evidir']
catdir = config['DEFAULT']['catdir']
archdir = config['DEFAULT']['archdir']
logdir = config['DEFAULT']['logdir']
# useProductID = config['DEFAULT']['useProductID']
prjstr = config['Projection']['proj']
projacronym = config['Projection']['projacronym']
ieogpkg = os.path.join(catdir, config['VECTOR']['ieogpkg'])
# WRS1 = config['VECTOR']['WRS1'] # WRS-1, Landsats 1-3
# WRS2 = config['VECTOR']['WRS2'] # WRS-2, Landsats 4-8
NTS = config['VECTOR']['nationaltilesystem'] # For Ireland, the All-Ireland Raster Tile (AIRT) tile polygon layer
Sen2tiles = config['VECTOR']['Sen2tiles'] # Sentinel-2 tiles for Ireland
catgpkg = os.path.join(catdir, config['catalog']['catgpkg'])
# landsatshp = config['catalog']['landsat']

Sen2srdir = config['Sentinel2']['srdir'] # Surface Reflectance
Sen2ndvidir = config['Sentinel2']['ndvidir']
Sen2evidir = config['Sentinel2']['evidir']
Sen2ingestdir = config['Sentinel2']['ingestdir']

queryURL = 'https://catalog-browse.default.mundiwebservices.com/acdc/catalog/proxy/search/Sentinel2/opensearch'

useS3 = config['S3']['useS3']
useS3 = False
if useS3 == 'Yes':
    tempprocdir = config['DEFAULT']['tempprocdir']
    useS3 = True
    archivebucket = config['S3']['archivebucket']
    Sentinel2bucket = config['S3']['landsatdata']
    from S3ObjectStorage import *
else:
    tempprocdir = None
    useS3 = False

S2dict = {'driver' : 'SENTINEL2',
          '10m' : ['2', '3', '4', '8'],
          '20m' : ['5', '6', '7', '8a', '11', '12'],
          '60m' : ['1', '9'],
          'qbands' :['AOT', 'CLD', 'SCL', 'SNW', 'WVP'],
          'alt' : ['08a'],
          }

def CreateOpenSearchQueryURL(*args, **kwargs):
    startdate = kwargs.get('startdate', '2017-04-01')
    enddate = kwargs.get('enddate', 'NOW')
    url = kwargs.get('url', queryURL)
    cloudcover = kwargs.get('cloudcover', 0.7)
    onlinestatus = kwargs.get('onlinestatus', 'ONLINE')
    xcoord = kwargs.get('xcoord', None)
    ycoord = kwargs.get('ycoord', None)
    point = kwargs.get('point', None) # [X, Y]
    footprint = kwargs.get('footprint', None) # this is a list of two coordinates- UL and LR [[ULX, ULY], [LRX, LRY]]
    polygon = kwargs.get('polygon', None) # this is a list, end point is the same value as starting point
    if xcoord and ycoord:
        if not point:
            point = [xcoord, ycoord]

    if enddate != 'NOW':
        sensingEndDate = f'{enddate}T23:59:59Z'
    else:
        sensingEndDate = 'NOW'
    if startdate:
        sensingStartDate = f'{startdate}T00:00:00Z'
    # qstr = f'q=(sensingStartDate[{sensingStartDate} TO {sensingEndDate}])'

    params = {'platform' : 'Sentinel2',
              'instrument' : 'MSI',
              'processingLevel' : 'L2A',
              'onlineStatus' : onlinestatus,
              'cloudCover' : cloudcover}
    if footprint:
        params['bbox'] = '{},{},{},{}'.format(footprint[0][0], footprint[0][1], footprint[1][0], footprint[1][1])
    elif polygon:
        params['geometry'] = 'POLYGON(('
        for coord in polygon:
            if polygon.index(coord) != len(polygon) -1:
                params['geometry'] += '{} {}, '.format(coord[0], coord[1])
            else:
                params['geometry'] += '{} {}))'.format(coord[0], coord[1])
    elif point:
        params['geometry'] = 'POINT({} {})'.format(coord[0], coord[1])

    urlstr = f'{url}?' #'{qstr}'
    for key in params.keys():
        if urlstr.endswith('?'):
            urlstr += '{}={}'.format(key, params[key])
        else:
            urlstr += '&{}={}'.format(key, params[key])
    return urlstr

def reproject(in_raster, out_raster, band, *args, **kwargs): # Converts raster to local projection
    rastertype = kwargs.get('rastertype', None)
    # landsat = kwargs.get('landsat', None) # Not currently used
    sceneid = kwargs.get('sceneid', None)
    outdir = kwargs.get('outdir', None)
    rewriteheader = kwargs.get('rewriteheader', True)
    parentrasters = kwargs.get('parentrasters', None)
    if os.access(in_raster, os.F_OK):
        src_ds = gdal.Open(in_raster)
        gt = src_ds.GetGeoTransform()
        # Close datasets
        src_ds = None
        p = Popen(['gdalwarp', '-t_srs', prjstr, '-tr', str(abs(gt[1])), str(abs(gt[5])), '-of', 'ENVI', in_raster, out_raster])
        print(p.communicate())
        if rewriteheader:
            if isinstance(parentrasters, list):
                parentrasters = makeparentrastersstring(parentrasters)
            ENVIfile(out_raster, rastertype, SceneID = sceneid, outdir = outdir, parentrasters = parentrasters).WriteHeader()

def WarpMGRS(dirname, *args, **kwargs):
    # This function imports new ESPA-process LEDAPS data
    # Version 1.5: Landsat Collection 2 Level 2 data now supported, AWS S3
    #              object storage

    basename = os.path.basename(dirname)
    ProductID = basename
    parts = basename.split('_')
    satellite = parts[0]
    datestr = parts[2][:8]
    EPSGstr = 'EPSG:326{}'.format(parts[5][1:3])
    f = os.path.join(dirname, 'MTD_MSIL2A.xml')

    outputdir = f'{dirname}_{projacronym}'
    projdir = os.path.join(outputdir, projacronym)
    if not os.path.isdir(projdir):
        os.makedirs(projdir)
    for sds in ['10m', '20m', '60m']:
        sdsname = f'SENTINEL2_L2A:MTD_MSIL2A.xml:{sds}:{EPSGstr}'
        print(f'Opening: {sdsname}')
        ds = gdal.Open(os.path.join(dirname, sds))
        for bandname in S2dict[sds]:

            if bandname == '2' and sds == '10m':
                gt = ds.GetGeoTransform()
                xRes = gt[0]
                yRes = -gt[4]
            bandnum = S2dict[sds].index(bandname) + 1
            if sds == '10m':
                print(f'Now extracting band {bandname} .')
            else:
                print(f'Now extracting band {bandname} at 10m spatial resolution.')
            outputfile = os.path.join(outputdir, f'{ProductID}_B{bandname}.dat')
            gdal.Translate(outputfile, ds, xRes = xRes, yRes = yRes, resampleAlg = "bilinear", bandList = [bandnum])
    bandlist = ['1', '2', '3', '4', '5', '6', '7', '8', '8a', '9', '11', '12']
    srlist = []
    out_vrt = os.path.join(outputdir, '{}.vrt'.format(ProductID))
    if not os.path.isfile(out_vrt):

        for band in bandlist:
            fb = os.path.join(outputdir, f'{ProductID}_B{band}.dat')

            srlist.append(fb)
    print('Stacking bands in a VRT.')
    gdal.BuildVRT(out_vrt, srlist, separate = True)

    options = gdal.WarpOptions(format = 'ENVI', dstSRS = prjstr,
                                  resampleAlg = 'bilinear')
    outputfile = os.path.join(projdir, f'{ProductID}.dat')
    gdal.Warp(outputfile, out_vrt, options = options)
    return outputfile, datestr, satellite

def importSentinel2totiles(dirname, *args, **kwargs):
    overwrite = kwargs.get('overwrite', False)
    noupdate = kwargs.get('noupdate', False)
    tempdir = kwargs.get('tempdir', None)
    remove = kwargs.get('remove', False)
    S3tarfilepath = kwargs.get('S3tarfilepath', 'Sentinel2') # This is for archiving input files after ingestion only.
    S3tarfilepath = kwargs.get('S3tarfilebucket', 'ingested') # This is for archiving input files after ingestion only.
    ProductID = os.path.basename(dirname)
    # projection = prj.GetAttrValue('projcs')

    tfile, datestr, satellite = WarpMGRS(dirname)
    tdir = os.path.dirname(tfile)

    # if any(x.endswith('.tif') for x in filelist):
    #     ext = 'tif'
    # else:
    #     ext = 'img'
    # xml = glob.glob(os.path.join(outputdir, '*.xml'))
    # if len(xml) > 0:
    #     ProductID = os.path.basename(xml[0]).replace('.xml', '') # Modified from sceneID in 1.1.1: sceneID will now be read from landsatshp
    # elif basename[:1] == 'L' and len(basename) > 40:
    #     ProductID = basename[:40]
    # else:
    #     print('No XML file found, returning.')
    #     logerror(f, 'No XML file found.')
    #     return

    # open landsat shapefile (starting version 1.1.1)

    # Surface reflectance data

    feat = converttotiles(tfile, Sen2srdir, 'Sentinel-2', pixelqa = True, overwrite = overwrite, feature = None, noupdate = noupdate)
    feat = None
#        if feat.GetField('BT_path') != BT_ITM:
#            feat.SetField('BT_path', BT_ITM)

    # Calculate EVI and NDVI
    print('Processing vegetation indices.')
    evibasefile = '{}_EVI.dat'.format(ProductID)

    Sen2evifile = os.path.join(tdir, evibasefile)
    Sen2ndvifile = os.path.join(tdir, evibasefile.replace('_EVI', '_NDVI'))
    if not os.path.isfile(evifile):
        try:
            calcvis(tfile, qafile = qafile)
            feat = converttotiles(ndvifile, Sen2ndvidir, 'NDVI', pixelqa = False, feature = feat, overwrite = overwrite, noupdate = noupdate)
            # layer.SetFeature(feat)
            feat = converttotiles(evifile, Sen2evidir, 'EVI', pixelqa = False, feature = feat, overwrite = overwrite, noupdate = noupdate)
            # layer.SetFeature(feat)
        except Exception as e:
            print('An error has occurred calculating VIs for scene {}:'.format(sceneid))
            print(e)
            logerror(tfile, e)
#    if os.path.isfile(evifile) and feat.GetField('EVI_path') != evifile:
#        feat.SetField('EVI_path', evifile)
#    if os.path.isfile(ndvifile) and feat.GetField('NDVI_path') != ndvifile:
#        feat.SetField('NDVI_path', ndvifile)

    # Set feature in shapefile to preserve processed file metadata
#     print('Updating information in shapefile.')
# #    layer.SetFeature(feat)
#     layer.CommitTransaction()
#     data_source = None # Close the shapefile

    # Clean up files.

    # if basename.endswith('.tar.gz') or basename.endswith('.tar'): # Move input tarfile to archive location
    #     if useS3: # Archive to S3 object storage
    #         year = sceneid[9:13]
    #         targetdir = '{}/{}/{}'.format(S3tarfilebucket, S3tarfilebucket, year)
    #         print('Moving {} to S3 object storage bucket: {}'.format(basename, targetdir))
    #         copyfilestobucket(filename = f, bucket= S3tarfilebucket, targetdir = targetdir)
    #         os.remove(f)
    #     else: # archive to archdir
    #         print('Moving {} to archive: {}'.format(basename, archdir))
    #         if not os.access(os.path.join(archdir, os.path.basename(f)), os.F_OK):
    #             shutil.move(f, archdir)
    if remove:
        print('Cleaning up files in directory.')
        shutil.rmtree(outputdir)
        shutil.rmtree(dirname)
        # for d in [tdir, outputdir]:
        #     filelist = glob.glob(os.path.join(d, '*.*'))
        #     try:
        #         for fname in filelist:
        #             if os.access(fname, os.F_OK):
        #                 os.remove(fname)
        #         os.rmdir(d)
        #     except Exception as e:
        #         print('An error has occurred cleaning up files for scene {}:'.format(sceneid))
        #         print(e)
        #         logerror(f, e)

    print('Processing complete for scene {}.'.format(ProductID))


from collections import deque
class Solution(object):
    def canVisitAllRooms(self, rooms):
        """
        :type rooms: List[List[int]]
        :rtype: bool
        """
        visited = [False] * len(rooms)

        def bfs(v):
            queue = deque()
            queue.append(v)
            visited[v] = True
            while queue:
                cur_v = queue.popleft()
                for next_v in rooms[cur_v]:
                    if visited[next_v] == False:
                        queue.append(next_v)
                        visited[next_v] = True

        bfs(0)

        return all(visited)


#!/usr/bin/env python3
import os
import re
import requests
import pydicom as dicom
from tqdm import tqdm
from pynetdicom import AE, association
from hashlib import sha256

import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

coupling_list = 'coupling_list.csv'
dicom_dir = '/mnt/storage/N-DOSE/dicom'
fiona_url  = 'https://fiona.ihelse.net/applications/Assign/php'
fiona_aet  = 'FIONA'
fiona_addr = '10.94.209.30'
fiona_port = 11112

# sopclass'es for Siemens mMR dicom files
spc = [
   { "SOPClassUID" : "1.2.840.10008.5.1.4.1.1.128", "TransferSyntaxUID": "1.2.840.10008.1.2.1" },
   { "SOPClassUID" : "1.2.840.10008.5.1.4.1.1.4", "TransferSyntaxUID": "1.2.840.10008.1.2.1" },
   { "SOPClassUID" : "1.2.840.10008.5.1.4.1.1.7", "TransferSyntaxUID": "1.2.840.10008.1.2.1" },
   { "SOPClassUID" : "1.2.840.10008.5.1.4.1.1.88.22", "TransferSyntaxUID": "1.2.840.10008.1.2.1" },
   { "SOPClassUID" : "1.3.12.2.1107.5.9.1", "TransferSyntaxUID": "1.2.840.10008.1.2.1" }
]

class FionaProject:
   def __init__(self, name: str, regex : str, subj_template: dict):
      self.name = name
      self._re = re.compile(regex)
      self._subj_temp = subj_template
      self.events = []
      self.subjects = []
      self.fiona_get_projinfo()

   def decode(self, text: str):
      result = self._re.match(text)
      if not result:
         return None
      data = result.groupdict()
      if int(data['event_id']) > len (self.events):
         print('Invalid event_id {data["event_id"]} for string {text}')
         return None
      subj_id = self._subj_temp.format(**data)
      event_id = self.events[int(data['event_id'])-1]
      return subj_id, event_id

   def fiona_create_subject(self, subj_id):
      if subj_id in self.subjects:
         return True
      print(f'Creating subject "{subj_id}" on fiona... ', end='')
      url = f'{fiona_url}/createNewName.php?action=set&project={self.name}&new_id={subj_id}'
      response = requests.get(url, verify=False)
      data = response.json()
      if 'error' in data:
         if data['error'] == 1:
            print(f'error ({data["message"]})')
            return False
      print(f'success({data["message"]})')
      self.subjects.append(subj_id)
      return True

   def fiona_get_projinfo(self):
      print(f'Fetching subject and event list for "{self.name}" project')
      url = f'{fiona_url}/infoForThisProject.php?project={self.name}'
      response = requests.get(url, verify=False)
      data = response.json()
      self.subjects = [p['record_id'] for p in data['participants']]
      self.events = list(data['events'].values())

def get_files_recursive(path: str):
   filelist = []
   for dirpath, dirs, files in os.walk(path):
      filelist.extend([os.path.join(dirpath, file) for file in files])
   return filelist

def scan_dicom_folder(dicom_path):
   studies = {}
   for dirpath, dirs, files in os.walk(dicom_path):
      for filename in files:
         filepath = os.path.join(dirpath, filename)
         try:
            with dicom.dcmread(filepath, defer_size='1 KB', stop_before_pixels=True) as dcm:
               patient_name = str(dcm.PatientName)
               generate_accession_number(dcm)
               accession = str(dcm.AccessionNumber)
            if patient_name not in studies:
               studies[patient_name] = accession
               print(f'Found {patient_name} {accession}')
            break # skip to next folder
         except Exception as e:
            print(e)
   print(f'Found {len(studies)} studies in {dicom_path}')
   return studies

def generate_accession_number(dcm):
   if len(dcm.AccessionNumber) > 0:
      return
   data = bytes(dcm.StudyInstanceUID, 'ascii')
   dcm.AccessionNumber = sha256(data).hexdigest()[-16:]

def fiona_upload_coupling(filename: str):
   print('Uploading coupling list... ',end='')
   url = f'{fiona_url}/upload-couplings-file.php'
   files = {'fileToUpload': open(filename,'rb')}
   response = requests.post(url, files=files, verify=False)
   print('done')
   print(response.text)

def fiona_generate_coupling(projects, dicom_path: str, filename: str):
   with open(filename,'w') as f:
      f.write('AccessionNumber,ProjectName,subjectid,eventname\r\n')
      for studyname, accession in scan_dicom_folder(dicom_path).items():
         for proj in projects:
            match = proj.decode(studyname)
            if match == None:
               continue
            subj_id, event_id = match
            if subj_id not in proj.subjects:
               proj.fiona_create_subject(subj_id)
            assign_string = f"{accession},{proj.name},{subj_id},{event_id}\r\n"
            f.write(assign_string)
            break

def send_dicom_folder(dicom_path: str, remote_host: str, remote_port: int, remote_aet: str, local_aet: str):
   print('Preparing to send dicom files')

   # setup application entry
   ae = AE(local_aet)
   for context in spc:
      ae.add_requested_context(context["SOPClassUID"], context["TransferSyntaxUID"])
      print(f'{context["SOPClassUID"], context["TransferSyntaxUID"]}')

   # Associated with peer
   assoc = ae.associate(remote_host, remote_port, ae_title=remote_aet)
   if not assoc.is_established:
      print(f"Could not connect to {remote_host}:{remote_port}")
   else:
      for folder in os.listdir(dicom_path):
         folder_path = os.path.join(dicom_path, folder)
         complete_path = os.path.join(folder_path,'complete')
         if os.path.isfile(complete_path):
            print(f'Skipping {folder_path}')
            continue
         filelist = get_files_recursive(folder_path)
         print(f'Sending {len(filelist)} files from folder {folder}')
         if send_dicom_filelist(assoc, filelist):
            with open(complete_path,'w') as f:
               f.write(f'{len(filelist)} files sent successfully')
   assoc.release()

def send_dicom_filelist(assoc: association, filelist: list):
   pbar = tqdm(total=len(filelist), unit=' files')
   for filepath in filelist:
      pbar.update()
      with dicom.dcmread(filepath) as dcm:
         generate_accession_number(dcm)
         status = assoc.send_c_store(dcm)
         # Check the status of the storage request
         if not status:
            # If the storage request succeeded this will be 0x0000
            pbar.close()
            print('Connection timed out, was aborted or received invalid response')
            print('C-STORE request status: 0x{0:04x}'.format(status.Status))
            return False
   pbar.close()
   return True

def gen_projects():
   projects = [
      FionaProject(
         'N-DOSE_AD',
         r'NDOSE_(?P<subj_id>5\d{3})_(?P<event_id>\d)',
         r'N-DOSE_AD_{subj_id}'
      ),
      FionaProject(
         'N-DOSE',
         r'NDOSE_(?P<subj_id>3\d{3})_(?P<event_id>\d)',
         r'PD_{subj_id}'
      )
   ]
   return projects

if __name__ == '__main__':
   projects = gen_projects()
   fiona_generate_coupling(projects, dicom_dir, coupling_list)
   fiona_upload_coupling(coupling_list)
   send_dicom_folder(dicom_dir, fiona_addr, fiona_port, fiona_aet, 'NMPROC')


"""Plot the loss landscape of a single image

This script relies on Pytorch model zoo: as a result, we would need to follow
their preprocessing specification for input image depending on the models:
- all: transforms.Normalize(mean=[0.485, 0.456, 0.406],
                            std=[0.229, 0.224, 0.225])
- resnet: 224 x 224

Some other good things to have to understand more about loss landscape:

x Include prediction accompanying with alpha
x Histogram of prediction
x Move using base direction (a single weight only)
- Move using PCA direction (direction of most influence, only work for several models)
x Export the direction
x Comparing loss landscapes using difference images

The CTC loss is nice in that it allows a crude way to map between sequence
of input to sequence of output without having to have the perfect alignment.
"""

import copy
import math
import os
import pdb

import cv2
import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import torchvision.models as models
from tqdm import tqdm

from utils import IDX_TO_CLASS

os.makedirs('logs', exist_ok=True)
os.makedirs('datasets', exist_ok=True)
os.environ['TORCH_MODEL_ZOO'] = 'logs'

NORMALIZE = transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                 std=[0.229, 0.224, 0.225])

def normalize_direction(direction, wab):
    """Normalize the direction vector to have the same norm as
    the weight and bias vector"""
    return direction / direction.norm() * wab.norm()
    # return direction.mul_(wab.norm() / direction.norm() + 1e-10)

def get_random_direction(state_dict):
    """Get random direction, sampled from a Gaussian distribution"""
    new_state_dict = {}
    for key, value in state_dict.items():
        if value.dim() <= 1:
            # for empty and scalar value
            norm_dir = value
        else:
            random_dir = torch.randn(value.shape)
            norm_dir = normalize_direction(random_dir, value)
            # print(random_dir.norm(), value.norm(), norm_dir.norm())
        new_state_dict[key] = norm_dir

    return new_state_dict

def get_random_base_direction(state_dict, layer=None, position=None):
    """Get random direction, basically a very sparse vector, positive/negative
    in 1 place and 0 everywhere"""
    new_state_dict = {}
    layer_keys = [key for key, value in state_dict.items()
                  if isinstance(value, torch.Tensor) and value.dim() > 1]

    if layer is None:
        layer = np.random.choice(layer_keys)

    for idx, (name, value) in enumerate(state_dict.items()):
        if isinstance(layer, int) and layer != idx:
            new_state_dict[name] = value
            continue
        elif isinstance(layer, str) and layer != name:
            new_state_dict[name] = value
            continue

        tensor = copy.deepcopy(value)
        if position is None:
            shape = tensor.shape
            position = tuple([np.random.randint(each) for each in shape])

        tensor[position] = tensor.norm()
        new_state_dict[name] = tensor

    return new_state_dict

def get_difference_state(state1, state2):
    """Get state1 - state2"""
    diff_state = {}
    for name, value in state1.items():
        diff_state[name] = value - state2[name]

    return diff_state

def update_state_1d(state_dict, diff_state, alpha):
    """Return state_dict + diff_state * alpha"""
    new_state = {}
    for key, value in state_dict.items():
        new_state[key] = value + diff_state[key] * alpha

    return new_state

def update_state_2d(state_dict, diff1, diff2, alpha1, alpha2):
    """Return state_dict + diff1 * alpha1 + diff2 * alpha2"""
    new_state = {}
    for key, value in state_dict.items():
        new_state[key] = value + diff1[key] * alpha1 + diff2[key] * alpha2

    return new_state

def plot_single_image_1d(
    image_path='images/tiger_incorrect.png', size=224, class_=292, debug=True):
    """Given a trained model and an image, draw the qqloss landscape of the
    model weight along a random 1D weight direction.

    For tiger, the correct class is 292.
    """

    # setup model and losses
    model = models.resnet18(pretrained=True)
    model.eval()
    loss = nn.CrossEntropyLoss()

    # setup the image
    image = cv2.imread(image_path)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    image = cv2.resize(image, (size, size))

    image_torch = NORMALIZE(torch.FloatTensor(image / 255))
    image_torch = image_torch.transpose(0, 2).transpose(1, 2).unsqueeze(0)

    # set up the linear interpolation
    weight = copy.deepcopy(model.state_dict())  # w/o deepcopy, `weight` will change
    direction = get_random_direction(weight)
    diff = get_difference_state(direction, weight)

    # gather the losses
    alpha = list((np.arange(100)-50) / 100)
    # alpha = list((np.arange(10)-5) / 10)
    losses = []
    debugs = []
    for each_alpha in tqdm(alpha):
        # each_alpha = 0.5
        inter_weight = update_state_1d(weight, diff, each_alpha)
        model.load_state_dict(inter_weight)
        model.eval()
        with torch.no_grad():
            # 292
            pred = model(image_torch).detach()
            l = loss(pred, torch.tensor([class_], dtype=torch.long)).detach().item()
            if debug:
                pred = IDX_TO_CLASS[np.argmax(pred.data.numpy())]
                print_debug = '{}, {}, {}'.format(each_alpha, l, pred)
                tqdm.write(print_debug)
                debugs.append(print_debug)
        losses.append(l)

    fig = plt.figure()
    plt.plot(alpha, losses)
    fig.canvas.draw()

    plot = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
    plot = plot.reshape(fig.canvas.get_width_height()[::-1] + (3,))

    cv2.imwrite(os.path.join('logs', '1d_{}_'.format(class_) + os.path.basename(image_path)),
                cv2.cvtColor(plot, cv2.COLOR_RGB2BGR))
    fig.show()

    if debug:
        with open(os.path.join('logs', '1d_{}_.txt'.format(class_)), 'w') as f_out:
            f_out.write('\n'.join(debugs))

def plot_single_image_2d(
    image_path='images/tiger_incorrect.png', class_=292, size=224, debug=True,
    save_diff=True):
    """Given a trained model and an image, draw the loss landscape of the
    model weight along a random 2D weight direction"""

    # setup model and losses
    model = models.resnet18(pretrained=True)
    model.eval()
    loss = nn.CrossEntropyLoss()

    # setup the image
    image = cv2.imread(image_path)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    image = cv2.resize(image, (size, size))

    image_torch = NORMALIZE(torch.FloatTensor(image / 255))
    image_torch = image_torch.transpose(0, 2).transpose(1, 2).unsqueeze(0)

    # set up the linear interpolation
    weight = copy.deepcopy(model.state_dict())  # w/o deepcopy, `weight` will change
    direction1, direction2 = get_random_direction(weight), get_random_direction(weight)
    diff1 = get_difference_state(direction1, weight)
    diff2 = get_difference_state(direction2, weight)

    with save_diff:
        obj = {
            'diff1': diff1,
            'diff2': diff2
        }
        torch.save(obj, os.path.join('logs/2d.john'))

    # gather the losses
    alpha1 = list((np.arange(11)-5) / 10)
    alpha2 = list((np.arange(11)-5) / 10)
    # alpha1 = list((np.arange(110)-50) / 100)
    # alpha2 = list((np.arange(110)-50) / 100)
    X, Y = np.meshgrid(alpha1, alpha2)
    losses = []
    _X, _Y = X.ravel(), Y.ravel()
    debugs = []

    for each_alpha1, each_alpha2 in tqdm(list(zip(_X, _Y))):
        inter_weight = update_state_2d(weight, diff1, diff2, each_alpha1, each_alpha2)
        model.load_state_dict(inter_weight)
        model.eval()
        with torch.no_grad():
            pred = model(image_torch).detach()
            l = loss(pred, torch.tensor([class_], dtype=torch.long)).detach().item()
            l = math.log(l, 10)
            if debug:
                pred = np.argmax(pred.data.numpy())
                pred_string = IDX_TO_CLASS[pred]
                print_debug = '{}, {}, {}, {}, {}'.format(each_alpha1, each_alpha2, l, pred_string, pred)
                tqdm.write(print_debug)
                debugs.append(print_debug)
        losses.append(l)

    losses = np.array(losses).reshape(X.shape)
    fig = plt.figure()
    plt.contourf(X, Y, losses, cmap='RdGy')
    plt.colorbar()
    fig.canvas.draw()

    plot = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
    plot = plot.reshape(fig.canvas.get_width_height()[::-1] + (3,))

    cv2.imwrite(os.path.join('logs', '2d_{}_'.format(class_) + os.path.basename(image_path)),
                cv2.cvtColor(plot, cv2.COLOR_RGB2BGR))
    fig.show()

    if debug:
        with open(os.path.join('logs', '2d_{}.txt'.format(class_)), 'w') as f_out:
            f_out.write('\n'.join(debugs))
        with open('tmp.txt', 'w') as f_out:
            _tmp = [each.split(',')[-1].strip() for each in debugs]
            f_out.write('\n'.join(_tmp))

def plot_interpolate_image(
        image1_path='images/tiger_correct.png',
        image2_path='images/tiger_incorrect.png', size=224, debug=True):
    """This is very the same as the above, but interpolate between 2 image
    points rather than 2 weight points"""

    # setup model and loss
    model = models.resnet18(pretrained=True)
    model.eval()
    loss = nn.CrossEntropyLoss()

    # get image1
    image1 = cv2.imread(image1_path)
    image1 = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)
    image1 = cv2.resize(image1, (size, size))

    image1_torch = NORMALIZE(torch.FloatTensor(image1 / 255))
    image1_torch = image1_torch.transpose(0, 2).transpose(1, 2).unsqueeze(0)

    # get image2
    image2 = cv2.imread(image2_path)
    image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2RGB)
    image2 = cv2.resize(image2, (size, size))

    image2_torch = NORMALIZE(torch.FloatTensor(image2 / 255))
    image2_torch = image2_torch.transpose(0, 2).transpose(1, 2).unsqueeze(0)

    # get the difference
    image_diff_torch = image2_torch - image1_torch

    losses = []
    alpha = list(np.linspace(-1.5, 1.5, 40))
    # alpha = [-1, -0.5, 0, 0.5, 1]
    for each_alpha in tqdm(alpha):
        image_inter = image1_torch + each_alpha * image_diff_torch
        with torch.no_grad():
            pred = model(image_inter).detach()
            l = loss(pred, torch.tensor([292], dtype=torch.long)).detach().item()
            if debug:
                pred = IDX_TO_CLASS[np.argmax(pred.data.numpy())]
                tqdm.write('{}, {}, {}'.format(each_alpha, l, pred))
        losses.append(l)

    fig = plt.figure()
    plt.plot(alpha, losses)
    fig.canvas.draw()

    plot = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
    plot = plot.reshape(fig.canvas.get_width_height()[::-1] + (3,))

    cv2.imwrite(
        os.path.join('logs', 'inter.png'),
        cv2.cvtColor(plot, cv2.COLOR_RGB2BGR))

def plot_test(
    image_path='images/tiger_incorrect.png', size=224, class_=292, debug=True):
    """Given a trained model and an image, draw the qqloss landscape of the
    model weight along a random 1D weight direction.

    For tiger, the correct class is 292.
    """

    # setup model and losses
    model = models.resnet18(pretrained=True)
    model.eval()
    loss = nn.CrossEntropyLoss()

    # setup the image
    image = cv2.imread(image_path)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    image = cv2.resize(image, (size, size))

    image_torch = NORMALIZE(torch.FloatTensor(image / 255))
    image_torch = image_torch.transpose(0, 2).transpose(1, 2).unsqueeze(0)

    weight = copy.deepcopy(model.state_dict())  # w/o deepcopy, `weight` will change
    predictions = []

    for _ in range(5):
        # set up the linear interpolation
        direction = get_random_direction(weight)
        diff = get_difference_state(direction, weight)

        # gather the losses
        alpha = list((np.arange(100)-50) / 100)
        # alpha = list((np.arange(10)-5) / 10)
        losses = []
        debugs = []
        preds = []
        for each_alpha in tqdm(alpha):
            # each_alpha = 0.5
            inter_weight = update_state_1d(weight, diff, each_alpha)
            model.load_state_dict(inter_weight)
            model.eval()
            with torch.no_grad():
                # 292
                pred = model(image_torch).detach()
                l = loss(pred, torch.tensor([class_], dtype=torch.long)).detach().item()
                if debug:
                    pred = IDX_TO_CLASS[np.argmax(pred.data.numpy())]
                    preds.append(pred)
                    print_debug = '{}, {}, {}'.format(each_alpha, l, pred)
                    tqdm.write(print_debug)
                    debugs.append(print_debug)
            losses.append(l)
        predictions.append(preds)

    for idx, p in enumerate(predictions):
        with open('tmp_{}.txt'.format(idx), 'w') as f_out:
            f_out.write('\n'.join(p))

if __name__ == '__main__':
    plot_test(debug=True)
    # plot_interpolate_image()