import os
import glob
import sys, stat
import re
import pdb
import time
##Creates the TextList
##Preconditions:
#   fileTxt - the Buildlog.txt
def createTextList(fileTxt):
    print("Creating TextList"+"....", end="", flush=True)
    filename = fileTxt
    lines = [line for line in open(filename)]
    os.chmod(filename, 0o777)
    F = open(filename, "w")
    ## keeps creating new lines on repeat##
    ##checks for duplicates and puts a \n on it
    for i in range(len(lines)):
       for j in range(i, len(lines)):
           #print (lines[i])
           if lines[i] == lines[j] and i != j:
               lines[i] = ''
       if lines[i] != '':
           F.write(''.join([lines[i], '\n']))
       F.flush()
    F.close()
    # flipping the list is necessary to clean assigned data type
    lines = lines[::-1]

    # remove this once finished with project, it's only for readability
    newfilename = "BuildLog1.txt"
    F = open(newfilename, "w")
    for i in lines:
        F.write(i)
        F.flush()
    F.close()
    print( "[Complete]")
    return lines

## main call function to fix all the errors
def fixAllErrors(fileLoc, fileList):
    initTime = time.time()
    fixError6278(fileList, fileLoc)
    fixError6362_7319(fileList, fileLoc)
    fixError6222(fileList, fileLoc)
    fixError6418(fileList, fileLoc)
    fixError6158(fileList, fileLoc)
    fixError6404(fileList, fileLoc)
    fixError6239(fileList, fileLoc)
    fixError6401(fileList, fileLoc)
    fixError6186(fileList, fileLoc)
    print("Time taken by functions: " + str(time.time()- initTime) +"s")

## this implicit statement is not positioned correctly within the scope
## fixs the above error
##Precondition:
##  txtLines - the BuildLog.txt
##  fileLocation - file directory
def fixError6278(txtLines, fileLocation):
    print("Fixing error:6278 " + "....", end="", flush=True)
    for i in range(len(txtLines)):
        A = txtLines[i]
        FindIndex4 = A.find("error #6278")
        if FindIndex4 != -1:
            LeftIndex2 = A.rfind("\\")
            RightIndex2 = A.rfind("(")
            newfilename = A[LeftIndex2+1:RightIndex2]
            print ("6278:" + newfilename)
            newfilename = fileLocation + newfilename

            LeftIndex3 = A.rfind("(")
            RightIndex3 = A.rfind(")")
            FileLine = A[LeftIndex3+1:RightIndex3]
            os.chmod(newfilename, 0o777)
            VarLine = int(FileLine)-1
            lines4 = [line4 for line4 in open(newfilename)]

            for ii in range(VarLine):
                if "IMPLICIT NONE" in lines4[ii]:
                    Index4 = ii

            F = open(newfilename, 'w')

            for iii in range(len(lines4)):
                if iii == Index4:
                    F.write("")
                    F.flush()
                elif iii == VarLine:
                    F.write(lines4[iii])
                    F.flush()
                    F.write("      IMPLICIT NONE\n")
                    F.flush()
                else:
                    F.write(lines4[iii])
                    F.flush()
            F.close()
    print( "[Complete]")

# Error error #6362: The data types of the argument(s) are invalid.
# error : 7319 This argument's data type is incompatible with this intrinsic procedure; procedure assumed
## fixs the above error
##Precondition:
##  txtLines - the BuildLog.txt
##  fileLocation - file directory
def fixError6362_7319(txtLines, fileLocation):
    print("Fixing error:6362_7319 " + "....", end="", flush=True)
    for i in range(len(txtLines)):
       A = txtLines[i]
       FindIndex2 = A.find("error #6362")
       FindIndex3 = A.find("error #7319")

       if FindIndex2 != -1 or FindIndex3 != -1:
           LeftIndex1 = A.find("[")
           RightIndex1 = A.find("]")
           Var = A[LeftIndex1+1:RightIndex1]

           LeftIndex2 = A.rfind("\\")
           RightIndex2 = A.find("(")
           newfilename = fileLocation + A[LeftIndex2+1:RightIndex2]
           print ("6362/7319:" + newfilename)
           os.chmod(newfilename, 0o777)

           lines6 = [line6 for line6 in open(newfilename)]
           F = open(newfilename, 'w')

           for ii in range(len(lines6)):
               if 'REAL '+Var in lines6[ii] or 'INTEGER '+Var in lines6[ii]:
                   F.write("\n")
                   F.flush()
               else:
                   F.write(lines6[ii])
                   F.flush()
           F.close()
    print( "[Complete]")

#error #6222: This IMPLICIT statement is not positioned correctly within the scoping unit.
## fixs the above error
##Precondition:
##  txtLines - the BuildLog.txt
##  fileLocation - file directory
def fixError6222(txtLines, fileLocation):
    print("Fixing Error:6222 " + "....", end="", flush=True)
    for i in range(len(txtLines)):
       A = txtLines[i]
       FindIndex2 = A.find("error #6222")

       if FindIndex2 != -1:
           LeftIndex2 = A.rfind("\\")
           RightIndex2 = A.rfind("(")
           newfilename = A[LeftIndex2+1:RightIndex2]
           print ("6222:" + newfilename)
           LeftIndex3 = A.rfind("(")
           RightIndex3 = A.rfind(")")
           FileLine = A[LeftIndex3+1:RightIndex3]

           os.chmod(newfilename, 0o777)

           lines7 = [line7 for line7 in open(NewFileName)]
           VarLine = int(FileLine)-1
           F = open(NewFileName, 'w')

           for ii in range(len(lines7)):
               if ii == VarLine and ("IMPLICIT NONE" in lines7[ii] or "IMPLICIT      NONE" in lines7[ii]):
                   F.write("\n")
                   F.flush()
               else:
                   F.write(lines7[ii])
                   F.flush()
           F.close()
    print( "[Complete]")

##This name has already been assigned a data type
## fixs the above error
##Precondition:
##  txtLines - the BuildLog.txt
##  fileLocation - file directory
def fixError6418(txtLines, fileLocation):
    print("Fixing Error:6418 " + "....", end="", flush=True)
    for i in range(len(txtLines)):
       A = txtLines[i]
       FindIndex2 = A.find("error #6418")
       if FindIndex2 != -1:
           LeftIndex2 = A.rfind("\\")
           RightIndex2 = A.rfind("(")
           NewFileName = fileLocation+ A[LeftIndex2+1:RightIndex2]

           LeftIndex3 = A.rfind("(")
           RightIndex3 = A.rfind(")")
           FileLine = A[LeftIndex3+1:RightIndex3]
           # NewFileName = fileLocation + NewFileName
           # print ("6418:" + NewFileName)
           os.chmod(NewFileName, 0o777)
           VarLine = int(FileLine)-1
           if NewFileName.endswith('.f') or NewFileName.endswith('.for'):
    ##        if NewFileName  == "solve_udc_moon.f":
               lines2 = [line2 for line2 in open(NewFileName)]
               F = open(NewFileName, 'w')

               for ii in range(len(lines2)):
                   if ii != VarLine:
                       F.write(lines2[ii])
                       F.flush()
                   elif "real" in lines2[ii].lower() or "integer" in lines2[ii].lower():
                       if "," in lines2[ii]:
                           F.write(lines2[ii])
                           F.flush()
                       else:
                           F.write("C This line was deliberately left commented\n")
                           F.flush()
                   else:
                       F.write(lines2[ii])
                       F.flush()
               F.close()
    print( "[Complete]")

# implicit reference error
# The structure-name is invalid or is missing.
## fixs the above error
##Precondition:
##  txtLines - the BuildLog.txt
##  fileLocation - file directory
def fixError6158(txtLines, fileLocation):
    print("Fixing Error:6158 " + "....", end="", flush=True)
    for i in range(len(txtLines)):
       A = txtLines[i]
       FindIndex2 = A.find("error #6158")

       if FindIndex2 != -1:

           LeftIndex1 = A.find("[")
           if LeftIndex1 != -1:
               RightIndex1 = A.find("]")
               Var = A[LeftIndex1+1:RightIndex1]

               LeftIndex2 = A.rfind("\\")
               RightIndex2 = A.rfind("(")
               NewFileName = fileLocation + A[LeftIndex2+1:RightIndex2]
               print ("6158: " + NewFileName)

               os.chmod(NewFileName, 0o777)
               lines6 = [line6 for line6 in open(NewFileName)]
               F = open(NewFileName, 'w')

               for ii in range(len(lines6)):
                   if 'REAL '+Var in lines6[ii] or 'INTEGER '+Var in lines6[ii]:
                       F.write("\n")
                       F.flush()
                   else:
                       F.write(lines6[ii])
                       F.flush()
               F.close()
    print( "[Complete]")
# IndexList = []
# VarList = ''
# FileList = ''

