import os
import re
import requests
import pandas as pd
from subprocess import call
from werkzeug.utils import secure_filename
from flask import Flask, request, render_template, url_for, redirect, flash
from wtforms import validators
from flask_wtf.csrf import CSRFProtect, CSRFError

# instantiating an object of the Flask class
app = Flask(__name__, template_folder="templates", static_folder='static')

app.config['TEMPLATES_AUTO_RELOAD'] = True

app.secret_key = 'q/w3!4er5t6y78y9=cd?u' #assign a secret key used for csrf_token
csrf = CSRFProtect(app) #Enable CSRF protection globally for a Flask app.

#Lax prevents sending cookies with CSRF-prone requests from external sites, such as submitting a form.
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'

#Custom Error message for 400 Bad Request
@app.errorhandler(400)
def error404(error):
    return '
Bad Request!
', 400

#Custom Error message for 404 Not Found
@app.errorhandler(404)
def error404(error):
    return '
Page Not Found
', 404

# Custom Error message for 500 Internal Server Errror
@app.errorhandler(500)
def error500(error):
    return '
Something Went Wrong!!!
', 500

# Custom Error message for 405 Method Not Allowed
@app.errorhandler(405)
def error405(error):
    return '
Method is not allowed!!!
', 405

#route() decorator tell Flask that when user type "/" in the address bar just after the "localhost:5000" it will
#trigger the URL for "home" page. It binds the home() function to the URL "localhost:5000/"
@app.route('/')
 #home() is the function name which is also used to generate URL for that particular function, and returns
 # the data we want to display in the user’s browser.
def home():
    return render_template("home.html") #render home.html template

@app.route('/fortesting')
def test():
    return render_template("test.html") #render home.html template

#secure configuration
@app.after_request
def apply_caching(response):
    #set X-Frame-Options Header "SAMEORIGIN", so page can only be displayed in a frame on the same origin
    #as the page itself to protect against 'ClickJacking' attacks.
    response.headers["X-Frame-Options"] = "SAMEORIGIN"
    #Set headers 'X-Content-Type-Options' to 'nosniff' to force the browser to honor the response content type instead
    #of trying to detect it, which can be abused to generate a cross-site scripting (XSS) attack.
    response.headers['X-Content-Type-Options'] = 'nosniff'
    #The browser will try to prevent reflected XSS attacks by not loading the page if the request contains something
    #that looks like JavaScript and the response contains the same data.
    response.headers['X-XSS-Protection'] = '1; mode=block'
    return response

#create the route and function for "capture"
@app.route('/capture')
def capture():
    return render_template("capture.html")

#after user click on "Submit and Capture" button on the "Capture Live Network Traffic" form, this function will be triggered
@app.route('/getinput', methods=['GET', 'POST'])
def getinput():
    if request.method == "POST":
        #when user selects the option "Number of packets"
        if request.values['useroption'] == 'packets':
            #tshark command will be used for capturing a number of packets
            tsharkcmd = "tshark -i WiFi -w userinputpackets.pcap -c {}"
            userinput_filename = "userinputpackets.pcap"
        #when user selects the option "Duration"
        if request.values['useroption'] == 'duration':
            #tshark command will be used for capturing in a set time
            tsharkcmd = "tshark -i WiFi -w userinputseconds.pcap -a duration:{}"
            userinput_filename = "userinputseconds.pcap"
        userinput = request.values['userinput']
        #filter the user's input to accept digits only
        if not(re.findall("\d+[a-zA-Z]+",userinput) or re.findall("[a-zA-Z]+\d+", userinput)):
            #pass the userinput to tshark command and then execute the tshark command in the windows terminal
            os.system(tsharkcmd.format(userinput))
        else:
            return redirect("/capture", code=302)
        #after the capturing finished, the network traffic data was saved in the file named userinput_filename as a pcap file
        #the following codes will read the pcap file with the tshark command and save the output as a csv file
        tsharkCall = ["tshark", "-r", f"{userinput_filename}", "-T", "fields", "-e", "frame.number", "-e", "_ws.col.Time", "-e", \
        "_ws.col.Source", "-e", "_ws.col.Destination", "-e", "_ws.col.Protocol", "-e", "_ws.col.Length", "-e", "_ws.col.Info", "-E", \
        "separator=,", "-E", "quote=d", "-E", "occurrence=f"]
        with open("data.csv", "w") as tsharkOut:
            tsharkOut.write("\"Fnum\",\"Time\",\"Source\",\"Destination\",\"Protocol\",\"Length\",\"Info\"\n")
            tsharkOut.flush() #method cleans out the internal buffer.
            call(tsharkCall, stdout=tsharkOut) #take the tsharkCall as input and write output to the tsharkOut
            tsharkOut.close()
    #redirect the user to visualization page after data ready for visualizing
    return redirect("/visualization", code=302)

#create URL and function for upload
@app.route('/upload')
def upload():
    return render_template("upload.html")

@app.route('/getupload', methods=['GET', 'POST'])
def getupload():
    if request.method == "POST":
        #get the uploaded file from the HTML form in the upload.html template
        f = request.files['file']
        # secure_filename(f.filename) function will change the malicious file name as meaningless name
        f.save(secure_filename(f.filename))
        final_name = f.filename #assign the safe name
        tsharkCall = ["tshark", "-r", f"{final_name}", "-T", "fields", "-e", "frame.number", "-e", "_ws.col.Time", "-e", \
            "_ws.col.Source", "-e", "_ws.col.Destination", "-e", "_ws.col.Protocol", "-e", "_ws.col.Length", "-e", "_ws.col.Info",\
             "-E", "separator=,", "-E", "quote=d", "-E", "occurrence=f"]
        with open("data.csv", "w") as tsharkOut:
            tsharkOut.write("\"Fnum\",\"Time\",\"Source\",\"Destination\",\"Protocol\",\"Length\",\"Info\"\n")
            tsharkOut.flush()
            call(tsharkCall, stdout=tsharkOut)
            tsharkOut.close()
        #redirect the user to visualization page after data ready for visualizing
        return redirect("/visualization", code=302)

@app.route('/dosvisualization')
def dosvisualization():
    return render_template("dosvisualization.html") #render dosvisualization.html template

#create URL and function for filter
@app.route('/filter')
def filter():
    #read the data in data.csv file and store them in the dataframe object
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    noofrows = len(dataframe.Fnum) #count number of rows in dataframe object
    return render_template("filter.html", title="Filter", dataframe=dataframe, noofrows=noofrows)

#create URL and function for visualization
@app.route('/visualization')
def visualization():
    return render_template("visualization.html", title="Chart")

#create URL and function for protocols
@app.route('/protocols') # route('/protocols') decorator is to tell Flask the "/protocols" URL should trigger protocol() function
def protocols():
    #read the data in data.csv file and store them in the dataframe object
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #calculate the frequency of each protocol in dataframe
    profreq = dataframe.Protocol.value_counts()
    numofpro = len(profreq)

    sumlength_of_eachpro = []
    for row in range(numofpro):
        sumlength_of_eachpro.append(dataframe[dataframe.Protocol == profreq.index[row]].Length.sum()*8)

    #render the template protocols.html and pass the data stored in the objects profreq and numofpro
    return render_template("protocols.html", title="Chart", profreq=profreq, numofpro=numofpro, df=dataframe, \
        sumlength_of_eachpro=sumlength_of_eachpro)

'''DDOS EXTRACTION AND ANALYZATION'''
#create URL and function for DoS attacks overview
@app.route('/dosattackoverview', methods=['GET', 'POST'])
def dosattackoverview():
    #read the data in data.csv file and store them in the dataframe object
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #calculate the frequency of each protocol in dataframe
    profreq = dataframe.Protocol.value_counts()
    numofpro = len(profreq)

    #Extract only HTTP protocol from dataframe object
    http = dataframe[dataframe.Protocol == "HTTP"]
    httpfreq = len(http)

    #Calculate a number of labels and set canvas width
    if (httpfreq < 29):
        canvas_width_httpReq = 1110
    elif (httpfreq*38 < 32768):
        canvas_width_httpReq = httpfreq*38
    else:
        canvas_width_httpReq = 32768

    #Create a dataframe that contains HTTP GET/POST requests
    httpReq = dataframe.loc[[0]].drop([0])
    for i in range(len(http)):
        httpreq = re.search("POST / HTTP/|GET / HTTP/", http.Info[http.index[i]])
        if httpreq:
            httpReq = httpReq.append(http.loc[[http.index[i]]])
    numOfHTTPReqs = len(httpReq)

    #Create a list of number of HTTP requests at specific times
    numofHTTPReqs_List = []
    for req in range(len(httpReq)):
        numofHTTPReqs = req + 1
        numofHTTPReqs_List.append(numofHTTPReqs)

    #Create a list of HTTP requests per second
    httpreqpersecond_list = []
    for req in range(len(httpReq)):
        httpreqpersecond_list.append(int(numofHTTPReqs_List[req]/httpReq.Time[httpReq.index[req]]))

    #Determine canvas width
    numoflabels = len(dataframe.index)
    if (numoflabels < 29):
        canvas_width = 1110
    elif (numoflabels*38 < 32768):
        canvas_width = numoflabels*38
    else:
        canvas_width = 32768

    sum_length_inMb = 0
    throughput_list = [(dataframe.Length[0]*8)/1000000]
    for index in range(len(dataframe.Length)-1):
        sum_length_inMb = sum_length_inMb + ((dataframe.Length[index])*8)/1000000
        throughput_list.append((sum_length_inMb/dataframe.Time[index+1]).round(6))

    packetsps_list = [dataframe.Fnum[0]]
    for i in range(len(dataframe.index)-1):
        packetsps = int(dataframe.Fnum[i]/dataframe.Time[i+1])
        packetsps_list.append(packetsps)

    sumlength_of_eachpro = []
    for row in range(numofpro):
        sumlength_of_eachpro.append(dataframe[dataframe.Protocol == profreq.index[row]].Length.sum()*8)

    Source_Info = dataframe[["Source","Info"]] #pull out the Source and Info fields in the dataframe object
    #The list of flags could be used in network traffic. The special characters [ and ] would be displayed as normal characters, so the
    #\[ and \] are used to escape special characters [ ] to avoid the findall() method would return anything insides these [] as a list
    flagList = ["\[SYN\]","\[SYN, ACK\]","\[ACK\]","\[PSH\]","\[PSH, ACK\]","\[FIN\]","\[FIN, ACK\]","\[RST\]","\[URG\]","\[ECE\]",\
                "\[CWR\]","\[NS\]"]
    SourceCorrespondingToFlag = [] # array/list to hold the Source IP addresses which related to flags
    FlagInInfo = [] # list to store flags that extracted from the Info field
    for flag in flagList: #Loop through each flag in the flagList
        for row in range(len(Source_Info)): #each flag will be search through all rows in the Info column
            if (re.findall(flag, str(Source_Info.Info[row]))): #if a flag found in a specific row
                x = re.findall(flag, str(Source_Info.Info[row])) #then take this flag, x is a list stores the found flag
                #append the Source IP address that corresponding to found flag
                SourceCorrespondingToFlag.append(Source_Info.Source[row])
                FlagInInfo.append(x[0]) #append the found flag to the FlagInInfo list
    # create a DataFrame for Source and Flag
    SourcenFlagDF = pd.DataFrame({'Source':SourceCorrespondingToFlag, 'Flag':FlagInInfo})
    #group the Source and Flag, Source will be set as the row label and Flag as column label
    groupbyFlagInInfo = SourcenFlagDF.groupby(['Source','Flag'])['Source'].count().unstack().fillna(0)
    numofrows = len(groupbyFlagInInfo)
    numofcolumns = len(groupbyFlagInInfo.columns)

    #render the template httpflood.html and pass the data stored in the objects profreq and numofpro
    return render_template("dosattackoverview.html", title="Chart", profreq=profreq, numofpro=numofpro, numoflabels=numoflabels,\
        sumlength_of_eachpro=sumlength_of_eachpro, throughput_list=throughput_list, canvas_width=canvas_width, df=dataframe, \
        packetsps_list=packetsps_list, groupbyFlagInInfo=groupbyFlagInInfo, numofrows=numofrows, numofcolumns=numofcolumns,\
        httpfreq=httpfreq, httpReq=httpReq, numOfHTTPReqs=numOfHTTPReqs, httpreqpersecond_list=httpreqpersecond_list, \
        canvas_width_httpReq=canvas_width_httpReq)

