import sys, getopt
try:
    import xmlrpc.client as xmlrpclib # PY3
except ImportError:
    import xmlrpclib # PY2
import os
import platform
try:
    from subprocess import getstatusoutput # PY3
except ImportError:
    from commands import getstatusoutput # PY2
import pprint
import math
import errno
try:
    import json
except ImportError:
    import simplejson as json

import re
import shutil
import glob
from subprocess import Popen, PIPE
from lxml import etree
from procfs import procfs

USAGE_TEXT = """
Usage:  beaker-system-scan [-d] [-j] [[-h <HOSTNAME>] [-S server]]
"""

def get_helper_program_output(program, *args):
    """ Run an external program and return it's output"""
    env = dict(os.environ)
    env['PATH'] = '/usr/libexec/beaker-system-scan:..:.:' + env['PATH']
    proc = Popen([program] + list(args), env=env,
                stdout=PIPE, stderr=PIPE)
    out, err = proc.communicate()
    if proc.returncode:
        raise RuntimeError('Error %s running %s: %s' % (proc.returncode, program, err))
    return out.decode('utf8')

def push_inventory(method, hostname, inventory):
   session = xmlrpclib.Server(lab_server, allow_none=True)
   try:
      resp = getattr(session, method)(hostname, inventory)
      if(resp != 0) :
         raise RuntimeError("ERROR: Pushing Inventory for host %s." % hostname)
   except:
      raise

def check_for_virt_iommu():

    arch = platform.machine()
    virt_iommu = 0

    if arch != 'x86_64':
        #only x86_64 boxes support virt iommu
        return 0

    #test what type of system we are on
    if os.path.exists("/sys/firmware/acpi/tables/DMAR"):
        # alright we are on an Intel vt-d box
        hwu = False
        ba = False

        # iasl can't read directly from /sys
        shutil.copyfile('/sys/firmware/acpi/tables/DMAR', 'DMAR.dat')

        # create ascii file
        os.system("iasl -d DMAR.dat > /dev/null 2>&1")
        if os.path.exists("DMAR.dsl"):
            f = open("DMAR.dsl", 'r')

            #look for keywords to validate ascii file
            hwu_pat = re.compile ('Hardware Unit')
            ba_pat = re.compile ('Base Address')
            ba_inv_pat = re.compile ('0000000000000000|FFFFFFFFFFFFFFFF')

            for line in f.readlines():
                if hwu_pat.search(line):
                    hwu = True
                if ba_pat.search(line):
                    if ba_inv_pat.search(line):
                        sys.stderr.write("VIRT_IOMMU: Invalid Base address: 0's or F's\n")
                    else:
                        ba = True
            if not hwu:
                sys.stderr.write("VIRT_IOMMU: No Hardware Unit\n")
            elif not ba:
                sys.stderr.write("VIRT_IOMMU: No Base Address\n")
            else:
                virt_iommu = 1
        else:
            sys.stderr.write("VIRT_IOMMU: Failed to create DMAR.dsl\n")

    elif os.path.exists("/sys/firmware/acpi/tables/IVRS"):
        # alright we are on an AMD iommu box
        #  we don't have a good way to validate this
        virt_iommu = 1

    return virt_iommu

def kernel_inventory(lshw_tree):
    data = {}
    data['VIRT_IOMMU'] = False

    ##########################################
    # check for virtual iommu/vt-d capability
    # if this passes, assume we pick up sr-iov for free

    if check_for_virt_iommu():
        data['VIRT_IOMMU'] = True

    ##########################################
    # DISK_CONTROLLER is the kernel driver of the device (e.g. PCI SCSI
    # controller card) to which the first hard disk is attached.
    disk_controller = lshw_tree.xpath(
            '//node[node/@id="disk" or node/@id="disk:0"]'
            '/configuration/setting[@id="driver"]/@value')
    if disk_controller:
        data['DISK_CONTROLLER'] = str(disk_controller[0])

    ##########################################
    # determine if machine is using multipath or not

    #ok, I am really lazy
    #remove the default blacklist in /etc/multipath.conf
    if os.path.exists('/etc/multipath.conf'):
        os.system("sed -i '/^blacklist/,/^}$/d' /etc/multipath.conf")
        #restart multipathd to see what it detects
        #this spits out errors if the root device is on a
        #multipath device, I guess ignore for now and hope the code
        #correctly figures things out
        os.system("service multipathd restart > /dev/null")
        #the multipath commands will display the topology if it
        #exists otherwise nothing
        #filter out vbds and single device paths
        status, mpaths = getstatusoutput("multipath -ll")
        mp = False
        if status:
            sys.stderr.write("MULTIPATH: multipath -ll failed with %d\n")
        else:
            count = 0
            mpath_pat = re.compile(" dm-[0-9]* ")
            sd_pat = re.compile(" sd[a-z]")
            for line in mpaths.split('\n'):
                #reset when a new section starts
                if mpath_pat.search(line):
                    # found at least one mp instance, declare success
                    if count > 1:
                        mp = True
                        break
                    count = 0

                #a hit! increment to indicate this
                if sd_pat.search(line):
                    count = count + 1

        if mp == True:
            data['DISK_MULTIPATH'] = True
        else:
            data['DISK_MULTIPATH'] = False

    return data

