from tabulate import tabulate
from io import StringIO
import csv
import getopt
import sys
from IPython.display import display, HTML
import pandas as pd
import numpy as np
import webbrowser
import os
import datetime
from pretty_html_table import build_table

def get_table_html(df):

    """
    From https://stackoverflow.com/a/49687866/2007153

    Get a Jupyter like html of pandas dataframe

    """

    styles = [
        #table properties
        dict(selector=" ",
             props=[("margin","0"),
                    ("font-family",'"Helvetica", "Arial", sans-serif'),
                    ("border-collapse", "collapse"),
                    ("border","none"),
                    # ("border", "2px solid #ccf")
                       ]),

        #background shading
        dict(selector="tbody tr:nth-child(even)",
             props=[("background-color", "#fff")]),
        dict(selector="tbody tr:nth-child(odd)",
             props=[("background-color", "#eee")]),

        #cell spacing
        dict(selector="td",
             props=[("padding", ".5em")]),

        #header cell properties
        dict(selector="th",
             props=[("font-size", "100%"),
                    ("text-align", "center")]),

    ]
    return (df.style.set_table_styles(styles)).render()

class FargatePricing():
    def __init__(self):
        ''' No Upfront Costs '''
        self.on_demand_cpu = 0.04048
        self.on_demand_mem = 0.004445
        self.one_year_cpu = 0.032384
        self.one_year_mem = 0.003556
        self.three_year_cpu = 0.022264
        self.three_year_mem = 0.00244475
        self.monthly = 730

class ECS_Service():
    def __init__(self):
        self.service_name = '-'

        self.current_count = 0
        self.new_count = 0

        self.current_cpu = 0
        self.current_mem = 0
        self.new_cpu = 0
        self.new_mem = 0

        self.count_diff = 0
        self.cpu_diff = 0
        self.mem_diff = 0
        self.total_cpu_diff = 0
        self.total_mem_diff = 0

        self.current_mem_total = 0
        self.current_cpu_total = 0
        self.new_mem_total = 0
        self.new_cpu_total = 0

    def calculate_totals(self):
        self.new_mem_total = int(self.new_mem) * int(self.new_count)
        self.new_cpu_total = int(self.new_cpu) * int(self.new_count)
        self.current_cpu_total = int(self.current_cpu) * int(self.current_count)
        self.current_mem_total = int(self.current_mem) * int(self.current_count)

        totals = {
            'new_mem': self.new_mem_total,
            'new_cpu': self.new_cpu_total,
            'current_mem': self.current_mem_total,
            'current_cpu': self.current_cpu_total,
        }

        return totals

    def calculate_diffs(self):
        self.count_diff = int(self.new_count) - int(self.current_count)
        self.cpu_diff = int(self.new_cpu) - int(self.current_cpu)
        self.mem_diff = int(self.new_mem) - int(self.current_mem)
        self.total_cpu_diff = int(self.new_cpu_total) - int(self.current_cpu_total)
        self.total_mem_diff = int(self.new_mem_total) - int(self.current_mem_total)

        diffs = {
            'count': self.count_diff,
            'cpu': self.cpu_diff,
            'mem': self.mem_diff,
            'total_cpu': self.total_cpu_diff,
            'total_mem': self.total_mem_diff,
        }
        return diffs

# def create_dataframe(dataframe, names):
#     df = pd.DataFrame(
#         dataframe, index=list(names),
#         # columns=pd.MultiIndex.from_product([['Decision Tree', 'Regression', 'Random'],['Tumour', 'Non-Tumour']], names=['Model:', 'Predicted:'])
#     )
#     return df

def import_csv(csvfile):
    def header_validation(headers):
        validity = True
        try:
            if header[0] != 'Service Name' or\
               header[1] != 'Current Count' or\
               header[2] != 'New Count' or\
               header[3] != 'Current vCPU Value' or\
               header[4] != 'New vCPU Value' or\
               header[5] != 'Current Memory (in MB)' or\
               header[6] != 'New Memory (in MB)':
                validity = False
        except Exception as e:
            print(e)
            return False
        return validity

    def row_processor(row):
        service_name = row[0]
        current_count = row[1]
        new_count = row[2]
        current_cpu = row[3]
        new_cpu = row[4]
        current_mem = row[5]
        new_mem = row[6]

        e = ECS_Service()
        e.service_name = service_name
        e.current_count = current_count
        e.new_count = new_count
        e.current_cpu = current_cpu
        e.new_cpu = new_cpu
        e.current_mem = current_mem
        e.new_mem = new_mem

        totals = e.calculate_totals()

        e.new_mem_total = totals['new_mem']
        e.new_cpu_total = totals['new_cpu']
        e.current_mem_total = totals['current_mem']
        e.current_cpu_total = totals['current_cpu']

        diffs = e.calculate_diffs()

        e.count_diff = diffs['count']
        e.cpu_diff = diffs['cpu']
        e.mem_diff = diffs['mem']
        e.total_cpu_diff = diffs['total_cpu']
        e.total_mem_diff = diffs['total_mem']

        return e

    with open(csvfile, newline='') as csvfile:
        reader = csv.reader(csvfile, delimiter=',')
        header = next(reader)
        valid_headers = header_validation(header)
        if not valid_headers:
            return False

        rows = []
        for row in reader:
            rows.append(row)

        services = []
        for row in rows:
            service = row_processor(row)
            services.append(service)
        return services

def process_services(services):

    headers = [
        'Current Count',
        'New Count',
        'Count Diff',
        'Current CPU',
        'New CPU',
        'CPU Diff',
        'Current Memory',
        'New Memory',
        'Memory Diff',
        'Current Total CPU',
        'New Total CPU',
        'Current Total Memory',
        'New Total Memory',
        'Total CPU Diff',
        'Total Memory Diff'
    ]

    dataframe = {}
    key_list = list(headers)
    names = []
    changes = []

    for header in headers:
        dataframe[header] = []

    for service in services:

        change = {
            'name': service.service_name,
            'data': [
                service.current_count,
                service.new_count,
                service.count_diff,
                service.current_cpu,
                service.new_cpu,
                service.cpu_diff,
                service.current_mem,
                service.new_mem,
                service.mem_diff,
                service.current_cpu_total,
                service.new_cpu_total,
                service.current_mem_total,
                service.new_mem_total,
                service.total_cpu_diff,
                service.total_mem_diff,
            ]
        }

        changes.append(change)

    for change in changes:
        name = change['name']
        names.append(name)
        for index, data in enumerate(change['data']):
            key = key_list[index]
            dataframe[key].append(data)

    df = pd.DataFrame(
        dataframe, index=list(names),
    )
    return df

def process_pricing(services):

    fargate = FargatePricing()

    headers = [
        'Current Total CPU',
        'Current CPU Price',
        'New Total CPU',
        'New CPU Price',
        'CPU Price Diff',
        'Current Total Memory',
        'Current Mem Price',
        'New Total Memory',
        'New Mem Price',
        'Mem Price Diff',
        'Total Price Diff'
    ]

    dataframe = {}
    key_list = list(headers)
    names = []
    changes = []

    for header in headers:
        dataframe[header] = []

    for service in services:
        current_cpu_price = (service.current_cpu_total / 1024) * (fargate.one_year_cpu * fargate.monthly)
        new_cpu_price = (service.new_cpu_total / 1024) * (fargate.one_year_cpu * fargate.monthly)
        cpu_diff = new_cpu_price - current_cpu_price
        current_mem_price = (service.current_mem_total / 1024) * (fargate.one_year_mem * fargate.monthly)
        new_mem_price = (service.new_mem_total / 1024) * (fargate.one_year_mem * fargate.monthly)
        total_cpu_diff = (service.total_cpu_diff / 1024) * (fargate.one_year_cpu * fargate.monthly)
        total_mem_diff = (service.total_mem_diff / 1024) * (fargate.one_year_mem * fargate.monthly)
        total_price_diff = total_cpu_diff + total_mem_diff

        change = {
            'name': service.service_name,
            'data': [
                service.current_cpu_total,
                current_cpu_price,
                service.new_cpu_total,
                new_cpu_price,
                cpu_diff,
                service.current_mem_total,
                current_mem_price,
                service.new_mem_total,
                new_mem_price,
                total_mem_diff,
                total_price_diff

            ]
        }

        changes.append(change)

    for change in changes:
        name = change['name']
        names.append(name)
        for index, data in enumerate(change['data']):
            key = key_list[index]
            dataframe[key].append(data)

    df = pd.DataFrame(
        dataframe, index=list(names),
    )
    df.loc['Total'] = df.sum()
    df = df.round(2)
    return df

def display_df_html(df):
    df = get_table_html(df)
    filename = 'pandas.html'
    with open(filename, 'w') as f:
        f.write(df)
    file_location = os.path.abspath(f'./%s' % (filename))
    webbrowser.open('file://' + file_location)

def define_service():
    new_cpu = 0
    new_mem = 0
    service_name = input("Set service name: ")
    service_action = input("Do you want to change or remove? (remove/change): ")
    service_action = service_action.strip().lower()
    current_count = int(input("How many tasks are currently running as a baseline: "))
    if service_action in ('r', 'remove'):
        new_count = 0
    else:
        new_count = int(input("Set new service count baseline: "))
        if not new_count:
            new_count = current_count
    current_cpu = int(input("Set current vCPU value: "))
    current_mem = int(input("Set current Memory value: "))
    if service_action in ('change', 'c'):
        service_action = 'change'
        new_cpu = int(input("Set new vCPU value: "))
        new_mem = int(input("Set new Memory value: "))
        # new_count = int(input("Set new service count baseline: "))
        if not new_count:
            new_count = current_count
    if service_action in ('r', 'remove'):
        new_count = 0

    service_definition = {
        'name': service_name,
        'current_count': current_count,
        'new_count': new_count,
        'action': service_action,
        'current_cpu': current_cpu,
        'current_mem': current_mem,
        'new_cpu': new_cpu,
        'new_mem': new_mem
        }
    return service_definition

def manual():
    services = []
    changes = []
    while True:
        service = define_service()
        services.append(service)

        add_more = input("Add another service? (y/n): ")
        add_more = add_more.strip().lower()

        if add_more in ('y', 'yes'):
            continue
        break

    current_total_count = 0
    current_total_cpu_usage = 0
    current_total_mem_usage = 0
    new_total_count = 0
    new_total_cpu_usage = 0
    new_total_mem_usage = 0

    for service in services:
        action = service.get('action')
        current_cpu = service.get('current_cpu')
        current_mem = service.get('current_mem')
        new_cpu = service.get('new_cpu')
        new_mem = service.get('new_mem')
        name = service.get('name')
        current_count = service.get('current_count')
        new_count = service.get('new_count')

        if action == 'change':

            current_cpu_total = current_cpu * current_count
            current_mem_total = current_mem * current_count
            new_cpu_total = new_cpu * new_count
            new_mem_total = new_mem * new_count
            cpu_diff = new_cpu - current_cpu
            mem_diff = new_mem - current_mem

            current_total_count += current_count
            current_total_cpu_usage += current_cpu_total
            current_total_mem_usage += current_mem_total

            new_total_count += new_count
            new_total_cpu_usage += new_cpu_total
            new_total_mem_usage += new_mem_total

            service_cpu_diff = new_cpu_total - current_cpu_total
            service_mem_diff = new_mem_total - current_mem_total
            count_diff = new_count - current_count

            change = {
                'name': name,
                'data': [
                    current_count,
                    new_count,
                    count_diff,
                    current_cpu,
                    new_cpu,
                    cpu_diff,
                    current_mem,
                    new_mem,
                    mem_diff,
                    current_cpu_total,
                    new_cpu_total,
                    current_mem_total,
                    new_mem_total,
                    service_cpu_diff,
                    service_mem_diff,
                ]
            }

            changes.append(change)

    total_cpu_diff = new_total_cpu_usage - current_total_cpu_usage
    total_mem_diff = new_total_mem_usage - current_total_mem_usage
    total_count_diff = new_total_count - current_total_count

    headers = [
        # 'Name',
        'Current Count',
        'New Count',
        'Count Diff',
        'Current CPU',
        'New CPU',
        'CPU Diff',
        'Current Memory',
        'New Memory',
        'Memory Diff',
        'Current Total CPU',
        'New Total CPU',
        'Current Total Memory',
        'New Total Memory',
        'Total CPU Diff',
        'Total Memory Diff'
    ]

    dataframe = {}

    for header in headers:
        dataframe[header] = []

    key_list = list(dataframe)
    names = []

    for change in changes:
        name = change['name']
        names.append(name)
        for index, data in enumerate(change['data']):
            key = key_list[index]
            dataframe[key].append(data)

    df = pd.DataFrame(
        dataframe, index=list(names),
        # columns=pd.MultiIndex.from_product([['Decision Tree', 'Regression', 'Random'],['Tumour', 'Non-Tumour']], names=['Model:', 'Predicted:'])
    )
    df.style
    print(tabulate(df, headers='keys', tablefmt='pretty'))