#create URL and function for httpflood
#route('/httpflood') decorator is to tell Flask the "/httpflood" URL should trigger httpflood() function
@app.route('/httpflood', methods=['GET','POST'])
def httpflood():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only HTTP protocol from dataframe object
    http = dataframe[dataframe.Protocol == "HTTP"]
    httpfreq = len(http)

    #Calculate a number of labels and set canvas width
    if (httpfreq < 29):
        canvas_width_httpReq = 1110
    elif (httpfreq*38 < 32768):
        canvas_width_httpReq = httpfreq*38
    else:
        canvas_width_httpReq = 32768

    #Create a dataframe that contains HTTP GET/POST requests
    httpReq = dataframe.loc[[0]].drop([0])
    for i in range(len(http)):
        httpreq = re.search("POST / HTTP/|GET / HTTP/", http.Info[http.index[i]])
        if httpreq:
            httpReq = httpReq.append(http.loc[[http.index[i]]])
    numOfHTTPReqs = len(httpReq)

    #Create a list of number of HTTP requests at specific times
    numofHTTPReqs_List = []
    for req in range(len(httpReq)):
        numofHTTPReqs = req + 1
        numofHTTPReqs_List.append(numofHTTPReqs)

    #Create a list of HTTP requests per second
    httpreqpersecond_list = []
    for req in range(len(httpReq)):
        httpreqpersecond_list.append(int(numofHTTPReqs_List[req]/httpReq.Time[httpReq.index[req]]))

    #Generate a dataframe which consists of only HTTP Responds
    httpRes = dataframe.loc[[0]].drop([0])
    for i in range(httpfreq):
        respond = re.search("HTTP/.+200 OK", http.Info[http.index[i]])
        if respond:
            httpRes = httpRes.append(http.loc[[http.index[i]]])
    numofHTTPRes = len(httpRes)

    #Calculate frequency of each protocol
    profreq = dataframe.Protocol.value_counts()
    numofpro = len(profreq)

    #Calculate a number of labels and set canvas width
    numoflabels = len(dataframe.index)

    #Set requests per second threshold
    rps_threshold = 350 # Set default threshold
    # Get user's threshold
    if request.method == "POST":
        userinput = request.values['rpsthreshold']
        #filter the user's input to accept digits only
        if not(re.findall("\d*[a-zA-Z]+\d*", userinput)):
            rps_threshold = int(userinput)
        else:
            return redirect("/httpflood", code=302)

    #render the template httpflood.html and pass the data stored in the objects
    return render_template("httpflood.html", title="HTTPFlood", profreq=profreq, numofpro=numofpro, df=dataframe, http=http,\
        rps_threshold=rps_threshold, numoflabels=numoflabels, httpfreq=httpfreq, httpReq=httpReq,httpRes=httpRes, \
        numOfHTTPReqs=numOfHTTPReqs, httpreqpersecond_list=httpreqpersecond_list, numofHTTPRes=numofHTTPRes,\
        canvas_width_httpReq=canvas_width_httpReq)

#create URL and function for tcpflood
@app.route('/tcpflood', methods=['GET', 'POST'])# decorator is to tell Flask the "/tcpflood" URL should trigger tcpflood() function
def tcpflood():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only HTTP protocol from dataframe object
    tcp = dataframe[dataframe.Protocol == "TCP"]
    tcpfreq = len(tcp)

    #Calculate frequency of each protocol
    profreq = dataframe.Protocol.value_counts()
    numofpro = len(profreq)

    #Calculate a number of labels and set canvas width
    numoflabels = len(dataframe.index)
    if (numoflabels < 29):
        canvas_width = 1110
    elif (numoflabels*38 < 32768):
        canvas_width = numoflabels*38
    else:
        canvas_width = 32768

    #Set packets per second threshold
    tcpSYNpps_threshold = 100 # Set default threshold
    # Get user's threshold
    if request.method == "POST":
        userinput = request.values['ppsthreshold']
        #filter the user's input to accept digits only
        if not(re.findall("\d*[a-zA-Z]+\d*", userinput)):
            tcpSYNpps_threshold = int(userinput)
        else:
            return redirect("/tcpflood", code=302)

    #Create a list for sum of length of each protocol
    sumlength_of_eachpro = []
    for row in range(numofpro):
        sumlength_of_eachpro.append(dataframe[dataframe.Protocol == profreq.index[row]].Length.sum()*8)

    Source_Info = dataframe[["Source","Info"]] #pull out the Source and Info fields in the dataframe object
    #The list of flags could be used in network traffic. The special characters [ and ] would be displayed as normal characters, so the
    #\[ and \] are used to escape special characters [ ] to avoid the findall() method would return anything insides these [] as a list
    flagList = ["\[SYN\]","\[SYN, ACK\]","\[ACK\]","\[PSH\]","\[PSH, ACK\]","\[FIN\]","\[FIN, ACK\]","\[RST\]","\[URG\]","\[ECE\]",\
                "\[CWR\]","\[NS\]"]
    SourceCorrespondingToFlag = [] # array/list to hold the Source IP addresses which related to flags
    FlagInInfo = [] # list to store flags that extracted from the Info field
    for flag in flagList: #Loop through each flag in the flagList
        for row in range(len(Source_Info)): #each flag will be search through all rows in the Info column
            if (re.findall(flag, str(Source_Info.Info[row]))): #if a flag found in a specific row
                x = re.findall(flag, str(Source_Info.Info[row])) #then take this flag, x is a list stores the found flag
                #append the Source IP address that corresponding to found flag
                SourceCorrespondingToFlag.append(Source_Info.Source[row])
                FlagInInfo.append(x[0]) #append the found flag to the FlagInInfo list
    # create a DataFrame for Source and Flag
    Source_Flag_DF = pd.DataFrame({'Source':SourceCorrespondingToFlag, 'Flag':FlagInInfo})
    #group the Source and Flag, Source will be set as the row label and Flag as column label
    groupbyFlagInInfo = Source_Flag_DF.groupby(['Source','Flag'])['Source'].count().unstack().fillna(0)
    numofrows = len(groupbyFlagInInfo)
    numofcolumns = len(groupbyFlagInInfo.columns)

    #Group all flags in groups
    groupofflags = Source_Flag_DF.Flag.value_counts()
    numofgroupsofflags = len(groupofflags)

    #Create a dataframe that contains only TCP SYN flags
    tcpSYNflags_df = tcp.loc[[tcp.index[0]]].drop([0])
    for i in range(len(tcp)):
        tcpflag = re.search("\[SYN\]|\[SYN, ACK\]|\[ACK\]|\[PSH\]|\[PSH, ACK\]|\[FIN\]|\[FIN, ACK\]|\[RST\]|\[URG\]|\[ECE\]|\[CWR\]|\[NS\]",\
                 tcp.Info[tcp.index[i]])
        if tcpflag.group() == "[SYN]":
            tcpSYNflags_df = tcpSYNflags_df.append(tcp.loc[[tcp.index[i]]])

    #Generate a list of TCP SYN packets per second
    numOfSYN_packets = 1
    tcpSYN_pps = [1]
    for i in range(len(tcpSYNflags_df)-1):
        numOfSYN_packets = numOfSYN_packets + 1
        tcpSYN_pps.append(int(numOfSYN_packets/tcpSYNflags_df.Time[tcpSYNflags_df.index[i+1]]))

    #render the template tcpflood.html and pass the data stored in the objects
    return render_template("tcpflood.html", titltcpSYNflags_dfe="TCP Flood", profreq=profreq, numofpro=numofpro, df=dataframe, tcpfreq=tcpfreq,\
        numoflabels=numoflabels, sumlength_of_eachpro=sumlength_of_eachpro, canvas_width=canvas_width,groupbyFlagInInfo=groupbyFlagInInfo,\
        numofrows=numofrows, numofcolumns=numofcolumns, groupofflags=groupofflags, numofgroupsofflags=numofgroupsofflags, tcp=tcp,\
        tcpSYNpps_threshold=tcpSYNpps_threshold, tcpSYN_pps=tcpSYN_pps, tcpSYNflags_df=tcpSYNflags_df)

#create URL and function for UDP flood
# route('/udpflood') decorator is to tell Flask the "/udpflood" URL should trigger udpflood() function
@app.route('/udpflood', methods=["GET", "POST"])
def udpflood():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Calculate frequency of each protocol
    profreq = dataframe.Protocol.value_counts()
    numofpro = len(profreq)

    numoflabels = len(dataframe.index)
    #Decide canvas width
    if (numoflabels < 29):
        canvas_width = 1110
    elif (numoflabels*38 < 32768):
        canvas_width = numoflabels*38
    else:
        canvas_width = 32768

    #Generate a throughput list (in Mbps)
    sum_length_inMb = 0
    throughput_list = [(dataframe.Length[0]*8)/1000000]
    for index in range(len(dataframe.Length)-1):
        sum_length_inMb = sum_length_inMb + ((dataframe.Length[index])*8)/1000000
        throughput_list.append((sum_length_inMb/dataframe.Time[index+1]).round(6))
    numofelements = len(throughput_list)

    #Create a list for sum of length of each protocol
    sumlength_of_eachpro = []
    for row in range(numofpro):
        sumlength_of_eachpro.append(dataframe[dataframe.Protocol == profreq.index[row]].Length.sum()*8)

    #Set bandwidth threshold
    mbps_threshold = 30 # Set default threshold
    # Get user's threshold
    if request.method == "POST":
        userinput = request.values['mbpsthreshold']
        #filter the user's input to accept digits only
        if not(re.findall("\d*[a-zA-Z]+\d*", userinput)):
            mbps_threshold = float(userinput)
        else:
            return redirect("/udpflood", code=302)

    return render_template("udpflood.html", title="UDP Flood", numofpro=numofpro, profreq=profreq, df=dataframe, \
        sumlength_of_eachpro=sumlength_of_eachpro, throughput_list=throughput_list, canvas_width=canvas_width, \
        mbps_threshold=mbps_threshold, numofelements=numofelements)

#create URL and function for icmpflood
@app.route('/icmpflood', methods=["GET", "POST"])
def icmpflood():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Calculate frequency of each protocol
    profreq = dataframe.Protocol.value_counts()
    numofpro = len(profreq)
    numoflabels = len(dataframe.index)

    # Determine canvas width
    if (numoflabels < 29):
        canvas_width = 1110
    elif (numoflabels*38 < 32768):
        canvas_width = numoflabels*38
    else:
        canvas_width = 32768

    #Create a list for sum of length of each protocol
    sumlength_of_eachpro = []
    for row in range(numofpro):
        sumlength_of_eachpro.append(dataframe[dataframe.Protocol == profreq.index[row]].Length.sum()*8)

    #Generate a throughput list (in Mbps)
    sum_length_inMb = 0
    throughput_list = [(dataframe.Length[0]*8)/1000000]
    for index in range(len(dataframe.Length)-1):
        sum_length_inMb = sum_length_inMb + ((dataframe.Length[index])*8)/1000000
        throughput_list.append((sum_length_inMb/dataframe.Time[index+1]).round(6))
    numofelements = len(throughput_list)

    #Set throughput threshold
    mbps_threshold = 30 # Set default threshold
    # Get user's threshold
    if request.method == "POST":
        userinput = request.values['mbpsthreshold']
        #filter the user's input to accept digits only
        if not(re.findall("\d*[a-zA-Z]+\d*", userinput)):
            mbps_threshold = float(userinput)
        else:
            return redirect("/icmpflood", code=302)

    return render_template("icmpflood.html", title="ICMP Ping Flood", icmp=icmp, profreq=profreq, numofpro=numofpro, df=dataframe,\
    sumlength_of_eachpro=sumlength_of_eachpro, canvas_width=canvas_width, throughput_list=throughput_list, mbps_threshold=mbps_threshold,\
    numofelements=numofelements)