##This name does not have a type, and must have an explicit type.
##doesnt work with old buildlog, the swiparse.f is not sync'd with the buildlog
## Issues :
#       some duplicates when running the subroutine more than once - should be fixed 7/03/2020
##      duplicates the # of times the error in the file is called in buildlog
## fixs the above error
##Precondition:
##  txtLines - the BuildLog.txt
##  fileLocation - file directory
def fixError6404(txtLines, fileLocation):
    print("Fixing Error:6404 " + "....", end="", flush=True)
    IndexList = []
    VarList = ''
    FileList = ''

    for i in range(len(txtLines)):
       A = txtLines[i]
       FindIndex = A.find("error #6404")
       if FindIndex != -1:
           ## this segment isolates the buildlog variable
           LeftIndex1 = A.find("[")
           RightIndex1 = A.find("]")
           Var = A[LeftIndex1+1:RightIndex1]

           LeftIndex2 = A.rfind("\\")
           RightIndex2 = A.rfind("(")
           NewFileName = fileLocation + A[LeftIndex2+1:RightIndex2]

           LeftIndex3 = A.rfind("(")
           RightIndex3 = A.rfind(")")
           FileLine = A[LeftIndex3+1:RightIndex3]
           # NewFileName = "tsatv6 - backup\\" + NewFileName
           print ("6404:" + NewFileName)

           os.chmod(NewFileName, 0o777)
           VarLine = int(FileLine)-1
           # print ( VarLine)
           if NewFileName.endswith('.f') or NewFileName.endswith('.for'):
               lines2 = [line2 for line2 in open(NewFileName)]

               ## last known instance of index
               ImplicitNoneIndex = 0
               for ii in range(VarLine):
                   if 'IMPLICIT NONE' in lines2[ii]:
                       if lines2[ii][0] == ' ':
                           ImplicitNoneIndex = ii

               IncludeIndex = 0
               for ii in range(VarLine):
                   if 'INCLUDE' in lines2[ii] and ('.INS' in lines2[ii] or '.ins' in lines2[ii]):
                       if lines2[ii][0] == ' ':
                           IncludeIndex = ii

               SubroutineIndex = 0
               for ii in range(VarLine+1):
                   if 'SUBROUTINE' in lines2[ii]:
                       if lines2[ii][0] == ' ':
                           SubroutineIndex = ii

                ## if subroutine is lower than implicit, recount implicit
               if SubroutineIndex > ImplicitNoneIndex:
                   ImplicitNoneIndex = 0
                   for ii in range(len(lines2)-1, VarLine, -1):
                       if 'IMPLICIT NONE' in lines2[ii]:
                           if lines2[ii][0] == ' ':
                               ImplicitNoneIndex = ii

                   SubroutineIndex = len(lines2)-1
                   for ii in range(len(lines2)-1, VarLine, -1):
                       if 'SUBROUTINE' in lines2[ii]:
                           if lines2[ii][0] == ' ':
                               SubroutineIndex = ii

                   IncludeIndex = 0
                   for ii in range(SubroutineIndex):
                       if 'INCLUDE' in lines2[ii] and ('.INS' in lines2[ii] or '.ins' in lines2[ii]):
                           if lines2[ii][0] == ' ':
                               IncludeIndex = ii

               # print ( str(ImplicitNoneIndex) + " " + str(IncludeIndex)+ " " + str(SubroutineIndex) )
               if ImplicitNoneIndex<IncludeIndex:
                   Index = IncludeIndex
               else:
                   Index = ImplicitNoneIndex

               IndexList.append(Index)
               VarList = VarList+' '+Var
               if FileList:
                   FileList = FileList+','+NewFileName
               else:
                   FileList = NewFileName
               # print ("Index: " + str(Index))
           elif NewFileName.endswith('.ins') or NewFileName.endswith('.INS'):
               with open(NewFileName, "r+") as F:
                   old = F.read()
                   F.seek(0)
                   if (Var[0]>='I' and Var[0]<='N') or (Var[0]>='i' and Var[0]<='n'):
                       F.write("      INTEGER " + Var + '\n' + old)
                   else:
                       F.write("      REAL " + Var + '\n' + old)
               F.close()

    VarList = VarList.split()
    FileList = FileList.split(",")

    ##Stripped variables (filename, variable, variable index) from the buildlog are placed into their relative positions
    for i in range(len(IndexList)):
       NewFileName = FileList[i]
       Index = IndexList[i]
       Var = VarList[i]
       os.chmod(NewFileName, 0o777)
       lines3 = [line3 for line3 in open(NewFileName)]

       F = open(NewFileName, 'w')

       for ii in range(len(lines3)):
           # reprint the lines that don't need to be reworked
           if ii != Index:
               F.write(lines3[ii])
               F.flush()
           # reprint the lines and then write INTEGER VARIABLE on a single line
           #
           elif ii == Index and Var not in lines3[ii]:
               # print(lines3[ii])
               F.write(lines3[ii])
               F.flush()
               if (Var[0]>='I' and Var[0]<='N') or (Var[0]>='i' and Var[0]<='n'):
                   F.write("      INTEGER " + Var + '\n')
                   F.flush()
               else:
                   F.write("      REAL " + Var + '\n')
                   F.flush()
           # else:
           #     F.write(lines3[ii])
           #     F.flush()
           #     if (Var[0]>='I' and Var[0]<='N') or (Var[0]>='i' and Var[0]<='n'):
           #         F.write("      INTEGER " + Var + '\n')
           #         F.flush()
           #     else:
           #         F.write("      REAL " + Var + '\n')
           #         F.flush()
           #     print(Var)
       F.close()
    print( "[Complete]")

## fixs the Variable with Integer or real
##Precondition:
##  txtLines - the BuildLog.txt
##  fileLocation - file directory
def fixError6239(txtLines, fileLocation):
    print("Fixing Error:6239 " + "....", end="", flush=True)
    for i in range(len(txtLines)):
       A = txtLines[i]
       FindIndex = A.find("error #6239")
       if FindIndex != -1:
           LeftIndex1 = A.find("[")
           RightIndex1 = A.find("]")
           Var = A[LeftIndex1+1:RightIndex1]

           LeftIndex2 = A.rfind("\\")
           RightIndex2 = A.rfind("(")
           NewFileName = A[LeftIndex2+1:RightIndex2]
           print ("error6239: " + NewFileName)
           NewFileName = fileLocation + NewFileName

           if NewFileName.endswith('.ins') or NewFileName.endswith('.INS'):
               with open(NewFileName, "r+") as F:
                   old = F.read()
                   F.seek(0)
                   if (Var[0]>='I' and Var[0]<='N') or (Var[0]>='i' and Var[0]<='n'):
                       F.write("      INTEGER " + Var + '\n' + old)
                   else:
                       F.write("      REAL " + Var + '\n' + old)
               F.close()
    print( "[Complete]")

# error #6401: The attributes of this name conflict with those made accessible by a USE statement.
#find library and put ",ONLY: VARNAME1, VARNAME2" on the use statement
#It works, but probably not needed
#flaws: it adds ONLY: to all the use modules that has that variable from buildlog. Could be better optimized. - 7/15/2020
def fixError6401(txtLines, fileLocation):
    print("Fixing Error:6401 " + "....", end="", flush=True)
    for i in range(len(txtLines)):
        A = txtLines[i]
        # findUse = A.find("      use ")
        findIndex = A.find("error #6401")
        if findIndex != -1:
           LeftIndex1 = A.find("[")
           RightIndex1 = A.find("]")
           Var = A[LeftIndex1+1:RightIndex1]

           LeftIndex2 = A.rfind("\\")
           RightIndex2 = A.rfind("(")
           NewFileName = A[LeftIndex2+1:RightIndex2]
           LeftIndex3 = A.rfind("(")
           RightIndex3 = A.rfind(")")
           FileLine = A[LeftIndex3+1:RightIndex3]

           print ("error6401: " + NewFileName)
           NewFileName = fileLocation + NewFileName
           os.chmod(NewFileName, 0o777)

           lines8 = [line8 for line8 in open(NewFileName)]
           varLine = int(FileLine) -1
           F = open(NewFileName, 'w')
           for ii in range(len(lines8)):
               if ii == varLine:
                   lines8[ii] = "C This line was deliberately left commented\n"
               if 'use' in lines8[ii].lower():
                   libraryContainsVar= ""
                   LeftIndex4 = lines8[ii].lower().rfind("use ")
                   RightIndex4 = lines8[ii].rfind("\n")
                   useLibraryVar = lines8[ii][LeftIndex4+4:RightIndex4]

                   ## if there is a space in useLibrary, the line is a comment, ignore the line
                   if ' ' in useLibraryVar and "ONLY:" not in useLibraryVar:
                       F.write(lines8[ii])
                       F.flush()
                       continue
                   elif ' ' in useLibraryVar and "ONLY: " in useLibraryVar:
                       RightIndex4 = lines8[ii].find(",")
                       useLibraryVar = lines8[ii][LeftIndex4+4:RightIndex4]

                   libraryFileName = fileLocation + useLibraryVar + ".f90"
                   #check if useLibraryVar relates to the file
                   os.chmod(libraryFileName, 0o444)
                   lines9 = [line9 for line9 in open(libraryFileName)]
                   for iii in range(len(lines9)):
                       if Var.lower() in lines9[iii]:
                           libraryContainsVar = Var
                   newLine = lines8[ii]
                   if libraryContainsVar == Var and ( ", ONLY: " not in lines8[ii]):
                       newLine = lines8[ii].rstrip('\n')+ ", ONLY: " + libraryContainsVar + "\n"
                       F.write( newLine)
                       F.flush()
                   elif libraryContainsVar == Var and ", ONLY: " in lines8[ii] and (libraryContainsVar not in lines8[ii]):
                       newLine = lines8[ii].rstrip('\n')+ ", " + Var + "\n"
                       F.write( newLine)
                       F.flush()
                   else:
                       F.write(newLine)
                       F.flush()
               else:
                   F.write(lines8[ii])
                   F.flush()
           F.close()
    print( "[Complete]")
## fixs format function descriptor. invalid format descriptors are removed.
##Precondition:
##  txtLines - the BuildLog.txt
##  fileLocation - file directory
def fixError6186(txtLines, fileLocation):
    print("Fixing error:6186 " + "....", end="", flush=True)
    for i in range(len(txtLines)):
        A = txtLines[i]
        findIndex = A.find("error #6186")

        if findIndex != -1:
            LeftIndex1 = A.rfind("\\")
            RightIndex1 = A.rfind("(")
            newfilename = A[LeftIndex1+1:RightIndex1]
            print ("6186: " + newfilename)
            newfilename = fileLocation + newfilename

            LeftIndex2 = A.rfind("(")
            RightIndex2 = A.rfind(")")
            FileLine = A[LeftIndex2+1:RightIndex2]

            LeftIndex3 = A.rfind("[")
            RightIndex3 = A.rfind("]")
            Var = A[LeftIndex3+1:RightIndex3]

            os.chmod(newfilename, 0o777)
            VarLine = int(FileLine)-1
            lines11 = [line11 for line11 in open(newfilename)]

            F = open(newfilename, 'w')

            for ii in range(len(lines11)):
                if ii == VarLine:
                    F.write(re.sub(r'\b%s\b' %Var, '', lines11[ii]))
                    F.flush()
                else:
                    F.write(lines11[ii])
                    F.flush()
            F.close()
    print( "[Complete]")


