import pandas as pd

def convt_name(entry):
    i = entry.find('City Of ')
    if i!=-1:
        entry = entry[i+len('City Of '):] + ' City'
    i = entry.find('Del')
    if i!=-1:
        entry = entry[0:i]+entry[i:i+3].lower()+entry[i+3:]
    i = entry.find('De')
    if i!=-1:
        entry = entry[0:i]+entry[i:i+2].lower()+entry[i+2:]
    if entry == 'Cotabato (North Cot.)':
        return "North Cotabato"
    elif entry == 'Davao (Davao del Norte)':
        return 'Davao del Norte'
    elif entry == 'Compostela Valley':
        return 'Davao de Oro'
    elif entry == 'Manila City':
        return 'Manila'
    elif entry == 'Samar (Western Samar)':
        return 'Samar'
    elif entry == 'San Jose del Monte  City':
        return 'San Jose Del Monte City'
    elif entry == 'Lapu-Lapu City (Opon)':
        return 'Lapu-Lapu City'
    elif entry == 'Taguig City':
        return 'Taguig'
    return entry
def fix_case(entry):
    if type(entry) is float:
        return entry
    if entry[0] in [str(x) for x in range(10)]:
        entry = entry[0] + entry[1].lower() + entry[2:]
    return entry

df = pd.read_csv('comelec_elected.csv')
df['district'] = df[df['name'].str.contains('DISTRICT')]['name'].str.title()
df['district'] = df['district'].fillna(method='ffill')
df['district'] = df['district'].map(fix_case)

df = df.drop(df[df['name'].str.contains('DISTRICT')].index)
df = df.drop(df[df['name'] == 'NATIONAL CAPITAL REGION - MANILA'].index)

df['region'] = df[df['name'].str.contains('REGION')]['name']
df.loc[df['name'] == 'BARMM', 'region'] = 'BARMM'
df['region'] = df['region'].fillna(method='ffill')

df = df.drop(df[df['name'].str.contains('REGION')].index)
df = df.drop(df[df['name'] == 'BARMM'].index)

subdistricts = df[~df['name'].str.contains(',')]['name']
df['subdistrict'] = df[~df['name'].str.contains(',')]['name'].str.title()
df['subdistrict'] = df['subdistrict'].fillna(method='ffill')
df['subdistrict'] = df['subdistrict'].map(convt_name)
df.loc[df['subdistrict'] == 'Taguig City-Pateros', 'subdistrict'] = 'Taguig-Pateros'

df = df.drop(df[~df['name'].str.contains(',')]['name'].index)
df.to_csv('comelec_elected_clean.csv', index=False)


from flask import render_template, request
from app.views import insert_details
from app import app
from flask import jsonify

@app.route('/')
def index(error=None):
    return render_template('index.html', error=error)

@app.route('/insert', methods=["POST"])
def insert():
    print(request.form)
    print(request.method)
    if request.method == "POST":
        print('Posting')
        try:
            username = request.form.get('fullname')
            license = request.form.get('licence')
            gender = request.form.get('gender')
            dob = request.form.get('date')
            contact = request.form.get('phone')

            try:
                insert_details(username, license, gender, dob, contact)
                return render_template('main.html', username=username)
            except Exception as e:
                return render_template('main.html')
        except Exception as e:
            print(str(e))
            return render_template('main.html')
    else:
        print("Wrong")

@app.route('/test', methods=["GET"])
def test():
    data = {"message": "yooo"}
    print("Working")
    return jsonify(data)


import sys
from collections import Counter
import numpy as np
import pandas as pd

def count_total_songs(data):
    total_songs = data['track_name'].count()
    return total_songs

def count_songs_with_key(data, key):
    songs_count_with_key = data['key'].value_counts()[key]
    return songs_count_with_key

def get_most_frequent_artists(data):
    # Get artists list for each track (string value containing artists as comma separated values)
    artists_list_per_track = data['artist(s)_name'].tolist()

    # Split the artists string around ',' and remove whitespaces to get 2D list of single artists
    artists_list = [[artist.strip() for artist in artists.split(',')] for artists in artists_list_per_track]

    # Convert 2D artists list to 1D list
    artists = list(np.concatenate(artists_list).flat)

    # Generate frequency map (dictionary) of artists
    artists_count = dict(Counter(artists))

    # Get list of most frequent artists
    max_count = max(artists_count.values())
    most_frequent_artists = [artist for artist,count in artists_count.items() if count == max_count]

    return most_frequent_artists, max_count

if __name__ == "__main__":
    csv_file_path = "spotify-2023.csv"
    data = pd.read_csv(csv_file_path)

    # Challenge-1 : Identify number of songs
    total_songs = count_total_songs(data)
    print("Total count of songs : " + str(total_songs))

    # Challenge-2 : Identify number of songs in the key of E
    key = "E"
    count = count_songs_with_key(data, key)
    print("Count of Songs with key '" + key + "' : " + str(count))

    # Challenge-3 : Count occurrences of values in column "artist(s)_name" & find most common value
    most_common_artists, count = get_most_frequent_artists(data)
    print("Most common artist(s) are : ", end="")
    for artist in most_common_artists:
        print(artist, ", ", sep="", end="")
    print("with count of " + str(count))


import json

from inginious.common.tasks_code_boxes import FileBox
from inginious.common.tasks_problems import MultipleChoiceProblem, BasicCodeProblem

def submission_to_json(data, debug, reloading=False, replace=False):
    """ Converts a submission to json (keeps only needed fields) """
    tojson = {
        'status': data['status'],
        'result': data.get('result', 'crash'),
        'id': str(data["_id"]),
        'submitted_on': str(data['submitted_on']),
        'grade': str(data.get("grade", 0.0)),
        'replace': replace and not reloading  # Replace the evaluated submission
    }

    if reloading:
        # Set status='ok' because we are reloading an old submission.
        tojson["status"] = 'ok'
        # And also include input
        tojson["input"] = data.get('input', {})

    if "text" in data:
        tojson["text"] = data["text"]
    if "problems" in data:
        tojson["problems"] = data["problems"]

    if debug:
        tojson["debug"] = data
    return json.dumps(tojson, default=str)

def list_multiple_multiple_choices_and_files(task):
    """ List problems in task that expect and array as input """
    output = {}
    for problem in task.get_problems():
        if isinstance(problem, MultipleChoiceProblem) and problem.allow_multiple():
            output[problem.get_id()] = []
        elif isinstance(problem, BasicCodeProblem):
            for box in problem.get_boxes():
                if isinstance(box, FileBox):
                    output[box.get_complete_id()] = {}
    return output


import gravity_mod as gfx
import random

# Creates a window 100 wide, and 100 tall
win = gfx.GravWindow("Sandbox")

import time
start = time.time()
print("Before sleep")
time.sleep(.25)
end = time.time()
print("The program slept for ", end - start, "seconds")

grid = []

# Function for blocks n cord
def draw_stone (x,y,block):
    x2 = upper_left_cord + 10
    y2 = lower_right_cord + 10
    print(x,x2,y,y2,block_type)

    if block_type == 'STONE':
        block_color = 'Gray'

    if block_type == 'SAND':
        block_color = 'Tan'

    if block_type == 'WATER':
        block_color = 'Blue'

    win.draw_rect(x,y,x2,y2,block_color)
    block_data = x,y,x2,y2,block_color
    print('This is the block data', block_data)
    grid.append(block_data)

while True:
    try:
        print()
        print('New event')
        win.draw_screen()
        time.sleep(.4)
        events = win.get_events()
        print('What user clicked on', events)

        if events == 'CLEAR':
            print('clear the sceen')

        num_events = len(events)
        if num_events >= 1 and events != 'CLEAR':

            block_type = events[0][0]
            print('This is the block type', block_type)
#For x cord
            upper_left_cord = events[0][1]

            x10 = upper_left_cord % 10

            upper_left_cord = upper_left_cord - x10

#For y cord
            lower_right_cord = events[0][2]

            y10 = lower_right_cord % 10

            lower_right_cord = lower_right_cord - y10

            draw_stone(upper_left_cord, lower_right_cord, block_type)

        total_items = 0
        for items in (grid):
            print('These are the items in the grid',items)

            one = items[0]
            two = items[1]
            three = items[2]
            four = items[3]
            five = items[4]

            if five == 'Tan' and four < 600:

                two = two + 10
                four = four + 10

                p = 0
                while p <= total_items:
                    print('current item adding',items)
                    print('over all grid',grid[p])
                    if items == grid[p]:
                        print('Same so stop block')
                        two = two - 10
                        four = four -10
                    p += 1

                grid.remove(items)

                items = one,two,three,four,five
                grid.append(items)

            if five == 'Blue' and four < 600:

                two = two + 10
                four = four + 10

                h = 0
                while h <= total_items:
                    print('current item adding',items)
                    print('over all grid',grid[h])
                    if items == grid[h]:
                        print('Same so stop block')
                        two = two - 10
                        four = four -10

                        random_direction = random.randrange(2)
                        if random_direction == 1 and three < 600:
                            one = one +10
                            three = three +10
                            print(one,three)
                        if random_direction != 1 and three < 600:
                            one = one -10
                            three = three -10
                            print('not one',one,three)

                    h += 1

                grid.remove(items)
                print('before',items)
                items = one,two,three,four,five
                print('after',items)
                grid.append(items)

            win.draw_rect(one,two,three,four,five)

            total_items += 1
            print(total_items)

        print(grid)

    except _tkinter.TclError:
        print('Thanks for playing')


from functools import wraps
from flask import request
from hashlib import sha512
from Crypto.PublicKey import RSA
from model.error import Forbidden
from base64 import urlsafe_b64decode
from time import time
import json
import requests
import os

def require_login(func):
    @wraps(func)
    def decorated(*args, **kwargs):
        if verify_token():
            return func(*args, **kwargs)
        else:
            raise Forbidden("Invalid access token.")

    return decorated

def verify_token(token = None):
    access_token = retrive_token() if token is None else token
    if access_token is None:
        return False

    # get the hash value from header and payload
    header, payload, signature = access_token.split('.')
    header_payload = f"{header}.{payload}".encode("utf-8")
    hash = int.from_bytes(sha512(header_payload).digest(), byteorder='big')

    # get hash value from signature and public key
    header, payload, signature = decode_token(access_token)

    # get public key from authenticator well know endpoint
    resp = requests.get(f'http://{os.environ.get("AUTHENTICATOR_ENDPOINT")}:{os.environ.get("AUTHENTICATOR_PORT")}/auth/.well-known/configuration')
    jwks = resp.json()
    jwk = None
    for data in jwks:
        if header["kid"] == data["kid"]:
            jwk = data
            break
    # kid not found
    if jwk is None:
        return False
    e = int.from_bytes(urlsafe_b64decode(fill_b64_padding(jwk["e"])), 'big')
    n = int.from_bytes(urlsafe_b64decode(fill_b64_padding(jwk["n"])), 'big')
    hash_from_signature = pow(signature, e, n)
    # verify signature
    if hash != hash_from_signature:
        return False

    # expiration time verify
    if int(time()) > payload["exp"]:
        return False

    # valid token
    return True

