import string
import random

WORDLIST_FILENAME = "words.txt"

def load_words():
    """
    Returns a list of valid words. Words are strings of lowercase letters.

    Depending on the size of the word list, this function may
    take a while to finish.
    """
    print("Loading word list from file...")
    # inFile: file
    inFile = open(WORDLIST_FILENAME, 'r')
    # line: string
    line = inFile.readline()
    # wordlist: list of strings
    wordlist = line.split()
    print("  ", len(wordlist), "words loaded.")
    return wordlist

# Load the list of words into the variable wordlist so that it can be accessed from anywhere in the program
wordlist = load_words()

def choose_word(wordlist):
    """
    wordlist (list): list of words (strings)
    Returns a word from wordlist at random
    """
    return random.choice(wordlist)

def get_guessed_word(secret_word,updated_word):
    """
    secret_word - string of lower case letters
    updated_word - list of lower case letters that have not been guessed yet
    Checks which letters in secret word have been guessed.
    Return guessed letters and "_ " for letters not guessed yet in a string. (in same order as the letters in secret_word)
    """
    word_array=[]
    index2=0
    for index in range(len(secret_word)):
        if index2<len(updated_word) and secret_word[index]==updated_word[index2]: #Letter not guessed yet
            word_array.append("_ ")
            index2+=1
        else:
            word_array.append(secret_word[index])
    return ''.join(word_array)

def get_available_letters(already_guessed):
    """
    already_guessed - list of lower_case letters already guessed incorrectly by user
    Returns a string of all lower case English letters that are not in already guessed
    """
    list_alphabet=list(string.ascii_lowercase)
    for letter in string.ascii_lowercase:
        if letter in already_guessed:
            list_alphabet.remove(letter)
    return ''.join(list_alphabet)

def warning_messages(string,guesses,warnings,secret_word,updated_word):
    """
    string - An additional string to print to the user.
    guesses - number of guesses left
    warnings - number of warnings left
    secret_word - the string that the user is trying to guess
    updated_word - the letters that have not been guessed yet by the user.
    Prints a message "Oops! " + string + number of warnings left if any: + the string that's been guessed so far
    Subtracts one from warning. If no warnings left, subtract one from guess.
    """
    if warnings==0:
        guesses-=1
        print("Oops!  " + string + "  You don't have any warnings left, so you lose a guess: ",get_guessed_word(secret_word,updated_word))
    else:
        warnings-=1
        print("Oops!  " + string + "  You have",warnings,"warnings left: ",get_guessed_word(secret_word,updated_word))
    return (guesses,warnings)

def match_with_gaps(my_word,other_word,already_guessed):
    """
    my_word - what is guessed so far of the word (with blanks Ex: t _ _ t)
    other_word - normal English word
    already_guessed - list of letters that have already been guessed by user
    Returns true if my word matches the corresponding letters of other_word, and the words match length. Otherwise returns false.
    """
    match=True
    index=0
    other_word=other_word.strip() #Get rid of leading space characters
    my_word=my_word.replace(" ","") #Remove spaces in my word
    if len(my_word) != len(other_word): #Words have different lengths
        return False
    while match and index<len(other_word):
        if my_word[index]!="_":
            if other_word[index] != my_word[index]: #Letters don't match
                match=False
        else:
            if other_word[index] in already_guessed:
                match=False #Other word contains a letter that was already guessed.
            if other_word[index] in my_word[index:len(my_word)]:
                match=False #Letter was guessed correctly and it appears later in word. So this word is not possible. (guesses happen left to right)
        index+=1
    return match

def show_possible_matches(my_word,already_guessed):
    """
    my_word - what is guessed so far of the word (with blanks Ex: t _ _ t)
    already_guessed - list of letters that have already been guessed by user
    Prints out a list of possible matches in the wordlist.
    """
    matches=[] #List of words that might be a match
    for word in wordlist:
        if match_with_gaps(my_word,word,already_guessed):
            matches.append(word)
    if len(matches)==0:
        return "No matches found"
    else:
        return ' '.join(matches)

def unique_char(word):
    """
    word - string of characters in the alphabet
    Returns how many unique characters are in the word.
    """
    unique=[]
    for letter in word:
        if letter not in unique:
            unique.append(letter)
    return len(unique)

def hangman_duplicates(secret_word):
    """
    secret_word - string of lower case English characters
    Plays the game hangman with a user. User must guess the letters in secret word to win.
    This game forces you to guess every letter even if there are two of the same letter in the word.
    This version of hang man gives more specific hints. It eliminates possibilities from the already guessed list.
    * At the start of the game, let the user know how many
      letters the secret_word contains and how many guesses s/he starts with.

    * The user should start with 6 guesses

    * Before each round, you should display to the user how many guesses
      s/he has left and the letters that the user has not yet guessed.

    * Ask the user to supply one guess per round. Remember to make
      sure that the user puts in a letter!

    * The user should receive feedback immediately after each guess
      about whether their guess appears in the computer's word.

    * After each guess, you should display to the user the
      partially guessed word so far.
    """
    secret_word=secret_word.lower()
    num_guesses=6 #Max guesses allowed for user.
    warnings=3    #Max number of warnings allowed
    updated_word=list(secret_word) #Make a copy of the word. The copy contains an array of characters
    already_guessed=[] #Holds letters that user guessed multiple times even though they already got it wrong
    print("Welcome to the game of hangman!")
    print("I am thinking of a word that is",len(secret_word),"letters long.")
    print("You have",num_guesses,"guesses and",warnings,"warnings total.")

    #Loop until the user used all guesses or they guessed the correct word.
    while (num_guesses>0 and len(updated_word)>0):
        print("-------------")
        print("You have",num_guesses," guesses left.")
        print("Available letters: ",get_available_letters(already_guessed))
        guess=input("Please guess a letter:  ")
        guess=guess.lower() #Make the guess lower case
        if guess=="*": #User wants a hint.
            print("Possible word matches are:")
            print(show_possible_matches(get_guessed_word(secret_word,updated_word),already_guessed))
        elif not guess.isalpha():
            message="You entered an invalid character (only alphabetic characters allowed)."
            (num_guesses,warnings)=warning_messages(message,num_guesses,warnings,secret_word,updated_word)
        elif (guess in updated_word):
            updated_word.remove(guess) #Remove the guessed letters.
            print("Good guess: ",get_guessed_word(secret_word,updated_word))
        elif guess in already_guessed: #Letter already guessed once incorrectly
            message="You already guessed that letter."
            (num_guesses,warnings)=warning_messages(message,num_guesses,warnings,secret_word,updated_word)
        #Guess is in secret word, but user already guessed the correct number of this letter.
        elif (guess in secret_word):
            already_guessed.append(guess) #Add to the already guessed list (if user guesses again it results in a warning rather than a missed guess)
            print("Oops! You already guessed the correct number of this letter: ",get_guessed_word(secret_word,updated_word))
            num_guesses-=1
        else:
            already_guessed.append(guess)
            print("Oops! That letter is not in my word:  ",get_guessed_word(secret_word,updated_word))
            if guess in "aeiou":
                num_guesses-=2 #Lose an extra guess (two guesses) if the user guessed a vowel.
            else:
                num_guesses-=1 #Lose one guess if the user guessed a consonant.

    print("-------------")
    if len(updated_word)==0: #All letters were guessed
        print("Congratulations! You won the game of hangman!")
        #Score is number of guesses left multiplied by the number of unique characters.
        score=num_guesses*unique_char(secret_word)
        print("Your score is",str(score)+".")
    else:
        print("Sorry, you lost of the game of hangman. The word was",secret_word+".")

if __name__ == "__main__":
    secret_word = choose_word(wordlist)
    hangman_duplicates(secret_word)


import logging
import yaml
import io
import appdeploy.bash as bash
import appdeploy.executor as e

class AppDeploy(object):
    def __init__(self, file, action):
        self.file = file
        self.action = action

    def process(self):
        logging.info("Starting Process")

        # Read YAML file
        with open(self.file, 'r') as stream:
            environment = yaml.load(stream)
            logging.debug(environment)

        #build command list based on action
        cmd_list = bash.cmds[self.action].__call__(environment)
        logging.debug(cmd_list)

        logging.debug("start executor")
        e.proc(environment["hosts"], cmd_list)


import spacy
from kg_detective import PKG_INDICES
from tests.lib import *
import json
from importlib import import_module
import os.path, pkgutil

lang = "es"
pkg = PKG_INDICES[lang]

def sen_kg(sentences, nlp, rules):
  content = {}
  for r in rules:
    content[r] = []

  for s in sentences:
    doc = nlp(s)
    for r in rules:
      info = {
        "sentence": doc.text,
        r: json.dumps([t for t in doc._.kg[r]])
      }
      content[r].append(info)
  # write to multiple files
  for k, v in content.items():
    write_to_csv(["sentence", k], v, csvfile="tbr/{}/kg_{}.csv".format(lang, k))

def test_kg_tbr_gen():
  #sentences = read_json('./S0405.json')
  data = get_lang_sens(lang)
  nlp = spacy.load(pkg)
  nlp.add_pipe('kg', config={"labels": ["NOUN"]})
  rules = nlp.get_pipe("kg").rules
  sentences = sum([sens for _, sens in data.items()], [])
  sen_kg(sentences, nlp, rules)


import tkinter
from tkinter import *
import time
import datetime
import pyaudio
import socket
import threading
import os

dir_path = os.path.dirname(os.path.realpath(__file__))+'\\elec.ico'

master = Tk()
master.iconbitmap(r'{}'.format(dir_path))
master.geometry('500x250')
master.title('Electors Sender App')
master.configure(background='orange')

ip_host = StringVar(master=master)
ip_port = IntVar(master=master)
emergencyVar = BooleanVar(master)
liveVar = BooleanVar(master)
bellVar = BooleanVar(master)
stopFlagVar = BooleanVar(master)
isConnected = StringVar(master)
#------------------------------------------------------------------------------------------------------------------------
pausing = False

is_live = False