#create URL and function for icmpflood
@app.route('/ipfragmentation', methods=["GET", "POST"])
def ipfragmentation():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Calculate frequency of each protocol
    profreq = dataframe.Protocol.value_counts()
    numofpro = len(profreq)
    numoflabels = len(dataframe.index)

    # Determine canvas width
    if (numoflabels < 29):
        canvas_width = 1110
    elif (numoflabels*38 < 32768):
        canvas_width = numoflabels*38
    else:
        canvas_width = 32768

    #Create a list for sum of length of each protocol
    sumlength_of_eachpro = []
    for row in range(numofpro):
        sumlength_of_eachpro.append(dataframe[dataframe.Protocol == profreq.index[row]].Length.sum()*8)

    #Generate a Packets per second (Pps) list
    packetsps_list = [dataframe.Fnum[0]]
    for i in range(len(dataframe.index)-1):
        packetsps = int(dataframe.Fnum[i]/dataframe.Time[i+1])
        packetsps_list.append(packetsps)
    numofelements = len(packetsps_list)

    #Set packets per second threshold
    pps_threshold = 100000 # Set default threshold
    # Get user's threshold
    if request.method == "POST":
        userinput = request.values['ppsthreshold']
        #filter the user's input to accept digits only
        if not(re.findall("\d*[a-zA-Z]+\d*", userinput)):
            pps_threshold = int(userinput)
        else:
            return redirect("/ipfragmentation", code=302)

    return render_template("ipfragmentation.html", title="IP Fragmentation", profreq=profreq, numofpro=numofpro, df=dataframe,\
        sumlength_of_eachpro=sumlength_of_eachpro, canvas_width=canvas_width, pps_threshold=pps_threshold, numofelements=numofelements,\
        packetsps_list=packetsps_list)

'''END DOS ANALYSIS'''

#create URL and function for sourceport
@app.route('/sourceport')
def sourceport():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    info = dataframe.Info

    liststoresports=[] #the list of lists to store pairs of source port and destination port
    srccorrespondingtoport=[] #an array to store the source IP address corresponding to port
    #Extract Source ports from the Info field
    for row in range(len(info)):
        #if each word in each row of Info does not start with a digit and follow by a letter/letters
        #or does not start with a letter/letters and end with a digit
        if not(re.findall("\d+[a-zA-Z]+", str(info[row])) or re.findall("[a-zA-Z]+\d+", str(info[row])) or \
            re.findall(r"\d+[.,?/\|#<>:;'@!£$%&()-]\b",str(info[row])) or re.findall(r"[.,?/\|#<>:;'@!£$%&()-]\d+",str(info[row]))):
            rowcontainsnum=re.findall("\d+",str(info[row]))
            if not(rowcontainsnum==[]): #if each time the array rowcontainsnum starts with a number
                srccorrespondingtoport.append(dataframe.Source[row])
                for n in range(1):
                    #append a pair of source port and destination port into liststoresports array
                    liststoresports.append([rowcontainsnum[n],rowcontainsnum[n+1]])

    #Store source ports and destination ports in seperated arrays
    srcports=[] #the array to keep source ports
    dstports=[] #the array to keep destination ports
    for row in range(len(liststoresports)):
        for col in range(2):
            if col==0:
                srcports.append(liststoresports[row][col])
            else:
                dstports.append(liststoresports[row][col])

    # create a dataframe for Source and Port
    SrcnPortDF = pd.DataFrame({'Source':srccorrespondingtoport, 'Port':srcports})
    groupbySrcPort = SrcnPortDF.groupby(['Source','Port'])['Source'].count().unstack().fillna(0)
    numofrows = len(groupbySrcPort)
    numofcolumns = len(groupbySrcPort.columns)

    if (numofcolumns < 29):
        canvas_width = 1110
    elif (numofcolumns*38 < 32768):
        canvas_width = numofcolumns*38
    else:
        canvas_width = 32768

    return render_template("sourceport.html", title="DstPort Chart", groupbySrcPort=groupbySrcPort, numofrows=numofrows, \
        numofcolumns=numofcolumns, canvas_width=canvas_width)

#create URL and function for dstport
#Extract Destination ports from the Info column
@app.route('/dstport')
def dstport():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    info = dataframe.Info #Extract the Info field and save it to the info object

    liststoresports=[] #the list of lists to store pairs of source port and destination port
    dstcorrespondingtoport=[] #an array to store the destination IP address corresponding to port
    for row in range(len(info)):
        #if each group of characters in each row of Info field does not start with a digit/digits and follow by a letter/letters or
        # ".,?/\|#<>:;'@!£$%&()-" or does not start with a letter/letters or ".,?/\|#<>:;'@!£$%&()-" and end with a digit/digits
        if not(re.findall("\d+[a-zA-Z]+",str(info[row])) or re.findall("[a-zA-Z]+\d+",str(info[row])) or \
            re.findall(r"\d+[.,?/\|#<>:;'@!£$%&()-]\b",str(info[row])) or re.findall(r"[.,?/\|#<>:;'@!£$%&()-]+\d+",str(info[row]))):
            rowcontainsnum=re.findall("\d+",str(info[row])) #find all numbers in the Info field and return to rowcontainsnum list
            if not(rowcontainsnum==[]): #if each time the array rowcontainsnum contains a number
                dstcorrespondingtoport.append(dataframe.Destination[row])
                for n in range(1):
                    #append a pair of source port and destination port into liststoresports list
                    liststoresports.append([rowcontainsnum[n],rowcontainsnum[n+1]])

    #Store source ports and destination ports in seperated arrays
    srcports=[] #the array to keep source ports
    dstports=[] #the array to keep destination ports
    for row in range(len(liststoresports)):
        for col in range(2):
            if col==0:
                srcports.append(liststoresports[row][col])
            else:
                dstports.append(liststoresports[row][col])

    # create a dataframe for Destination and Port
    DstPortDF = pd.DataFrame({'Source':dstcorrespondingtoport, 'Port':dstports})
    groupbyDstPort = DstPortDF.groupby(['Source','Port'])['Source'].count().unstack().fillna(0)
    numofrows = len(groupbyDstPort)
    numofcolumns = len(groupbyDstPort.columns)
    if (numofcolumns < 29):
        canvas_width = 1110
    elif (numofcolumns*38 < 32768):
        canvas_width = numofcolumns*38
    else:
        canvas_width = 32768

    return render_template("dstport.html", title="Chart", groupbyDstPort=groupbyDstPort, numofrows=numofrows, \
        numofcolumns=numofcolumns, canvas_width=canvas_width)

#create URL and function for source
@app.route('/source')
def source():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Pull out the Source IP addresses and count the frequency of each one
    source = dataframe.Source.value_counts()
    sumsrc = len(source)

    return render_template("source.html", title="Chart", sumsrc=sumsrc, source=source)

#create URL and function for destination
@app.route('/destination')
def destination():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Pull out the Destination IP addresses and count the frequency of each one
    destination = dataframe.Destination.value_counts()
    dstrows = len(destination)

    return render_template("destination.html", title="Chart", dstrows=dstrows, destination=destination)

#create URL and function for groupbysource
@app.route('/groupbysource')
def groupbysource():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #group the Source and Protocol, Protocol will be set as the row label and Source as column label
    groupbySource = dataframe.groupby(['Source','Protocol'])['Source'].count().unstack(0).fillna(0)
    numofrows = len(groupbySource)
    numofcolumns = len(groupbySource.columns)
    if (numofcolumns < 29):
        canvas_width = 1110
    elif (numofcolumns*38 < 32768):
        canvas_width = numofcolumns*38
    else:
        canvas_width = 32768

    return render_template("groupbysource.html", title="Chart", numofcolumns=numofcolumns, numofrows=numofrows, \
        groupbySource=groupbySource, canvas_width=canvas_width)

#create URL and function for groupbyprotocol
@app.route('/groupbyprotocol') # The decorator tells Flask "/groupbyprotocol" URL should trigger groupbyprotocol() function
def groupbyprotocol():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    # Group 'Source' and 'Protocol' together, count the Source IP address for each protocol,
    #the method unstack() is to seperate Source IP addresses as row labels and protocols as column labels
    #the fillna(0) method fills all Nan with 0
    groupbyProtocol = dataframe.groupby(['Source','Protocol'])['Source'].count().unstack().fillna(0)
    #count the number of rows in groupbyProtocol object
    numofrows = len(groupbyProtocol)
    #count the number of columns in groupbyProtocol object
    numofcolumns = len(groupbyProtocol.columns)
    if (numofcolumns < 29):
        canvas_width = 1110
    elif (numofcolumns*38 < 32768):
        canvas_width = numofcolumns*38
    else:
        canvas_width = 32768
    #display the result on a table and a chart by rendering the groupbyprotocol.html template
    return render_template("groupbyprotocol.html", title="Chart", numofcolumns=numofcolumns, numofrows=numofrows, \
        groupbyProtocol=groupbyProtocol, canvas_width=canvas_width)

#create URL and function for tcp
@app.route('/tcp')
def tcp():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only TCP protocol from the dataframe object
    tcp = dataframe[dataframe.Protocol == "TCP"]
    tcpfreq = len(tcp)
    if (tcpfreq < 29):
        canvas_width = 1110
    elif (tcpfreq*38 < 32768):
        canvas_width = tcpfreq*38
    else:
        canvas_width = 32768
    #plt.xticks(np.arange(51))
    return render_template("tcp.html", title="Chart", tcp=tcp, tcpfreq=tcpfreq, canvas_width=canvas_width)

#create URL and function for http
@app.route('/http')
def http():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only HTTP protocol from dataframe object
    http = dataframe[dataframe.Protocol == "HTTP"]
    frequency= len(http)

    if (frequency < 29):
        canvas_width = 1110
    elif (frequency*38 < 32768):
        canvas_width = frequency*38
    else:
        canvas_width = 32768

    return render_template("http.html", title="Chart", http=http, frequency=frequency, canvas_width=canvas_width)

#create URL and function for tcp
@app.route('/udp')
def udp():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only UDP protocol from the dataframe object
    udp = dataframe[dataframe.Protocol == "UDP"]
    udpfreq= len(udp)
    if (udpfreq < 29):
        canvas_width = 1110
    elif (udpfreq*38 < 32768):
        canvas_width = udpfreq*38
    else:
        canvas_width = 32768

    return render_template("udp.html", title="Chart", udp=udp, udpfreq=udpfreq, canvas_width=canvas_width)

#create URL and function for dns
@app.route('/dns')
def dns():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only DNS protocol from dataframe object
    dns = dataframe[dataframe.Protocol == "DNS"]
    dnsfreq= len(dns)
    if (dnsfreq < 29):
        canvas_width = 1110
    elif (dnsfreq*38 < 32768):
        canvas_width = dnsfreq*38
    else:
        canvas_width = 32768
    return render_template("dns.html", title="Chart", dns=dns, dnsfreq=dnsfreq, canvas_width=canvas_width)

#create URL and function for tlsv1
@app.route('/tlsv1')
def tlsv1():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only TLSv1 protocol from dataframe object
    tlsv1 = dataframe[dataframe.Protocol == "TLSv1"]
    tlsv1freq = len(tlsv1)
    if (tlsv1freq < 29):
        canvas_width = 1110
    elif (tlsv1freq*38 < 32768):
        canvas_width = tlsv1freq*38
    else:
        canvas_width = 32768

    return render_template("tlsv1.html", title="Chart", tlsv1=tlsv1, tlsv1freq=tlsv1freq, canvas_width=canvas_width)

#create URL and function for tlsv1.2
@app.route('/tlsv1_2')
def tlsv1_2():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only TLSv1.2 protocol from dataframe object
    tlsv1_2 = dataframe[dataframe.Protocol == "TLSv1.2"]
    tlsv1_2freq = len(tlsv1_2)
    if (tlsv1_2freq < 29):
        canvas_width = 1110
    elif (tlsv1_2freq*38 < 32768):
        canvas_width = tlsv1_2freq*38
    else:
        canvas_width = 32768

    return render_template("tlsv1_2.html", title="Chart", tlsv1_2=tlsv1_2, tlsv1_2freq=tlsv1_2freq, canvas_width=canvas_width)

