import os
import time
import json
import re
import csv
import _thread      # python2's built in 'thread' is changed to '_thread' in python3
import threading    # create multi-thread test case.
from random import randint

import udpCom
import tcpCom
import serialCom
import BgCtrl as bg
import M2PLC221 as m221
import S7PLC1200 as s71200
import Ieee754FBcvt

APP_NAME = "pwrGenMgr"
UDP_PORT = 5005
TCP_PORT = 5009     # set to None if don't want tranfer data under modebus
TEST_MODE = True   # Local test mode flag.
TIME_INT = 1        # time interval to fetch the load.
PLC1_IP = '192.168.10.72'
PLC2_IP = '192.168.10.73'
PLC3_IP = '192.168.10.71'
CSV_VAL = 'pwrSubParm.csv'

# PLC output connection map table:
# PLC 0 [schneider M221]:
#   M10 -> Q0.0 Airport LED
#   M0 -> Q0.1 Power Plant
#   M60 -> Q0.2 Industrial LED
# PLC 1 [seimens S7-1200]
#   Qx0.0-> Q0.0 station + sensor
#   Qx0.1-> Q0.1 level crossing pwr
#   Qx0.2-> Q0.2 Resident LED
# PLC 2 [schneider M221]:
#   M0  -> Q0.0 fork turnout
#   M10 -> Q0.1 track A pwr
#   M20 -> Q0.2 track B pwr
#   M60 -> Q0.3 city LED
#   M50 -> All power down.

#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class pwrGenClient(object):
    """ Client program running on Raspberry PI or normal computer to connect
        to PLC and Arduino. A UDP echo server running in sub-thread will also
        be inited to response the UI control's request.
    """
    def __init__(self, parent, debug=True):
        self.parent = parent
        self.bgCtrler = bg.BgController(APP_NAME)
        self.loadNum = 0        # number of loads.
        self.autoCtrl = False   # generator auto control based on load number.
        self.debug = debug      # debug mode flag.
        self.atkLocker = False  # lock the new incoming attack request if doing attack simulation.
        self.stSubAtkFlag  = 0  # Stealthy substation attack active flag 0 normal case, 1 under attack.
        self.mainPwrSet = False # Wheter we need to set/update main power in the next around of loop.
        self.mainPwrStr = 'on'  # Main power set string 'on'/'off'

        # try to connect to the arduino by serial port.
        self.serialComm = serialCom.serialCom(None, baudRate=115200)
        print("func[__init__]: Parameters inited, wait 30 sec make sure PLCs oneline.")
        time.sleep(40) # wait 40 second to make sure all the PLCs are online already
        # try to connect to the PLCs.
        # ping the IP address first.
        self.plc1 = m221.M221(PLC1_IP)
        self.plc2 = s71200.S7PLC1200(PLC2_IP)
        self.plc3 = m221.M221(PLC3_IP)
        self.reConnectCount = 0 if self.plc1.connected and self.plc2.connected and self.plc3.connected else 10
        # Init the UDP server.
        # self.server = udpCom.udpServer(None, UDP_PORT)
        self.servThread = CommThreadUDP(self, 0, "UDP server thread")
        # Init the TCP modbus data server.
        if TCP_PORT: self.mdBusThread = CommThreadTCP(self, 1, "TCP server thread")
        # Init the state information manager.
        self.stateMgr = stateManager()
        # Power generator nit the platform state:
        if self.serialComm and self.serialComm.connected and not TEST_MODE:
            self.setGenState("50.00:11.00:green:green:green:green:slow:off")
        # Connection state log.
        print('Init finished [Test mode:%s], connection state :\n' %str(TEST_MODE))
        print('Arduino connection : %s' %str(self.serialComm.connected))
        print('PLC 1 [%s] connection: %s' %(PLC1_IP, self.plc1.connected))
        print('PLC 2 [%s] connection: %s' %(PLC2_IP, self.plc2.connected))
        print('PLC 3 [%s] connection: %s' %(PLC3_IP, self.plc3.connected))

#--------------------------------------------------------------------------
    def mainLoop(self):
        """ Controler request handling loop."""
        print("echo-servers start.")
        self.servThread.start()
        if TCP_PORT: self.mdBusThread.start()
        print("Manager main loop start.")
        while self.bgCtrler.bgRun():
            if TEST_MODE:
                # Local simulation mode test:
                self.loadNum = randint(0,3)
            else:
                if self.mainPwrSet:
                    self.setMainPwr(self.mainPwrStr)
                    self.mainPwrSet = False
                if self.atkLocker:continue # dont change the plc when attack is happening
                self.loadNum = self.stateMgr.getLoadNum()
                self.getLoadState()
                # Try reconnect to the PLC if we are in real mode.
                if self.reConnectCount > 0:
                    print(">>> reconnect PLC in %s sec" %str(self.reConnectCount))
                    if self.reConnectCount == 1: self.plcReconnect() # Do the reconnect
                    self.reConnectCount -= 1
            self.autoCtrlGen(self.loadNum) # get the load number.
            time.sleep(TIME_INT)

        # Stop the program and disconnect all the connection.
        self.servThread.stop()
        self.servThread = None
        if self.serialComm: self.serialComm.close()
        if self.plc1.connected: self.plc1.disconnect()
        if self.plc2.connected: self.plc2.disconnect()
        if self.plc3.connected: self.plc3.disconnect()
        print("Power generator main loop end.")

#--------------------------------------------------------------------------
    def plcReconnect(self):
        """ Try to reconnect the PLC if the plc is not connect."""
        if not self.plc1.connected:
            print("Try to reconnect to PLC1: %s" %str(PLC1_IP))
            self.plc1.disconnect()  # disconnect to release the socket.
            self.plc1 = m221.M221(PLC1_IP)
            time.sleep(0.1)

        if not self.plc2.connected:
            print("Try to reconnect to PLC2: %s" %str(PLC2_IP))
            self.plc2.disconnect()  # disconnect to release the socket.
            self.plc2 = s71200.S7PLC1200(PLC2_IP)
            time.sleep(0.1)

        if not self.plc3.connected:
            print("Try to reconnect to PLC3: %s" %str(PLC3_IP))
            self.plc3.disconnect()  # disconnect to release the socket.
            self.plc3 = m221.M221(PLC3_IP)

#--------------------------------------------------------------------------
    def mdBusHandler(self, msg):
        """ Modebus request message handler function.
            incomming message sample: msg = { 'Cmd': str(***), 'Parm': {}}
        """
        if self.debug: print("Incomming TCP message: %s" %str(msg))
        if msg == b'' or msg == b'end' or msg == b'logout':
            return None  # get at program terminate signal.
        # message String
        msgStr = msg.decode('utf-8')
        msgDict = json.loads(msgStr)
        respStr = json.dumps({'Cmd': 'Set', 'Param': 'Done'}) # response string.
        if msgDict['Cmd'] == 'Get':
             if msgDict['Parm'] == 'MdBs':
                respDict = {'Cmd': 'MdBs',
                            'Param': '000040010C'+ self.stateMgr.getModBusStr()
                            }
                respStr = json.dumps(respDict)
                #unitId = 16
                #functionCode = 5
                #coilId = 1
                #req = struct.pack('12B', 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, int(unitId), int(functionCode), 0x00, int(coilId),
                #      0xff,
                #      0x00)
                #return b'\x41\x24\x00\x00\x00\x05\x00\x41\x24\x01\x00'
                #return b'\x00\x01\x00\x00\x00\x06\x15\x03\x00\x6B\x00\x03'
                #return '000040010C'+ self.stateMgr.getModBusStr()
        return respStr

#--------------------------------------------------------------------------
    def msgHandler(self, msg):
        """ Generator request message handler function.
            incomming message sample:
            msg = { 'Cmd': str(***),
                    'Parm': {}}
        """
        if self.debug: print("Incomming UDP message: %s" %str(msg))
        if msg == b'' or msg == b'end' or msg == b'logout':
            return None  # get at program terminate signal.
        # message String
        msgStr = msg.decode('utf-8')
        # Implement cyber attack start and stop.
        if msgStr == 'A;1' or msgStr == 'A;3':
            if self.atkLocker: return None
            _thread.start_new_thread(self.startAttack, (msgStr,))
            return None
        if msgStr == 'A;0':
            self.stopAttack()
            return None
        respStr = json.dumps({'Cmd': 'Set', 'Param': 'Done'}) # response string.
        # Handle the control reqest from the UI.
        msgDict = json.loads(msgStr)
        if msgDict['Cmd'] == 'Get':
            # state get request.
            if msgDict['Parm'] == 'Con':
                # connection state fetch request.
                fbDict = {'Serial': self.serialComm.connected,
                          'Plc1': (not self.plc1 is None) and self.plc1.connected,
                          'Plc2': (not self.plc2 is None) and self.plc2.connected,
                          'Plc3': (not self.plc2 is None) and self.plc3.connected
                          }
                respStr = json.dumps(fbDict)
            elif msgDict['Parm'] == 'Gen':
                # Generator's Ardurino controller state.
                respStr = self.stateMgr.getGenInfo()
            elif msgDict['Parm'] == 'Load':

                respStr = self.stateMgr.getLoadInfo()
            else:
                print('msgHandler : can not handle the un-expect cmd: %s' %str(msgDict['Parm']))
        elif msgDict['Cmd'] == 'SetGen':
            # Generator set request.
            msgStr = self.stateMgr.updateGenSerState(msgDict['Parm'])
            # Send the control cmd to COMM if not under test mode.
            if self.serialComm.connected and (not TEST_MODE):
                if self.debug: print('Write message <%s> to Ardurino' %msgStr)
                self.serialComm.write(msgStr.encode('utf-8'))
            respStr = self.stateMgr.getGenInfo()
        elif msgDict['Cmd'] == 'SetPLC':
            # PLC  set request.
            # Main power
            if 'Mpwr' in msgDict['Parm'].keys():
                self.setMainPwr(msgDict['Parm']['Mpwr'])
            # TrackA and B all sensor power
            if 'Spwr' in msgDict['Parm'].keys():
                self.setSensorPwr(msgDict['Parm']['Spwr'])
            # Pump speed.
            if 'Pspd' in msgDict['Parm'].keys():
                self.setPumpSpeed(msgDict['Parm']['Pspd'])
            # Moto speed.
            if 'Mspd' in msgDict['Parm'].keys():
                self.setMotoSpeed(msgDict['Parm']['Mspd'])
            # Updaste the state manager
            self.stateMgr.updateGenPlcState(msgDict['Parm'])
            respStr = self.stateMgr.getGenInfo()

        elif msgDict['Cmd'] == 'SetALC':
            # set auto load control
            self.autoCtrl = msgDict['Parm']
            self.stateMgr.updateGenPlcState(msgDict['Parm'])
        elif msgDict['Cmd'] == 'GetSub':
            # get the Substation memory value;\
            respStr = self.stateMgr.getSubInfo(self.stSubAtkFlag)
        # Send back the response string.
        return respStr

#--------------------------------------------------------------------------
    def getLoadState(self):
        """" Connect to PLC to get the current load state. <m221_plc_modbus.txt>"""
        loadDict = {'Indu': 0,      # Industry area
                    'Airp': 0,      # Air port
                    'Resi': 0,      # Residential area
                    'Stat': 0,      # Stataion power
                    'TrkA': 0,      # Track A power
                    'TrkB': 0,      # Track B power
                    'City': 0,      # City power
                    }
        # get the PLC 1 state:
        if self.plc1.connected:
            try:
                s1resp = re.findall('..', str(self.plc1.readMem())[-16:])
                loadDict['Indu'] = 1 if s1resp[7] == '00' else 0
                loadDict['Airp'] = 1 if s1resp[1] == '04' else 0
            except Exception as err:
                print("PLC1[%s] data read error:\n%s" %(PLC1_IP, err))
                self.plc1.connected = False
        # get PLC 2 state:
        if self.plc2.connected:
            try:
                loadDict['Resi'] = 0 if self.plc2.getMem('qx0.2') else 1
                loadDict['Stat'] = 1 if self.plc2.getMem('qx0.0') else 0
            except Exception as err:
                print("PLC2[%s] data read error:\n%s" %(PLC2_IP, err))
                self.plc2.connected = False
        # get PLC 3 state
        if self.plc3.connected:
            try:
                s3resp = re.findall('..', str(self.plc3.readMem())[-16:])
                loadDict['TrkA'] = 1 if s3resp[1] == '04' else 0
                loadDict['TrkB'] = 1 if s3resp[2] == '10' else 0
                loadDict['City'] = 1 if s3resp[7] == '00' else 0
            except Exception as err:
                print("PLC3[%s] data read error:\n%s" %(PLC3_IP, err))
                self.plc3.connected = False
        self.stateMgr.updateLoadPlcState(loadDict)