def run_csv(inputfile):
    services = import_csv(inputfile)
    service_df = process_services(services)
    pricing_df = process_pricing(services)

    print(tabulate(service_df, headers='keys', tablefmt='pretty'))
    print(tabulate(pricing_df, headers='keys', tablefmt='pretty'))

    display_df_html(pricing_df)

def main(argv):

    inputfile = ''
    try:
        opts, args = getopt.getopt(argv, "hmi:", ["ifile="])
    except getopt.GetoptError:
        print('pricing.py -i <csvfile.csv>')
        sys.exit(2)

    for opt, arg in opts:
        if opt == '-h':
            print('pricing -i <file>.csv')
            sys.exit()
        elif opt in ("-i", "--ifile"):
            inputfile = arg
            run_csv(inputfile)
        elif opt == '-m':
            manual()

if __name__ == '__main__':
    main(sys.argv[1:])


from time import time
from neo.lib import logging
from neo.lib.util import dump
from neo.lib.protocol import ProtocolError, uuid_str, ZERO_TID

class ConflictError(Exception):
    """
        Raised when a resolvable conflict occurs
        Argument: tid of locking transaction or latest revision
    """

    def __init__(self, tid):
        Exception.__init__(self)
        self._tid = tid

    def getTID(self):
        return self._tid

class DelayedError(Exception):
    """
        Raised when an object is locked by a previous transaction
    """

class NotRegisteredError(Exception):
    """
        Raised when a ttid is not registered
    """

class Transaction(object):
    """
        Container for a pending transaction
    """
    _tid = None
    has_trans = False

    def __init__(self, uuid, ttid):
        self._uuid = uuid
        self._ttid = ttid
        self._object_dict = {}
        self._locked = False
        self._birth = time()
        self._checked_set = set()

    def __repr__(self):
        return "<%s(ttid=%r, tid=%r, uuid=%r, locked=%r, age=%.2fs) at 0x%x>" \
         % (self.__class__.__name__,
            dump(self._ttid),
            dump(self._tid),
            uuid_str(self._uuid),
            self.isLocked(),
            time() - self._birth,
            id(self))

    def addCheckedObject(self, oid):
        assert oid not in self._object_dict, dump(oid)
        self._checked_set.add(oid)

    def getTTID(self):
        return self._ttid

    def setTID(self, tid):
        assert self._tid is None, dump(self._tid)
        assert tid is not None
        self._tid = tid

    def getTID(self):
        return self._tid

    def getUUID(self):
        return self._uuid

    def lock(self):
        assert not self._locked
        self._locked = True

    def isLocked(self):
        return self._locked

    def addObject(self, oid, data_id, value_serial):
        """
            Add an object to the transaction
        """
        assert oid not in self._checked_set, dump(oid)
        self._object_dict[oid] = oid, data_id, value_serial

    def delObject(self, oid):
        try:
            return self._object_dict.pop(oid)[1]
        except KeyError:
            self._checked_set.remove(oid)

    def getObject(self, oid):
        return self._object_dict[oid]

    def getObjectList(self):
        return self._object_dict.values()

    def getOIDList(self):
        return self._object_dict.keys()

    def getLockedOIDList(self):
        return self._object_dict.keys() + list(self._checked_set)

class TransactionManager(object):
    """
        Manage pending transaction and locks
    """

    def __init__(self, app):
        self._app = app
        self._transaction_dict = {}
        self._store_lock_dict = {}
        self._load_lock_dict = {}
        self._uuid_dict = {}

    def register(self, uuid, ttid):
        """
            Register a transaction, it may be already registered
        """
        logging.debug('Register TXN %s for %s', dump(ttid), uuid_str(uuid))
        transaction = self._transaction_dict.get(ttid, None)
        if transaction is None:
            transaction = Transaction(uuid, ttid)
            self._uuid_dict.setdefault(uuid, set()).add(transaction)
            self._transaction_dict[ttid] = transaction
        return transaction

    def getObjectFromTransaction(self, ttid, oid):
        """
            Return object data for given running transaction.
            Return None if not found.
        """
        try:
            return self._transaction_dict[ttid].getObject(oid)
        except KeyError:
            return None

    def reset(self):
        """
            Reset the transaction manager
        """
        self._transaction_dict.clear()
        self._store_lock_dict.clear()
        self._load_lock_dict.clear()
        self._uuid_dict.clear()

    def vote(self, ttid, txn_info=None):
        """
            Store transaction information received from client node
        """
        logging.debug('Vote TXN %s', dump(ttid))
        transaction = self._transaction_dict[ttid]
        object_list = transaction.getObjectList()
        if txn_info:
            user, desc, ext, oid_list = txn_info
            txn_info = oid_list, user, desc, ext, False, ttid
            transaction.has_trans = True
        # store metadata to temporary table
        dm = self._app.dm
        dm.storeTransaction(ttid, object_list, txn_info)
        dm.commit()

    def lock(self, ttid, tid):
        """
            Lock a transaction
        """
        logging.debug('Lock TXN %s (ttid=%s)', dump(tid), dump(ttid))
        try:
            transaction = self._transaction_dict[ttid]
        except KeyError:
            raise ProtocolError("unknown ttid %s" % dump(ttid))
        # remember that the transaction has been locked
        transaction.lock()
        self._load_lock_dict.update(
            dict.fromkeys(transaction.getOIDList(), ttid))
        # commit transaction and remember its definitive TID
        if transaction.has_trans:
            self._app.dm.lockTransaction(tid, ttid)
        transaction.setTID(tid)

    def unlock(self, ttid):
        """
            Unlock transaction
        """
        tid = self._transaction_dict[ttid].getTID()
        logging.debug('Unlock TXN %s (ttid=%s)', dump(tid), dump(ttid))
        dm = self._app.dm
        dm.unlockTransaction(tid, ttid)
        self._app.em.setTimeout(time() + 1, dm.deferCommit())
        self.abort(ttid, even_if_locked=True)

    def getFinalTID(self, ttid):
        try:
            return self._transaction_dict[ttid].getTID()
        except KeyError:
            return self._app.dm.getFinalTID(ttid)

    def getLockingTID(self, oid):
        return self._store_lock_dict.get(oid)

    def lockObject(self, ttid, serial, oid, unlock=False):
        """
            Take a write lock on given object, checking that "serial" is
            current.
            Raises:
                DelayedError
                ConflictError
        """
        # check if the object if locked
        locking_tid = self._store_lock_dict.get(oid)
        if locking_tid == ttid and unlock:
            logging.info('Deadlock resolution on %r:%r', dump(oid), dump(ttid))
            # A duplicate store means client is resolving a deadlock, so
            # drop the lock it held on this object, and drop object data for
            # consistency.
            del self._store_lock_dict[oid]
            data_id = self._transaction_dict[ttid].delObject(oid)
            if data_id:
                self._app.dm.pruneData((data_id,))
            # Give a chance to pending events to take that lock now.
            self._app.executeQueuedEvents()
            # Attemp to acquire lock again.
            locking_tid = self._store_lock_dict.get(oid)
        if locking_tid is None:
            previous_serial = None
        elif locking_tid == ttid:
            # If previous store was an undo, next store must be based on
            # undo target.
            previous_serial = self._transaction_dict[ttid].getObject(oid)[2]
            if previous_serial is None:
                # XXX: use some special serial when previous store was not
                # an undo ? Maybe it should just not happen.
                logging.info('Transaction %s storing %s more than once',
                             dump(ttid), dump(oid))
        elif locking_tid < ttid:
            # We have a bigger TTID than locking transaction, so we are younger:
            # enter waiting queue so we are handled when lock gets released.
            # We also want to delay (instead of conflict) if the client is
            # so faster that it is committing another transaction before we
            # processed UnlockInformation from the master.
            logging.info('Store delayed for %r:%r by %r', dump(oid),
                    dump(ttid), dump(locking_tid))
            raise DelayedError
        else:
            # We have a smaller TTID than locking transaction, so we are older:
            # this is a possible deadlock case, as we might already hold locks
            # the younger transaction is waiting upon. Make client release
            # locks & reacquire them by notifying it of the possible deadlock.
            logging.info('Possible deadlock on %r:%r with %r',
                dump(oid), dump(ttid), dump(locking_tid))
            raise ConflictError(ZERO_TID)
        if previous_serial is None:
            previous_serial = self._app.dm.getLastObjectTID(oid)
        if previous_serial is not None and previous_serial != serial:
            logging.info('Resolvable conflict on %r:%r',
                dump(oid), dump(ttid))
            raise ConflictError(previous_serial)
        logging.debug('Transaction %s storing %s', dump(ttid), dump(oid))
        self._store_lock_dict[oid] = ttid

    def checkCurrentSerial(self, ttid, serial, oid):
        try:
            transaction = self._transaction_dict[ttid]
        except KeyError:
            raise NotRegisteredError
        self.lockObject(ttid, serial, oid, unlock=True)
        transaction.addCheckedObject(oid)

    def storeObject(self, ttid, serial, oid, compression, checksum, data,
            value_serial, unlock=False):
        """
            Store an object received from client node
        """
        try:
            transaction = self._transaction_dict[ttid]
        except KeyError:
            raise NotRegisteredError
        self.lockObject(ttid, serial, oid, unlock=unlock)
        # store object
        if data is None:
            data_id = None
        else:
            data_id = self._app.dm.holdData(checksum, data, compression)
        transaction.addObject(oid, data_id, value_serial)

    def abort(self, ttid, even_if_locked=False):
        """
            Abort a transaction
            Releases locks held on all transaction objects, deletes Transaction
            instance, and executed queued events.
            Note: does not alter persistent content.
        """
        if ttid not in self._transaction_dict:
            # the tid may be unknown as the transaction is aborted on every node
            # of the partition, even if no data was received (eg. conflict on
            # another node)
            return
        logging.debug('Abort TXN %s', dump(ttid))
        transaction = self._transaction_dict[ttid]
        has_load_lock = transaction.isLocked()
        # if the transaction is locked, ensure we can drop it
        if has_load_lock:
            if not even_if_locked:
                return
        else:
            self._app.dm.abortTransaction(ttid)
        # unlock any object
        for oid in transaction.getLockedOIDList():
            if has_load_lock:
                lock_ttid = self._load_lock_dict.pop(oid, None)
                assert lock_ttid in (ttid, None), 'Transaction %s tried to ' \
                    'release the lock on oid %s, but it was held by %s' % (
                    dump(ttid), dump(oid), dump(lock_ttid))
            write_locking_tid = self._store_lock_dict.pop(oid)
            assert write_locking_tid == ttid, 'Inconsistent locking state: ' \
                'aborting %s:%s but %s has the lock.' % (dump(ttid), dump(oid),
                    dump(write_locking_tid))
        # remove the transaction
        uuid = transaction.getUUID()
        self._uuid_dict[uuid].discard(transaction)
        # clean node index if there is no more current transactions
        if not self._uuid_dict[uuid]:
            del self._uuid_dict[uuid]
        del self._transaction_dict[ttid]
        # some locks were released, some pending locks may now succeed
        self._app.executeQueuedEvents()

    def abortFor(self, uuid):
        """
            Abort any non-locked transaction of a node
        """
        logging.debug('Abort for %s', uuid_str(uuid))
        # BUG: Discarding voted transactions must only be a decision of the
        #      master, and for this, we'll need to review how transactions are
        #      aborted. As a workaround, we rely on the fact that lock() will
        #      disconnect from the master in case of LockInformation.
        # abort any non-locked transaction of this node
        for ttid in [x.getTTID() for x in self._uuid_dict.get(uuid, [])]:
            self.abort(ttid)
        # cleanup _uuid_dict if no transaction remains for this node
        transaction_set = self._uuid_dict.get(uuid)
        if transaction_set is not None and not transaction_set:
            del self._uuid_dict[uuid]

    def isLockedTid(self, tid):
        for t in self._transaction_dict.itervalues():
            if t.isLocked() and t.getTID() <= tid:
                return True
        return False

    def loadLocked(self, oid):
        return oid in self._load_lock_dict

    def log(self):
        logging.info("Transactions:")
        for txn in self._transaction_dict.values():
            logging.info('    %r', txn)
        logging.info('  Read locks:')
        for oid, ttid in self._load_lock_dict.items():
            logging.info('    %r by %r', dump(oid), dump(ttid))
        logging.info('  Write locks:')
        for oid, ttid in self._store_lock_dict.items():
            logging.info('    %r by %r', dump(oid), dump(ttid))

    def updateObjectDataForPack(self, oid, orig_serial, new_serial, data_id):
        lock_tid = self.getLockingTID(oid)
        if lock_tid is not None:
            transaction = self._transaction_dict[lock_tid]
            if transaction.getObject(oid)[2] == orig_serial:
                if new_serial:
                    data_id = None
                else:
                    self._app.dm.holdData(data_id)
                transaction.addObject(oid, data_id, new_serial)