def decode_token(token = None):
    access_token = retrive_token() if token is None else token
    header, payload, signature = access_token.split('.')
    header_decode = json.loads(urlsafe_b64decode(fill_b64_padding(header)))
    payload_decode = json.loads(urlsafe_b64decode(fill_b64_padding(payload)))
    signature_decode = int.from_bytes(urlsafe_b64decode(fill_b64_padding(signature)), 'big')

    return (header_decode, payload_decode, signature_decode)

def fill_b64_padding(b64msg):
    missing_padding = 4 - len(b64msg) % 4
    b64msg += '=' * missing_padding
    return b64msg

def retrive_token() -> str:
    # check field in header
    header = request.headers
    if "Authorization" not in header:
        return None

    # check schema
    if not header["Authorization"].lower().startswith("bearer "):
        return None
    else:
        _, token = header["Authorization"].split()
        return token


n=int(input())
while(n>0):
    n-=1
    str1=input()
    list0=str1.split()
    s1=list0[0]
    list1=[]
    for x in range(len(s1)):
        for i in range(len(s1) - x):
            list1.append(s1[i:i + x + 1])
    list1.sort()
    time=[0]*1000000
    length=len(list1)
    temp=1
    for i in range(length-1):
        if(list1[i]==list1[i+1]):
            temp+=1
        else:
            if(time[len(list1[i])]<temp):
                time[len(list1[i])]=temp
            temp=1
    num=int(list0[1])
    time[0]=num
    for i in range(100,-1,-1):
        if(time[i]==num):
            print(i)
            break
        if(i==0):
            print(-1)


from abc import ABC, abstractmethod
from enum import Enum
from typing import Union
from datetime import datetime, timedelta

EPOCH = datetime(1970, 1, 1)

class ModerationDecision(Enum):
    ABSTAIN = -1
    DELETE_MSG = 0
    TIMEOUT_USER = 1

class Moderator(ABC):
    message: str
    decision: ModerationDecision

    def __init__(self, message: str, decision: ModerationDecision, timeout_duration: Union[None, int]):
        self.message = message
        self.timeout_duration = timeout_duration
        self.decision = decision

    @abstractmethod
    def get_name(self) -> str:
        pass

    @abstractmethod
    def vote(self, msg: str, author: str) -> ModerationDecision:
        pass

class CapsLockModerator(Moderator):
    def __init__(
            self,
            message: str,
            decision: ModerationDecision,
            timeout_duration: Union[None, int],
            min_size: int,
            threshold: int
    ):
        super().__init__(message, decision, timeout_duration)

        self.min_size = min_size
        self.threshold = threshold / 100

    def get_name(self) -> str:
        return 'Caps Lock'

    def vote(self, msg: str, author: str) -> ModerationDecision:
        msg = ''.join(filter(str.isalpha, msg))

        if len(msg) < self.min_size:
            return ModerationDecision.ABSTAIN

        n = 0
        for char in msg:
            if char.strip() == '':
                continue
            if char == char.upper():
                n += 1

        if n / len(msg) >= self.threshold:
            return self.decision

        return ModerationDecision.ABSTAIN

class FloodModerator(Moderator):
    def __init__(
            self,
            message: str,
            decision: ModerationDecision,
            timeout_duration: Union[None, int],
            max_word_length: Union[None, int],
            raid_cooldown: Union[None, int],
            ignore_hashtags: bool,
            max_msg_occurrences: Union[None, int],
            min_time_between_occurrence: Union[None, int]
    ):
        super().__init__(message, decision, timeout_duration)
        self.max_word_length = max_word_length
        self.raid_cooldown = raid_cooldown
        self.last_raid = EPOCH
        self.ignore_hashtags = ignore_hashtags
        self.max_msg_occurrences = max_msg_occurrences
        self.min_time_between_occurrence = min_time_between_occurrence
        self.last_msgs = []

    def get_name(self) -> str:
        return 'Flood'

    def vote(self, msg: str, author: str) -> ModerationDecision:
        if self.raid_cooldown is not None and self.last_raid + timedelta(minutes=self.raid_cooldown) > datetime.now():
            return ModerationDecision.ABSTAIN

        if self.max_word_length is not None:
            for word in msg.split(' '):
                if word.startswith('#'):
                    continue
                if len(word) > self.max_word_length:
                    return ModerationDecision.TIMEOUT_USER

        if self.max_msg_occurrences is None or self.min_time_between_occurrence is None:
            return ModerationDecision.ABSTAIN

        clean_msg = None
        for last_msg in self.last_msgs:
            if last_msg['first-occurrence'] + timedelta(seconds=self.min_time_between_occurrence) <= datetime.now():
                clean_msg = last_msg
                break

            if author != last_msg['author'] or msg != last_msg['message']:
                break

            last_msg['occurrences'] += 1
            if last_msg['occurrences'] >= self.max_msg_occurrences:
                return ModerationDecision.TIMEOUT_USER

        if clean_msg is not None:
            self.last_msgs.remove(clean_msg)

        self.last_msgs.append({
            'first-occurrence': datetime.now(),
            'author': author,
            'message': msg,
            'occurrences': 1
        })

        return ModerationDecision.ABSTAIN

    def declare_raid(self):
        self.last_raid = datetime.now()