#--------------------------------------------------------------------------
    def autoCtrlGen(self, loadCount):
        """"Auto adjust the gen based on the load number.
        Args:
            loadCount ([int]): [l]
        Returns:
            [type]: [description]
        """
        loadCount = self.stateMgr.getLoadNum(keyList=('Airp', 'Stat', 'TrkA'))
        if (not self.autoCtrl) or (self.loadNum == loadCount):
            return  # no change.
        self.loadNum = loadCount
        freqList = ['51.2', '50.8', '50.0', '49.8']
        sirenSt = 'off'
        color = 'red' if self.loadNum == 0 else 'green'
        msgStr = ':'.join((freqList[self.loadNum], '11.00', color, color, color, color, 'fast', sirenSt))
        self.setGenState(msgStr)

#--------------------------------------------------------------------------
    def setMainPwr(self, val):
        """ Set the system main power. 0-off, 1-on."""
        self.autoCtrl = False
        pwrVal = 1 if val == 'on' else 0
        ledVal = 0 if val == 'on' else 1
        plc2Val = True if val == 'on' else False
        if self.plc1.connected:
            self.plc1.writeMem('M0', pwrVal)
            time.sleep(0.1)
            self.plc1.writeMem('M10', pwrVal)
            time.sleep(0.1)
            self.plc1.writeMem('M60', ledVal)
            time.sleep(0.1)
        if self.plc2.connected:
            self.plc2.writeMem('qx0.0', plc2Val)
            time.sleep(0.1)
            self.plc2.writeMem('qx0.2', not plc2Val)
            time.sleep(0.1)
        if self.plc3.connected:
            self.plc3.writeMem('M10', pwrVal)
            time.sleep(0.1)
            self.plc3.writeMem('M60', ledVal)
            time.sleep(0.1)
        return
        # below is the one using new PLC lider diagram follow the function introduction.
        if not self.plc3.connected:
            print('PLC3 not connected, can not set system main power.')
            return
        self.plc3.writeMem('M6', pwrVal)

#--------------------------------------------------------------------------
    def setMotoSpeed(self, val):
        """ Set generator pump speed plc2 [Q3, Q3]. FF-off, FT-low, TF-high."""
        # change the plc state to do the action.
        if not self.plc2.connected:
            if self.debug: print('PLC2 not connected, can not set Moto speed.')
            return
        mSpeedDict = {'off': (False, False), 'low': (False, True), 'high': (True, False)}
        self.plc2.writeMem('qx0.3', mSpeedDict[val][0])
        time.sleep(0.01) # need we sleep a shot while for plc to response?
        self.plc2.writeMem('qx0.4', mSpeedDict[val][1])

#--------------------------------------------------------------------------
    def setPumpSpeed(self, val):
        """ Set generator pump speed plc1 [M4, M5]. 00-off, 01-low, 10-high."""
        if not self.plc1.connected:
            if self.debug: print('PLC1 not connected, can not set pump speed.')
            return
        # change the plc state to do the action.
        pSpeedDict = {'off': (0, 0), 'low': (0, 1), 'high': (1, 0)}
        self.plc1.writeMem('M4', pSpeedDict[val][0])
        time.sleep(0.01) # need we sleep a shot while for plc to response?
        self.plc1.writeMem('M5', pSpeedDict[val][1])

#--------------------------------------------------------------------------
    def setSensorPwr(self, val):
        """ Set all track sensor's power PLC3 [M4, M5]. 00-off, 11-on."""
        if not self.plc3.connected:
            if self.debug: print('PLC3 not connected, can not set all sensor power.')
            return
        parm = 1 if val == 'on' else 0
        self.plc3.writeMem('M4', parm)
        self.plc3.writeMem('M5', parm)

#--------------------------------------------------------------------------
    def setGenState(self, stateStr):
        """ Set the generator working state.
        Args:
            stateStr ([str]): generator state string:
            Freq:Volt:Fled:Vled:Mled:Pled:Smok:Sirn
            example: 52.00:11.00:amber:amber:amber:amber:off:on"
        Returns:
            [None]: [description]
        """
        if self.serialComm and self.serialComm.connected:
            self.serialComm.write(stateStr.encode('utf-8'))
        valList = stateStr.split(':')
        if len(valList) != 8:
            print("Error: serialComm str parameter missing: %s" %stateStr)
            return None
        else:
            genDict = {'Freq': valList[0],
                        'Volt': valList[1],
                        'Fled': valList[2],
                        'Vled': valList[3],
                        'Mled': valList[4],
                        'Pled': valList[5],
                        'Smok': valList[6],
                        'Sirn': valList[7]}
            self.stateMgr.updateGenSerState(genDict)

#--------------------------------------------------------------------------
    def startAttack(self, threadName):
        """ Simulate the attack situation."""
        self.atkLocker = True   # Lock the attack flag.
        self.autoCtrl = False   # disable the auto control.
        if threadName == 'A;1':
            # Create the generator alert.
            time.sleep(10)
            self.setGenState("52.00:11.00:amber:amber:amber:amber:off:on")
            time.sleep(5)
            # Show the generator down situation.
            self.setGenState("50.00:00.00:red:red:red:red:off:off")
            self.autoCtrl = True
            return None
        elif threadName == 'A;3':
            time.sleep(5) # wait 5 sec then start the attack.
            print(">>> Start the Stealthy attack.")
            self.setGenState("49.89:11.00:red:red:red:red:off:on")
            self.stSubAtkFlag = 1 # put the attack appearence after the module have action.
            time.sleep(1)
            if self.plc1.connected: self.plc1.writeMem('M60', 1)
            time.sleep(1)

            for i in range(15):
                val = i%2
                # 1. Flickering of Airport runway light
                if self.plc1.connected:
                    self.plc1.writeMem('M0', val)
                    time.sleep(0.3)
                    self.plc1.writeMem('M10', val)
                    time.sleep(0.3)
                # 2. Flickering of substation light(optional)
                if self.plc2.connected:
                    v = True if val == 1 else False
                    self.plc2.writeMem('qx0.0', v)
                    time.sleep(0.3)
                # 3.Train stop/start moving
                if self.plc3.connected:
                    self.plc3.writeMem('M10', 0)
                    time.sleep(0.5)
                    self.plc3.writeMem('M10', 1)
                if i == 5:
                    self.setGenState("50.80:11.00:red:red:red:red:off:off")
                if i == 10:
                    self.setGenState("50.00:11.00:amber:amber:amber:amber:off:on")

            # 3.Switch off Airport runway light
            self.plc1.writeMem('M10', 0)
            # 4.Wait for 10 secs
            time.sleep(10)
            # Generater show alert
            self.setGenState("51.20:11.00:red:red:red:red:off:off")
            # 5. Switch off Train
            self.plc3.writeMem('M10', 0)
            # 6. Wait for 10 secs
            time.sleep(10)
            # self.plc2.writeMem('qx0.2', True)
            # 7.City light change to red.
            self.plc3.writeMem('M60', 1)
            # self.autoCtrl = True
        self.atkLocker = False
        return None

#--------------------------------------------------------------------------
    def stopAttack(self):
        """ recover the PLC and power generator state after attack."""
        # Recover the power generator
        self.atkLocker = True
        self.setGenState("52.00:11.00:green:green:green:green:off:off")
        # Revocer the PLC state.
        if self.plc1.connected:
            self.plc1.writeMem('M0', 1)
            self.plc1.writeMem('M10', 1)
            self.plc1.writeMem('M60', 0)
        if self.plc2.connected:
            self.plc2.writeMem('qx0.0', True)
        if self.plc3.connected:
            self.plc3.writeMem('M10', 1)
        self.atkLocker = False
        self.stSubAtkFlag = 0

#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class stateManager(object):
    """ Manager module to save the current system state."""
    def __init__(self):
        # Serial cmd str sequence.
        self.serialSqu = ('Freq', 'Volt', 'Fled', 'Vled', 'Mled', 'Pled', 'Smok', 'Sirn')
        self.subParms = {'Nml':[[] for a in range(4)],
                        'Atk':[[] for a in range(4)]}
        self.loadCSVParm(os.path.join(os.path.dirname(__file__), CSV_VAL))
        self.AtkFlag = False # The flag to identify whether fetch the attack data.
        # Generator state dictionary.
        self.genDict = {    'Freq': '50.00',    # frequency (dd.dd)
                            'Volt': '11.00',    # voltage (dd.dd)
                            'Fled': 'green',    # frequency led (green/amber/off)
                            'Vled': 'green',    # voltage led (green/amber/off)
                            'Mled': 'green',    # motor led (green/amber/off)
                            'Pled': 'green',    # pump led (green/amber/off)
                            'Smok': 'off',      # smoke indicator (fast/slow/off)
                            'Pspd': 'off',      # pump speed (high/low/off)
                            'Mspd': 'off',      # moto speed (high/low/off)
                            'Sirn': 'off',      # siren (on/off)
                            'Spwr': 'off',      # sensor power (on/off)
                            'Mpwr': 'on',       # main power (on/off)
                            'Mode': 0           # control mode.
                        }
        # Power load state dictionary.
        self.loadDict = {   'Indu': 0,      # Industry area
                            'Airp': 1,      # Airport runway
                            'Resi': 0,      # Residential area
                            'Stat': 1,      # Stataion power
                            'TrkA': 0,      # Track A power
                            'TrkB': 1,      # Track B power
                            'City': 0,      # City power
                         }
        # Substation memory dictrionary.
        self.subMemDict = {
            'ff00': '0',    # FF00:Pkm
            'ff01': '0',    # FF01:Qkm
            'ff02': '0',    # FF02:Pmk
            'ff03': '0',    # FF03:Qkm
            'ff04': '0',    # FF04:Pk
            'ff05': '0',    # FF05:Qk
            'ff06': '0',    # FF06:Pm
            'ff07': '0',    # FF07:Qm
            'ff08': '0',    # FF08:Vk
            'ff09': '0',    # FF09:Vm
            'ff10': '0',    # Attack flag
        }

#--------------------------------------------------------------------------
    def printState(self):
        """ Test function used for debug.(Print all current state."""
        print("self.genDict: \n %s \n" %str(self.genDict))
        print("self.loadDict: \n %s \n" %str(self.loadDict))
        print("self.subMemDict: \n %s \n" %str(self.subMemDict))
        print("self.subParms: \n %s \n" %str(self.subParms))

#--------------------------------------------------------------------------
    def loadCSVParm(self, csvFile):
        """ Load the parameters data from the CSV file. """
        try:
            with open(csvFile, 'r') as file:
                reader = csv.reader(file)
                rowCnt = 0
                for row in reader: # remove header.
                    if rowCnt == 0:
                        rowCnt +=1
                        continue    # ignore the title row.
                    tag = 'Nml' if int(row[0]) == 0 else 'Atk'
                    self.subParms[tag][int(row[1])].append(row[2:])
        except Exception as err:
            print("CSV file IO Error: %s" %str(err))

#--------------------------------------------------------------------------
    def getGenInfo(self):
        """ Return the generator state json string."""
        return json.dumps(self.genDict)