from ch08_binary_trees.util import tree_utils
from ch08_binary_trees.intro.intro_binary_tree_node import BinaryTreeNode
from ch08_binary_trees.intro.intro_binary_search_tree import insert

def create_lca_example_tree():
    _6 = BinaryTreeNode(6)
    insert(_6, 7)
    insert(_6, 4)
    insert(_6, 5)
    insert(_6, 2)
    insert(_6, 1)
    insert(_6, 3)

    return _6

def find_lca(start_node, value1, value2):
    # rekursiver Abbruch
    if start_node is None:
        return None

    current_value = start_node.item

    # rekursiver Abstieg
    if value1 < current_value and value2 < current_value:
        return find_lca(start_node.left, value1, value2)

    if value1 > current_value and value2 > current_value:
        return find_lca(start_node.right, value1, value2)

    # Hier gilt value1 < currentValue && currentValue < value2 bzw.
    # value2 < currentValue &&  currentValue < value1
    return start_node

def main():
    root = create_lca_example_tree()
    print("LCA: ", find_lca(root, 1, 5).item)

    tree_utils.nice_print(root)

if __name__ == "__main__":
    main()


# -*- coding: utf-8 -*-
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import os
import datetime as dt

def check_results():
    pd.set_option('display.max_rows', 800)
    pd.set_option('display.min_rows', 200)

    today = dt.datetime.now()
    today_str = today.strftime("%Y-%m-%d")
    yest = today - dt.timedelta(days = 1)
    yest_str = yest.strftime("%Y-%m-%d")
    n_dir = '../nope_dataframes/'
    today_file = f'../ohlcv/{today_str}_openprices.csv'
    b = pd.read_csv(today_file, compression='gzip')
    list_of_files = [(n_dir + i) for i in os.listdir(n_dir) if (i.startswith(f'recs_{yest_str}'))]
    list_of_files = sorted(list_of_files)
    print('\n\n\n')
    for j in list_of_files:
        rec_file = j
        #rec_file = f'../nope_dataframes/recs_2021-02-19_14.30.csv'
        print (rec_file)
        print (today_file)
        a = pd.read_csv(rec_file, compression = 'gzip')
        x = pd.merge(a, b, on='symbol')
        cols = ['symbol','close_price','hurdle','confidence','buy','Open']
        x = x[cols]
        x = x[x['buy']==1]
        x['profit'] = ((x['Open'] - x['close_price']) / x['close_price']) * x['buy']
        x['profit'] = round(x['profit'],3)
        x['Open'] = round(x['Open'], 3)
        x = x.sort_values(by='profit', ascending=False)

        print (x)

        r = x['profit'].sum() / x['buy'].sum()
        print (f'num bets: {len(x.index)}')
        print (f'return: {r}')
        print ('\n\n\n')
        #sns.regplot(x['pred'], x['profit'])
        #plt.show()

if __name__ == "__main__":
    check_results()


from Project import Project
import argparse
from pythonosc import udp_client

search = "cat"

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip", default="192.168.1.145",
                        help="The ip of the OSC server")
    parser.add_argument("--port2", default=12000,
                        help="The port the OSC server is listening on")
    parser.add_argument("--port", type=int, default=7004,
                        help="The port the OSC server is listening on")
    args = parser.parse_args();

client = udp_client.SimpleUDPClient(args.ip, args.port)

client.send_message("/HA/Jackfreesound", search)

SimpleThings = Project(search, 10, 25)
SimpleThings.Haiku.display_haiku()


# Name: Kyrne Li
# OSU Email: liky@oregonstate.edu
# Course: CS261 - Data Structures
# Assignment: Assignment 6 - HashMap
# Due Date: 06/05/2022
# Description: Implementation of HashMap using Dynamic Arrays and HashEntry

from a6_include import (DynamicArray, HashEntry,
                        hash_function_1, hash_function_2)

class HashMap:
    def __init__(self, capacity: int, function) -> None:
        """
        Initialize new HashMap that uses
        quadratic probing for collision resolution
        DO NOT CHANGE THIS METHOD IN ANY WAY
        """
        self._buckets = DynamicArray()
        for _ in range(capacity):
            self._buckets.append(None)

        self._capacity = capacity
        self._hash_function = function
        self._size = 0

    def __str__(self) -> str:
        """
        Override string method to provide more readable output
        DO NOT CHANGE THIS METHOD IN ANY WAY
        """
        out = ''
        for i in range(self._buckets.length()):
            out += str(i) + ': ' + str(self._buckets[i]) + '\n'
        return out

    def get_size(self) -> int:
        """
        Return size of map
        DO NOT CHANGE THIS METHOD IN ANY WAY
        """
        return self._size

    def get_capacity(self) -> int:
        """
        Return capacity of map
        DO NOT CHANGE THIS METHOD IN ANY WAY
        """
        return self._capacity

    # ------------------------------------------------------------------ #

    def put(self, key: str, value: object) -> None:
        """
        Updates a key/value pair in the hash map. If the given key already exists in the map, then it will
        replace the value. If it isn't in the hash map, then it will add the key/value pair. The table will be
        resized to double its capacity if the load factor >= .5.
        """
        # remember, if the load factor is greater than or equal to 0.5,
        # resize the table before putting the new key/value pair

        # checks if table load is under the required threshold of .5, if not double capacity
        if self.table_load() >= .5:
            self.resize_table(self.get_capacity() * 2)

        index = self._hash_function(key) % self.get_capacity()
        spot = self._buckets.get_at_index(index)

        # checks if the key exists in the hash map to replace value
        if self.contains_key(key) is True:
            for i in range(0, self.get_capacity()):
                current = self._buckets.get_at_index(i)
                if current is not None and current.is_tombstone is False and current.key == key:
                    current.value = value
                    return

        # current spot is open for putting at index
        if spot is None:
            self._buckets.set_at_index(index, HashEntry(key, value))
            self._size += 1

        # case for spot being a tombstone
        elif spot is not None and spot.is_tombstone is True:
            spot.key = key
            spot.value = value
            spot.is_tombstone = False
            self._size += 1

        else:
            for i in range(1, self._capacity):
                new_index = (index + (i ** 2)) % self._capacity
                new_spot = self._buckets.get_at_index(new_index)

                # new spot free for putting
                if new_spot is None:
                    self._buckets.set_at_index(new_index, HashEntry(key, value))
                    self._size += 1
                    return

                # case for new spot being a tombstone
                elif new_spot is not None and new_spot.is_tombstone is True:
                    print('2')
                    new_spot.key = key
                    new_spot.value = value
                    self._size += 1
                    new_spot.is_tombstone = False
                    return

    def table_load(self) -> float:
        """
        Returns the current hash table load factor.
        """
        return self.get_size()/self.get_capacity()

    def empty_buckets(self) -> int:
        """
        Returns the number of empty buckets in the hash map.
        """

        count = 0

        for i in range(0, self.get_capacity()):
            current = self._buckets.get_at_index(i)
            if current is None:
                count += 1

        return count

    def resize_table(self, new_capacity: int) -> None:
        """
        Changes the capacity of the internal hash table. All exists key/value pairs will be kept and
        all hash table links will be rehashed. If new_capacity is less than 1, this method does nothing.
        """
        # remember to rehash non-deleted entries into new table

        # check for new capacity to be over 0:
        if new_capacity < 1:
            return

        elif new_capacity < self.get_size():
            return

        new_table = DynamicArray()

        # copy contents from current buckets to new table for rehashing
        for i in range(0, self._capacity):
            new_table.append(self._buckets.get_at_index(i))

        # reset buckets and capacity
        self._buckets = DynamicArray()
        self._capacity = new_capacity
        for i in range(0, self.get_capacity()):
            self._buckets.append(None)
        self._size = 0

        for i in range(0, new_table.length()):
            current = new_table.get_at_index(i)
            if current is not None:
                if current.is_tombstone is False:
                    self.put(current.key, current.value)

    def get(self, key: str) -> object:
        """
        Returns the value associated with the given key, if the key is not in the hash table, then
        it returns None:
        """

        for i in range(0, self.get_capacity()):
            current = self._buckets.get_at_index(i)
            if current is not None and current.is_tombstone is False:
                if current.key == key:
                    return current.value

        return None

    def contains_key(self, key: str) -> bool:
        """
        Returns if the given key is in the hash map. If it doesn't exist, then it will return False.
        An empty hash map does not contain any keys.
        """

        if self.get_size() == 0:
            return False

        for i in range(0, self.get_capacity()):
            current = self._buckets.get_at_index(i)
            if current is not None and current.is_tombstone is False:
                if current.key == key:
                    return True

        return False

    def remove(self, key: str) -> None:
        """
        Removes the given key and its associated value from the hash map. if the key is not in the map,
        then this function does nothing
        """

        for i in range(0, self.get_capacity()):
            current = self._buckets.get_at_index(i)
            if current is not None and current.is_tombstone is False:
                if current.key == key:
                    current.is_tombstone = True
                    self._size -= 1
                    return None

        return None

    def clear(self) -> None:
        """
        Clears the current contents of the hash map, it will not change the underlying hash table
        capacity.
        """

        self._size = 0
        for i in range(0, self.get_capacity()):
            self._buckets.set_at_index(i, None)

    def get_keys(self) -> DynamicArray:
        """
        Returns a dynamic array containing all the keys in the hash map.
        """

        keys_array = DynamicArray()

        for i in range(0, self.get_capacity()):
            current = self._buckets.get_at_index(i)
            if current is not None:
                if current.is_tombstone is False:
                    keys_array.append(current.key)

        return keys_array