def legacy_inventory(inv):
    # Take the gathered inventory data, fill legacy key/value schema with it
    # and gather any missing bits.
    data = {}
    data['MODULE'] = []
    data['HVM'] = False
    data['DISK'] = []
    data['BOOTDISK'] = []
    data['DISKSPACE'] = 0
    data['NR_DISKS'] = 0
    data['NR_ETH'] = 0
    data['NR_IB'] = 0

    data['ARCH'] = inv['Arch'][0]
    if inv['Cpu']['family']:
        data['CPUFAMILY'] = inv['Cpu']['family']
    data['CPUVENDOR'] = inv['Cpu']['vendor']
    data['CPUMODEL'] = inv['Cpu']['modelName']
    if inv['Cpu']['model']:
        data['CPUMODELNUMBER'] = inv['Cpu']['model']
    data['PROCESSORS'] = inv['Cpu']['processors']
    data['VENDOR'] = inv['vendor']
    data['MODEL'] = inv['model']
    data['FORMFACTOR'] = inv['formfactor']
    data['CPUFLAGS'] = inv['Cpu']['CpuFlags']
    data['PCIID'] = ["%s:%s" % (d['vendorID'], d['deviceID'])
            for d in inv['Devices'] if d['bus'] == 'pci' and
                (d['vendorID'] != '0000' or d['deviceID'] != '0000')]
    data['USBID'] = ["%s:%s" % (d['vendorID'], d['deviceID'])
            for d in inv['Devices'] if d['bus'] == 'usb' and
                (d['vendorID'] != '0000' or d['deviceID'] != '0000')]

    # The below data (and kernel_inventory()) has not (yet) made it to the new schema
    # (and formfactor above)

    modules = getstatusoutput('/sbin/lsmod')[1].split('\n')[1:]
    for module in modules:
        data['MODULE'].append(module.split()[0])

    # Find Active Storage Driver(s)
    bootdisk = None
    bootregex = re.compile(r'/dev/([^ ]+) on /boot')
    disks = getstatusoutput('/bin/mount')[1].split('\n')[1:]
    for disk in disks:
        if bootregex.search(disk):
            # Replace / with !, needed for cciss
            bootdisk = bootregex.search(disk).group(1).replace('/','!')

    if bootdisk:
        try:
            drivers = get_helper_program_output('getdriver.sh', bootdisk).split('\n')[1:]
        except RuntimeError:
            # /boot might be on a device-mapper device, but getdriver.sh
            # doesn't handle those properly. We don't care much about
            # BOOTDISK though so just ignore failures.
            pass
        else:
            for driver in drivers:
                data['BOOTDISK'].append(driver)
    # Find Active Network interface
    iface = None
    for line in getstatusoutput('route -n')[1].split('\n'):
        if line.find('0.0.0.0') == 0:
            iface = line.split()[-1:][0] #eth0, eth1, etc..
    if iface:
        drivers = get_helper_program_output('getdriver.sh', iface).split('\n')
        if len(drivers) == 1:
            data['NETWORK'] = drivers[0]
        else:
            data['NETWORK'] = drivers[1:][0]

    # disk sizes are converted to MiB in key-values for backwards compatibility
    data['DISK'] = [int(d['size']) // 1024**2 for d in inv['Disk']['Disks']]
    data['DISKSPACE'] = sum(int(d['size']) for d in inv['Disk']['Disks']) // 1024**2
    data['NR_DISKS'] = len(data['DISK'])

    # constants from include/linux/if_arp.h
    ETH_TYPE = 1
    IB_TYPE = 32
    # finding out eth and ib interfaces...
    interfaces = os.listdir('/sys/class/net')
    for iface in interfaces:
        iface_path = os.path.join('/sys/class/net', iface)

        # skip if path is not a dir as later we rely on files inside it
        if not os.path.isdir(iface_path):
            continue

        # don't count virtual devices (lo, bridge)
        if (os.path.islink(iface_path) and 'virtual' in os.readlink(iface_path)):
            continue

        # don't count wifi devices
        if os.path.exists(os.path.join(iface_path, 'phy80211')):
            continue

        with open(os.path.join(iface_path, 'type')) as type_file:
            int_type = int(type_file.readline())
            if int_type == ETH_TYPE:
                data['NR_ETH'] += 1
            if int_type == IB_TYPE:
                data['NR_IB'] += 1

    # checking for whether or not the machine is hvm-enabled.
    caps = ""
    if os.path.exists("/sys/module/kvm_amd") or \
       os.path.exists("/sys/module/kvm_intel"):
           data['HVM'] = True
    elif os.path.exists('/sys/module/kvm_hv'): # ppc64
        data['HVM'] = True
    elif os.path.exists('/proc/pal/cpu0/processor_info'): # ia64
        for line in open('/proc/pal/cpu0/processor_info', 'r'):
            if re.match('Virtual machine features.*: On', line):
                data['HVM'] = True

    if os.path.exists("/root/NETBOOT_METHOD.TXT"):
        data['NETBOOT_METHOD'] = open('/root/NETBOOT_METHOD.TXT', 'r').readline()[:-1]
    return data

def read_inventory(inventory, arch = None, proc_cpuinfo='/proc/cpuinfo'):

    data = {}
    flags = []
    data['Devices'] = []
    cpu = None

    procCpu  = procfs.cpuinfo(filename=proc_cpuinfo)

    #Break the xml into the relevant sets of data
    cpuinfo = inventory.xpath(".//node[@class='processor']")[0]
    memory_elems = inventory.xpath(".//node[@class='memory']")
    memoryinfo = None
    for m in memory_elems:
       desc = m.find('description')
       if desc is not None and desc.text.lower() == 'system memory':
          memoryinfo = m

    devices = inventory.xpath(".//node[@id!='subsystem']")
    capabilities = cpuinfo.find('capabilities')
    if capabilities is not None:
       for capability in capabilities.getchildren():
          flags.append(capability.get('id'))

    if not arch:
       arch = os.uname()[4]

    # BZ 1213685
    if arch in ['i486', 'i586', 'i686']:
        arch = 'i386'

    if arch in ['i386', 'x86-64', "x86_64"]:
       vendor = cpuinfo.find('vendor')
       if vendor is not None:
          vendor = vendor.text
       #rhbz: 1212284
       if vendor == 'Intel Corp.':
           vendor = 'GenuineIntel'
       if vendor == 'Advanced Micro Devices [AMD]':
           vendor = 'AuthenticAMD'
       modelName = cpuinfo.find('product')
       if modelName is not None:
          modelName = modelName.text

       #https://bugzilla.redhat.com/show_bug.cgi?id=1212281
       try:
           idx = flags.index('x86-64')
       except ValueError:
           pass
       else:
           flags[idx] = 'lm'
       cpu = dict(vendor     = vendor,
                  model      = int(procCpu.tags['model']),
                  modelName  = modelName,
                  speed      = float(procCpu.tags['cpu mhz']),
                  processors = int(procCpu.nr_cpus),
                  cores      = int(procCpu.nr_cores),
                  sockets    = int(procCpu.nr_sockets),
                  CpuFlags   = flags,
                  family     = int(procCpu.tags['cpu family']),
                  stepping   = int(procCpu.tags['stepping']),
       )
    elif arch in ["ppc", "ppc64", "ppc64le"]:
       cpu = dict(vendor     = "IBM",
                  model      = int(''.join(re.split('^.*([0-9a-f]{4})\s([0-9a-f]{4}).*$',
                                                    procCpu.tags['revision'])), 16),
                  modelName  = str(procCpu.tags['cpu']),
                  speed      = float(re.findall('\d+.+\d+', procCpu.tags['clock'])[0]),
                  processors = int(procCpu.nr_cpus),
                  cores      = 0,
                  sockets    = 0,
                  CpuFlags   = flags,
                  family     = 0,
                  stepping   = 0,
               )
    elif arch in ["s390", "s390x"]:
       for cpuflag in procCpu.tags['features'].split(" "):
          flags.append(cpuflag)
       proc = dict([tuple(s.strip() for s in kv.split('=')) for kv in procCpu.tags['processor 0'].split(',')])
       cpu = dict(vendor     = str(procCpu.tags['vendor_id']),
                  model      = int(proc['identification'], 16),
                  modelName  = str(proc['machine']),
                  processors = int(procCpu.tags['# processors']),
                  cores      = 0,
                  sockets    = 0,
                  CpuFlags   = list(set(flags)),
                  family     = 0,
                  speed      = 0,
                  stepping   = 0,
       )
    elif arch == "ia64":
       for cpuflag in procCpu.tags['features'].split(","):
          flags.append(cpuflag.strip())
       vendor = cpuinfo.find('vendor')
       if vendor is not None:
          vendor = vendor.text
          if vendor == 'Intel Corp.':
            vendor = 'GenuineIntel'
       product = cpuinfo.find('product')
       if product is not None:
          product = product.text
       cpu = dict(vendor     = vendor,
                  model      = int(procCpu.tags['model']),
                  modelName  = product,
                  speed      = float(procCpu.tags['cpu mhz']),
                  processors = int(procCpu.nr_cpus),
                  cores      = int(procCpu.nr_cores),
                  sockets    = int(procCpu.nr_sockets),
                  # As the cpu flags are retrieved from /proc/cpuinfo and lshw,
                  # we need to remove duplicate flags if they are exist.
                  CpuFlags   = list(set(flags)),
                  # bz1212307: smolt is using revision for family
                  family     = int(procCpu.tags['revision']),
                  stepping   = 0,
               )

    elif arch == 'aarch64':
        # count logical CPUs
        n_procs = 0
        f = open(proc_cpuinfo)
        for line in f:
            if line.startswith('processor'):
                n_procs += 1
        f.close()
        # count CPU cores
        n_cores = 0
        for cpu in inventory.findall('.//node[@class="processor"]'):
            cores_setting = cpu.find('configuration/setting[@id="cores"]')
            if cores_setting is not None:
                n_cores += int(cores_setting.get('value'))
            else:
                n_cores += 1
        # count physical CPUs
        n_sockets = len(inventory.findall('.//node[@class="processor"]'))

        cpu = dict(vendor     = cpuinfo.findtext('vendor'),
                   modelName  = cpuinfo.findtext('product'),
                   speed      = float(cpuinfo.findtext('capacity') or 0) / 1000000,
                   processors = n_procs,
                   cores      = n_cores,
                   sockets    = n_sockets,
                   CpuFlags   = flags,
                   # Beaker's data model assumes model/family/stepping are
                   # integers, as in the x86 world, so we can't store anything
                   # useful in them here.
                   model      = None,
                   family     = None,
                   stepping   = None,
               )

    sysinfo = inventory.xpath(".//node[@class='system']")[0]
    vendor = sysinfo.find('vendor')
    product = sysinfo.find('product')
    memsize = memoryinfo.find('size')
    if vendor is not None:
       vendor = vendor.text
    if product is not None:
       product = product.text
    if memsize is not None:
       memsize = int(memsize.text) // 1024**2

    data['Cpu'] = cpu
    data['Arch'] = [arch]
    data['vendor'] = vendor
    data['model'] = product
    data['memory'] = memsize

    disklist = []
    for disk in inventory.xpath('.//node[@class="disk" and @id!="medium"]'):
        diskinfo = {}
        if disk.find('size') is None:
            continue # probably an optical drive
        # need to send size as an XML-RPC string as it is likely to overflow
        # the 32-bit size limit for XML-RPC ints
        diskinfo['size'] = disk.findtext('size')
        diskinfo['model'] = disk.findtext('product')
        logicalsectorsize = disk.find('configuration/setting[@id="logicalsectorsize"]')
        if logicalsectorsize is not None:
            diskinfo['sector_size'] = int(logicalsectorsize.get('value'))
        else:
            diskinfo['sector_size'] = 512
        sectorsize = disk.find('configuration/setting[@id="sectorsize"]')
        if sectorsize is not None:
            diskinfo['phys_sector_size'] = int(sectorsize.get('value'))
        else:
            diskinfo['phys_sector_size'] = diskinfo['sector_size']
        disklist.append(diskinfo)
    data['Disk'] = {'Disks': disklist}
    data['Numa'] = {
        'nodes': len(glob.glob('/sys/devices/system/node/node*')), #: number of NUMA nodes in the system, or 0 if not supported
    }
    # default
    data['formfactor'] = ''
    chassis = sysinfo.xpath('//configuration/setting[@id="chassis"]')
    if len(chassis) > 0:
        data['formfactor'] = chassis[0].get('value')
    try:
        hypervisor = get_helper_program_output('hvm_detect')
    except OSError as e:
        if e.errno == errno.ENOENT and arch != 'x86_64':
            pass
        else:
            raise
    else:
        hvm_map = {"No KVM or Xen HVM\n"    : None,
                   "KVM guest.\n"           : 'KVM',
                   "Xen HVM guest.\n"       : 'Xen',
                   "Microsoft Hv guest.\n"  : 'HyperV',
                   "VMWare guest.\n"        : 'VMWare',
                }
        data['Hypervisor'] = hvm_map[hypervisor]

    for device in devices:
        # Defaults for nonexistent values
        description = driver = bus = device_class = "Unknown"
        vendorID = deviceID = subsysVendorID = subsysDeviceID = "0000"
        firmware = None

        if device.findtext('product'):
            description = device.findtext('product')
        elif device.findtext('description'):
            description = device.findtext('description')

        usbvendornode = device.find('hints/hint[@name="usb.idVendor"]')
        if usbvendornode is not None:
            vendorID = '%04x' % int(usbvendornode.get('value'), 16)
        usbproductnode = device.find('hints/hint[@name="usb.idProduct"]')
        if usbproductnode is not None:
            deviceID = '%04x' % int(usbproductnode.get('value'), 16)
        pcivendornode = device.find('hints/hint[@name="pci.vendor"]')
        if pcivendornode is not None:
            vendorID = '%04x' % int(pcivendornode.get('value'), 16)
        pcidevicenode = device.find('hints/hint[@name="pci.device"]')
        if pcidevicenode is not None:
            deviceID = '%04x' % int(pcidevicenode.get('value'), 16)
        pcisubvendornode = device.find('hints/hint[@name="pci.subvendor"]')
        if pcisubvendornode is not None:
            subsysVendorID = '%04x' % int(pcisubvendornode.get('value'), 16)
        pcisubdevicenode = device.find('hints/hint[@name="pci.subdevice"]')
        if pcisubdevicenode is not None:
            subsysDeviceID = '%04x' % int(pcisubdevicenode.get('value'), 16)

        if device.find('businfo') is not None:
            bus = device.find('businfo').text.split('@')[0]
        elif device.find('capabilities/capability[@id="pnp"]') is not None:
            bus = 'pnp'

        if device.get('class') is not None:
            device_class = device.get('class')
        # Virtio mem balloon is not memory (RHBZ#1249462)
        if description == 'Virtio memory balloon':
            device_class = 'generic'

        drivernode = device.find('configuration/setting[@id="driver"]')
        if drivernode is not None:
            driver = drivernode.get('value')

        # We report these separately
        if device_class in ['memory', 'processor', 'disk']:
            continue
        # The system itself is not a device
        if device_class == 'system':
            continue
        # Add firmware information to device table
        firmwarenode = device.find('configuration/setting[@id="firmware"]')
        if firmwarenode is not None:
            firmware = firmwarenode.get('value')
        # System firmware is a special case
        if device.get('id') == 'core':
            firmwarenode = device.find('.//node[@id="firmware"]')
            if firmwarenode is not None:
                description = firmwarenode.findtext('description')
                firmware = firmwarenode.findtext('version')
        # Volumes/partitions are transient
        if device_class == 'volume':
            continue
        # If none of these have any useful information, skip it
        if description == 'Unknown' and driver == 'Unknown' and vendorID == '0000' and \
           deviceID == '0000' and subsysDeviceID == '0000' and subsysVendorID == '0000':
            continue

        # Map lshw device classes to smolt-compatible device types
        # https://git.fedorahosted.org/cgit/smolt.git/tree/client/smolt.py#n1015
        device_type = device_class.upper()
        if device_class == 'storage':
            if device.xpath('./capabilities/capability[@id="scsi"]'):
                device_type = 'SCSI'
            if device.xpath('./capabilities/capability[@id="ide"]'):
                device_type = 'IDE'
            if device.xpath('./capabilities/capability[@id="raid"]'):
                device_type = 'RAID'
            if device.xpath('./capabilities/capability[@id="sata"]'):
                device_type = 'SATA'
            if device.xpath('./capabilities/capability[@id="sas"]'):
                device_type = 'SAS'
        elif device_class == 'bus':
            if device.xpath('./hints/hint[@name="icon" and @value="usb"]'):
                device_type = 'USB'
            if device.xpath('./hints/hint[@name="icon" and @value="firewire"]'):
                device_type = 'FIREWIRE'
        elif device_class == 'communication':
            if device.xpath('./hints/hint[@name="icon" and @value="modem"]'):
                device_type = 'MODEM'
        elif device_class == 'display':
            device_type = 'VIDEO'
        elif device_class == 'multimedia':
            device_type = 'AUDIO'

        data['Devices'].append(dict( vendorID = vendorID,
                                     deviceID = deviceID,
                                     subsysVendorID = subsysVendorID,
                                     subsysDeviceID = subsysDeviceID,
                                     bus = bus,
                                     driver = driver,
                                     type = device_type,
                                     description = description,
                                     fw_version = firmware))

    return data

def usage():
    print(USAGE_TEXT)
    sys.exit(-1)

def main():
    global lab_server, hostname

    lab_server = None
    hostname = None
    debug = 0
    json_output = 0

    if 'LAB_SERVER' in os.environ:
        lab_server = os.environ['LAB_SERVER']
    if 'HOSTNAME' in os.environ:
        hostname = os.environ['HOSTNAME']

    args = sys.argv[1:]
    try:
        opts, args = getopt.getopt(args, 'dh:S:j', ['server='])
    except:
        usage()
    for opt, val in opts:
        if opt in ('-d', '--debug'):
            debug = 1
        if opt in ('-j', '--json') and debug:
            json_output = 1
        if opt in ('-h', '--hostname'):
            hostname = val
        if opt in ('-S', '--server'):
            lab_server = val

    lshw_xml = Popen(['lshw', '-xml'], stdout=PIPE).communicate()[0]
    lshw_tree = etree.XML(lshw_xml)
    inventory = read_inventory(lshw_tree)
    legacy_inv = legacy_inventory(inventory)
    legacy_inv.update(kernel_inventory(lshw_tree))
    del inventory['formfactor']
    if debug:
       if json_output:
          print(json.dumps({'legacy':legacy_inv,
                            'Data':inventory}))
       else:
          print("Legacy inventory:\n%s\nData:\n%s" % (
             pprint.pformat(legacy_inv), pprint.pformat(inventory)))
    else:
        if not hostname:
            print("You must specify a hostname with the -h switch")
            sys.exit(1)

        if not lab_server:
            print("You must specify a lab_server with the -S switch")
            sys.exit(1)

        push_inventory("legacypush", hostname, legacy_inv)
        push_inventory("push", hostname, inventory)

if __name__ == '__main__':
    main()
    sys.exit(0)


from flask import Flask, request, render_template
import MySQLdb

import config

app = Flask(__name__)
sphinx_connection = MySQLdb.connect(host=config.SPHINX_HOST, port=config.SPHINX_PORT)

def get_address(text: str, limit: int = 20):
    c = sphinx_connection.cursor()
    c.execute(f"SELECT address_name FROM address WHERE match('*{text}*') LIMIT {limit}")
    return [adr[0] for adr in c.fetchall()]

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/search')
def find():
    addr = request.args.get('addr', '')
    limit = request.args.get('limit', 20)
    return get_address(addr, limit)

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


import  pygame, random, sys
from pygame.locals import *

WINDOWWIDTH = 600
WINDOWHEIGTH = 600
TEXTCOLOR = (0,0,0)
BACKGROUNDCOLOR = (255,255,255)
FPS = 60
BADDIEMINSIZE = 10
BADDIEMAXSIZE = 40
BADDIEMINSPEED = 1
BADDIEMAXSPEED = 8
ADDNEWBADDIERATE = 6
PLAYERMOVERATE = 5

def terminate():
    pygame.quit()
    sys.exit()

def waitForPlayerToPressKey():
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE: # нажатие эскейп осуществляет выход
                    terminate()
                return

def playerHasHitBaddie(playerRect, baddies):
    for b in baddies:
        if playerRect.colliderect(b['rect']):
            return  True
    return False

def drawText(text, font, surface, x, y):
    textobj = font.render(text, 1, TEXTCOLOR)
    textrect = textobj.get_rect()
    textrect.topleft = (x, y)
    surface.blit(textobj, textrect)

# настройки pygame окна и указателя мыши
pygame.init()
mainClock = pygame.time.Clock()
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGTH))
pygame.display.set_caption('Ловкач')
pygame.mouse.set_visible(False)