#create URL and function for tlsv1.3
@app.route('/tlsv1_3')
def tlsv1_3():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only TLSv1.3 protocol from dataframe object
    tlsv1_3 = dataframe[dataframe.Protocol == "TLSv1.3"]
    tlsv1_3freq = len(tlsv1_3)
    if (tlsv1_3freq < 29):
        canvas_width = 1110
    elif (tlsv1_3freq*38 < 32768):
        canvas_width = tlsv1_3freq*38
    else:
        canvas_width = 32768

    return render_template("tlsv1_3.html", title="Chart", tlsv1_3=tlsv1_3, tlsv1_3freq=tlsv1_3freq, canvas_width=canvas_width)

#create URL and function for telnet
@app.route('/telnet')
def telnet():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only TELNET protocol from dataframe object
    telnet = dataframe[dataframe.Protocol == "TELNET"]
    telnetfreq= len(telnet)
    if (telnetfreq < 29):
        canvas_width = 1110
    elif (telnetfreq*38 < 32768):
        canvas_width = telnetfreq*38
    else:
        canvas_width = 32768

    return render_template("telnet.html", title="Chart", telnet=telnet, telnetfreq=telnetfreq, canvas_width=canvas_width)

#create URL and function for ssdp
@app.route('/ssdp')
def ssdp():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only SSDP protocol from dataframe object
    ssdp = dataframe[dataframe.Protocol == "SSDP"]
    ssdpfreq= len(ssdp)
    if (ssdpfreq < 29):
        canvas_width = 1110
    elif (ssdpfreq*38 < 32768):
        canvas_width = ssdpfreq*38
    else:
        canvas_width = 32768
    return render_template("ssdp.html", title="Chart", ssdp=ssdp, ssdpfreq=ssdpfreq, canvas_width=canvas_width)

#create URL and function for arp
@app.route('/arp')
def arp():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only ARP protocol from dataframe object
    arp = dataframe[dataframe.Protocol == "ARP"]
    arpfreq= len(arp)
    if (arpfreq < 29):
        canvas_width = 1110
    elif (arpfreq*38 < 32768):
        canvas_width = arpfreq*38
    else:
        canvas_width = 32768
    return render_template("arp.html", title="Chart", arp=arp, arpfreq=arpfreq, canvas_width=canvas_width)

#create URL and function for icmp
@app.route('/icmp')
def icmp():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only ICMP protocol from dataframe object
    icmp = dataframe[dataframe.Protocol == "ICMP"]
    frequency= len(icmp)
    if (frequency < 29):
        canvas_width = 1110
    elif (frequency*38 < 32768):
        canvas_width = frequency*38
    else:
        canvas_width = 32768
    return render_template("icmp.html", title="Chart", icmp=icmp, frequency=frequency, canvas_width=canvas_width)

#create URL and function for icmpv6
@app.route('/icmpv6')
def icmpv6():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only ICMPv6 protocol from dataframe object
    icmpv6 = dataframe[dataframe.Protocol == "ICMPv6"]
    frequency= len(icmpv6)
    if (frequency < 29):
        canvas_width = 1110
    elif (frequency*38 < 32768):
        canvas_width = frequency*38
    else:
        canvas_width = 32768
    return render_template("icmpv6.html", title="Chart", icmp=icmp, frequency=frequency, canvas_width=canvas_width)

#create URL and function for ocsp
@app.route('/ocsp')
def ocsp():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only OCSP protocol from dataframe object
    ocsp = dataframe[dataframe.Protocol == "OCSP"]
    frequency= len(ocsp)
    if (frequency < 29):
        canvas_width = 1110
    elif (frequency*38 < 32768):
        canvas_width = frequency*38
    else:
        canvas_width = 32768
    return render_template("ocsp.html", title="Chart", ocsp=ocsp, frequency=frequency, canvas_width=canvas_width)

#create URL and function for dhcpv6
@app.route('/dhcpv6')
def dhcpv6():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only DHCPv6 protocol from dataframe object
    dhcpv6 = dataframe[dataframe.Protocol == "DHCPv6"]
    frequency= len(dhcpv6)
    if (frequency < 29):
        canvas_width = 1110
    elif (frequency*38 < 32768):
        canvas_width = frequency*38
    else:
        canvas_width = 32768
    return render_template("dhcpv6.html", title="Chart", dhcpv6=dhcpv6, frequency=frequency, canvas_width=canvas_width)

#create URL and function for mdns (Multicast Domain Name System query)
@app.route('/mdns')
def mdns():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only MDNS protocol from dataframe object
    mdns = dataframe[dataframe.Protocol == "MDNS"]
    frequency= len(mdns)
    if (frequency < 29):
        canvas_width = 1110
    elif (frequency*38 < 32768):
        canvas_width = frequency*38
    else:
        canvas_width = 32768
    return render_template("mdns.html", title="Chart", mdns=mdns, frequency=frequency, canvas_width=canvas_width)

#create URL and function for db_lsp_disc (Dropbox LAN Sync Discovery Protocol)
@app.route('/db_lsp_disc')
def db_lsp_disc():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only DB-LSD-DISC protocol from dataframe object
    db_lsp_disc = dataframe[dataframe.Protocol == "DB-LSP-DISC"]
    db_lsp_discfreq= len(db_lsp_disc)
    if (db_lsp_discfreq < 29):
        canvas_width = 1110
    elif (db_lsp_discfreq*38 < 32768):
        canvas_width = db_lsp_discfreq*38
    else:
        canvas_width = 32768
    return render_template("db_lsp_disc.html", title="Chart", db_lsp_disc=db_lsp_disc, db_lsp_discfreq=db_lsp_discfreq,\
     canvas_width=canvas_width)

#create URL and function for nbns (NetBIOS Name Service)
@app.route('/nbns')
def nbns():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only NBNS protocol from dataframe object
    nbns = dataframe[dataframe.Protocol == "NBNS"]
    frequency= len(nbns)
    if (frequency < 29):
        canvas_width = 1110
    elif (frequency*38 < 32768):
        canvas_width = frequency*38
    else:
        canvas_width = 32768
    return render_template("nbns.html", title="Chart", nbns=nbns, frequency=frequency, canvas_width=canvas_width)

#create URL and function for browser (Microsoft Windows Browser Protocol)
@app.route('/browser')
def browser():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only BROWSER protocol from dataframe object
    browser = dataframe[dataframe.Protocol == "BROWSER"]
    browserfreq= len(browser)
    if (browserfreq < 29):
        canvas_width = 1110
    elif (browserfreq*38 < 32768):
        canvas_width = browserfreq*38
    else:
        canvas_width = 32768
    return render_template("browser.html", title="Chart", browser=browser, browserfreq=browserfreq, canvas_width=canvas_width)

#create URL and function for igmpv2 (Internet Group Management Protoco v2)
@app.route('/igmpv2')
def igmpv2():
    dataframe = pd.read_csv("data.csv", usecols=[0, 1, 2, 3, 4, 5, 6])
    #Extract only IGMPv2 protocol from dataframe object
    igmpv2 = dataframe[dataframe.Protocol == "IGMPv2"]
    frequency= len(igmpv2)
    if (frequency < 29):
        canvas_width = 1110
    elif (frequency*38 < 32768):
        canvas_width = frequency*38
    else:
        canvas_width = 32768
    return render_template("igmpv2.html", title="Chart", igmpv2=igmpv2, frequency=frequency, canvas_width=canvas_width)

#Run the app if __name='__main__'
if __name__ == '__main__':
    app.run(host="localhost", port=5000, debug=False)


from setuptools import setup, find_packages

with open("README.md", "r") as fh:
    long_description = fh.read()

setup(
    nmae='Youtube Downloader',
    version='1.0.0',
    author='Kebba Kanyi',
    author_email='kebbakanyi@gmail.com',
    description='Download videos from Youtube',
    long_description=long_description,
    long_description_content_type='text/markdown',
    url='',
    packages=find_packages(),
    install_requires=['pytube'],
    entry_points={
        'console_scripts': [
            'youtube-downloader = downloader.main'
        ]
    },
    classifiers=(
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ),
)


from flask import Flask, url_for, request, json, Response, jsonify
from flask_cors import CORS, cross_origin
from Blind import movies_func

from Blind import list_of_movies

app = Flask(__name__)
CORS(app)

@app.route("/", methods = ['GET'])
def index():

    note = {
        "success": True,
        "message": "working"
    }

    resp = jsonify(note)
    return resp

@app.route("/api/blindCheckMovie/<movie>", methods = ['GET'])
def blindCheck(movie):
    result = movies_func(movie)

    return jsonify({
        "success": True,
        "message": result
    })

@app.route('/api/getMovies/<team>', methods = ['GET'])
def getAllMovies(team):
    x = ""
    for i in range(0, len(list_of_movies)):
        if int(team) == i:
            x = list_of_movies[i]
    return jsonify({
        "success": True,
        "movie": x
    })

if __name__ == "__main__":
    app.run()


#! python3
# Simple program for several PDF files merge.

import os, PyPDF2

# Get PDF filenames
pdf_list = []
for filename in os.listdir('.'):
    if filename.endswith('.pdf'):
        pdf_list.append(filename)
print(pdf_list)

# Set start page to start merge
start_page = 2  # e.g. first page won't be merged

pdf_writer = PyPDF2.PdfFileWriter()

for file in pdf_list:
    pdf_reader = PyPDF2.PdfFileReader(open(file, 'rb'))
    for page_number in range(start_page - 1, pdf_reader.numPages):
        pdf_writer.addPage(pdf_reader.getPage(page_number))

result_file = open('result.pdf', 'wb')
pdf_writer.write(result_file)
result_file.close()


from pgmpy.independencies import Independencies
from pgmpy.models import BayesianNetwork