# ------------------- BASIC TESTING ---------------------------------------- #

if __name__ == "__main__":

    # print("\nPDF - put example 1")
    # print("-------------------")
    # m = HashMap(50, hash_function_1)
    # for i in range(150):
    #     m.put('str' + str(i), i * 100)
    #     if i % 25 == 24:
    #         print(m.empty_buckets(), m.table_load(), m.get_size(), m.get_capacity())
    #
    # print("\nPDF - put example 2")
    # print("-------------------")
    # m = HashMap(40, hash_function_2)
    # for i in range(50):
    #     m.put('str' + str(i // 3), i * 100)
    #     if i % 10 == 9:
    #         print(m.empty_buckets(), m.table_load(), m.get_size(), m.get_capacity())
    #
    # print("\nPDF - table_load example 1")
    # print("--------------------------")
    # m = HashMap(100, hash_function_1)
    # print(m.table_load())
    # m.put('key1', 10)
    # print(m.table_load())
    # m.put('key2', 20)
    # print(m.table_load())
    # m.put('key1', 30)
    # print(m.table_load())
    #
    # print("\nPDF - table_load example 2")
    # print("--------------------------")
    # m = HashMap(50, hash_function_1)
    # for i in range(50):
    #     m.put('key' + str(i), i * 100)
    #     if i % 10 == 0:
    #         print(m.table_load(), m.get_size(), m.get_capacity())
    #
    # print("\nPDF - empty_buckets example 1")
    # print("-----------------------------")
    # m = HashMap(100, hash_function_1)
    # print(m.empty_buckets(), m.get_size(), m.get_capacity())
    # m.put('key1', 10)
    # print(m.empty_buckets(), m.get_size(), m.get_capacity())
    # m.put('key2', 20)
    # print(m.empty_buckets(), m.get_size(), m.get_capacity())
    # m.put('key1', 30)
    # print(m.empty_buckets(), m.get_size(), m.get_capacity())
    # m.put('key4', 40)
    # print(m.empty_buckets(), m.get_size(), m.get_capacity())
    #
    # print("\nPDF - empty_buckets example 2")
    # print("-----------------------------")
    # m = HashMap(50, hash_function_1)
    # for i in range(150):
    #     m.put('key' + str(i), i * 100)
    #     if i % 30 == 0:
    #         print(m.empty_buckets(), m.get_size(), m.get_capacity())
    #
    # print("\nPDF - resize example 1")
    # print("----------------------")
    # m = HashMap(20, hash_function_1)
    # m.put('key1', 10)
    # print(m.get_size(), m.get_capacity(), m.get('key1'), m.contains_key('key1'))
    # m.resize_table(30)
    # print(m.get_size(), m.get_capacity(), m.get('key1'), m.contains_key('key1'))
    #
    # print("\nPDF - resize example 2")
    # print("----------------------")
    # m = HashMap(75, hash_function_2)
    # keys = [i for i in range(1, 1000, 13)]
    # for key in keys:
    #     m.put(str(key), key * 42)
    # print(m.get_size(), m.get_capacity())
    #
    # for capacity in range(111, 1000, 117):
    #     m.resize_table(capacity)
    #
    #     if m.table_load() >= 0.5:
    #         print("Check that capacity gets updated during resize(); "
    #               "don't wait until the next put()")
    #
    #     m.put('some key', 'some value')
    #     result = m.contains_key('some key')
    #     m.remove('some key')
    #
    #     for key in keys:
    #         # all inserted keys must be present
    #         result &= m.contains_key(str(key))
    #         # NOT inserted keys must be absent
    #         result &= not m.contains_key(str(key + 1))
    #     print(capacity, result, m.get_size(), m.get_capacity(), round(m.table_load(), 2))
    #
    # print("\nPDF - get example 1")
    # print("-------------------")
    # m = HashMap(30, hash_function_1)
    # print(m.get('key'))
    # m.put('key1', 10)
    # print(m.get('key1'))
    #
    # print("\nPDF - get example 2")
    # print("-------------------")
    # m = HashMap(150, hash_function_2)
    # for i in range(200, 300, 7):
    #     m.put(str(i), i * 10)
    # print(m.get_size(), m.get_capacity())
    # for i in range(200, 300, 21):
    #     print(i, m.get(str(i)), m.get(str(i)) == i * 10)
    #     print(i + 1, m.get(str(i + 1)), m.get(str(i + 1)) == (i + 1) * 10)
    #
    # print("\nPDF - contains_key example 1")
    # print("----------------------------")
    # m = HashMap(10, hash_function_1)
    # print(m.contains_key('key1'))
    # m.put('key1', 10)
    # m.put('key2', 20)
    # m.put('key3', 30)
    # print(m.contains_key('key1'))
    # print(m.contains_key('key4'))
    # print(m.contains_key('key2'))
    # print(m.contains_key('key3'))
    # m.remove('key3')
    # print(m.contains_key('key3'))
    #
    # print("\nPDF - contains_key example 2")
    # print("----------------------------")
    # m = HashMap(75, hash_function_2)
    # keys = [i for i in range(1, 1000, 20)]
    # for key in keys:
    #     m.put(str(key), key * 42)
    # print(m.get_size(), m.get_capacity())
    # result = True
    # for key in keys:
    #     # all inserted keys must be present
    #     result &= m.contains_key(str(key))
    #     # NOT inserted keys must be absent
    #     result &= not m.contains_key(str(key + 1))
    # print(result)
    #
    print("\nPDF - remove example 1")
    print("----------------------")
    m = HashMap(50, hash_function_1)
    print(m.get('key1'))
    m.put('key1', 10)
    print(m.get('key1'))
    m.remove('key1')
    print(m.get('key1'))
    m.remove('key4')
    #
    # print("\nPDF - clear example 1")
    # print("---------------------")
    # m = HashMap(100, hash_function_1)
    # print(m.get_size(), m.get_capacity())
    # m.put('key1', 10)
    # m.put('key2', 20)
    # m.put('key1', 30)
    # print(m.get_size(), m.get_capacity())
    # m.clear()
    # print(m.get_size(), m.get_capacity())
    #
    # print("\nPDF - clear example 2")
    # print("---------------------")
    # m = HashMap(50, hash_function_1)
    # print(m.get_size(), m.get_capacity())
    # m.put('key1', 10)
    # print(m.get_size(), m.get_capacity())
    # m.put('key2', 20)
    # print(m.get_size(), m.get_capacity())
    # m.resize_table(100)
    # print(m.get_size(), m.get_capacity())
    # m.clear()
    # print(m.get_size(), m.get_capacity())
    #
    # print("\nPDF - get_keys example 1")
    # print("------------------------")
    # m = HashMap(10, hash_function_2)
    # for i in range(100, 200, 10):
    #     m.put(str(i), str(i * 10))
    # print(m.get_keys())
    #
    # m.resize_table(1)
    # print(m.get_keys())
    #
    # m.put('200', '2000')
    # m.remove('100')
    # m.resize_table(2)
    # print(m.get_keys())


"""Implementation of estimators that select features."""
from typing import List, Optional, Tuple

import dask.dataframe as daskdf
import networkx as nx
import numpy as np
import pandas as pd
import scipy.stats as stats
from py4ai.data.model.ml import PandasDataset
from dask.multiprocessing import get
from psutil import cpu_count
from typeguard import typechecked
from typing_extensions import Literal

from py4ai.analytics.ml.core import Estimator, Numeric
from py4ai.analytics.ml.core.enricher.transformer.discretizer import toMultiLevels
from py4ai.analytics.ml.core.enricher.transformer.selector import FeatureSelector
from py4ai.analytics.ml.eda.general import computeCorrelation, filterColumnsWith

Correlations = Literal["absolute", "positive", "negative"]

class DeleteConstantFeatures(Estimator):
    """Remove features with ratio between standard deviation and mean less than a defined threshold."""

    def __init__(self, threshold: Numeric = 0) -> None:
        """
        Class instance initializer.

        :param threshold: threshold for the standard deviation of features
        """
        self.threshold = threshold

    @typechecked
    def train(self, dataset: PandasDataset) -> FeatureSelector:
        """
        Select columns to keep and drop.

        :param dataset: Dataset instance with features and labels

        :return: FeatureSelector Transformer
        """
        X = dataset.features
        self.logger.debug("Deleting constant features...")
        to_drop = X.columns[X.std() <= self.threshold]
        to_keep = list(set(X.columns).difference(set(to_drop)))

        self.logger.info(
            "Number of columns dropped by EnhancedDeleteCostantFeatures: %d"
            % len(to_drop)
        )
        self.logger.debug(
            "EnhancedDeleteCostantFeatures dropped columns:\n%s"
            % ("\n".join(sorted(to_drop)))
        )

        return FeatureSelector(to_keep=to_keep, estimator=self)

class FilterOutNans(Estimator):
    """Drop columns with a number of nulls bigger than the selected threshold."""

    def __init__(self, percentage: Numeric = 0.05):
        """
        Class instance initializer.

        :param percentage: minimum percentage of NAs allowed in a column
        """
        self.percentage = percentage

    @typechecked
    def train(self, dataset: PandasDataset) -> FeatureSelector:
        """
        Select columns to keep and drop.

        :param dataset: Dataset instance with features and labels
        :return: FeatureSelector Transformer
        """
        X = dataset.features
        nans = X.isnull().sum() * 1.0 / X.shape[0]
        to_drop = list(nans[nans > self.percentage].index)
        to_keep = list(set(X.columns).difference(set(to_drop)))

        return FeatureSelector(to_keep=to_keep, estimator=self)

class SelectByCorrelation(Estimator):
    """Select features based on a correlation threshold."""

    _correlation_functions = {
        "absolute": lambda x: np.abs(x),
        "positive": lambda x: x,
        "negative": lambda x: -x,
    }

    def __init__(
        self,
        threshold: Numeric = 0.4,
        correlation: Correlations = "absolute",
        start: Optional[str] = None,
        end: Optional[str] = None,
    ):
        """
        Class instance initializer.

        :param threshold: minimum correlation threshold to select variables
        :param correlation: function to apply to calculate correlation one of "absolute", "positive" or "negative". Default "absolute"
        :param start: start date to apply correlation function
        :param end: end date to apply correlation function
        """
        self.threshold = threshold
        self.start = start
        self.end = end
        self._f = self._correlation_functions[correlation]

    @typechecked
    def train(self, dataset: PandasDataset) -> FeatureSelector:
        """
        Select columns to keep and drop.

        :param dataset: Dataset instance with features and labels
        :return: FeatureSelector Transformer
        """
        x = dataset.features
        y = dataset.labels

        if type(x) == pd.DataFrame:
            x_ = x[slice(self.start, self.end)].copy()
        else:
            x_ = pd.DataFrame(x)[slice(self.start, self.end)]

        if type(y) == pd.DataFrame:
            y_ = y[slice(self.start, self.end)].copy()
        else:
            y_ = pd.DataFrame(y, index=x.index)[slice(self.start, self.end)]

        correlations = computeCorrelation(x_, y_).applymap(self._f)

        # Max correlations along rows
        maxCorrelations = correlations.max(axis=1)
        self.correlations = maxCorrelations

        to_keep = maxCorrelations[maxCorrelations > self.threshold].index

        # self.logger.info("Number of columns dropped by SelectByCorrelation: %d" % len(to_drop))
        # self.logger.debug("SelectByCorrelation dropped columns:\n%s" % ("\n".join(sorted(to_drop))))

        return FeatureSelector(to_keep=to_keep, estimator=self)