# настройка шрифтов
font = pygame.font.SysFont(None, 35)

#настройка звуков
gameOverSound = pygame.mixer.Sound('gameover.wav')
pygame.mixer.music.load('background.mid')

#настройка изображений
playerImage = pygame.image.load('player.png')
playerRect =playerImage.get_rect()
baddieImage = pygame.image.load('baddie.png')

# вывод начального экрана
windowSurface.fill(BACKGROUNDCOLOR)
drawText('Ловкач', font, windowSurface,(WINDOWWIDTH/3), (WINDOWHEIGTH/3))
drawText('Нажмите клавиатуру для начала игры', font, windowSurface, (WINDOWWIDTH/5)-30, (WINDOWHEIGTH/3)+50)
pygame.display.update()
waitForPlayerToPressKey()

topScore = 0
while True:
    #Настройка начала игры
    baddies = []
    score = 0
    playerRect.topleft = (WINDOWWIDTH/0, WINDOWHEIGTH-50)
    moveLeft = moveRight = moveUp = moveDown = False
    reversCheat = slowCheat = False
    baddieAddCounter = 0
    pygame.mixer.music.play(-1,0.0)

    while True: #игровой цикл выполняется пока игра работает
        score += 1 # увеличение колличества очков

        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()


"""Compare speed of different aggregation algorithms."""

import torch
from pytest import mark
from torch import Tensor, jit

def square_norm(x: Tensor) -> Tensor:
    """Manual Square norm."""
    return (x**2).sum()

aggregations = {
    "norm2-mul-sum": lambda x: x.mul(x).sum(),
    "norm2-pow2-sum": lambda x: x.pow(2).sum(),
    "norm2-jit": jit.script(square_norm),
    "norm2-einsum": lambda x: torch.einsum("..., ... -> ", x, x),
}

@mark.parametrize("name", aggregations)
@mark.benchmark
class TestAggregation:
    """Compare speed of different aggregation algorithms."""

    small = torch.randn(100)
    medium = torch.randn(1000)
    large = torch.randn(10_000)
    xlarge = torch.randn(100_000)
    xxlarge = torch.randn(1_000_000)
    xxxlarge = torch.randn(10_000_000)

    def test_small(self, benchmark, name):
        func = aggregations[name]
        benchmark(func, self.small)

    def test_medium(self, benchmark, name):
        func = aggregations[name]
        benchmark(func, self.medium)

    def test_large(self, benchmark, name):
        func = aggregations[name]
        benchmark(func, self.large)

    def test_xlarge(self, benchmark, name):
        func = aggregations[name]
        benchmark(func, self.xlarge)

    def test_xxlarge(self, benchmark, name):
        func = aggregations[name]
        benchmark(func, self.xxlarge)

    def test_xxxlarge(self, benchmark, name):
        func = aggregations[name]
        benchmark(func, self.xxxlarge)

#
# @mark.parametrize("size", [10, 100, 1000, 10000])
# @mark.parametrize("name", aggregations)
# @mark.benchmark(group_by="name")
# def test_speed(benchmark, name: str, size: int) -> None:
#     """Compare speed of different aggregation algorithms."""
#     func = aggregations[name]
#     x = torch.randn(size)
#     benchmark(func, x)


import os
import copy
import sys
import random
import gc
import datetime
sys.path.append(os.path.abspath('..'))
from COLD.predictor import predictor as COLDPredictor
from CTCD.ber_predictor import predictor as CTCDBerPredictor
from CTCD.poi_predictor import predictor as CTCDPoiPredictor
from BIGCLAM.predictor import predictor as BIGCLAMPredictor

def mkdir_if_not_exists(path):
    if not os.path.exists(path):
        os.makedirs(path)

def load_edges(data_dir, predictor):
    edges = []
    user_pair = set()
    for line in open(os.path.join(data_dir, 'links.txt')):
        line = line.strip().split('\t')
        if line[0] not in predictor.uname2uid:
            continue
        if line[1] not in predictor.uname2uid:
            continue
        uid0 = predictor.uname2uid[line[0]]
        uid1 = predictor.uname2uid[line[1]]
        user_pair.add((uid0, uid1))
        for time_pair in line[2:]:
            time_pair = time_pair.split()
            edges.append((uid0, uid1, int(time_pair[0]), int(time_pair[1])))
    max_time = max(i for edge in edges for i in edge[-2:]) + 1
    min_time = min(i for edge in edges for i in edge[-2:]) - 1
    for i in range(len(edges)):
        edge = edges[i]
        edges[i] = (edge[0], edge[1], (edge[2] - min_time) / (max_time - min_time), (edge[3] - min_time) / (max_time - min_time))
    return user_pair, edges

def prdict_pos(predictor, edges, num):
    scores = []
    count = 0
    for edge in random.sample(edges, num):
        if count % 100000 == 0:
            print(datetime.datetime.now(), 'pos: ', count)
            sys.stdout.flush()
        count += 1
        scores.append(predictor.link_predict(*edge))
    return scores

def prdict_neg(predictor, user_pair, num):
    scores = []
    for i in range(num):
        if i % 100000 == 0:
            print(datetime.datetime.now(), 'neg: ', i)
            sys.stdout.flush()
        while True:
            from_user = random.randint(0, len(predictor.uname2uid) - 1)
            to_user = random.randint(0, len(predictor.uname2uid) - 1)
            if (from_user, to_user) not in user_pair:
                break
        time1 = random.random()
        time2 = random.random()
        scores.append(predictor.link_predict(from_user, to_user, time1, time2))
    return scores

def load_data(args):
    model2predictor = {
        'CTCDPoi': ctcd_poi_predictor,
        'CTCDBer': ctcd_ber_predictor,
        'COLD': cold_predictor,
        'BIGCLAM': bigclam_predictor,
    }
    predictor = model2predictor[args['model']]
    data_dir = '{root:s}/Data/{exp:s}/{dataset:s}/'.format(**args)
    predictor.load_data(data_dir)

def prdict(args):
    print(datetime.datetime.now(), args)
    sys.stdout.flush()
    model2predictor = {
        'CTCDPoi': ctcd_poi_predictor,
        'CTCDBer': ctcd_ber_predictor,
        'COLD': cold_predictor,
        'BIGCLAM': bigclam_predictor,
    }
    model2score_prefix = {
        'CTCDPoi': '{root:s}/Score/{exp:s}/{dataset:s}/{model:s}/cc{cc:d}_lw{lw:d}_{it:s}',
        'CTCDBer': '{root:s}/Score/{exp:s}/{dataset:s}/{model:s}/cc{cc:d}_lw{lw:d}_{it:s}',
        'COLD': '{root:s}/Score/{exp:s}/{dataset:s}/{model:s}/cc{cc:d}_lw{lw:d}_{it:s}',
        'BIGCLAM': '{root:s}/Score/{exp:s}/{dataset:s}/{model:s}/cc{cc:d}_lw{lw:d}',
    }
    args['score_prefix'] = model2score_prefix[args['model']].format(**args)
    mkdir_if_not_exists(os.path.split(args['score_prefix'])[0])
    model2result_prefix = {
        'CTCDPoi': '{root:s}/Result/{exp:s}/{dataset:s}/{model:s}/cc{cc:d}_lw{lw:d}_{it:s}',
        'CTCDBer': '{root:s}/Result/{exp:s}/{dataset:s}/{model:s}/cc{cc:d}_lw{lw:d}_{it:s}',
        'COLD': '{root:s}/Result/{exp:s}/{dataset:s}/{model:s}/cc{cc:d}_lw{lw:d}_{it:s}',
        'BIGCLAM': '{root:s}/Result/{exp:s}/{dataset:s}/{model:s}/cc{cc:d}_lw{lw:d}',
    }
    args['data_dir'] = '{root:s}/Data/{exp:s}/{dataset:s}/'.format(**args)
    args['result_prefix'] = model2result_prefix[args['model']].format(**args)
    if os.path.isfile(args['score_prefix'] + '.txt'):
        return
    predictor = model2predictor[args['model']]

    predictor.load_result(args['result_prefix'])
    print(datetime.datetime.now(), 'predictor init done')
    sys.stdout.flush()

    user_pair, edges = load_edges(args['data_dir'], predictor)
    print(datetime.datetime.now(), 'load edges done')
    sys.stdout.flush()

    score_pos = prdict_pos(predictor, edges, int(len(edges) * 0.1))
    print(datetime.datetime.now(), 'predict pos done')
    sys.stdout.flush()

    score_neg = prdict_neg(predictor, user_pair, int(len(edges) * 0.1))
    print(datetime.datetime.now(), 'predict neg done')
    sys.stdout.flush()

    fp = open(args['score_prefix'] + '.txt', 'w')
    for score in score_pos:
        fp.write('%f\t1\n' % score)
    print(datetime.datetime.now(), 'save pos done')
    sys.stdout.flush()

    for score in score_neg:
        fp.write('%f\t0\n' % score)
    print(datetime.datetime.now(), 'save neg done')
    sys.stdout.flush()

    fp.close()