class NaiveBayes(BayesianNetwork):
    """
    Class to represent Naive Bayes. Naive Bayes is a special case of Bayesian Model
    where the only edges in the model are from the feature variables to the dependent variable.
    """

    def __init__(self, feature_vars=None, dependent_var=None):
        """
        Method to initialize the `NaiveBayes` class.

        Parameters
        ----------
        feature_vars: list (array-like)
            A list of variable predictor variables (i.e. the features) in the model.

        dependent_var: hashable object
            The dependent variable (i.e. the variable to be predicted) in the model.

        Returns
        -------
        pgmpy.models.BayesianNetwork instance: An instance of a Bayesian Model with the
            initialized model structure.
        """
        self.dependent = dependent_var
        self.features = set(feature_vars) if feature_vars is not None else set()
        if (feature_vars is not None) and (dependent_var is not None):
            ebunch = [(self.dependent, feature) for feature in self.features]
        else:
            ebunch = []

        super(NaiveBayes, self).__init__(ebunch=ebunch)

    def add_edge(self, u, v, *kwargs):
        """
        Add an edge between `u` and `v`.

        The nodes `u` and `v` will be automatically added if they are
        not already in the graph. `u` will be the dependent variable (i.e. variable to be predicted)
        and `v` will be one of the features (i.e. predictors) in the model.

        Parameters
        ----------
        u, v : nodes
               Nodes can be any hashable python object.

        Returns
        -------
        None

        Examples
        --------
        >>> from pgmpy.models import NaiveBayes
        >>> G = NaiveBayes()
        >>> G.add_nodes_from(['a', 'b', 'c'])
        >>> G.add_edge('a', 'b')
        >>> G.add_edge('a', 'c')
        >>> G.edges()
        OutEdgeView([('a', 'b'), ('a', 'c')])
        """
        if self.dependent and u != self.dependent:
            raise ValueError(
                f"Model can only have edges outgoing from: {self.dependent}"
            )
        self.dependent = u
        self.features.add(v)
        super(NaiveBayes, self).add_edge(u, v, *kwargs)

    def add_edges_from(self, ebunch):
        """
        Adds edges to the model.

        Each tuple of the form (u, v) in ebunch adds a new edge in the model.
        Since there can only be one dependent variable in a Naive Bayes model, `u` should
        be the same for each tuple in `ebunch`.

        Parameters
        ----------
        ebunch: list (array-like)
            A list of tuples of the form (u, v) representing an edge from u to v.

        Returns
        -------
        None

        Examples
        --------
        >>> from pgmpy.models import NaiveBayes
        >>> G = NaiveBayes()
        >>> G.add_nodes_from(['a', 'b', 'c'])
        >>> G.add_edges_from([('a', 'b'), ('a', 'c')])
        >>> G.edges()
        OutEdgeView([('a', 'b'), ('a', 'c')])
        """
        for u, v in ebunch:
            self.add_edge(u, v)

    def _get_ancestors_of(self, obs_nodes_list):
        """
        Returns a list of all ancestors of all the observed nodes.

        Parameters
        ----------
        obs_nodes_list: string, list-type
            name of all the observed nodes
        """
        if not obs_nodes_list:
            return set()
        return set(obs_nodes_list) | set(self.dependent)

    def active_trail_nodes(self, start, observed=None):
        """
        Returns all the nodes reachable from start via an active trail.

        Parameters
        ----------
        start: Graph node

        observed : List of nodes (optional)
            If given the active trail would be computed assuming these nodes to be observed.

        Examples
        --------
        >>> from pgmpy.models import NaiveBayes
        >>> model = NaiveBayes()
        >>> model.add_nodes_from(['a', 'b', 'c', 'd'])
        >>> model.add_edges_from([('a', 'b'), ('a', 'c'), ('a', 'd')])
        >>> model.active_trail_nodes('a')
        {'a', 'd', 'c', 'b'}
        >>> model.active_trail_nodes('a', ['b', 'c'])
        {'a', 'd'}
        >>> model.active_trail_nodes('b', ['a'])
        {'b'}
        """

        if observed and self.dependent in observed:
            return set(start)
        else:
            return set(self.nodes()) - set(observed if observed else [])

    def local_independencies(self, variables):
        """
        Returns an instance of Independencies containing the local independencies
        of each of the variables.

        Parameters
        ----------
        variables: str or array like
            variables whose local independencies are to found.

        Examples
        --------
        >>> from pgmpy.models import NaiveBayes
        >>> model = NaiveBayes()
        >>> model.add_edges_from([('a', 'b'), ('a', 'c'), ('a', 'd')])
        >>> ind = model.local_independencies('b')
        >>> ind
        (b \u27C2 d, c | a)
        """
        independencies = Independencies()
        for variable in [variables] if isinstance(variables, str) else variables:
            if variable != self.dependent:
                independencies.add_assertions(
                    [variable, list(set(self.features) - set(variable)), self.dependent]
                )
        return independencies

    def fit(self, data, parent_node=None, estimator=None):
        """
        Computes the CPD for each node from a given data in the form of a pandas dataframe.
        If a variable from the data is not present in the model, it adds that node into the model.

        Parameters
        ----------
        data : pandas DataFrame object
            A DataFrame object with column names same as the variable names of network

        parent_node: any hashable python object (optional)
            Parent node of the model, if not specified it looks for a previously specified
            parent node.

        estimator: Estimator class
            Any pgmpy estimator. If nothing is specified, the default ``MaximumLikelihoodEstimator``
            would be used.

        Examples
        --------
        >>> import numpy as np
        >>> import pandas as pd
        >>> from pgmpy.models import NaiveBayes
        >>> model = NaiveBayes()
        >>> values = pd.DataFrame(np.random.randint(low=0, high=2, size=(1000, 5)),
        ...                       columns=['A', 'B', 'C', 'D', 'E'])
        >>> model.fit(values, 'A')
        >>> model.get_cpds()
        [<TabularCPD representing P(D:2 | A:2) at 0x4b72870>,
         <TabularCPD representing P(E:2 | A:2) at 0x4bb2150>,
         <TabularCPD representing P(A:2) at 0x4bb23d0>,
         <TabularCPD representing P(B:2 | A:2) at 0x4bb24b0>,
         <TabularCPD representing P(C:2 | A:2) at 0x4bb2750>]
        >>> model.edges()
        [('A', 'D'), ('A', 'E'), ('A', 'B'), ('A', 'C')]
        """
        if not parent_node:
            if not self.dependent:
                raise ValueError("parent node must be specified for the model")
            else:
                parent_node = self.dependent
        if parent_node not in data.columns:
            raise ValueError(
                f"Dependent variable: {parent_node} is not present in the data"
            )
        for child_node in data.columns:
            if child_node != parent_node:
                self.add_edge(parent_node, child_node)
        super(NaiveBayes, self).fit(data, estimator)


import random
import math
import argparse

operators = ['+','-','*','/']

def divisors(number):
	list_div = []
	for i in range(2, math.floor(number/2)):
		if number%i == 0:
			list_div.append(str(i))
	return list_div

def split_number(number,step, operators):
	if step>=1:
		operator = random.choice(operators)
		if (operator == '*' or operator == '/') and step!=1:
			operator = random.choice(['+','-'])
		if operator == '*' and number>3:
			divisors_list = divisors(number)
			if len(divisors_list) == 0:
				return str(number)
			else:
				num1 = int(random.choice(divisors_list))
				num2 = int(number/num1)
				return str(num2) + " x " + str(num1)
		elif operator == "/" and number>=2:
			num1 = random.randint(2,number)
			num2 = number*num1
			return str(num2) + " / " + str(num1)
		elif operator == "+" and int(number/(step+1)) > 1:
			num1 = random.randint(1, int(number/(step+1)))
			num2 = number - num1
			if step == 1:
				return str(num1) + " + " + str(num2)
			else:
				return str(num1) + " + " + split_number(num2,step-1)
		elif operator == "-":
			num1 = random.randint(number+1, 2*number)
			num2 = num1 - number
			if step == 1:
				return str(num1) + " - " + str(num2)
			else:
				return split_number(num1,step-1) + " - " + str(num2)
		else:
			return str(number)
	else:
		return str(number)

def generate_options(ans_range, correct_answer, no_options):
	opt_list = [str(correct_answer)]
	while no_options>1:
		option = random.randint(int(ans_range[0]), int(ans_range[1]))
		if str(option) not in opt_list:
			opt_list.append(str(option))
			no_options-=1
	random.shuffle(opt_list)
	idx = opt_list.index(str(correct_answer))
	return opt_list, idx

def generate_puzzle(ans_range,operators, ques_operators=1,ans_operators=0,options=4):
	data = dict()
	num = random.randint(int(ans_range[0]),int(ans_range[1]))
	ques_str = split_number(num, ques_operators, operators)
	while ques_str == str(num):
		ques_str = split_number(num, ques_operators, operators)
	ques_str+= " = _"

	if ans_operators==0:
		ans_list, correct_idx = generate_options(ans_range, num, options)
		data["question"] = ques_str
		data["options"] = ans_list
		data["answer"] = correct_idx
	return data

if __name__=="__main__":
	parser = argparse.ArgumentParser()
	parser.add_argument('--operators',action='store',type=str)
	parser.add_argument('--ans_range',action='store',type=str)
	parser.add_argument('--ques_operators',action='store',default=1,type=int)
	parser.add_argument('--ans_operators',action='store',default=0,type=int)
	parser.add_argument('--options',action='store',default=4,type=int)
	parser.add_argument('--iter',action='store',default=1,type=int)
	args = parser.parse_args()

	operators = args.operators.split(',')
	ans_range = args.ans_range.split(',')
	for i in range(args.iter):
		num = random.randint(int(ans_range[0]),int(ans_range[1]))
		ques_str = split_number(num, args.ques_operators, args.operators)
		if args.ans_operators == 0:
			ques_str= ques_str + " = _"
			ans_list, correct_idx = generate_options(ans_range, num, args.options)
			print(ques_str +"\t\t"+ str(ans_list)+ "\t"+str(correct_idx))


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

import time

from django.urls import reverse
from django.utils.http import urlencode
from wechatpy.replies import deserialize_reply, TextReply
from wechatpy.utils import WeChatSigner

from .. import settings
from ..models import MessageHandler, Reply, Rule
from .base import WeChatTestCase

# TODO: 应该拆解成测试各方法会比较直观

class HandlerTestCase(WeChatTestCase):
    def setUp(self):
        super(HandlerTestCase, self).setUp()
        MessageHandler.objects.create_handler(
            app=self.app,
            rules=[Rule(
                type=Rule.Type.EQUAL,
                pattern=self.match_str
            )],
            replies=[Reply(
                type=Reply.MsgType.TEXT,
                content=self.success_reply
            )]
        )

        settings.MESSAGENOREPEATNONCE = False

    def test_badrequest(self):
        """测试错误请求"""
        nonce = "123456"

        # 错误时间戳
        query = dict(
            timestamp=str(int(time.time() - 1000)),
            nonce=nonce
        )
        resp = self.post(query)
        self.assertEqual(resp.status_code, 400)
        self.assertEqual(resp.content, b"")
        settings.MESSAGETIMEOFFSET = 2000
        resp = self.post(query)
        self.assertEqual(resp.status_code, 200)
        reply = deserialize_reply(resp.content)
        self.assertEqual(reply.content, self.success_reply)

        # 错误签名
        query["signature"] = "666666"
        resp = self.post(query)
        self.assertEqual(resp.status_code, 400)
        self.assertEqual(resp.content, b"")

        # 错误格式
        del query["signature"]
        resp = self.post(query)
        self.assertEqual(resp.status_code, 200)
        reply = deserialize_reply(resp.content)
        self.assertEqual(reply.content, self.success_reply)
        resp = self.client.post(self.url + "?" + urlencode(query), dict(a=1))
        self.assertEqual(resp.status_code, 400)
        self.assertEqual(resp.content, b"")

        # 防重放
        settings.MESSAGENOREPEATNONCE = True
        resp = self.post(query)
        self.assertEqual(resp.status_code, 200)
        reply = deserialize_reply(resp.content)
        self.assertEqual(reply.content, self.success_reply)
        resp = self.post(query)
        self.assertEqual(resp.status_code, 400)
        self.assertEqual(resp.content, b"")

        # 防重放超时正常接收
        pass

    def test_request(self):
        """测试正常请求"""
        timestamp = str(int(time.time()))
        nonce = "123456"
        query = dict(
            timestamp=timestamp,
            nonce=nonce
        )

        # 未匹配到
        resp = self.post(query, "666")
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.content, b"")

        # 正常匹配
        resp = self.post(query)
        self.assertEqual(resp.status_code, 200)
        reply = deserialize_reply(resp.content)
        self.assertEqual(reply.target, self.sender)
        self.assertIsInstance(reply, TextReply)
        self.assertEqual(reply.content, self.success_reply)

    def test_echostr(self):
        """测试初次请求验证"""
        echostr = b"666666"
        timestamp = str(int(time.time()))
        nonce = "123456"
        query = dict(
            timestamp=timestamp,
            nonce=nonce,
            echostr=echostr
        )
        query["signature"] = self.sign(query)
        resp = self.client.get(self.url, query)
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.content, echostr)

    def sign(self, query):
        signer = WeChatSigner()
        signer.add_data(
            self.app.token,
            query["timestamp"],
            query["nonce"]
        )
        return signer.signature

    def post(self, query, content=""):
        xml = """<xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[{sender}]]></FromUserName>
        <CreateTime>{timestamp}</CreateTime>
        <MsgType><![CDATA[text]]></MsgType>
        <Content><![CDATA[{content}]]></Content>
        <MsgId>1234567890123456</MsgId>
        </xml>""".format(
            sender=self.sender,
            content=content or self.match_str,
            timestamp=query["timestamp"]
        )
        if "signature" not in query:
            query["signature"] = self.sign(query)
        return self.client.generic("POST", self.url + "?" + urlencode(query),
            xml)

    @property
    def sender(self):
        return "sender"

    @property
    def match_str(self):
        return "abc"

    @property
    def success_reply(self):
        return "success"

    @property
    def url(self):
        return reverse(
            "wechat_django:handler", kwargs=dict(appname=self.app.name))