from time import sleep
import requests

# 1. sleep
# 3초간 슬립
def sleep_3_seconds():
    sleep(3)
    print('잘잤다')

print('이제 자야지')
sleep_3_seconds()
print('학교가자')

# 2. requests
response = requests.get('https://jsonplaceholder.typicode.com/todos/1/')
# 파싱
todo = response.json()

print(todo)


"""class person:
    def __init__(self,fname,lname):
        self.fname=fname
        self.lname=lname
    @property
    def full_name(self):
        return self.fname+ " " +self.lname

p=person("anitha","thosam")
print(p.full_name)"""

"""class Myclass:
    def __init__(self):
        self.a=1
        self.__b=1

    def increment_b(self):
        self.__b+=1
        return self.__b
    def get_b(self):
        return self.__b

p=Myclass()
print(p.a)

#print(p.__b)
print(p.increment_b())
print(p.get_b())
print(p._Myclass__b)"""

"""class Myclass:
    a=10
    b=[]
    def __init__(self):
        self.c=1
x,y=Myclass(),Myclass()
print(x.b,y.b,Myclass.b)
x.b.append(10)
print(x.b,y.b,Myclass.b)
Myclass.b.append(20)
print(x.b,y.b,Myclass.b)"""

"""class parent:
    x=1
    def __init__(self):
        self.y=2
    def hello(self):
        print("Hello from Parent")
        return ("return")
class child(parent):
    z=3

p,c=parent(),child()
print(p.x,p.y)
print(parent.x,child.x)
print(c.hello())
print(p.hello())
print(c.z)
print(issubclass(child,parent))
print(isinstance(c,child))
print(isinstance(p,parent))"""

"""class parent:
    x=1
    def __init__(self):
        self.y=2
    def hello(self):
        print("Hello from Parent")
        return ("return")
class child(parent):
    z=3
    def hello(self):
        super().hello()   #super() method to get parent methods
        print("hello from child")
        return ("return")

p,c=parent(),child()
print(p.hello())
print(c.hello())"""

class anitha:
    def __init__(self):
        self.c=1

class sunitha(anitha):
    #def __init__(self):
        #super().__init__()
        z=4
p,cc=anitha(),sunitha()
print(p.c)
print(cc.z)
print(cc.c)


import zmq
import logging
import logging.config

logging.basicConfig(filename='errors_log.log', filemode='a',
                        format='%(process)s - %(asctime)s - %(levelname)s - %(message)s')

context = zmq.Context()
socket = context.socket(zmq.SUB)
try:
    socket.connect("tcp://127.0.0.1:5687")
except zmq.ZMQError as connection_error:
    logging.error(
        'CLIENT ERROR: Exception of type {!s} : {!s}'.format(type(connection_error).__name__, str(connection_error)))

socket.setsockopt_string(zmq.SUBSCRIBE, '')
while True:
    messages = socket.recv_pyobj()
    # Печатает все числа
    for i in range(len(messages)):
        print(messages[i])


from future import standard_library
standard_library.install_aliases()
from builtins import str
from past.builtins import basestring
import json
import logging
import re
import sys
import urllib.parse
from datetime import datetime
from dateutil import tz
from dateutil import parser

from django.utils.formats import localize_input
from desktop.lib.parameterization import find_variables
from liboozie.oozie_api import get_oozie, DEFAULT_USER

if sys.version_info[0] > 2:
  from django.utils.translation import gettext as _
else:
  from django.utils.translation import ugettext as _

LOG = logging.getLogger()

JSON_FIELDS = ('parameters', 'job_properties', 'files', 'archives', 'prepares', 'params',
               'deletes', 'mkdirs', 'moves', 'chmods', 'touchzs')
BOOLEAN_FIELDS = ('propagate_configuration','capture_output')
NUMBER_FIELDS_OR_NULL = ('sub_workflow',)
GMT_TIME_FORMAT = "%Y-%m-%dT%H:%MGMT%z"
UTC_TIME_FORMAT = "%Y-%m-%dT%H:%MZ"
FREQUENCY_REGEX = r'^\$\{coord:(?P<frequency_unit>\w+)\((?P<frequency_number>\d+)\)\}$'

def format_field_value(field, value):
  if field in JSON_FIELDS:
    if isinstance(value, basestring):
      value = json.loads(value)
    value = [item for item in value if isinstance(item, dict) and item.get('name')]
    return json.dumps(value)
  if field in NUMBER_FIELDS_OR_NULL:
    if not isinstance(value, int) and value is not None:
      return int(value)
  if field in BOOLEAN_FIELDS:
    return str(value).lower() == 'true'
  return value

def format_dict_field_values(dictionary):
  for key in dictionary:
    dictionary[key] = format_field_value(key, dictionary[key])
  return dictionary

def model_to_dict(model):
  from django.db import models

  dictionary = {}
  for field in model._meta.fields:
    try:
      attr = getattr(model, field.name, None)
      if isinstance(attr, models.Model):
        dictionary[field.name] = attr.id
      elif isinstance(attr, datetime):
        dictionary[field.name] = str(attr)
      else:
        dictionary[field.name] = attr
    except Exception as e:
      LOG.debug(_("Could not set field %(field)s: %(exception)s") % {'field': field.name, 'exception': str(e)})
  return dictionary

def sanitize_node_dict(node_dict):
  for field in ['node_ptr', 'workflow']:
    if field in node_dict:
      del node_dict[field]
  return node_dict

def workflow_to_dict(workflow):
  workflow_dict = model_to_dict(workflow)
  node_list = [node.get_full_node() for node in workflow.node_list]
  nodes = [model_to_dict(node) for node in node_list]

  for index, node in enumerate(node_list):
    nodes[index]['child_links'] = [model_to_dict(link) for link in node.get_all_children_links()]

  workflow_dict['nodes'] = nodes

  return workflow_dict

def smart_path(path, mapping=None, is_coordinator=False):
  # Try to prepend home_dir and FS scheme if needed.
  # If path starts by a parameter try to get its value from the list of parameters submitted by the user or the coordinator.
  # This dynamic checking enable the use of <prepares> statements in a workflow scheduled manually of by a coordinator.
  # The logic is a bit complicated but Oozie is not consistent with data paths, prepare, coordinator paths and Fs action.
  if mapping is None:
    mapping = {}

  path = path.strip()
  if not path.startswith('$') and not path.startswith('/') and not urllib.parse.urlsplit(path).scheme:
    path = '/user/%(username)s/%(path)s' % {
        'username': '${coord:user()}' if is_coordinator else '${wf:user()}',
        'path': path
    }

  if path.startswith('$'):
    variables = find_variables(path)
    for var in variables:
      prefix = '${%s}' % var
      if path.startswith(prefix):
        if var in mapping:
          if not urllib.parse.urlsplit(mapping[var]).scheme and not mapping[var].startswith('$'):
            path = '%(nameNode)s%(path)s' % {'nameNode': '${nameNode}', 'path': path}
  else:
    if not urllib.parse.urlsplit(path).scheme:
      path = '%(nameNode)s%(path)s' % {'nameNode': '${nameNode}', 'path': path}

  return path

def contains_symlink(path, mapping):
  vars = find_variables(path)
  return any([var in mapping and '#' in mapping[var] for var in vars]) or '#' in path

def utc_datetime_format(utc_time):
  if utc_time and type(utc_time) is datetime:
    return utc_time.strftime(UTC_TIME_FORMAT)
  return utc_time

def oozie_to_django_datetime(dt_string):
  try:
    return localize_input(datetime.strptime(dt_string, UTC_TIME_FORMAT))
  except ValueError:
    pass

  try:
    return localize_input(datetime.strptime(dt_string, GMT_TIME_FORMAT))
  except ValueError:
    pass

  return None

class InvalidFrequency(Exception):
  pass

def oozie_to_hue_frequency(frequency_string):
  """
  Get frequency number and units from frequency, which must be of the format
  "${coord:$unit($number)}".

  frequency units and number are just different parts of the EL function.

  Returns:
    A tuple of the frequency unit and number

  Raises:
    InvalidFrequency: If the `frequency_string` does not match the frequency pattern.
  """
  matches = re.match(FREQUENCY_REGEX, frequency_string)
  if matches:
    return matches.group('frequency_unit'), matches.group('frequency_number')
  else:
    raise InvalidFrequency(_('invalid frequency: %s') % frequency_string)

def convert_to_server_timezone(date, local_tz='UTC', server_tz=None, user=DEFAULT_USER):
  api = get_oozie(user)

  if server_tz is None:
    oozie_conf = api.get_configuration()
    server_tz = oozie_conf.get('oozie.processing.timezone') or 'UTC'

  if date and date.startswith('$'):
    return date

  # To support previously created jobs
  if date.endswith('Z'):
    date = date[:-1]
    local_tz = 'UTC'

  try:
    date_local_tz = parser.parse(date)
    date_local_tz = date_local_tz.replace(tzinfo=tz.gettz(local_tz))
    date_server_tz = date_local_tz.astimezone(tz.gettz(server_tz))

    # Oozie timezone is either UTC or GMT(+/-)####
    if 'UTC' == server_tz:
      return date_server_tz.strftime('%Y-%m-%dT%H:%M') + u'Z'
    else:
      return date_server_tz.strftime('%Y-%m-%dT%H:%M') + date_server_tz.strftime('%z')
  except TypeError as ValueError:
    LOG.error("Failed to convert Oozie timestamp: %s" % date)
  return None


'''
#BY: TANUSHRI SINGH
#NETID: TTS150030
#CS 6375.001 - MACHINE LEARNING
#ASSIGNMENT 2
#INSTRUCTOR - ANJUM CHIDA
'''

#Import Libraries
import os
import sys
import math