""" Provide class to handle a data buffer with multiple disconnected parts.

  License::

    MIT License

    Copyright (c) 2015-2022 by Martin Scharrer <martin.scharrer@web.de>

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software
    and associated documentation files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use, copy, modify, merge, publish,
    distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or
    substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
    BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""

import collections.abc as collections
import copy

from hexformat.fillpattern import FillPattern, int_to_bytes

MOD_USABLE_BUFFER_FOUND = 0
MOD_NO_BUFFER_FOUND_NEXT_HIGHER_USED = 1
MOD_BEYOND_END_LAST_BUFFER_USED = -1

def ensurebuffer(buforint):
    if isinstance(buforint, bytearray):
        return buforint
    elif isinstance(buforint, collections.Sequence):
        return bytearray(buforint)
    else:
        return bytearray((buforint,))

class MultiPartBuffer(object):
    # noinspection PyUnresolvedReferences
    """Class to handle disconnected binary data.

       Each segment (simply called "part") is identified by its starting address and its content (a Buffer instance).

       Attributes:
         _STANDARD_FORMAT (str): The standard format used by :meth:`.fromfh` and :meth:`.fromfile` if no format
                                 was given.
         _padding (int, iterable or FillPattern): Standard fill pattern.
    """
    _STANDARD_FORMAT = 'bin'
    _padding = 0xFF

    def __init__(self):
        super(MultiPartBuffer, self).__init__()
        self._parts = list()

    def __repr__(self):
        """Print representation including class name, id, number of parts, range and used size."""
        start, totalsize = self.range()
        return "<{:s} at 0x{:X}: {:d} parts in range 0x{:X} + 0x{:X}; used 0x{:X}>".format(self.__class__.__name__,
                                                                                id(self), len(self._parts),
                                                                                start, totalsize,
                                                                                self.usedsize())

    # noinspection PyProtectedMember
    def __eq__(self, other):
        """Compare with other instance for equality."""
        return self._parts == other._parts

    def _create(self, beforeindex, address, data=list()):
        """Create new buffer before index or at end if index is None.

           Args:
             beforeindex (int): The data will be inserted before this index.
             address (int): Address of first byte in data buffer.
             data (Buffer): Data to be stored.
        """
        buffer = bytearray(data)
        if beforeindex is None:
            self._parts.append([address, buffer])
        else:
            self._parts.insert(beforeindex, [address, buffer])

    def _find(self, address, size, create=True):
        """Find buffer corresponding to data block given by address and size.

           Args:
             address (int): Starting address of data block.
             size (int): Size of data block.
             create (bool): If True a new (empty) buffer is created if no suitable one already exists.

           Returns:
             Tuple (buffer index, mod). The meaning of <mod> is
                0: MOD_USABLE_BUFFER_FOUND: Buffer of given index contains at least part of the given range. Always
                                            returned if create=True.
                1: MOD_NO_BUFFER_FOUND_NEXT_HIGHER_USED: No buffer containing the given range found. Index states next
                                                         buffer with an higher address.
                -1: MOD_BEYOND_END_LAST_BUFFER_USED: Address lies after all buffers. Index states last buffer before
                                                     address.
        """
        dataend = address + size
        for index, part in enumerate(self._parts):
            bufstart, buffer = part
            bufend = bufstart + len(buffer)
            if address < bufstart:
                if dataend < bufstart:
                    if create:
                        self._create(index, address)
                        return index, MOD_USABLE_BUFFER_FOUND
                    else:
                        return index, MOD_NO_BUFFER_FOUND_NEXT_HIGHER_USED
                else:
                    return index, MOD_USABLE_BUFFER_FOUND
            elif address <= bufend:
                return index, MOD_USABLE_BUFFER_FOUND
        # If this line is reached no matching buffer was found and address lies after all buffers
        index = (len(self._parts) - 1)
        if create:
            self._create(None, address)
            index += 1
            return index, MOD_USABLE_BUFFER_FOUND
        else:
            return index, MOD_BEYOND_END_LAST_BUFFER_USED

    def _insert(self, index, newdata, datasize, dataoffset):
        """Insert new data at begin of existing buffer. Reduce starting address of buffer accordantly.

           Args:
             index (int): Index of buffer.
             newdata (Buffer): Data buffer with new data to be inserted.
             datasize (int): Size of data be added. Can be smaller than data buffer size if not all content should be
                             inserted.
             dataoffset (int): Starting read offset of newdata.
        """
        if dataoffset == 0 and datasize == len(newdata):
            data = newdata
        else:
            data = newdata[dataoffset:dataoffset + datasize]
        self._parts[index][1] = bytearray(data) + self._parts[index][1]
        self._parts[index][0] -= datasize  # adjust address

    def _set(self, index, address, newdata, datasize, dataoffset):
        """Store new data in given buffer at given address. New data is read from given offset for the given size.

           Args:
             index (int): Index of buffer where data will be stored.
             address (int): Address of first data byte.
             newdata (Buffer): Data buffer with new data.
             datasize (int): Size of data. Can be smaller than data buffer size if not all content should be inserted.
             dataoffset (int): Starting read offset of newdata.
        """
        bufferstart = self._parts[index][0]
        bufferoffset = address - bufferstart
        self._parts[index][1][bufferoffset:bufferoffset + datasize] = newdata[dataoffset:dataoffset + datasize]

    def _extend(self, index, newdata, datasize, dataoffset):
        """Extend given buffer with the new data.

           Args:
             index (int): Index of buffer where data will be appended.
             newdata (Buffer): Data buffer with new data.
             datasize (int): Size of data. Can be smaller than data buffer size if not all content should be inserted.
             dataoffset (int): Starting read offset of newdata.
        """
        if dataoffset == 0 and datasize == len(newdata):
            data = newdata
        else:
            data = newdata[dataoffset:dataoffset + datasize]
        self._parts[index][1].extend(data)

    def _merge(self, index):
        """Merge the given buffer with the next following one.

           Args:
             index (int): Index of first buffer which will be merged with the next buffer.
        """
        nextpart = self._parts.pop(index + 1)
        self._parts[index][1].extend(nextpart[1])

    def setint(self, address, intvalue, datasize, byteorder='big', signed=False, overwrite=True):
        """Set integer value at given address."""
        databytes = int_to_bytes(intvalue, datasize, byteorder, signed=signed)
        return self.set(address, databytes, datasize, 0, overwrite)

    def set(self, address, newdata, datasize=None, dataoffset=0, overwrite=True):
        """Add <newdata> starting at <address>.
           The data size can be given explicitly, otherwise it is taken as len(newdata).
           Additionally a data offset can be specified to read the data starting from this index from <newdata>.
        """
        if datasize is None:
            datasize = len(newdata) - dataoffset

        if datasize == 0:
            return self

        (index, mod) = self._find(address, datasize, create=True)
        endaddress = address + datasize

        bufferstart, buffer = self._parts[index]
        bufferend = bufferstart + len(buffer)

        # Insert left overlapping data
        if address < bufferstart:
            before = bufferstart - address
            self._insert(index, newdata, before, dataoffset)
            # Adjust values for remaining data
            datasize -= before
            dataoffset += before
            address += before

        # Overwrite existing data
        if datasize > 0:
            size = min(datasize, bufferend - address)
            if overwrite:
                self._set(index, address, newdata, size, dataoffset)
            datasize -= size
            dataoffset += size
            address += size

        # Insert right overlapping data
        if endaddress > bufferend:
            nextindex = index + 1

            nextbufferstart = None
            if nextindex < len(self._parts):
                nextbufferstart = self._parts[nextindex][0]

            # Check if data does not reach into next buffer
            if nextbufferstart is None or nextbufferstart > endaddress:
                after = endaddress - bufferend
                self._extend(index, newdata, after, dataoffset)
            else:
                gap = nextbufferstart - bufferend
                self._extend(index, newdata, gap, dataoffset)
                datasize -= gap
                dataoffset += gap
                address += gap
                self._merge(index)
                self.set(address, newdata, datasize, dataoffset, overwrite)
        return self

    def crop(self, address, size=None):
        """Crop content to range <address>+<size> by deleting all other content."""
        address, size = self._checkaddrnsize(address, size)
        start, totalsize = self.range()
        end = start + totalsize
        self.delete(start, address - start)
        self.delete(address + size, end - address)
        return self

    def extract(self, address, size=None, keep=True):
        """Extract given range and return it as new instance. Gaps in the range are preserved.
           The <keep> argument controls if the range is kept in the original instance or deleted.
        """
        new = self.copy()
        new.crop(address, size)
        if not keep:
            self.delete(address, size)
        return new

    def includesgaps(self, address=None, size=None):
        address, size = self._checkaddrnsize(address, size)
        (index, mod) = self._find(address, size, False)
        if mod == MOD_USABLE_BUFFER_FOUND:
            (start, data) = self._parts[index]
            end = start + len(data)
            if (address < start) or (end < (address + size)):
                return True
            return False
        else:
            if len(self._parts) == 0 and address == 0 and size == 0:
                return False
            return True

    def offset(self, offset):
        """Add an offset to all addresses.
           A ValueError is raised if offset < -start, as this would lead to negative addresses.
           If offset is None, the negative start address is used, i.e. the first byte is moved to address 0.
        """
        start = self.start()
        if offset is None:
            offset = -start
        else:
            offset = int(offset)
        if offset < -start:
            raise ValueError("offset < -start")
        for part in self._parts:
            part[0] += offset
        return self

    def relocate(self, newaddress, address=None, size=None, overwrite=True):
        """Relocate given range to new address.
           If address is None the start address is used.
           If size is None the remaining size from address to the endaddress is used.
           The <overwrite> argument determines if existing data in the new range is overwritten
           or if the overlapping bytes of the relocated data are discarded.
        """
        newaddress = int(newaddress)
        address, size = self._checkaddrnsize(address, size)
        start, totalsize = self.range()
        if address == start and size == totalsize:
            self.offset(newaddress - address)
        else:
            data = self.get(address, size)
            self.delete(address, size)
            self.set(newaddress, data, overwrite=overwrite)
        return self

    def __getitem__(self, n):
        try:
            return self.get(int(n), 1)[0]
        except TypeError:
            if n.step is not None:
                raise IndexError("Slice step not supported")
            # _checkaddrnsize is used here while n.stop is not the size but the end address.
            # However, if None the correct size is returned and if not the value is adjusted later
            address, size = self._checkaddrnsize(n.start, n.stop)
            if n.stop is not None:
                size -= address
            return self.get(address, size)

    def delete(self, address, size=None):
        """Deletes <size> bytes starting from <address>. Does nothing if <size> is non-positive."""
        address, size = self._checkaddrnsize(address, size)
        while size > 0:
            (index, mod) = self._find(address, size, create=True)
            bufferstart, buffer = self._parts[index]
            buffersize = len(buffer)
            if address < bufferstart:
                size -= bufferstart - address
                address = bufferstart
            leading = address - bufferstart
            trailing = bufferstart + buffersize - address - size
            trailaddress = address + size
            if trailing > 0:
                if leading > 0:
                    self._parts[index][1] = buffer[0:leading]
                    self._create(index + 1, trailaddress, buffer[buffersize - trailing:buffersize])
                else:
                    self._parts[index][1] = buffer[buffersize - trailing:buffersize]
                    self._parts[index][0] = trailaddress
                break
            else:
                nextbufferstart = None
                if index < len(self._parts) - 1:
                    nextbufferstart = self._parts[index + 1][0]

                if leading > 0:
                    self._parts[index][1] = buffer[0:leading]
                else:
                    self._parts.pop(index)  # index now points to NEXT part

                if nextbufferstart is None:
                    break
                size = -trailing
                address = bufferstart + buffersize
                gap = nextbufferstart - address
                address += gap
                size -= gap
        return self

    def _filler(self, size, fillpattern):
        """Generate buffer with given fillpattern and size."""
        size = int(size)
        if isinstance(fillpattern, BaseException) or (
            type(fillpattern) == type and issubclass(fillpattern, BaseException)):
            raise fillpattern
        if fillpattern is None:
            fillpattern = self._padding
        fillpattern = FillPattern.frompattern(fillpattern)
        return bytearray(fillpattern[0:size])

    def _checkaddrnsize(self, address, size):
        """Helper method: Ensure proper address and size values.

        If address is None the starting address of the instance is substituted.
        Also if size is None the remaining size to the end of the last buffer is substituted.
        """
        if address is None or size is None:
            start, totalsize = self.range()
            if address is None:
                address = start
            if size is None:
                size = start + totalsize - address
        return address, size

    def fill(self, address=None, size=None, fillpattern=None, overwrite=False):
        """Fill with <fillpattern> from <address> for <size> bytes.
           Filling pattern can be a single byte (0..255) or list-like object.
           If <overwrite> is False (default) then only gaps are filled.
           If <address> is None the first existing address is used.
           If <size> is None the remaining size is used.
        """
        address, size = self._checkaddrnsize(address, size)
        self.set(address, self._filler(size, fillpattern), size, 0, overwrite)
        return self

    def unfill(self, address=None, size=None, unfillpattern=None, mingapsize=16, unfillboundaries=True):
        """Removes <unfillpattern> and leaves a gap, as long a resulting new gap would be least <mingapsize> large."""
        if len(self._parts) == 0:
            return self
        if unfillpattern is None:
            unfillpattern = self._padding
        if isinstance(unfillpattern, int):
            unfillpattern = [unfillpattern, ]
        unfillpattern = bytearray(unfillpattern)
        ufvlen = len(unfillpattern)
        address, size = self._checkaddrnsize(address, size)
        (index, mod) = self._find(address, size, create=False)
        if mod != MOD_USABLE_BUFFER_FOUND:
            return self
        uflist = list()
        while index < len(self._parts) and size > 0:
            bufferstart, buffer = self._parts[index]
            buffersize = len(buffer)
            startpos = address - bufferstart
            if startpos < 0:
                size += startpos
                startpos = 0
            maxpos = min(buffersize, size)
            pos = startpos
            try:
                while pos < maxpos:
                    delstartpos = buffer.index(unfillpattern, pos, maxpos)
                    pos = delstartpos + ufvlen
                    while buffer.startswith(unfillpattern, pos, maxpos):
                        pos += ufvlen
                    ufsize = pos - delstartpos
                    # always delete at part boundaries
                    if ufsize >= mingapsize or (unfillboundaries and (pos == buffersize or delstartpos == startpos)):
                        uflist.append((bufferstart + delstartpos, ufsize))
            except ValueError:
                pass
            index += 1
            size -= maxpos
            address += buffersize

        for deladdr, delsize in uflist:
            self.delete(deladdr, delsize)
        return self

    def get(self, address, size, fillpattern=None):
        """ Get <size> bytes from <address>. Fill missing bytes with <fillpattern>.

            Where <fillpattern> can be:
             1. A byte-sized integer, i.e. in range 0..255.
             2. A list-like object which has all of the following properties:
                 - can be converted to a list of bytes
                 - is indexable
                 - should be multipliable
             3. A type which produces a list-like object as mentioned in 2) if
                instanciated with no argument or with the requested size as only argument.
             4. An exception class or instance.
                If given then no filling is performed but the exception is raised if filling would be required.
        """
        address, size = self._checkaddrnsize(address, size)
        (index, mod) = self._find(address, size, create=False)
        endaddress = address + size

        retbuffer = bytearray()

        if mod != 0:
            return self._filler(size, fillpattern)
        else:
            bufferstart, buffer = self._parts[index]
            bufferend = bufferstart + len(buffer)

            if address < bufferstart:
                before = bufferstart - address
                retbuffer = self._filler(before, fillpattern)
                size -= before
                address += before

            pos = address - bufferstart
            insize = min(size, bufferend - pos)
            if insize > 0:
                if len(retbuffer) > 0:
                    retbuffer.extend(buffer[pos: pos + insize])
                else:
                    retbuffer = buffer[pos: pos + insize]
                size -= insize
                address += insize

            if endaddress > bufferend:
                nextindex = index + 1

                nextbufferstart = None
                if nextindex < len(self._parts):
                    nextbufferstart = self._parts[nextindex][0]
                # Check if data does not reach into next buffer
                if nextbufferstart is None or nextbufferstart > endaddress:
                    after = endaddress - bufferend
                    retbuffer.extend(self._filler(after, fillpattern))
                else:
                    gap = nextbufferstart - bufferend
                    retbuffer.extend(self._filler(gap, fillpattern))
                    size -= gap
                    address += gap
                    retbuffer.extend(self.get(address, size, fillpattern))
        return retbuffer

    def range(self):
        """Get range of content as (start address, size) tuple. The range may contain unfilled gaps.
           An empty buffer with return (0, 0).
        """
        if len(self._parts) == 0:
            return 0, 0
        else:
            start = self._parts[0][0]
            lastaddress, buffer = self._parts[-1]
            totalsize = lastaddress + len(buffer) - start
            return start, totalsize

    def start(self):
        """Get start address. An empty buffer with return 0."""
        if len(self._parts) == 0:
            return 0
        else:
            return self._parts[0][0]

    def end(self):
        """Get end address, i.e. the address one after the very last byte of data.
           An empty buffer will return 0.
        """
        (start, totalsize) = self.range()
        return start + totalsize

    def usedsize(self):
        """Returns used data size, i.e. without the size of any gaps"""
        return sum([len(buffer) for addr, buffer in self._parts])

    def parts(self):
        """Return a list with (address,length) tuples for all parts."""
        return [(start, len(data)) for start, data in self._parts]

    def gaps(self):
        """Return a list with (address,length) tuples for all gaps between the existing parts."""
        gaplist = list()
        for n in range(0, len(self._parts) - 1):
            address, buffer = self._parts[n]
            nextaddress = self._parts[n + 1][0]
            endaddress = address + len(buffer)
            gap = nextaddress - endaddress
            gaplist.append([endaddress, gap])
        return gaplist

    def hasdata(self, address=None, size=None):
        """Returns True if there is data in area (address, size)."""
        address, size = self._checkaddrnsize(address, size)
        index, mod = self._find(address, size, create=False)
        # Check if there is a suitable buffer
        if mod != MOD_USABLE_BUFFER_FOUND:
            # No data if not
            return False
        # Otherwise the given address might be just at the end of the buffer.
        # It hasdata only if the address is really inside the buffer span, not at the very end.
        adr, data = self._parts[index]
        return address < adr + len(data)

    def blockfilter(self, blocksize, filterfunc, address=None, size=None, skipempty=False):
        """Execute op(address, blocksize) for each block of <blocksize>."""
        address, size = self._checkaddrnsize(address, size)
        try:
            blocksize = int(blocksize)
            assert blocksize > 0
        except AssertionError:
            raise ValueError
        endaddress = address + size
        # Align startaddress to blocksize
        startaddress = int(address / blocksize) * blocksize

        for addr in range(startaddress, endaddress, blocksize):
            if not skipempty or self.hasdata(addr, blocksize):
                filterfunc(addr, blocksize)

    def blockfill(self, blocksize, address=None, size=None, fillpattern=None, overwrite=False):
        """Fill with <fillpattern> blockwise with given <blocksize>. Skipping empty blocks."""
        def doblockfill(_address, _size):
            self.fill(_address, _size, fillpattern, overwrite)
        self.blockfilter(blocksize, doblockfill, address, size, skipempty=True)
        return self

    def blockunfill(self, blocksize, address=None, size=None, unfillpattern=None, mingapsize=None, unfillboundaries=False):
        """Unfill with <unfillpattern> blockwise with given <blocksize>."""
        if mingapsize is None:
            mingapsize = blocksize
        def doblockunfill(_address, _size):
            self.unfill(_address, _size, unfillpattern, mingapsize, unfillboundaries)
        self.blockfilter(blocksize, doblockunfill, address, size, skipempty=True)
        return self

    def fillgaps(self, fillpattern=None):
        """Fill all gaps with given fillpattern."""
        for address, size in self.gaps():
            self.fill(address, size, fillpattern)
        return self

    def fillfront(self, startaddress=0, fillpattern=None):
        """Fill the data range in front starting from the given address (0 by default)
           to the beginning of the buffer.
        """
        if len(self._parts) > 0:
            endaddress = self._parts[0][0]
            size = endaddress - startaddress
            if size > 0:
                self.fill(startaddress, size, fillpattern)
        return self

    def fillend(self, endaddress, fillpattern=None):
        """Fill the data range after the buffer up to the given address.
        """
        (startaddress, totalsize) = self.range()
        startaddress += totalsize
        size = endaddress - startaddress
        if size > 0:
            self.fill(startaddress, size, fillpattern)
        return self

    def tobinfile(self, filename, address=None, size=None, fillpattern=None):
        """ """
        with open(filename, "wb") as fh:
            return self.tobinfh(fh, address, size, fillpattern)

    def tobinfh(self, fh, address=None, size=None, fillpattern=None):
        """ """
        start, esize = self.range()
        if address is not None:
            if address < 0:
                address = 0
            endaddress = start + esize
            esize = endaddress - address
            start = address
            if esize < 0:
                esize = 0
        if size is None:
            size = esize
        fh.write(self.get(start, size, fillpattern))
        return self

    def todict(self):
        """Return a dictionary with a numeric key for all used bytes like intelhex.IntelHex does it."""
        d = {addr: byte for address, buffer in self._parts for addr, byte in enumerate(buffer, address)}
        return d

    def loaddict(self, d, overwrite=True):
        """Load data from dictionary where each key must be numeric and represent an address and the corresponding \
        value the byte value."""
        for addr, byte in d.items():
            self.set(addr, (byte,), 1, overwrite=overwrite)
        return self

    def __iadd__(self, other):
        """Add content of other instance to itself, overwriting existing data if parts overlap.

           Args:
             other (MultiPartBuffer, dict or iterable): Second summand.
               If a dict then the keys must be address and the values a buffer.
               If an iterable it must yield (address, data) combinations.
        """
        return self.add(other, True)

    def __add__(self, other):
        """Add two instances together and return the sum as new instance.

           Args:
             other (MultiPartBuffer, dict or iterable): Second summand.
               If a dict then the keys must be address and the values a buffer.
               If an iterable it must yield (address, data) combinations.

           Returns:
             New instance with the data of both sources combined.
             Overlapping parts will be set to the data of the second summand.
        """
        newinst = self.copy()
        newinst.__iadd__(other)
        return newinst

    def __ior__(self, other):
        """Add content of other instance to itself, keeping existing data if parts overlap.

           Args:
             other (MultiPartBuffer, dict or iterable): Second summand.
               If a dict then the keys must be address and the values a buffer.
               If an iterable it must yield (address, data) combinations.
        """
        return self.add(other, False)

    def __or__(self, other):
        inst = self.copy()
        return inst.add(other, False)

    def add(self, other, overwrite=True):
        """Add content of other instance to itself, overwriting or keeping existing data if parts overlap.

           Args:
             other (MultiPartBuffer, dict or iterable): Second summand.
               If a dict then the keys must be address and the values a buffer.
               If an iterable it must yield (address, data) combinations.
             overwrite (bool): If True existing data will be overwritten if parts overlap.
        """
        if isinstance(other, MultiPartBuffer):
            source = other._parts
        elif isinstance(other, dict):
            source = iter(other.items())
        else:
            source = other
        try:
            for address, buffer in source:
                self.set(address, ensurebuffer(buffer), overwrite=overwrite)
        except Exception as e:
            raise TypeError(e)
        return self

    def copy(self):
        """Return a deep copy of the instance."""
        return copy.deepcopy(self)

    def filter(self, filterfunc, address=None, size=None, fillpattern=None):
        """Call filterfunc(bufferaddr, buffer, bufferstartindex, buffersize) on all parts matching <address> and <size>.
           If <address> is None the first existing address is used.
           If <size> is None the remaining size is used.
           If fillpattern is NOT None the given range is filled and the filter function will be called with the
           resulting single part.
        """
        address, size = self._checkaddrnsize(address, size)
        if size <= 0:  # don't filter over a non-positive range
            return self
        if fillpattern is not None:
            self.fill(address, size, fillpattern)
        (startindex, mod1) = self._find(address, size, create=False)
        if mod1 != MOD_USABLE_BUFFER_FOUND:  # range not included (was not filled)
            return self
        endaddress = address + size
        (lastindex, mod2) = self._find(endaddress - 1, 0, create=False)
        if mod2 == MOD_NO_BUFFER_FOUND_NEXT_HIGHER_USED:
            lastindex -= 1
        for bufferaddr, buffer in self._parts[startindex:lastindex + 1]:
            bufferstartindex = max(address - bufferaddr, 0)
            bufferendindex = min(len(buffer), endaddress - bufferaddr)
            filterfunc(bufferaddr, buffer, bufferstartindex, bufferendindex)
        return self

    @classmethod
    def fromfile(cls, filename, fformat=None, *args, **kvargs):
        """ """
        if fformat is None:
            fformat = cls._STANDARD_FORMAT
        methodname = "from" + fformat.lower() + "file"
        if hasattr(cls, methodname):
            return getattr(cls, methodname)(filename, *args, **kvargs)
        else:
            with open(filename, "r") as fh:
                return cls.fromfh(fh, *args, fformat=fformat, **kvargs)

    def loadfile(self, filename, fformat=None, *args, **kvargs):
        """ """
        with open(filename, "rb") as fh:
            return self.loadfh(fh, fformat, *args, **kvargs)

    def tofile(self, filename, fformat=None, *args, **kvargs):
        """ """
        opt = "w"
        if fformat == "bin" or (fformat is None and self._STANDARD_FORMAT == "bin"):
            opt = "wb"
        with open(filename, opt) as fh:
            self.tofh(fh, *args, fformat=fformat, **kvargs)
        return self

    def tofh(self, fh, fformat=None, *args, **kvargs):
        """ """
        if fformat is None:
            fformat = self._STANDARD_FORMAT
        methodname = "to" + fformat.lower() + "fh"
        if hasattr(self, methodname):
            getattr(self, methodname)(fh, *args, **kvargs)
        else:
            raise ValueError
        return self

    def loadfh(self, fh, fformat=None, *args, **kvargs):
        """ """
        if fformat is None:
            fformat = self._STANDARD_FORMAT
        methodname = "load" + fformat.lower() + "fh"
        if hasattr(self, methodname):
            getattr(self, methodname)(fh, *args, **kvargs)
        else:
            raise ValueError
        return self

    @classmethod
    def fromfh(cls, fh, fformat=None, *args, **kvargs):
        """ """
        if fformat is None:
            fformat = cls._STANDARD_FORMAT
        methodname = "load" + fformat.lower() + "fh"
        self = cls()
        if hasattr(self, methodname):
            getattr(self, methodname)(fh, *args, **kvargs)
        else:
            raise ValueError
        return self

    @classmethod
    def frombinfile(cls, filename, address=0, size=-1, offset=0):
        """ """
        with open(filename, "rb") as fh:
            return cls.frombinfh(fh, address, size, offset)

    @classmethod
    def frombinfh(cls, fh, address=0, size=-1, offset=0):
        """ """
        self = cls()
        self.loadbinfh(fh, address, size, offset)
        return self

    def loadbinfh(self, fh, address=0, size=-1, offset=0):
        """ """
        if offset != 0:
            fh.seek(offset, (offset < 0) and 2 or 0)
        buffer = bytearray(fh.read(size))
        self.set(address, buffer)
        return self

    def loadbinfile(self, filename, address=0, size=-1, offset=0):
        """ """
        with open(filename, "rb") as fh:
            return self.loadbinfh(fh, address, size, offset)


import torch
from torch.utils.data import Dataset
import pandas as pd
from transformers import BertTokenizer

class dataset(Dataset):
    def __init__(self,csv_file_name,token_len = 128,
                 tokenizer_nombre = 'bert-base-cased'):
        self.df = self.build_df(csv_file_name)
        self.tokenizer = BertTokenizer.from_pretrained(tokenizer_nombre)
        self.token_len = token_len

    def build_df(self,csv_file_name):
        df = pd.read_csv(csv_file_name)
        df['l1'] = df['l1'].astype('category').cat.codes
        df['l2'] = df['l2'].astype('category').cat.codes
        df['l3'] = df['l3'].astype('category').cat.codes
        return df
    def __len__(self):
        return len(self.df)
    def __getitem__(self,idx):
        label = torch.tensor((self.df['l1'].loc[idx],self.df['l2'].loc[idx],self.df['l3'].loc[idx]))
        txt = self.df['text'][0]
        txt = self.tokenizer(txt , return_tensors="pt",padding='max_length',
                             truncation=True, max_length=self.token_len)
        return txt,label.type(torch.LongTensor)


import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
os.environ['TF_CUDNN_DETERMINISTIC'] = '1'
os.environ['TF_DETERMINISTIC_OPS'] = '1'

import tensorflow as tf
from tensorflow import keras as k
from tensorflow.keras import layers as l

import custom_layers

RANDOM_SEED = 1337

# Model config
FILTERS = [8, 16, 32, 64, 128]
KERNEL_SIZES =  [(5, 5), (3, 3), (3, 3), (3, 3), (3, 3)]
BRANCH_KERNEL_SIZE = (4, 10)
RESNET_K = 2
RESNET_N = 3
ACTIVATION = 'relu'
INITIALIZER = 'he'
DROPOUT_RATE = 0.33
NUM_CLASSES = 1000

# Input config
SAMPLE_RATE = 48000
SPEC_LENGTH = 3.0 # 3 seconds
SPEC_SHAPE = (257, 384) # (height, width)

# Initializers
initializers = {'glorot': tf.initializers.GlorotNormal(seed=RANDOM_SEED),
                'he': k.initializers.he_normal(seed=RANDOM_SEED),
                'random': k.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=RANDOM_SEED),
                'constant': k.initializers.Constant(value=0)
                }

# Activations
activations = {'relu': l.ReLU(max_value=None, negative_slope=0.0, threshold=0.0),
               'elu': l.ELU(alpha=1.0),
               'lrelu': l.LeakyReLU(alpha=0.3)
              }

def resBlock(net_in, filters, kernel_size, stride=1, preactivated=True, block_id=1, name=''):

    # Show input shape
    print('    ' + name + ' IN SHAPE:', net_in.shape, end=' ')

    # Pre-activation
    if block_id > 1:
        net_pre = l.BatchNormalization(axis=-1, name=name + '_BN_PA')(net_in)
        net_pre = activations[ACTIVATION](net_pre)
    else:
        net_pre = net_in

    # Pre-activated shortcut?
    if preactivated:
        net_in = net_pre

    # Bottleneck Convolution
    if stride > 1:
        net_pre = l.Conv2D(filters=net_pre.shape[-1],
                            kernel_size=1,
                            padding='same',
                            strides=1,
                            data_format='channels_last',
                            kernel_initializer=initializers[INITIALIZER],
                            name=name + '_CONV_1')(net_pre)
        net_pre = l.BatchNormalization(axis=-1, name=name + '_BN_1')(net_pre)
        net_pre = activations[ACTIVATION](net_pre)

    # First Convolution
    net = l.Conv2D(filters=net_pre.shape[-1],
                   kernel_size=kernel_size,
                   padding='same',
                   strides=1,
                   data_format='channels_last',
                   kernel_initializer=initializers[INITIALIZER],
                   name=name + '_CONV_2')(net_pre)
    net = l.BatchNormalization(axis=-1, name=name + '_BN_2')(net)
    net = activations[ACTIVATION](net)

    # Pooling layer
    if stride > 1:
        net = l.MaxPooling2D(pool_size=(stride, stride),
                             data_format='channels_last',
                             name=name + '_POOL_1')(net)

    # Dropout Layer
    net = l.Dropout(rate=DROPOUT_RATE, seed=RANDOM_SEED, name=name + '_DO_1')(net)

    # Second Convolution (make 1x1 if downsample block)
    if stride > 1:
        k_size = (1, 1)
    else:
        k_size =  kernel_size
    net = l.Conv2D(filters=filters,
                   kernel_size=k_size,
                   padding='same',
                   strides=1,
                   activation=None,
                   data_format='channels_last',
                   kernel_initializer=initializers[INITIALIZER],
                   name=name + '_CONV_3')(net)

    # Shortcut Layer
    if not net.shape[1:] == net_in.shape[1:]:

        # Average pooling
        shortcut = l.AveragePooling2D(pool_size=(stride, stride),
                                      data_format='channels_last',
                                      name=name + '_SC_POOL')(net_in)

        # Shortcut convolution
        shortcut = l.Conv2D(filters=filters,
                            kernel_size=1,
                            padding='same',
                            strides=1,
                            activation=None,
                            data_format='channels_last',
                            kernel_initializer=initializers[INITIALIZER],
                            name=name + '_SC_CONV')(shortcut)

    else:

        # Shortcut = input
        shortcut = net_in

    # Merge Layer
    out = l.add([net, shortcut], name=name + '_ADD')

    # Show output shape
    print('OUT SHAPE:', out.shape)

    return out

def classificationBranch(net, kernel_size):

    # Post Convolution
    branch = l.Conv2D(filters=int(FILTERS[-1] * RESNET_K),
                      kernel_size=kernel_size,
                      strides=1,
                      data_format='channels_last',
                      kernel_initializer=initializers[INITIALIZER],
                      name='BRANCH_CONV_1')(net)
    branch = l.BatchNormalization(axis=-1, name='BRANCH_BN_1')(branch)
    branch = activations[ACTIVATION](branch)

    print('    POST  CONV SHAPE:', branch.shape)

    # Dropout Layer
    branch = l.Dropout(rate=DROPOUT_RATE, seed=RANDOM_SEED, name='BRANCH_DO_1')(branch)

    # Dense Convolution
    branch = l.Conv2D(filters=int(FILTERS[-1] * RESNET_K * 2),
                      kernel_size=1,
                      strides=1,
                      data_format='channels_last',
                      kernel_initializer=initializers[INITIALIZER],
                      name='BRANCH_CONV_2')(branch)
    branch = l.BatchNormalization(axis=-1, name='BRANCH_BN_2')(branch)
    branch = activations[ACTIVATION](branch)

    print('    DENSE CONV SHAPE:', branch.shape)

    # Dropout Layer
    branch = l.Dropout(rate=DROPOUT_RATE, seed=RANDOM_SEED, name='BRANCH_DO_2')(branch)

    # Class Convolution
    branch = l.Conv2D(filters=NUM_CLASSES,
                      kernel_size=1,
                      activation=None,
                      data_format='channels_last',
                      kernel_initializer=initializers[INITIALIZER],
                      name='BRANCH_CONV_3_' + str(NUM_CLASSES))(branch)

    return branch

def buildModel():

    print('BUILDING BirdNET MODEL...')

    # Input layer
    print('  INPUT:')
    inputs = k.Input(shape=int(SAMPLE_RATE * SPEC_LENGTH), name='INPUT')

    # Spectrogram layer if input is raw signal
    net = custom_layers.SimpleSpecLayer(sample_rate=SAMPLE_RATE,
                                spec_shape=SPEC_SHAPE,
                                frame_step=int(SAMPLE_RATE * SPEC_LENGTH / (SPEC_SHAPE[1] + 1)),
                                data_format='channels_last',
                                name='SIMPLESPEC')(inputs)

    print('    INPUT LAYER  IN SHAPE:', inputs.shape)
    print('    INPUT LAYER OUT SHAPE:', net.shape)

    # Preprocessing convolution
    print('  PRE-PROCESSING STEM:')
    net = l.Conv2D(filters=int(FILTERS[0] * RESNET_K),
                   kernel_size=KERNEL_SIZES[0],
                   strides=(2, 1),
                   padding='same',
                   data_format='channels_last',
                   kernel_initializer=initializers[INITIALIZER],
                   name='CONV_0')(net)

    # Batch norm layer
    net = l.BatchNormalization(axis=-1, name='BNORM_0')(net)
    net = activations[ACTIVATION](net)
    print('    FIRST  CONV OUT SHAPE:', net.shape)

    # Max pooling
    net = l.MaxPooling2D(pool_size=(2, 2), data_format='channels_last', name='POOL_0')(net)
    print('    FIRST  POOL OUT SHAPE:', net.shape)

    # Residual Stacks
    for i in range(1, len(FILTERS)):
        print('  RES STACK', i, ':')
        net = resBlock(net,
                       filters=int(FILTERS[i] * RESNET_K),
                       kernel_size=KERNEL_SIZES[i],
                       stride=2,
                       preactivated=True,
                       block_id=i,
                       name='BLOCK_' + str(i) + '-1')

        for j in range(1, RESNET_N):
            net = resBlock(net,
                           filters=int(FILTERS[i] * RESNET_K),
                           kernel_size=KERNEL_SIZES[i],
                           preactivated=False,
                           block_id=i+j,
                           name='BLOCK_' + str(i) + '-' + str(j + 1))

    # Post Activation
    net = l.BatchNormalization(axis=-1, name='BNORM_POST')(net)
    net = activations[ACTIVATION](net)

    # Classification branch
    print('  CLASS BRANCH:')
    net = classificationBranch(net,  BRANCH_KERNEL_SIZE)
    print('    BRANCH OUT SHAPE:', net.shape)

    # Pooling
    net = l.GlobalAveragePooling2D(data_format='channels_last', name='GLOBAL_AVG_POOL')(net)
    print('  GLOBAL POOLING SHAPE:', net.shape)

    # Classification layer
    outputs = k.activations.sigmoid(net)
    print('  FINAL NET OUT SHAPE:', outputs.shape)

    # Build Keras model
    model = k.Model(inputs=inputs, outputs=outputs, name='BirdNET')

    # Print model stats
    print('...DONE!')
    #log.l(model.summary())

    print('MODEL HAS', (len([layer for layer in model.layers if len(layer.get_weights()) > 0])), 'WEIGHTED LAYERS (', len(model.layers), 'TOTAL )')
    print('MODEL HAS', model.count_params(), 'PARAMS')

    return model

def saveModel(model, name):

    print('SAVING MODEL...', end='')
    model.save(os.path.join('model', name))
    print('DONE!')

if __name__ == '__main__':

    model = buildModel()
    saveModel(model, 'BirdNET_1000_RAW_model.h5')


import sys
import re
import subprocess

def checkOperatingSystem():
    proc = subprocess.Popen(["grep", "^NAME", "/etc/os-release"], stdout=subprocess.PIPE)
    output = proc.stdout.read()

    if "Debian" in output.decode():
        print("Debian")
    elif "RHEL" in output.decode():
        print("RHEL")

def hostSyntaxCheck(host):
    hostName = host.split("@")

    if len(hostName) == 2 and hostName[1] != "":
        return True
    else:
        return False

def parser():
    if len(sys.argv) == 2:
        print("Correct Argument Number")
    else:
        print("Incorrect Argument Number")

    hostSyntaxCheck(sys.argv[1])
    checkOperatingSystem()
    # Matching regular expression of username with given OS

parser()


import os
import jsonpickle as json
import importlib
from . import log_manager

def get_files_in_folder(path):
    try:
        return os.listdir(path)
    except:
        log_manager.warning("Could not get a list of dirs")
        return []

def create_folder(path):
    if os.path.exists(path):
        log_manager.log("Directory already exists")
        return

    try:
        os.makedirs(path)
    except:
        log_manager.warning("Could not create dir")
    else:
        log_manager.log("Created folder structure: ", path)

def delete_folder(path):
    try:
        os.rmdir(path)
    except:
        log_manager.warning("Could not delete dir")
    else:
        log_manager.log("Deleted folder structure: ", path)

def encode_to_json(obj, forWeb=False):
    try:
        if(forWeb):
            return json.encode(obj, unpicklable=False)
        else:
            return json.encode(obj)
    except:
        log_manager.warning("Couldn't convert to JSON")
        return ""

def decode_json(text):
    try:
        return json.decode(text)
    except:
        log_manager.warning("Couldn't convert to python object")
        return None

def exists(path, name):
    s = os.path.join(path, name)
    return os.path.exists(s)

#open file and return text
def open_file(path, name):
    s = os.path.join(path, name)
    try:
        file = open(s, encoding='utf-8')
        text = file.read()
        file.close()
        log_manager.log("Opened file: ", s)
        return text
    except:
        log_manager.warning("Couldn't open file")
        return ""

#save text to the specified path, creates new if it doesn't exist
def write_file(path, name, text):
    s = os.path.join(path, name)
    try:
        file = open(s, mode='w', encoding='utf-8')
        file.write(text)
        file.flush()
        file.close()
        log_manager.log("written to/ created: ", s)
        return True
    except Exception as e:
        log_manager.warning(str(e))
        return False

def delete_file(path, name):
    try:
        s = os.path.join(path, name)
        if os.path.exists(s):
            os.remove(s)
            log_manager.log("deleted: ", s)
            return True
    except:
        log_manager.warning("Couldn't delete file")
        return False

"""
Imports a module and class on runtime
This function works only if the filname IS EXACTLY THE SAME
as the classname, or give a specific classname.
Returns an attribute that can be instantiated as a class