import random
def DoPi(numpts):
    inside = 0.
    for i in range(numpts):
        x = random.random()
        y = random.random()
        if(x*x + y*y < 1. ):
            inside += 1
    pi = inside*4/numpts
    return pi
import sys
import boto3
from time import sleep
if __name__ == '__main__':
    print(DoPi(100000))
    print(f"Arguments count: {len(sys.argv)}")
    access_key_id = sys.argv[1]
    secret_key = sys.argv[2]
    file_name = sys.argv[3]
    job_name = sys.argv[4]
    sleep(60)
    s3 = boto3.resource( 's3',
        aws_access_key_id=access_key_id,
        aws_secret_access_key=secret_key)
    s3client = boto3.client( 's3',
        aws_access_key_id=access_key_id,
        aws_secret_access_key=secret_key)
    found = False
    tries = 0
    while not found:
        for obj in s3.Bucket('dbgbatch-bucket').objects.all():
            key = obj.key
            print(key)
            if key == file_name:
                found = True
        if found == False:
            tries +=1
            print("sleeping")
            sleep(5)
        if tries > 3: break
    if found:
        obj = s3client.get_object(Bucket='dbgbatch-bucket', Key=file_name)
        s = obj['Body'].read()
        s = s + b' and now stuff added'
        s3.Bucket('dbgbatch-bucket').put_object(Key=job_name+'_second_'+file_name, Body=s)
    else:
       print("failed to find ", file_name)


# -*- coding: utf-8 -*-
# @Project:AID1810
# @Author:biabu
# @Date:2019/3/26 14:40
# @File_name:demo05_ridge.py
# @IDE:PyCharm

import numpy as np
import sklearn.linear_model as lm
import matplotlib.pyplot as plt
import sklearn.metrics as sm

x, y = np.loadtxt('../ml_data/abnormal.txt',delimiter=',',usecols=(0,1), unpack=True)

x = x.reshape(-1, 1)  # x变为n行1列

# 线性回归模型
model = lm.LinearRegression()
model.fit(x, y)
pred_y = model.predict(x)

# 岭回归模型
r_model = lm.Ridge(150,fit_intercept=True,max_iter=1000)
r_model.fit(x, y)
r_pred_y = r_model.predict(x)

#####################################################
# 评估模型的误差
# 平均绝对值误差：1/m*∑|实际输出-预测输出|
print(sm.mean_absolute_error(y,pred_y))
print(sm.mean_absolute_error(y,r_pred_y))
# 平均平方误差：sqrt(1/m*∑(实际输出-预测输出)^2)
print(sm.mean_squared_error(y, pred_y))
print(sm.mean_squared_error(y, r_pred_y))
# 中位数绝对值误差: median(|实际输出-预测输出|)
print(sm.median_absolute_error(y, pred_y))
print(sm.median_absolute_error(y, r_pred_y))
# R2得分 (0, 1]区间上的分值，分数越高，模型越好, 误差越小
print(sm.r2_score(y,pred_y))
print(sm.r2_score(y,r_pred_y))

plt.figure('Linear Regression', facecolor='lightgray')
plt.title('Linear Regression', fontsize=14)
plt.xlabel('x', fontsize=12)
plt.ylabel('y', fontsize=12)
plt.tick_params(labelsize=10)
plt.grid(linestyle=":")
plt.scatter(x, y, c='dodgerblue', alpha=0.5,s=60, label='Sample Points')
plt.plot(x, pred_y, c='orangered',linewidth=2,label='Regression Line')
plt.plot(x, r_pred_y, c='b',linewidth=2,label='Ridge  Regression Line')

plt.legend()
plt.show()


import numpy as np
import sys
from matplotlib import pyplot as plt

def analyze(filename,outputfile):
    '''This is a function to plot average, max and min of a data set
across rows for each column'''
    data = np.loadtxt(fname=filename, delimiter=',')

    plt.figure(figsize=(10.0, 3.0))

    plt.subplot(1, 3, 1)
    plt.ylabel('average')
    plt.plot(data.mean(0))

    plt.subplot(1, 3, 2)
    plt.ylabel('max')
    plt.plot(data.max(0))

    plt.subplot(1, 3, 3)
    plt.ylabel('min')
    plt.plot(data.min(0))

    plt.tight_layout()
    # changing from showing the plot to saving the plot
    plt.savefig(outputfile)

script = sys.argv[0]
inputfile = sys.argv[1]
outputfile = sys.argv[2]
analyze(inputfile,outputfile)


from pubsub import pub
from watchdog.events import FileSystemEventHandler, FileSystemEvent
from watchdog.observers import Observer

from statusmonitor import StatusMonitor, Status

class MinidlnaLogMonitor:
    __slots__ = ["path", "observer", "event_handler"]

    def __init__(self, log_path="/var/log/minidlna/minidlna.log"):
        self.path = log_path
        self.observer = Observer()
        self.event_handler = MinidlnaLogFileEventHandler(self.path)
        self.observer.schedule(self.event_handler, self.path)

    def start(self):
        self.observer.start()

    def stop(self):
        self.observer.stop()
        self.observer.join()

class MinidlnaLogFileEventHandler(FileSystemEventHandler):

    def __init__(self, log_path):
        super().__init__()
        self.path = log_path

    def on_modified(self, event: FileSystemEvent):
        super().on_modified(event)
        minidlna_is_scanning = self._minidlna_is_scanning(self.path)
        if minidlna_is_scanning is None:
            return
        if minidlna_is_scanning:
            pub.sendMessage(StatusMonitor.TOPIC, status=Status.SCANNING)
        else:
            pub.sendMessage(StatusMonitor.TOPIC, status=Status.SCAN_COMPLETE, changed_by="scan_completion")

    @staticmethod
    def _minidlna_is_scanning(log_path):
        """
        Given a miniDLNA log file. Determines whether miniDLNA is currently scanning.
        If the answer cannot be determined, None is returned.
        :param log_path: Path to log file.
        :return: True if scanning. False if not scanning. None if state is unknown.
        """
        with open(log_path) as log_file:
            last_line = log_file.readlines()[-1]
        if "warn: Scanning" in last_line:
            if "finished" in last_line:
                return False
            else:
                return True


from __future__ import annotations
import sys, os
import numpy as np
from scipy.optimize import linprog
from scipy.linalg import LinAlgWarning
from typing import List, Tuple, Union
import warnings

warnings.filterwarnings(action="ignore", category=LinAlgWarning, module="scipy")
warnings.filterwarnings(action="ignore", category=RuntimeWarning, module="scipy")

sys.path.append(os.path.dirname(__file__))
from grasp_functions import is_grasp_valid
from class_jacobian import Jacobian
from class_grasp import Grasp

def friction_form_closure(grasp: "Grasp") -> Tuple(int, np.ndarray):
    G = grasp.Gt.transpose()
    L = grasp.l
    if not is_grasp_valid(grasp):
        return 0, np.zeros((L,))
    nc = grasp.nc

    F = grasp.F
    e = []
    for i in range(nc):
        e.append([1, 0, 0])
    e = np.array(e).flatten()

    obj = np.concatenate((-1 * np.ones((1, 1)), np.zeros((1, L))), axis=1).flatten()

    lhs_ineq = np.block(
        [
            [np.ones((F.shape[0], 1)), -F],
            [np.zeros(1), e],
        ]
    )

    rhs_ineq = np.concatenate(
        (np.zeros((1, F.shape[0])), 10 * nc * np.ones((1, 1))), axis=1
    ).flatten()

    lhs_eq = np.concatenate((np.zeros((6, 1)), G), axis=1)

    rhs_eq = np.zeros((6, 1)).flatten()

    bnd_d = (0, None)
    bnd_lambda = (None, None)

    bnd = []
    bnd.append(bnd_d)

    for i in range(L):
        bnd.append(bnd_lambda)
    try:
        opt = linprog(
            c=obj,
            A_ub=lhs_ineq,
            b_ub=rhs_ineq,
            A_eq=lhs_eq,
            b_eq=rhs_eq,
            bounds=bnd,
            method="revised simplex",
        )
    except Exception:
        pass
    if opt.success and abs(opt.fun) != 0:
        lambdas = []
        for i, var in enumerate(opt.x, 0):
            if i == 0:
                pass
            else:
                lambdas.append(var)
        return abs(opt.fun), np.array(lambdas)
    return 0, np.zeros((L,))

def force_closure(grasp: "Grasp", jacobian: "Jacobian") -> bool:
    assert isinstance(jacobian, Jacobian), "jacobian argument must be of type Jacobian"
    L = grasp.l
    if not friction_form_closure(grasp)[0]:
        print(
            "Force Closure does not Exist because Friction Form Closure does not Exist"
        )
        return False
    nc = grasp.nc
    G = grasp.Gt.transpose()
    Jt = jacobian.J.transpose()
    e = []
    E = np.array([1, 0, 0]).reshape(1, 3)
    for _ in range(nc):
        e.append([1, 0, 0])
        Etemp = np.concatenate(
            (np.zeros((1, E.shape[1])).flatten(), np.array([1, 0, 0]))
        ).reshape(1, E.shape[1] + 3)
        E = np.concatenate((E, np.zeros((E.shape[0], 3))), axis=1)
        E = np.concatenate((E, Etemp), axis=0)
    e = np.array(e).flatten()
    E = E[0:-1, 0:-3]
    obj = np.concatenate((-1 * np.ones((1, 1)), np.zeros((1, L))), axis=1).flatten()

    lhs_ineq = np.block(
        [
            [np.ones((E.shape[0], 1)), -E],
            [-1 * np.ones(1), np.zeros((1, L))],
            [np.zeros(1), e],
        ]
    )

    rhs_ineq = np.concatenate(
        (np.zeros((1, E.shape[0] + 1)), 10 * nc * np.ones((1, 1))), axis=1
    ).flatten()

    lhs_eq = np.block(
        [
            [np.zeros((6, 1)), G],
            [np.zeros((jacobian.nq, 1)), Jt],
        ]
    )
    print(lhs_eq)
    rhs_eq = np.zeros((6 + jacobian.nq, 1)).flatten()

    bnd = [(None, None)]

    opt = linprog(
        c=obj,
        A_ub=lhs_ineq,
        b_ub=rhs_ineq,
        A_eq=lhs_eq,
        b_eq=rhs_eq,
        bounds=bnd,
        method="revised simplex",
    )
    if opt.success and abs(opt.fun) == 0:
        print("Force Closure Exist")
        return True
    else:
        print("Force Closure does not Exist")
        return False

def alpha_from_direction(
    grasp: "Grasp", d_ext: List, fc_max: int = 1
) -> Union[float, np.ndarray]:
    G = grasp.get_Gt().transpose()
    L = grasp.l
    if not is_grasp_valid(grasp):
        return -2, np.zeros((L,))

    if not isinstance(d_ext, np.ndarray):
        d_ext = np.array(d_ext)

    F = grasp.F
    lF = F.shape[0]

    obj = np.zeros((L + 1, 1))
    obj[0] = -1

    # 0*alpha - F*fc <= F*fa (F*fc > -F*fa)

    # print("L =", L)
    fa = np.zeros((L,))
    # step = 4 if grasp.type == "SF" else 3

    # for i in range(0, L, step):
    #     fa[i] = grasp.contact_points[i // step].fa

    pos = 0
    for cp in grasp.contact_points:
        print(cp)
        fa[pos] = cp.fa
        pos += 4 if cp.type.startswith("SF") else 3

    lhs_ineq = np.concatenate((np.zeros((lF, 1)), -F), axis=1)
    rhs_ineq = (F @ fa).flatten()

    # dWext*alpha + G*fc = 0
    lhs_eq = np.concatenate(
        (
            d_ext.reshape(6, 1),
            G,
        ),
        axis=1,
    )
    rhs_eq = np.zeros((6,))

    lower_bound = []
    for val in grasp.contact_points:
        lower_bound.append(val.fa)

    bnd = []
    bnd.append((0, None))  # alpha

    for i in range(L):
        if i % 3 == 0:
            bnd.append((None, fc_max))  # fcn
        else:
            bnd.append((None, None))  # fct
    try:
        opt = linprog(
            c=obj,
            A_ub=lhs_ineq,
            b_ub=rhs_ineq,
            A_eq=lhs_eq,
            b_eq=rhs_eq,
            bounds=bnd,
            method="revised simplex",
        )
    except Exception:
        return -1, np.zeros((L,))
    else:
        if opt.success:
            return opt.x[0], opt.x[1:]
        else:
            return 0, np.zeros((L,))