#--------------------------------------------------------------------------
    def getSubInfo(self,atkFlag=None):
        """ Return the generator state parameter json string.
            atkFlag = 0/None : normal case
            atkFlag = 1: attack started
        """
        loadNum = 3 if TEST_MODE else sum(
            (self.loadDict['Airp'], self.loadDict['Stat'], self.loadDict['TrkA']))
        valIdx = randint(0, 5) if atkFlag else randint(0, 18)
        statStr = 'Atk' if atkFlag else 'Nml'
        for i in range(10):
            self.subMemDict["ff{:02d}".format(i)] = self.subParms[statStr][loadNum][valIdx][i]
        self.subMemDict["ff10"] = '0' if atkFlag else '1'
        return json.dumps(self.subMemDict)

#--------------------------------------------------------------------------
    def getModBusStr(self):
        """ Convert the substation message dict to ModBus string format."""
        dataList = [Ieee754FBcvt.F2B(float(val)) for val in self.subMemDict.values()]
        return "".join(dataList)

#--------------------------------------------------------------------------
    def getLoadInfo(self):
        """ Return the power load state json string."""
        return json.dumps(self.loadDict)

#--------------------------------------------------------------------------
    def getLoadNum(self, keyList=None):
        """ Return the number of loads """
        if keyList is None:
            return sum(self.loadDict.values())
        else:
            count = 0
            for key in keyList:
                count+=self.loadDict[key]
            return count

#--------------------------------------------------------------------------
    def updateGenSerState(self, changeDict):
        """ Passed in the changeDict and the function will return the Ardurino
            control string.
        """
        # first time init setting.
        if changeDict is None:
            return ':'.join([self.genDict[keyStr] for keyStr in self.serialSqu])
        valList = []
        for keyStr in self.serialSqu:
            if keyStr in changeDict.keys():
                self.genDict[keyStr] = changeDict[keyStr]
                valList.append(self.genDict[keyStr])
            else:
                valList.append('-') # append the ingore char if the value not change.
        return ':'.join(valList)

#--------------------------------------------------------------------------
    def updateGenPlcState(self, changeDict):
        """ Update the generator PLC state."""
        for keyStr in changeDict.keys():
            self.genDict[keyStr] = changeDict[keyStr]

#--------------------------------------------------------------------------
    def updateLoadPlcState(self, changeDict):
        """ Update the load PLc state. """
        for keyStr in changeDict.keys():
            self.loadDict[keyStr] = changeDict[keyStr]

#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class CommThreadUDP(threading.Thread):
    """ Sub-thread running parallel with the main thread to handle the UDP
        request from the control UI program running on the SCADA PC.
    """
    def __init__(self, parent, threadID, name):
        threading.Thread.__init__(self)
        self.threadName = name
        self.parent = parent
        self.server = udpCom.udpServer(None, UDP_PORT)
        print("CommThreadUDP:   UDP data handling server thread started.")

    def run(self):
        """ Start the udp server's main message handling loop."""
        print("CommThreadUDP:   UDP Server thread run() start.")
        self.server.serverStart(handler=self.parent.msgHandler)
        print("CommThreadUDP:   Server thread run() end.")
        self.threadName = None # set the thread name to None when finished.

    def stop(self):
        """ Stop the udp server. Create a endclient to bypass the revFrom() block."""
        self.server.serverStop()
        endClient = udpCom.udpClient(('127.0.0.1', UDP_PORT))
        endClient.disconnect()
        endClient = None

#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class CommThreadTCP(threading.Thread):
    """ Sub-thread running parallel with the main thread to feed back the ModBus
        TCP message.
    """
    def __init__(self, parent, threadID, name):
        threading.Thread.__init__(self)
        self.threadName = name
        self.parent = parent
        self.server = tcpCom.tcpServer(None, TCP_PORT, connectNum=1)
        print("CommThreadTCP:   TCP ModBus msg handling server thread started.")

    def run(self):
        """ Start the tcp server's main message handling loop."""
        print("CommThreadTCP:   TCP Server thread run() start.")
        self.server.serverStart(handler=self.parent.mdBusHandler)
        print("CommThreadTCP:   Server thread run() end.")
        self.threadName = None # set the thread name to None when finished.

    def stop(self):
        """ Stop the tcp server. Create a endclient to bypass the rev() block."""
        self.server.serverStop()
        endClient =tcpCom.tcpClient(('127.0.0.1', TCP_PORT))
        endClient.disconnect()
        endClient = None

#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
def main(mode=0):
    if mode == 0:
        client = pwrGenClient(None, debug=True)
        client.mainLoop()
    elif mode == 1:
        stateMgr = stateManager()
        stateMgr.printState()

#-----------------------------------------------------------------------------
if __name__ == '__main__':
    main()


import re

keywords_list = ["class", "constructor", "function", "method", "field",
                 "static",
                 "var", "int", "char", "boolean", "void", "true", "false",
                 "null", "this",
                 "let", "do", "if", "else", "while", "return"]
symbols_list = ['{', '}', '(', ')', '[', ']', '.', ',', ';', '+', '-', '/',
                '*', '>', '<', '&','=', '~', '|']

exceptions = ["<", ">", "\"", "&"]