if __name__ == '__main__':
    models = [
        'CTCDPoi',
        'CTCDBer',
    ]
    datasets = [
        'dblp_citation',
        # 'dblp_coauthor',
        # 'weibo',
    ]
    community_count = [
        10,
        50,
        # 100,
        # 150,
    ]
    ctcd_poi_predictor = COLDPredictor()
    ctcd_ber_predictor = CTCDBerPredictor()
    cold_predictor = CTCDPoiPredictor()
    bigclam_predictor = BIGCLAMPredictor()

    exp = 'topic'
    root = os.path.abspath('../..')
    for dataset in datasets:
        for model in models:
            load_data({'exp': exp, 'root': root, 'model': model, 'dataset': dataset})
            for cc in community_count:
                for lw in [16, 32, 48, 64] if 'CTCD' in model else [32]:
                    for it in range(0, 310, 10):
                        prdict({'exp': exp, 'root': root, 'model': model, 'dataset': dataset, 'cc': cc, 'lw': lw, 'it': ('%04d' % it) if it < 300 else 'final'})
                        gc.collect()


## Generic Parts
# These functions are providing the functionality to load
# arbitrary configuration files.
#
# They can be imported by other code (see `ldap_config.py` for an example).

import importlib.util
import sys
from os import scandir
from os.path import abspath, isfile

def _filename(f):
    return f.name