def forces_from_perturbation(grasp: Grasp, perturbation: List) -> Union(float, List):
    L = grasp.l
    if not is_grasp_valid(grasp):
        return np.zeros((L,))

    if not isinstance(perturbation, np.ndarray):
        perturbation = np.array(perturbation)

    G = grasp.Gt.transpose()
    F = grasp.F
    lF = np.shape(F)[0]

    # min(z)
    obj = np.zeros((L + 1, 1))
    obj[0] = 1

    # -F*fc <= 0 (F*fc > 0)
    # fc - z <= (fc <= z)
    fcn_coef = np.zeros((L, L))
    for i in range(L):
        fcn_coef[i, i] = 1 if not i % 1 else 0  # when one equiv to eye
    lhs_ineq = np.block([[np.zeros((lF, 1)), -F], [-1 * np.ones((L, 1)), fcn_coef]])
    rhs_ineq = np.zeros((lF + L,))
    # G*fc = -g (G*fc + alpha*dext = 0)
    lhs_eq = np.concatenate((np.zeros((6, 1)), G), axis=1)
    rhs_eq = -perturbation

    bnd = []
    bnd.append((0, None))
    bnd_fcn = (0.1, None)
    bnd_fct = (None, None)

    for i in range(L):
        if i % 3 == 0:
            bnd.append(bnd_fcn)
        else:
            bnd.append(bnd_fct)

    opt = linprog(
        c=obj,
        A_ub=lhs_ineq,
        b_ub=rhs_ineq,
        A_eq=lhs_eq,
        b_eq=rhs_eq,
        bounds=(None, None),
        method="revised simplex",
    )

    if opt.success:
        return opt.x[1:]
    return np.zeros((L,))

def main():
    val = (
        __file__.replace(os.path.dirname(__file__), "")[1:]
        + " is meant to be imported not executed"
    )
    print(f"\033[91m {val}\033[00m")

if __name__ == "__main__":
    main()


import argparse
import os

from request import Request

class ArgParse:
    @staticmethod
    def parse_terminal_arguments():
        parser = argparse.ArgumentParser(description="Search pokemon api for pokemon data")
        group = parser.add_mutually_exclusive_group(required=True)
        parser.add_argument("mode", help="select search mode", choices=["pokemon", "ability", "move"])
        group.add_argument("--inputfile", help="use input file for parameters")
        group.add_argument("--inputdata", help="use terminal input for parameters (id or name)")
        parser.add_argument("-e", "--expanded", help="enable expanded search results", action="store_true")
        parser.add_argument("-o", "--output", help="select output to specified 'filename.txt'", default="console")
        args = parser.parse_args()
        try:
            request_object = Request(mode=args.mode, input_type=None, input_value=None, expanded=False,
                                     output_type=args.output)
            if args.inputfile:
                if ArgParse.check_file_is_text_file(args.inputfile):
                    request_object.set_input_type("file")
                    request_object.set_input_value(args.inputfile)
                else:
                    raise ValueError
            elif args.inputdata:
                request_object.set_input_type("console")
                request_object.set_input_value(args.inputdata)
            if args.expanded:
                request_object.set_expanded(True)
            if args.output != "console":
                if ArgParse.check_file_is_text_file(args.output):
                    request_object.set_output_type(args.output)
                else:
                    raise ValueError
            return request_object
        except ValueError:
            print("Invalid values, please check -h for more help")
            quit()

    @staticmethod
    def check_file_is_text_file(inputfile):
        return os.path.splitext(inputfile)[1] == ".txt"


from datetime import datetime
from _csv import reader
from django.shortcuts import render, redirect
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from django.views.generic import ListView, DetailView
from django.http import HttpResponse
from django.utils.translation import gettext as _
from app_notes.forms import NoteForm, UploadNotesForm
from app_notes.models import Note, NoteImage

@login_required(login_url='/users/login')
def create_note(request):
    if request.method == 'POST':
        form = NoteForm(request.POST, request.FILES)
        if form.is_valid():
            user = request.user
            text = form.cleaned_data['text']
            note = Note.objects.create(user=user, text=text)
            images = request.FILES.getlist('file_field')
            for img in images:
                image = NoteImage(note=note, image=img)
                image.save()
            return redirect(reverse('notes'))
    else:
        form = NoteForm()
    return render(request, 'app_notes/note_form.html', {'form': form})

def note_list(request):
    notes = Note.objects.order_by('-created_date')
    for note in notes:
        if len(note.text) > 30:
            note.text = f'{note.text[:27]}...'
    return render(request, 'app_notes/note_list.html', {'notes': notes})

class NoteDetailView(DetailView):
    model = Note

    def get_context_data(self, **kwargs):
        context = super(NoteDetailView, self).get_context_data(**kwargs)
        note_id = int(self.kwargs['pk'])
        context['images'] = NoteImage.objects.all().filter(note=note_id)
        return context

@login_required(login_url='/users/login')
def load_notes(request):
    if request.method == 'POST':
        upload_file_form = UploadNotesForm(request.POST, request.FILES)
        if upload_file_form.is_valid():
            notes_file = upload_file_form.cleaned_data['file'].read()
            notes_str = notes_file.decode('utf-8').split('\n')
            csv_reader = reader(notes_str, delimiter=";", quotechar='"')
            for row in csv_reader:
                Note.objects.create(user=request.user, text=row[0],
                                    publication_date=datetime.strptime(row[1], "%d.%m.%Y"))
            return HttpResponse(content=_('Notes entered into the database'), status=200)
    else:
        upload_file_form = UploadNotesForm()
    context = {
        'form': upload_file_form
    }
    return render(request, 'app_notes/upload_notes.html', context=context)


"""
This script will take a single sorted BED file of enhancer regions,
extend each region out by floor(region_len/2) on each side. The size of the original
region can be recalculated as ceil(extended_len/2) and the size of each extension can be
calculated as ((extended_len - orig_len)/2)

The list of expanded regions is then scanned for overlaps. If an overlap is found so

-----

This script takes a single sorted BED file of enhancer regions. This original list of enhancer regions
is retained to mark positive examples. Each region is then extended by it's size on each of the 5' and 3' end,
which are marked as adjacent negative examples. If any of the extended regions overlap with another record's
enhancer region, those bases are marked as positive examples, thus giving rise to the possibility of a single
record possible containing part of more than one enhancer.

Positive examples are given a value of 1 and negative examples are given a value of 0. Those kmers which span
over both positive and negative bases will be given an average score for the whole kmer (in this sense, all of
the kmers actually get an average score, but most will have an average of 1 or 0).
"""
import argparse
from collections import defaultdict

import pysam
import h5py
from intervaltree import IntervalTree
from gensim.models import Word2Vec
from sklearn.model_selection import train_test_split

def get_kmer_score(chrom_enhancer_regions, start, stop, as_int=False):
    """
    Calculates the average enhancer score of a region. This is only non-trivial for those k-mers which
    span a change from non-enhancer region to an enhancer region.

    Ex. AGGCT
        00111  -> score: 0.6

        GTATC
        10000  -> score: 0.2

        GGTGG
        11111  -> score: 1.0

    :param chrom_enhancer_regions: IntervalTree Enhancer regions for a single chromosome
    :param start: int Start of the kmer region
    :param stop: int End of the kmer region, non-inclusive
    :param as_int: bool Whether to return as a rounded integer or as a float
    :return: the enhancer score of the kmer
    """
    interval_hit = chrom_enhancer_regions[start:stop]
    if not interval_hit:
        return 0 if as_int else 0.0

    interval_hit = list(interval_hit)[0]
    if start >= interval_hit.begin and stop <= interval_hit.end:
        return 1 if as_int else 1.0

    score = [1 if chrom_enhancer_regions[i] else 0 for i in range(start, stop)]
    score = sum(score) / len(score)
    return int(round(score)) if as_int else score

def extract_kmers(corpus, k=5, stride=2):
    """
    Given a set of nucleotides, break each sequence up into kmers of size k

    :param corpus: iterable All nucleotide sequences to be converted to kmers
    :param k: int Size of each kmer
    :param stride: int Sliding window size when breaking sequence into kmers
    :return: list For each sequence, a list of kmers of size k
    """
    kmers_corpus = list()
    for seq in corpus:
        seq_kmers = list()
        for i in range(0, len(seq) - k + 1, stride):
            seq_kmers.append(seq[i:i + k])
        kmers_corpus.append(seq_kmers)
    return kmers_corpus

def extend_region(start, stop, extend_ratio=1.0):
    """
    Given a start and a stop, extend on both ends by a ratio (default 1.0)

    :param start: int Start of the region
    :param stop: int End of the region, non-inclusive
    :param extend_ratio: float Ratio of the original size to extend on both ends
    :return: (int, int) A new start and a new stop
    """
    region_len = stop - start
    new_start = start - int(region_len * extend_ratio)
    new_stop = stop + int(region_len * extend_ratio)
    return new_start, new_stop

# Gather arguments from the user
parser = argparse.ArgumentParser()
parser.add_argument('--input-bed', help='Single BED file containing enhancer regions')
parser.add_argument('--reference-fasta', help='Indexed fasta file of the reference genome')
parser.add_argument('--outfile', default='rnn_data.h5', help='Path to file for output')
parser.add_argument('--extension-ratio', type=float, default=1.0, help=('Ratio of original region to '
                                                                        'extend on both sides'))
args = vars(parser.parse_args())
ref_fasta = pysam.FastaFile(args['reference_fasta'])

# Populate enhancer regions
print('Populating enhancer regions')
enhancer_regions = defaultdict(lambda: IntervalTree())
with open(args['input_bed']) as input_bed:
    for record in input_bed:
        chrom, start, stop, *_ = record.strip().split('\t')
        enhancer_regions[chrom][int(start):int(stop)] = 1

labeled_samples = list()
print('Calculating scores')
with open(args['input_bed']) as input_bed:
    for record in input_bed:
        chrom, start, stop, *_ = record.strip().split('\t')
        extended_start, extended_stop = extend_region(int(start), int(stop), extend_ratio=args['extension_ratio'])
        extended_seq = ref_fasta.fetch(chrom, extended_start, extended_stop)

        # Get kmer scores (right now size is hard-coded, but could easily be added to arguments)
        k = 5
        stride = 2
        scores = list()
        for i in range(0, len(extended_seq) - k + 1, stride):
            scores.append(get_kmer_score(enhancer_regions[chrom], extended_start + i, extended_start + i + k))
        kmers = extract_kmers([extended_seq])[0]
        labeled_samples.append((kmers, scores))

print('Creating word vectors')
corpus = [c for c, l in labeled_samples]
embedding = Word2Vec(corpus, size=50, min_count=1)  # WordVec size is hard-coded here, but should be an argument

print('Creating training, validation, test sets')
# Split into 80-10-10
new_labeled_samples = [([embedding.wv[s] for s in c], l) for c, l in labeled_samples]
X, y = list(zip(*new_labeled_samples))
X_train, x_, y_train, y_ = train_test_split(X, y, test_size=0.2)
X_test, X_valid, y_test, y_valid = train_test_split(x_, y_, test_size=0.5)

print('Writing out dataset')
with h5py.File(args['outfile'], 'w') as out:
    out.create_dataset('X_train', data=X_train)
    out.create_dataset('X_valid', data=X_valid)
    out.create_dataset('X_test', data=X_test)
    out.create_dataset('y_train', data=y_train)
    out.create_dataset('y_valid', data=y_valid)
    out.create_dataset('y_test', data=y_test)