class naiveBayes:
    trainPath = 'train'
    testPath = 'test'

    def __init__(object, useStopWords):
        #Initialize parands to be empty
        object.mapOfHam = {}
        object.mapOfSpam = {}
        object.setOfWords = None
        object.numOfHam = 0
        object.numOfSpam = 0
        object.stopWords = []
        object.useStopWords = useStopWords

    #TRAINING FUNCTION
    def train(object):
        object.numOfSpam, listOfSpam = object.initialList(object.trainPath + '/spam')
        object.numOfHam, listOfHam = object.initialList(object.trainPath + '/ham')

        # This is to remove empty strings
        if '' in listOfSpam:
            listOfSpam.remove('')
        if '' in listOfHam:
            listOfHam.remove('')

        # Remove a word if it is one of the stop words
        if object.useStopWords:
            object.stopWords = object.readInStopWords()
            for word in object.stopWords:
                if word in listOfSpam:
                    listOfSpam.remove(word)
                if word in listOfHam:
                    listOfHam.remove(word)

        #Calculate length of both spam and ham
        lengthOfSpam = len(listOfSpam)
        lengthOfHam = len(listOfHam)

        #Aggregate Spam and Ham to get setOfWords
        object.setOfWords = set(listOfSpam + listOfHam)
        words_space_len = len(object.setOfWords)

        #Map the Spam's and Hams
        object.mapOfHam = object.initialMap(listOfHam)
        object.mapOfSpam = object.initialMap(listOfSpam)

        #Calculate total number of spams and hams
        countOfTotalSpam = lengthOfSpam + words_space_len
        countOfTotalHam = lengthOfHam + words_space_len

        for word in object.mapOfHam.keys():
            object.mapOfHam[word] = math.log2((object.mapOfHam[word] + 1) * 1.0 / countOfTotalHam)

        for word in object.mapOfSpam.keys():
            object.mapOfSpam[word] = math.log2((object.mapOfSpam[word] + 1) * 1.0 / countOfTotalSpam)

        #Return Values back
        return countOfTotalSpam, countOfTotalHam

    def test(object, countOfTotalSpam, countOfTotalHam):

        # spam
        contentOfFile = os.listdir(object.testPath + '/spam')

        if not contentOfFile:
            return

        TestNumOfSpam = len(contentOfFile)
        postValueOfSpam = 0

        for filename in contentOfFile:
            with open(object.testPath + '/spam' + '/' + filename, 'r', encoding='utf-8', errors='ignore') as val:
                value = val.read().lower().replace('\n', ' ').split(' ')
            proportionOfHam = math.log2(object.numOfHam * 1.0 / (object.numOfHam + object.numOfSpam))
            proportionOfSpam = math.log2(object.numOfSpam * 1.0 / (object.numOfHam + object.numOfSpam))

            # delete empty string
            if '' in value:
                value.remove('')
            # delete stopWords from list
            if object.useStopWords:
                for word in object.stopWords:
                    if word in value:
                        value.remove(word)

            for word in value:
                if word in object.mapOfSpam:
                    proportionOfSpam += object.mapOfSpam[word]
                else:
                    proportionOfSpam += math.log2(1 / countOfTotalSpam)

                if word in object.mapOfHam:
                    proportionOfHam += object.mapOfHam[word]
                else:
                    proportionOfHam += math.log2(1 / countOfTotalHam)

            if proportionOfSpam >= proportionOfHam:
                postValueOfSpam += 1

        spamSuccess = postValueOfSpam * 1.0 / TestNumOfSpam

        # ham
        contentOfFile = os.listdir(object.testPath + '/ham')

        if not contentOfFile:
            return

        testNumOfHam = len(contentOfFile)
        postValueOfHam = 0

        for filename in contentOfFile:
            with open(object.testPath + '/ham' + '/' + filename, 'r', encoding='utf-8', errors='ignore') as f:
                value = f.read().lower().replace('\n', ' ').split(' ')

            # delete empty string if they exist
            if '' in value:
                value.remove('')

            proportionOfHam = math.log2(object.numOfHam * 1.0 / (object.numOfHam + object.numOfSpam))
            proportionOfSpam = math.log2(object.numOfSpam * 1.0 / (object.numOfHam + object.numOfSpam))

            # delete stopWords from list
            if object.useStopWords:
                for word in object.stopWords:
                    if word in value:
                        value.remove(word)

            for word in value:
                if word in object.mapOfSpam:
                    proportionOfSpam += object.mapOfSpam[word]
                else:
                    proportionOfSpam += math.log2(1 / countOfTotalSpam)

                if word in object.mapOfHam:
                    proportionOfHam += object.mapOfHam[word]
                else:
                    proportionOfHam += math.log2(1 / countOfTotalHam)

            if proportionOfSpam <= proportionOfHam:
                postValueOfHam += 1

        hamSuccess = postValueOfHam * 1.0 / testNumOfHam
        totalSuccess = (postValueOfSpam + postValueOfHam) * 1.0 / (TestNumOfSpam + testNumOfHam)

        return spamSuccess, hamSuccess, totalSuccess

    def initialMap(object, listOfWords):
        value = {}
        for word in listOfWords:
            if word in value:
                value[word] += 1
            else:
                value[word] = 0
        return value

    def initialList(object, folder):
        contentOfFile = os.listdir(folder)
        if not contentOfFile:
            return
        message = []
        for filename in contentOfFile:
            with open(folder + '/' + filename, 'r', encoding='utf-8', errors='ignore') as val:
                value = val.read().lower().replace('\n', ' ').split(' ')
                message = message + value
        return len(contentOfFile), message

    def readInStopWords(object):
        with open('stopWords.txt') as file:
            value = file.read().lower().replace('\n', ' ').split(' ')
        return value

#MAIN FUNCTION
def main(stopWords):
    #Call NaiveBayes Functionalities
    nb = naiveBayes(stopWords)
    totalCountOfSpam, totalCountOfHam = nb.train()

    #Call classify to retrieve results on how the algorithm performed
    spamSuccess, hamSuccess, overallSuccess = nb.test(totalCountOfSpam, totalCountOfHam)
    print('********************** -------- **********************')
    print('The Ratio of Success For Spam Emails -> %.4f%%' %(spamSuccess*100))
    print('The Ratio of Success For Ham Emails -> %.4f%%' %(hamSuccess*100))
    print('The Ratio of Success For All Emails -> %.4f%%' %(overallSuccess*100))
    print('********************** -------- **********************')

#PARAMETER DECLARATION
if __name__ == "__main__":
    stopWords = False
    if sys.argv[1].lower() == 'true':
        stopWords = True
    main(stopWords)


def lengthOfLIS(nums):
    if len(nums) == 0:
        return 0
    dp = [1]
    for i in range(1, len(nums)):
        ans = 0
        for j in range(i):
            if nums[i] > nums[j]:
                ans = max(ans, dp[j])
        dp.append(ans + 1)
    return max(dp)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Mar 17 16:17:10 2020