class Live_Client(object):
    def __init__(self, ip, port):
        super(Live_Client, self).__init__()
        self.ip = ip
        self.port = port
        self.frames = []
        self.addresses = (self.ip, self.port)
        self.resume_playing()
        FORMAT = pyaudio.paInt16
        CHUNK = 1024
        self.chunk = CHUNK
        CHANNELS = 2
        RATE = 44100
        datetime.datetime.now().strftime("%H:%M:%S.%f")
        self.Audio = pyaudio.PyAudio()
        self.stream = self.Audio.open(format=FORMAT,
                            channels=CHANNELS,
                            rate=RATE,
                            input=True,
                            frames_per_buffer=CHUNK,
                            )
        self.AudioThread = threading.Thread(target=self.record,daemon=True)
        self.udpThread = threading.Thread(target=self.udpStream, daemon=True)
        self.AudioThread.start()
        self.udpThread.start()

    def udpStream(self):
        udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.z1 = udp
        while True:
            if pausing:
                break
            while True:
                if pausing:
                    break
                if len(self.frames) > 0:
                    frames_mod = self.frames.pop(0)
                    self.z1.sendto(frames_mod, self.addresses)
        print("closing socket")
        udp.close()

    def record(self):
        while True:
            if pausing:
                break
            self.frames.append(self.stream.read(self.chunk))
        print("closing recording")
        self.stream.stop_stream()
        self.stream.close()
        self.Audio.terminate()

    def stop_playing(self):
        global pausing
        pausing = True

    def resume_playing(self):
        global pausing
        pausing = False
#------------------------------------------------------------------------------------------------------------------------
class sender_gui(object):
    def __init__(self):
        super(sender_gui,self).__init__()
        self.f = "name.txt"

        self.b0 = Button(text="Settings", fg='black', bg="white", relief='solid', font=('arial', 8, 'bold'), width='6',
                    height='1', command=self.show_settings)
        self.b1 = Button(master, text='Emergency Alarm', command=self.alarm, fg='black', bg='white', relief='solid',
                    width=20,
                    font=('arial', 19, 'bold'))
        # b2 = Button(master, text="Browse", command=self.browse_button, fg='black', bg="white", relief='solid', width=6,
        #             font=('arial', 12, 'bold'), height=2)
        self.b3 = tkinter.Button(master, text='Live Anouncement', command=self.live, fg='black', bg='white', relief='solid',
                    width=20,
                    font=('arial', 19, 'bold'))
        self.b4 = tkinter.Button(master, text='Stop', command=self.stop, fg='black', bg='white', width=12,
                    font=('arial', 10, 'bold'))
        self.b5 = Button(master, text='Hourly Bell', command=self.bell, fg='black', bg='white', relief='solid', width=20,
                    font=('arial', 19, 'bold'))

        self.b0.place(x=0, y=0)
        self.b1.place(x=90, y=10)
        # b2.place(x=415, y=10)
        self.b3.place(x=90, y=150)
        self.b4.place(x=280, y=215)
        self.b5.place(x=90, y=80)

        self.b3['state'] = 'disabled'
        self.b1['state'] = 'disabled'
        self.b5['state'] = 'disabled'
        isConnected.set('Not yet Connected!')
        ip_host.set('0.0.0.0')
        ip_port.set(8080)
        self.show_clk()
        mainloop()

    def show_settings(self):
        self.top = tkinter.Toplevel(master=master)
        self.top.iconbitmap(r'{}'.format(dir_path))
        L1 = Label(self.top, text="IP Address: ", font=('arial', 10, 'bold'), bg='orange')
        L1.place(x=25, y=10)
        L2 = Label(self.top, text="Port Address: ", font=('arial', 10, 'bold'), bg='orange')
        L2.place(x=25, y=50)
        L3 = Label(self.top, textvariable=isConnected, bg='white', fg='blue' )
        L3.place(x=30, y=100)
        E1 = Entry(self.top, bd=5, textvariable=ip_host, )
        E1.place(x=130, y=10)
        E2 = Entry(self.top, bd=5, textvariable=ip_port)
        E2.place(x=130, y=50)
        set_button = Button(self.top, text='Set', command=self.connect_ip, fg='black', bg='white', relief='solid',
                            width=6, height=2,
                            font=('arial', 10, 'bold'))
        set_button.place(x=210, y=90)
        self.top.geometry('340x150')
        self.top.configure(background='orange')
        self.top.title("Settings")
        self.top.mainloop()

    def connect_ip(self):
        host = ip_host.get()
        port = ip_port.get()
        threading.Thread(target=self.init_connect, args=(host,port,), daemon=True).start()

    def init_connect(self, host, port):
        print("Connecting at IP address: "+host+"   Port: "+str(port))
        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect((host, port))
        except:
            print("Connection unsuccessful. Try again")
            self.off_limit_button()
        else:
            print("Connected at IP adress: "+host+"   Port: "+str(port))
            self.top.withdraw()
            self.check_connection()

    def check_connection(self):
        if liveVar:
            self.b3['state'] = 'normal'
        if emergencyVar:
            self.b1['state'] = 'normal'
        if bellVar:
            self.b5['state'] = 'normal'
        isConnected.set('Connected successfully!')

    def off_limit_button(self):
        self.b3['state'] = 'disabled'
        self.b1['state'] = 'disabled'
        self.b5['state'] = 'disabled'
        isConnected.set('Failed to connect! Try again')

    def show_clk(self):
        self.clock = Label(master, font=('arial', 10, 'bold'), fg='black', bg='white', width=12)
        self.clock.place(x=120, y=215)
        self.time1()

    def time1(self):
        timenow = time.strftime('%H:%M:%S %p')
        self.clock.config(text=timenow)
        self.clock.after(200, self.time1)

    def exit1(self):
        exit()

    def stop(self):
        global pausing, is_live
        pausing = True
        MESSAGE1 = 'stop'
        self.sock.send(bytes(MESSAGE1, 'ascii'))
        if is_live:
            self.b3['state'] = 'disabled'
            is_live = False
        threading.Thread(target=self.disable_timer, daemon=True).start()

    def disable_timer(self):
        i = 0
        sec = 5
        while i < sec:
            time.sleep(1)
            i += 1
        self.b3['state'] = 'normal'

    def alarm(self):
        global pausing
        pausing = True
        MESSAGE2 = 'alarm'
        self.sock.send(bytes(MESSAGE2, 'ascii'))
        time.sleep(0.1)

    def bell(self):
        global pausing
        pausing = True
        MESSAGE3 = 'bell'
        self.sock.send(bytes(MESSAGE3, 'ascii'))
        time.sleep(0.1)

    def live(self):
        ip = ip_host.get()
        port = ip_port.get()
        global is_live
        is_live = True
        MESSAGE3 = 'live'
        self.sock.send(bytes(MESSAGE3, 'ascii'))
        self.b3['state'] = 'disabled'
        Live_Client(ip, port)
        time.sleep(0.1)

#------------------------------------------------------------------------------------------------------------------------
if __name__ == "__main__":
    run1 = sender_gui()


class Solution:
    def maximumBinaryString(self, binary: str) -> str:
        zero = 0
        first = 0
        while first  < len(binary)  and binary[first] == '1':
            first += 1
        for i in binary:
            if i == '0':
                zero += 1
        ones = len(binary) - zero - first
        if zero > 0:
            return '1'*(zero-1 + first) + '0' + '1'*ones
        else:
            return '1'*(first)


from django.forms import ModelForm
from .models import ContactModel

class ContactForm(ModelForm):
    class Meta:
        model = ContactModel
        fields = ['name', 'e_mail', 'message']
        labels = {
            'name': 'Name:',
            'e_mail': 'E-mail:',
            'message': 'Message:'
        }


from ..models import TipoModulo, Modulo
from django import template
from django.urls import reverse

register = template.Library()

@register.simple_tag
def modulo_for_groups(request, tm):
    return [modulo for modulo in tm.modulos.all() if request.user.groups.all()[0] in modulo.grupos.all()]

@register.simple_tag
def tipo_menu(request):
    tipos = [tipo for tipo in TipoModulo.objects.filter(padre_tipo=None) if len(modulo_for_groups(request,tipo))>0]
    #tipo = TipoModulo.objects.filter(padre_tipo=None)
    return tipos

@register.simple_tag
def is_active_tm(request):
    try:
        modulos = Modulo.objects.all()
        for m in modulos:
            if m.get_url() == request.path:
                return m.tipo
        return None
    except:
        return None

@register.simple_tag
def is_papa(hijo, papa):
    try:
        if hijo.padre_tipo == papa:
            return True
        return False
        #print(f"{}")
        #print(f"{papa}")
        # if hijo in papa.padre_tipo.all():
        #     print(f"Si soy papa- {hijo}")
        #     return True
        # print(f'desde is_papa - {hijo}')
        # return False
    except:
        return False

@register.simple_tag
def activo(request, urlconfi):
    try:
        url_reverse = reverse(urlconfi)
        if request.path == url_reverse:
            return "active"
        return 'no-active'
    except:
        return "no-active"


import sys
from socket import *
from threading import Thread
from HttpRequest import httpReq
from struct import unpack

def atol(a):
    return unpack(">L", inet_aton(a))[0]

serverSocket = socket(AF_INET, SOCK_STREAM)

portNum = 12000
threadNum = 1

serverSocket.bind(("", portNum))
serverSocket.listen(1)

while True:
    print('The server is ready to receive')
    connSocket, addr = serverSocket.accept()
    print(f"sender subnet address = {addr[0][:-2]}, host: {addr[0][-1]}")

    addrs = atol(addr[0])
    mask = atol("255.255.255.0")
    lo = atol("192.168.0.0")
    hi = atol("192.168.0.255")
    prefix = addrs & mask

    if (lo <= prefix <= hi):
        th = Thread(target=httpReq, args=(connSocket, threadNum))
        print(f"\nThread {threadNum} started\n")
        th.start()
        threadNum = threadNum + 1
    else:
        print(f"Access Failed, IP=({addr[0]})")
        continue