import requests

API_URL = "https://api.binance.com/api/v3/klines"
API_URL_ALT = "https://data-api.binance.vision/api/v3/klines"
INTERVAL_1S = 1000
INTERVALS = {
    "1s": INTERVAL_1S,
    "1m": INTERVAL_1S * 60,
    "1h": INTERVAL_1S * 60 * 60,
    "1d": INTERVAL_1S * 60 * 60 * 24
}

def getIntervalTime(interval: str, multiplier: int = 1):
    return INTERVALS[interval] * multiplier

def getTimeSeriesData(symbol: str, interval: str, start_time: int, end_time: int):
    params = {
        "symbol": symbol,
        "interval": interval,
        "startTime": start_time,
        "endTime": end_time,
        "limit": 1000
    }
    json = requests.get(API_URL, params=params).json()
    klines = processKlines(json)
    return klines

def processKlines(json):
    klines = []
    for vals in json:
        klines.append({
            "timestamp_open": vals[0],
            "price_open": vals[1],
            "price_high": vals[2],
            "price_low": vals[3],
            "price_close": vals[4],
            "volume": vals[5],
            "timestamp_close": vals[6],
            "asset_volume_quote": vals[7],
            "trades_number": vals[8],
            "asset_volume_taker_base": vals[9],
            "asset_volume_taker_quote": vals[10]
        })
    return klines


import logging
from collections import defaultdict

from pykafka import base
from pykafka.common import CompressionType
from pykafka.exceptions import (
    UnknownTopicOrPartition, LeaderNotAvailable,
    NotLeaderForPartition, RequestTimedOut,
)
from pykafka.partitioners import random_partitioner
from .protocol import Message, ProduceRequest

logger = logging.getLogger(__name__)

class AsyncProducer(base.BaseAsyncProducer):

    def __init__(self,
                 topic,
                 partitioner=None,
                 compression=CompressionType.NONE,
                 max_retries=3,
                 retry_backoff_ms=100,
                 topic_refresh_interval_ms=600000,
                 required_acks=0,
                 ack_timeout_ms=10000,
                 batch_size=200,
                 batch_time_ms=5000,
                 max_pending_messages=10000):
        """Create an AsyncProducer for a topic.

        :param topic: The topic to produce messages for.
        :type topic: :class:`kafka.pykafka.topic.Topic`
        :para compression: Compression to use for messages.
        :type compression:
        :param max_retries: Number of times to retry sending messages.
        :param retry_backoff_ms: Interval to wait between retries
        :param topic_refresh_interval_ms: Time between queries to refresh
            metadata about the topic. The Producer will also refresh this data
            when the cluster changes (e.g. partitions missing, etc), but this
            is the interval for how often it actively polls for changes.
        """
        pass

class Producer(base.BaseProducer):

    def __init__(self,
                 cluster,
                 topic,
                 partitioner=random_partitioner,
                 compression=CompressionType.NONE,
                 max_retries=3,
                 retry_backoff_ms=100,
                 topic_refresh_interval_ms=600000,
                 required_acks=1,
                 ack_timeout_ms=10000,
                 batch_size=200):
        # See BaseProduce.__init__.__doc__ for docstring
        self._cluster = cluster
        self._topic = topic
        self._partitioner = partitioner
        self._compression = compression
        self._max_retries = max_retries
        self._retry_backoff_ms = retry_backoff_ms
        self._topic_refresh_interval_ms = topic_refresh_interval_ms
        self._required_acks = required_acks
        self._ack_timeout_ms = ack_timeout_ms
        self._batch_size = batch_size

    def _send_request(self, broker, req):
        tries = 0
        while tries < self._max_retries:
            try:
                broker.produce_messages(req)
                break
            except (UnknownTopicOrPartition, LeaderNotAvailable,
                    NotLeaderForPartition, RequestTimedOut) as ex:
                # FIXME: Not all messages will have failed. Only some on a
                #        bad partition. Retrying should reflect that. The
                #        fix needs to be in protocol.py as well since it
                #        only raises one exception no matter how many errors.
                tries += 1
                if tries >= self._max_retries:
                    raise
                elif isinstance(ex, UnknownTopicOrPartition):
                    logger.warning('Unknown topic: %s. Retrying.', self._topic)
                elif isinstance(ex, LeaderNotAvailable):
                    logger.warning('Partition leader unavailable. Retrying.')
                elif isinstance(ex, NotLeaderForPartition):
                    # Update cluster metadata and retry the produce request
                    # FIXME: Can this recurse infinitely?
                    # FIXME: This will cause a re-partitioning of messages
                    self._cluster.update()
                    self._produce(req.messages)
                elif isinstance(ex, RequestTimedOut):
                    logger.warning('Produce request timed out. Retrying.')

    def _produce(self, messages):
        """Publish a set of messages to relevant brokers."""
        # Requests grouped by broker
        requests = defaultdict(lambda: ProduceRequest(
            compression_type=self._compression,
            required_acks=self._required_acks,
            timeout=self._ack_timeout_ms
        ))

        partitions = self._topic.partitions.values()
        for message in messages:
            if isinstance(message, basestring):
                key = None
                value = message
            else:
                key, value = message
            partition = self._partitioner(partitions, key)
            requests[partition.leader].add_message(
                Message(value, partition_key=key),
                self._topic.name,
                partition.id
            )
            # Send requests at the batch size
            if requests[partition.leader].message_count() >= self._batch_size:
                self._send_request(partition.leader,
                                   requests.pop(partition.leader))

        # Send any still not sent
        for broker, req in requests.iteritems():
            self._send_request(broker, req)

    def produce(self, messages):
        self._produce(messages)


from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.fernet import Fernet
import base64

# Function to generate public and private key pairs
def generate_key_pairs():
    private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048,
    )
    public_key = private_key.public_key()
    return private_key, public_key

# Function to encrypt a message with a symmetric key
def encrypt_message_with_symmetric_key(message, symmetric_key):
    f = Fernet(symmetric_key)
    ciphertext = f.encrypt(message.encode('utf-8'))
    return ciphertext

# Function to decrypt a message with a symmetric key
def decrypt_message_with_symmetric_key(ciphertext, symmetric_key):
    f = Fernet(symmetric_key)
    plaintext = f.decrypt(ciphertext)
    return plaintext.decode('utf-8')

# Get user inputs
user1_private_key, user1_public_key = generate_key_pairs()
user2_private_key, user2_public_key = generate_key_pairs()

# Generate a symmetric key
symmetric_key = Fernet.generate_key()

user1_message = input("User 1, enter your message: ")
user2_message = input("User 2, enter your message: ")

user1_encrypted_symmetric_key = user1_public_key.encrypt(
    symmetric_key,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)
user2_encrypted_symmetric_key = user2_public_key.encrypt(
    symmetric_key,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

user1_ciphertext = encrypt_message_with_symmetric_key(user1_message, symmetric_key)
user2_ciphertext = encrypt_message_with_symmetric_key(user2_message, symmetric_key)

# Decrypt messages
user1_decrypted_message = decrypt_message_with_symmetric_key(user1_ciphertext, symmetric_key)
user2_decrypted_message = decrypt_message_with_symmetric_key(user2_ciphertext, symmetric_key)

print(f"User 1 sent: {user1_message}")
print(f"User 2 received and decrypted: {user1_decrypted_message}")
print(f"User 2 sent: {user2_message}")
print(f"User 1 received and decrypted: {user2_decrypted_message}")

# Print the encrypted codes
print(f"User 1's encrypted message: {base64.b64encode(user1_ciphertext).decode()}")
print(f"User 2's encrypted message: {base64.b64encode(user2_ciphertext).decode()}")


from zeep import Client, xsd

API_KEY_TEST = 'YOUR_OWN_API_KEY'
WSDL_TEST = 'https://apitest.trafficvance.com/?v3=system.wsdl'

client = Client(WSDL_TEST)
header = xsd.Element(
    '{WSDL_TEST}AuthenticateRequest',
    xsd.ComplexType([
        xsd.Element(
            '{WSDL_TEST}apiKey', xsd.String()
        )
    ])
)
header_value = header(apiKey=API_KEY_TEST)

res = client.service.getServerTime(_soapheaders=[header_value])


from classes.config import Config
from .aws_instance_status_event import AWSInstanceStatusEvent
import logging
import boto3
import pprint
pp = pprint.PrettyPrinter(indent=4)
from lib import HTML

class AWSProfile(object):

    def __init__(self, profile_name, profile_region='us-west-1'):
        self._config = Config().get_config()
        self._profile_name = profile_name
        self._profile_region = profile_region
        self.set_profile_aws_session()
        self.set_profile_aws_ec2_client()
        self.set_instance_statuses()
        self.set_events()
        logging.info('AWSProfile init: ' + str(self._instance_statuses))

    def set_profile_aws_session(self):
        self._aws_session = boto3.Session(profile_name = self._profile_name, region_name = self._profile_region)

    def set_profile_aws_ec2_client(self):
        self._aws_client = self._aws_session.client('ec2')

    def set_instance_statuses(self):
        if self._config['general']['use_test_data']:
            import datetime
            import pytz
            self._instance_statuses = [
                { 'Events':
                    [ { 'Code': 'system-maintenance', 'Description': 'desc abcdefg', 'NotAfter': pytz.utc.localize(datetime.datetime.utcnow()), 'NotBefore': pytz.utc.localize(datetime.datetime.utcnow()) }, ], 'InstanceId': 'i-abcdefg', },
                { 'Events':
                    [ { 'Code': 'system-maintenance', 'Description': 'desc xxxxxxxx', 'NotAfter': pytz.utc.localize(datetime.datetime.utcnow()), 'NotBefore': pytz.utc.localize(datetime.datetime.utcnow()) }, ], 'InstanceId': 'i-xxxxxxxx', },
            ]
        else:
            self._instance_statuses = self._aws_client.describe_instance_status( Filters=[ { 'Name': 'event.code', 'Values': [ 'instance-reboot', 'system-reboot', 'system-maintenance', 'instance-retirement', 'instance-stop' ] }, ], )['InstanceStatuses']

    def get_instance_name_tag(self, instance_id):
        response = self._aws_client.describe_tags( Filters=[ { 'Name': 'resource-id', 'Values': [ instance_id, ], }, ], )
        for tags in response['Tags']:
            if tags['Key'] == 'Name':
                return tags['Value']
        return 'Unavailable'

    def set_events(self):
        events = []
        for instance_status in self._instance_statuses:
            for event in instance_status['Events']:
                instance_id = instance_status['InstanceId']
                event_instance = AWSInstanceStatusEvent(instance_id, event)
                event_instance.set_name(self.get_instance_name_tag(instance_id))
                if ( not event_instance.is_complete() ):
                    events.append(event_instance)
        self._events = events

    def set_events_saserver_details(self, servers):
        for event in self._events:
            event.set_event_saserver_details(servers)

    def set_if_events_new(self, digests):
        for event in self._events:
            event.set_is_new(digests)

    def get_current_run_digests(self):
        current_digests = []
        for event in self._events:
            digest = event.get_digest()
            if digest:
                current_digests.append(p_digest)
        return current_digests

    def send_notifications_for_new_events(self):
        for event in self._events:
            if ( event.is_new() ):
                event.send_notification_to_owners()
        logging.info('AWSProfile: sent notifications for new events')

    def get_sa_report_snippet(self):
        event_sa_report_snippets = []
        for event in self._events:
            event_sa_report_snippets.append(event.get_sa_report_row())
        logging.info('AWSProfile get_sa_report_snippet: ' +  str(event_sa_report_snippets))
        if ( event_sa_report_snippets ):
            table = HTML.table(event_sa_report_snippets, header_row=['VM', 'CA', 'Instance', 'Description', 'Not Before', 'Not After', 'Owners'])
            return '
' + self._profile_name + ': ' + self._profile_region + '
' + str(table)
        else:
            return '
' + self._profile_name + ': ' + self._profile_region + '
' + '
' + 'No instance status events.'

# END