class SelectorFromSubstrings(Estimator):
    """Select columns with given substings in their name."""

    def __init__(self, strlist: List[str]):
        """
        Class instance initializer.

        :param strlist: list of strings
        """
        self.strlist = strlist

    @typechecked
    def train(self, dataset: PandasDataset) -> FeatureSelector:
        """
        Select columns to keep and drop.

        :param dataset: Dataset instance with features and labels
        :return: FeatureSelector Transformer
        """
        X = dataset.features
        to_keep = filterColumnsWith(X, self.strlist).columns

        # self.logger.info("Number of columns dropped by SelectFromSubstrings: %d" % len(to_drop))
        # self.logger.debug("SelectorFromSubstrings dropped columns:\n%s" % ("\n".join(sorted(to_drop))))

        return FeatureSelector(to_keep=to_keep, estimator=self)

class SelectByKL(Estimator):
    """Select features depending on the Kullback-Leibler divergence.

    Select features depending on the Kullback-Leibler divergence between the distribution of under the two levels of the
    target variable. The ratio is to drop features that to not exhibit particularly different distribution under the two
    levels of the target variables.
    """

    def __init__(
        self, kl_thresh: Numeric = 1.0, y_thresh: Optional[Numeric] = None
    ) -> None:
        """
        Class instance initializer.

        :param kl_thresh: threshold on KL divergence. Drop columns if KL divergence is greater than thresh
        :param y_thresh: threshold to discretize the target variable (in case it is not already discrete)
        """
        self.kl_thresh = kl_thresh
        self.y_thresh = y_thresh
        self.divergences01: Optional[PandasDataset] = None

    @staticmethod
    def _compute_divergences(x: pd.Series, y: pd.Series) -> float:
        """
        Compute KL between x series when y is 0 and when y is 1.

        :param x: feature series
        :param y: target series
        :return: KL divergence
        """
        yvals = np.unique(y)
        points = np.linspace(x.min(), x.max(), max((x.max() - x.min()) * 2, 100))

        if x.std() == 0:  # If the feature is constant, we drop it
            out = 0.0
        elif len(np.unique(x[y == yvals[0]])) == 1:
            # If the feature is constant where the target is not interesting it means that it is not constant where the
            # target is interesting and thus we keep it
            out = np.inf
        elif len(np.unique(x[y == yvals[1]])) == 1:
            # If the feature is constant where the target is interesting it means that it is not constant where the
            # target is not interesting.
            # Thus we check if that value is common where the target is not interesting and, if it is, we drop it.
            if (
                sum(x[y == yvals[0]] == np.unique(x[y == yvals[1]])[0])
                * 1.0
                / len(x[y == yvals[0]])
                > 0.3
            ):
                out = 0.0
            else:
                out = np.inf
        else:
            out = stats.entropy(
                stats.kde.gaussian_kde(x[y == yvals[0]].values.ravel())(points),
                stats.kde.gaussian_kde(x[y == yvals[1]].values.ravel())(points),
            )

        return out

    @typechecked
    def train(self, dataset: PandasDataset) -> FeatureSelector:
        """
        Select columns to keep and drop.

        :param dataset: Dataset instance with features and labels
        :return: FeatureSelector Transformer
        """
        cleaned = dataset.dropna().intersection()

        if len(cleaned) != len(dataset):
            self.logger.warning(
                f"{type(self)}: Training Set has nan values which has been dropped from the training"
            )

        X, y = cleaned.features, cleaned.labels

        if self.y_thresh is not None:
            y = toMultiLevels(y, self.y_thresh)

        if len(np.unique(y)) == 2:
            dX = daskdf.from_pandas(X.T, npartitions=cpu_count() * 2)
            self.divergences01 = dX.apply(
                (lambda x: self._compute_divergences(x, y)), axis=1
            ).compute(get=get)
            to_drop = list(
                self.divergences01[self.divergences01.values < self.kl_thresh].index
            )
        else:
            to_drop = []
        to_keep = list(set(X.columns).difference(to_drop))

        return FeatureSelector(to_keep=to_keep, estimator=self)

class DeleteDuplicates(Estimator):
    """Keep only the most correlated with the target of a set of highly correlated features."""

    def __init__(
        self,
        threshold: Numeric = 0.9,
        min_threshold: Numeric = 0.8,
        step: Numeric = 0.1,
    ):
        """
        Class instance initializer.

        :param threshold: minimum value to consider features to be deleted
        :param min_threshold: min_threshold for graph correlation
        :param step: step used to increase threshold
        """
        self.threshold = threshold
        self.min_threshold = min_threshold
        self.step = step

    def _most_correlated(self, X: pd.DataFrame, y: pd.DataFrame) -> Tuple[str, float]:
        """
        Calculate the feature with the max correlation.

        :param X: pd.DataFrame with features
        :param y: pd.DataFrame with targets
        :return: tuple with the name of the variable and the value of correlation
        """
        corr = computeCorrelation(X, y).abs().max(axis=1)
        ret = (corr.idxmax(), corr.max())
        if len(corr) > 1:
            self.logger.info(
                f"Keeping \033[1m{ret[0]}\033[0m [{round(ret[1], 2)}] between {', '.join(corr.index)}"
            )
        return ret

    @staticmethod
    def _least_correlated_components(
        corr: pd.DataFrame, cols: List[str]
    ) -> Tuple[float, int]:
        """
        Calculate least correlated features.

        :param corr: corr matrix
        :param cols: columns to include in calculation
        :return: tuple with the name of the variable, the value of correlation and the number of cols considered
        """
        sub_corr = corr[cols].loc[cols].abs().min(axis=1)
        return sub_corr.min(), len(cols)

    def _graph_correlation(self, dataset: PandasDataset) -> PandasDataset:
        """
        Get list with columns to drop based on the thresholds selected.

        :param dataset: input dataset
        :return: new dataset with removed columns
        """
        corrs = computeCorrelation(dataset.features).abs()
        thres = self.threshold
        self.logger.info(f"Initial pruning threshold: {self.threshold}")
        to_keep = dataset.features.columns

        check = False
        ith = 0
        while not check:
            ith += 1
            self.logger.debug("Iteration: %d" % ith)
            # Undirected Graph with edges given by correlations over threshold
            mat = corrs.applymap(lambda x: 1 if x > thres else 0)
            g = nx.Graph(mat.values)
            for icol, col in enumerate(mat.columns):
                g.nodes[icol].update({"name": col})

            # List of couples of least correlated features for each connected component
            minCorrs = [
                self._least_correlated_components(
                    corrs, [g.nodes[x]["name"] for x in group]
                )
                for group in nx.connected_components(g)
            ]

            self.logger.info(
                f"Number of non-singleton connected components: "
                f"{sum(map(lambda x: 1 if x[1] > 1 else 0, minCorrs))}"
            )
            self.logger.info(
                f"Total elements in non-sigleton connected components: "
                f"{sum(map(lambda x: x[1] if x[1] > 1 else 0, minCorrs))}"
            )
            self.logger.info(
                f"Number of connected components with minimal correlation under {self.min_threshold}: "
                f"{len([t for t in minCorrs if t[0] <= self.min_threshold])}"
            )

            # Check that all correlations are above a certain threshold
            check = all(map(lambda x: x[0] > self.min_threshold, minCorrs))
            self.logger.debug("check: " + str(check))

            if not check:
                thres = (1 - self.step) * thres + self.step
                self.logger.info(f"Updating threshold to: {thres}\n")
            else:
                to_keep = [
                    self._most_correlated(
                        dataset.features[[g.nodes[x]["name"] for x in group]],
                        dataset.labels,
                    )[0]
                    for group in nx.connected_components(g)
                ]
                self.logger.debug(f"Number of columns to keep: {len(to_keep)}")

        if set(to_keep) != set(dataset.features.columns):
            return self._graph_correlation(
                dataset.createObject(dataset.features[to_keep], dataset.labels)
            )
        else:
            return dataset

    @typechecked
    def train(self, dataset: PandasDataset) -> FeatureSelector:
        """
        Get the list of columns to drop based on the correlation function selected.

        :param dataset: input data
        :return: feature selector instance
        """
        outdataset = self._graph_correlation(
            DeleteConstantFeatures(threshold=0).train(dataset).transform(dataset)
        )

        self.logger.info(
            f"Number of columns to keep: {len(outdataset.features.columns)}"
        )
        self.logger.debug(
            "Columns to keep:\n%s" % ("\n".join(sorted(outdataset.features.columns)))
        )

        return FeatureSelector(
            to_keep=list(outdataset.features.columns), estimator=self
        )


import heapq

def solution(jobs):
    answer = []

    q = []
    arr = [[] for _ in range(2002)]
    t = 0 #작업 시작 가능 시간
    ans = 0 #총 대기시간

    for a, b in jobs:
        arr[a].append(b)

    for i in range(2002):
        ans += len(q)

        for a, b in i:
            heapq.heappush(q, b)

    return None
    '''
    * n초에 하는 작업

    n초까지 들어온 값을 heap에 삽입
    그리고 현재 작업중이 아니라면 끝나는 시간이 가장 빠른 녀석을 pop
    현재 시간 t
    매 초마다 heapq의 길이만큼 cnt += t
    '''

    return answer

#jobs = [[0, 3], [1, 9], [2, 6]]
jobs = [[0, 3], [1, 9], [4, 5], [2, 6]]
print(solution(jobs))


from inspect import cleandoc, isclass
from typing import Any, Callable, Iterable, TypeVar

class ModelInfo:
    __slots__ = ("title", "description")

    def __init__(self, obj: Any) -> None:
        try:
            schema = obj.schema()
        except Exception:
            cls = obj if isclass(obj) else type(obj)
            self.title = cls.__name__
            self.description = None if cls.__doc__ is None else cleandoc(cls.__doc__)
        else:
            self.title = schema["title"]
            self.description = schema.get("description", None)

    @property
    def gqldescription(self) -> str:
        # Strawberry only accepts strings as descriptions, but None should be used.
        return self.description  # type: ignore

_T = TypeVar("_T")

def multifilter(functions: Iterable[Callable[[_T], bool]], iterable: Iterable[_T]):
    return filter(lambda val: all(f(val) for f in functions), iterable)


__author__ = 'Administrator'

from pico2d import *
from Player import *
import random

class Ranger:

    PIXEL_PER_METER = (10.0 / 0.3)
    RUN_SPEED_KMPH = 20.0
    RUN_SPEED_MPM = (RUN_SPEED_KMPH * 1000.0 / 60.0)
    RUN_SPEED_MPS = (RUN_SPEED_MPM / 60.0)
    RUN_SPEED_PPS = (RUN_SPEED_MPS * PIXEL_PER_METER)

    TIME_PER_ACTION = 0.5
    ACTION_PER_TIME = 1.0 / TIME_PER_ACTION
    FRAMES_PER_ACTION = 8

    def __init__(self):

       #Base Setting
        self.frame = random.randint(0, 1)
        self.frame_x = 0
        self.frame_y = 0
        self.total_frames = 0.0
        self.dir = 1
        self.image = load_image('resource\\attack.png')
        self.x=300
        self.y=400
        self.distance = 0

    def update(self, frame_time):
        self.distance = Ranger.RUN_SPEED_PPS * frame_time
        #self.total_frames += Ranger.FRAMES_PER_ACTION * Ranger.ACTION_PER_TIME * frame_time
        self.x += self.distance
        self.draw()

    def draw(self):

      self.image.draw(self.x, self.y)

    def get_bb(self):
        return self.x-5.5,self.y-5.5,self.x+5.5,self.y+5.5

    def draw_bb(self):
        draw_rectangle(*self.get_bb())

    def collide(a,b):
        left_a, bottom_a, right_a, top_a = a.get_bb()
        left_b, bottom_b, right_b, top_b = b.get_bb()
        if left_a > right_b: return False
        if right_a < left_b: return False
        if top_a < bottom_b: return False
        if bottom_a > top_b: return False
        return True