def _import(module_name, path, loaded_configurations):
    spec = importlib.util.spec_from_file_location("", path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    sys.modules[module_name] = module

    loaded_configurations.insert(0, module)

    print(f"ЁЯзм loaded config '{path}'")

def read_configurations(config_module, config_dir, main_config):
    loaded_configurations = []

    main_config_path = abspath(f"{config_dir}/{main_config}.py")
    if isfile(main_config_path):
        _import(f"{config_module}.{main_config}", main_config_path, loaded_configurations)
    else:
        print(f"тЪая╕П Main configuration '{main_config_path}' not found.")

    with scandir(config_dir) as it:
        for f in sorted(it, key=_filename):
            if not f.is_file():
                continue

            if f.name.startswith("__"):
                continue

            if not f.name.endswith(".py"):
                continue

            if f.name == f"{main_config}.py":
                continue

            if f.name == f"{config_dir}.py":
                continue

            module_name = f"{config_module}.{f.name[:-len('.py')]}".replace(".", "_")
            _import(module_name, f.path, loaded_configurations)

    if len(loaded_configurations) == 0:
        print(f"тА╝я╕П No configuration files found in '{config_dir}'.")
        raise ImportError(f"No configuration files found in '{config_dir}'.")

    return loaded_configurations

## Specific Parts
# This section's code actually loads the various configuration files
# into the module with the given name.
# It contains the logic to resolve arbitrary configuration options by
# levaraging dynamic programming using `__getattr__`.

_loaded_configurations = read_configurations(
    config_dir="/etc/netbox/config/",
    config_module="netbox.configuration",
    main_config="configuration",
)

def __getattr__(name):
    for config in _loaded_configurations:
        try:
            return getattr(config, name)
        except:
            pass
    raise AttributeError

def __dir__():
    names = []
    for config in _loaded_configurations:
        names.extend(config.__dir__())
    return names


import cherrypy
from os import getcwd, environ

class Server:

    ON_HEROKU = environ.get('ON_HEROKU')

    def __init__(self, site_map):
        self.site_map = site_map
        self.tree = cherrypy.tree
        self.engine = cherrypy.engine

    def app_config(self):
        return {
            '/static': {
                "tools.staticdir.on": True,
                "tools.staticdir.dir": "%s/public" % getcwd()
            }
        }

    def build(self):
        if self.ON_HEROKU is True or self.ON_HEROKU == 'True':
            port = int(environ.get('PORT'))
        else:
            port = 8080
        cherrypy.config.update(
            {
                'server.socket_port': port,
                'server.socket_host': '0.0.0.0',
                'tools.sessions.on': True,
                'tools.staticdir.root': getcwd(),
                'engine.timeout_monitor.on': False
            }
        )
        for item in self.site_map:
            app = self.site_map[item]()
            self.tree.mount(app, item, self.app_config())

    def start(self):
        self.engine.start()
        self.engine.block()


import math, sys, time, traceback
import board, busio
from enum import Enum
from colorama import init, Fore, Style
init()

# if not busio.I2C, then use this:
#try:
#    from adafruit_extended_bus import ExtendedI2C as I2C
#except ImportError as ie:
#    sys.exit("This script requires the adafruit_extended_bus module.\n"\
#           + "Install with: pip3 install --user adafruit_extended_bus")
try:
    import adafruit_bno08x
    from adafruit_bno08x.i2c import BNO08X_I2C
#   from adafruit_bno08x.i2c import BNO08X
    from adafruit_bno08x import (
        PacketError,
        BNO_REPORT_ACCELEROMETER,
        BNO_REPORT_GYROSCOPE,
        BNO_REPORT_MAGNETOMETER,
        REPORT_ACCURACY_STATUS,
        BNO_REPORT_ACTIVITY_CLASSIFIER,
        BNO_REPORT_STABILITY_CLASSIFIER,
#       BNO_REPORT_ROTATION_VECTOR,
#       BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR,
#       BNO_REPORT_GAME_ROTATION_VECTOR,
    )
except ImportError as ie:
    sys.exit("This script requires the adafruit_bno08x module.\n"\
           + "Install with: pip3 install --user adafruit-circuitpython-bno08x")
try:
    from pyquaternion import Quaternion
except ImportError:
    sys.exit("This script requires the pyquaternion module.\nInstall with: pip3 install --user pyquaternion")

from lib.logger import Level, Logger
from lib.config_loader import ConfigLoader
from lib.message import Message
from lib.queue import MessageQueue
from lib.message_factory import MessageFactory
from lib.convert import Convert

# ..............................................................................
class BNO08x:
    '''
        Reads from a BNO08x 9DoF sensor.
    '''
    def __init__(self, config, queue, level):
        self._log = Logger("bno085", level)
        if config is None:
            raise ValueError("no configuration provided.")
        self._queue = queue

        self._config = config
        # config
        _config = self._config['ros'].get('bno085')
        self._loop_delay_sec    = _config.get('loop_delay_sec')
        _i2c_device             = _config.get('i2c_device')
        # default trim, can be overridden by methods
        self.set_heading_trim(_config.get('heading_trim'))
        self.set_pitch_trim(_config.get('pitch_trim'))
        self.set_roll_trim(_config.get('roll_trim'))
        i2c = busio.I2C(board.SCL, board.SDA, frequency=800000)
        self._bno = BNO08X_I2C(i2c, debug=False)
#       self._bno = BNO08X()
        self._error_range       = 5.0 # permitted error between Euler and Quaternion (in degrees) to allow setting value, was 3.0
        self._min_calib_status  = 1
        self._settle_sec        = 0.0
        self._calibrated        = False
        self._verbose           = False # True for stack traces
        self._configure()
        self._log.info('ready.')

    # ..........................................................................
    def set_heading_trim(self, trim):
        '''
        Set the heading trim in degrees.
        '''
        self._heading_trim = trim
        self._log.info('heading trim:\t{:>6.2f}°'.format(self._heading_trim))

    # ..........................................................................
    @property
    def heading_trim(self):
        '''
        Return the heading trim in degrees.
        '''
        return self._heading_trim

    # ..........................................................................
    def set_pitch_trim(self, trim):
        '''
        Set the pitch trim in degrees.
        '''
        self._pitch_trim = trim
        self._log.info('pitch trim:  \t{:>6.2f}°'.format(self._pitch_trim))

    # ..........................................................................
    @property
    def pitch_trim(self):
        '''
        Return the pitch trim in degrees.
        '''
        return self._pitch_trim

    # ..........................................................................
    def set_roll_trim(self, trim):
        '''
        Set the roll trim in degrees.
        '''
        self._roll_trim = trim
        self._log.info('roll trim:   \t{:>6.2f}°'.format(self._roll_trim))

    # ..........................................................................
    @property
    def roll_trim(self):
        '''
        Return the roll trim in degrees.
        '''
        return self._roll_trim

    # ..........................................................................
    def _configure(self):
        self._log.info('settle time... ({:1.0f}s)'.format(self._settle_sec))
        time.sleep(self._settle_sec) # settle before calibration
        self._log.info(Fore.YELLOW + 'begin configuration/calibration...')
        self._bno.begin_calibration()
        time.sleep(0.1)
        try:
            self._log.info(Fore.YELLOW + 'setting features...')
            _features = [
                    BNO_REPORT_ACCELEROMETER,
                    BNO_REPORT_GYROSCOPE,
                    BNO_REPORT_MAGNETOMETER,
                    BNO_REPORT_ACTIVITY_CLASSIFIER,
                    BNO_REPORT_STABILITY_CLASSIFIER,
#                   BNO_REPORT_ROTATION_VECTOR,
#                   BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR,

#                   BNO_REPORT_GAME_ROTATION_VECTOR,
#                   BNO_REPORT_LINEAR_ACCELERATION,
#                   BNO_REPORT_STEP_COUNTER,
#                   BNO_REPORT_SHAKE_DETECTOR,
#                   BNO_REPORT_RAW_ACCELEROMETER,
#                   BNO_REPORT_RAW_GYROSCOPE,
#                   BNO_REPORT_RAW_MAGNETOMETER,
                ]
            for feature in _features:
                self._log.debug('feature {}'.format(feature))
                self._bno.enable_feature(feature)
                time.sleep(0.01)
            self._log.info(Fore.YELLOW + 'features set.  ------------------- ')

            # now calibrate...
            time.sleep(2.0)
            self._log.info(Fore.YELLOW + 'calibrating...')
            start_time = time.monotonic()
            _fail_count = 0
            _confidence = 0
            while not self._calibrated \
                    and _confidence < 50 \
                    and _fail_count < 30:
                _fail_count += 1
                try:

                    _confidence = self._activity_report()
                    self._stability_report()
                    _calibration_status = self._calibration_report()

                    self._log.info("Magnetometer:")
                    mag_x, mag_y, mag_z = self._bno.magnetic  # pylint:disable=no-member
                    self._log.info("X: {:0.6f}  Y: {:0.6f} Z: {:0.6f} uT".format(mag_x, mag_y, mag_z))

#                   self._log.info("Game Rotation Vector Quaternion:")
#                   ( game_quat_i, game_quat_j, game_quat_k, game_quat_real,) = self._bno.game_quaternion  # pylint:disable=no-member
#                   self._log.info("I: {:0.6f}  J: {:0.6f} K: {:0.6f}  Real: {:0.6f}".format(game_quat_i, game_quat_j, game_quat_k, game_quat_real))

                    if _calibration_status >= self._min_calib_status: # we'll settle for Low Accuracy to start
                        self._calibrated = True
                        self._log.info(Fore.GREEN + "Calibrated.")
                        if _calibration_status > 1: # but save it if better than Low.
                            self._log.info(Fore.GREEN + Style.BRIGHT + "better than low quality calibration, saving status...")
                            self._bno.save_calibration_data()
                        break
                    time.sleep(0.2)
                except Exception as e:
                    self._log.error("calibration error: {}".format(e))
                finally:
                    self._min_calib_status = 1
                    self._calibrated = True

                self._log.info(Fore.BLACK + "fail count: {:d}".format(_fail_count))

        except Exception as e:
            self._log.error('error setting features: {}'.format(e))

        self._log.info("calibration complete.")

    # ..........................................................................
    @property
    def calibrated(self):
        return self._calibrated

    # ..........................................................................
    def _stability_report(self):
        '''
        Prints a report indicating the current stability status, returning
        a text string.
        '''
        _stability_classification = self._bno.stability_classification
        self._log.info(Fore.BLUE + "Stability:  \t{}".format(_stability_classification))
        pass

    # ..........................................................................
    def _activity_report(self):
        '''
        Prints a report indicating the current activity, returning an int
        indicating a confidence level from 0-100%.
        '''
        _activity_classification = self._bno.activity_classification
        _most_likely = _activity_classification["most_likely"]
        _confidence = _activity_classification[_most_likely]
        self._log.info(Fore.BLUE + "Activity:   \t{}".format(_most_likely))
        self._log.info(Fore.BLUE + "Confidence: \t{}%".format(_confidence))
        return _confidence

    # ..........................................................................
    def _calibration_report(self):
        '''
        Prints a report indicating the current calibration status,
        returning an int value from 0-3, as follows: "Accuracy Unreliable",
        "Low Accuracy", "Medium Accuracy", or "High Accuracy".
        '''
        _calibration_status = self._bno.calibration_status
        self._log.info(Fore.BLUE + "Calibration:\t{} ({:d})".format(REPORT_ACCURACY_STATUS[_calibration_status], _calibration_status))
        return _calibration_status

    # ..........................................................................
    def _process_quaternion(self, color, title, quaternion):
        # ( quat_i, quat_j, quat_k, quat_real ) = self._bno.quaternion
            ( quat_i, quat_j, quat_k, quat_real ) = quaternion
            _q = Quaternion(real=quat_real, imaginary=[quat_i, quat_j, quat_k])
            _q_heading        = _q.degrees
            _q_yaw_pitch_roll = _q.yaw_pitch_roll
            _q_yaw            = _q_yaw_pitch_roll[0]
            _q_pitch          = _q_yaw_pitch_roll[1]
            _q_roll           = _q_yaw_pitch_roll[2]
            self._log.info(color + 'heading: {:>6.2f}°\t({})\t'.format(_q_heading, title) + Fore.BLACK + 'p={:>5.4f}\t r={:>5.4f}\t y={:>5.4f}'.format(_q_pitch, _q_roll, _q_yaw))

    # ..........................................................................
    def magneto(self):
        '''
        Returns the current x, y, z reading of the magnetometer.
        '''
        try:
            self._calibration_report()
#           _calibration_status = self._calibration_report()
            return self._bno.magnetic
        except Exception as e:
            return None

    # ..........................................................................
    def read(self):
        '''
        The function that reads sensor values in a loop. This checks to see
        if the 'sys' calibration is at least 3 (True), and if the Euler and
        Quaternion values are within an error range of each other, this sets
        the class variable for heading, pitch and roll. If they aren't within
        range for more than n polls, the values revert to None.
        '''
#       self._log.info('starting sensor read...')

        try:

            # reports ......................................
#           _confidence = self._activity_report()
#           self._stability_report()
#           _calibration_status = self._calibration_report()

#           if _calibration_status >= self._min_calib_status:
            if True:

                # Accelerometer ..................................................................
#               gyro_x, gyro_y, gyro_z = self._bno.gyro  # pylint:disable=no-member
#               self._log.info(Fore.RED + 'Gyroscope:\tX: {:0.6f}  Y: {:0.6f} Z: {:0.6f} rads/s'.format(gyro_x, gyro_y, gyro_z))

                # Magnetometer ...................................................................
#               self._log.info(Fore.BLACK + 'self._bno.magnetic...')
                mag_x, mag_y, mag_z = self._bno.magnetic  # pylint:disable=no-member
                _mag_degrees = Convert.convert_to_degrees(mag_x, mag_y, mag_z)
                if self._heading_trim != 0.0:
                    _mag_degrees = Convert.offset_in_degrees(_mag_degrees, self._heading_trim)
                self._log.info(Fore.YELLOW + 'heading: {:>6.2f}°\t(magneto)'.format(_mag_degrees))

                # Rotation Vector Quaternion .....................................................
#               self._log.info(Fore.BLACK + 'self._bno.quaternion...')
                ( quat_i, quat_j, quat_k, quat_real ) = self._bno.quaternion  # pylint:disable=no-member
                _quaternion = self._bno.quaternion
                self._process_quaternion(Fore.GREEN, 'rot-quat', self._bno.quaternion)

                # Geomagnetic Rotation Vector Quatnernion ........................................
#               self._log.info(Fore.BLACK + 'self._bno.geometric_quaternion...')
                _geomagnetic_quaternion = self._bno.geomagnetic_quaternion
                ( geo_quat_i, geo_quat_j, geo_quat_k, geo_quat_real, ) = _geomagnetic_quaternion  # pylint:disable=no-member
                self._process_quaternion(Fore.GREEN + Style.BRIGHT, 'geo-quat', _geomagnetic_quaternion)
                return _mag_degrees, _quaternion[0], _geomagnetic_quaternion[0]

            else:
                self._log.warning('uncalibrated...')
                return 0.0, 0.0, 0.0

            self._log.debug('read ended.')

        except KeyError as ke:
            if self._verbose:
                self._log.error('bno08x key error: {} {}'.format(ke, traceback.format_exc()))
            else:
                self._log.error('bno08x key error: {}'.format(ke))
        except RuntimeError as re:
            if self._verbose:
                self._log.error('bno08x runtime error: {} {}'.format(re, traceback.format_exc()))
            else:
                self._log.error('bno08x runtime error: {}'.format(re))
        except IndexError as ie:
            if self._verbose:
                self._log.error('bno08x index error: {} {}'.format(ie, traceback.format_exc()))
            else:
                self._log.error('bno08x index error: {}'.format(ie))
        except OSError as oe:
            if self._verbose:
                self._log.error('bno08x os error: {} {}'.format(oe, traceback.format_exc()))
            else:
                self._log.error('bno08x OS error: {}'.format(oe))
        except PacketError as pe:
            if self._verbose:
                self._log.error('bno08x packet error: {} {}'.format(pe, traceback.format_exc()))
            else:
                self._log.error('bno08x packet error: {}'.format(pe))
        except Exception as e:
            if self._verbose:
                self._log.error('bno08x error: {} {}'.format(e, traceback.format_exc()))
            else:
                self._log.error('bno08x error: {}'.format(e))

## ..............................................................................
class Calibration(Enum):
    UNKNOWN    = ( 0, "Unknown", "The sensor is unable to classify the current stability.", False)
    ON_TABLE   = ( 1, "On Table", "The sensor is at rest on a stable surface with very little vibration.", False)
    STATIONARY = ( 2, "Stationary", "The sensor’s motion is below the stable threshold but the stable duration requirement has not been met. This output is only available when gyro calibration is enabled.", False)
    STABLE     = ( 3, "Stable", "The sensor’s motion has met the stable threshold and duration requirements.", True)
    IN_MOTION  = ( 4, "In motion", "The sensor is moving.", False)

    # ignore the first param since it's already set by __new__
    def __init__(self, num, name, description, calibrated):
        self._num = num
        self._name = name
        self._description = description
        self._calibrated = calibrated

    @property
    def name(self):
        return self._name

    @property
    def description(self):
        return self._description

    @property
    def calibrated(self):
        return self._calibrated

#EOF


from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import datetime

def get_blockworks_news(driver: webdriver) -> list[dict]:
    output_data: list[dict] = []
    driver.get("https://blockworks.co/news/")
    articles = driver.find_elements(By.CLASS_NAME, "card")
    for article in articles:
        date_str = article.find_element(By.CLASS_NAME, "post-creation-details").text.split(" / ")[-1]
        date_str = date_str.replace(" EDT", "")
        try:
            date = datetime.datetime.strptime(date_str, "%B %d, %Y, %H:%M %p")
        except ValueError:
            continue
        output_data.append({
            "name": article.find_element(By.CLASS_NAME, "card_title").text,
            "link": article.find_element(By.TAG_NAME, "a").get_attribute("href"),
            "date": date.strftime("%Y-%m-%d"),
            "time": date.strftime("%H:%M")
        })
    return output_data

if __name__ == '__main__':
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
    data = get_blockworks_news(driver)
    print(data)


import requests
from lxml import etree

headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
}

if __name__ == '__main__':
    url = "https://twitter.com/search?q=%23BBL10&src=trend_click&vertical=trends"
    response = requests.get(url=url,headers=headers)
    etre = etree.HTML(response.text)
    etr = etre.xpath('//*[@id="react-root"]/div/div/div[2]/main/div/div/div/div/div/div[2]/div/div/section/div/div/div[1]/div/div/article/div')
    print(etr)
    for div in etr:
        print(div)


import os
import signal
import sys
from collections import defaultdict

# Maps map the rule_name : organization_name : violation_count
warning_design_rule_to_occurrence = defaultdict(lambda: defaultdict(lambda: 0))
error_design_rule_to_occurrence = defaultdict(lambda: defaultdict(lambda: 0))
organization_name_to_specs = defaultdict(lambda: 1)

def design_rule_to_occurrence_index(organization_name, output):
    for line in output.split('\n'):
        tokens = line.split()
        if len(tokens) < 3:
            continue

        type = tokens[1]
        rule_name = tokens[2]

        # Record metrics
        if type == "warning":
            warning_design_rule_to_occurrence[rule_name][organization_name] += 1
        elif type == "error":
            error_design_rule_to_occurrence[rule_name][organization_name] += 1

def dfs(cur_dir_tokens):

    # Iterate through all files in the current directory.
    for filename in os.listdir(os.path.join("", *cur_dir_tokens)):

        # Skip files that are redundant.
        if filename in {".", ".."}:
            continue

        # Construct the absolute path to the file that's being iterated on.
        next_dir_tokens = cur_dir_tokens + [filename]
        next_dir_str = os.path.join("", *next_dir_tokens)

        # If this file is a directory, then it should be recursed on.
        if os.path.isdir(next_dir_str):
            dfs(next_dir_tokens)

        # If this is a yaml file, it is likely a spec. We should run the linter on it.
        elif filename.endswith(".yaml"):
            print(next_dir_str)

            # This file is extremely large and causes the program to hang. Ignore it.
            if next_dir_str == "./beezup.com/2.0/openapi.yaml":
                continue
            stream = os.popen(f"spectral lint {next_dir_str}")
            output = stream.read()
            if len(cur_dir_tokens) >= 2:
                organization_name = cur_dir_tokens[1]
                organization_name_to_specs[organization_name] += 1

                # Get the actual metrics
                design_rule_to_occurrence_index(organization_name, output)