class JackTokenizer:
    string_list = []

    def __init__(self, file_text):
        self.index = 0  # token index
        self.text = file_text.readlines()  # the original jack commands
        self.tokenized_text = []  # the tokenized text include only tokens
        # which the engine will work on.
        self.current_token = None
        self.TokenizingProccess(self.text) # the whole process starts here

    def TokenizingProccess(self, text):
        # ignoring all kind of comments and replacing and saving all strings("") in special list
        inside_comment = False
        inside_string = False

        for line in text:
            line = line.lstrip()
            if line == "" or line[0:2] == "//" or line == "\n":
                continue
            if line[0:2] == "/*":
                inside_comment = True
            if inside_comment and "*/" in line:  # if start comment and close comment on the same line
                inside_comment = False
                two_sides = line.split("*/")
                if two_sides[1] != "\n":
                    line = two_sides[1]
                else:
                    continue
            elif inside_comment:  # if we dont see the light the end of the tunnel
                continue
            # if the line is not a kind of comment - check if it is any other object and add it to tokenizd text
            if not inside_comment:
                temp = ""
                for index, char in enumerate(line):

                    if char == "\"":
                        # if we are about to close a string
                        if inside_string:
                            inside_string = False
                            temp += str(char)
                            self.tokenized_text.append(temp)
                            temp = ""
                            continue
                        # if we in string
                        elif not inside_string and temp != "":
                            self.tokenized_text.append(temp)
                            temp = ""
                            temp += str(char)
                            inside_string = True
                            continue
                        elif not inside_string and temp == "":
                            temp += str(char)
                            inside_string = True
                            continue

                    if inside_string:
                        temp += char

                    # if we are not in a string
                    else:
                        if char == "/":
                            if line[index + 1] == "/":
                                temp = ""
                                break
                            elif line[index + 1] == "*":
                                inside_comment = True
                                break
                            else:
                                # if its the "/" symbol and continue iteration
                                self.tokenized_text.append(char)
                                temp = ""
                                continue

                        if char == "\n":
                            break
                        # if its a normal char
                        if char != " " and char not in symbols_list:
                            temp += str(char)
                        # if the char is whitespace so we just finished read a token
                        elif char == " " and temp != "":
                            self.tokenized_text.append(temp)
                            temp = ""
                        # if we deal with one of the symbol
                        elif char in symbols_list and temp != "":
                            self.tokenized_text.append(temp)
                            self.tokenized_text.append(char)
                            temp = ""
                        elif char in symbols_list and temp == "":
                            self.tokenized_text.append(char)

        # another cleaner of the tokens which keep up for reserved words and
        # lstrip them all
        for index,token in enumerate(self.tokenized_text):
            self.tokenized_text[index] = token.lstrip()
            if token in exceptions:
                if token == "<":
                    self.tokenized_text[index] = "<"
                elif token == ">":
                    self.tokenized_text[index] = ">"
                elif token == "\"":
                    self.tokenized_text[index] = """
                elif token == "&":
                    self.tokenized_text[index] = "&"

    def advance(self):
        "advancing the next token in the tokenized_text list"
        if self.hasMoreTokens():
            self.current_token = self.tokenized_text[
                self.index].lstrip()  # remove whitespace maybe unneeded
            self.index += 1

    def hasMoreTokens(self):
        if self.index == len(self.tokenized_text):
            return False
        return True

    # resposnsible to return the type of tokens only - job of the tokenizer
    def typeOfToken(self):
        int_pattern = '^\d+$'
        string_pattern = '^\".*\"$'
        identifier_pattern = '^[^0-9]\w*$'

        if self.current_token in keywords_list:
            return "keyword"

        if self.current_token in symbols_list:
            return "symbol"

        if re.match(int_pattern, self.current_token):
            return "int_constant"

        if re.match(string_pattern, self.current_token):
            return "string_constant"
        # if none of the above - so it must be an identifier
        if re.match(identifier_pattern, self.current_token):
            return "identifier"

    def getNextToken(self):
        """returns the next token without advancing the engine (for ll(1) purposes
        """
        if self.hasMoreTokens():
            return self.tokenized_text[self.index]

    def getCurrentToken(self):
        "returns the current token which the compilationEngine is working on"
        return self.current_token

    def showNextToken(self):
        """very useful method which used for ll(1) problem"""
        if self.hasMoreTokens():
            return self.tokenized_text[self.index]
        return True

    def previousToken(self):
        """get the previous token"""
        if self.index>1:
            self.current_token = self.tokenized_text[self.index -2]
            self.index -= 1


import torch.utils.data as data

from PIL import Image
import os
import os.path
import numpy as np
from numpy.random import randint

def abs_listdir(directory, prefix=None):
    def abspath_join(directory, path):
        return os.path.abspath(os.path.join(directory, path))

    if prefix:
        filepaths = [
            abspath_join(directory, path)
            for path in os.listdir(directory)
            if path.startswith(prefix)
        ]

    else:
        filepaths = [
            abspath_join(directory, path)
            for path in os.listdir(directory)
        ]

    return filepaths

class VideoRecord(object):
    def __init__(self, row, custom = False, prefix=None):
        self._data = row
        self.custom = custom

        filepaths = abs_listdir(self._data[0], prefix=prefix)
        self.__num_frames = len(filepaths)

        if self.__num_frames == 0:
            print("No Frames %s, %s" %(prefix, self.path))

    @property
    def path(self):
        return self._data[0]

    @property
    def num_frames(self):
        if self.custom:
            return int(self.__num_frames) - 9
        else:
            return int(self.__num_frames) - 1

    @property
    def label(self):
        return int(self._data[-1])

class TSNDataSet(data.Dataset):
    def __init__(self, root_path, list_file,
                 num_segments=1, new_length=1, modality='RGB',
                 image_tmpl='img_{:05d}.jpg', transform=None, custom_prefix = None,
                 force_grayscale=False, random_shift=True, test_mode=False):

        self.root_path = root_path
        self.list_file = list_file
        self.num_segments = num_segments
        self.new_length = new_length
        self.modality = modality
        self.custom_prefix = custom_prefix

        if custom_prefix:
            self.image_tmpl = self.custom_prefix + '{:05d}.jpg'
        else:
            self.image_tmpl = image_tmpl

        self.transform = transform
        self.random_shift = random_shift
        self.test_mode = test_mode

        if self.modality == 'RGBDiff':
            self.new_length += 1# Diff needs one more image to calculate diff

        self._parse_list()

    def _load_image(self, directory, idx):
        if self.modality == 'RGB' or self.modality == 'RGBDiff' or self.modality== 'ARP':
            return [Image.open(os.path.join(directory, self.image_tmpl.format(idx))).convert('RGB')]
        elif self.modality == 'Flow':
            if idx != 1: # WHAT IS THIS FOR???
                idx = idx - 1
            x_img = Image.open(os.path.join(directory, self.image_tmpl.format('x', idx))).convert('L')
            y_img = Image.open(os.path.join(directory, self.image_tmpl.format('y', idx))).convert('L')

            return [x_img, y_img]

    def _parse_list(self):
        prefix = self.modality.lower()
        if prefix == 'flow':
            prefix = prefix + '_x'

        if self.image_tmpl.startswith('rp'):
            self.video_list = [VideoRecord(x.strip().split(' '), True, prefix=prefix) for x in open(self.list_file)]
        else:
            self.video_list = [VideoRecord(x.strip().split(' '), False, prefix=prefix) for x in open(self.list_file)]

    def _sample_indices(self, record):
        """

        :param record: VideoRecord
        :return: list
        """

        average_duration = (record.num_frames - self.new_length + 1) // self.num_segments
        if average_duration > 0:
            offsets = np.multiply(list(range(self.num_segments)), average_duration) + randint(average_duration, size=self.num_segments)
        elif record.num_frames > self.num_segments:
            offsets = np.sort(randint(record.num_frames - self.new_length + 1, size=self.num_segments))
        else:
            offsets = np.zeros((self.num_segments,))
        return offsets + 1

    def _get_val_indices(self, record):
        if record.num_frames > self.num_segments + self.new_length - 1:
            tick = (record.num_frames - self.new_length + 1) / float(self.num_segments)
            offsets = np.array([int(tick / 2.0 + tick * x) for x in range(self.num_segments)])
        else:
            offsets = np.zeros((self.num_segments,))
        return offsets + 1

    def _get_test_indices(self, record):

        tick = (record.num_frames - self.new_length + 1) / float(self.num_segments)

        offsets = np.array([int(tick / 2.0 + tick * x) for x in range(self.num_segments)])

        return offsets + 1

    def __getitem__(self, index):
        record = self.video_list[index]

        if not self.test_mode:
            segment_indices = self._sample_indices(record) if self.random_shift else self._get_val_indices(record)
        else:
            segment_indices = self._get_test_indices(record)

        return self.get(record, segment_indices)

    def get(self, record, indices):

        images = list()
        for seg_ind in indices:
            p = int(seg_ind)
            for i in range(self.new_length):
                seg_imgs = self._load_image(record.path, p)
                images.extend(seg_imgs)
                if p < record.num_frames:
                    p += 1

        process_data = self.transform(images)
        return process_data, record.label

    def __len__(self):
        return len(self.video_list)


# ipv4 to 32

def ipv4_to_32(IPadd):

    res = []
    oct_list = IPadd.split(".")

    for oct in oct_list:
        dec_to_bin = {
            128 : 0,
            64 : 0,
            32 : 0,
            16 : 0,
            8 : 0,
            4 : 0,
            2 : 0,
            1 : 0
        }

        oct = int(oct)
        while oct > 0:
            for n in dec_to_bin:
                if oct - n >= 0:
                    oct = oct - n
                    dec_to_bin[n] = 1

        oct = "".join(list(map(str,list(dec_to_bin.values()))))
        res.append(oct)

    print(".".join(res))
    # return ".".join(res)

# ipv4_to_32("100.43.94.0")

# int32 to IPv4 https://www.codewars.com/kata/52e88b39ffb6ac53a400022e
def int32_to_ipv4(int32):
    int32 = bin(int32)

    print(int32)

int32_to_ipv4(2149583361)

'''
To convert an unsigned 32-bit number to a signed binary representation, we can use the Two's Complement method. Here are the steps:

Write down the 32-bit binary representation of the unsigned number. If the number is already in binary format, then skip this step.

If the most significant bit (MSB) is 0, then the number is positive, and the signed representation is the same as the unsigned representation.

If the MSB is 1, then the number is negative. In this case, we need to take the Two's Complement of the number to get the signed representation.

To get the Two's Complement of the number, we invert all the bits (change 0 to 1, and 1 to 0) and add 1 to the result.

The result of step 4 is the signed binary representation of the original unsigned number.

Here is an example:

Let's convert the unsigned 32-bit number 2147483648 to a signed binary representation.

The 32-bit binary representation of the number is 10000000000000000000000000000000.

The MSB is 1, so the number is negative.

To get the Two's Complement of the number, we invert all the bits:

01111111111111111111111111111111

Add 1 to the result:

10000000000000000000000000000000

The result is the signed binary representation of the original unsigned number: -2147483648.
'''


import resolver.Unifier as Unifier
from preprocessor.KnowledgeBase import KBStorageUnit
import time

class Resolver:
    def __init__(self, knowledge_base, queries):
        self.knowledge_base = knowledge_base
        self.queries = queries

    def fetch_conjugate_predicates(self, query, clause):
        conjugate_list = []
        query_predicates = query.predicates
        clause_predicates = clause.predicates
        existing_conjugates = set()
        common_predicates = query_predicates.keys() & clause_predicates.keys()
        for pred in common_predicates:
            for x in clause_predicates[pred]:
                for y in query_predicates[pred]:
                    if x.operator != y.operator and x not in \
                            existing_conjugates and y not in existing_conjugates:
                        existing_conjugates.add(x)
                        existing_conjugates.add(y)
                        conjugate_list.append([x, y])
        return conjugate_list

    def result_output(self):
        raise TrueQuery

    def resolve_clause(self, sub_dicts, clauses, query, query_start_time,
                       depth=0):
        output = "TRUE"
        check_flag = False
        query_elapsed_time = int(time.time())
        if depth >= 800: # or query_elapsed_time >= query_start_time:
            raise MaxDepthLimit
        for kb_clause in clauses:
            print(kb_clause.predicates.keys() & query.predicates.keys())
            if kb_clause.predicates.keys() & query.predicates.keys():
                conjugates = self.fetch_conjugate_predicates(query,
                                                             kb_clause)
                for conjugate in conjugates:
                    check_flag = False
                    resolution_step_output = self.resolve_query(query,
                                                                conjugate,
                                                                kb_clause)
                    if resolution_step_output:
                        new_clause, sub_dict = resolution_step_output
                        if new_clause.disjunct_clauses == set():
                            self.result_output()
                        else:
                            if len(
                                    sub_dict) == 0 and new_clause in self.knowledge_base:
                                continue
                            if len(sub_dict) != 0:
                                new_clause = new_clause.substitute_unified_values(
                                    sub_dict)
                                for k in clauses:
                                    if new_clause.disjunct_clauses == k.disjunct_clauses:
                                        check_flag = True
                                        break

                                if check_flag:
                                    continue
                            output = self.resolve_clause(
                                (sub_dict, sub_dicts), clauses + [query],
                                new_clause, query_start_time, depth + 1)
        return "FALSE"

    def resolve_query(self, query, conjugate, clause):
        var1 = conjugate[0]
        var2 = conjugate[1]
        unified_predicates = set()
        if var1.operator == "~":
            clause1 = var1.sub_expr[0]
            clause2 = var2
        else:
            clause1 = var1
            clause2 = var2.sub_expr[0]
        try:
            unified_dict = Unifier.unify_clause({}, clause1, clause2)
        except Exception:
            pass
        else:
            if not unified_dict and self.check_constants(clause1.sub_expr,
                                                         clause2.sub_expr):
                return False
            else:
                if unified_dict or (
                    not unified_dict and not self.check_constants(clause1,
                                                                  clause2)):
                    unified_predicates.add(var1)
                    unified_predicates.add(var2)
        if unified_predicates:
            return KBStorageUnit(clause.disjunct_clauses.union(
                query.disjunct_clauses) - unified_predicates), unified_dict
        return False

    def check_constants(self, expr1, expr2):
        if expr1 != expr2:
            return True
        else:
            return False

    def resolve_all_queries(self):
        output_list = []
        for query in self.queries:
            try:
                query_start_time = time.time()
                result = self.resolve_clause(None, self.knowledge_base,
                                             query,
                                             (int(query_start_time) + 60))
                output_list.append(result)
            except TrueQuery:
                output_list.append("TRUE")
                pass
            except MaxDepthLimit:
                output_list.append("FALSE")
        print("Output File Result: ", output_list)
        return output_list

class TrueQuery(Exception):
    pass

class MaxDepthLimit(Exception):
    pass


import pygame
import random
import struct
import sys

class AddressOutOfRange(Exception):
  pass

class ProgramCounterOutOfRange(Exception):
  pass

class StackPointerOutOfRange(Exception):
  pass

class UnsupportedOpcode(Exception):
  pass

class AddressValueIsNotEven(Exception):
  pass

class Cpu:

  font_set = (
      0xF0, 0x90, 0x90, 0x90, 0xF0, # 0
      0x20, 0x60, 0x20, 0x20, 0x70, # 1
      0xF0, 0x10, 0xF0, 0x80, 0xF0, # 2
      0xF0, 0x10, 0xF0, 0x10, 0xF0, # 3

      0x90, 0x90, 0xF0, 0x10, 0x10, # 4
      0xF0, 0x80, 0xF0, 0x10, 0xF0, # 5
      0xF0, 0x80, 0xF0, 0x90, 0xF0, # 6
      0xF0, 0x10, 0x20, 0x40, 0x40, # 7

      0xF0, 0x90, 0xF0, 0x90, 0xF0, # 8
      0xF0, 0x90, 0xF0, 0x10, 0xF0, # 9
      0xF0, 0x90, 0xF0, 0x90, 0x90, # A
      0xE0, 0x90, 0xE0, 0x90, 0xE0, # B

      0xF0, 0x80, 0x80, 0x80, 0xF0, # C
      0xF0, 0x80, 0x80, 0x80, 0xF0, # D
      0xF0, 0x80, 0xF0, 0x80, 0xF0, # E
      0xF0, 0x80, 0xF0, 0x80, 0x80  # F
  )

  cols = 64
  rows = 32

  def __init__(self):
    self._main_optbl = {
      0x0 : self._op0_nest,
      0x1 : self._op_jmp,
      0x2 : self._op_call,
      0x3 : self._op_ske,
      0x4 : self._op_skne,
      0x5 : self._op_sker,
      0x6 : self._op_ld,
      0x7 : self._op_add,
      0x8 : self._op8_nest,
      0x9 : self._op_sner,
      0xA : self._op_ldi,
      0xB : self._op_jmpv0,
      0xC : self._op_rnd,
      0xD : self._op_drw,
      0xE : self._opE_nest,
      0xF : self._opF_nest,
    }

    self._optbl0 = {
      0xE0 : self._op_cls,
      0xEE : self._op_ret,
    }

    self._optbl8 = {
      0x0 : self._op_ldr,
      0x1 : self._op_orr,
      0x2 : self._op_andr,
      0x3 : self._op_xorr,
      0x4 : self._op_addr,
      0x5 : self._op_subr,
      0x6 : self._op_shr,
      0x7 : self._op_subnr,
      0xE : self._op_shl,
    }

    self._optblE = {
      0x9E : self._op_skp,
      0xA1 : self._op_sknp,
    }

    self._optblF = {
      0x07 : self._op_ldv,
      0x0A : self._op_ldvk,
      0x15 : self._op_lddt,
      0x18 : self._op_ldst,
      0x1E : self._op_addi,
      0x29 : self._op_ldf,
      0x33 : self._op_ldb,
      0x55 : self._op_ldix,
      0x65 : self._op_ldxi,
    }

    self.reset()

  def _unsupported_opcode(self):
    raise UnsupportedOpcode

  def _pop(self):
    if self.sp <= -1:
      raise StackPointerOutOfRange
    item = self.stack[self.sp]
    self.sp -= 1
    return item

  def _push(self, item):
    if self.sp >= len(self.stack):
      raise StackPointerOutOfRange
    self.sp += 1
    self.stack[self.sp] = item

  def _opF_nest(self):
    self._optblF.setdefault(self._nn, self._unsupported_opcode)()

  def _op_ldxi(self):
    ''' 0xFx65 - LD Vx, [I] - Read registers V0 through Vx from memory
    starting at location I. '''
    # Read values from memory starting at location I into registers V0
    # through Vx.
    for i in range(self._x + 1):
      self.V[i] = self.read(self.I + i)

  def _op_ldix(self):
    ''' 0xFx55 - LD [I], Vx - Store registers V0 through Vx in memory
    starting at location I. '''
    # Copy values of registers V0 through Vx into memory,
    # starting at the address in I.
    for i in range(self._x + 1):
      self.write(self.V[i], self.I + i)

  def _op_ldb(self):
    # 0xFx33 - LD B, Vx - Store BCD representation of Vx in memory
    # locations I, I + 1, and I + 2.
    # Takes the decimal value of Vx, and places the hundreds
    # digit in memory at location in I, the tens digit at location in I + 1,
    # and the ones digit a location I + 2.
    hundreds = self.V[self._x] // 100 # Integer division.
    tens = (self.V[self._x] - hundreds*100) // 10 # Integer division.
    ones = self.V[self._x] - hundreds*100 - tens*10
    self.memory[self.I] = hundreds
    self.memory[self.I + 1] = tens
    self.memory[self.I + 2] = ones

  def _op_ldf(self):
    # 0xFx29 - LD F, Vx - Set I = location of sprite for digit Vx. In
    # other words I will contain the address of the font character stored
    # in Vx.
    # The value of I is set to the location for the hexadecimal sprite
    # corresponding to the value of Vx.

    # Make sure that Vx is not greater than 15
    self.I = (self.V[self._x] % 16) * 5

  def _op_addi(self):
    # 0xFx1E - Set I = I + Vx.
    # The values of I and Vx are added, and the result is stored in I.
    self.I = (self.I + self.V[self._x]) & 0xFFFF

  def _op_ldst(self):
    # 0xFx18 - Set sound timer = Vx.
    # ST is set equal to the value of Vx.
    self.sound_timer = self.V[self._x]

  def _op_lddt(self):
    # 0xFx15 - Set delay timer = Vx.
    # DT is set equal to the value of Vx.
    self.delay_timer = self.V[self._x]

  def _op_ldvk(self):
    # 0xFx0A - Wait for a key press, store the value of the key in Vx
    # All execution stops until a key is pressed, then the value of that key is
    # stored in Vx.

    # Check for a keypress.
    for i in range(len(self.keyboard)):
      if self.keyboard[i]:
        self.V[self._x] = i
        break;

    # When we get out of the loop above there are two possibilities:
    # 1. The key was pressed, meaning that i is the index into the keyboard
    # list indicating a given key was pressed. In this case everthing
    # that needs to be done was already done.
    # 2. The key was not pressed, meaning that i will be equal to the
    # len(self.keyboard)-1. In this case we need to change the program
    # counter back to its original value and stop all execution.
    if not self.keyboard[i]:
      self.pc = self.pc - 2
      return # Stop all execution.

  def _op_ldv(self):
      # 0xFx07 - LD Vx, DT, Set Vx = delay timer value.
      # The value of DT is placed into Vx.
      self.V[self._x] = self.delay_timer

  def _opE_nest(self):
    self._optblE.setdefault(self._nn, self._unsupported_opcode)()

  def _op_sknp(self):
    # 0xEx9E - SKNP Vx - Skip next instruction if the key with the value of Vx is not pressed.
    # Checksthe keyboard, and if the key corresponding to the value of Vx is currently
    # in the up position, PC is incremented by 2.
    if not self.keyboard[self.V[self._x] % len(self.keyboard)]:
      self.pc = self.pc + 2

  def _op_skp(self):
    # 0xEx9E - SKP Vx - Skip next instruction if the key with the value of Vx is pressed.
    # Checksthe keyboard, and if the key corresponding to the value of Vx is currently
    # in the down position, PC is incremented by 2.
    if self.keyboard[self.V[self._x] % len(self.keyboard)]:
      self.pc = self.pc + 2

  def _op_drw(self):
    # 0xDxyn - DRW Vx, Vy, nibble - Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision
    # The interpreter reads n bytes from memory, starting at the address stored in I. These bytes are then displayed
    # as sprites on screen at coordinates (Vx, Vy). Sprites are XORed onto the existing screen.
    # If this causes any pixels to be erased, VF is set to 1, otherwise it is set to 0.
    # If the sprite is positioned so part of it is outside the coordinates of the display, it wrraps
    # around to the oposite side of the screen. Each bit corresponds to a single pixel.
    self.draw_flag = True # Let the outside world know that display needs to be updated.
    self.V[0xF] = 0
    for yline in range(self._n):
      byte = self.read(self.I + yline)
      for xline in range(8):
        pixel = byte & (0x80 >> xline)
        if 0 != pixel:
          if(1 == self.gfx[(self.V[self._y] + yline) % self.rows][(self.V[self._x] + xline) % self.cols]):
            self.V[0xF] = 1
          self.gfx[(self.V[self._y] + yline) % self.rows][(self.V[self._x] + xline) % self.cols] ^= 1

  def _op_rnd(self):
    # 0xCxkk - RND Vx, byte - Set Vx = random byte AND kk.
    # The interpreter generates a random number from 0 to 255, which is
    # then ANDed with the value kk. The results are stored in Vx.
    random.seed()
    self.V[self._x] = random.randrange(0x100)

    # Check if we are in the test mode and store a copy of V[x] in the
    # V[x + 1].
    if self.test:
      self.V[(self._x + 1) % len(self.V)] = self.V[self._x]
    self.V[self._x] &= self._nn

  def _op_jmpv0(self):
    # 0xBnnn - JP V0, addr - Jump to location nnn + V0.
    # The program counter is set to nnn plus the value of V0.
    self.pc = self.V[0x0] + self._nnn

  def _op_ldi(self):
    # 0xAnnn - LD I, addr - Set I = nnn.
    # The value of register I is set to nnn.
    self.I = self._nnn

  def _op_sner(self):
    # 0x9xy0 - SNE Vx, Vy - Skip next instruction if Vx != Vy.
    if self.V[self._x] != self.V[self._y]:
      self.pc = self.pc + 2

  def _op8_nest(self):
    self._optbl8.setdefault(self._n, self._unsupported_opcode)()

  def _op_shl(self):
    # 0x8xyE - SHL Vx - Shift Vx left by one. Store most significant bit in VF
    self.V[0xF] = self.V[self._x] & 0x80
    self.V[self._x] = (self.V[self._x] << 1) & 0xFF

  def _op_subnr(self):
    # 0x8xy7 - SUBN Vx, Vy - Subract Vx from Vy. Store result in Vx. If Vx > Vy, then set VF to 1.
    self.V[0xF] = 0
    if self.V[self._y] > self.V[self._x]:
      self.V[0xF] = 1
    self.V[self._x] = self.V[self._y] - self.V[self._x]
    self.V[self._x] &= 0xFF

  def _op_shr(self):
    # 0x8xy6 - SHR Vx - Shift Vx right by one. Store least significant bit in VF
    self.V[0xF] = self.V[self._x] & 0x01
    self.V[self._x] = self.V[self._x] >> 1

  def _op_subr(self):
    # 0x8xy5 - Sub Vx, Vy - Subract Vy from Vx. Store result in Vx. If Vx > Vy, then set VF to 1.
    self.V[0xF] = 0
    if self.V[self._x] > self.V[self._y]:
      self.V[0xF] = 1
    self.V[self._x] -= self.V[self._y]
    self.V[self._x] &= 0xFF

  def _op_addr(self):
    # 0x8xy4 - Add Vx, Vy - Add reigisters Vx and Vy. Store result in Vx. If result is > 255, then set VF to 1.
    self.V[self._x] += self.V[self._y]
    self.V[0xF] = 0
    if self.V[self._x] > 0xFF:
      self.V[0xF] = 1
      self.V[self._x] &= 0xFF

  def _op_xorr(self):
      # 0x8xy3 - XOR Vx, Vy - XOR of reigisters Vx and Vy. Store result in Vx.
      self.V[self._x] ^= self.V[self._y]

  def _op_andr(self):
    # 0x8xy2 - AND Vx, Vy - Bitwise and of reigisters Vx and Vy. Store result in Vx.
    self.V[self._x] &= self.V[self._y]

  def _op_orr(self):
    # 0x8xy1 - OR Vx, Vy - Bitwise or of reigisters Vx and Vy. Store result in Vx.
    self.V[self._x] |= self.V[self._y]

  def _op_ldr(self):
    # 0x8xy0 - LD Vx, Vy - Store value of register Vy in register Vx.
    self.V[self._x] = self.V[self._y]

  def _op_add(self):
      # 7xkk - Add Vx, byte - Adds the value kk to the value of register Vx,
      # then stores the result in Vx.
      self.V[self._x] = (self.V[self._x] + self._nn) & 0xFF

  def _op_ld(self):
    # 0x6xkk - LD Vx, byte - Put the value kk into register Vx.
    self.V[self._x] = self._nn

  def _op_sker(self):
    # 5xy0 - SE Vx, Vy Skip next instruction if Vx = Vy.
    # Compare register Vx to register Vy, and if they are equal,
    # increments the program counter by 2.
    if self.V[self._x] == self.V[self._y]:
      # Skip next instruction and go to the one after it.
      self.pc = self.pc + 2

  def _op_skne(self):
    # 0x4xkk - SNE Vx, byte - Skip next instruction if Vx != kk.
    # Compare Vx to kk, and if they are not equal, increment the program counter
    # by 2.
    if self.V[self._x] != self._nn:
      # Skip next instruction and go to the one after it.
      self.pc = self.pc + 2

  def _op_ske(self):
    # 0x3xkk - SE Vx, byte - Skip next instruction if Vx = kk.
    # Compare Vx to kk, and if they are equal, increment the program counter
    # by 2.
    if self.V[self._x] == self._nn:
      # Skip next instruction and go to the one after it.
      self.pc = self.pc + 2

  def _op_call(self):
    # 0x2nnn - CALL addr - call subroutine at nnn.
    # Increment the stack pointer, then put the current PC on the top of
    # the stack. The PC is then set to nnn.
    self._push(self.pc)
    self.pc = self._nnn

  def _op_jmp(self):
    # 0x1nnn - JP addr - jump to location nnn.
    # Set the program counter to nnn.
    self.pc = self._nnn

  def _op0_nest(self):
    self._optbl0.setdefault(self._nn, self._unsupported_opcode)()

  def _op_ret(self):
    # Return from a subroutine.
    self.pc = self._pop()

  def _op_cls(self):
    # Clear the display.
    self.gfx = [[0 for col in range(self.cols)] for row in range(self.rows)]

  def __str__(self):
    mystr = 'pc = 0x{:04X}'.format(self.pc)
    mystr = '{}{}memory[0x{:04X}] = 0x{:02X} memory[0x{:04X}] = 0x{:02X}'.format(
        mystr, ' '*3, self.pc, self.memory[self.pc], self.pc + 1, self.memory[self.pc + 1])
    mystr = '{}\nI  = 0x{:04X}'.format(mystr, self.I)
    mystr = '{}\n'.format(mystr)
    mystr = '{}{}'.format(mystr, ' '*5)
    for i in reversed(range(len(self.V))):
      mystr = '{}{:^4X}|'.format(mystr, i)
    mystr = '{}\n'.format(mystr)
    mystr = '{}V    '.format(mystr)

    for i in reversed(range(len(self.V))):
      mystr = '{}0x{:>02X}|'.format(mystr, self.V[i])

    mystr = '{}\nsp = {}'.format(mystr, self.sp)
    mystr = '{}{}Stack'.format(mystr, ' '*5)

    for i in reversed(range(len(self.stack))):
      mystr = '{}\n{}-- ------\n{}{:>2d}|0x{:04X}'.format(mystr, ' '*12, ' '*12, i, self.stack[i])

    return mystr

  def reset(self):
    self.pc = 0x200 # Program starts at 0x200
    self.I = 0x0000 # Reset index register.
    self.sp = -1 # Reset stack pointer.
    self.test = False # Is the chip in the test mode?
    self.draw_flag = False

    # Reset the keypad. If keypad[x] is True then key x is pressed, otherwise key x is not pressed.
    self.keyboard = [False] * 16

    # Clear display
    self.gfx = [[0 for col in range(type(self).cols)] for row in range(type(self).rows)]

    # Clear stack
    self.stack = [0] * 16

    # Clear registers V0-VF
    self.V = [0] * 16

    # Clear memory
    self.memory = [0] * 4096

    # Reset timers.
    self.delay_timer = 0x0
    self.sound_timer = 0x0

    # Load font set.
    self.memory[0:80] = type(self).font_set[0:80]

  def load_app(self, file_name):
    self.reset()
    with open(file_name, 'rb') as f:
      # Read one byte at a time.
      i = 0
      byte = f.read(1)
      while byte:
        # Copy each byte into chip8 memory.
        # self.write(int.from_bytes(byte, byteorder ='little'), 0x200 + i)
        self.write(struct.unpack('B', byte)[0], 0x200 + i)
        byte = f.read(1)
        i = i + 1

  def emulate_cycle(self):
    # Check the program counter.
    if self.pc >= len(self.memory):
      raise ProgramCounterOutOfRange('pc = {}'.format(self.pc))

    # Check the stack pointer.
    if self.sp < -1 or self.sp >= len(self.stack):
      raise StackPointerOutOfRange('sp = {}'.format(self.spdefaultdict))

    self.draw_flag = False

    # Update timers
    if self.delay_timer > 0:
      self.delay_timer = self.delay_timer - 1

    if self.sound_timer > 0:
      # NOTE: make a sound.
      self.sound_timer = self.sound_timer - 1

    # Fetch opcode
    opcode = (self.memory[self.pc] << 8) | self.memory[self.pc + 1]

    # Update program counter.
    self.pc = self.pc + 2

    # Decode.
    self._nnn = opcode & 0x0FFF
    self._nn  = opcode & 0x00FF
    self._n   = opcode & 0x000F
    self._x   = (opcode & 0x0F00) >> 8
    self._y   = (opcode & 0x00F0) >> 4

    # Execute.
    self._main_optbl.setdefault((opcode & 0xF000) >> 12, self._unsupported_opcode)()

  def print_gfx(self):
    for row in range(self.rows):
      print('{:2}'.format(row), end=': ')
      for col in range(self.cols):
        if self.gfx[row][col]:
          print('*', end='')
        else:
          print(' ', end='')
      print()

  def write_opcode(self, opcode, addr):
    # Make sure opcode is 2 bytes.
    opcode = opcode & 0xFFFF

    # Make sure address is in the 4KB range.
    addr = addr & 0xFFF

    # Make sure that address is even.
    if 0 != addr % 2:
      raise AddressValueIsNotEven('addr = {}'.format(addr))

    if addr < 0x200:
      raise AddressOutOfRange('addr = {}'.format(addr))

    self.memory[addr] = (opcode & 0xFF00) >> 8
    self.memory[addr+1] = (opcode & 0xFF)

  def write(self, byte, addr):
    # Make sure address is in the 4KB range.
    addr = addr & 0xFFF
    self.memory[addr] = byte

  def read_opcode(self, addr):
    # Make sure address is in the 4KB range.
    addr = addr & 0xFFF

    # Make sure that address is even.
    if 0 != addr % 2:
      raise AddressValueIsNotEven('addr = {}'.format(addr))

    return (self.memory[addr] << 8) | (self.memory[addr+1])

  def read(self, addr):
    # Make sure address is in the 4KB range.
    return self.memory[addr & 0xFFF]

  def clear_memory(self):
    self.memory[0x200:len(self.memory)] = [0] * (len(self.memory) - 0x200)

class Block(pygame.sprite.Sprite):
  def __init__(self, row, col, gfx):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.Surface((10, 10)).convert()
    self.image.fill((255, 255, 255))
    self.rect = self.image.get_rect()
    self.rect.left = col*10
    self.rect.top = row*10
    self.row = row
    self.col = col
    self.gfx = gfx

  def update(self):
    if self.gfx[self.row][self.col]:
      self.image.fill((255, 255, 255))
    else:
      self.image.fill((0, 0, 0))

class Emulator:
  def __init__(self):
    self._cpu = Cpu()

  def _press_key(self, key, keyboard, is_down):
    if pygame.K_1 == key:
      self._cpu.keyboard[0x1] = is_down
    elif pygame.K_2 == key:
      self._cpu.keyboard[0x2] = is_down
    elif pygame.K_3 == key:
      self._cpu.keyboard[0x3] = is_down
    elif pygame.K_4 == key:
      self._cpu.keyboard[0xC] = is_down
    elif pygame.K_q == key:
      self._cpu.keyboard[0x4] = is_down
    elif pygame.K_w == key:
      self._cpu.keyboard[0x5] = is_down
    elif pygame.K_e == key:
      self._cpu.keyboard[0x6] = is_down
    elif pygame.K_r == key:
      self._cpu.keyboard[0xD] = is_down
    elif pygame.K_a == key:
      self._cpu.keyboard[0x7] = is_down
    elif pygame.K_s == key:
      self._cpu.keyboard[0x8] = is_down
    elif pygame.K_d == key:
      self._cpu.keyboard[0x9] = is_down
    elif pygame.K_f == key:
      self._cpu.keyboard[0xE] = is_down
    elif pygame.K_z == key:
      self._cpu.keyboard[0xA] = is_down
    elif pygame.K_x == key:
      self._cpu.keyboard[0x0] = is_down
    elif pygame.K_c == key:
      self._cpu.keyboard[0xB] = is_down
    elif pygame.K_v == key:
      self._cpu.keyboard[0xF] = is_down

  def load_app(self, file_name):
    self._cpu.load_app(file_name)

  def run(self):
    # I - Initialize.
    pygame.init()

    # D - Display.
    display = pygame.display.set_mode((640, 320))

    # E - Entities.
    background = pygame.Surface(display.get_size())
    background.fill((0, 0, 0))
    background = background.convert()
    all_sprites = pygame.sprite.Group()
    for row in range(self._cpu.rows):
      for col in range(self._cpu.cols):
        all_sprites.add(Block(row, col, self._cpu.gfx))

    # A - Action.
    clock = pygame.time.Clock()
    keep_going = True

    # A - Assign values.
    # L - Loop.
    while keep_going:

      # T - Timing.
      clock.tick(60) # 60 Frames per second.

      self._cpu.emulate_cycle()

      # E - Events.
      for event in pygame.event.get():
        if pygame.QUIT == event.type:
          keep_going = False
        elif pygame.KEYDOWN == event.type:
          self._press_key(event.key, self._cpu.keyboard, True)
        elif pygame.KEYUP == event.type:
          self._press_key(event.key, self._cpu.keyboard, False)

      # R - Refresh display.
      if self._cpu.draw_flag:
        all_sprites.clear(display, background)
        all_sprites.update()
        all_sprites.draw(display)
        pygame.display.flip()

def main():
  usage = '{} <file name>'.format(__file__)
  if 2 != len(sys.argv):
    print(usage)
    sys.exit()
  emulator = Emulator()
  emulator.load_app(sys.argv[1])
  emulator.run()

if '__main__' == __name__:
  main()


import pandas as pd
from mlxtend.frequent_patterns import apriori, association_rules
data = pd.read_excel("groceries_Full_data.xlsx", header=None)
transactions = []
for i in range(data.shape[0]):
    transaction = data.loc[i].dropna().tolist()
    transactions.append(transaction)
one_hot_encoded_data = pd.get_dummies(pd.DataFrame(transactions).stack(dropna=True)).groupby(level=0).sum()
min_support = 0.01
frequent_itemsets = apriori(one_hot_encoded_data, min_support=min_support, use_colnames=True)
rules = association_rules(frequent_itemsets, metric="support", min_threshold=min_support)
rules_three_items = rules[rules['antecedents'].apply(lambda x: len(x)) == 2]
rules_three_items = rules_three_items.sort_values(by="lift", ascending=False)
print("Frequent itemsets:")
print(frequent_itemsets)
print("\nAssociation rules (3 items purchased together):")
print(rules_three_items)


import sqlite3

import click
from flask import current_app, g
from flask.cli import with_appcontext

def get_db() -> sqlite3.Connection:
    db = g.get("db", None)
    if db is None:
        db = g.db = sqlite3.connect(
            current_app.config['DATABASE'],
            detect_types=sqlite3.PARSE_DECLTYPES
        )
        db.row_factory = sqlite3.Row

    return db

def close_db(e=None) -> None:
    db = g.pop('db', None)

    if db is not None:
        db.close()

def init_db(filename='schema.sql') -> None:
    with current_app.open_resource(filename) as f:
        get_db().executescript(f.read().decode('utf8'))

@click.command('init-db')
@with_appcontext
def init_db_command():
    "Clear the existing data and create new tables."

    init_db()
    click.echo('Initialized the database.')

@click.command('test-db')
@with_appcontext
def test_db_command():
    "Clear the existing data and create new tables with test data."

    init_db()
    init_db("test_data.sql")
    click.echo('Initialized the database.')

@click.command('real-db')
@with_appcontext
def real_db_command():
    "Clear the existing data and create new tables with the real data."

    init_db()
    init_db("real_data.sql")
    click.echo('Initialized the database.')

def init_app(app):
    app.teardown_appcontext(close_db)
    app.cli.add_command(init_db_command)
    app.cli.add_command(test_db_command)
    app.cli.add_command(real_db_command)


import pandas as pd
import numpy as np
import random

def add_reason(df, num):
    df = df[df.label == 0]
    column_feature = df.columns[:-1]
    data = df.values
    data = data[:,:-1]
    data = abs(data)
    reason = ['0']*len(data)
    y_true = np.zeros(len(data))
    outlier = int(0.2*len(data))

    _avg_ = [np.max(data.T[i]) for i in range(len(column_feature))]
    print(_avg_, len(_avg_))
    for i in range(outlier):
        y_true[i] = 1
        loc = random.randint(0, len(column_feature)-1)
        a = 1 + num
        reason[i] = column_feature[loc]
        data[i][loc] = _avg_[loc] * a
    df = pd.DataFrame(data, columns=column_feature)
    df['label'] = y_true
    df['reason'] = reason
    df = df.sample(frac=1.0)
    df = df.reset_index(drop=True)
    return df

import os
if __name__ == '__main__':
    path = "../data/csv"
    for _, _, files in os.walk(path):  # root 根目录，dirs 子目录
        for filename in files:
            if str(filename)[-4:] == '.csv':
            # if str(filename) == 'cardio.csv':
                filepath = path + "/" + str(filename)
                df = pd.read_csv(filepath, engine='python')
                for i in range(2, 10, 2):
                    path_out = '../data/reason/' + filename[:-4] + '_reason' + str(i/10) + '.csv'
                    reason_df = add_reason(df, i/10)
                    reason_df.to_csv(path_out, index=False)


import os
import time as t
import msvcrt as ms
import random as r

mascota=[]
mascotas=[]

#Menú
def menu():
    print("--MENU--\n")
    print("1. Registrar mascota\n2. Listar todos los registros\n3. Buscar mascota\n4. Imprimir reportes\n5. Salir ")
    print("\n---------------")

#Registro
def regm():
    w1=1
    os.system("Cls")
    print("--REGISTRO DE MASCOTAS--\n")
    while w1==1:
        idmascota= input("Ingrese el ID de la mascota\n> ")
        if len(idmascota)==5 and idmascota.isdigit():
            w1=0
            for mascota in mascotas:
                if mascota[0]==idmascota:
                    os.system("Cls")
                    print("--REGISTRO DE MASCOTAS--\n")
                    print("La ID ya existe, ingrese otra.")
                    w1=1
        else:
            os.system("Cls")
            print("--REGISTRO DE MASCOTAS--\n\nIngrese un codigo válido.\n")
    namem= input("Ingrese el nombre de la mascota\n> ")
    namem=namem.capitalize()
    named= input("Ingrese el nombre del dueño\n> ")
    named=named.capitalize()
    op1= (input("La mascota es (P)erro o (G)ato?\n> "))
    if op1=="P" or op1=="p":
        tipom= "Perro"
    elif op1=="G" or op1=="g":
        tipom= "Gato"
    mascota=[idmascota,namem,named,tipom]
    mascotas.append(mascota)
    print("La mascota fue registrada con éxito, presione una tecla para volver al menu.")
    ms.getch()

#Buscador
def buscar(idmascota):
    os.system("Cls")
    print("--BUSCAR MASCOTA--\n")
    i=1
    for mascota in mascotas:
        if mascota[0]==idmascota:
            print(f"ID: {mascota[0]}")
            print(f"Nombre: {mascota[1]}")
            print(f"Dueño: {mascota[2]}")
            print(f"Tipo: {mascota[3]}")
            print("\nPresione una tecla para ingresar otra.")
            ms.getch()
            i=0
    if i==1:
            os.system("Cls")
            print("--BUSCAR MASCOTA--\n")
            print("La ID que escribió no existe, presione una tecla para ingresar otra.\n")
            ms.getch()

#Listado completo
def listar():
    os.system("Cls")
    print("--LISTADO DE MASCOTAS--\n")
    for mascota in mascotas:
        print(f"ID: {mascota[0]}")
        print(f"Nombre: {mascota[1]}")
        print(f"Dueño: {mascota[2]}")
        print(f"Tipo: {mascota[3]}\n")
    print("Presione una tecla para volver al menu. ")
    ms.getch()

#Reporte de perros
def reportesp():
    os.system("Cls")
    print("--REPORTES--\n")
    nump=0
    for mascota in mascotas:
        if mascota[3]=="Perro":
            numr= r.randint(1,10)
            print(f"ID: {mascota[0]}")
            print(f"Nombre: {mascota[1]}")
            print(f"Tipo: {mascota[3]}")
            print(f"\nSr/a {mascota[2]}:\nLe informamos que a su mascota le fantan {numr} vacuna/s.\n-----------\n")
            nump=nump+1
    print(f"El numero de perros registrados es: {nump}\nPresione una tecla para volver al menu. ")
    ms.getch()

#Reporte de gatos
def reportesg():
    os.system("Cls")
    print("--REPORTES--\n")
    numg=0
    for mascota in mascotas:
        if mascota[3]=="Gato":
            numr= r.randint(1,10)
            print(f"ID: {mascota[0]}")
            print(f"Nombre: {mascota[1]}")
            print(f"Tipo: {mascota[3]}")
            print(f"\nSr/a {mascota[2]}:\nLe informamos que a su mascota le fantan {numr} vacuna/s.\n-----------\n")
            numg=numg+1
    print(f"El numero de gatos registrados es: {numg}\nPresione una tecla para volver al menu. ")
    ms.getch()

#MAIN CODE
w2=1
w4=1
while w2==1:
    w3=1
    try:
        os.system("Cls")
        menu()
        op= int(input("Ingrese una opción\n> "))
        if op==1:
            regm()
        elif op==2:
            listar()
        elif op==3:
            while w3==1:
                os.system("Cls")
                print("--BUSCAR MASCOTA--\n")
                idmascota= input("Ingrese el ID de la mascota o 'X' para volver al menu.\n> ")
                if len(idmascota)==5:
                    buscar(idmascota)
                elif idmascota=="X" or idmascota=="x":
                    os.system("Cls")
                    print("--BUSCAR MASCOTA--\n")
                    print("Volverá al menu...")
                    t.sleep(2)
                    w3=0
                else:
                    os.system("Cls")
                    print("--BUSCAR MASCOTA--\n")
                    print("Ingresó una ID no válida, presione una tecla para volver a intentar.")
                    ms.getch()
        elif op==4:
            os.system("Cls")
            print("--REPORTES--\n")
            op2= int(input("¿Para que mascotas desea los reportes?\n1. Perros\n2. Gatos\n> "))
            if op2==1:
                reportesp()
            elif op2==2:
                reportesg()
        elif op==5:
            w2=0
            os.system("Cls")
            print("Hasta luego ;)\n")
            t.sleep(0.5)
    except:
        print("Ha ocurrido un error, presione una tecla para intentar de nuevo.")
        ms.getch()


import math
import sys
import os
import bisect
import time
import csv
from matplotlib import pyplot as plt

input_dir = sys.argv[1]
output_dir = sys.argv[2]
stop_list_filename = 'stoplist.txt'
N = os.listdir(input_dir)   # count of corpus

def readFile(filename):
    file = open(filename, 'r')
    ret = file.read().splitlines()
    file.close()
    return ret

stop_words_list = readFile(stop_list_filename)

# searches a token in stop words list
def binarySearch(token):
    i = bisect.bisect_left(stop_words_list, token)
    return i if (i != len(stop_words_list) and stop_words_list[i] == token) else -1

# pre-processing on tokens in each document
def preProcessing2(file_data):
    pre_processed_hashmap = {}
    # remove remove stopwords, words that occur only once in the entire corpus, and words of length 1
    for i in range(len(file_data)):
        temp = file_data[i].split(" ")
        token, freq = temp[0], int(temp[1])

        if binarySearch(token) != -1 or len(token) == 1 or df_hashmap[token] == 1:
            continue
        pre_processed_hashmap[token] = freq

    return pre_processed_hashmap

# TF-IDF calculation
def calculateTF(pre_processed_hashmap, filename):
    # total tokens in d
    count_tokens_doc = len(pre_processed_hashmap.keys())

    out_filename = os.path.splitext(filename)[0] + ".wts"
    out_path = os.path.join(output_dir, out_filename)
    out = open(out_path, 'w')
    for token, freq in pre_processed_hashmap.items():
        tf = freq / count_tokens_doc
        df = df_hashmap[token]
        n = len(N)
        idf = math.log(n/df)
        tf_idf = tf * idf

        out.write("{} {}\n".format(token, tf_idf))
    out.close()

def calculate_DF_data():
    hm = {}
    for i in range(len(N)):
        filename = N[i]
        file_path = os.path.join(input_dir,filename)
        file_data = readFile(file_path) # file_data contains list of string: "<token> <its frequency>"
        for i in range(len(file_data)):
            temp = file_data[i].split(" ")
            hm[temp[0]] = 1 + hm.get(temp[0], 0)
    return hm

# gloabla hashmap to store count of documents in which a token occurs
df_hashmap = calculate_DF_data()

def start():
    if not os.path.isdir(output_dir):
        os.makedirs(output_dir)
    curr_time, total_time = 0.0, 0.0
    graph_interval = [53,103,153,203,253,303,353,403,453,503]
    graph_dict = {}
    for i in range(len(N)):
        filename = N[i]
        file_path = os.path.join(input_dir,filename)
        file_data = readFile(file_path) # file_data contains list of string: "<token> <its frequency>"

        ## start recording time
        start_time = time.process_time()

        pre_processed_hashmap = preProcessing2(file_data)
        calculateTF(pre_processed_hashmap, filename)

        ## stop time
        stop_time = (time.process_time()) - start_time
        curr_time += stop_time

        ## record time and write it into csv file
        if i+1 == graph_interval[0]:
            total_time += curr_time
            curr_time = 0
            print("CPU time for calculating tf-idf of {} docs: {}".format(i+1,total_time))
            graph_dict[i+1] = round(total_time,4)
            graph_interval.pop(0)

    graphfilename = 'out-graph.csv'
    graphfilepath = os.path.join(graphfilename)
    out = open(graphfilepath,'w')
    for key, value in graph_dict.items():
        out.write("{},{}\n".format(key,value))
    out.close()

    """# Plotting a graph"""
    x, y = [], []
    csvfile = open('out-graph.csv','r')
    lines = csv.reader(csvfile,delimiter=',')
    for row in lines:
        x.append(int(row[0]))
        y.append(float(row[1]))

    plt.plot(x,y,color='g',linestyle='dashed',marker='o',label='execution time')
    plt.xlabel('No. of documents')
    plt.ylabel('Time of execution (seconds)')
    plt.title('CPU execution speed vs No. of documents processed for TF-IDF calulation')
    plt.grid()
    plt.legend()
    plt.savefig('graph.png')
    plt.show()
    plt.close()
    csvfile.close()

if __name__ == "__main__":
    start()

# references : https://towardsdatascience.com/natural-language-processing-feature-engineering-using-tf-idf-e8b9d00e7e76
# https://towardsdatascience.com/tf-idf-for-document-ranking-from-scratch-in-python-on-real-world-dataset-796d339a4089


# -*- coding: utf-8 -*-
from pandas_ta.utils import get_offset, verify_series

def mcgd(close, length=None, offset=None, c=None, **kwargs):
    """Indicator: McGinley Dynamic Indicator"""
    # Validate arguments
    length = int(length) if length and length > 0 else 10
    c = float(c) if c and 0 < c <= 1 else 1
    close = verify_series(close, length)
    offset = get_offset(offset)

    if close is None: return

    # Calculate Result
    close = close.copy()

    def mcg_(series):
        denom = (c * length * (series.iloc[1] / series.iloc[0]) ** 4)
        series.iloc[1] = (series.iloc[0] + ((series.iloc[1] - series.iloc[0]) / denom))
        return series.iloc[1]

    mcg_cell = close[0:].rolling(2, min_periods=2).apply(mcg_, raw=False)
    mcg_ds = close[:1].append(mcg_cell[1:])

    # Offset
    if offset != 0:
        mcg_ds = mcg_ds.shift(offset)

    # Handle fills
    if "fillna" in kwargs:
        mcg_ds.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        mcg_ds.fillna(method=kwargs["fill_method"], inplace=True)

    # Name & Category
    mcg_ds.name = f"MCGD_{length}"
    mcg_ds.category = "overlap"

    return mcg_ds

mcgd.__doc__ = \
"""McGinley Dynamic Indicator

The McGinley Dynamic looks like a moving average line, yet it is actually a
smoothing mechanism for prices that minimizes price separation, price whipsaws,
and hugs prices much more closely. Because of the calculation, the Dynamic Line
speeds up in down markets as it follows prices yet moves more slowly in up
markets. The indicator was designed by John R. McGinley, a Certified Market
Technician and former editor of the Market Technicians Association's Journal
of Technical Analysis.

Sources:
    https://www.investopedia.com/articles/forex/09/mcginley-dynamic-indicator.asp

Calculation:
    Default Inputs:
        length=10
        offset=0
        c=1

    def mcg_(series):
        denom = (constant * length * (series.iloc[1] / series.iloc[0]) ** 4)
        series.iloc[1] = (series.iloc[0] + ((series.iloc[1] - series.iloc[0]) / denom))
        return series.iloc[1]
    mcg_cell = close[0:].rolling(2, min_periods=2).apply(mcg_, raw=False)
    mcg_ds = close[:1].append(mcg_cell[1:])

Args:
    close (pd.Series): Series of 'close's
    length (int): Indicator's period. Default: 10
    offset (int): Number of periods to offset the result. Default: 0
    c (float): Multiplier for the denominator, sometimes set to 0.6. Default: 1

Kwargs:
    fillna (value, optional): pd.DataFrame.fillna(value)
    fill_method (value, optional): Type of fill method

Returns:
    pd.Series: New feature generated.
"""


import numpy as np
from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor

from ..utils import code_to_query, debug_print

VERBOSITY = 0

def base_induction_algorithm(
    data,
    m_codes,
    metadata,
    classifier=DecisionTreeClassifier,
    regressor=DecisionTreeRegressor,
    classifier_kwargs=None,
    regressor_kwargs=None,
):
    """
    Basic induction algorithm. Models according to the m_codes it receives.

    Parameters
    ----------
    data:                   np.ndarray
    m_codes:                np.ndarray
    metadata:               dict
    classifier:
    regressor:
    classifier_kwargs:      dict
    regressor_kwargs:       dict

    Returns
    -------

    """
    assert isinstance(data, np.ndarray)

    # Init
    if classifier_kwargs is None:
        classifier_kwargs = dict()
    if regressor_kwargs is None:
        regressor_kwargs = dict()

    n_rows, n_cols = data.shape
    m_list = []

    attributes = set(range(n_cols))
    nominal_attributes = metadata.get("nominal_attributes")
    numeric_attributes = metadata.get("numeric_attributes")
    msg = """Not all attributes of m_codes are accounted for in metadata"""
    assert not (attributes - nominal_attributes - numeric_attributes), msg

    # Codes to queries
    ids = [(d, t) for d, t, x in [code_to_query(m_code) for m_code in m_codes]]

    for desc_ids, targ_ids in ids:
        msg = """
        Learning model with desc ids:    {}
                            targ ids:    {}
        """.format(
            desc_ids, targ_ids
        )
        debug_print(msg, level=1, V=VERBOSITY)

        if set(targ_ids).issubset(nominal_attributes):
            kwargs = classifier_kwargs
            learner = classifier
            out_kind = "nominal"
        elif set(targ_ids).issubset(numeric_attributes):
            kwargs = regressor_kwargs
            learner = regressor
            out_kind = "numeric"
        else:
            msg = """
            Cannot learn mixed (nominal/numeric) models
            """
            raise ValueError(msg)

        # Learn a model for current desc_ids-targ_ids combo
        m = _learn_model(data, desc_ids, targ_ids, learner, out_kind, **kwargs)
        m_list.append(m)

    return m_list

# Random edit

def _learn_model(data, desc_ids, targ_ids, learner, out_kind="numeric", **kwargs):
    """
    Learn a model from the data.

    The arguments of this function determine specifics on which task,
    which learner etc.

    Model is a machine learning method that has a .fit() method.

    Parameters
    ----------
    data:           np.ndarray
                    The actual input data, all columns
    desc_ids:       set
                    Set of integers identifying the descriptive columns
    targ_ids:       set
                    Set of integers identifying the target columns
    learner:        algorithm
                    Algorithm used for learning a ML-model
    kwargs:         dict
                    Keyword arguments that are passed to ML-algorithm constructor

    Returns
    -------

    """

    i, o = data[:, desc_ids], data[:, targ_ids]

    if i.ndim == 1:
        # We always want 2D inputs
        i = i.reshape(-1, 1)
    if o.shape[1] == 1:
        # If output is single variable, we need 1D matrix
        o = o.ravel()

    try:
        model = learner(**kwargs)
        model.fit(i, o)
    except ValueError as e:
        print(e)

    # Bookkeeping
    model.desc_ids = desc_ids
    model.targ_ids = targ_ids
    model.out_kind = out_kind
    return model


from spinn_utilities.overrides import overrides
from spinn_front_end_common.interface.ds import DataType
from .abstract_synapse_type import AbstractSynapseType
from spynnaker.pyNN.utilities.struct import Struct
from spynnaker.pyNN.data import SpynnakerDataView

EXC_RESPONSE = "exc_response"
EXC_EXP_RESPONSE = "exc_exp_response"
TAU_SYN_E = "tau_syn_E"
INH_RESPONSE = "inh_response"
INH_EXP_RESPONSE = "inh_exp_response"
TAU_SYN_I = "tau_syn_I"
Q_EXC = "q_exc"
Q_INH = "q_inh"
TIMESTEP_MS = "timestep_ms"

class SynapseTypeAlpha(AbstractSynapseType):
    __slots__ = [
        "__exc_exp_response",
        "__exc_response",
        "__inh_exp_response",
        "__inh_response",
        "__tau_syn_E",
        "__tau_syn_I",
        "__q_exc",
        "__q_inh"]

    def __init__(self, exc_response, exc_exp_response,
                 tau_syn_E, inh_response, inh_exp_response, tau_syn_I):
        r"""
        :param exc_response: :math:`response^\mathrm{linear}_e`
        :type exc_response: float or iterable(float) or
            ~spynnaker.pyNN.RandomDistribution or (mapping) function
        :param exc_exp_response: :math:`response^\mathrm{exponential}_e`
        :type exc_exp_response: float or iterable(float) or
            ~spynnaker.pyNN.RandomDistribution or (mapping) function
        :param tau_syn_E: :math:`\tau^{syn}_e`
        :type tau_syn_E: float or iterable(float) or
            ~spynnaker.pyNN.RandomDistribution or (mapping) function
        :param inh_response: :math:`response^\mathrm{linear}_i`
        :type inh_response: float or iterable(float) or
            ~spynnaker.pyNN.RandomDistribution or (mapping) function
        :param inh_exp_response: :math:`response^\mathrm{exponential}_i`
        :type inh_exp_response: float or iterable(float) or
            ~spynnaker.pyNN.RandomDistribution or (mapping) function
        :param tau_syn_I: :math:`\tau^{syn}_i`
        :type tau_syn_I: float or iterable(float) or
            ~spynnaker.pyNN.RandomDistribution or (mapping) function
        """
        super().__init__(
            [Struct([
                (DataType.S1615, EXC_RESPONSE),
                (DataType.S1615, EXC_EXP_RESPONSE),
                (DataType.S1615, Q_EXC),
                (DataType.S1615, TAU_SYN_E),
                (DataType.S1615, INH_RESPONSE),
                (DataType.S1615, INH_EXP_RESPONSE),
                (DataType.S1615, Q_INH),
                (DataType.S1615, TAU_SYN_I),
                (DataType.S1615, TIMESTEP_MS)])],
            {EXC_RESPONSE: "", EXC_EXP_RESPONSE: "", TAU_SYN_E: "ms",
             INH_RESPONSE: "", INH_EXP_RESPONSE: "", TAU_SYN_I: "ms"})

        # pylint: disable=too-many-arguments
        self.__exc_response = exc_response
        self.__exc_exp_response = exc_exp_response
        self.__tau_syn_E = tau_syn_E
        self.__inh_response = inh_response
        self.__inh_exp_response = inh_exp_response
        self.__tau_syn_I = tau_syn_I

    @overrides(AbstractSynapseType.add_parameters)
    def add_parameters(self, parameters):
        parameters[TAU_SYN_E] = self.__tau_syn_E
        parameters[TAU_SYN_I] = self.__tau_syn_I

    @overrides(AbstractSynapseType.add_state_variables)
    def add_state_variables(self, state_variables):
        state_variables[EXC_RESPONSE] = self.__exc_response
        state_variables[EXC_EXP_RESPONSE] = self.__exc_exp_response
        state_variables[Q_EXC] = 0
        state_variables[INH_RESPONSE] = self.__inh_response
        state_variables[INH_EXP_RESPONSE] = self.__inh_exp_response
        state_variables[Q_INH] = 0
        state_variables[TIMESTEP_MS] = (
            SpynnakerDataView.get_simulation_time_step_ms())

    @overrides(AbstractSynapseType.get_n_synapse_types)
    def get_n_synapse_types(self):
        return 2  # EX and IH

    @overrides(AbstractSynapseType.get_synapse_id_by_target)
    def get_synapse_id_by_target(self, target):
        if target == "excitatory":
            return 0
        elif target == "inhibitory":
            return 1
        return None

    @overrides(AbstractSynapseType.get_synapse_targets)
    def get_synapse_targets(self):
        return "excitatory", "inhibitory"

    @property
    def exc_response(self):
        return self.__exc_response

    @exc_response.setter
    def exc_response(self, exc_response):
        self.__exc_response = exc_response

    @property
    def tau_syn_E(self):
        return self.__tau_syn_E

    @property
    def inh_response(self):
        return self.__inh_response

    @property
    def tau_syn_I(self):
        return self.__tau_syn_I


import unittest
from unittest.mock import Mock

from kubekarma.controlleroperator import ResultsReportPublisher
from kubekarma.controlleroperator.core.abc.resultspublisher import \
    IResultsSubscriber

class ResultsReportPublisherTest(unittest.TestCase):

    def test_publisher_behaviour(self):
        publisher = ResultsReportPublisher()
        susb_1 = Mock(spec=IResultsSubscriber)
        susb_2 = Mock(spec=IResultsSubscriber)
        execution_id = "execution_id"
        publisher.add_results_listener(
            execution_id,
            subscriber=susb_1
        )
        publisher.add_results_listener(
            execution_id,
            subscriber=susb_2
        )

        publisher.notify_new_results(
            execution_id,
            results=None
        )
        susb_1.update.assert_called_once_with(None)
        susb_2.update.assert_called_once_with(None)

        publisher.remove_results_listeners(execution_id)

        susb_1.on_delete.assert_called_once_with()
        susb_2.on_delete.assert_called_once_with()

        # Validate that the subscribers are removed and not called anymore
        publisher.notify_new_results(
            execution_id,
            results=True
        )
        susb_1.update.assert_called_once_with(None)
        susb_2.update.assert_called_once_with(None)


"""
Given folder of images and associated JSON label file, this script constructs corresponding class images (where each
colour is associated with a class).
If a region has a class-label 'nan' in the JSON file, then it is recorded in the image as 99 and adds one to the
'white count'.
The JSON file should be in the current working directory
"""

import os
import json
from PIL import Image, ImageDraw

def create_class_images(original_json, out_folder_suffix, data_dir, converter):
    """
    Assumes: all annotations in original_json have a corresponding JPEG image in either data_dir/train or data_dir/val

    Requires:
    - original_json: JSON file containing all annotations
    - out_folder_suffix: string; identifier that will be attached to the train and val folders
    - data_dir: directory containing train and val true-colour images, class image folders will be made here
    - converter: dictionary[string -> int]; maps class names to integer
    """
    # Import annotations
    with open(original_json) as jsonfile:
        labels = json.load(jsonfile)

    # Set folders to save class images to
    train_class_dir = os.path.join(data_dir, 'train_class_images_' + out_folder_suffix)
    if not os.path.exists(train_class_dir):
        os.makedirs(train_class_dir)
    val_class_dir = os.path.join(data_dir, 'val_class_images_' + out_folder_suffix)
    if not os.path.exists(val_class_dir):
        os.makedirs(val_class_dir)

    print(f"Processing: {original_json}...\n"
          f"Processing image number:", end="", flush=True)
    nan_count = 0
    for image_num, image_info in enumerate(labels.values()):
        # print progress
        if (image_num + 1) % 20 == 0:
            print(f"  {image_num + 1}", end="", flush=True)

        filename = image_info['filename']
        if filename in os.listdir(os.path.join(data_dir, 'train')):
            in_filepath = os.path.join(data_dir, 'train', filename)
            out_filepath = os.path.join(train_class_dir, filename)
        elif filename in os.listdir(os.path.join(data_dir, 'val')):
            in_filepath = os.path.join(data_dir, 'val', filename)
            out_filepath = os.path.join(val_class_dir, filename)

        # Get dimensions of original image
        image = Image.open(in_filepath)
        w, h = image.size

        # Construct class image
        class_image = Image.new(mode="P", size=(w, h), color=0)  # every pixel is initialised as black
        class_image1 = ImageDraw.Draw(class_image)
        for regions in image_info['regions']:
            polygon_info = regions['shape_attributes']
            xy = list(zip(polygon_info['all_points_x'], polygon_info['all_points_y']))

            class_name = regions['region_attributes']['label']
            if class_name in converter.keys():
                fill = converter[class_name]
            else:
                nan_count += 1

            class_image1.polygon(xy, fill=fill)

        # Save to disk (with same filename as original image)
        class_image.convert('RGB').save(out_filepath, "JPEG")

    # Print the number of nan entries
    print(f"\nNumber of NAN entries: {nan_count}")

if __name__ == "__main__":
    data_dir = os.path.join(os.getcwd(), "data_aug")

    manual_class_to_colours = {
        'water': 1,
        'vegetation': 2
    }
    create_class_images("manual_annotations_aug.json", "manual", data_dir, manual_class_to_colours)

    MW_class_to_colours = {
        'Artificial Surfaces': 1,
        'Bare or Lightly-vegetated Surfaces': 2,
        'Water Bodies': 3,
        'Cropland': 4,
        'Grassland, Sedgeland and Marshland': 5,
        'Scrub and Shrubland': 6,
        'Forest': 7
    }
#     create_class_images("MW_annotations_aug.json", "MW", data_dir, MW_class_to_colours)