import random
import numpy as np
from typing import List
from scipy.optimize import linprog
import utils

def chi(strings, i, j, a):
    if strings[i][j] == a:
        return 0
    return 1

def reconstruct_solution(m, Q, primary_reference_string, x_values, alphabet):
    A = len(alphabet)
    s_prime_as_list = ['' for _ in range(m)]
    p_index = 0
    for x_index in range(m):
        if x_index in Q:
            s_prime_as_list[x_index] = primary_reference_string[x_index]
        else:
            # For each position j we treat all of its a-solutions as the probability distribution
            # for picking the letter a, that is j: (xja1, xja2, ... xja|A|) is the distrib
            candidate_vars = x_values[p_index * A:(p_index + 1) * A]
            # print(f'x_values={x_values}', file=sys.stderr)
            # print(f'candidate vars={candidate_vars}', file=sys.stderr)
            # print(f'Candidate vars sum: {sum(candidate_vars)}')
            alph_idx = random.choices(range(len(candidate_vars)), k=1, weights=candidate_vars)[0]
            s_prime_as_list[x_index] = alphabet[alph_idx]
            p_index += 1

    s_prime = ''.join(s_prime_as_list)
    return s_prime

# Optimize on disagreeing positions
# P - disagreeing positions
# Q - agreeing positions
def solve_by_lp_relaxation(P, Q, alphabet, m, n, original_strings, primary_reference_string):
    LP_T_ = 'float64'

    A = len(alphabet)
    nP = len(P)

    # There are nP*A + 1 variables - nP*A for each xja, and 1 for d
    num_variables = nP*A + 1

    # ======================= CONSTRUCTING THE EQUALITY CONSTRAINTS ========================
    # There are nP constraints with equality
    lp_eq_matrix = np.zeros((nP, num_variables), dtype=LP_T_)
    # For each j we need an "exactly one" constraints
    # The constraint will have ones only within one j-group, and zeros on other positions
    # Therefore we iterate over j-groups
    for i in range(nP):
        left_bound = i*A
        right_bound = (i+1)*A
        lp_eq_matrix[i][left_bound:right_bound] = np.ones(A, dtype=LP_T_)

    # The ds are not in this part and they remain zeros since the matrix was constructed with np.zerps
    # RHS are all ones
    lp_eq_b = np.ones(nP, dtype=LP_T_)

    # ======================= CONSTRUCTING THE INEQUALITY CONSTRAINTS ======================
    # There are n inequality constraints
    # For x_j_a, its absolute position as a variable
    # is j*A + a
    lp_leq_matrix = np.zeros((n, num_variables), dtype=LP_T_)
    # Each of them has -1 coefficient with d, and those correspond to the very last column
    lp_leq_matrix[:, -1] = -np.ones(n, dtype=LP_T_)
    # Other coefficients are chi(i, j, a)
    for i in range(n):
        for a in range(A):
            for j in range(nP):
                actual_var_idx = j*A + a
                lp_leq_matrix[i][actual_var_idx] = chi(original_strings, i, j, alphabet[a])
    # RHS are -d(si|Q, s'|Q)
    lp_leq_b = -np.array([utils.hamming_distance(utils.sat(original_strings[i], Q), utils.sat(primary_reference_string, Q)) for i in range(n)], dtype='int32')

    # Target function is just 'd'
    c = np.zeros(num_variables, dtype=LP_T_)
    c[-1] = 1

    # Every variable must be positive
    lower_bounds = [0.0 for _ in range(num_variables)]
    # xs are constrainted by 1, d is unconstrained above
    upper_bounds: List[any] = [1.0 for _ in range(num_variables-1)] + [None]

    # Now we just plug it into scipy's solver
    # sout, serr = sys.stdout, sys.stderr
    # sys.stdout, sys.stderr = None, None
    lp_solution = linprog(c,
                          A_ub=lp_leq_matrix,
                          b_ub=lp_leq_b,
                          A_eq=lp_eq_matrix,
                          b_eq=lp_eq_b,
                          bounds=list(zip(lower_bounds, upper_bounds)))
    # sys.stdout, sys.stderr = sout, serr

    if not lp_solution.success:
        print('not stonks')
        return None

    # print(lp_solution)
    s_prime = reconstruct_solution(m, Q, primary_reference_string, lp_solution.x, alphabet)
    return s_prime, utils.problem_metric(s_prime, original_strings)


import datetime
from google.appengine.ext import ndb
from google.net.proto import ProtocolBuffer
from webob import exc
import common
import converters
from datastore import models, transactions
from util import  parse_csv, parse, util, currency_rates_util

class DoEditProfile(common.CommonHandler):
  def HandlePost(self, command):
    # TODO: check permissions
    profile_id = parse.ParseInt(self.request.get('profile_id'))
    name = self.request.get('name', None)
    main_currency = self.request.get('main_currency', None)

    # TODO: use JSON request
    kw = {}
    if name is not None:
      kw['name'] = name

    if command == 'add':
      kw['name'] = kw.get('name') or 'Untitled'
      main_currency = main_currency or 'USD'
      assert currency_rates_util.IsCurrencySupported(main_currency)
      kw['main_currency'] = main_currency
      profile = models.Profile.Create(self.visitor.key.id(), **kw)
      models.User.Update(
        self.visitor.key.id(), active_profile_id=profile.key.id())
    elif command == 'edit':
      profile = models.Profile.Update(profile_id, **kw)
    elif command == 'delete':
      assert profile_id is not None
      if profile_id == self.visitor.active_profile_id:
        models.User.Update(self.visitor.key.id(), active_profile_id=None)
      ndb.Key(models.Profile, profile_id).delete()
      profile = None
    else:
      raise ValueError('Command %r is not supported' % command)

    response = {'status': 'ok'}
    if profile:
      response['profile'] = converters.ConvertProfile(profile)
    return response

class DoSetActiveProfile(common.CommonHandler):
  def HandlePost(self):
    profile_id = parse.ParseInt(self.request.get('id'))

    if models.Profile.get_by_id(profile_id):
      models.User.Update(self.visitor.key.id(), active_profile_id=profile_id)
      return {'status': 'ok'}
    else:
      return {'status': 'profile_does_not_exist'}

class DoConnectToProfile(common.CommonHandler):
  def HandlePost(self):
    profile_code = self.request.get('profile_code')
    if not profile_code:
      raise exc.HTTPBadRequest('Profile code is not specified')

    try:
      profile = models.Profile.GetByCode(profile_code)
    except ProtocolBuffer.ProtocolBufferDecodeError:
      raise exc.HTTPBadRequest('Profile code %r can\'t be parsed' % profile_code)
    if not profile:
      raise exc.HTTPBadRequest('Profile for code %r does not exist' % profile_code)

    # TODO: ask the owner's permission.
    profile.AddUser(self.visitor.key.id())
    # TODO: create a helper function for this
    models.User.Update(
      self.visitor.key.id(), active_profile_id=profile.key.id())

    return {'status': 'ok'}

class DoEditAccount(common.CommonHandler):
  @common.active_profile_required
  def HandlePost(self, command):
    account_id = parse.ParseInt(self.request.get('account_id'))
    name = self.request.get('name', None)
    currency = self.request.get('currency', None)
    type = self.request.get('type', None)
    balance = parse.ParseFloat(self.request.get('balance'))

    # TODO: use JSON request
    kw = {}
    if name is not None:
      kw['name'] = name

    if command == 'add':
      kw['name'] = kw.get('name') or 'Untitled'
      if type == models.Account.Types.VIRTUAL and not currency:
        currency = self.profile.main_currency
      assert currency_rates_util.IsCurrencySupported(currency)
      kw['currency'] = currency
      if not type:
        type = models.Account.Types.PHYSICAL
      assert type in models.Account.Types.ALL
      kw['type'] = type

      account = self.profile.AddAccount(**kw)
    elif command == 'edit':
      assert account_id is not None
      account = self.profile.UpdateAccount(account_id, **kw)
    elif command == 'delete':
      assert account_id is not None
      self.profile.DeleteAccount(account_id)
      account = None
    else:
      raise ValueError('Command %r is not supported' % command)

    if account and balance is not None and abs(balance - account.balance) > 0.001:
      transactions.AddTransaction(
        self.profile.key.id(), balance - account.balance, util.DatetimeUTCNow(),
        description='Manual account balance adjust',
        dest_account_id=account.id, source='manual')
      self.ReloadProfile()

    response = {'status': 'ok'}
    if account:
      response['account'] = converters.ConvertAccount(
        self.profile.GetAccountById(account.id))
    return response

class DoEditTransaction(common.CommonHandler):
  @common.active_profile_required
  def HandlePost(self, command):
    amount = parse.ParseFloat(self.request.get('amount'))
    description = self.request.get('description')
    # TODO: use consistent date formats.
    raw_date = self.request.get('date')
    date = raw_date and datetime.datetime.strptime(raw_date, '%d.%m.%Y')
    transaction_id = parse.ParseInt(self.request.get('id'))

    if command == 'add':
      source_account_id = parse.ParseInt(self.request.get('source_account_id'))
      dest_account_id = parse.ParseInt(self.request.get('dest_account_id'))
      transaction = transactions.AddTransaction(
        self.profile.key.id(), amount, date, description=description,
        source_account_id=source_account_id, dest_account_id=dest_account_id,
        source=models.Transaction.Sources.MANUAL)
    elif command == 'edit':
      assert transaction_id is not None
      transaction = transactions.UpdateTransaction(
        self.profile.key.id(), transaction_id, amount, date, description=description)
    elif command == 'delete':
      assert transaction_id is not None
      transactions.DeleteTransaction(self.profile.key.id(), transaction_id)
      transaction = None
    else:
      raise ValueError('Command %r is not supported' % command)

    response = {'status': 'ok'}
    if transaction:
      response['transaction'] = converters.ConvertTransaction(transaction)
    return response

# Not tested

class DoAddParseSchema(common.CommonHandler):
  def HandlePost(self):
    name = self.request.get('name')
    schema = self.request.get('schema')

    self.profile.parse_schemas.append(
      models.ParseSchema(name=name, schema=schema))
    self.profile.put()

    self.WriteToJson({'status': 'ok'})

class DoApplyParseSchemaToImportedFile(common.CommonHandler):
  def HandlePost(self):
    imported_file_id = int(self.request.get('id'))
    schema = self.request.get('schema')

    imported_file = lookup.GetImportedFileById(self.profile, imported_file_id)
    imported_file.schema = schema
    imported_file.parsed = True
    imported_file.parsed_transactions = parse_csv.ParseCsv(
      imported_file.schema, imported_file.source_file)

    # For future performance
    imported_file.source_file = None
    imported_file.put()

    self.WriteToJson({'status': 'ok'})


from .models import Course, Session
from decimal import *
# import copy

def totalUnits(session_id):
    session = Session.objects.get(sid=session_id)
    units = 0
    for course in session.course_set.all():
        units += course.units
    return units

def totalQP(session_id):
    session = Session.objects.get(sid=session_id)
    qp = 0
    for course in session.course_set.all():
        units = course.units
        if(course.grade == "A"):
            gradeMultiplier = 4
        elif(course.grade == "B"):
            gradeMultiplier = 3
        elif(course.grade == "C"):
            gradeMultiplier = 2
        elif(course.grade == "D"):
            gradeMultiplier = 1
        else:
            gradeMultiplier = 0
        course.qp = units * gradeMultiplier
        course.save()
        qp += units * gradeMultiplier
    return qp