def flush_to_csv(file_name, data_map):
    import csv

    with open(file_name, 'w') as f:

        # create the csv writer
        writer = csv.writer(f)
        writer.writerow(["name", "organization_name", "occurrences"])

        for tag in data_map.keys():
            for organization_name in data_map[tag]:
                violations = data_map[tag][organization_name]/organization_name_to_specs[organization_name]
                writer.writerow([tag, organization_name, violations])

def flush_data():
    flush_to_csv("./warnings.csv", warning_design_rule_to_occurrence)
    flush_to_csv("./errors.csv", error_design_rule_to_occurrence)

def signal_handler(signal, frame):
     # join all processes
    flush_data()
    sys.exit(0)

if __name__ == "__main__":
    # Register signal handler
    signal.signal(signal.SIGINT, signal_handler)

    dfs(['.'])
    flush_data()


import random
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

list_x = []
list_y = []
num  = 1000

while(num):
    list_x.append(random.randint(0.0,100.0))
    list_y.append(random.randint(0.0,100.0))
    num -= 1

list_x = np.asarray(list_x,dtype='int')
list_y = np.asarray(list_y,dtype='int')

train = 800
test = 200
x_train,x_test,y_train,y_test = list_x[:train],list_x[:test],list_y[:train],list_x[:test]

def accuracy(y_pred,y_test):
    print("mae :",np.abs(y_test-y_pred).mean())
    print("rmse :",(((y_test-y_pred)**2).mean())**0.5)

def gradient_descent(m_now, b_now, x, y, L):
     m_gradient = 0
     b_gradient = 0

     n = 1000

     for i in range(n):
        x = list_x[i]
        y = list_y[i]

        m_gradient += (-2/n) * x * (y - (m_now * x + b_now))
        b_gradient += (-2/n) * (y - (m_now * x + b_now))

     m = m_now - m_gradient * L
     b = b_now - b_gradient * L

     return m, b

m = 0
b = 0
L = 0.0001
epochs = 300

for i in range(epochs):
    if i%50 == 0:
        print(f"Epoch: {i}")
    m, b = gradient_descent(m, b, list_x, list_y, L)

print(m, b)
y_pred = m*x_test + b
accuracy(y_pred,y_test)
plt.scatter(list_x, list_y, color='pink')
plt.plot(list(range(0,100)), [m *x + b for x in range(0,100)], color = 'black')

from sklearn.linear_model import LinearRegression
reg = LinearRegression()

reg.fit(x_train.reshape(-1,1),y_train.reshape(-1,1))

c = reg.intercept_[0]
m = reg.coef_[0,0]

y_pred = reg.predict(x_test.reshape(-1,1))

accuracy(y_test,y_pred)
plt.scatter(list_x,list_y,c="r")
plt.plot(x_test,y_pred,c="b")


import requests
from fastapi import Depends, HTTPException
from jose.backends import RSAKey
from jose.jwt import decode, get_unverified_header

from app.config import settings

def get_keycloak_jwks():
    keycloak_well_known_url = settings.OIDC_CONFIG_URL
    response = requests.get(keycloak_well_known_url)
    well_known_config = response.json()
    jwks_url = well_known_config["jwks_uri"]
    jwks_response = requests.get(jwks_url)
    jwks = jwks_response.json()
    return jwks["keys"]

def validate_jwt(token: str = Depends(get_keycloak_jwks)):
    header = get_unverified_header(token)
    jwks = get_keycloak_jwks()

    # Find the RSA key with the matching kid in the JWKS
    rsa_key = None
    for key in jwks:
        if key["kid"] == header["kid"]:
            rsa_key = RSAKey(
                key=key["n"], alg=key["alg"], use=key["use"], kid=key["kid"]
            )
            break

    if rsa_key is None:
        raise HTTPException(status_code=401, detail="RSA Key not found in JWKS")

    try:
        payload = decode(token, rsa_key, algorithms=[header["alg"]])
    except Exception:
        raise HTTPException(status_code=401, detail="Invalid JWT token") from Exception

    return payload


"""
Please note that this app does *not* demonstrate Flask best practice!

It is much better to place views, controllers, configuration
files, and the like in their own directories.
"""

import json
import os
import sqlite3

from flask import Flask, render_template, request, send_from_directory
from flask_api import FlaskAPI, status, exceptions

from werkzeug.exceptions import NotFound
from werkzeug.middleware.proxy_fix import ProxyFix

app = FlaskAPI(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)

class IncidentDAO:
    def __init__(self, db_path='db/incident.db'):
        os.makedirs('db/', exist_ok=True)
        db_exists = os.path.exists(db_path)
        # Yup...this will be local, and only to this container
        # See notes in README
        self.conn =  sqlite3.connect(db_path)
        if not db_exists:
            cur = self.conn.cursor()
            sql = """
            CREATE TABLE IF NOT EXISTS "incidents" (
            "id" TEXT NOT NULL,
            "address" TEXT NOT NULL,
            "latitude" TEXT NOT NULL,
            "longitude" TEXT NOT NULL,
            "comment"  TEXT NOT NULL,
            "event_opened" TEXT NOT NULL,
            "event_closed" TEXT NOT NULL,
            "data" TEXT NOT NULL,
            PRIMARY KEY("id")
            )
            """
            cur.execute(sql)
            self.conn.commit()

    def _extract_data(self, data):
        # This should do a full schema validation, but a schema was not provided
        try:
            inc_id = data['description']['incident_number']
            address = data['address']['address_line1']
            latitude = data['address']['latitude']
            longitude = data['address']['longitude']
            comment = data['description']['comments']
            event_opened = data['description']['event_opened']
            event_closed = data['description']['event_opened']
        except KeyError as err:
            raise ValueError(f'Invalid data structure. Missing key {err.args[0]}')

        return [inc_id, address, latitude, longitude, comment, event_opened, event_closed,
                json.dumps(data)]

    def get(self, inc_id):
        cur = self.conn.cursor()
        cur.execute('SELECT *  FROM incidents WHERE id=?', (inc_id,))
        row = cur.fetchone()
        cur.description
        if row is not None:
            return dict(zip([d[0] for d in cur.description], row))

        raise NotFound(f'No incident with given id: {inc_id}')

    def incedents(self):
        """Get *all* the incidents"""
        cur = self.conn.cursor()

        cur.execute('SELECT * FROM incidents')

        all_incedents = []

        for row in cur:
            all_incedents.append(dict(zip([d[0] for d in cur.description], row)))

        return all_incedents

    def create(self, data):
        cur = self.conn.cursor()
        fields = self._extract_data(data)

        try:
            cur.execute('INSERT INTO incidents VALUES (?, ?, ?, ?, ?, ?, ?, ?)', fields)
        except sqlite3.IntegrityError as err:
            if 'UNIQUE constraint failed: incidents.id' in err.args[0]:
                raise RuntimeError(f"Incident with given number already exists: '{fields[0]}'")
        self.conn.commit()

        return self.get(fields[0])

    def update(self, inc_id, data):
        # Check we have an incident with that ID already
        self.get(inc_id)
        fields = self._extract_data(data)

        if inc_id != fields[0]:
            raise ValueError(f'Given incident ID {inc_id}, but data contains incident id {fields[0]}')

        cur = self.conn.cursor()
        cur.execute('UPDATE incidents SET id = ?, address = ?, latitude = ?, longitude = ?, '
                    'comment = ?, event_opened = ?, event_closed = ?, data = ?', fields)
        self.conn.commit()

        return self.get(fields[0])

    def delete(self, inc_id):
        # Check we have an incident with that ID already
        self.get(inc_id)

        cur = self.conn.cursor()
        cur.execute('DELETE FROM incidents WHERE id = ?', (inc_id,))

        self.conn.commit()

# These are static routes, not part of the API
@app.route('/favicon.ico')
def favicon(): # pragma: nocover
    return send_from_directory(os.path.join(app.root_path, 'static'),
                               'favicon.ico', mimetype='image/vnd.microsoft.icon')

@app.route('/')
def home(): # pragma: nocover
    return render_template("whale_hello.html")

@app.route('/env')
def env(): # pragma: nocover
    return '<pre>\n' + json.dumps(dict(os.environ), indent=4) + '\n</pre>\n'
# End static routs

@app.route("/api/", methods=['GET', 'POST'])
def incidents():
    #NOT best practice. :)
    incedent_dao = IncidentDAO()
    if request.method == 'POST':
        try:
            return incedent_dao.create(request.data), status.HTTP_201_CREATED
        except RuntimeError as err:
            return err.args[0], status.HTTP_400_BAD_REQUEST
    elif request.method == 'GET':
        return incedent_dao.incedents()

@app.route("/api/<inc_id>", methods=['GET', 'PUT', 'DELETE'])
def incident_detail(inc_id):
    #NOT best practice. :)
    incedent_dao = IncidentDAO()
    """Retreive, update, or delete an incident"""
    if request.method == 'PUT':
        try:
            return incedent_dao.update(inc_id, request.data)
        except NotFound:
            return '', status.HTTP_404_NOT_FOUND
        except ValueError as err:
            return err.args[0], status.HTTP_400_BAD_REQUEST
    elif request.method == 'DELETE':
        try:
            incedent_dao.delete(inc_id)
        except NotFound:
            return '', status.HTTP_404_NOT_FOUND
        return '', status.HTTP_204_NO_CONTENT
    elif request.method == 'GET':
        try:
            return incedent_dao.get(inc_id)
        except NotFound:
            return '', status.HTTP_404_NOT_FOUND

if __name__ == '__main__': # pragma: nocover
    app.run(host='0.0.0.0', port=8080)


import tkinter as tk
from tkinter import ttk
import time
from time import sleep
from tkinter import simpledialog
import serial
import io
import os

class RingBuffer:
    def __init__(self, size):
        self.size = size
        self.head = 0
        self.tail = 0
        self.count = 0
        self.lines = 0
        self.buffer = [None] * size
    def getch(self):
        if self.count == 0: return 0
        c = self.buffer[self.tail]
        self.tail += 1
        if self.tail >= self.size: self.tail = 0
        self.count -= 1
        if c == '\n': self.lines -= 1
        return c
    def putch(self, c):
        if c == chr(0x06): return self.count
        if c == chr(0x15): return self.count
        if c == '\r': return self.count
        if c == '\n': self.lines += 1
        self.buffer[self.head] = c
        self.head += 1
        if self.head >= self.size: self.head = 0
        self.count += 1
        return self.count
    def clear(self):
        self.head = 0
        self.tail = 0
        self.count = 0
        self.lines = 0
    def numChars(self):
        return self.count
    def available(self):
        return self.size-self.count
    def numLines(self):
        return self.lines
    def getline(self):
        str = ""
        if self.lines <= 0: return str
        while True:
            c = self.getch()
            if c == '\n': break
            if self.count <= 0: break
            str += c
        return str