portNum.close()
sys.exit()


#!/usr/bin/env python

import roslib
import rospy
import math
import numpy
import tf
import tf.transformations as tft
import geometry_msgs.msg
from gazebo_msgs.srv import GetLinkState
from gazebo_msgs.msg import LinkState
#from gazebo_msgs.msg import GetLinkState
from gazebo_msgs.srv import GetLinkStateRequest
from geometry_msgs.msg import Pose
from geometry_msgs.msg import PoseStamped
#from gazebo_msgs.msg import *
#import gazebo_msg.srv

if __name__ == '__main__':
    rospy.init_node('tf_listener')

    listener = tf.TransformListener()
    get_state_service = rospy.ServiceProxy('/gazebo/get_link_state', GetLinkState)
    rate = rospy.Rate(50.0)
    pub = rospy.Publisher('/link4_under_aptag0', PoseStamped, queue_size=1)
    while not rospy.is_shutdown():
        try:
            t, r = listener.lookupTransform('/link4', '/camera_fr_link', rospy.Time(0))
        except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
            #rospy.error("failed to listen transform from '/link4' to '/camera_fr_link'")
            continue
        offset_to_link4 = numpy.matrix(tft.quaternion_matrix(r))
        offset_to_link4[0,3] = t[0]
        offset_to_link4[1,3] = t[1]
        offset_to_link4[2,3] = t[2]
        print('offset_to_link4 = ',offset_to_link4)

        rospy.wait_for_service('/gazebo/get_link_state')
        #link = GetLinkStateRequest()
        #link = LinkState()
        #link.link_name = 'link4'
        #link.reference_frame = 'Apriltag0'
        links = get_state_service("link4", "Apriltag0")
        linkstate = links.link_state
        link4matrix = tft.quaternion_matrix(numpy.array([linkstate.pose.orientation.x, linkstate.pose.orientation.y, linkstate.pose.orientation.z, linkstate.pose.orientation.w]))
        link4matrix[0,3] = linkstate.pose.position.x
        link4matrix[1,3] = linkstate.pose.position.y
        link4matrix[2,3] = linkstate.pose.position.z

        T = numpy.array(numpy.dot(link4matrix, offset_to_link4))
        print('T = ',T)

        p = Pose()
        # # Belows to check the correctness
        # R=T[:3,:3].transpose()
        # t = numpy.array([[-T[0,3]], [-T[1,3]], [-T[2,3]]])
        # t = R.dot(t)
        # p.position.x = t[0]
        # p.position.y = t[1]
        # p.position.z = t[2]
        # ps.header.frame_id = "camera_fr_link"
        p.position.x = T[0,3]
        p.position.y = T[1,3]
        p.position.z = T[2,3]
        R=T[:3,:3]
        roll, pitch, yaw = tft.euler_from_matrix(R)
        q = tft.quaternion_from_euler(roll, pitch, yaw)
        p.orientation.x = q[0]
        p.orientation.y = q[1]
        p.orientation.z = q[2]
        p.orientation.w = q[3]
        ps = PoseStamped()
        ps.pose = p
        ps.header.stamp =  rospy.Time.now()
        ps.header.frame_id = "Apriltag0"
        pub.publish(ps)
        #tf_brocast(ps,q)

        rate.sleep()


# -*- coding: utf-8 -*-
"""
Created on Mon Mar 16 17:35:11 2020

@author: pit
"""
#WYKRESY

import matplotlib.pyplot as plt
import numpy as np
from scipy import interpolate

x = np.linspace(0,10)
y = np.sin(x)

plt.plot(x,y)

x = np.linspace(0, 10, 5)
y = np.cos(x**1/3)

plt.scatter(x,y)

f1 = interpolate.interp1d(x, y, kind='linear')
f2 = interpolate.interp1d(x, y, kind='cubic')
x2 = np.linspace(0, 10, 50)

plt.figure() # create a plot figure
plt.subplot(2, 1, 1) # (rows, columns, panel number)
plt.plot(x, np.sin(x))
plt.subplot(2, 1, 2)
plt.plot(x, np.cos(x));

#style
print(plt.style.available)
plt.style.use('ggplot')

#tworzenie nowej figury
x = np.linspace(0, 10)
y = np.sin(x)
y2 = np.cos(x)
fig, (ax1, ax2) = plt.subplots(2, 1)
ax1.plot(x, y)
ax2.plot(x, y2)

#dwa wykresy na jednej osi
import math
fig, ax = plt.subplots()
ax.plot(x,y)
ax.set(xlim=[0, 2*math.pi], xlabel='x', ylabel='y',
title='sin(x)')
ax.axhline(0.5, ls='--', color='r', linewidth=3, alpha=0.2)

#plt.axis([-1, 11, -1.5, 1.5]);
#dwa wykresy na jednej figurze
f, (ax1, ax2) = plt.subplots(2, 1, sharex=True)
ax1.plot(x, y)
ax1.set_title('X axis shared')
x2 = np.linspace(-10, 0)
ax2.scatter(x2, y)

#zapisywanie figury
fig.canvas.get_supported_filetypes()
fig.savefig('sin.png', transparent=False, dpi=120, bbox_inches='tight')
plt.plot(x, np.sin(x), '-')
plt.plot(x, np.sin(x), color='blue') #ustawienie koloru
plt.plot(x, x + 5, linestyle='--') #lina przerywana
plt.plot(x, x + 1, '-g')
plt.plot(x, np.sin(x))
plt.xlim(-1, 11)
plt.ylim(-1.5, 1.5)
plt.xlabel('x')
plt.ylabel('sin(x)');
plt.plot(x, np.sin(x), '-g', label='sin(x)')
plt.axis('equal')
plt.legend();

#zapisywanie figury
fig = plt.figure()
plt.scatter(x, y, marker='x');
data = np.random.randn(50)
plt.hist(data, bins=5, alpha=0.9,
histtype='stepfilled', color='orange',
edgecolor='none')
fig.savefig('D:\MachineLearningPandaIT\Materials\my_figure.png')

#scipy
import matplotlib.pyplot as plt
from scipy import interpolate
import numpy as np
x = np.linspace(0, 10, 5)
y = np.cos(x**1/3)
f1 = interpolate.interp1d(x, y,kind = 'linear')
f2 = interpolate.interp1d(x, y, kind = 'cubic')
x2 = np.linspace(0, 10, 50)
plt.plot(x, y, 'o', x, f1(x), ':', x2, f2(x2), '-')
plt.legend(['real data', 'linear', 'cubic'], loc = 'best')
plt.show()


import datetime
import json
import os

from dotenv import load_dotenv
from pydantic import BaseModel
import snakemd
from snakemd import Inline, Paragraph, Raw

from config import get_config
from utils import get_valid_filename

#
# Models
#

class Message(BaseModel):
    speaker: str
    message: str

    def __str__(self) -> str:
        return f"### {self.speaker}: {self.message}"

class Session(BaseModel):
    name: str
    timestamp: str
    scenario: str
    red_bot: str
    red_directive: str
    blue_bot: str
    blue_directive: str
    first_speaker: str
    prompt: str
    tokens: int = 0
    cost: float = 0.0
    messages: list[Message] = []

#
# Functions
#

def _mk_session_filename(name: str, dir: str) -> str:
    name = get_valid_filename(name)
    session_file = os.path.join(dir, f"{name}.json")
    return session_file

def session_save(session: Session, session_dir: str) -> None:
    os.makedirs(session_dir, exist_ok=True)
    session_file = _mk_session_filename(session.name, session_dir)
    with open(session_file, "w") as f:
        json.dump(session.dict(), f, indent=2)

def session_rename(session: Session, session_dir: str, new_name: str) -> None:
    os.makedirs(session_dir, exist_ok=True)
    session_file = _mk_session_filename(session.name, session_dir)
    new_session_file = _mk_session_filename(new_name, session_dir)
    os.rename(session_file, new_session_file)

def session_dir(session_dir: str) -> list[str]:
    os.makedirs(session_dir, exist_ok=True)
    sessions = []
    for file in os.listdir(session_dir):
        if file.endswith(".json"):
            session = Session.parse_file(os.path.join(session_dir, file))
            sessions.append(session.name)
    sessions.sort()
    return sessions

def session_purge(session_dir: str, exclude: Session) -> None:
    for file in os.listdir(session_dir):
        if file.endswith(".json"):
            filename = file.removesuffix(".json")
            session = Session.parse_file(os.path.join(session_dir, file))
            if session.name != exclude.name and len(session.messages) < 2:
                os.remove(os.path.join(session_dir, file))

def session_load(name: str, session_dir: str) -> Session:
    session_file = _mk_session_filename(name, session_dir)
    session = Session.parse_file(session_file)
    return session

def _mk_transcript_filename(
    dir: str,
    name: str,
    timestamp: str,
) -> str:
    # ensure outdir exists
    os.makedirs(dir, exist_ok=True)
    name = get_valid_filename(name)
    transcript_file = os.path.join(dir, f"{name} {timestamp}")
    return transcript_file

def session_transcript_save(
    session: Session,
    dir: str,
) -> None:
    transcript_file = _mk_transcript_filename(
        dir,
        session.name,
        session.timestamp,
    )

    # parse the timestamp
    timestamp = datetime.datetime.strptime(
        session.timestamp,
        get_config().DATETIME_FORMAT,
    )

    doc = snakemd.new_doc()
    doc.add_heading(session.name, 1)
    doc.add_paragraph(
        f"A InsightCrafter™ transcript between {session.red_bot} (red) and {session.blue_bot} (blue) on {timestamp.strftime('%B %d, %Y at %I:%M %p')}."
    )

    doc.add_heading(f"Directives", 2)

    doc.add_heading(f"{session.red_bot} (Red)", 3)
    doc.add_paragraph(session.red_directive)

    doc.add_heading(f"{session.blue_bot} (Blue)", 3)
    doc.add_paragraph(session.blue_directive)

    doc.add_heading(f"Discussion", 2)
    speakers = {
        "Red": session.red_bot,
        "Blue": session.blue_bot,
    }
    for message in session.messages:
        doc.add_block(Inline(f"{speakers[message.speaker]}:", bold=True))
        doc.add_raw(message.message)
    doc.dump(transcript_file)