param modulename: name of the module
param classname: OPTIONAL, name of the class to import
param pkgname: name of the package the module is in
"""
def dynamic_import_module(modulename, *, classname = "", pkgname=""):
    try:
        path = "."+pkgname+"."+modulename
        module = importlib.import_module(path , package="cosplay_manager_server")
        dynClass = None
        if classname == "":
            dynClass = getattr(module, modulename)
        else:
            dynClass = getattr(module, classname)
        return dynClass

    except Exception as e:
        log_manager.error(str(e))
        return None


import mwparserfromhell as parser
import re

ExternalLink = parser.nodes.external_link.ExternalLink
Argument = parser.nodes.argument.Argument
Template = parser.nodes.template.Template
Wikilink = parser.nodes.wikilink.Wikilink
Comment = parser.nodes.comment.Comment
Heading = parser.nodes.heading.Heading
Text = parser.nodes.text.Text
Tag = parser.nodes.tag.Tag
Node = parser.nodes.Node

def get_heading(heading):
  properties = normalize_section(heading.title.nodes)
  if properties[0]["type"] == "text":
    properties[0]["text"] = properties[0]["text"].lstrip()

  return {
    "properties": properties,
    "level": heading.level,
    "type": "heading",
  }

def get_template(template):
  params = template.params
  name = str(template.name)

  result = {
    "type": "template",
    "content": [],
    "params": {},
    "name": name,
  }

  for param in params:
    if param.showkey:
      result["params"][str(param.name)] = str(param.value)
    else:
      result["content"].append(normalize_section(param.value.nodes))

  return result

def get_tag(tag):
  result = {
    "closing_tag": str(tag.closing_tag),
    "attributes": str(tag.attributes),
    "self_closing": tag.self_closing,
    "implicit": tag.implicit,
    "type": "tag"
  }

  if tag.closing_wiki_markup:
    result["closing_wiki_markup"] = str(tag.closing_wiki_markup),

  if tag.contents:
    result["properties"] = normalize_section(tag.contents.nodes)
  else:
    result["properties"] = []
  return result

def get_wikilink(link):
  result = {
    "title": str(link.title)
  }

  matching_file = re.compile("^(File|Файл):.*$")
  if matching_file.fullmatch(result["title"]):
    result["type"] = "filelink"
  else:
    result["type"] = "wikilink"
    if link.text:
      result["text"] = str(link.text)

  if (link.text):
    result["text"] = str(link.text)
  return result

def get_external_link(link):
  return {
    "title": str(link.title),
    "url": str(link.url),
    "type": "link",
  }

def normalize_section(nodes):
  result = []

  for index, node in enumerate(nodes):
    node_type = type(node)

    if node_type == Text:
      result.append({
        "text": node.value,
        "type": "text"
      })

    elif node_type == Heading:
      heading = get_heading(node)
      result.append(heading)

    elif node_type == Template:
      template = get_template(node)
      result.append(template)

    elif node_type == Tag:
      tag = get_tag(node)
      result.append(tag)

    elif node_type == Wikilink:
      wikilink = get_wikilink(node)
      result.append(wikilink)

    elif node_type == ExternalLink:
      external_link = get_external_link(node)
      result.append(external_link)

  return result

def parse(wikicode):
  sections = parser.parse(wikicode).get_sections()
  result_nodes = [ normalize_section(section.nodes) for section in sections ]
  return result_nodes


import cv2
import os
import numpy as np
import pickle as pkl
import mediapipe as mp
from utils.mediapipe_utils import mediapipe_detection

def landmark_to_array(mp_landmark_list):
    """Inputs a list to return a np array of size (nb_keypoints x 3)"""
    keypoints = []
    for landmark in mp_landmark_list.landmark:
        keypoints.append([landmark.x, landmark.y, landmark.z])
    return np.nan_to_num(keypoints)

def extract_landmarks(results):
    """Extract the results of pose and convert into np array
    if a pose doesn't appear, return an array of zeros
    :param results: mediapipe object that contains the 3D position of all keypoints
    :return: Two np arrays of size (1, 33 * 3) = (1, nb_keypoints * nb_coordinates) corresponding to both hands
    """
    pose = landmark_to_array(results.pose_landmarks).reshape(99).tolist()
    return pose

def save_landmarks_from_video(video_name):

    landmark_list = {"pose": []}
    yoga_name = video_name.split("-")[0]
    # Set the Video stream
    cap = cv2.VideoCapture(
        os.path.join("data", "videos", yoga_name,video_name + ".mp4")
    )
    with mp.solutions.holistic.Holistic(
        min_detection_confidence=0.5, min_tracking_confidence=0.5
    ) as holistic:
        # print(cap.isOpened())#This is outputting false
        while cap.isOpened():
            ret, frame = cap.read()
            if ret:
                # Make detections
                image, results = mediapipe_detection(frame, holistic)
                # Store results
                pose = extract_landmarks(results)
                landmark_list["pose"].append(pose)
            else:
                break

        cap.release()
    # Create the folder of the pose if it doesn't exists
    path = os.path.join("data", "dataset", yoga_name)
    if not os.path.exists(path):
        os.mkdir(path)

    # Create the folder of the video data if it doesn't exists
    data_path = os.path.join(path, video_name)
    if not os.path.exists(data_path):
        os.mkdir(data_path)

    # Saving the landmark_list in the correct folder
    save_array(
        landmark_list["pose"], os.path.join(data_path, f"pose_{video_name}.pickle")
    )

def save_array(arr, path):
    file = open(path, "wb")
    pkl.dump(arr, file)
    file.close()

def load_array(path):
    file = open(path, "rb")
    arr = pkl.load(file)
    file.close()
    return np.array(arr)


from celery import shared_task
from celery.task import periodic_task
from celery.schedules import crontab
from django.core.mail import send_mail
from datetime import timedelta
from django.conf import settings

@shared_task(retry_kwargs={'max_retries': 3, 'countdown': 5})
def send_update_mail(title, email_from=settings.FROM_EMAIL):
    try:
        send_mail(
            'Information Mail',
            'A new movie ' + title + ' was created!',
            email_from,
            [settings.ADMIN_EMAIL_ADDRESS],
            fail_silently=False
        )
        return True
    except Exception as e:
        try:
            send_update_mail.retry()
        except MaxRetriesExceededError:
            retry_email_1h(title)

@periodic_task(run_every=timedelta(hours=1), options={"task_id":"12345"})
def retry_email_1h(title, email_from=settings.FROM_EMAIL):
    send_mail(
        'Information Mail',
        'A new movie ' + title + ' was created!',
        email_from,
        [settings.ADMIN_EMAIL_ADDRESS],
        fail_silently=False
    )
    stop()

def stop():
    x = revoke("12345",terminate=True,signal="KILL")


# coding: utf-8

# In[89]:

from collections import Counter
import scipy.stats as stats
import pandas as pd
import os
import skimage.io as io
import matplotlib.pyplot as plt
import csv
import errno
import sys
import random

#reload(sys)
#sys.setdefaultencoding('utf8')

def chunks(listItems, groupSize):
    #Generator function to yield chuncks of 4 from the list
    for i in range(0, len(listItems), groupSize):
        yield listItems[i:i + groupSize]

def produceLabel(answerList):
    entropy = stats.entropy(createFreqDistribution(answerList))
    return entropy

def createFreqDistribution(answerList):
    #print "before>>>"
    #print answerList
    #print "<<<<<<<<after>>>>>>"
    answerList=[ans.lower() for ans in answerList]
    #print answerList
    uniqueAnswers = Counter(answerList).keys()
    answersFrequencies = Counter(answerList).values()
    frequencyVector = []
    numSamples = 10
    for count in answersFrequencies:
        frequency = float(count)/float(numSamples)
        frequencyVector.append(frequency)

    numZeros = numSamples - len(answersFrequencies)
    for i in range(numZeros):
        frequencyVector.append(0)
    return frequencyVector

# In[90]:

def search_dictionary(key, value, list_of_dictionaries):
    return [element for element in list_of_dictionaries if element[key] == value]

# User-configurable parameter
baseDir = "D:/Study !/CPU-Vision/project/test/VQACrowdSourcing/data/"
imgDirPath = "https://www.cs.utexas.edu/~dgurari/Projects/vqAnswerCollection/" + "Images/"
vqasPath = baseDir + "Answers/answers.xls"
destPath = baseDir + "Res-Test/"

df = pd.read_excel(open(vqasPath,'rb'), sheetname='answers')
allHITResults = df['hitResult'].values

questionList = []
answersList = {}
entropyMoreHalf=[]
entropyBetweenHalfandThreeHalf=[]
entropyMoreThanThreeHalf=[]
checkCount=0
with open(destPath+'../testInput.input', 'wb') as csvfile:
    VQAWriter = csv.writer(csvfile,delimiter='\t', quoting=csv.QUOTE_MINIMAL)
    VQAWriter.writerow(["i1", "i2", "i3","i4"])
    for hit in allHITResults:
        processedhit = hit.replace("[", "")
        processedhit = processedhit.replace("]", "")
        processedhit = processedhit.replace("\"", "")
        processedhit = processedhit.replace("{", "")
        vqas = processedhit.split('}')
        for vqa in vqas:  # ignore last entry which will be blank
            if (len(vqa) == 0):
                continue
            if (vqa[0] == ','):
                vqa = vqa[1:len(vqa)]
            imgIndex = vqa.find("imgID:")
            questionIndex = vqa.find("question:")
            answerIndex = vqa.find("answer:")
            answerConfIndex = vqa.find("ansConf:")
            imageName = vqa[imgIndex+6:questionIndex-1]
            question = vqa[questionIndex+9:answerIndex-1]
            answer = vqa[answerIndex+7:answerConfIndex-1]
            # answerConf = vqaPieces[3].replace("ansConf:","")
            dict = {'imageName': imageName, 'question': question}
            questionList.append(dict)
            answersList.setdefault(imageName, []).append(answer)
            imgPath = imgDirPath + imageName
            imgText = question + '\n'
            curAnswers = answersList.get(imageName)
            answers = '#'.join(map(str, curAnswers))
            if (len(curAnswers) == 10):
                entropyVal=produceLabel(curAnswers)
                if(entropyVal>1.5):
                    entropyMoreThanThreeHalf.append(imageName+"|"+question+"|"+answers+"|"+str(3)+"|"+"V")
                elif(entropyVal>1.0 and entropyVal<1.5):
                    entropyBetweenHalfandThreeHalf.append(imageName+"|"+question+"|"+answers+"|"+str(2)+"|"+"V")
                elif(entropyVal>0.5):
                    entropyMoreHalf.append(imageName+"|"+question+"|"+answers+"|"+str(1)+"|"+"V")
                else:
                    checkCount+=1

    entropyMoreThanThreeHalf=random.sample(entropyMoreThanThreeHalf,16)
    entropyBetweenHalfandThreeHalf=random.sample(entropyBetweenHalfandThreeHalf,16)
    entropyMoreHalf=random.sample(entropyMoreHalf,16)

    for element in chunks(entropyMoreThanThreeHalf,4):
        VQAWriter.writerow(element)
    for element in chunks(entropyBetweenHalfandThreeHalf,4):
        VQAWriter.writerow(element)
    for element in chunks(entropyMoreHalf,4):
        VQAWriter.writerow(element)

# In[60]:

# In[ ]:


"""
Given a collection of candidate numbers (candidates) and a target number (target),
find all unique combinations in candidates where the candidate numbers sums to target.