class Comm:
    def __init__(self, parent):
        self.master = parent
        self.isOpen = False
        self.isError = False
        self.ErrorMessage = ""
        self.statusbar = None
        self.stopbits = 1
        self.bytesize = 8
        self.baudrate = 115200
        self.flowcontrol = "None"
        self.port = ""
        self.parity = 'N'
        self.rb = RingBuffer(10000)
        self.cp = None
        self.blkSize = 128
        self.MIPSname = 'MIPS'
    def update(self):
        # walks back to root or just fails to update!
        master = self.master
        while True:
            try:
                master.update()
                return
            except: pass
            try: master = master.master
            except: return
    def __statusbarMessage(self,message):
        if self.statusbar != None:
            self.statusbar.configure(text=message)
    def open(self):
        xonxoff = False
        rtscts = False
        if self.flowcontrol == "RTS/CTS": rtscts = True
        if self.flowcontrol == "XON/XOFF": xonxoff = True
        try:
            self.cp = serial.Serial(self.port,self.baudrate,self.bytesize,self.parity,self.stopbits,None,xonxoff,rtscts,None,False,None,None)
            self.isError = False
            self.isOpen = True
            # Get MIPS name
            res = self.SendMessage("GNAME\n")
            if res.count('?') == 0: self.MIPSname = res
            self.__statusbarMessage("Connected: " + self.port)
        except Exception as e:
            self.isError = True
            self.isOpen = False
            self.ErrorMessage = e
            if (self.statusbar != None): self.statusbar.configure(text=e)
    def close(self):
        if self.cp == None:
            self.__statusbarMessage('Nothing to disconnect!')
            return
        if self.cp.isOpen():
            self.cp.close()
        else:
            self.__statusbarMessage(self.port + ' all ready disconnected!')
            return
        while self.cp.isOpen():
            self.master().update()
        self.isOpen = False
        self.__statusbarMessage('Disconnected: ' + self.port)
    def findPorts(self):
        from serial.tools.list_ports import comports
        ports = []
        for n, (port, desc, hwid) in enumerate(sorted(comports()), 1):
            ports.append(port)
        return ports
    def ProcessSerial(self):
        if(self.isOpen == False): return
        while True:
            if self.cp.inWaiting() > 0:
                c = self.cp.read(1)
                self.rb.putch(chr(int.from_bytes(c,byteorder='big')))
            else:
                break
    def SendString(self, message):
        if(self.isOpen == False): return
        try:
            self.cp.flush()
            self.cp.write(message.encode('utf-8'))
            self.isError = False
        except Exception as e:
            self.isError = True
            self.ErrorMessage = e
            if (self.statusbar != None): self.statusbar.configure(text=e)
            self.__statusbarMessage('Error sending string!')
    def waitforline(self,timeout):
        if(self.isOpen == False): return True
        if timeout == 0:
            while True:
                self.ProcessSerial()
                if self.rb.lines > 0: break
            return True
        startT = time.monotonic()
        while (startT + timeout) > time.monotonic():
            self.ProcessSerial()
            if self.rb.lines > 0: return True
        return False
    def getlines(self):
        res = ""
        while self.waitforline(0.5):
            res += self.rb.getline() + "\n"
        return res
    def SendMessage(self,message):
        if (self.isOpen == False): return
        for i in range(0,1):
            self.SendString(message)
            if len(message) > 100: self.waitforline(3)
            else: self.waitforline(1)
            if self.rb.numLines() >= 1:
                return self.rb.getline()
        self.__statusbarMessage(message.replace('\n' , ' ') + ' :Timeout')
        return '?\n'
    def SendCommand(self, message):
        if (self.isOpen == False): return
        for i in range(0,1):
            self.SendString(message)
            if len(message) > 100: self.waitforline(3)
            else: self.waitforline(1)
            if self.rb.numLines() >= 1:
                res = self.rb.getline()
                if res == "": return True
                if res == "?":
                    return False
        self.__statusbarMessage(message.replace('\n', ' ') + ' :Timeout')
        return False
    def isMIPS(self):
        if not self.isOpen: return False
        res = self.SendMessage("GVER\n")
        if res.count("Version") > 0: return True
        return False
    def CalculateCRC(self, binarydata):
        generator = 0x1D
        crc = 0x00
        for b in binarydata:
            crc ^= int(b)
            for i in range(0,8):
                if (crc & 0x80) != 0: crc = (((crc << 1) & 0xFF) ^ int(generator))
                else:
                    crc <<= 1
                    crc &= 0xFF
        return crc
    def GetMIPSfile(self,MIPSfile, LocalFile):
        self.__statusbarMessage("Reading file from MIPS...")
        self.update()
        if self.SendCommand("GET," + MIPSfile + "\n"):
            self.waitforline(0.5)
            FileSize = self.rb.getline()
            FileData = ""
            for i in range(0,int(FileSize),1024):
                length = 1024
                self.waitforline(0.5)
                if int(FileSize) < 1024: length = int(FileSize)
                for j in range(0, length*2):
                    c = self.rb.getch()
                    if c == "\n": break;
                    FileData += c
                if (int(FileSize) - i) > 1024: self.SendString("Next\n")
            if len(FileData) != (2 * int(FileSize)):
                self.__statusbarMessage("File size read error!")
                return
            self.waitforline(0.5)
            FileCRC = self.rb.getline()
            if FileCRC == "":               #not sure why??
                self.waitforline(0.5)
                FileCRC = self.rb.getline().strip('\n')
            FileDataBinary = bytes.fromhex(FileData)
            if self.CalculateCRC(FileDataBinary) != int(FileCRC):
                self.__statusbarMessage("CRC error!")
                return
            # here with a valid file in FileDataBinary, save it to a file on this machine
            newFile = open(LocalFile, "wb")
            newFile.write(FileDataBinary)
            newFile.close()
            self.__statusbarMessage(LocalFile + " downloaded from MIPS")
            return
        self.__statusbarMessage("MIPS did not accept command!")
    def PutMIPSfile(self, MIPSfile, LocalFile):
        newFile = open(LocalFile, "rb")
        FileDataBinary = newFile.read()
        FileData = FileDataBinary.hex()
        newFile.close()
        self.__statusbarMessage("Sending file to MIPS...")
        self.update()
        self.SendCommand("PUT," + MIPSfile + "," + str(len(FileDataBinary)) + "\n")
        sleep(0.1)
        for i in range(0, len(FileData), 1024):
            flen = 1024
            if (len(FileData)-i) < 1024: flen = len(FileData)-i
            # Send data block in chunks
            for k in range(0,flen,self.blkSize):
                if flen >= (k+self.blkSize): self.SendString(FileData[i+k:i+k+self.blkSize])
                else: self.SendString(FileData[i+k:i+k+flen])
                sleep(0.05)
            if (flen == 1024) and ((len(FileData)-i) != 1024):
                if not self.waitforline(1.0):
                    print("timeout")
                    self.__statusbarMessage("Timeout, waiting for signal from MIPS!")
                else: self.rb.getline()
        sleep(0.1)
        self.SendString("\n")
        self.SendString(str(self.CalculateCRC(FileDataBinary)) + "\n")
        self.__statusbarMessage(LocalFile + " uploaded to MIPS")
    def GetEEPROM(self, fileName, board, addr):
        self.update()
        # Send the command to MIPS to get the EEPROM
        if self.SendCommand("GETEEPROM," + board + "," + '{:x}'.format(addr) + '\n'):
            # Now process the data in the ring buffer
            # First read the length
            self.waitforline(0.5)
            fileSize = self.rb.getline()
            # Read the hex data stream
            self.waitforline(1.0)
            fileData = self.rb.getline()
            if len(fileData) != 2 * int(fileSize):
                # Here if file data block is not the proper size
                self.__statusbarMessage("Data block size not correct!")
                return
            # Read the CRC
            self.waitforline(0.5)
            fileCRC = self.rb.getline()
            # Convert data to byte array and calculate CRC
            FileDataBinary = bytes.fromhex(fileData)
            if self.CalculateCRC(FileDataBinary) == int(fileCRC):
                # Now save the data to the user selected file
                newFile = open(fileName, "wb")
                newFile.write(FileDataBinary)
                newFile.close()
                self.__statusbarMessage("EEPROM from MIPS read and saved successfully!")
            else:
                self.__statusbarMessage("CRC error!")
    def PutEEPROM(self, fileName, board, addr):
        self.update()
        # Send the command to MIPS to send EEPROM data
        if self.SendCommand("PUTEEPROM," + board + "," + '{:x}'.format(addr) + '\n'):
            # open the local file to send and read the data
            newFile = open(fileName, "rb")
            FileDataBinary = newFile.read()
            FileData = FileDataBinary.hex()
            newFile.close()
            # Send file size
            self.SendString(str(len(FileDataBinary)) + '\n')
            # send hex data
            flen = len(FileData)
            for k in range(0,flen,self.blkSize):
                if flen >= (k+self.blkSize): self.SendString(FileData[k:k+self.blkSize])
                else: self.SendString(FileData[k:k+flen])
                sleep(0.05)
            self.SendString('\n')
            # Send CRC
            self.SendString(str(self.CalculateCRC(FileDataBinary)) + '\n')
            self.__statusbarMessage("MIPS module's EEPROM Written!")
    def GetFLASH(self, fileName):
        self.update()
        if self.SendCommand("GETFLASH\n"):
            # Now process the data in the ring buffer
            # First read the length
            self.waitforline(0.5)
            fileSize = self.rb.getline()
            # Read the hex data stream
            self.waitforline(1.0)
            fileData = self.rb.getline()
            if len(fileData) != 2 * int(fileSize):
                # Here if file data block is not the proper size
                self.__statusbarMessage("Data block size not correct!")
                return
            # Read the CRC
            self.waitforline(0.5)
            fileCRC = self.rb.getline()
            # Convert data to byte array and calculate CRC
            FileDataBinary = bytes.fromhex(fileData)
            if self.CalculateCRC(FileDataBinary) == int(fileCRC):
                # Now save the data to the user selected file
                newFile = open(fileName, "wb")
                newFile.write(FileDataBinary)
                newFile.close()
                self.__statusbarMessage("FLASH from module read and saved successfully!")
            else:
                self.__statusbarMessage("CRC error!")
    def PutFLASH(self, fileName):
        self.update()
        if self.SendCommand("PUTFLASH\n"):
            # open the local file to send and read the data
            newFile = open(fileName, "rb")
            FileDataBinary = newFile.read()
            FileData = FileDataBinary.hex()
            newFile.close()
            # Send file size
            flen = len(FileData)
            for k in range(0,flen,self.blkSize):
                if flen >= (k+self.blkSize): self.SendString(FileData[k:k+self.blkSize])
                else: self.SendString(FileData[k:k+flen])
                sleep(0.05)
            self.SendString('\n')
            # send hex data
            self.SendString(FileData + '\n')
            # Send CRC
            self.SendString(str(self.CalculateCRC(FileDataBinary)) + '\n')
            self.__statusbarMessage("Module FLASH Written!")
    def FLASHupload(self, faddress, fileName, cmd = 'ARBPGM'):
        # open the local file to send and read the data
        newFile = open(fileName, "rb")
        FileDataBinary = newFile.read()
        FileData = FileDataBinary.hex()
        newFile.close()
        self.update()
        # Send the data to MIPS module
        if self.SendCommand(cmd + "," + format(faddress, 'x') + "," + str(len(FileDataBinary)) + "\n"):
            for i in range(0, len(FileData), 512):
                length = 512
                if (len(FileData) - i) < 512: length = len(FileData) - i
                # Send this in chunks in case the sender is a lot faster than MIPS
                for k in range(0, length, 128):
                    if length > (k + 128): self.SendString(FileData[i+k : i+k+128])
                    else: self.SendString(FileData[i+k : i+length])
                    sleep(0.010)
                if length == 512:
                    self.waitforline(0.5)
                    if self.rb.getline() == "":
                        # Here if we timed out, display error and exit
                        self.__statusbarMessage("Timedout waiting for data from module!")
                        return
            self.SendString('\n')
            self.SendString(str(self.CalculateCRC(FileDataBinary)) + '\n')
            self.__statusbarMessage("File uploaded to Module FLASH!")
    def settings(self):
        def applyCallBack():
            self.baudrate = int(BaudRate.get())
            self.stopbits = int(StopBits.get())
            self.bytesize = int(DataBits.get())
            self.parity = Parity.get()[0]
            self.flowcontrol = FlowControl.get()
            self.port=portsel.get()
            settings.destroy()
            settings.quit()
        def portselCallback(event):
            from serial.tools.list_ports import comports
            for p in comports():
                if p.device == portsel.get():
                    self.desc.configure(text="")
                    self.manf.configure(text="")
                    self.sn.configure(text="")
                    self.loc.configure(text="")
                    self.vid.configure(text="")
                    self.pid.configure(text="")
                    self.desc.configure(text=p.description)
                    self.manf.configure(text=p.manufacturer)
                    self.sn.configure(text=p.serial_number)
                    self.loc.configure(text=p.location)
                    self.vid.configure(text=p.vid)
                    self.pid.configure(text=p.pid)
                    break
        settings = tk.Toplevel()
        settings.config(bg="gray98")
        settings.geometry('670x350')
        settings.title("Settings")
        ssp = tk.LabelFrame(settings, text="Select Serial Port", width=400, height=180, bg="gray95", bd=0)
        ssp.place(x=10, y=10)
        portsel = ttk.Combobox(ssp, width=40, textvariable=12)
        portsel['values'] = self.findPorts()
        #portsel['values'] += ('12',)
        portsel.bind("<<ComboboxSelected>>", portselCallback)
        portsel.set(self.port)
        portsel.place(x=10, y=5)
        portsel.current()
        tk.Label(ssp, text="Description:", bg="gray95").place(x=10, y=30)
        self.desc = tk.Label(ssp, text="", bg="gray95")
        self.desc.place(x=130, y=30)
        tk.Label(ssp, text="Manufacture:", bg="gray95").place(x=10, y=50)
        self.manf = tk.Label(ssp, text="", bg="gray95")
        self.manf.place(x=130, y=50)
        tk.Label(ssp, text="Serial number:", bg="gray95").place(x=10, y=70)
        self.sn = tk.Label(ssp, text="", bg="gray95")
        self.sn.place(x=130, y=70)
        tk.Label(ssp, text="Location:", bg="gray95").place(x=10, y=90)
        self.loc = tk.Label(ssp, text="", bg="gray95")
        self.loc.place(x=130, y=90)
        tk.Label(ssp, text="Vendor identifier:", bg="gray95").place(x=10, y=110)
        self.vid = tk.Label(ssp, text="", bg="gray95")
        self.vid.place(x=130, y=110)
        tk.Label(ssp, text="Product identifier:", bg="gray95").place(x=10, y=130)
        self.pid = tk.Label(ssp, text="", bg="gray95")
        self.pid.place(x=130, y=130)

        sp = tk.LabelFrame(settings, text="Select Parameters", width=220, height=180, bg="gray95", bd=0)
        sp.place(x=430, y=10)
        tk.Label(sp, text="BaudRate:", bg="gray95").place(x=10, y=10)
        tk.Label(sp, text="Data bits:", bg="gray95").place(x=10, y=40)
        tk.Label(sp, text="Parity:", bg="gray95").place(x=10, y=70)
        tk.Label(sp, text="Stop bits:", bg="gray95").place(x=10, y=100)
        tk.Label(sp, text="Flow control:", bg="gray95").place(x=10, y=130)
        BaudRate = ttk.Combobox(sp, width=10)
        BaudRate.place(x=100, y=10)
        BaudRate['values'] = (9600, 19200, 38400, 115200)
        BaudRate.set(self.baudrate)
        DataBits = ttk.Combobox(sp, width=10)
        DataBits.place(x=100, y=40)
        DataBits['values'] = (5, 6, 7, 8)
        DataBits.set(self.bytesize)
        Parity = ttk.Combobox(sp, width=10)
        Parity.place(x=100, y=70)
        Parity['values'] = ("None", "Even", "Odd", "Mark", "Space")
        Parity.set(self.parity)
        if self.parity == 'E': Parity.set("Even")
        if self.parity == 'O': Parity.set("Odd")
        if self.parity == 'M': Parity.set("Mark")
        if self.parity == 'S': Parity.set("Space")
        StopBits = ttk.Combobox(sp, width=10)
        StopBits.place(x=100, y=100)
        StopBits['values'] = (1, 2)
        StopBits.set(self.stopbits)
        FlowControl = ttk.Combobox(sp, width=10)
        FlowControl.place(x=100, y=130)
        FlowControl['values'] = ("None", "RTS/CTS", "XON/XOFF")
        FlowControl.set(self.flowcontrol)
        apply = tk.Button(settings, text=" Apply ", command=applyCallBack)
        apply.place(x=600, y=250)
        portselCallback(None)
        settings.mainloop()