def calculateQPA(session_id):
    units = totalUnits(session_id)
    qp = totalQP(session_id)
    return Decimal(str(qp / units)).quantize(Decimal('.01'), rounding=ROUND_DOWN)

def raiseToQPA(session_id, finalQPA):
    """
    given a qpa to reach, raises grades of all courses(or lowers them) till the
    returned QPA is greater than the final (if it is above) or less than the final
    (if it is below.)
    """
    session = Session.objects.get(sid=session_id)
    courses = session.course_set.all()
    units = 0
    currGrades = dict()
    for course in courses:
        units += course.units
        # creates a dict with course names and their grade multipliers
        currGrades[course.courseName] = 4-(ord(course.grade)-65)
    # increases a single grade
    changedCourse = dict()
    for course in currGrades:
        if(currGrades[course]==4): #can't increase the grade if it's an A
            continue
        for i in range(4 - currGrades[course]):
            currGrades[course] += 1
            if(course not in changedCourse):
                changedCourse[course] = 0
            else:
                changedCourse[course] += 1
            if(testQPA(session_id, currGrades, finalQPA)):#currGrades, gradeList, finalQPA
                return currGrades
    for course in changedCourse:
        currGrades[course] -= changedCourse[course]
    return None

def calcDesiredQPA(session_id, gradeList, finalQPA):
    qp = 0
    units = 0
    session = Session.objects.get(sid=session_id)
    for course in session.course_set.all():
        qp += course.units * gradeList[course.courseName]
        units += course.units
    qpa = qp / units
    print("\n\nQPA:%4.2f\n\n" % qpa)
    qpa = float(Decimal(str(qpa)).quantize(Decimal("0.01")))
    return qpa

def testQPA(session_id, gradeList, finalQPA):
    qpa = calcDesiredQPA(session_id, gradeList, finalQPA)
    if(qpa >= finalQPA):
        return True
    return False


result = 0
cont = 0

for cont_n in range(0,6):
    num = int(input('Digite um número '))
    if num % 2 == 0:
        result = result + num
        cont += 1
print('Você digitou {} PARES e a soma deles é {}'.format(cont,result))


print('-'*40)
print('{:^40}'.format('CADASTRO DE PESSOA FISICA'))
print('-'*40)
homens = mulheres = maiores = 0
while True:
    sexo = ' '
    continuar = ' '
    idade = int(input('Idade: '))
    while sexo not in 'MF':
        sexo = str(input('Sexo: [M/F] ')).strip().upper()[0]
    print('-' * 40)
    if idade >= 18:
        maiores += 1
    if sexo in 'M':
        homens += 1
    if sexo in 'F' and idade < 20:
        mulheres += 1
    while continuar not in 'SN':
        continuar = str(input('Quer continuar: [S/N] ')).strip().upper()[0]
    print('-' * 40)
    if continuar in 'N':
        break
print(f'Total de pessoas com mais de 18 anos: {maiores}')
print(f'Ao todo temos {homens} homens cadastrados.')
print(f'Temos {mulheres} mulheres com menos de 20 anos.')


import urllib2

import tornado.web
import tornado.ioloop

from config import settings
from core.utils import show_urls
from core.utils import show_words
from core.utils import url_save_to_db
from core.utils import words_save_to_db
from core.utils import html_body_to_list_text

class WebPageProcessing(tornado.web.RequestHandler):
    def get(self):
        data = {}
        self.render("templates/main.html", data=data)

    def post(self):
        data = {}
        url = self.get_argument('url')
        req = urllib2.Request(url)
        try:
            html = urllib2.urlopen(req).read()
        except ValueError:
            data['error'] = {
                'msg': 'Please Enter a valid URL!'
            }
            self.render("templates/main.html", data=data)
        # Process words based on questionario
        process_words = html_body_to_list_text(html)

        # Save to DB
        words_save_to_db(process_words[:100])
        result_url = url_save_to_db(url, process_words[:100])
        data['words'] = process_words[:100]
        data['result_url'] = result_url
        self.render("templates/main.html", data=data)

class DashboardAdmin(tornado.web.RequestHandler):
    def get(self, mode=None):
        data = {}
        if mode == 'words':
            data['words'] = show_words()
        elif mode == 'urls':
            data['urls'] = show_urls()
        data['mode'] = mode

        self.render("templates/dashboard.html", data=data)

application = tornado.web.Application(
    [
        (r"/", WebPageProcessing),
        (r"/dashboard/([^/]*)", DashboardAdmin),
    ],
    **settings
)

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()


from tkinter import *
import csv
from os import chdir
# chdir(r"C:\Users\fabie\Documents\JDR\Entre l'Empire et l'Enfer\Programme BattleMap\Données")

InfoCarte=[] #On définie la liste qui organise le csv
with open("TableauValeurs.csv") as fichier :
    spamreader=csv.reader(fichier, delimiter=';',quotechar='"')
    for row in spamreader:
        InfoCarte.append(row)
    fichier.close
print(InfoCarte)

class Battlemaps():
    def __init__(self,fond,TailleX,TailleY):
        self.fenetre=Toplevel()
        self.liste_ob=[]
        self.carte=fond
        self.largeur=TailleX
        self.hauteur=TailleY                                                                        #Def standart d'un canvas
        self.can=Canvas(self.fenetre, width=self.largeur, height=self.hauteur, bg='black')
        self.can.grid(row=0, column=0)
        self.WP=PhotoImage(file=self.carte, master=self.fenetre)
        self.can.create_image(0,0,anchor=NW,image=self.WP)
        self.frame_bouton=Frame(self.fenetre,bg='#b23519')
        self.frame_bouton.grid(row=1, column=0)
        self.Boutons()

        self.can.bind('<Button-1>',self.clic)
        self.fenetre.mainloop()

    def Boutons(self):      #Chaque fonction lance une battlemap (et seulement la carte)
        bouton_Sortie=Button(self.frame_bouton,fg='grey',font='CasablancaAntique',activebackground="white", text="Quitter", command=self.fenetre.destroy)
        bouton_Sortie.grid(row=1, column=1, padx=20, pady=5)

        bouton_Nec=Button(self.frame_bouton,fg='grey',font='CasablancaAntique',activebackground="white", text="Entrée", command=self.Entree)
        bouton_Nec.grid(row=1, column=2, padx=20, pady=5)

        bouton_Nocs=Button(self.frame_bouton,fg='grey',font='CasablancaAntique',activebackground="white", text="Les Nocturnes", command=self.Necropolis)
        bouton_Nocs.grid(row=1, column=3, padx=20, pady=5)

        bouton_CI=Button(self.frame_bouton,fg='grey',font='CasablancaAntique',activebackground="white", text="Marche !", command=self.CampImp)
        bouton_CI.grid(row=1, column=4, padx=20, pady=5)

        bouton_ALP=Button(self.frame_bouton,fg='grey',font='CasablancaAntique',activebackground="white", text="La Brume", command=self.CampNuit)
        bouton_ALP.grid(row=1, column=5, padx=20, pady=5)

    def Entree(self):
        Battlemaps(InfoCarte[2][1],InfoCarte[2][2],InfoCarte[2][3])

    def Necropolis(self):
        Battlemaps(InfoCarte[3][1],InfoCarte[3][2],InfoCarte[3][3])

    def CampImp(self):
        Battlemaps(InfoCarte[4][1],InfoCarte[4][2],InfoCarte[4][3])

    def CampNuit(self):
        Battlemaps(InfoCarte[5][1],InfoCarte[5][2],InfoCarte[5][3])

    def clic(self,event):
        x,y=event.x,event.y
        liste_indice=self.can.find_overlapping(x,y,x+5,y+5) #♦On trouve tous les objets autour du clic
        for i in liste_indice :
            if i>1: #nb de cases
                self.selection=i #l'indice de la pièce sélectionnée
                self.can.bind('<Motion>',self.drag) # association du mouvement de la souris
                self.piec=trouver_objet(self.liste_ob,i)

    def drag(self,event):
        self.can.coords(self.selection,event.x,event.y) #on bouge la  au fur et à mesure
        self.can.bind('<ButtonRelease-1>',self.unclick)

    def unclick(self,event):
        x,y=event.x,event.y
        indice=self.can.find_overlapping(x,y,x+5,y+5)
        self.piec.MAJ_xy(x,y,self.can)
        self.can.unbind('<Motion>') #on désassocie le mouvement de la souris

def trouver_objet(liste_ob,indice): #Fonction qui sert à permettre le unbind
    for ob in liste_ob:
        if ob.indice==indice :
            return ob
class objet():
    def __init__(self,x=0,y=0,nf=''):
        self.x=x
        self.y=y
        self.nom_fichier=nf

    def MAJ_xy(self,x,y,can):
        self.x=x
        self.y=y
        can.coords(self.indice,self.x,self.y)

    def MAJ_position(self,ij):
        self.ij=ij

    def creation_image(self,can):
        self.fichier=self.nom_fichier
        self.img=PhotoImage(file=self.fichier)
        self.indice=can.create_image(self.x,self.y,anchor=CENTER,image=self.img)

Battlemaps(InfoCarte[1][1],InfoCarte[1][2],InfoCarte[1][3])
# Jaskier=objet(300,450,nf="dandelion.png")
# self.liste_ob.append(Jaskier)
# Jaskier.creation_image(self.can)                  #Lignes type pour placer un objet


#! /usr/bin/env python3

import rospy
from sensor_msgs.msg import LaserScan

def callback(data):
    print(min(data.ranges))

rospy.init_node("Laser_Sub")
rospy.Subscriber("/laser/scan", LaserScan, callback)
rospy.spin()


def visualize(cnn_model):

    import matplotlib.pyplot as plt

    # summarize history for accuracy
    plt.plot(cnn_model.history['accuracy'])
    plt.plot(cnn_model.history['val_accuracy'])
    plt.title('Model Accuracy')
    plt.ylabel('Accuracy')
    plt.xlabel('Epochs')
    plt.legend(['Train', 'Validation'], loc='lower left')
    plt.show()

    # summarize history for loss
    plt.plot(cnn_model.history['loss'])
    plt.plot(cnn_model.history['val_loss'])
    plt.title('Model Loss')
    plt.ylabel('Loss')
    plt.xlabel('Epochs')
    plt.legend(['Train', 'Validation'], loc='upper left')
    plt.show()


import random
from words_and_drawings import words
from words_and_drawings import drawings

#game logic
def game_loop():
    word = random.choice(words).upper()
    hidden_word = "_" * len(word)
    guessed_letters = []
    num_wrong_guesses = 0
    limit = 6

    print("Welcome to HANGMAN, let's begin!")
    print_hangman(num_wrong_guesses, hidden_word)
    while hidden_word != word and num_wrong_guesses < limit:

        guess = input("Guess a letter \n=>").upper()

        if len(guess) == 1 and guess.isalpha():
            if guess in guessed_letters:
                print("You already guessed this letter, try again.")
                guessed_letters.append(guess)
            if guess not in word:
                print("Wrong guess,", guess, "is not in the word.")
                num_wrong_guesses += 1
            else:
                print("Good guess,", guess, "is in the word")
                guessed_letters.append(guess)
                for x in find(word, guess):
                    hidden_word = hidden_word[:x] + guess + hidden_word[x+1:]

        elif len(guess) == len(word) and guess.isalpha():
            if word == guess:
                hidden_word = word
            else:
                print("Wrong guess,", guess, "is not the correct word.")
                num_wrong_guesses += 1

        else:
            print("Invalid guess, please try again.")

        print_hangman(num_wrong_guesses, hidden_word)

    if hidden_word == word:
        print("Good Job, you correctly guessed", word)
    else:
        print("The word was", word, ". Better luck next time!")