@author: danbiderman
"""

"""In: time indices; DLC tracked pts in 2D (cam1+cam2); DLC 3D tracked pts; recovered dict
we loop over time points, and present the images along with our 3D plot
figure should be presented using """
import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objs as go
import cv2
from scipy.spatial.transform import Rotation as R
from matplotlib import colors
from PIL import Image

# this function assumes that we're plotting the first n frames of our dictionaries
def video_recover_plots(
    noisy_pose_dict,
    recovered_pose_dict,
    stacked_images,
    DLC_sliced1,
    DLC_sliced2,
    reproj_list_of_dicts,
    save_name,
    title,
    n_frames,
    lim_abs,
):
    """seems to work.this version has the gridspec including
    what i learned - using p3.Axes3D along with regular ax.plot was helpful.
    in ax.plot I just use x,y,z, coordinates.
    there is no init function like in the 2d plots, we initialize the lines
    with the vales at the zeroth timepoint"""
    from matplotlib.animation import FuncAnimation
    from matplotlib.gridspec import GridSpec

    fig = plt.figure(constrained_layout=True, figsize=(11, 6))

    gs = GridSpec(2, 2, figure=fig)
    ax1 = fig.add_subplot(gs[:2, 0])
    import mpl_toolkits.mplot3d.axes3d as p3

    # identical to ax1 = plt.subplot(gs.new_subplotspec((0, 0), colspan=3))
    ax2 = fig.add_subplot(
        gs[:2, 1], projection="3d"
    )  # https://matplotlib.org/3.1.1/gallery/mplot3d/subplot3d.html

    # fig = plt.figure()
    ax2.view_init(elev=-82.0, azim=-72)  # specific for costa data, found manually

    #    ax.set_xlim3d([-2.0, 2.0])
    #    ax.set_xlabel('X')
    #
    #    ax.set_ylim3d([-2.0, 2.0])
    #    ax.set_ylabel('Y')
    #
    #    ax.set_zlim3d([-2.0, 2.0])
    #    ax.set_zlabel('Z')

    im_stacked = ax1.imshow(
        stacked_images[:, :, 0], cmap="gray"
    )  # all the lines below consider a SPECIFIC CROP
    (line_1,) = ax1.plot(
        DLC_sliced1[0 + 1, [0, 3, 6]] - 200,
        DLC_sliced1[0 + 1, [1, 4, 7]],
        "r*",
        markersize=10,
    )

    (line_1_reproj,) = ax1.plot(
        reproj_list_of_dicts[0]["x_coords"][:, 0 + 1] - 200,
        reproj_list_of_dicts[0]["y_coords"][:, 0 + 1],
        "b+",
        markersize=10,
    )
    #    scatt_1 = ax1.scatter(DLC_sliced1[0+1,[0,3,6]]-200, DLC_sliced1[0+1,[1,4,7]],
    #        color='red', marker='*', s=50)
    (line_2,) = ax1.plot(
        DLC_sliced2[0 + 1, [0, 3, 6]] - 220 + 300,
        DLC_sliced2[0 + 1, [1, 4, 7]] - 50,  # +300 due to stack
        "r*",
        markersize=10,
    )
    (line_2_reproj,) = ax1.plot(
        reproj_list_of_dicts[1]["x_coords"][:, 0 + 1] - 220 + 300,
        reproj_list_of_dicts[1]["y_coords"][:, 0 + 1] - 50,
        "b+",
        markersize=10,
    )

    line_v = ax1.axvline(x=300, ymin=0, ymax=300, color="white", linewidth=5)
    ax1.set_title("View 1             View 2", fontsize=16, weight="bold")
    ax1.axis("off")
    ax1.legend(loc="lower left", labels=["DLC 2D", "BA-reproj"])

    # init lines with true data, no init method.
    (line_noise,) = ax2.plot(
        noisy_pose_dict["x_coords"][:, 0],
        noisy_pose_dict["y_coords"][:, 0],
        noisy_pose_dict["z_coords"][:, 0],
        "ro-",
        lw=4,
        markersize=5,
        label="DLC 3D",
    )
    (line_recovered,) = ax2.plot(
        recovered_pose_dict["x_coords"][:, 0],
        recovered_pose_dict["y_coords"][:, 0],
        recovered_pose_dict["z_coords"][:, 0],
        "ko-",
        lw=4,
        markersize=5,
        label="BA_3D",
        alpha=0.5,
    )
    #    plt.legend(loc = "lower left")
    #    plt.title(title, fontsize = 16)

    # dan 2/28 can be avoided
    # new for costa data
    #     ax2.set_xlim3d([-2.0, 2.0])
    #     #ax.set_xticks([])
    #     ax2.set_xticks([-2.0, -1.0, 0.0, 1.0, 2.0])
    #     ax2.set_xticklabels([])
    #     ax2.tick_params('x')
    #     ax2.set_xlabel('X', fontsize=12, labelpad = 0.1)
    #     ax2.set_ylim3d([-2.0, 2.0])
    #     ax2.set_yticks([-2.0, -1.0, 0.0, 1.0, 2.0])
    #     ax2.set_yticklabels([])
    #     ax2.set_ylabel('Y', fontsize=12)
    #     ax2.set_zlim3d([-2.0, 2.0])
    #     ax2.set_zticks([-2.0, -1.0, 0.0, 1.0, 2.0])
    #     ax2.set_zticklabels([])
    #     ax2.set_zlabel('Z', fontsize=12)
    ax2.legend(loc="lower left", fontsize=10)
    ax2.set_title("DLC Calib VS BA", fontsize=16, weight="bold", pad=18)

    # need to get images here
    def animate(
        i,
        stacked_images,
        im_stacked,
        DLC_sliced1,
        line_1,
        DLC_sliced2,
        line_2,
        reproj_list,
        line_1_reproj,
        line_2_reproj,
        line_v,
        noisy_pose_dict,
        line_noise,
        recovered_pose_dict,
        line_recovered,
    ):  # note, the loop has to see all these datasets

        im_stacked.set_data(
            stacked_images[:, :, i]
        )  # all the lines below consider a SPECIFIC CROP
        line_1.set_data(
            DLC_sliced1[i + 1, [0, 3, 6]] - 200, DLC_sliced1[i + 1, [1, 4, 7]]
        )
        line_1_reproj.set_data(
            reproj_list_of_dicts[0]["x_coords"][:, i + 1] - 200,
            reproj_list_of_dicts[0]["y_coords"][:, i + 1],
        )
        line_2.set_data(
            DLC_sliced2[i + 1, [0, 3, 6]] - 220 + 300,
            DLC_sliced2[i + 1, [1, 4, 7]] - 50,
        )
        line_2_reproj.set_data(
            reproj_list_of_dicts[1]["x_coords"][:, i + 1] - 220 + 300,
            reproj_list_of_dicts[1]["y_coords"][:, i + 1] - 50,
        )
        line_v = ax1.axvline(
            x=300, ymin=0, ymax=300, color="white", linewidth=5
        )  # .set_data(x=300, ymin = 0, ymax = 300)
        # noisy obs
        line_noise.set_data(
            noisy_pose_dict["x_coords"][:, i], noisy_pose_dict["y_coords"][:, i]
        )
        line_noise.set_3d_properties(noisy_pose_dict["z_coords"][:, i])

        # recovered
        line_recovered.set_data(
            recovered_pose_dict["x_coords"][:, i], recovered_pose_dict["y_coords"][:, i]
        )
        line_recovered.set_3d_properties(recovered_pose_dict["z_coords"][:, i])

        return (
            im_stacked,
            line_1,
            line_2,
            line_1_reproj,
            line_2_reproj,
            line_v,
            line_noise,
            line_recovered,
        )  # not sure the return is needed. check.

    anim = FuncAnimation(
        fig,
        animate,
        fargs=(
            stacked_images,
            im_stacked,
            DLC_sliced1,
            line_1,
            DLC_sliced2,
            line_2,
            reproj_list_of_dicts,
            line_1_reproj,
            line_2_reproj,
            line_v,
            noisy_pose_dict,
            line_noise,
            recovered_pose_dict,
            line_recovered,
        ),  # all inputs to loop
        frames=n_frames,
        interval=50,
        blit=False,
    )  # blit false important?

    # anim.save("recover.mp4")
    # anim.save(save_name + '.gif', writer='Imagekick') # works
    anim.save(save_name + ".gif", writer="pillow")  # pillow important

def plot_reproj_traces(points_2d, points_proj, frame_range, title, savename):
    """choose frame range according to num_frames_analyzed and
    num_body_parts and num_cameras. above, we take each body part coord, and stack
    it for all body parts and cameras."""
    plt.suptitle(title, fontsize=14)
    plt.subplot(211)
    plt.ylabel("x coord")
    plt.plot(points_2d[frame_range, 0], color="gray", linewidth=3)
    plt.plot(points_proj[frame_range, 0], color="red", linestyle="dashed", linewidth=1)
    plt.subplot(212)
    plt.ylabel("y coord")
    plt.plot(points_2d[frame_range, 1], color="gray", linewidth=3, label="DLC 2D")
    plt.plot(
        points_proj[frame_range, 1],
        color="red",
        linestyle="dashed",
        linewidth=1,
        label="re-projection",
    )
    plt.xlabel("frame num.")
    plt.legend(loc="lower right")
    plt.savefig(savename + ".png")

def plot_image_labels(
    image,
    coord_list_of_dicts,
    index,
    color_list,
    label_list=None,
    ax=None,
    top_img_height=0,
    pad=10,
):
    """ToDo: add multiple data sources, so instead of x_arr, y_arr have a list of dicts
    with x,y coords."""
    if len(image.shape) == 2:
        nrows, ncols = image.shape
    else:
        nrows, ncols = image.shape[0:2]

    assert len(color_list) == len(coord_list_of_dicts)

    ax.axis("off")
    ax.set_xlim(-pad, ncols + pad)  # pad x,y axes
    ax.set_ylim(nrows + pad, -pad)

    ax.imshow(image, "gray")
    for i in range(len(coord_list_of_dicts)):
        x_coord = np.copy(coord_list_of_dicts[i]["x_coords"][index, :])
        y_coord = np.copy(coord_list_of_dicts[i]["y_coords"][index, :])

        # indices 1 and 3 correspond to the bottom image.
        # Recall, we subtracted out the height of the top
        # image earlier.
        if i % 2 != 0:
            y_coord += top_img_height

        if label_list is not None:
            ax.scatter(
                x_coord, y_coord, color=color_list[i], label=label_list[i],
            )
        else:
            ax.scatter(x_coord, y_coord, color=color_list[i])

def plot_3d_points(coord_list_of_dicts, lims_dict, index, color_list, ax):
    """plot a single frame
    ToDo: specify plotting patams, allow for multiple inputs"""

    assert len(color_list) == len(coord_list_of_dicts)

    ax.set_xlim3d(lims_dict["x"])
    ax.set_ylim3d(lims_dict["y"])
    ax.set_zlim3d(lims_dict["z"])
    ax.set_xlabel("X")
    ax.set_ylabel("Y")
    ax.set_zlabel("Z")

    for i in range(len(coord_list_of_dicts)):
        ax.plot(
            coord_list_of_dicts[i]["x_coords"][index, :],
            coord_list_of_dicts[i]["y_coords"][index, :],
            coord_list_of_dicts[i]["z_coords"][index, :],
            linestyle="None",
            marker="o",
            color=color_list[i],
            markersize=4,
            label=None,
        )

def vector_plot(
    tvects,
    is_vect=True,
    orig=[0, 0, 0],
    # names=["x", "y", "z"],
    names=["", "", ""],
    cam_name="",
    colors=["red", "blue", "green"],
):
    """Plot vectors using plotly"""

    if is_vect:
        if not hasattr(orig[0], "__iter__"):
            coords = [[orig, np.sum([orig, v], axis=0)] for v in tvects]
        else:
            coords = [[o, np.sum([o, v], axis=0)] for o, v in zip(orig, tvects)]
    else:
        coords = tvects

    data = []
    for i, c in enumerate(coords):
        X1, Y1, Z1 = zip(c[0])
        X2, Y2, Z2 = zip(c[1])
        vector = go.Scatter3d(
            x=[X1[0], X2[0]],
            y=[Y1[0], Y2[0]],
            z=[Z1[0], Z2[0]],
            text=[cam_name, names[i]],
            marker=dict(size=[0, 5], color="blue"),
            line=dict(width=5, color=colors[i]),
            mode="lines+markers+text",
            name=names[i] + cam_name,
        )
        data.append(vector)

    return data
    # fig = go.Figure(data=data,layout=layout)
    # fig.show()

def draw_circles(
    img, points, point_colors=None, point_size=10, marker_type=None, thickness=-1
):

    if point_colors is not None:
        if not isinstance(point_colors, list):
            point_colors = [point_colors] * points.shape[0]
        assert len(point_colors) == points.shape[0]

    for i, point in enumerate(points):
        if point_colors is not None:
            color = [i * 255 for i in colors.to_rgb(point_colors[i])]
        else:
            color = (255, 255, 255)

        if marker_type is not None:
            assert marker_type in ("cross", "diamond", "square")
            if marker_type == "cross":
                marker = cv2.MARKER_CROSS

            cv2.drawMarker(
                img,
                (point[0], point[1]),
                markerType=marker,
                markerSize=point_size,
                thickness=2,
                color=(color[2], color[1], color[0], 0),
            )
        else:
            cv2.circle(
                img,
                (point[0], point[1]),
                point_size,
                (color[2], color[1], color[0]),
                thickness,
            )

    return img

def slope(x1, y1, x2, y2):
    ###finding slope
    if x2 != x1:
        return (y2 - y1) / (x2 - x1)
    else:
        return "NA"

def drawLine(image, x1, y1, x2, y2, color=None):

    m = slope(x1, y1, x2, y2)
    h, w = image.shape[:2]
    if m != "NA":
        ### here we are essentially extending the line to x=0 and x=width
        ### and calculating the y associated with it
        ##starting point
        px = 0
        py = -(x1 - 0) * m + y1
        ##ending point
        qx = w
        qy = -(x2 - w) * m + y2
    else:
        ### if slope is zero, draw a line with x=x1 and y=0 and y=height
        px, py = x1, 0
        qx, qy = x1, h

    if color is not None:
        color = [i * 255 for i in colors.to_rgb(color)]
        image = cv2.line(
            image,
            (int(px), int(py)),
            (int(qx), int(qy)),
            (color[2], color[1], color[0]),
            2,
        )
    else:
        image = cv2.line(
            image, (int(px), int(py)), (int(qx), int(qy)), (255, 255, 255), 2
        )
    return image

def skew(vector):
    """
    this function returns a numpy array with the skew symmetric cross product matrix for vector.
    the skew symmetric cross product matrix is defined such that
    np.cross(a, b) = np.dot(skew(a), b)

    :param vector: An array like vector to create the skew symmetric cross product matrix for
    :return: A numpy array of the skew symmetric cross product vector
    """

    return np.array(
        [
            [0, -vector[2], vector[1]],
            [vector[2], 0, -vector[0]],
            [-vector[1], vector[0], 0],
        ]
    )

def plot_cams_and_points(
    cam_group=None,
    points_3d=None,
    title=None,
    scene_lims=None,
    point_size=2,
    scene_aspect=None,
    scene_camera=None,
    show_plot=True,
    skeleton_bp=None,
    skeleton_lines=None,
    line_colors=None,
    point_colors=None,
    legend=False,
    font_size=15,
    plot_names=False,
    cam_names=None
):
    """
    Plots the coordinate systems of the cameras along with the 3D points
    """
    if points_3d is not None:
        scatter_data = [
            go.Scatter3d(
                x=points_3d[:, 0],
                y=points_3d[:, 1],
                z=points_3d[:, 2],
                mode="markers",
                marker=dict(size=point_size, color=point_colors),
            )
        ]

        data = scatter_data
    else:
        data = []

    if cam_group is not None:
        for i, cam in enumerate(cam_group.cameras):
            rot_vec = R.from_rotvec(cam.get_rotation())
            R_mat = rot_vec.as_matrix() * 0.2
            t = cam.get_translation()

            if cam_names is None:
                cam_name = f"cam_{i+1}"
            else:
                cam_name = cam_names[i]
            data += vector_plot(
                [R_mat[:, 0], R_mat[:, 1], R_mat[:, 2]], orig=t, cam_name=cam_name
            )
    if skeleton_bp is not None and skeleton_lines is not None:
        for i, line in enumerate(skeleton_lines):
            from_bp = line[0]
            to_bp = line[1]

            # Standard case
            if isinstance(from_bp, str):
                vec = [
                    skeleton_bp[from_bp][i] - skeleton_bp[to_bp][i] for i in range(3)
                ]

                if line_colors is not None:
                    color = [line_colors[i]]
                else:
                    color = ["gray"]

                cam_name = to_bp if plot_names else ""
                # names = [from_bp]
                names = [""]

                vec_data = vector_plot(
                    [vec],
                    orig=skeleton_bp[to_bp],
                    cam_name=cam_name,
                    names=names,
                    colors=color,
                )
                data += vec_data

            # Want to draw to midpoint
            elif isinstance(from_bp, tuple):
                # calculate midpoint
                vec_from_from = [
                    skeleton_bp[from_bp[0]][i] - skeleton_bp[from_bp[1]][i]
                    for i in range(3)
                ]

                mid = [
                    (skeleton_bp[from_bp[1]][j] + vec_from_from[j] * from_bp[-1])
                    for j in range(3)
                ]

                vec = [mid[i] - skeleton_bp[to_bp][i] for i in range(3)]
                if line_colors is not None:
                    color = [line_colors[i]]
                else:
                    color = ["green"]
                vec_data = vector_plot(
                    [vec],
                    orig=skeleton_bp[to_bp],
                    cam_name=to_bp,
                    names=[""],
                    colors=color,
                )
                data += vec_data

    if scene_lims is not None:
        layout = go.Layout(
            margin=dict(l=0, r=0, b=0, t=0),
            scene=dict(
                xaxis=dict(nticks=4, range=scene_lims[0], showticklabels=False),
                yaxis=dict(nticks=4, range=scene_lims[1], showticklabels=False),
                zaxis=dict(nticks=4, range=scene_lims[2], showticklabels=False),
            ),
        )
    else:
        layout = go.Layout(margin=dict(l=0, r=0, b=0, t=0),)

    fig = go.FigureWidget(data=data, layout=layout)
    fig.update_traces(textfont_size=font_size)
    fig.update_layout(scene_aspectmode=scene_aspect)
    fig.update_layout(scene_camera=scene_camera)
    fig.update_layout(margin=dict(l=0, r=0, b=0, t=0))
    if not legend:
        fig.update_layout(showlegend=False)

    fig.update_layout(
        title={
            "text": title,
            "y": 0.9,
            "x": 0.5,
            "xanchor": "center",
            "yanchor": "top",
        },
    )

    if show_plot:
        fig.show()

    fig["layout"]["uirevision"] = "nothing"

    return fig

# Source: http://193.51.245.4/tutorials/convert_a_matplotlib_figure
def fig2data(fig):
    """
    @brief Convert a Matplotlib figure to a 4D numpy array with RGBA channels and return it
    @param fig a matplotlib figure
    @return a numpy 3D array of RGBA values
    """
    # draw the renderer
    fig.canvas.draw()

    # Get the RGBA buffer from the figure
    w, h = fig.canvas.get_width_height()
    buf = np.fromstring(fig.canvas.tostring_argb(), dtype=np.uint8)
    buf.shape = (w, h, 4)

    # canvas.tostring_argb give pixmap in ARGB mode. Roll the ALPHA channel to have it in RGBA mode
    buf = np.roll(buf, 3, axis=2)
    return buf

def fig2img(fig):
    """
    @brief Convert a Matplotlib figure to a PIL Image in RGBA format and return it
    @param fig a matplotlib figure
    @return a Python Imaging Library ( PIL ) image
    """
    # put the figure pixmap into a numpy array
    buf = fig2data(fig)
    w, h, d = buf.shape
    return Image.frombytes("RGBA", (w, h), buf.tostring())


from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
import datetime
import dateutil
from typing import List
from cjwmodule.i18n import trans, I18nMessage

import pandas as pd

def _warn_converted_to_text_because_value_not_timestamp(colname: str, value: str):
    return {
        "message": trans(
            "errors.valueNotTimestamp",
            "Column “{colname}” was converted to Text because the given value is not a Timestamp. "
            "Try entering a value that looks like “2020-01-10” or “2020-01-10T13:11”.",
            # This message doesn't take a "value" argument, but let's
            # store arguments in case we change the message in the future.
            {"colname": colname, "value": value},
        )
    }

def _warn_converted_to_text_because_value_not_number(colname: str, value: str):
    return {
        "message": trans(
            "errors.valueNotNumber",
            "Column “{colname}” was converted to Text because the given value is not a Number. "
            "Try entering a value that looks like “1234” or “12.31242”.",
            # This message doesn't take a "value" argument, but let's
            # store arguments in case we change the message in the future.
            {"colname": colname, "value": value},
        )
    }

def _warn_converted_to_text_because_types_conflict(
    colname: str, value_colnames: List[str]
):
    return {
        "message": trans(
            "errors.valueColumnsWrongType",
            "Values in column “{colname}” were converted to Text because "
            "the chosen columns have different types.",
            # This message doesn't take a "value_colnames" argument, but let's
            # store arguments in case we change the message in the future.
            {"colname": colname, "value_colnames": value_colnames},
        )
    }

def _workbench_type(series: pd.Series) -> Literal["text", "number", "timestamp"]:
    if pd.api.types.is_numeric_dtype(series):
        return "number"
    elif pd.api.types.is_datetime64_dtype(series):
        return "timestamp"
    else:
        return "text"

def _convert_to_str(series: pd.Series) -> pd.Series:
    ret = series.astype(str)
    ret[series.isna()] = None
    return ret

class FillWith(ABC):
    """Abstract class describing how to fill missing values."""

    @abstractmethod
    def run(series: pd.Series) -> Tuple[pd.Series, List]:
        """Return a new `series` with NA values filled in."""

    @classmethod
    def parse(cls, method: str, value: str, from_columns: List[Series]) -> FillWith:
        if method == "value":
            return FillValue(value)
        elif method == "pad":
            return FillPad()
        elif method == "backfill":
            return FillBackfill()
        elif method == "columns":
            return FillWithColumns(from_columns)
        else:
            raise ValueError(f"Invalid method {method}")

class FillValue(FillWith):
    """Operation that fills missing values with a provided value.

    The provided value is given as ``str``; `apply()` will attempt to convert
    it to the series type, if possible.
    """

    def __init__(self, value: str):
        self.value = value

    def run(self, series: pd.Series):
        if not series.isnull().any():
            # There are no nulls. No-op.
            return series, []

        if self.value == "" and _workbench_type(series) in {"number", "timestamp"}:
            # "" means null for timestamps and numbers
            return series, []

        value = self.value
        warnings = []

        # Try to convert `value` to series type. If we fail, convert `series`
        # to str and add a warning.
        if _workbench_type(series) == "number":
            try:
                value = float(self.value)
            except ValueError:
                warnings.append(
                    _warn_converted_to_text_because_value_not_number(series.name, value)
                )
                series = _convert_to_str(series)
        elif _workbench_type(series) == "timestamp":
            try:
                value = dateutil.parser.isoparse(value)
                # TODO test nixing timezone
                if value.tzinfo:
                    value = value.astimezone(datetime.timezone.utc).replace(tzinfo=None)
            except ValueError:
                warnings.append(
                    _warn_converted_to_text_because_value_not_timestamp(
                        series.name, value
                    )
                )
                series = _convert_to_str(series)

        # category (of text) series: value is str; make sure we can fillna() with it
        if hasattr(series, "cat") and self.value not in series.cat.categories:
            series = series.cat.add_categories([self.value])

        return series.fillna(value), warnings

class FillPad(FillWith):
    """Operation that fills missing values with previous ones in the Series."""

    def run(self, series: pd.Series):
        return series.fillna(method="pad"), []

class FillBackfill(FillWith):
    """Operation that fills missing values with next ones in the Series."""

    def run(self, series: pd.Series):
        return series.fillna(method="backfill"), []

class FillWithColumns(FillWith):
    """Operation that fills missing values using other columns' values."""

    def __init__(self, from_columns: List[pd.Series]):
        self.from_columns = from_columns

    def run(self, series: pd.Series):
        warnings = []

        output_is_categorical = hasattr(series, "cat") and all(
            hasattr(c, "cat") for c in self.from_columns
        )

        if hasattr(series, "cat"):
            series = _convert_to_str(series)

        best_type = _workbench_type(series)
        for from_column in self.from_columns:
            if _workbench_type(from_column) != best_type:
                # Unhappy path: convert everything to text
                if best_type != "text":
                    series = _convert_to_str(series)

                from_columns = [
                    col if _workbench_type(col) == "text" else _convert_to_str(col)
                    for col in self.from_columns
                ]
                warnings.append(
                    _warn_converted_to_text_because_types_conflict(
                        series.name,
                        [
                            col.name
                            for col, orig in zip(from_columns, self.from_columns)
                            if col is not orig
                        ],
                    )
                )

                break
        else:
            from_columns = self.from_columns

        ret = series.copy()
        for from_column in from_columns:
            if hasattr(from_column, "cat"):
                from_column = _convert_to_str(from_column)
            ret.fillna(from_column, inplace=True)

        if output_is_categorical:
            ret = ret.astype("category")

        return ret, warnings