class Terminal:
    def __init__(self, parent, cp):
        self.parent = parent
        self.cp = cp
        self.RepeatCmd = ""
        self.stopRequest = False
        self.scrollmips = tk.Scrollbar(self.parent)
        self.scrollmips.pack(side=tk.RIGHT, fill=tk.Y)
        self.mipsTerm = tk.Text(self.parent, bg="gray95")
        self.mipsTerm.pack(fill="both", expand=True)
        self.mipsTerm.bind("<Key>", self.key_pressed)
        self.mipsTerm.bind("<<Paste>>", self.key_paste)
        self.mipsTerm.bind("<Command-c>", self.key_copy)
        self.scrollmips.config(command=self.mipsTerm.yview)
        self.mipsTerm['yscrollcommand'] = self.scrollmips.set
    def print(self, *args, **kwargs):
        output = io.StringIO()
        print(*args, file=output, **kwargs)
        contents = output.getvalue()
        output.close()
        self.mipsTerm.insert(tk.END, contents)
    def key_pressed(self,event):
        if(event.char == ""): return
        self.cp.SendString(event.char)
    def key_paste(self,event):
        lines = self.mipsTerm.clipboard_get()
        for c in lines:
            self.cp.SendString(c)
    def key_copy(self,event):
        pass
    def clear(self):
        self.mipsTerm.delete("1.0", "end")
    def repeatLoop(self):
        if self.RepeatCmd == "": return
        if self.RepeatCmd == None: return
        if not self.cp.isOpen: return
        #if tabControl.tab(tabControl.select(), "text") != 'Terminal': return
        self.cp.SendString(self.RepeatCmd + "\n")
        self.parent.after(1000, self.repeatLoop)
    def messageRepeat(self):
        self.RepeatCmd=""
        self.repeatLoop()
        self.RepeatCmd = simpledialog.askstring(title="Repeat command", prompt="Enter the command to repeat:")
        self.parent.after(1000, self.repeatLoop)
    def commLoop(self):
        if self.stopRequest:
            self.stopRequest = False
            return
        self.cp.ProcessSerial()
        if self.cp.rb.numChars() > 0:
            while self.cp.rb.numChars() > 0:
                c=self.cp.rb.getch()
                self.mipsTerm.insert(tk.END,c)
            self.mipsTerm.see('end')
        if self.cp.isOpen:
            self.parent.after(100, self.commLoop)


import argparse
from pathlib import Path

def main() -> None:
    parser = argparse.ArgumentParser(description="Script to merge stubs with the Microsoft opencv stubs.",
                                     formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("--microsoft_stubs_path", "-m", type=Path, default=Path("./microst_stubs.pyi"),
                        help="Path to pre-existing stubs.")
    parser.add_argument("--new_stubs_path", "-n", type=Path, default=Path("src/cv2-stubs/__init__.pyi"),
                        help="Path to my stubs.")
    args = parser.parse_args()

    microsoft_stubs: Path = args.microsoft_stubs_path
    my_stubs: Path = args.new_stubs_path

    print("Reading pre-existing stubs")
    functions: dict[str, str] = {}  # function_signature: doctring
    done_functions_names: set[str] = set()
    head: list[str] = []
    with my_stubs.open("r", encoding="utf-8") as stubs:
        stub_lines = stubs.readlines()
    for i in range(len(stub_lines)):
        if stub_lines[i][:3] == "def":
            function_name = stub_lines[i][4:].split("(")[0]
            done_functions_names.add(function_name)
            functions[stub_lines[i]] = stub_lines[i+1]

        if len(done_functions_names) == 0:
            head.append(stub_lines[i])
    print(f"Found {len(done_functions_names)} functions.")

    print("Reading Microsoft stubs")
    with microsoft_stubs.open("r", encoding="utf-8") as stubs:
        stub_lines = stubs.readlines()
    for i in range(len(stub_lines)):
        if stub_lines[i][:3] == "def" and stub_lines[i][4:].split("(")[0] not in done_functions_names:
            functions[stub_lines[i]] = stub_lines[i+1]

    print("Writing new stubs")
    with my_stubs.open("w", encoding="utf-8") as new_file:
        new_file.writelines(head[:-1])

        functions = dict(sorted(functions.items(), key=lambda item: item[0]))
        for signature, docstring in functions.items():
            new_file.write("\n")
            new_file.write(signature)
            new_file.write(docstring)
            new_file.write("    ...\n")

    print("Done")

    # Replace commands that can be used to add some typings automatically:
    # sed -i "s/src: Mat/src: npt.NDArray[TImg]/" src/cv2-stubs/__init__.pyi
    # sed -i "s/dst: Mat/dst: npt.NDArray[TImg]/" src/cv2-stubs/__init__.pyi
    # sed -i "s/\(dst: npt.NDArray\[TImg\].*\) -> typing.Any:/\1 -> npt.NDArray[TImg]:/" src/cv2-stubs/__init__.pyi
    # sed -i "s/(image: Mat/(image: npt.NDArray[TImg]/" src/cv2-stubs/__init__.pyi
    # sed -i "s/borderMode=.../borderMode: int = .../" src/cv2-stubs/__init__.pyi
    # sed -i "s/borderValue=.../borderValue: TColor  = .../" src/cv2-stubs/__init__.pyi
    # sed -i "s/src1: Mat/src1: npt.NDArray[TImg]/" src/cv2-stubs/__init__.pyi
    # sed -i "s/src2: Mat/src2: npt.NDArray[TImg]/" src/cv2-stubs/__init__.pyi
    # sed -i "s/typing.Tuple\[/tuple\[/" src/cv2-stubs/__init__.pyi
    # sed -i "s/mask: Mat/mask: TMask/g" src/cv2-stubs/__init__.pyi

if __name__ == "__main__":
    main()