Each number in candidates may only be used once in the combination.

Note:

All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
Example 1:

Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]
Example 2:

Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:
[
  [1,2,2],
  [5]
]
"""

class Solution(object):
    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        res = []
        res = []
        candidates.sort()
        self.backtrack([], res,candidates, target,0)
        return res

    def backtrack(self, temp, res,candidates, target,start):
        if sum(temp) > target:
            return
        if sum(temp) == target:
            res.append(temp)
            return
        for i in range(start,len(candidates)):
            if i > start and candidates[i] == candidates[i-1]:
                continue
            self.backtrack(temp+[candidates[i]], res,candidates, target,i+1)


from setuptools import setup, find_packages
from pip.req import parse_requirements
from pip.exceptions import InstallationError

try:
    requirements = parse_requirements("requirements.txt")
    install_requires = [str(r.req) for r in requirements]
except InstallationError:
    install_requires = []

try:
    long_description = open("README.rst").read()
except IOError:
    long_description = ""

setup(
    name="vim-winclipper",
    version="0.0.1",
    description="Vagrant VM vim register to Windows clipboard",
    license="MIT",
    author="Mikael Fridh",
    author_email="frimik@gmail.com",
    url="https://github.com/frimik/vim-winclipper",
    packages=find_packages(),
    install_requires=install_requires,
    long_description=long_description
)


import os
from PIL import Image

# Function to rename and convert .jpg files to .png
def rename_jpg_to_png(folder_path, folder_name, parent_directory):
    i = 0
    for filename in os.listdir(folder_path):
        if filename.endswith('.jpg'):

            png_image = Image.open(parent_directory + "\\" + folder_name + "\\" + filename)
            jpeg_image = png_image.convert("RGB")
            jpeg_image.save(parent_directory + "\\" + folder_name + "\\" + folder_name + "_" + str(i) + ".jpg", "JPEG")
            i += 1
            os.remove(parent_directory + "\\" + folder_name + "\\" + filename)

# List of folder names
folder_names = ['Ahri', 'Annie', 'Corki', 'Garen', 'Miss_fortune', 'Jinx', 'Nidalee', 'Poppy', 'Yasuo', 'Urgot']

# Specify the parent directory where the folders are located
parent_directory = "bloc 4 DL\Who's that Pkmn\Dataset champion"

# Iterate through each folder and rename .jpg files to .png
for folder_name in folder_names:
    folder_path = os.path.join(parent_directory, folder_name)

    # Check if the folder exists
    if os.path.exists(folder_path):
        rename_jpg_to_png(folder_path, folder_name, parent_directory)
    else:
        print(f"Folder not found: {folder_path}")


import numpy as np
import pandas as pd
import random
import tqdm
import os
import sys

def main():

	base_path = sys.argv[1]
	df = pd.read_csv(os.path.join(base_path, "trainLabels.csv"))
	df.loc[df["level"] > 0, "level"] = 1
	data = df.values
	N, _ = data.shape

	print(f"Creating split for kaggle dataset with {N} images.")

	train_ratio, val_ratio = 0.85, 0.15

	img_ids = data[:,0].tolist()
	person_ids = list(set(i.split('_')[0] for i in img_ids))
	person_ids_to_ind = {}
	for i, img_id in enumerate(img_ids):
		p_id = img_id.split('_')[0]
		if p_id in person_ids_to_ind: person_ids_to_ind[p_id].append(i)
		else: person_ids_to_ind[p_id] = [i]

	z0 = np.mean(data[:,1])
	min_score = np.inf
	best_train_ind = None

	for _ in tqdm.tqdm(range(2000)):

		train_person_ids = random.sample(person_ids, int(train_ratio*len(person_ids)))
		train_split_ind = [j for i in train_person_ids for j in person_ids_to_ind[i]]

		s = abs(z0 - np.mean(data[train_split_ind, 1]))

		if s < min_score:
			min_score = s
			best_train_ind = train_split_ind
			s = f"min score: {min_score:.7f}"
			tqdm.tqdm.write(s)

	best_train_ind = sorted(best_train_ind)
	best_val_ind = sorted(list(set(range(N)) - set(best_train_ind)))

	train_df = df.iloc[best_train_ind]
	val_df   = df.iloc[best_val_ind]

	train_df.to_csv(os.path.join(base_path, "train_ann.csv"), index=False)
	val_df.to_csv(os.path.join(base_path, "val_ann.csv"), index=False)

	print("Done!")

if __name__ == "__main__":
	main()


from assignment import *

def main():
    # -----
    # 1. Load the list of 100 most frequent words from Part I.
    # 2. Load the context dictionary using the load_pkl function.
    # 3. Compute the spectral word embeddings for the top 100 words.
    # 3. Create a text file called top_100_dist.txt, with 100 lines, each line
    #    corresponding to a word on the same line in the top_100_list.txt file.
    #    The top_100_sim.txt file should contain a series of 100 floating point
    #    numbers in each line (10000 numbers total). The numbers should be your
    #    computed spectral distances to each of the words in the
    #    top_100_list.txt. This means the diagonal numbers should all be 0.0,
    #    and a number in row i, column j should represent the distance from the
    #    ith to the jth word in the top_100_list.txt loaded in step 1. Use your
    #    Use your implementation of the word_distance function.
    # 4. Answer the question: Which method of finding nearest neighbors do you
    #    suspect might be better in general (context similarity of spectral
    #    distance)? Why? Why do you think the results in this particular
    #    exercise might favor the similarity method (think data size used).
    #
    # YOUR CODE GOES HERE
    # 1
    top100 = open('top_100_list.txt').read()
    words = top100.split('\n')
    # 2

    cd = load_pkl('cd.pkl')
    cd2 = dict()
    for x in cd.keys():
        if x in words:
            values = cd[x]
            cd2[x] = values
    cd = cd2
    # 3
    sim_matrix, word_index = get_sim_matrix(cd)
    l = get_normalized_laplacian(sim_matrix)
    k = 100
    v = get_eigenvector_matrix(l, k)
    wv = get_word_vectors(v, word_index)
    word_dist = []
    for w1 in words:
        for w2 in words:
            word_dist.append(word_distance(w1, w2, wv))

    f = open('top_100_dist.txt', 'w')
    for n, i in enumerate(word_dist):
        if (n + 1) % 100 == 0:
            f.write(str(i) + "\n")
        else:
            f.write(str(i) + ",")
    f.close()

    # YOUR ANSWERS GO HERE
    # To get the spectral distance I had to get the normalized laplacian
    # for the 40,000+ individual words and when getting the matrix of (40,000+ , 40,000+),
    # I have hit an memmory error when getting 'l'.  From my own experiment,
    # I found out that for this corpus, using the similarity method
    # saves data and it is much faster to compute compared to spectral distance.
    # Thus, from reasons above, context similarity is better when obtaining nearest neighbors.
    # -----
    return

if __name__ == "__main__":
    main()


# -*- coding: utf-8 -*-
"""
Created on Thu Mar 17 09:33:13 2022