def fillna(table: pd.DataFrame, colnames: List[str], fill_with: FillWith) -> None:
    warnings = []
    for colname in colnames:
        series = table[colname]
        series2, series_warnings = fill_with.run(series)
        warnings.extend(series_warnings)
        table[colname] = series2
    return warnings

def render(table, params):
    fill_with = FillWith.parse(
        params["method"], params["value"], [table[c] for c in params["from_colnames"]]
    )
    warnings = fillna(table, params["colnames"], fill_with)
    if warnings:
        return table, warnings
    else:
        return table

def _migrate_params_v0_to_v1(params):
    """
    v0: 'colnames' is comma-separated str; menus are integers
    'contenttype' (0=value, 1=show another menu) and
    'method' (0=pad, 1=backfill). value is 'fillvalue'.

    v1: 'colnames' is List[str]; menu options are value|pad|backfill.
    value is 'value'.

    (These all bring params in line with pandas.DataFrame.fillna.)
    """
    method = {
        (0, 0): "value",
        (0, 1): "value",
        (1, 0): "pad",
        (1, 1): "backfill",
    }[(params["contenttype"], params["method"])]
    return {
        "colnames": [c for c in params["colnames"].split(",") if c],
        "method": method,
        "value": params["fillvalue"],
    }

def _migrate_params_v1_to_v2(params):
    """v1: No "from_colnames" choice. v2 has one."""
    return {
        **params,
        "from_colnames": [],
    }