def find(str, c):
    return [i for i, letter in enumerate(str) if letter == c]

#prints current state of the hangman and word
def print_hangman(drawing_progress, word_progress):
    print(drawings[drawing_progress])
    print(word_progress, "\n\n")

if __name__ == '__main__':
    game_loop()


Q_T = 2

class Process:
    def __init__(self, id, at, bt):
        self.id = id
        self.at = at
        self.bt = bt
        self.wt = -1
        self.ct = -1
        self.st = -1
        self.tat = -1
        self.rt = bt

    def fill(self):
        print('Process completed:', self.id)
        self.tat = self.ct - self.at
        self.wt = self.tat - self.bt
        return self.ct

    def execute(self, now):
        print('Current process:', self.id)
        if self.st == -1:
            self.st = now
        if self.rt <= Q_T:
            self.ct = self.rt + now
            self.rt = 0
            self.fill()
            return self.ct
        else:
            self.rt -= Q_T
            return now + Q_T

    def print(self):
        st = '\t'.join(map(str, [self.id, self.at, self.bt, self.st, self.rt, self.ct, self.tat, self.wt]))
        print(st)

    @classmethod
    def display(cls, process_list):
        print('ID\tAT\tBT\tST\tRT\tCT\tTAT\tWT')
        for process in process_list:
            process.print()
        print('----------------------')

if __name__ == '__main__':
    # n = int(input("Enter the number of processes: "))
    # print("Enter the process and their details in the format ID AT BT")
    l = [
        [1, 0, 5],
        [2, 1, 4],
        [3, 2, 2],
        [4, 3, 1],
    ]
    n = len(l)
    processes = []

    for p in l:
        processes.append(Process(*p))
    Process.display(processes)
    print('Sorting.')
    processes.sort(key=lambda x: x.at)
    Process.display(processes)
    min_at = processes[0].at
    max_at = processes[-1].at
    i = 0
    t = min_at
    flag = True
    while flag:
        flag = False
        for process in processes:
            if process.rt > 0:
                print('T =', t)
                t = process.execute(t)
                Process.display(processes)
                flag = True

    Process.display(processes)


"""
--- Day 6: Custom Customs ---
As your flight approaches the regional airport where you'll switch to a much larger plane, customs declaration forms are distributed to the passengers.

The form asks a series of 26 yes-or-no questions marked a through z. All you need to do is identify the questions for which anyone in your group answers "yes". Since your group is just you, this doesn't take very long.

However, the person sitting next to you seems to be experiencing a language barrier and asks if you can help. For each of the people in their group, you write down the questions for which they answer "yes", one per line. For example:

abcx
abcy
abcz
In this group, there are 6 questions to which anyone answered "yes": a, b, c, x, y, and z. (Duplicate answers to the same question don't count extra; each question counts at most once.)

Another group asks for your help, then another, and eventually you've collected answers from every group on the plane (your puzzle input). Each group's answers are separated by a blank line, and within each group, each person's answers are on a single line. For example:

abc

a
b
c

ab
ac

a
a
a
a

b
This list represents answers from five groups:

The first group contains one person who answered "yes" to 3 questions: a, b, and c.
The second group contains three people; combined, they answered "yes" to 3 questions: a, b, and c.
The third group contains two people; combined, they answered "yes" to 3 questions: a, b, and c.
The fourth group contains four people; combined, they answered "yes" to only 1 question, a.
The last group contains one person who answered "yes" to only 1 question, b.
In this example, the sum of these counts is 3 + 3 + 3 + 1 + 1 = 11.

For each group, count the number of questions to which anyone answered "yes". What is the sum of those counts?

--- Part Two ---
As you finish the last group's customs declaration, you notice that you misread one word in the instructions:

You don't need to identify the questions to which anyone answered "yes"; you need to identify the questions to which everyone answered "yes"!

Using the same example as above:

abc

a
b
c

ab
ac

a
a
a
a

b
This list represents answers from five groups:

In the first group, everyone (all 1 person) answered "yes" to 3 questions: a, b, and c.
In the second group, there is no question to which everyone answered "yes".
In the third group, everyone answered yes to only 1 question, a. Since some people did not answer "yes" to b or c, they don't count.
In the fourth group, everyone answered yes to only 1 question, a.
In the fifth group, everyone (all 1 person) answered "yes" to 1 question, b.
In this example, the sum of these counts is 3 + 0 + 1 + 1 + 1 = 6.

For each group, count the number of questions to which everyone answered "yes". What is the sum of those counts?

"""

def get_yes_answers(grp_ans):
    yes_answers = []
    for ans in grp_ans:
        if not ans in yes_answers and not ans == '\n':
            yes_answers.append(ans)
    return len(yes_answers)

def get_all_yes_ans(grp_arr):
    # if only one person answered, return all his yes's
    if len(grp_arr) == 1:
        return get_yes_answers(grp_arr[0])
    else:
        ans_list = []
        unanimous = []
        # get all the answers
        for i in range(0, len(grp_arr)):
            for ch in grp_arr[i]:
                if not ch == '\n':
                    ans_list.append(ch)
        # for all the answers, check to see if the length
        # equals the total number of people responding
        for ans in ans_list:
            if ans_list.count(ans) == len(grp_arr) and \
                not ans in unanimous:
                unanimous.append(ans)
        return len(unanimous)

if __name__ == "__main__":
    with open('day6.txt', 'r') as file:
        lines = file.readlines()
    yes_count = 0
    unanimous_count = 0
    grp_ans = ""
    grp_arr = []

    for line in lines:
        if line != '\n':
            grp_ans += line
            grp_arr.append(line)
        else:
            yes_count += get_yes_answers(grp_ans)
            unanimous_count += get_all_yes_ans(grp_arr)
            grp_arr.clear()
            grp_ans = ''
    print("# of yes ans=", yes_count)
    print('# of unanimous ans=', unanimous_count)


import tkinter as tk
import tkinter.font as tkFont

class App:
    def __init__(self, root):
        #setting title
        root.title("undefined")
        #setting window size
        width=519
        height=143
        screenwidth = root.winfo_screenwidth()
        screenheight = root.winfo_screenheight()
        alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
        root.geometry(alignstr)
        root.resizable(width=False, height=False)

        GLabel_18=tk.Label(root)
        ft = tkFont.Font(family='Times',size=10)
        GLabel_18["font"] = ft
        GLabel_18["fg"] = "#333333"
        GLabel_18["justify"] = "center"
        GLabel_18["text"] = "Fecha"
        GLabel_18.place(x=20,y=30,width=83,height=30)

        GLineEdit_854=tk.Entry(root)
        GLineEdit_854["borderwidth"] = "1px"
        ft = tkFont.Font(family='Times',size=10)
        GLineEdit_854["font"] = ft
        GLineEdit_854["fg"] = "#333333"
        GLineEdit_854["justify"] = "center"
        GLineEdit_854["text"] = ""
        GLineEdit_854.place(x=90,y=30,width=138,height=33)

        GLabel_983=tk.Label(root)
        ft = tkFont.Font(family='Times',size=10)
        GLabel_983["font"] = ft
        GLabel_983["fg"] = "#333333"
        GLabel_983["justify"] = "center"
        GLabel_983["text"] = "hora"
        GLabel_983.place(x=20,y=80,width=70,height=25)

        GLineEdit_526=tk.Entry(root)
        GLineEdit_526["borderwidth"] = "1px"
        ft = tkFont.Font(family='Times',size=10)
        GLineEdit_526["font"] = ft
        GLineEdit_526["fg"] = "#333333"
        GLineEdit_526["justify"] = "center"
        GLineEdit_526["text"] = ""
        GLineEdit_526.place(x=90,y=80,width=139,height=30)

        GLabel_495=tk.Label(root)
        ft = tkFont.Font(family='Times',size=10)
        GLabel_495["font"] = ft
        GLabel_495["fg"] = "#333333"
        GLabel_495["justify"] = "center"
        GLabel_495["text"] = "Pelicula"
        GLabel_495.place(x=280,y=30,width=70,height=25)

        GListBox_901=tk.Listbox(root)
        GListBox_901["borderwidth"] = "1px"
        ft = tkFont.Font(family='Times',size=10)
        GListBox_901["font"] = ft
        GListBox_901["fg"] = "#333333"
        GListBox_901["justify"] = "center"
        GListBox_901.place(x=360,y=80,width=140,height=30)

        GLabel_534=tk.Label(root)
        ft = tkFont.Font(family='Times',size=10)
        GLabel_534["font"] = ft
        GLabel_534["fg"] = "#333333"
        GLabel_534["justify"] = "center"
        GLabel_534["text"] = "salas"
        GLabel_534.place(x=280,y=80,width=70,height=25)

        GListBox_71=tk.Listbox(root)
        GListBox_71["borderwidth"] = "1px"
        ft = tkFont.Font(family='Times',size=10)
        GListBox_71["font"] = ft
        GListBox_71["fg"] = "#333333"
        GListBox_71["justify"] = "center"
        GListBox_71.place(x=360,y=30,width=145,height=30)
if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    root.mainloop()


import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
import numpy as np

X = np.linspace(-1, 11, num=100)
y = (X - 3)**2 + 3 * X - 12 + np.random.randn(100)
X = X.reshape(-1, 1)
plt.scatter(X, y)

X_test = np.linspace(-2, 12, num=200).reshape(-1, 1)
model_1 = LinearRegression()
model_1.fit(X, y)
y_test1 = model_1.predict(X_test)
plt.plot(X_test, y_test1, color='red')

# 升维
X = np.concatenate([X, X**2], axis=1)
model_2 = LinearRegression()
model_2.fit(X, y)
X_test2 = np.concatenate([X_test, X_test**2], axis=1)
y_test2 = model_2.predict(X_test2)
plt.plot(X_test2[:, 0], y_test2, color='green')
plt.show()


# -*- coding: utf-8 -*-
"""
Created on Mon Oct 19 00:29:34 2020

@author: wilfr
"""

#Sumar modo recursivo
def sumar(a, b):
    print(f"LLame a sumar {a} {b}")
    if b == 0:
        res = a
    else:
        res = 1 + sumar(a, b-1)

    return res

#Factorial
def factorial(n):
    if n == 1:
        res = 1
    else:
        res = n * factorial(n-1)

    return res

def es_impar(n, str_tab=""):
    if n == 0:
        print(f"{str_tab} llegue al cero")
        res = False
    else:
        print(f"{str_tab} para saber si {n} es impar, niego la paridad de uno menos")
        temp = es_impar(n-1, str_tab + "\t")
        res = not temp
        print(f"{str_tab} para saber si {n} obtuve es_impar({n-1})={temp} y lo negue para obtener {res}")

    return res

def maximo(lista, debug_extra_str=""):

    print(f"{debug_extra_str}Acabo de entrar con {lista}")
    if len(lista) == 1:
        res = lista[0]
        print(f"{debug_extra_str}En el caso base")
    else:
        primero = lista[0]
        max_del_resto = maximo(lista[1:], debug_extra_str+"\t")
        res = max(primero, max_del_resto)
        print(f"{debug_extra_str}Asigno res=max({primero}, maximo ({lista[1:]}))=max({primero}, {max_del_resto})={res}")

    print(f"{debug_extra_str}Devuelvo: {res}")
    return res

def permutaciones(lista):

    if len(lista) == 0:
        res = []

    elif len(lista) == 1:
        res = [lista]

    else:
        res = []
        for idx, elem in enumerate(lista):
            permut_resto = permutaciones(lista[:idx] + lista[idx+1:])
            res += [ [elem] + p for p in permut_resto ]

    return res