@author: hmkao
"""

from linebot import LineBotApi
from linebot.models import TextSendMessage

#-- Link to the "Capstone_bot"

line_bot_api= LineBotApi('channel_access_token') #在 line_developer取得

"""
Push API:      發送 1：1 訊息（指定）。
Multicast API: 一次發送訊息給多個好友（指定）。
Broadcast API: 一次發送訊息給所有的好友。
"""

# In[] Push API

# Specify User ID
user_id= 'your user id'  #在 line_developer取得

# Push text you want
Push_api_str= 'This is a "Push API test" for the capstone course.'

# Push API command
line_bot_api.push_message(user_id, TextSendMessage(text= Push_api_str))

# In[] Broadcast API

# Broadcast text you want
Broadcast_api_str= 'This is a "Broadcast API test" for the capstone course.'

# Broadcast API command
#line_bot_api.broadcast(TextSendMessage(text= Broadcast_api_str))


import customtkinter as ctk  # Enhanced tkinter module for improved UI elements
from datetime import date  # Date module for handling date operations

# Define the 'Penalties' class, inheriting from customtkinter's CTkFrame
class Penalties(ctk.CTkFrame):
    def __init__(self, parent, controller, db):
        super().__init__(parent)    # Initialize the parent class (CTkFrame)
        # Initialize attributes for storing various data and UI elements
        self.scrollable_frame = None
        self.lapsL = None
        self.trackL = None
        self.countryL = None
        self.penalties = None
        self.lapsT = None
        self.trackT = None
        self.countryT = None

        self.controller = controller  # Controller reference
        self.data = db  # Database connection
        self.load_data(self.controller.race_menu.get())  # Load data based on the selected race
        self.setup_ui()  # Setup the user interface

    def setup_ui(self):
        # Set grid weights for layout management and create UI elements
        # Configure rows and columns with appropriate weights for the layout

        # Set weights for rows and columns
        self.grid_rowconfigure(1, weight=0)  # Country label row
        self.grid_rowconfigure(2, weight=0)  # Track row
        self.grid_rowconfigure(3, weight=1)  # Scrollable Frame row

        self.grid_columnconfigure(1, weight=1)  # Country and track label column
        self.grid_columnconfigure(2, weight=1)  # This will be the container for the segmented button
        self.grid_columnconfigure(3, weight=1)  # Laps and Pts label column

        # UI Elements

        self.countryL = ctk.CTkLabel(self, text=self.countryT, font=("Lucidia Sans", 25))
        self.countryL.grid(row=1, column=1, sticky="nw", padx=20, pady=10)

        self.trackL = ctk.CTkLabel(self, text=self.trackT, font=("Lucidia Sans", 20))
        self.trackL.grid(row=2, column=1, sticky="nw", padx=20)

        self.lapsL = ctk.CTkLabel(self, text=f"Laps: {self.lapsT}", font=("Lucidia Sans", 20))
        self.lapsL.grid(row=1, column=2, sticky="ne", columnspan=3, padx=20, pady=10)

        self.scrollable_frame = ctk.CTkScrollableFrame(self, width=720, height=200)
        self.scrollable_frame.grid(row=3, column=1, columnspan=3, pady=10, sticky="nsew")

        self.fill_penalties()

    def fill_penalties(self):
        # Update label text with the current data and populate penalties
        # Clear existing content in the scrollable frame
        # Iterate over fetched penalty data, creating and positioning labels
        self.countryL.configure(text=self.countryT)
        self.trackL.configure(text=self.trackT)
        self.lapsL.configure(text=f"Laps: {self.lapsT}")

        for widget in self.scrollable_frame.winfo_children():
            widget.destroy()

        i = 0
        while self.penalties:
            nameT = self.penalties[0]
            sessionT = self.penalties[1]
            offenceT = self.penalties[2]
            decisionT = self.penalties[3]

            self.scrollable_frame.grid_columnconfigure(0, weight=1)
            self.scrollable_frame.grid_columnconfigure(1, weight=1)
            self.scrollable_frame.grid_columnconfigure(2, weight=1)

            nameL = ctk.CTkLabel(self.scrollable_frame, text=nameT, font=("Lucidia Sans", 17))
            nameL.grid(row=i, column=0, sticky="nw", padx=20, pady=10)

            sessionL = ctk.CTkLabel(self.scrollable_frame, text=sessionT, font=("Lucidia Sans", 17))
            sessionL.grid(row=i, column=1, sticky="nw", padx=20, pady=10)

            offenceL = ctk.CTkLabel(self.scrollable_frame, text=offenceT, font=("Lucidia Sans", 17))
            offenceL.grid(row=i, column=2, sticky="nw", padx=20, pady=10)

            decisionL = ctk.CTkLabel(self.scrollable_frame, text=decisionT, font=("Lucidia Sans", 17))
            decisionL.grid(row=i, column=3, sticky="nw", padx=20, pady=10)

            self.penalties = self.data.fetchone()
            i += 1

    def load_data(self, race, season=date.today().year):
        # Load penalty data based on the selected race and season
        # Execute SQL queries to fetch race details and penalty data
        # Update class attributes with fetched data
        query = (
            f"SELECT r.country, r.track, r.laps, r.season, r.round FROM races r WHERE r.season = {season} AND r.track ="
            "? ORDER BY date DESC")
        self.data.execute(query, (race,))
        fetched = self.data.fetchone()

        self.countryT = fetched[0]
        self.trackT = fetched[1]
        if fetched[2] is not None:
            self.lapsT = str(int(fetched[2]))
        else:
            self.lapsT = "Not Updated Yet"
        seasonT = fetched[3]
        roundT = fetched[4]

        query = ("SELECT d.name, p.session, p.offence, p.decision "
                 "FROM drivers d "
                 "JOIN penalties p ON d.number = p.number AND d.season = p.season "
                 f"WHERE p.round = {roundT} AND p.season = {seasonT} "
                 "ORDER BY p.incident")
        self.data.execute(query)

        self.penalties = self.data.fetchone()


from main import *

def create_InlineKeyboard(keys: list, index:int=1):
    keyboard = types.InlineKeyboardMarkup()
    callback_button_back = types.InlineKeyboardButton(text='<', callback_data=f'back|{len(keys)}|{index}')
    callback_button_ahead = types.InlineKeyboardButton(text='>', callback_data=f'ahead|{len(keys)}|{index}')
    callback_button_first = types.InlineKeyboardButton(text='1', callback_data=f'1|{len(keys)}')
    callback_button_last = types.InlineKeyboardButton(text=f'{math.ceil(len(keys)/15)}', callback_data=f'{math.ceil(len(keys)/15)}|{len(keys)}')
    keyboard.row(callback_button_back, callback_button_first)
    if math.ceil(len(keys)/15) <= 5:  # (1-60)
        for i in range(1, math.ceil(len(keys)/15)):
            print(f'now key is {i+1}')
            key = types.InlineKeyboardButton(text=str(i+1), callback_data=f'{i+1}|{len(keys)}')
            keyboard.insert(key)
        keyboard.insert(callback_button_ahead)

    return keyboard

async def get_top_coin_cmc(message: types.Message):
    text = message.text[4:]
    text = re.sub(r' *_*-*', '', text)  # delete all '_', '-' and ' ' symbols
    text = int(text)-1 % 200+1 if text.isdigit() else 100

    with open('coin_price.json', 'r') as f:
        prices = json.load(f)
        if time.time() - prices['time'] > 5:
            prices = get_top_cryptocurrencies(text)  # {'ETH': 2000.009, 'BTC': 4000.12, 'DOGE': 0.1093}

    response = f'Top {text}(1-15) cryptocurrencies:\n' if text in range(16) else f'Top {text} cryptocurrencies:\n'
    keys = list(prices.keys())[1:]  # prices['time'] delete
    for i in range(15):
        if i in range(len(keys)):
            response += f'{keys[i]}: {round(prices[keys[i]], 4)}$\n'

    if text in range(16):
        await bot.send_message(message.from_user.id, text=response)
    else:
        keyboard = create_InlineKeyboard(keys=keys)
        await bot.send_message(message.from_user.id, text=response, reply_markup=keyboard)

s = 'ahead|58|1'
command, total_amount, *index = s.split('|')
print(command, end='---------------\n')
print(total_amount, end='---------------\n')
print(int(index[0]), end='---------------\n')