def migrate_params(params):
    if "contenttype" in params:
        params = _migrate_params_v0_to_v1(params)
    if "from_colnames" not in params:
        params = _migrate_params_v1_to_v2(params)
    return params


# coding: utf-8
# The Hazard Library
# Copyright (C) 2012 GEM Foundation
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
Module exports :class:`Anbazhagan2013`.
"""
from __future__ import division

import numpy as np
# standard acceleration of gravity in m/s**2
from scipy.constants import g

# Compute this log only once
ln10 = np.log(10)

from openquake.hazardlib.gsim.base import CoeffsTable, GMPE
from openquake.hazardlib import const
from openquake.hazardlib.imt import PGA, PGV, SA

class Anbazhagan2013(GMPE):
    """
    Implements GMPE developed by Anbazhagan et al. (2013),  and published
    as "Ground motion prediction equation considering combined dataset
    of recorded and simulated ground motions" (Soil Dynamics and Earthquake
    Engineering, 2013, volume 53, pages 92-108).

    This GMPE was developed for the Himalayan region.
    """

    #: Supported tectonic region type is active shallow crust.
    DEFINED_FOR_TECTONIC_REGION_TYPE = const.TRT.ACTIVE_SHALLOW_CRUST

    #: Supported intensity measure types are spectral acceleration
    #: and peak ground acceleration.
    DEFINED_FOR_INTENSITY_MEASURE_TYPES = set([
        PGA,
        SA
    ])

    #: Supported intensity measure component is the geometric mean of two
    #: horizontal components.
    DEFINED_FOR_INTENSITY_MEASURE_COMPONENT = const.IMC.AVERAGE_HORIZONTAL

    #: Supported standard deviation type is only total.
    DEFINED_FOR_STANDARD_DEVIATION_TYPES = set([
        const.StdDev.TOTAL
    ])

    #: There ar no required site parameters
    REQUIRES_SITES_PARAMETERS = set()

    #: Required rupture parameter is only magnitude.
    REQUIRES_RUPTURE_PARAMETERS = set(('mag',))

    #: Required distance measure is Rhypo.
    REQUIRES_DISTANCES = set(('rhypo', ))

    def get_mean_and_stddevs(self, sites, rup, dists, imt, stddev_types):
        """
        See :meth:`superclass method
        <.base.GroundShakingIntensityModel.get_mean_and_stddevs>`
        for spec of input and result values.
        """
        # extract dictionaries of coefficients specific to required
        # intensity measure type
        C = self.COEFFS[imt]

        # mean value as given by equation (4), p. 103.
        # log y = c1 + c2 * M - b * log10(rhypo + exp(c3 * M))
        c1, c2, c3, b = C['c1'], C['c2'], C['c3'], C['b']
        log10_mean = c1 + c2 * rup.mag - b * np.log10(dists.rhypo + np.exp(c3 * rup.mag))

        # From base-10 to natural logarithm
        mean = log10_mean * ln10

        stddevs = self._get_stddevs(C, stddev_types, num_sites=len(mean))
        # From base-10 to natural logarithm
        stddevs *= ln10

        return mean, stddevs

    def _get_stddevs(self, C, stddev_types, num_sites):
        """
        Return total standard deviation.
        """
        stddevs = []
        for stddev_type in stddev_types:
            assert stddev_type in self.DEFINED_FOR_STANDARD_DEVIATION_TYPES
            stddevs.append(C['sigma'] + np.zeros(num_sites))

        return np.array(stddevs)

    #: Coefficient table constructed from Table 3 of the original paper.
    COEFFS = CoeffsTable(sa_damping=5, table="""\
    IMT      c1         c2          b           c3          sigma
    pga     -1.283      0.544       1.792       0.381       0.283
    0.1     -1.475      0.544       1.585       0.322       0.307
    0.2     -1.366      0.546       1.641       0.410       0.318
    0.3     -1.982      0.542       1.385       0.367       0.298
    0.4     -2.602      0.555       1.178       0.329       0.298
    0.5     -2.980      0.606       1.206       0.350       0.292
    0.6     -3.00       0.623       1.258       0.387       0.299
    0.8     -3.812      0.670       1.080       0.365       0.296
    1.0     -4.357      0.731       1.114       0.383       0.300
    1.2     -4.750      0.766       1.082       0.390       0.298
    1.4     -5.018      0.779       1.032       0.375       0.303
    1.6     -5.219      0.824       1.123       0.399       0.306
    1.8     -5.327      0.840       1.139       0.412       0.313
    2.0     -4.920      0.953       1.617       0.581       0.310
    """)


from turtle import Turtle, Screen
import random

screen = Screen()
screen.setup(width=500, height=400)

bet = screen.textinput(title="Make your bet", prompt="Which turtle will win the race? Enter the color: ").lower()

colors = ["red", "orange", "yellow", "green", "blue", "purple"]

is_race_on = False

red = Turtle(shape="turtle")
red.penup()
red.goto(x=-240, y=27)
# red.pendown()
red.color("red")

orange = Turtle(shape="turtle")
orange.penup()
orange.goto(x=-240, y=81)
# orange.pendown()
orange.color("orange")

yellow = Turtle(shape="turtle")
yellow.penup()
yellow.goto(x=-240, y=135)
# yellow.pendown()
yellow.color("yellow")

green = Turtle(shape="turtle")
green.penup()
green.goto(x=-240, y=-27)
# green.pendown()
green.color("green")

blue = Turtle(shape="turtle")
blue.penup()
blue.goto(x=-240, y=-81)
# blue.pendown()
blue.color("blue")

purple = Turtle(shape="turtle")
purple.penup()
purple.goto(x=-240, y=-135)
# purple.pendown()
purple.color("purple")

if bet:
    is_race_on = True

winners = []

while is_race_on:
    ran_distance_red = random.randint(0, 10)
    ran_distance_orange = random.randint(0, 10)
    ran_distance_yellow = random.randint(0, 10)
    ran_distance_green = random.randint(0, 10)
    ran_distance_blue = random.randint(0, 10)
    ran_distance_purple = random.randint(0, 10)

    red.forward(ran_distance_red)
    orange.forward(ran_distance_orange)
    yellow.forward(ran_distance_yellow)
    green.forward(ran_distance_green)
    blue.forward(ran_distance_blue)
    purple.forward(ran_distance_purple)

    if red.pos()[0] > 222:
        winners.append("red")
    if orange.pos()[0] > 222:
        winners.append("orange")
    if yellow.pos()[0] > 222:
        winners.append("yellow")
    if green.pos()[0] > 222:
        winners.append("green")
    if blue.pos()[0] > 222:
        winners.append("blue")
    if purple.pos()[0] > 222:
        winners.append("purple")

    if len(winners) != 0:
        is_race_on = False

print("The winners are... " + str(winners))

if winners.__contains__(bet):
    print(f"You've won! The {winners} turtle/s are the winner!")
else:
    print(f"You've lost! The {winners} turtle/s are the winner!")

screen.exitonclick()


"""
python3 prog_2.py texts/alice.txt texts/second.txt
"""

import sys
#	NLTK modules
import nltk
from nltk import sent_tokenize as st
from nltk import word_tokenize as wt
from nltk.probability import FreqDist as fd
#	Statistical module
import LC.tok as LC
#	Statistical module
import LC.ner as NE
#	Data cleaning module
import LC.clean as cl
#	Utility module
import LC.toolbox as tool
#import bs4 to edit the output in html format
from bs4 import BeautifulSoup
import write_output as OUT

st = nltk.data.load('tokenizers/punkt/english.pickle')

def main(f_1, f_2):
	"""
	Extracts NER stats from 2 text files
	"""

	######################################
	#	Text extraction
	######################################

	t_1 = ''
	t_2 = ''

	with open(f_1, 'r') as f:
		t_1 = f.read()
	with open(f_2, 'r') as f:
		t_2 = f.read()

	######################################
	#	Text cleaning
	######################################

	t_1 = cl.clean_text(t_1)
	t_2 = cl.clean_text(t_2)

	# Initialize output
	output = OUT.init_html()
	soup = BeautifulSoup(output, 'html.parser')

	col_1 = soup.find('div', {'id': 'text-1-container'})
	col_2 = soup.find('div', {'id': 'text-2-container'})

	title_1 = soup.new_tag('p', attrs={'id' : 'title-1'})
	title_1.insert(1,'Alice in Wonderland')

	title_2 = soup.new_tag('p', attrs={'id' : 'title-2'})
	title_2.insert(1,'Second Variety')

	author_1 = soup.new_tag('p', attrs={'id' : 'author-1'})
	author_1.insert(1,'Lewis Carroll')

	author_2 = soup.new_tag('p', attrs={'id' : 'author-2'})
	author_2.insert(1,'Philip Kindred Dick')

	col_1.append(title_1)
	col_1.append(author_1)

	col_2.append(title_2)
	col_2.append(author_2)

	######################################
	#	Extracting the useful elements
	######################################

	# Sentence tokens
	sents_1 = st.tokenize(t_1)
	sents_2 = st.tokenize(t_2)

	# Word tokens (by sentence)
	s_toks_1 = []
	s_toks_2 = []

	for s_1, s_2 in zip(sents_1, sents_2):
		s_toks_1.append(wt(s_1))
		s_toks_2.append(wt(s_2))

	# Word tokens (unique list)
	toks_1 = wt(t_1)
	toks_2 = wt(t_2)

	# NER tagging

	POS_NE_1 = NE.ner_sents(sents_1)
	POS_NE_2 = NE.ner_sents(sents_2)

	PERSON_sents_1 = NE.get_ner_sents(POS_NE_1, ['PERSON'])
	PERSON_sents_2 = NE.get_ner_sents(POS_NE_2, ['PERSON'])

	# Get the entities of specific NER_tag
	ENTITIES_1 = NE.get_ner_entities(PERSON_sents_1, ['PERSON'])
	ENTITIES_2 = NE.get_ner_entities(PERSON_sents_2, ['PERSON'])

	PEOPLE_1 = LC.rank(ENTITIES_1['PERSON'])[:10]
	PEOPLE_2 = LC.rank(ENTITIES_2['PERSON'])[:10]

	# Print most frequent characters
	nc_1 = OUT.complex_container('Most frequent characters', PEOPLE_1, soup)
	nc_2 = OUT.complex_container('Most frequent characters', PEOPLE_2, soup)
	col_1.append(nc_1)
	col_2.append(nc_2)
	print('added Most frequent characters to project/index.html')

	# Extract only sentence in which appear the selected PEOPLE
	PEOPLE_1 = tool.tup_2_list(PEOPLE_1)
	PEOPLE_2 = tool.tup_2_list(PEOPLE_2)

	useful_sents_1 = NE.meaningful_sents(PERSON_sents_1, ['PERSON'], PEOPLE_1)
	useful_sents_2 = NE.meaningful_sents(PERSON_sents_2, ['PERSON'], PEOPLE_2)

	######################################
	#	Extracting informations
	######################################

	"""
	Now that we have extracted the useful sentences,
	we can begin to mine the information inside them.
	"""

	# NER_tags to look for in the sentence
	NER_tags = ['PERSON', 'LOC', 'GPE', 'DATE', 'TIME']
	POS_tags = ['NN', 'NNP', 'NNPS', 'NNS', 'VB', 'VBD', 'VBG', 'VBN', 'VBP', 'VBZ']

	# For every sent: find the Person and {PERSON_1 : [link1: freq, link2: freq], PERSON_2: [link1: freq, link2: freq]}
	links_1 = NE.extract_links(useful_sents_1, {'PERSON' : PEOPLE_1}, NER_tags, POS_tags)
	links_2 = NE.extract_links(useful_sents_2, {'PERSON' : PEOPLE_2}, NER_tags, POS_tags)

	# Extract the frequency of each link
	links_freqs_1 = NE.extract_link_freqs(links_1)
	links_freqs_2 = NE.extract_link_freqs(links_2)

	#with open('tests/links_freqs_1.txt', 'w') as output:
		#output.write(str(links_freqs_1))

	# Extract the most frequent items for each field
	most_freq_1 = NE.rank_link_freqs(links_freqs_1, 10)
	most_freq_2 = NE.rank_link_freqs(links_freqs_2, 10)

	# Print infos TEXT_1
	for NER in most_freq_1:
		for leaf in most_freq_1[NER]:
			for link_type in most_freq_1[NER][leaf]:
				nc_1 = OUT.complex_container(leaf + ' + ' + link_type, most_freq_1[NER][leaf][link_type], soup)
				col_1.append(nc_1)
				print('added', leaf, ' + ', link_type,'to project/index.html')

	# Print infos TEXT_2
	for NER in most_freq_2:
		for leaf in most_freq_2[NER]:
			for link_type in most_freq_2[NER][leaf]:
				nc_2 = OUT.complex_container(leaf + ' + ' + link_type, most_freq_2[NER][leaf][link_type], soup)
				col_2.append(nc_2)
				print('added', leaf, ' + ', link_type,'to project/index.html')

	# Get the max-prob sentence of lenght between 8 and 12 token

	# Select sents of lenght between 8 and 12 token containing
	selected_sents_1 = tool.sents_of_len(NE.trees_2_toks(useful_sents_1), 8, 12)
	selected_sents_2 = tool.sents_of_len(NE.trees_2_toks(useful_sents_2), 8, 12)

	sents_4_person_1 = NE.assign_sent_2_person(selected_sents_1, PEOPLE_1)
	sents_4_person_2 = NE.assign_sent_2_person(selected_sents_2, PEOPLE_2)

	# Compute the probability for each sentence for each important person in the text
	max_markow_1 = {}
	for person in sents_4_person_1:
		max_markow_1[person] = NE.get_max_markow(sents_4_person_1[person], fd(toks_1), len(t_1), False)

	max_markow_2 = {}
	for person in sents_4_person_2:
		max_markow_2[person] = NE.get_max_markow(sents_4_person_2[person], fd(toks_2), len(t_2), False)

	# Print Markov probabilities
	for person in max_markow_1:
		nc_1 = OUT.tok_sent_container('Probable sentence for ' + person, max_markow_1[person], soup)
		col_1.append(nc_1)
		print('added '+ 'Probable sentence for ' + person + 'to project/index.html')

	for person in max_markow_2:
		nc_2 = OUT.tok_sent_container('Probable sentence for ' + person, max_markow_2[person], soup)
		col_2.append(nc_2)
		print('added '+ 'Probable sentence for ' + person + 'to project/index.html')

	# Final prints
	title_1 = soup.new_tag('p', attrs={'id' : 'book-1'})
	title_1.insert(1,'Alice in Wonderland')
	soup.body.append(title_1)

	title_2 = soup.new_tag('p', attrs={'id' : 'book-2'})
	title_2.insert(1,'Second Variety')
	soup.body.append(title_2)

	# Exporting output
	with open('output/index_2.html', 'w') as h:
		h.write(str(soup))

main(sys.argv[1], sys.argv[2])


from rosbags.rosbag2 import Writer, Reader
from rosbags.serde import serialize_cdr, deserialize_cdr
import csv

def create_ros2_bag(csv_file_path):
    topic_name = "/ins_fix"

    with Reader('bags/path00') as reader:
        for connection, timestamp, rawdata in reader.messages():
            if connection.topic == topic_name:
                msg_type = connection.msgtype
                msg = deserialize_cdr(rawdata, msg_type)
                break

    with Writer('./forged_loop') as bag_writer:
        connection = bag_writer.add_connection(topic_name, msg_type, 'cdr', '')
        with open(csv_file_path, "r") as csvfile:
            csvreader = csv.reader(csvfile)
            header = next(csvreader)  # Skip the header row
            for row in csvreader:
                t, lat, lon, alt = map(float, row)
                msg.latitude = lat
                msg.longitude = lon
                msg.altitude = alt
                cdr_data = serialize_cdr(msg, 'sensor_msgs/msg/NavSatFix')
                bag_writer.write(connection, t, cdr_data)

if __name__ == "__main__":
    csv_file_path = "forged_loop.csv"
    create_ros2_bag(csv_file_path)