def session_transcript_load(
    dir: str,
    name: str,
    timestamp: str,
) -> str | None:
    transcript_file = (
        _mk_transcript_filename(
            dir,
            name,
            timestamp,
        )
        + ".md"
    )
    # does the file exist?
    if not os.path.exists(transcript_file):
        return None
    with open(transcript_file, "r") as f:
        transcript = f.read()
    return transcript


from __future__ import print_function
import numpy as np
import scipy as sp
import scipy.sparse as sprs

def get_degrees_from_edge_list(N,edges):
    rowcol = np.array(edges,dtype=int)
    if len(rowcol) == 0:
        return np.zeros(N)
    A = sprs.csr_matrix((np.ones(len(edges)),(rowcol[:,0], rowcol[:,1])),shape=(N,N),dtype=int)
    A += A.T
    k = np.asarray(A.sum(axis=1)).flatten()
    return k

def get_adjacency_matrix_from_edge_list(N,edges,sparse=False):

    if sparse:
        rowcol = np.array(edges,dtype=int)
        if len(rowcol) == 0:
            return sprs.csr_matrix(([],([],[])),shape=(N,N),dtype=int)
        A = sprs.csr_matrix((np.ones(len(edges)),(rowcol[:,0], rowcol[:,1])),shape=(N,N),dtype=int)
        A += A.T
        return A
    else:
        A = np.zeros((N, N))
        for i, j in edges:
            A[i, j] = 1
        A += A.T
        return A

def ccdf(x):
    return 1 - 0.5*(1 + sp.special.erf(x/np.sqrt(2)))


from rest_framework import viewsets, mixins, status
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from backend.filters import RateFilter
from backend.models import Rate
from backend.serializers.rateserializers import RateCreateSerializer

class RateViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
    serializer_class = RateCreateSerializer
    queryset = Rate.objects.all()
    permission_classes = [IsAuthenticated, ]
    filter_class = RateFilter

    @action(methods=['POST'], url_path='create', detail=False)
    def _create(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        group = serializer.validated_data['group']
        if self.request.user != group.leader:
            return Response({
                    'success': False,
                    'message': '你不是这个组的队长，不能评分！'
                }, status=status.HTTP_403_FORBIDDEN)

        self.perform_create(serializer)

        return Response(
            {
                'success': True,
                'message': '创建成功',
                'data': serializer.data
            }, status=status.HTTP_201_CREATED
        )

    def perform_create(self, serializer):
        serializer.save()


"""Functional test suite for :class:`pypi_parker.util.SpecificTemporaryFile`."""
import base64
import os

from pypi_parker import util

def test_specific_temporary_file(tmpdir):
    filename = tmpdir.mkdir('test').join('a_file.txt')
    body = str(base64.b64encode(os.urandom(1024)))

    assert not os.path.exists(str(filename))

    with util.SpecificTemporaryFile(name=filename, body=body):
        assert os.path.isfile(str(filename))
        assert filename.read() == body

    assert not os.path.exists(str(filename))


from __future__ import annotations
import collections
import enum

import quokka
from quokka.types import (
    AddressT,
    DefaultDict,
    Dict,
    Index,
    Iterator,
    List,
    LocationValueType,
    Mapping,
    MutableMapping,
    Optional,
    ReferenceTarget,
    ReferenceType,
    Tuple,
    Union,
)

class Reference:
    """Reference: a link between a source and a destination

    Arguments:
        source: Source of the reference
        destination: Destination (target) of the reference
        type_: Type of the reference

    Attributes:
        source: Source of the reference
        destination: Destination (target) of the reference
        type: Type of the reference
    """

    def __init__(
        self,
        source: ReferenceTarget,
        destination: ReferenceTarget,
        type_: ReferenceType,
    ) -> None:
        """Constructor"""
        self.source: ReferenceTarget = source
        self.destination: ReferenceTarget = destination
        self.type: ReferenceType = type_

class ReferencesLocation(enum.Enum):
    """Reference location

    A reference may be attached to one of the following :
        * an instruction index (that means every instance of the instruction)
        * a data index
        * a structure position (e.g. a structure or a member inside a structure)
        * an instruction : a tuple with (chunk, block, inst_index) identifying precisely
            one instruction
        * a function
        * a chunk
    """

    INSTRUCTION = "inst_idx"
    DATA = "data_idx"
    STRUCTURE = "struct_position"
    INST_INSTANCE = "instruction_position"
    FUNCTION = "function_idx"
    CHUNK = "chunk_idx"

    @staticmethod
    def from_proto(location_type: str) -> ReferencesLocation:
        """Convert reference location from proto"""
        # These are the name of the fields in the protobuf
        mapping = {
            "inst_idx": ReferencesLocation.INSTRUCTION,
            "data_idx": ReferencesLocation.DATA,
            "struct_position": ReferencesLocation.STRUCTURE,
            "instruction_position": ReferencesLocation.INST_INSTANCE,
            "function_idx": ReferencesLocation.FUNCTION,
            "chunk_idx": ReferencesLocation.CHUNK,
        }

        try:
            return mapping[location_type]
        except IndexError as exc:
            raise ValueError("Unknown location type") from exc

class References(Mapping):
    """References bucket : maintain the list of all references inside the program

    The instantiation of the class will create a mapping for every reference but not
    resolve them yet.

    This class is probably the most messy one in Quokka and needs a global refactoring.
    However, since it's somehow working, let's try to not break it yet.

    Arguments:
        program: Reference to the program

    Attributes:
        program: Reference to the program
        proto_ref: Protobuf data
        references_category: A mapping that contains every reference for each direction.
            For instance, a ref X from inst a to struct b will be stored in both the
            structure key and the instruction key

    """

    SOURCE = "source"
    DESTINATION = "destination"

    def __init__(self, program: quokka.Program) -> None:
        """Init method

        Arguments:
            program: A backref to program
        """

        # Define the update method
        def update(
            mapping: Mapping,  # type: ignore
            key: Union[Tuple[int], LocationValueType],
            value: Index,
        ) -> None:
            """Recursive method to update the `self.references_category` mapping"""
            if isinstance(key, int):
                mapping[key].append(value)
                return

            current_key: int = key[0]
            sub_key: Union[Tuple[()], Tuple[int], Tuple[int, int]] = key[1:]
            if sub_key:
                update(mapping[current_key], sub_key, value)
            elif not isinstance(mapping.get(current_key), MutableMapping):
                mapping[current_key].append(value)

        self.program: quokka.Program = program
        self.proto_ref = program.proto.references

        # Init the references mapping
        self.references_category: Dict[ReferencesLocation, DefaultDict] = {  # type: ignore
            ReferencesLocation.INSTRUCTION: collections.defaultdict(list),
            ReferencesLocation.DATA: collections.defaultdict(list),
            ReferencesLocation.STRUCTURE: collections.defaultdict(
                lambda: collections.defaultdict(list)
            ),
            ReferencesLocation.INST_INSTANCE: collections.defaultdict(
                lambda: collections.defaultdict(lambda: collections.defaultdict(list))
            ),
            ReferencesLocation.FUNCTION: collections.defaultdict(list),
            ReferencesLocation.CHUNK: collections.defaultdict(list),
        }

        reference: quokka.pb.Quokka.Reference
        for index, reference in enumerate(self.proto_ref):
            source_ref = self.references_category[self.location_type(reference.source)]
            update(source_ref, self.get_location_value(reference.source), index)

            destination_ref = self.references_category[
                self.location_type(reference.destination)
            ]
            update(
                destination_ref, self.get_location_value(reference.destination), index
            )

    @staticmethod
    def location_type(
        location: quokka.pb.Quokka.Location,
    ) -> ReferencesLocation:
        """Convert the proto location type"""
        return ReferencesLocation.from_proto(location.WhichOneof("LocationType"))

    def get_location_value(
        self, location: quokka.pb.Quokka.Location
    ) -> LocationValueType:
        """Resolve a location

        This method resolves a location for quokka.

        Arguments:
            location: Reference location

        Returns:
            A LocationTypeValue
        """
        location_type: ReferencesLocation = self.location_type(location)
        location_value: LocationValueType = getattr(location, location_type.value)

        if location_type in (
            ReferencesLocation.INSTRUCTION,
            ReferencesLocation.DATA,
            ReferencesLocation.FUNCTION,
            ReferencesLocation.CHUNK,
        ):
            return location_value

        elif location_type == ReferencesLocation.STRUCTURE:
            structure_idx: int = getattr(location_value, "structure_idx")

            if getattr(location_value, "no_member") is False:
                return structure_idx, getattr(location_value, "member_idx")

            return structure_idx, -1

        elif location_type == ReferencesLocation.INST_INSTANCE:
            return (
                getattr(location_value, "func_chunk_idx"),
                getattr(location_value, "block_idx"),
                getattr(location_value, "instruction_idx"),
            )

        raise ValueError

    def __getitem__(self, k: Index) -> Reference:
        """Lazy loading for references"""
        return self.create_reference(self.proto_ref[k])

    def __len__(self) -> int:
        """References count"""
        return len(self.proto_ref)

    def __iter__(self) -> Iterator[Dict[AddressT, Reference]]:
        """Iterator over references"""
        raise NotImplementedError

    @property
    def structures(self) -> List[quokka.Structure]:
        """Accessor to the program structures"""
        return self.program.structures

    @property
    def data(self):
        """Accessor to the program PROTO data"""
        return self.program.proto.data

    @property
    def instructions(self):
        """Accessor to the program proto instruction"""
        return self.program.proto.instructions

    def create_reference(self, reference: quokka.pb.Quokka.Reference) -> "Reference":
        """Create a reference

        Start with resolving both the source and the destination.

        Arguments:
            reference: A protobuf reference object

        Returns:
            A python reference with both source and destination resolved
        """
        source: ReferenceTarget = self.resolve_location(reference.source)
        destination: ReferenceTarget = self.resolve_location(reference.destination)

        return Reference(
            source, destination, ReferenceType.from_proto(reference.reference_type)
        )

    def find_instruction(
        self,
        instruction_identifier: "quokka.pb.Quokka.Location.InstructionIdentifier",
    ) -> Tuple[quokka.Chunk, quokka.Block, Index]:
        """Search an instruction from an instruction identifier.

        The parameters are a chunk index, a block index, and an inst index inside the
        block.

        Arguments:
            instruction_identifier: Protobuf instruction identifier

        Returns:
            A instruction tuple (Chunk, Block, Instruction Index)
        """
        chunk = self.program.get_chunk(
            instruction_identifier.func_chunk_idx, instruction_identifier.block_idx
        )
        block = chunk[chunk.index_to_address[instruction_identifier.block_idx]]
        return chunk, block, instruction_identifier.instruction_idx

    def resolve_location(self, location: quokka.pb.Quokka.Location) -> ReferenceTarget:
        """Resolve a location

        This convert a proto location to the actual instance of the object.

        Arguments:
            location: A protobuf Location (sigh) object

        Returns:
            A ReferenceTarget

        Raises:
            ValueError: When no appropriate location has been found.
        """
        location_type: ReferencesLocation = self.location_type(location)
        if location_type == ReferencesLocation.INSTRUCTION:
            raise DeprecationWarning("Not used anymore")

        elif location_type == ReferencesLocation.DATA:
            return self.program.data_holder[location.data_idx]

        elif location_type == ReferencesLocation.STRUCTURE:
            structure: quokka.Structure = self.structures[
                location.struct_position.structure_idx
            ]
            if location.struct_position.no_member is False:
                return structure[
                    structure.index_to_offset[location.struct_position.member_idx]
                ]
            return structure

        elif location_type == ReferencesLocation.INST_INSTANCE:
            return self.find_instruction(location.instruction_position)

        elif location_type == ReferencesLocation.CHUNK:
            return self.program.chunks[location.chunk_idx]

        raise ValueError("No location found")

    @staticmethod
    def get_direction(towards: bool = True) -> Tuple[str, str]:
        """Helper method to analyze if we take the reference or unwind it"""
        target = "destination" if towards else "source"
        wanted = "destination" if not towards else "source"

        return target, wanted

    def resolve_block_references(
        self,
        chunk_index: Index,
        block_index: Index,
        reference_type: ReferenceType,
        towards: bool = True,
    ) -> List[Reference]:
        """Return a list of references from/towards a block.

        Arguments:
            chunk_index: Index of the chunk
            block_index: Index of the block
            reference_type: TYpe of reference wanted (e.g. Data)
            towards: True if we want the reference *to* this block.
                False if we want the references *from* the block.

        Returns:
            A List of references matching the criteria
        """
        target, _ = self.get_direction(towards)

        return_list = []
        for reference_ids in self.references_category[ReferencesLocation.INST_INSTANCE][
            chunk_index
        ][block_index].values():
            for reference_id in reference_ids:
                reference: Reference = self[reference_id]
                if reference.type == reference_type and isinstance(
                    getattr(reference, target), tuple
                ):
                    target_loc = getattr(reference, target)
                    if (target_loc[0].proto_index, target_loc[1].proto_index) == (
                        chunk_index,
                        block_index,
                    ):
                        return_list.append(reference)

        return return_list

    def resolve_inst_instance(
        self,
        inst_tuple: Tuple[int, int, int],
        reference_type: Optional[ReferenceType] = None,
        towards: bool = True,
    ) -> List[Reference]:
        """Resolve instruction references

        Return a list of references from/towards an instruction.
        If a reference_type is specified the references will be filtered by their type

        Arguments:
            inst_tuple: A tuple (Chunk Index, Block Index, Instruction Index)
            reference_type: Reference type to consider (filter result)
            towards: In which sense to search the reference?

        Returns:
            A list of reference matching the criteria
        """
        return_list = []
        target, _ = self.get_direction(towards)

        for reference_idx in self.references_category[ReferencesLocation.INST_INSTANCE][
            inst_tuple[0]
        ][inst_tuple[1]][inst_tuple[2]]:
            reference: "Reference" = self[reference_idx]
            if (not reference_type or reference.type == reference_type) and isinstance(
                getattr(reference, target), tuple
            ):
                target_loc = getattr(reference, target)
                if (
                    target_loc[0].proto_index,
                    target_loc[1].proto_index,
                    target_loc[2],
                ) == inst_tuple:
                    return_list.append(reference)

        return return_list

    def resolve_calls(
        self, chunk: quokka.Chunk, towards: bool = True
    ) -> List[Union[Tuple[quokka.Chunk, quokka.Block, int], quokka.Chunk]]:
        """Resolve calls to a chunk

        This method resolves calls initiated or received from every instruction in a
        chunk. Of note, a call must be from an Instruction Tuple to another.

        Arguments:
            chunk: Target chunk
            towards: Do we look at calls towards this chunk {X,Y,Z} -> Chunk or at calls
                from this chunk Chunk -> {X,Y,Z} ?

        Returns:
            A list of objects that are either tuple (Chunk, Block, Instruction Index) or
            Chunk (only for fake chunks that are created from an imported function)
        """
        return_list = []
        target, wanted = self.get_direction(towards)

        for block_index in self.references_category[ReferencesLocation.INST_INSTANCE][
            chunk.proto_index
        ]:
            # For super-chunks, filter out block that do not belong to this chunk
            # anymore
            if block_index not in chunk.index_to_address:
                continue

            block_references = self.references_category[
                ReferencesLocation.INST_INSTANCE
            ][chunk.proto_index][block_index]
            for references in block_references.values():
                for reference_idx in references:
                    reference: "Reference" = self[reference_idx]
                    if reference.type == ReferenceType.CALL and isinstance(
                        getattr(reference, target), tuple
                    ):
                        target_loc = getattr(reference, target)
                        if target_loc[0].proto_index == chunk.proto_index:
                            location = getattr(reference, wanted)
                            # Fix: Only returns valid tuple
                            # TODO(dm): check why sometimes a Data might be returned
                            if isinstance(location, (tuple, quokka.Chunk)):
                                return_list.append(location)

        return return_list

    def resolve_data(
        self,
        data_index: Index,
        reference_type: Union[ReferenceType, None] = None,
    ) -> List[Reference]:
        """Resolve data references

        Returns a list of reference towards a data
        If a reference_type is specified the references will be filtered by their type

        Arguments:
            data_index: Index of the data in the protobuf
            reference_type: Type of reference

        Returns:
            A list of reference matching the criteria
        """

        references: List[Reference] = []
        for reference_idx in self.references_category[ReferencesLocation.DATA][
            data_index
        ]:
            reference = self[reference_idx]

            if reference_type is not None and reference_type != reference.type:
                continue

            references.append(reference)

        return references


# hashset 可以有Ｏ(n),但題目要求O(1) space!!
# To apply the Floyd's agorithm to identify the beginning of the cycle
class Solution:

    def findDuplicate(self, nums: List[int]) -> int:
        slow, fast = 0, 0
        # find the intersection/ cycle
        while True:
            slow = nums[slow]
            fast = nums[nums[fast]]
            # move forward twice
            if slow == fast:
                break

# slow: 1
# fast: 3
# slow: 3
# fast: 4
# slow: 2
# fast: 4
# slow: 4
# fast: 4

# put the slow pointer in the intersection,the secod intersection will be the begining of the cycle
# 8:36
# the distance between the 1st intersection and the beginning of the cyle
#        ||
# the distance between the starting point and the begining of the cycle

        slow2 = 0
        while True:
            slow = nums[slow]
            slow2 = nums[slow2]
            if slow == slow2:
                return slow


import json
import os
import re
import sys
import time
import uuid
import http.client
import logging
import cherrypy
import threading

import requests
from lxml import etree
from queue import Queue
from enum import Enum
from cherrypy import _cpnative_server

from .utils import load_xml, XMLPath, Setting, cherrypy_publish, SETTING_DIR

logger = logging.getLogger("Protocol")
logger.setLevel(logging.INFO)

SERVICE_STATE_OBSERVED = {
    "AVTransport": ['TransportState',
                    'TransportStatus',
                    'CurrentMediaDuration',
                    'CurrentTrackDuration',
                    'CurrentTrack',
                    'NumberOfTracks'],
    "RenderingControl": ['Volume', 'Mute'],
    "ConnectionManager": ['A_ARG_TYPE_Direction',
                          'SinkProtocolInfo',
                          'CurrentConnectionIDs']
}

class Protocol:
    def __init__(self):
        self._handler = None

    @property
    def handler(self):
        if self._handler is None:
            self._handler = Handler()
        return self._handler

    def start(self):
        pass

    def stop(self):
        pass

    def reload(self):
        self.stop()
        self.start()

    def methods(self):
        return list(filter(lambda m: m.startswith('set_state_') and callable(getattr(self, m)), dir(self)))

    @property
    def renderer(self):
        renderers = cherrypy.engine.publish('get_renderer')
        if len(renderers) == 0:
            logger.error("Unable to find an available renderer.")
            return None
        return renderers.pop()

    # The following methods are called by the renderer to set the playback status within the protocol,
    # which will be passed to the client (generally the mobile phone)

    def set_state_position(self, data: str):
        """
        :param data: string, eg: 00:00:00
        :return:
        """
        pass

    def set_state_duration(self, data: str):
        """
        :param data: string, eg: 00:00:00
        :return:
        """
        pass

    def set_state_pause(self):
        """
        :return:
        """
        pass

    def set_state_play(self):
        """
        :return:
        """
        pass

    def set_state_stop(self):
        """
        :return:
        """
        pass

    def set_state_eof(self):
        """
        :return:
        """
        pass

    def set_state_transport(self, data: str):
        """
        :param data: string in [PLAYING, PAUSED_PLAYBACK, STOPPED, NO_MEDIA_PRESENT]
        :return:
        """
        pass

    def set_state_transport_error(self):
        """
        :return:
        """
        pass

    def set_state_mute(self, data: bool):
        """
        :param data: bool
        :return:
        """
        pass

    def set_state_volume(self, data: int):
        """
        :param data: int 0-100
        :return:
        """
        pass

    def set_state_speed(self, data: str):
        pass

    def set_state_display_subtitle(self, data: bool):
        """ set custom subtitle file path
        :param data: bool, whether display the subtitle
        :return:
        """
        pass

    def set_state_url(self, data: str):
        pass

    def set_state(self, state_name, state_value):
        pass

    def get_state(self, state_name):
        return ''

    def get_state_title(self) -> str:
        """
        :return: string, eg: demo
        """
        return ''

    def get_state_url(self) -> str:
        """
        :return: string, eg: http://10.10.10.10/demo.mp4
        """
        return ''

    def get_state_position(self) -> str:
        """
        :return: string, eg: 00:00:00
        """
        return '00:00:00'

    def get_state_duration(self) -> str:
        """
        :return: string, eg: 00:00:00
        """
        return '00:00:00'

    def get_state_volume(self) -> int:
        """
        :return: int, range from 0 to 100
        """
        return 80

    def get_state_mute(self) -> bool:
        """
        :return: bool
        """
        return False

    def get_state_transport_state(self) -> str:
        """
        :return: string in [PLAYING, PAUSED_PLAYBACK, STOPPED, NO_MEDIA_PRESENT]
        """
        return 'STOPPED'

    def get_state_transport_status(self) -> str:
        """
        :return: string in [OK, ERROR_OCCURRED]
        """
        return 'OK'

    def get_state_speed(self) -> str:
        return '1'

    def get_state_display_subtitle(self) -> bool:
        return True

class ObserveClient:
    def __init__(self, service, url, timeout=1800):
        self.url = url
        self.service = service
        self.startTime = int(time.time())
        self.sid = "uuid:{}".format(uuid.uuid4())
        self.timeout = timeout
        self.seq = 0
        self.host = re.findall(r"//([0-9:.]*)", url)[0]
        self.path = re.findall(r"//[0-9:.]*(.*)$", url)[0]
        print("-----------------------------", self.host)
        self.error = 0

    def is_timeout(self):
        return int(time.time()) - self.startTime > self.timeout

    def update(self, timeout=1800):
        self.startTime = int(time.time())
        self.timeout = timeout

    def send_event_callback(self, data):
        """Sending event data to client
        """
        headers = {"NT": "upnp:event",
                   "NTS": "upnp:propchange",
                   "CONTENT-TYPE": 'text/xml; charset="utf-8"',
                   "SERVER": Setting.get_server_info(),
                   "SID": self.sid,
                   "SEQ": self.seq,
                   "TIMEOUT": "Second-{}".format(self.timeout)
                   }
        namespace = 'urn:schemas-upnp-org:event-1-0'
        root = etree.Element(etree.QName(namespace, 'propertyset'),
                             nsmap={'e': namespace})
        if self.service == 'ConnectionManager':
            for i in data:
                prop = etree.SubElement(
                    root, '{urn:schemas-upnp-org:event-1-0}property')
                item = etree.SubElement(prop, i)
                item.text = str(data[i])
        else:
            prop = etree.SubElement(
                root, '{urn:schemas-upnp-org:event-1-0}property')
            last_change = etree.SubElement(prop, 'LastChange')
            event = etree.Element('Event')
            event.attrib['xmlns'] = 'urn:schemas-upnp-org:metadata-1-0/AVT/'
            instance_id = etree.SubElement(event, 'InstanceID')
            instance_id.set('val', '0')
            for i in data:
                p = etree.SubElement(instance_id, i)
                p.set('val', str(data[i]))
            last_change.text = etree.tostring(event, encoding="UTF-8").decode()
        data = etree.tostring(root, encoding="UTF-8")
        logger.debug("Prop Change---------")
        logger.debug(data)
        conn = http.client.HTTPConnection(self.host, timeout=5)
        conn.request("NOTIFY", self.path, data, headers)
        conn.close()
        self.seq = self.seq + 1

class DataType(Enum):
    boolean = 'boolean'
    i2 = 'i2'
    ui2 = 'ui2'
    i4 = 'i4'
    ui4 = 'ui4'
    string = 'string'

class StateVariable:
    """The state of render
    """

    def __init__(self, name, send_events, datatype, service):
        self.name = name
        self.sendEvents = True if send_events == 'yes' else False
        self.datatype = DataType(datatype)
        self.minimum = None
        self.maximum = None
        self.allowedValueList = None
        self.value = '' if self.datatype == DataType.string else 0
        self.service = service

    def set_value(self, value):
        self.value = value

    def set_allowed_value_list(self, values):
        self.allowedValueList = values
        if 'NOT_IMPLEMENTED' in values:
            self.value = 'NOT_IMPLEMENTED'

    def set_allowed_value_range(self, minimum, maximum):
        self.minimum = minimum
        self.maximum = maximum

class Argument:
    def __init__(self, name, state, value=None):
        self.name = name
        self.state = state
        self.value = value

class Action:
    """Operations supported by render.

    Parameters
    ----------
    name : string
        The name of the operation.
    input : list<Argument>
        A set of state values.
    output : list<Argument>
        A set of state values.

    """

    def __init__(self, name, input, output):
        self.name = name
        self.input = input
        self.output = output

class Service:
    service_map = {}

    @classmethod
    def get(cls, name):
        return cls.service_map.get(name, Service(name))

    @classmethod
    def build(cls, name, ns, actions):
        cls.service_map[name] = Service(name, ns, actions)

    def __init__(self, name, namespace='', actions={}):
        self.name = name
        self.namespace = namespace
        self.actions = actions

class DLNAProtocol(Protocol):

    def __init__(self):
        super(DLNAProtocol, self).__init__()
        self.running = False
        self.state_list = {}
        self.action_list = {}
        self.event_thread = None
        self.event_subscribes = {}  # subscribe devices
        self.state_queue = Queue()  # states needed be send to subscribe devices
        self.removed_device_queue = Queue()  # devices needed be removed
        self.append_device_queue = Queue()  # devices needed be added
        self.init_services()  # create services handle function from xml file
        self.init_state()  # set default value

    @property
    def handler(self):
        if self._handler is None:
            self._handler = DLNAHandler()
        return self._handler

    def init_state(self):
        self.set_state('CurrentPlayMode', 'NORMAL')
        self.set_state('TransportPlaySpeed', 1)
        self.set_state('TransportStatus', 'OK')
        self.set_state('RelativeCounterPosition', 2147483647)
        self.set_state('AbsoluteCounterPosition', 2147483647)
        self.set_state('A_ARG_TYPE_Direction', 'Output')
        self.set_state('CurrentConnectionIDs', '0')
        self.set_state('PlaybackStorageMedium', 'None')
        self.set_state('SinkProtocolInfo', load_xml(XMLPath.PROTOCOL_INFO.value).strip())

    def init_services(self, description=XMLPath.DESCRIPTION.value):
        """
        :param description: dlna description xml file
        :return:
        """
        desc = etree.parse(description).getroot()
        for service_type in desc.iter('{urn:schemas-upnp-org:device-1-0}serviceType'):
            # service_type:  urn:schemas-upnp-org:service:ConnectionManager:1
            namespace = service_type.text
            service = service_type.text.split(":")[3]
            self.build_action(namespace, service, etree.parse(
                XMLPath.BASE_PATH.value + f"/xml/{service}.xml").getroot())

    def build_action(self, namespace, service, xml):
        """
        :param namespace: eg: urn:schemas-upnp-org:service:ConnectionManager:1
        :param service:  eg: ConnectionManager
        :param xml: xml content of service
        :return:
        """
        """Build action and variable list from xml file
        """
        ns = '{urn:schemas-upnp-org:service-1-0}'
        # get state variable from xml file
        for state_variable in xml.iter(ns + 'stateVariable'):
            name = state_variable.find(ns + "name").text

            data = StateVariable(name,
                                 state_variable.attrib['sendEvents'],
                                 state_variable.find(ns + "dataType").text,
                                 service)
            default_value = state_variable.find(ns + "defaultValue")
            if default_value is not None:
                data.set_value(default_value.text)
            allowed_value_list = state_variable.find(ns + "allowedValueList")
            if allowed_value_list is not None:
                values = [
                    value.text
                    for value in allowed_value_list.findall(ns + "allowedValue")
                ]
                data.set_allowed_value_list(values)

            allowed_value_range = state_variable.find(ns + "allowedValueRange")
            if allowed_value_range is not None:
                data.set_allowed_value_range(
                    int(allowed_value_range.find(ns + "minimum").text),
                    int(allowed_value_range.find(ns + "maximum").text))
            self.state_list[name] = data

        # get action from xml file
        actions = {}
        for action in xml.iter(ns + 'action'):
            name = action.find(ns + "name").text
            input = []
            output = []
            argument_list = action.find(ns + "argumentList")
            if argument_list is not None:
                for argument in argument_list.findall(ns + 'argument'):
                    data = Argument(
                        argument.find(ns + "name").text,
                        argument.find(ns + "relatedStateVariable").text)
                    if argument.find(ns + "direction").text == 'in':
                        input.append(data)
                    else:
                        output.append(data)
            actions[name] = Action(name, input, output)
        # self.action_list[service] = actions
        Service.build(service, namespace, actions)

    def add_subscribe(self, service, url, timeout=1800):
        """Add a DLNA client to subscribe list
        """
        logger.error("SUBSCRIBE: " + url)
        for client in self.event_subscribes:
            if self.event_subscribes[client].url == url and \
                    self.event_subscribes[client].service == service:
                s = self.event_subscribes[client]
                s.update(timeout)
                logger.error("SUBSCRIBE UPDATE")
                return {
                    "SID": s.sid,
                    "TIMEOUT": "Second-{}".format(s.timeout)
                }
        logger.error("SUBSCRIBE ADD")
        client = ObserveClient(service, url, timeout)
        self.append_device_queue.put(client)
        threading.Thread(target=self.send_init_event,
                         kwargs={
                             'service': service,
                             'client': client
                         }).start()
        return {
            "SID": client.sid,
            "TIMEOUT": "Second-{}".format(client.timeout)
        }

    def send_init_event(self, service, client):
        """When there is a client subscription,
        the first event callback will send all the state values of the service.
        """
        data = {}
        for state in SERVICE_STATE_OBSERVED[service]:
            data[state] = self.state_list[state].value
        try:
            client.send_event_callback(data)
        except Exception as e:
            logger.error(str(e))

    def remove_subscribe(self, sid):
        """Remove a DLNA client from subscribe list
        """
        if sid in self.event_subscribes:
            self.removed_device_queue.put(sid)
        return 200

    def renew_subscribe(self, sid, timeout=1800):
        """Renew a DLNA client in subcribe list
        """
        if sid in self.event_subscribes:
            self.event_subscribes[sid].update(timeout)
            return 200
        return 412

    def send_states_to_clients(self, state_change_list):
        """Sending the states in the stateChangeList to the clients which subscribe to them.
        :param state_change_list:
        :return:
        """
        if not bool(state_change_list):
            return
        # remove offline clients
        while not self.removed_device_queue.empty():
            sid = self.removed_device_queue.get()
            logger.info("Remove client: {}".format(sid))
            del self.event_subscribes[sid]
            self.removed_device_queue.task_done()
        # add clients
        while not self.append_device_queue.empty():
            client = self.append_device_queue.get()
            self.event_subscribes[client.sid] = client
            self.append_device_queue.task_done()
        # send stateChangeList to client
        for sid in self.event_subscribes:
            client = self.event_subscribes[sid]
            if client.is_timeout():
                self.remove_subscribe(client.sid)
                continue
            try:
                # Only send state which within the service
                state = {}
                for name in state_change_list:
                    if self.state_list[name].service == client.service:
                        state[name] = state_change_list[name]
                if len(state) == 0:
                    continue
                client.send_event_callback(state)

            except Exception as e:
                logger.error("send event error: " + str(e))
                client.error = client.error + 1
                if client.error > 10:
                    logger.debug("remove " + client.sid)
                    self.remove_subscribe(client.sid)

    def event(self):
        """DLNA Event thread
        If a DLNA client subscribes to the dlna event,
        it will automatically send the event to the client when the renderer state changes.
        """
        while self.running:
            if not self.state_queue.empty():
                state = {}
                while not self.state_queue.empty():
                    k, v = self.state_queue.get()
                    state[k] = v
                    self.state_queue.task_done()
                self.send_states_to_clients(state)
            time.sleep(1)

    def call(self, rawbody):
        """Processing requests from DLNA clients
        The request from the client is passed into this method
        through the DLNAHandler(macast.py -> class DLNAHandler).
        If the Render class implements the corresponding action method,
        the method will be called automatically.
        Otherwise, the corresponding state variable will be returned
        according to the **action return value** described in the XML file.
        :param rawbody: soap request from dlna client
        :return:
        """
        root = etree.fromstring(rawbody)[0][0]
        param = {}
        for node in root:
            param[node.tag] = node.text
        action = root.tag.split('}')[1]
        service = root.tag.split(":")[3]
        method = "{}_{}".format(service, action)
        if method not in [
            'AVTransport_GetPositionInfo',
            'AVTransport_GetTransportInfo',
            'RenderingControl_GetVolume'
        ]:
            logger.info("{} {}".format(method, param))
        res = {}
        service_type = Service.get(service)
        if hasattr(self, method):
            data = {}
            # input = self.action_list[service][action].input
            input = service_type.actions[action].input
            for arg in input:
                data[arg.name] = Argument(
                    arg.name, arg.state,
                    param[arg.name] if arg.name in param else None)
                if arg.name in param:
                    self.set_state(arg.state, param[arg.name])
            res = getattr(self, method)(data)
        else:
            # output = self.action_list[service][action].output
            output = service_type.actions[action].output
            for arg in output:
                res[arg.name] = self.state_list[arg.state].value
        if method not in ['ConnectionManager_GetProtocolInfo', 'AVTransport_GetPositionInfo']:
            logger.info("{}res: {}".format("*" * 20, res))
        else:
            logger.info("{}res: {}".format("*" * 20, method))

        # build response xml
        ns = 'http://schemas.xmlsoap.org/soap/envelope/'
        encoding = 'http://schemas.xmlsoap.org/soap/encoding/'
        root = etree.Element(etree.QName(ns, 'Envelope'), nsmap={'s': ns})
        root.attrib[f'{{{ns}}}encodingStyle'] = encoding
        body = etree.SubElement(root, etree.QName(ns, 'Body'), nsmap={'s': ns})
        # namespace = 'urn:schemas-upnp-org:service:{}:1'.format(service)
        response = etree.SubElement(body,
                                    etree.QName(
                                        service_type.namespace, '{}Response'.format(action)),
                                    nsmap={'u': service_type.namespace})
        for key in res:
            prop = etree.SubElement(response, key)
            prop.text = str(res[key])
        return etree.tostring(root, encoding="UTF-8", xml_declaration=False)

    def set_state(self, name: str, value) -> None:
        """Set DLNA state which defined by xml file
        :param name: state name
        :param value: state value
        :return:
        """
        # update states which will send to DLNA Client
        if name in SERVICE_STATE_OBSERVED['AVTransport'] or \
                name in SERVICE_STATE_OBSERVED['RenderingControl']:
            logger.debug("setState: {} {}".format(name, value))
            # When some states change, the DLNA client needs to be notified immediately
            # We put this kind of state into state_queue, waiting to be sent to client.
            self.state_queue.put((name, value))
        # update other states
        if self.state_list[name].value != value:
            self.state_list[name].value = value

    def get_state(self, name: str):
        """Get DLNA state, The type of state is described by XML file
        :param name: DLNA state name
        :return: int/string/bool
        """
        return self.state_list[name].value

    def start(self):
        """Start render thread
        """
        if self.running:
            return

        self.running = True
        self.event_thread = threading.Thread(target=self.event, daemon=True)
        self.event_thread.start()
        self.set_state_stop()

    def stop(self):
        """Stop render thread
        """
        self.running = False

    # The following method names are defined by the XML file

    def RenderingControl_SetVolume(self, data):
        volume = data['DesiredVolume']
        self.renderer.set_media_volume(volume.value)
        return {}

    def RenderingControl_SetMute(self, data):
        mute = data['DesiredMute']
        if mute.value == 0 or mute.value == '0':
            mute = False
        else:
            mute = True
        self.renderer.set_media_mute(mute)
        return {}

    def AVTransport_SetAVTransportURI(self, data):
        uri = data['CurrentURI'].value
        logger.info(uri)
        self.set_state_url(uri)
        self.renderer.set_media_url(uri)
        title = Setting.get_friendly_name()
        try:
            meta = etree.fromstring(data['CurrentURIMetaData'].value.encode())
            title_xml = meta.find('.//{{{}}}title'.format(meta.nsmap['dc']))
            if title_xml is not None and title_xml.text is not None:
                title = title_xml.text
            metadata = etree.tostring(meta, encoding="UTF-8", xml_declaration=False)
        except Exception as e:
            logger.error(str(e))
            logger.error(data['CurrentURIMetaData'].value)
            self.set_state('CurrentTrackMetaData', data['CurrentURIMetaData'].value)
        else:
            self.set_state('CurrentTrackMetaData', metadata.decode())
        self.renderer.set_media_title(title)
        self.renderer.set_media_resume()
        self.set_state('CurrentTrackTitle', title)
        self.set_state('CurrentTrackURI', uri)
        self.set_state('RelativeTimePosition', '00:00:00')
        self.set_state('AbsoluteTimePosition', '00:00:00')
        self.set_state('TransportState', 'PAUSED_PLAYBACK')
        self.set_state('TransportStatus', 'OK')
        return {}

    def AVTransport_Play(self, data):
        self.renderer.set_media_resume()
        self.set_state('TransportState', 'PLAYING')
        self.set_state('TransportStatus', 'OK')
        return {}

    def AVTransport_Pause(self, data):
        self.renderer.set_media_pause()
        self.set_state('TransportState', 'PAUSED_PLAYBACK')
        return {}

    def AVTransport_Seek(self, data):
        target = data['Target']
        self.renderer.set_media_position(target.value)
        self.set_state('RelativeTimePosition', target.value)
        self.set_state('AbsoluteTimePosition', target.value)
        return {}

    def AVTransport_Stop(self, data):
        self.renderer.set_media_stop()
        self.set_state('TransportState', 'STOPPED')
        return {}

    # The following methods are usually used to update the states of
    # DLNA Renderer according to the status obtained from the player.
    # So, when your player state changes, call the following methods.
    # For example, when you click the pause button of the player,
    # call "self.protocol.set_state_pause()" from renderer
    # Then, the DLNA client (such as your mobile phone) will
    # automatically get this information and update it to the front-end.

    def set_state_position(self, data: str):
        """
        :param data: string, eg: 00:00:00
        :return:
        """
        self.set_state('RelativeTimePosition', data)
        self.set_state('AbsoluteTimePosition', data)

    def set_state_duration(self, data: str):
        """
        :param data: string, eg: 00:00:00
        :return:
        """
        self.set_state('CurrentTrackDuration', data)
        self.set_state('CurrentMediaDuration', data)

    def set_state_pause(self):
        self.set_state_transport('PAUSED_PLAYBACK')

    def set_state_play(self):
        self.set_state_transport('PLAYING')

    def set_state_stop(self):
        self.set_state_transport('STOPPED')

    def set_state_eof(self):
        self.set_state_transport('NO_MEDIA_PRESENT')

    def set_state_transport(self, data: str):
        """
        :param data: string in [PLAYING, PAUSED_PLAYBACK, STOPPED, NO_MEDIA_PRESENT]
        :return:
        """
        self.set_state('TransportState', data)
        self.set_state('TransportStatus', 'OK')

    def set_state_transport_error(self):
        """
        :return:
        """
        self.set_state('TransportState', 'STOPPED')
        self.set_state('TransportStatus', 'ERROR_OCCURRED')

    def set_state_mute(self, data: bool):
        """
        :param data: bool
        :return:
        """
        self.set_state('Mute', data)

    def set_state_volume(self, data: int):
        """
        :param data: int, range from 0 to 100
        :return:
        """
        self.set_state('Volume', data)

    def set_state_speed(self, data: str):
        self.set_state('TransportPlaySpeed', data)

    def set_state_display_subtitle(self, data: bool):
        self.set_state('DisplayCurrentSubtitle', data)

    def set_state_url(self, data: str):
        self.set_state('CurrentTrackURI', data)

    # When you are implementing another protocol similar to DLNA,
    # you can get the status of DLNA renderer by calling the following methods.
    # Using DLNA protocol usually does not need to pay attention to these methods,
    # because the state of renderer will be read automatically when using DLNA protocol.

    def get_state_title(self) -> str:
        """
        :return: string, eg: demo
        """
        return self.get_state('CurrentTrackTitle')

    def get_state_url(self) -> str:
        """
        :return: string, eg: http://10.10.10.10/demo.mp4
        """
        return self.get_state('CurrentTrackURI')

    def get_state_position(self) -> str:
        """
        :return: string, eg: 00:00:00
        """
        return self.get_state('RelativeTimePosition')

    def get_state_duration(self) -> str:
        """
        :return: string, eg: 00:00:00
        """
        return self.get_state('CurrentMediaDuration')

    def get_state_volume(self) -> int:
        """
        :return: int, range from 0 to 100
        """
        return self.get_state('Volume')

    def get_state_mute(self) -> bool:
        """
        :return: bool
        """
        return self.get_state('Mute')

    def get_state_transport_state(self) -> str:
        """
        :return: string in [PLAYING, PAUSED_PLAYBACK, STOPPED, NO_MEDIA_PRESENT]
        """
        return self.get_state('TransportState')

    def get_state_transport_status(self) -> str:
        """
        :return: string in [OK, ERROR_OCCURRED]
        """
        return self.get_state('TransportStatus')

    def get_state_speed(self) -> str:
        return self.get_state('TransportPlaySpeed')

    def get_state_display_subtitle(self) -> bool:
        return bool(self.get_state('DisplayCurrentSubtitle'))

@cherrypy.expose
class Handler:

    def __init__(self):
        self.setting_page = load_xml(XMLPath.SETTING_PAGE.value).encode()
        self.__downloading = False

    @property
    def protocol(self) -> Protocol:
        protocols = cherrypy.engine.publish('get_protocol')
        if len(protocols) == 0:
            logger.error("Unable to find an available protocol.")
            return Protocol()
        return protocols.pop()

    def reload(self):
        cherrypy.server.httpserver = _cpnative_server.CPHTTPServer(cherrypy.server)

    def __download_plugin(self, path, url):
        try:
            with open(path, 'wb') as f:
                f.write(requests.get(url).content)
        except Exception as e:
            logger.error(f"download plugin error: {e}")
        finally:
            self.__downloading = False
            Setting.restart()
            # cherrypy.engine.restart()

    def GET(self, param=None, *args, **kwargs):
        if not Setting.is_service_running():
            raise cherrypy.HTTPError(503, 'Server restarting')
        if param == 'api':
            cherrypy.response.headers['Content-Type'] = 'application/json;charset:utf-8'
            query = kwargs.get('query', '')
            res = {
                'api?query=log': 'get logs of macast',
                'api?query=settings': 'get settings of macast',
            }
            if query == 'log':
                log_path = os.path.join(SETTING_DIR, 'macast.log')
                data = ''
                try:
                    with open(log_path, 'r', encoding='utf-8') as f:
                        data = f.read()
                except:
                    pass
                res = {"logs": data}
            elif query == 'launch-param':
                res = Setting.setting
            elif query == 'plugin-info':
                info = cherrypy_publish('get_plugin_info', [])
                res = {
                    'platform': sys.platform,
                    'version': Setting.version,
                    'plugins': info
                }
            return json.dumps(res, indent=4).encode()
        if param is not None:
            raise cherrypy.HTTPRedirect('/')
        cherrypy.response.headers['Content-Type'] = 'text/html'
        # return self.setting_page
        return load_xml(XMLPath.SETTING_PAGE.value).encode()

    def POST(self, *args, **kwargs):
        cherrypy.response.headers['Content-Type'] = 'application/json;charset:utf-8'
        res = {'code': 0, 'message': 'success'}
        if kwargs.get('save-launch-param', None) is not None:
            setting = kwargs.get('save-launch-param', None)
            try:
                setting = json.loads(setting)
            except Exception as e:
                res['code'] = 1
                res['message'] = 'json format error'
            else:
                Setting.setting = setting
                Setting.save()
                Setting.restart()
                # cherrypy.engine.restart()
        elif kwargs.get('install-plugin', None) is not None:
            plugin = kwargs.get('install-plugin', None)
            if self.__downloading:
                cherrypy.engine.publish('app_notify', 'ERROR', 'Downloading other plugin now')
                res['code'] = 1
                res['message'] = 'Downloading other plugin now'
            else:
                cherrypy.engine.publish('app_notify', 'INFO', 'installing plugin...')
                self.__downloading = True
                try:
                    plugin = json.loads(plugin)
                    url = plugin.get('url', '')
                    plugin_name = url.split('/')[-1]
                    local_path = os.path.join(SETTING_DIR, plugin.get('type', 'renderer'), plugin_name)
                    threading.Thread(target=self.__download_plugin(local_path, url),
                                     daemon=True).start()
                except Exception as e:
                    res['code'] = 1
                    res['message'] = 'json format error'
        else:
            logger.info(kwargs)

        return json.dumps(res, indent=4).encode()

@cherrypy.expose
class DLNAHandler(Handler):
    """Receiving requests from DLNA client
    and communicating with the RenderPlugin thread
    see also: plugin.py -> class RenderPlugin
    """

    def __init__(self):
        super(DLNAHandler, self).__init__()
        self.description = None
        self.reload()

    def reload(self):
        super(DLNAHandler, self).reload()
        self.build_description()

    @property
    def protocol(self) -> DLNAProtocol:
        protocols = cherrypy.engine.publish('get_protocol')
        if len(protocols) == 0:
            logger.error("Unable to find an available protocol.")
            return DLNAProtocol()
        return protocols.pop()

    def build_description(self):
        self.description = load_xml(XMLPath.DESCRIPTION.value).format(
            friendly_name=Setting.get_friendly_name(),
            manufacturer="xfangfang",
            manufacturer_url="https://github.com/xfangfang",
            model_description="AVTransport Media Renderer",
            model_name="Macast",
            model_url="https://xfangfang.github.io/Macast",
            model_number=Setting.get_version(),
            uuid=Setting.get_usn(),
            serial_num=1024,
            header_extra="",
            service_extra=""
        ).encode()

    def GET(self, param=None, *args, **kwargs):
        if param == 'description.xml':
            return self.description
        return super(DLNAHandler, self).GET(param, *args, **kwargs)

    def POST(self, service=None, param=None, *args, **kwargs):
        length = cherrypy.request.headers['Content-Length']
        rawbody = cherrypy.request.body.read(int(length))
        logger.debug('RAW: {}'.format(rawbody))
        if param == 'action':
            res = self.protocol.call(rawbody)
            cherrypy.response.headers['EXT'] = ''
            logger.debug('RES: {}'.format(res))
            return res
        return super(DLNAHandler, self).POST(service, param, *args, **kwargs)

    def SUBSCRIBE(self, service="", param=""):
        """DLNA/UPNP event subscribe
        """
        if param == 'event':
            SID = cherrypy.request.headers.get('SID')
            CALLBACK = cherrypy.request.headers.get('CALLBACK')
            TIMEOUT = cherrypy.request.headers.get('TIMEOUT')
            TIMEOUT = TIMEOUT if TIMEOUT is not None else 'Second-1800'
            TIMEOUT = int(TIMEOUT.split('-')[-1])
            if SID:
                logger.error("RENEW SUBSCRIBE:!!!!!!!" + service)
                res = self.protocol.renew_subscribe(SID, TIMEOUT)
                if res != 200:
                    logger.error("RENEW SUBSCRIBE: cannot find such sid.")
                    raise cherrypy.HTTPError(status=res)
                cherrypy.response.headers['SID'] = SID
                cherrypy.response.headers['TIMEOUT'] = TIMEOUT
            elif CALLBACK:
                logger.error("ADD SUBSCRIBE:!!!!!!!" + service)
                suburl = re.findall("<(.*?)>", CALLBACK)[0]
                res = self.protocol.add_subscribe(service, suburl, TIMEOUT)
                cherrypy.response.headers['SID'] = res['SID']
                cherrypy.response.headers['TIMEOUT'] = res['TIMEOUT']
            else:
                logger.error("SUBSCRIBE: cannot find sid and callback.")
                raise cherrypy.HTTPError(status=412)
        return b''

    def UNSUBSCRIBE(self, service, param):
        """DLNA/UPNP event unsubscribe
        """
        if param == 'event':
            SID = cherrypy.request.headers.get('SID')
            if SID:
                logger.error("REMOVE SUBSCRIBE:!!!!!!!" + service)
                res = self.protocol.remove_subscribe(SID)
                if res != 200:
                    raise cherrypy.HTTPError(status=res)
                return b''
        logger.error("UNSUBSCRIBE: error 412.")
        raise cherrypy.HTTPError(status=412)


class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        hashmap={}
        interlist=[]
        for i in range(len(nums1)):
            if(nums1[i] in hashmap.keys()):
                hashmap[nums1[i]]+=1
                continue
            hashmap[nums1[i]]=1
        print(hashmap)

        for i in nums2:
            if(i in hashmap.keys() and hashmap[i]!=0):
                interlist.append(i)
                hashmap[i]-=1
        return interlist