import json
import itertools
from PIL import Image, ImageDraw, ImageFont
#calculation algorithm

def day_calc(arr):
    new_arr = sorted(arr)
    total = 0
    for i in range(len(new_arr)-1):
        f= (new_arr[i+1]-new_arr[i])*2
        if f ==0:
            total+= 100000
            break
        else:
            total+= f
    return total

def week_calc(dict):
    total = 0
    for i in dict.values():
        total+= day_calc(i)+7
    return total

def week_main(arr):
    dict1= {}
    for i in arr:
        if i//100000!= 0 :
            if 6 not in dict1:
                dict1[6]=[]
            dict1[6]+= [i//100000]
        elif i//10000!= 0 :
            if 5 not in dict1:
                dict1[5]=[]
            dict1[5]+= [i//10000]
        elif i//1000!= 0 :
            if 4 not in dict1:
                dict1[4]=[]
            dict1[4]+= [i//1000]
        elif i//100!= 0 :
            if 3 not in dict1:
                dict1[3]=[]
            dict1[3]+= [i//100]
        elif i//10!= 0 :
            if 2 not in dict1:
                dict1[2]=[]
            dict1[2]+= [i//10]
        else :
            if 1 not in dict1:
                dict1[1]=[]
            dict1[1]+= [i]

    return week_calc(dict1)

#functions

def convert_to_int(input_string):
    day_dict = {'Sa': 1, 'Su': 10, 'Mo': 100, 'Tu': 1000, 'We': 10000, 'Th': 100000}
    num_dict = {'08': 1, '09': 2, '11': 3, '12': 4, '02': 5, '03': 6, '05': 7}
    day = input_string[:2]
    num = input_string[2:]
    if day in day_dict and num in num_dict:
        return day_dict[day] * num_dict[num]

def course_covert_ONE(data):
    course = {}
    for i in data:
        k= i[2].split()
        for j in range(len(k)):
            if j%3==0:
                if (int(i[1][:2])-1) not in course:
                    course[(int(i[1][:2])-1)]=[]
                course[(int(i[1][:2])-1)] += [convert_to_int(k[j][0:2]+ k[j][3:5])]
    return course

def course_covert_ONE_online(data):
    course = {}
    for i in data:
        if int(i[3])<= 0:
            continue
        k= i[2].split()
        for j in range(len(k)):
            if j%3==0:
                if (int(i[1][:2])-1) not in course:
                    course[(int(i[1][:2])-1)]=[]
                course[(int(i[1][:2])-1)] += [convert_to_int(k[j][0:2]+ k[j][3:5])]
    return course

def course_covert_MANY(courses, available):
    #accessing data
    f = open('data.json')
    data = json.load(f)
    f.close()
    #--------------
    all_courses = {}
    if available:
        for i in courses:
            all_courses[i.upper()]= course_covert_ONE_online(data[i.upper()])
    else:
        for i in courses:
            all_courses[i.upper()]= course_covert_ONE(data[i.upper()])

    return all_courses

def find_best(courselist, filter, available, top):
    a = course_covert_MANY(courselist, available)
    if filter:
        del_list= []
        for key, value in filter.items():
            if key.upper() in a:
                for p,l in a[key.upper()].items():
                    if (p+1) not in value:
                        del_list.append((key.upper(),p))

        for s,d in del_list:
            del a[s][d]

    list1=[]
    for k, v in a.items():
        list1.append(list(v.keys()))

    z=list(itertools.product(*list1))
    test_dict={}
    for i in z :
        day = []
        for j in range(len(i)) :
            day+= a[courselist[j].upper()][i[j]]

        val= week_main(day)
        if val<100000:
            test_dict[i] = val

    sorted_list = sorted(test_dict.items(), key=lambda x:x[1] )

    return a, sorted_list[:top]

def draw_routine_ONE(data_list, input_image_path, output_image_path):
    # Define grid properties
    margin = 180
    grid_columns = 6
    grid_rows = 7

    # Open the input image
    image = Image.open(input_image_path)
    image_width, image_height = image.size

    # Calculate grid cell dimensions
    cell_width = 1+ (image_width - (2 * margin)) // grid_columns
    cell_height = (image_height - (2 * margin)) // grid_rows

    # Create a drawing context
    draw = ImageDraw.Draw(image)

    # Load a font to write the text
    font_path = "Roboto-Regular.ttf"  # Replace with the actual font file path
    font_size = 20
    font = ImageFont.truetype(font_path, font_size)

    # Iterate over the data list and draw each text on the image
    for data in data_list:
        location, text = data

        # Calculate the target cell based on the provided location
        column = len(location)-1
        row = int(location[0])-1

        # Calculate the coordinates of the cell's top-left corner
        x = 273 + (column * cell_width)
        y = 315 + (row * cell_height)

        # Write the text on the image at the calculated position
        draw.text((x, y), text, font=font, fill="#A6E6F7")

    # Save the modified image
    image.save(output_image_path)

def main_function(courselist, filter=None, available=False, top=5):
    a, base = find_best(courselist, filter, available, top)
    main_list =[]
    for z in base:
        listz= []
        b= z[0]
        for i in range(len(b)):
            k = a[courselist[i].upper()][b[i]]
            for kk in k:
                listz.append([str(kk) , courselist[i]+" ("+str(b[i]+1)+")" ])
        main_list.append(listz)
    count= 1
    for i in main_list:
        output= "output/Best "+str(count)+".png"
        draw_routine_ONE(i, "1.png", output)
        count+=1

def course_suggest (courses, filter=None, available=False, course_num=5,lab=2 ,top=5, must=False):
    labs= {'CSE111', 'CSE350', 'CSE220', 'CSE472', 'CSE427', 'CSE360', 'CSE484', 'CSE446', 'ARC101', 'CSE330', 'CSE424', 'ARC401', 'PHY112', 'CSE422', 'MAT092', 'CSE221', 'ARC201', 'ARC402', 'ARC102', 'CSE370', 'CSE460', 'CSE428', 'EEE421', 'PHY111', 'ARC503', 'EEE308', 'ARC501', 'EEE447', 'ARC301', 'CSE341', 'CSE420', 'CSE421', 'CSE489', 'EEE431', 'ARC502', 'CSE321', 'ARC302', 'CSE391', 'EEE472', 'CSE461', 'CSE251', 'CSE447', 'ECE103', 'EEE103', 'CSE471', 'CSE260', 'MAT091', 'ARC202', 'MAT120', 'CSE110', 'EEE385', 'CSE101', 'CSE250', 'CSE423', 'ECE447', 'CSE490', 'CSE310'}
    courses= list(map(str.upper, courses))
    if must:
        must= list(map(str.upper, must))
        for i in must:
            courses.remove(i)
    if must:
        all_combination = itertools.combinations(courses, course_num-len(must))
    else:
        all_combination = itertools.combinations(courses, course_num)
    a={}
    u_base=[]
    for i in all_combination:
        if must:
            i= tuple(list(i)+must)
        if len(labs.intersection(set(list(i))))<lab:
            continue
        a1, base1 = find_best(list(i), filter, available, top)
        a.update(a1)
        for j in base1:
            u_base.append((j[0],j[1], list(i)))
    base= sorted(u_base, key=lambda x: x[1])
    main_list =[]
    for z in base:
        courselist= z[2]
        listz= []
        b= z[0]
        for i in range(len(b)):
            k = a[courselist[i].upper()][b[i]]
            for kk in k:
                listz.append([str(kk) , courselist[i]+" ("+str(b[i]+1)+")" ])
        main_list.append(listz)
    count= 1
    for i in main_list:
        output= "output/Best "+str(count)+".png"
        draw_routine_ONE(i, "1.png", output)
        count+=1
        if count>top:
            break


import re
import requests
import lxml
import pandas as pd
import time
import numpy as np
from bs4 import BeautifulSoup as bs
from random import randint
import Scraping.constants as const
from imdb_probe import Boxy

class MoviePage():
    def __init__(self, movie='The Wasp Woman', url_sfx='/title/tt0054462/'):
        self.name = movie
        self.url_sfx = url_sfx
        self.gross_pattern  = re.compile(r'.+(mojo-performance-summary-table$)')
        self.budget_pattern  = re.compile(r'Budget')
        self.mpaa_pattern  = re.compile(r'MPAA')
        self.genre_pattern  = re.compile(r'Genres')
        self.dictionary_row = {}

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f'Execution Type {exc_type}')
        print(f'Exc val {exc_val}')
        print(f'Exc Trace {exc_tb}')

    def __repr__(self):
        return(f'{self.name} has a url of {self.url_sfx}')

    def input_movie(self, movie, url_sfx):
        self.name = movie
        self.url_sfx = url_sfx

    def url_clean(self, sfx):
        clean_url = sfx.split('?')
        return clean_url[0]

    def crawl(self):
        gross_list = []
        time.sleep(randint(2, 3))
        page = requests.get(const.MOJO_PRE + self.url_sfx,
            headers={'User-Agent': 'Mozilla/5.0'})
        soup = bs(page.text, 'lxml')
        self.dictionary_row['Budget'] = self.get_budget(soup)
        self.dictionary_row['MPAA'] = self.get_mpaa(soup)
        self.dictionary_row['Genre'] = self.get_genre(soup)
        gross_list = self.get_gross(soup)
        self.dictionary_row['D.Gross'] = gross_list[0]
        self.dictionary_row['I.Gross'] = gross_list[1]
        self.dictionary_row['Total Gross'] = gross_list[2]
        if (self.dictionary_row['Budget'] is np.nan
            or self.dictionary_row['MPAA'] == 'Not Found'):
            self.probe_imdb(soup)
        self.check_rerelease(soup)

    def check_rerelease(self, soup):
        if re.match('Re-release', soup.get_text()):
            self.dictionary_row['']
        else:
            return True

    def get_budget(self, soup):
        try:
            budget = soup.find(text=self.budget_pattern).next_element
            budget_amount = int(re.sub('[$,]', '', budget.text))
        except AttributeError:
            budget_amount = np.nan
        return(budget_amount)

    def get_mpaa(self, soup):
        try:
            mpaa = soup.find(text=self.mpaa_pattern).next_element.text
        except AttributeError:
            mpaa = 'Not Found'
        return mpaa.strip()

    def get_genre(self, soup):
        try:
            genre = soup.find(
                text=self.genre_pattern).next_element.text.split()
            return(genre)
        except AttributeError:
            return ('attrerror')

    def get_gross(self, soup):
        grosses = soup.find(class_='mojo-performance-summary-table')
        money_pattern = re.compile('\$[\d+,]+|–')
        grosses = grosses.find_all('span', text=money_pattern)
        for idx, gross in enumerate(grosses):
            if gross.text == '–':
                grosses[idx] = np.nan
                continue
            else:
                grosses[idx] = int(re.sub('[$,]', '', gross.text))
        return(grosses)

    def probe_imdb(self, soup):
        pattern = re.compile('/title/.{2}\d+/')
        title_ref = soup.find('a', href=pattern)['href']
        with Boxy(URL=title_ref) as probe:
            probe.land_page()
            if self.dictionary_row['Budget'] is np.nan:
                try:
                    probe.get_budget()
                except AttributeError:
                    print(f'Error Occured. {self.name}, Budget, probe_imdb')
            if self.dictionary_row['MPAA'] == 'Not Found':
                try:
                    self.dictionary_row['MPAA'] = probe.get_rating_cert()
                except AttributeError:
                    print(f'Error Occured. {self.name}, MPAA, probe_imdb')


#
#
#
#
# New scraper for -> RaiffeisenBank
# RaiffeisenBank job page -> https://www.ejobs.ro/company/raiffeisen/4779
#
#
from random import randint

from A_OO_get_post_soup_update_dec import DEFAULT_HEADERS, update_peviitor_api
from L_00_logo import update_logo
#

from bs4 import BeautifulSoup
import time
import requests
import uuid

def request_and_collect_data(page):
    """
    ... this func() make a simple requests
    and collect data from API.
    """

    response = requests.get(url=f'https://www.ejobs.ro/company/raiffeisen/4779/{page}',
                            headers=DEFAULT_HEADERS)
    soup = BeautifulSoup(response.text, 'lxml')
    soup_data = soup.find_all('div', attrs={'class': 'JobCard'})

    lst_data = []

    for job in soup_data:
        lst_data.append({
            "id": str(uuid.uuid4()),
            "job_title": job.find('h2', attrs={'class': 'JCContentMiddle__Title'}).find('a').text,
            "job_link": 'https://www.ejobs.ro' + job.find('h2', attrs={'class': 'JCContentMiddle__Title'}).find('a')[
                'href'],
            "company": "RaiffeisenBank",
            "country": "Romania",
            "city": job.find('span', attrs={'class': 'JCContentMiddle__Info'}).text.strip(),
        })

    job_links_seen = set()
    final_lst_data = []
    for data in lst_data:
        job_link = data['job_link']
        if job_link not in job_links_seen:
            job_links_seen.add(job_link)
            final_lst_data.append(data)

    return final_lst_data

def scrape_all_data_from_() -> list:
    """
    Scrap all data from , and return big list.
    """

    page = 1
    flag = True

    big_lst_jobs = []
    while flag:

        # collect data from site!
        data_site = request_and_collect_data(page)

        if data_site:
            big_lst_jobs.extend(data_site)

        else:
            flag = False

        page += 1
        time.sleep(randint(1, 2))

    return big_lst_jobs

# update data on peviitor!
@update_peviitor_api
def scrape_and_update_peviitor(company_name, data_list):
    """
    Update data on peviitor API!
    """

    return data_list

company_name = 'RaiffeisenBank'  # add test comment
data_list = scrape_all_data_from_()
scrape_and_update_peviitor(company_name, data_list)

print(update_logo('RaiffeisenBank',
                  'https://www.sun-plaza.ro/wp-content/uploads/2016/10/raiffeisen-bank-logo.jpg'
                  ))


from __future__ import absolute_import
from __future__ import print_function
from pychron.core.ui import set_qt
from six.moves import map

set_qt()
# ============= enthought library imports =======================
from traits.api import HasTraits, Str, Color
from traitsui.api import View, UItem, VGroup

# ============= standard library imports ========================
# ============= local library imports  ==========================

class NewLabelView(HasTraits):
    text = Str
    color = Color

    @property
    def color_str(self):
        f = lambda x: "{:X}".format(x).zfill(2)
        color = self.color
        args = list(map(f, (color.red(), color.green(), color.blue(), color.alpha())))
        return "".join(args)

    def traits_view(self):
        v = View(
            VGroup(UItem("text"), UItem("color")),
            buttons=["OK", "Cancel"],
            kind="livemodal",
            width=500,
            height=500,
            resizable=True,
            title="New Label",
        )
        return v

if __name__ == "__main__":
    nv = NewLabelView()
    nv.configure_traits()
    print(nv.color_str)
# ============= EOF =============================================


import pandas
import os
from geopy.geocoders import Nominatim

def scv_validate(file):
    filename, ext = os.path.splitext(file)
    if ext == ".csv":
        df = pandas.read_csv(file)
        if 'Address' in df.columns:
            return True
        else:
            return False
    else:
        print("Invalid")
        return False

def process_csv(file):
    df = pandas.read_csv(file)
    df['lat'] = [get_lat(address) for address in df.Address]
    df['lon'] = [get_lon(address) for address in df.Address]
    return df

def get_lat(address):
    locator = Nominatim(user_agent="example app")
    point = locator.geocode(address).raw
    return point['lat']

def get_lon(address):
    locator = Nominatim(user_agent="example app")
    point = locator.geocode(address).raw
    return point['lon']


"""
https://leetcode.com/explore/featured/card/top-interview-questions-easy/94/trees/628/

Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).

For example:
Given binary tree [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
return its level order traversal as:
[
  [3],
  [9,20],
  [15,7]
]
"""
from typing import List
from tree import TreeNode

def level_order(root: TreeNode) -> List[List[int]]:
    if root is None:
        return []

    level_vals = [[root.val]]
    prev_level = [root]
    while len(prev_level) > 0:
        next_level_vals = []
        next_level = []
        for node in prev_level:
            if node.left is not None:
                next_level.append(node.left)
                next_level_vals.append(node.left.val)

            if node.right is not None:
                next_level.append(node.right)
                next_level_vals.append(node.right.val)

        prev_level = next_level
        if len(next_level_vals) > 0:
            level_vals.append(next_level_vals)

    return level_vals

def test1():
    root = TreeNode(3)
    root.left = TreeNode(9)
    root.right = TreeNode(20)
    root.right.left = TreeNode(15)
    root.right.right = TreeNode(7)

    print(level_order(root))

test1()


from clients.reservation import reservation_client
from flask import request, current_app
from grpc import RpcError

def create_reservation():
    try:
        return reservation_client.create_reservation(request.json), 201
    except RpcError as e:
        current_app.logger.error("%s", e)
        return e, 502
    except Exception as e:
        current_app.logger.error("%s", e)
        return e, 500

def cancel_reservation():
    try:
        return reservation_client.cancel_reservation(request.json["id"])
    except RpcError as e:
        current_app.logger.error("%s", e)
        return e, 502
    except Exception as e:
        current_app.logger.error("%s", e)
        return e, 500

def complete_reservation():
    try:
        return reservation_client.complete_reservation(request.json["id"])
    except RpcError as e:
        current_app.logger.error("%s", e)
        return e, 502
    except Exception as e:
        current_app.logger.error("%s", e)
        return e, 500

def retrieve_users_reservation(userId):
    try:
        return reservation_client.retrieve_users_reservation(userId)
    except RpcError as e:
        current_app.logger.error("%s", e)
        return e, 502
    except Exception as e:
        current_app.logger.error("%s", e)
        return e, 500

def collect_routes(app):
    app.add_url_rule("/reservation/create", view_func=create_reservation, methods=["POST"])
    app.add_url_rule(
        "/reservation/cancel", view_func=cancel_reservation, methods=["POST"]
    )
    app.add_url_rule(
        "/reservation/complete", view_func=complete_reservation, methods=["POST"]
    )
    app.add_url_rule(
        "/reservation/<string:userId>", view_func=retrieve_users_reservation, methods=["GET"]
    )


import utility

import sys
sys.path.append("./packages")

import openai
import tiktoken
import json
import requests

class ChatApi:
    API_PATH = 'documents/config.json'
    def __init__(self, randomness=1, presence_penalty=0.6, messages_max_token=1500):
        # m_config = config.APIKeys()
        self.randomness = randomness
        self.presence_penalty = presence_penalty
        self.messages_max_token = messages_max_token
        self.api_key = ""
        self.default_api_key = ""
        with open(self.API_PATH, 'r') as file:
            content = json.load(file)
            self.api_key = content["open_ai_key"]
            self.default_api_key = content["open_ai_key"]
        openai.api_key = self.api_key
        self.message_clamper = utility.MessageClamping(self.count_tokens)

    def assign_api_key(self, new_api_key = ""):
        if (new_api_key == ""):
            new_api_key = self.default_api_key
        self.api_key = new_api_key
        openai.api_key = new_api_key

    def get_current_api_key(self):
        return openai.api_key

    @staticmethod
    def count_tokens(text):
        encoding = tiktoken.encoding_for_model('gpt-3.5-turbo')
        try:
            tokens = encoding.encode(text)
            return len(tokens)
        except Exception:
            return self.messages_max_token

    def request_normal(self, request, chat_history):
        messages = request["message_list"]
        pre_lines = request["pre_lines"]
        after_lines = request["after_lines"]
        token_limit = request["token_limit"]
        break_response = request["break_response"]

        (message_being_sent, total_tokens) = self.message_clamper.insert_more_messages_to_messages(messages, chat_history, token_limit, pre_lines, after_lines)
        print(message_being_sent)
        openai.api_key = self.api_key
        # response = self.chat_completion(message_being_sent, "gpt-3.5-turbo", self.randomness, 512, 1, 0, self.presence_penalty, None)
        try:
            response = openai.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=message_being_sent,
                temperature=self.randomness,
                max_tokens=1024,
                top_p=1,
                frequency_penalty=0,
                presence_penalty=self.presence_penalty,
                stop=None
            )
            response["choices"][0]["tokens_spent"] = total_tokens
            return response
        except Exception as e:
            # Handle other exceptions
            return "faild"

    # set max_token equal to 0 to get ride of all the body messages
    def request_hard(self, request, chat_history):
        messages = request["message_list"]
        pre_lines = request["pre_lines"]
        after_lines = request["after_lines"]
        token_limit = request["token_limit"]
        break_response = request["break_response"]

        (message_being_sent, total_tokens) = self.message_clamper.insert_more_messages_to_messages(messages, chat_history, token_limit, pre_lines, after_lines)
        openai.api_key = self.api_key
        # response = self.chat_completion(message_being_sent, "gpt-3.5-turbo", 0, _max_tokens, 1, 0, 0, None)
        try:
            response = openai.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=message_being_sent,
                temperature=0,
                max_tokens=1024,
            )
            response["choices"][0]["tokens_spent"] = total_tokens
            return response
        except Exception as e:
            # Handle other exceptions
            return "faild"


import requests
from helpers import get_frequencies
from helpers import days_in_month
from helpers import BASE_URL

# Get entrees frequencies for a single month
def get_desserts_frequencies(start_year, start_month, location=None):
    desserts_freq = {}
    count = get_frequencies(start_year, start_month, 1,
                            days_in_month(start_year, start_month),
                            [(17, 'Desserts')])
    num_recipes = len(count.keys())
    ordered_frequencies = count.most_common(num_recipes)
    for (recipe_id, _), occurrences in ordered_frequencies:
        url = '{}/recipes/{}'.format(BASE_URL, str(recipe_id))
        name = requests.get(url).json()['name']
        desserts_freq[name] = occurrences
    return desserts_freq

def sort_desserts(start_year, start_month):
    desserts_freq = get_desserts_frequencies(start_year, start_month)
    dessert_types = {
        'Cookies': 0,
        'Pies': 0,
        'Brownies': 0,
        'Squares': 0,
        'Cakes': 0,
        'Frozen Yogurt': 0,
        'Soft Serve Yogurt': 0,
        'Ice Cream': 0,
        'Pudding': 0,
        'Fruit': 0,
        'Others': 0
    }
    for key, value in desserts_freq.items():
        key_sorted = False
        if 'Cookie' in key:
            dessert_types['Cookies'] = dessert_types['Cookies'] + value
            key_sorted = True
        if 'Pie' in key:
            dessert_types['Pies'] = dessert_types['Pies'] + value
            key_sorted = True
        if 'Brownie' in key:
            dessert_types['Brownies'] = dessert_types['Brownies'] + value
            key_sorted = True
        if 'Square' in key:
            dessert_types['Squares'] = dessert_types['Squares'] + value
            key_sorted = True
        if 'Cake' in key or 'cake' in key or 'Tiramisu' in key:
            dessert_types['Cakes'] = dessert_types['Cakes'] + value
            key_sorted = True
        if 'Frozen Yogurt' in key:
            dessert_types['Frozen Yogurt'] = dessert_types['Frozen Yogurt'] + value
            key_sorted = True
        if 'Soft Serve Yogurt' in key:
            dessert_types['Soft Serve Yogurt'] = dessert_types['Soft Serve Yogurt'] + value
            key_sorted = True
        if 'Ice Cream' in key:
            dessert_types['Ice Cream'] = dessert_types['Ice Cream'] + value
            key_sorted = True
        if 'Pudding' in key:
            dessert_types['Pudding'] = dessert_types['Pudding'] + value
            key_sorted = True
        if key == 'Pineapple' or key == 'Watermelon':
            dessert_types['Fruit'] = dessert_types['Fruit'] + value
            key_sorted = True
        if not key_sorted:
            dessert_types['Others'] = dessert_types['Others'] + value
    return dessert_types

def append_desserts_data(start_year, start_month, X_list, Y_cook, Y_ps, Y_br,
                         Y_sq, Y_cake, Y_fy, Y_ssy, Y_ic, Y_pd, Y_fr, Y_ot):
    X_list.append(str(start_month) + '/' + str(start_year))
    Y_lists = {
        'Cookies': Y_cook,
        'Pies': Y_ps,
        'Brownies': Y_br,
        'Squares': Y_sq,
        'Cakes': Y_cake,
        'Frozen Yogurt': Y_fy,
        'Soft Serve Yogurt': Y_ssy,
        'Ice Cream': Y_ic,
        'Pudding': Y_pd,
        'Fruit': Y_fr,
        'Others': Y_ot
    }
    desserts_freq = sort_desserts(start_year, start_month)
    for key, value in Y_lists.items():
        value.append(desserts_freq[key])


import os
import cv2
import numpy as np
import h5py
import re
from collections import defaultdict
import glob
import random
from sklearn.decomposition import IncrementalPCA, PCA
from sklearn.cluster import KMeans
import glob
import shutil
import ntpath
from collections import Counter
import ntpath

def combine_images_into_tensor(img_fnames, width, height):
    """
    Given a list of image file names, read the images, flatten them
    and return a tensor such that each row contains one image.

    Size of individual image: 300*300
    """
    # Initialize the tensor
    tensor = np.zeros((len(img_fnames), width * height))

    for i, fname in enumerate(img_fnames):
        try:
            img = cv2.imread(fname, cv2.IMREAD_GRAYSCALE)
            img = cv2.resize(img, (width, height), interpolation=cv2.INTER_AREA)
            tensor[i] = img.reshape(width * height)
        except Exception as ex:
            print(fname)

    return tensor

def get_image_fnames(img_dir):
    """
    Return ist of needed images
    """
    fnames = list(glob.glob(f"{img_dir}/*.png"))
    # print(fnames)
    return fnames

def get_pca_reducer(tr_tensor):
    # Apply PCA on the training images
    pca = PCA(n_components=12)
    pca.fit(tr_tensor)

    return pca

def cluster_images(all_img_fnames, num_clusters, width, height):
    # Select 200 images at random for PCA
    random.shuffle(all_img_fnames)
    tr_img_fnames = all_img_fnames[:500]

    # Flatten and combine the images
    tr_tensor = combine_images_into_tensor(tr_img_fnames,width,height)

    # Perform PCA
    pca = get_pca_reducer(tr_tensor)
    print("PCA REDUCER DONE")
    # Reduce dimensions of all
    all_tensor = combine_images_into_tensor(all_img_fnames,width,height)
    points = pca.transform(all_tensor)
    print("TRANSFORM IS DONE")
    # Cluster
    kmeans = KMeans(n_clusters=num_clusters, random_state=0).fit(points)
    print("CLUSTER IS DONE")
    cluster_fnames = defaultdict(list)
    for i, label in enumerate(kmeans.labels_):
        cluster_fnames[label].append(all_img_fnames[i])

    for k in cluster_fnames:
        print(k, len(cluster_fnames[k]), cluster_fnames[k][:3])
        destPath = os.path.join(r"E:\karim\Code\Clusters", str(k))
        if(not os.path.isdir(destPath)):
            os.mkdir(destPath)

        for fname in cluster_fnames[k]:
            destPath = os.path.join(r"E:\karim\Code\Clusters", str(k))
            destPath = os.path.join(destPath, ntpath.basename(fname))
            shutil.copy(fname,destPath)

if __name__ == "__main__":
    all_img_fnames = get_image_fnames(r"E:\karim\Code")
    cluster_images(all_img_fnames, 1000, 400 , 400)


from modulator import module_audio
import numpy as np
from parameters import CHANNELS, CHUNK, NP_TYPE, PA_TYPE, RATE
import pyaudio as pa
import scipy.signal as signal
import time

p = pa.PyAudio()

def filter_audio(data):
    """
    Performs digital filter audio filtering.
    :param data: input sound data, numpy array
    :return: filtered sound data, numpy array
    """
    # elliptic filter with those parameters proved
    # experimentally to be the best
    b, a = signal.iirdesign(0.2, 0.3, 4, 60, ftype="ellip")
    data = signal.filtfilt(b, a, data).astype(NP_TYPE)
    return data

# function for manipulating input data
def callback(data, frame_count, time_info, flag):
    """
    Applies sound effects to input and outputs it in real time.
    :param data: input sound data, byte stream
    :param frame_count: unused, see PyAudio documentation
    :param time_info: unused, see PyAudio documentation
    :param flag: unused, see PyAudio documentation
    :return: tuple of: audio data after applying sound effects (numpy array),
    PyAudio constant to continue recording
    """
    data = np.frombuffer(data, dtype=NP_TYPE)
    data = filter_audio(data)
    data[abs(data) < 10] = 0

    data = module_audio(data, RATE, NP_TYPE)

    data[abs(data) < 10] = 0

    return data, pa.paContinue

def playback(callback_function):
    """
    Records audio in endless loop and plays it back with callback function.
    """
    stream = p.open(format=PA_TYPE,
                    rate=RATE,
                    channels=CHANNELS,
                    input=True,
                    output=True,
                    frames_per_buffer=CHUNK,
                    stream_callback=callback_function)

    stream.start_stream()

    # main input loop
    while True:
        time.sleep(1)

    stream.stop_stream()
    stream.close()
    p.terminate()

if __name__ == "__main__":
    playback(callback)


#!/usr/bin/env python3

## Reads bam files (typically for ribo-seq) and analyses various attributes such as length, 5' mismatch nucleotide and frame
## Calls LengthandFramePlot.R -- make sure it is in the same directory as this script when running

import sys
import numpy as np
import pandas as pd
from collections import defaultdict
import pysam
import argparse
import re
import subprocess
import gffutils

parser = argparse.ArgumentParser(description = 'Analyse Ribo-seq bam files and extract mapped read characteristics')
parser.add_argument('-b','--bam', metavar = 'input bam files', required = True, dest = 'bams', nargs = '*')
parser.add_argument('-n', '--name', metavar = 'name for file prefix', required = True, dest = 'name')
parser.add_argument('--read-min', metavar = 'min read length', required = False, dest = 'min', help = 'Min read length to include in plots')
parser.add_argument('--read-max', metavar = 'max read length', required = False, dest = 'max', help = 'Max read length to include in plots')
parser.add_argument('--mismatch', dest = 'mismatch', required = False, action = 'store_true',\
	help = "Plot 5' mismatch data")
#parser.set_defaults(min = 10, max = 45)
args = parser.parse_args()

mapped_count = 0
results_list = list()

for bam in args.bams:
	seq_dict = defaultdict(list)
	print(bam)
	bam_file = pysam.AlignmentFile(bam,"rb")
	for read in bam_file.fetch(until_eof=True):
		if not read.is_unmapped:
			mapped_count += 1
			seq_dict['length'].append(read.query_length)
			seq_dict["5'_mis"].append(bool(re.search('^0[A:Z].',read.get_tag("MD"))))
			seq_dict['frame'].append(read.reference_start % 3)

	seq_df = pd.DataFrame(seq_dict)

	frame_size_distr = seq_df.groupby(['length',"5'_mis","frame"])['length'].count()
	frame_size_distr = pd.DataFrame(frame_size_distr)
	frame_size_distr.columns = ['count']

	filename = bam.split("/")[-1].split(".")[0]
	frame_size_distr.to_csv(filename + "_LengthFrame.csv")
	results_list.append(filename + "_LengthFrame.csv")

# set default min and max read lengths based on those in data
min_length = min(frame_size_distr.index.get_level_values(0))
max_length = max(frame_size_distr.index.get_level_values(0))
parser.set_defaults(min = min_length, max = max_length)
args = parser.parse_args()

command = "Rscript"
path = "./LengthandFramePlot.R"
cmd = [command, path, str(args.min), str(args.max), str(args.mismatch), str(args.name)] + results_list
x = subprocess.check_output(cmd, universal_newlines=True)
	#size_distr.to_csv(filename + "_LengthDistr.csv")
	#frame_distr.to_csv(filename + "_FrameDistr.csv")


# -*- coding: utf-8 -*-
# @Time    : 2022/10/8
# @Author  : Naihe
# @Email   : 239144498@qq.com
# @File    : sgtv.py
# @Software: PyCharm
import asyncio

import aiohttp
from fastapi import APIRouter, Query, Response
from loguru import logger
from fastapi.background import BackgroundTasks
from fastapi.responses import StreamingResponse, RedirectResponse
from app.api.a4gtv.tools import generate_m3u, now_time
from app.api.a4gtv.utile import get, backtaskonline, backtasklocal
from app.conf.config import default_cfg, idata, localhost, host2, host1, headers, headers2
from app.db.DBtools import DBconnect
from app.scheams.basic import Response200, Response400

sgtv = APIRouter(tags=["4GTV"])

@sgtv.get('/online.m3u8', summary="带缓冲区m3u8")
async def online(
        background_tasks: BackgroundTasks,
        host=Query(localhost),
        fid=Query(...),
        hd=Query("1080")):
    """
    该版本具有redis缓存，视频中转缓存处理等优点,直白说就是播放稳定不卡顿，看超清、4k不是问题
    """
    if default_cfg['defaultdb'] == "":
        return Response200(msg="此功能禁用，请连接数据库")
    if not (fid in idata):
        return Response400(data=f"Not found {fid}", code=404)
    t = idata[fid].get("lt", 0) - now_time()
    if t > 0:
        return Response400(data=f"{fid} 频道暂不可用，请过 {t} 秒后重试", code=405)
    code = get.check(fid)
    if code != 200:
        return Response400(data=f"{fid} 频道暂不可用，请过 {idata[fid].get('lt', 0) - now_time()} 秒后重试", code=406)
    return Response("".join((i for i in get.new_generatem3u8(host, fid, hd, background_tasks))), 200, headers=headers2)

@sgtv.get('/channel.m3u8', summary="代理|转发m3u8")
async def channel1(
        host=Query(localhost),
        fid=Query(...),
        hd=Query("720")):
    """
    在redis中设置截止时间，过期重新获取保存到redis，默认通过读取redis参数，构造ts链接
    新增对接口复用，channel2接口重定向到该接口做转发，默认采取代理方式
    """
    if not (fid in idata):
        return Response400(data=f"Not found {fid}", code=404)
    t = idata[fid].get("lt", 0) - now_time()
    if t > 0:
        return Response400(data=f"{fid} 频道暂不可用，请过 {t} 秒后重试", code=405)
    code = get.check(fid)  # 檢查是否出错
    if code != 200:
        return Response400(data=f"{fid} 频道暂不可用，请过 {idata[fid].get('lt', 0) - now_time()} 秒后重试", code=406)
    return Response("".join((i for i in get.generatem3u8(host or "239144498@qq.com", fid, hd))), 200, headers=headers2)

@sgtv.get('/channel2.m3u8', summary="重定向m3u8")
async def channel2(
        host=Query(None),
        fid=Query(...),
        hd=Query("720")):
    """
    读取redis获取链接进行重定向
    """
    if not (fid in idata):
        return Response400(data=f"Not found {fid}", code=404)
    t = idata[fid].get("lt", 0) - now_time()
    if t > 0:  # 冷卻期
        return Response400(data=f"{fid} 频道暂不可用，请过 {t} 秒后重试", code=405)
    code = get.check(fid)  # 檢查是否出错
    if code != 200:
        return Response400(data=f"{fid} 频道暂不可用，请过 {idata[fid].get('lt', 0) - now_time()} 秒后重试", code=406)
    host = host or host2 if "4gtv-live" in fid else host1
    return RedirectResponse(f"channel.m3u8?fid={fid}&hd={hd}&host={host}", status_code=302)

@sgtv.get('/channel3.m3u8', summary="重定向m3u8")
async def channel3(
        fid=Query(...),
        hd=Query("720")):
    """
    根据大家的需要特意新增该接口，用于直接重定向m3u8
    该链接最稳定，推荐使用该接口
    """
    if not (fid in idata):
        return Response400(data=f"Not found {fid}", code=404)
    t = idata[fid].get("lt", 0) - now_time()
    if t > 0:
        return Response400(data=f"{fid} 频道暂不可用，请过 {t} 秒后重试", code=405)
    code = get.check(fid)  # 檢查是否出错
    if code != 200:
        return Response400(data=f"{fid} 频道暂不可用，请过 {idata[fid].get('lt', 0) - now_time()} 秒后重试", code=406)
    return RedirectResponse(get.geturl(fid, hd), status_code=307)

@sgtv.get('/program.m3u', summary="IPTV频道列表")
async def program(
        host=Query(localhost),
        hd=Query("720"),
        name="channel2"):
    """
    生成频道表，由程序生成数据
    """
    name += ".m3u8"
    return StreamingResponse(generate_m3u(host, hd, name), 200, headers=headers2)

@sgtv.get('/epg.xml', summary="IPTV节目预告")
def epg():
    """
    获取4gtv未来3天所有节目表
    """
    return RedirectResponse("https://agit.ai/239144498/demo/raw/branch/master/4gtvchannel.xml", status_code=302)

@sgtv.get('/call.ts', summary="缓存式ts视频下载")
async def call(background_tasks: BackgroundTasks, fid: str, seq: str, hd: str):
    """
    api v3 版中读取数据库ts片响应给客户端，采用多线程下载ts片，加载视频没有等待时长！
    """
    if default_cfg['defaultdb'] == "":
        return Response200(msg="此功能禁用，请连接数据库")
    logger.info(f"{fid} {seq}")
    if not (fid in idata):
        return Response200(msg="NOT FOUND " + fid)
    vname = fid + str(seq) + ".ts"
    gap, seq, url, begin = get.generalfun(fid, hd)
    if default_cfg.get("downchoose") == "online":
        background_tasks.add_task(backtaskonline, url, fid, seq, hd, begin, None)
    elif default_cfg.get("downchoose") == "local":
        background_tasks.add_task(backtasklocal, url, fid, seq, hd, begin, None)
    for i in range(1, 10):
        logger.info(f"第{i}次尝试获取{get.filename.get(vname)}")
        if get.filename.get(vname) and get.filename.get(vname) != 0:
            sql = "SELECT vcontent FROM video where vname='{}'".format(vname)
            content = DBconnect.fetchone(sql)
            return Response(content=content['vcontent'], status_code=200, headers=headers)
        else:
            await asyncio.sleep(1 + i * 0.095)
    return Response400(msg="NOT FOUND " + vname)

@sgtv.get("/live/{file_path:path}", summary="代理ts视频下载")
async def downlive(file_path: str, token1: str = None, expires1: int = None):
    """
    api v2 版代理请求，客户端无需翻墙即可观看海外电视
    """
    file_path = "/live/" + file_path
    if "live/pool/" not in file_path:
        return Response400(msg="wrong parameter")
    if token1 and expires1:
        file_path += f"?token1={token1}&expires1={expires1}"
    url = host2 + file_path if "live/pool/4gtv-live" in file_path else host1 + file_path
    header = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:103.0) Gecko/20100101 Firefox/103.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
        "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
        "Accept-Encoding": "gzip, deflate, br",
        "Upgrade-Insecure-Requests": "1",
    }
    # with request.get(url=url, headers=header) as res:
    #     return Response(content=res.content, status_code=200, headers=headers, media_type='video/MP2T')
    async with aiohttp.ClientSession(headers=header) as session:
        async with session.get(url=url) as res:
            if res.status != 200:
                return Response400(msg="Error in requestr")
            return Response(content=await res.read(), status_code=200, headers=headers, media_type='video/MP2T')


# ------------------------------------------------------------------------------ #
# @Author:        Sebastian B. Mohr
# @Email:
# @Created:       2020-10-27 11:13:12
# @Last Modified: 2020-12-17 20:02:07
# ------------------------------------------------------------------------------ #
"""
Script to create an animated gif of the incidence in each age group.
Run timeseries.py for new data!

Runtime: 15-20mins
"""

import pandas as pd
import numpy as np
import geopandas as gpd
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
import datetime
from tqdm.auto import tqdm
import imageio

mpl.rcParams["font.sans-serif"] = "Arial"
mpl.rcParams["font.family"] = "sans-serif"

# Agegroups
groups = ["A00-A04", "A05-A14", "A15-A34", "A35-A59", "A60-A79", "A80+"]

# Load geojson file for underground
df_places = gpd.read_file("./data/landkreise_simplify200.geojson")

# Color of plot
cmap = plt.get_cmap("YlOrRd")
count = 0

# Progressbar
pbar = tqdm(
    total=pd.date_range(
        start=datetime.datetime(2020, 3, 2), end=datetime.datetime.now()
    ).size
    * len(groups),
    position=1,
)

# Images dictionary for each agegroup
images = {}
for g in groups:
    images[g] = []

# Loop over each date
for date in pd.date_range(
    start=datetime.datetime(2020, 3, 2), end=datetime.datetime.now()
):

    # Load json with casenumbers
    try:
        df = pd.read_json(
            f"./data/ts/data_{date.strftime('%d_%m')}.json", orient="values"
        )
    except Exception as e:
        break

    df = df.T
    df.index.name = "RS"
    df = df.reset_index()
    df["RS"] = df["RS"].astype(str).apply(lambda x: x.zfill(5))

    merged = df_places.merge(df, left_on="RS", right_on="RS")

    # Create a plot for every agegroup:
    for i, age_group in enumerate(groups):
        fig, ax = plt.subplots(1, 1, figsize=(3.5, 4))
        cm = merged.plot(
            column=f"inzidenz_{age_group}", ax=ax, cmap=cmap, vmin=0, vmax=300
        )

        # ------------------------------------------------------------------------------ #
        # Visual markup
        # ------------------------------------------------------------------------------ #
        ax.axes.xaxis.set_visible(False)
        ax.axes.yaxis.set_visible(False)
        for spine in ax.spines:
            ax.spines[spine].set_visible(False)

        # Text of date
        fig.text(
            0.36,
            0.75,
            date.strftime("%-d. %B %Y"),
            fontsize=8,
            ha="right",
            weight="bold",
        )

        # Colorbar
        cax = fig.add_axes([0.84, 0.1, 0.03, 0.8])
        sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize(vmin=0, vmax=300))
        # fake up the array of the scalar mappable. Urgh...
        sm._A = []
        cb = fig.colorbar(sm, cax=cax)
        cb.ax.set_xlabel(
            "Fälle pro\n100.000 EW", horizontalalignment="left", fontsize=8
        )
        cb.ax.tick_params(axis="y", labelsize=8)
        cb.ax.xaxis.set_label_coords(-1.2, -0.025)
        fig.savefig(
            f"./figures/{age_group}/{str(count).zfill(4)}.png",
            transparent=True,
            dpi=300,
        )
        images[age_group].append(
            imageio.imread(f"./figures/{age_group}/{str(count).zfill(4)}.png")
        )
        plt.close(fig)
        pbar.update(1)
        # Append to array for gif
    count = count + 1

pbar.close()

print("Combining images to gifs (could take a min)!")
for age_group in groups:
    imageio.mimsave(
        f"{age_group}.mp4",
        images[age_group],
        fps=10,
        quality=10,
        codec="mjpeg",
        pixelformat="yuvj444p",
    )


import requests
import zipfile
from constants import (
    SUNSET_DATA_URL,
    WEATHER_3DAY_DATA_URL,
    WEATHER_7DAY_DATA_URL,
    XML_NAMESPACE,
    ZIP_CODE,
    SUNSET_DATA_NEEDED,
)
from pathlib import Path
from xml.etree.ElementTree import ElementTree

def find_node(root, name):
    while name.startswith('/'):
        length = name.find('/', 1)
        if length == -1:
            name = name[1:]
            break
        else:
            root = root.find('all:' + name[1:length], XML_NAMESPACE)
            name = name[length:]
    return root.find('all:' + name, XML_NAMESPACE)

def url_retrieve(url: str, outfile: Path):
    r = requests.get(url)
    if r.status_code != 200:
        raise ConnectionError(f"Failed to download {url}\nWith error code: {r.status_code}")
    outfile.write_bytes(r.content)

class SunsetData(object):
    def __init__(self, download_path: Path = Path('sunset.xml')):
        self.download_path = download_path
        self.all_sunset_data = []
        url_retrieve(SUNSET_DATA_URL, download_path)

    def format_sunset_data(self):
        tree = ElementTree(file=self.download_path)
        root = tree.getroot()
        locations = find_node(root, '/dataset/locations')
        for location in locations.iterfind('all:location', XML_NAMESPACE):
            location_name = find_node(location, 'locationName').text
            area_data = []
            for time in location.iterfind('all:time', XML_NAMESPACE):
                data_time = find_node(time, 'dataTime').text
                single_set = [location_name, data_time]
                for parameter in time.iterfind('all:parameter', XML_NAMESPACE):
                    parameter_name = parameter.find('all:parameterName', XML_NAMESPACE).text
                    if parameter_name in SUNSET_DATA_NEEDED:
                        single_set.append(parameter.find('all:parameterValue', XML_NAMESPACE).text)
                area_data.append(tuple(single_set))
            self.all_sunset_data += area_data

class WeatherData3day(object):
    """
        資料欄位 = ['zip_code', 'time', 'T', 'RH', 'PoP6h', 'CI', 'Wx', 'WeatherDescription']
    """

    def __init__(self, download_path: Path = Path('data.zip')):
        url_retrieve(WEATHER_3DAY_DATA_URL, download_path)
        self.all_weather_data = []
        with zipfile.ZipFile(download_path) as ZF:
            self.zip_file_list = ZF.namelist()
            self.zip_file_list = [f for f in self.zip_file_list if not f.find("72hr_CH") == -1]
            self.zip_file_list.remove("TAIWAN_72hr_CH.xml")
            for file_name in self.zip_file_list:
                ZF.extract(file_name)

    def format_weather_data(self):
        weather_data_needed = ['T', 'RH', 'CI', 'Wx', 'WeatherDescription']
        for file_name in self.zip_file_list:
            tree = ElementTree(file=file_name)
            root = tree.getroot()
            locations = find_node(root, "/dataset/locations")
            for location in locations.iterfind("all:location", XML_NAMESPACE):
                location_name = find_node(location, "locationName")
                weather_ele = location.find("all:weatherElement", XML_NAMESPACE)
                weather_data = []
                for all_time in weather_ele.iterfind("all:time", XML_NAMESPACE):
                    time_str = all_time.find("all:dataTime", XML_NAMESPACE).text
                    t_loc = time_str.find('T')
                    plus_loc = time_str.find('+')
                    weather_data.append([time_str[:t_loc] + " " + time_str[t_loc + 1:plus_loc]])
                for weather_ele in location.iterfind("all:weatherElement", XML_NAMESPACE):
                    node = weather_ele.find("all:elementName", XML_NAMESPACE)
                    if node.text == 'PoP6h':
                        node_iter = weather_ele.iterfind("all:time", XML_NAMESPACE)
                        for i in range(12):
                            try:
                                node = next(node_iter)
                                weather_data[2 * i].append(int(find_node(node, "/elementValue/value").text))
                                weather_data[2 * i + 1].append(None)
                            except StopIteration:
                                weather_data[2 * i].append(None)
                                weather_data[2 * i + 1].append(None)

                    if node.text in weather_data_needed:
                        node_iter = weather_ele.iterfind("all:time", XML_NAMESPACE)
                        for i in range(24):
                            node = next(node_iter)
                            text = str(find_node(node, "/elementValue/value").text)
                            if text.isnumeric():
                                weather_data[i].append(int(text))
                            else:
                                weather_data[i].append(text)
                for i in range(24):
                    single_set = [ZIP_CODE[find_node(locations, "locationsName").text][location_name.text]]
                    single_set += weather_data[i]
                    self.all_weather_data.append(single_set)

class WeatherData7day(object):
    """
        資料欄位 = ['zip_code', 'time', 'T', 'RH', 'PoP6h', 'CI', 'Wx', 'WeatherDescription']
    """

    def __init__(self, download_path: Path = Path('data.zip')):
        url_retrieve(WEATHER_7DAY_DATA_URL, download_path)
        self.all_weather_data = []
        with zipfile.ZipFile(download_path) as ZF:
            self.zip_file_list = ZF.namelist()
            self.zip_file_list = [f for f in self.zip_file_list if not f.find("Week24_CH") == -1]
            self.zip_file_list.remove("TAIWAN_Week24_CH.xml")
            for file_name in self.zip_file_list:
                ZF.extract(file_name)

    def format_weather_data(self):
        weather_data_needed = ['T', 'RH', 'Wx', 'WeatherDescription', 'PoP24h']
        for file_name in self.zip_file_list:
            tree = ElementTree(file=file_name)
            root = tree.getroot()
            locations = find_node(root, "/dataset/locations")
            for location in locations.iterfind("all:location", XML_NAMESPACE):
                location_name = find_node(location, "locationName")
                weather_ele = location.find("all:weatherElement", XML_NAMESPACE)
                weather_data = []
                for all_time in weather_ele.iterfind("all:time", XML_NAMESPACE):
                    time_str = all_time.find("all:startTime", XML_NAMESPACE).text
                    t_loc = time_str.find('T')
                    plus_loc = time_str.find('+')
                    weather_data.append([time_str[:t_loc] + " " + time_str[t_loc + 1:plus_loc]])
                for weather_ele in location.iterfind("all:weatherElement", XML_NAMESPACE):
                    node = weather_ele.find("all:elementName", XML_NAMESPACE)
                    node_iter = weather_ele.iterfind("all:time", XML_NAMESPACE)
                    if node.text == "MaxCI":
                        CI = [0 for i in range(7)]
                        for i in range(7):
                            try:
                                node = next(node_iter)
                                text = int(find_node(node, "/elementValue/value").text)
                                CI[i] += text
                            except StopIteration:
                                pass
                    elif node.text == "MinCI":
                        for i in range(7):
                            try:
                                node = next(node_iter)
                                text = int(find_node(node, "/elementValue/value").text)
                                weather_data[i].append(int((CI[i] + text) / 2))
                            except StopIteration:
                                pass
                    if node.text in weather_data_needed:
                        for i in range(7):
                            node = next(node_iter)
                            text = str(find_node(node, "/elementValue/value").text)
                            if text.isnumeric():
                                weather_data[i].append(int(text))
                            elif text.isspace():
                                weather_data[i].append(None)
                            else:
                                weather_data[i].append(text)
                for i in range(7):
                    single_set = [ZIP_CODE[find_node(locations, "locationsName").text][location_name.text]]
                    # single_set.append(Re.find_node(locations,"locationsName").text)
                    # single_set.append(location_name.text)
                    single_set += weather_data[i]
                    self.all_weather_data.append(single_set)

if __name__ == '__main__':
    data = SunsetData()
    data.format_sunset_data()


# -*- coding: utf-8 -*-#

# ---------------------------------------------
# Name:         data_loader
# Description:
# Author:       Laity
# Date:         2022/3/28
# ---------------------------------------------
import pandas as pd
import torch
import numpy as np

class Vocab:
    def __init__(self, sentences1, sentences2):
        sentences = sentences1 + [' '] + sentences2
        self.vocab_size = 2
        self.word2id = {'<PAD>': 0, '<UNK>': 1}
        self.id2word = {0: '<PAD>', 1: '<UNK>'}
        self.label_dict = {'contradiction':0, 'neutral': 1, 'entailment': 2, '<UNK>': 3}
        self.label_id = {0: 'contradiction', 1: 'neutral', 2: 'entailment', 3: '<UNK>'}
        self.stop_sign = '.,/?;:!'
        for sentence in sentences:
            # 去标点符号
            for sign in self.stop_sign:
                sentence = sentence.replace(sign, ' ')
            for word in sentence.split():
                if word not in self.word2id:
                    word = word.lower()
                    self.word2id[word] = self.vocab_size
                    self.id2word[self.vocab_size] = word
                    self.vocab_size += 1

    def __getitem__(self, item):
        if item in self.word2id:
            return self.word2id[item]
        else:
            return self.id2word[item]

    def label2id(self, label_text):
        # label制作成one_hot
        label = [0]*4
        if label_text not in self.label_dict:
            label_text = '<UNK>'
        label[self.label_dict[label_text]] = 1
        return label

    def id2label(self, label_num):
        if label_num not in self.label_id:
            return '<UNK>'
        return self.label_id[label_num]

    def sentence2id(self, sentence):
        sentence_id = []
        for sign in self.stop_sign:
            sentence = sentence.replace(sign, ' ')
        for word in sentence.split():
            word = word.lower()
            sentence_id.append(self.word2id[word])
        return sentence_id

    def padding(self, sentence_id, sentence_size):
        for i in range(len(sentence_id), sentence_size):
            sentence_id.append(self.word2id['<PAD>'])
        # 截取超出长度
        return sentence_id[:sentence_size]

    def loader(self, sentences1, sentences2, label, batch_size=64, sentence_size=32):
        size = min([len(sentences1), len(sentences2)])
        for i in range(0, size, batch_size):
            batch_data = []
            batch_label = []
            for j in range(i, i+batch_size):
                if j >= size:
                    break
                batch_data.append([self.padding(self.sentence2id(sentences1[j]), sentence_size), self.padding(self.sentence2id(sentences2[j]), sentence_size)])
                batch_label.append(self.label2id(label[j]))
            yield torch.LongTensor(batch_data), torch.Tensor(batch_label)

def data_set(max_len=-1, batch_size=64):
    data = pd.read_csv('data/snli_1.0/snli_1.0_train.txt', sep='\t')
    v1 = data['sentence1'][:max_len]
    v2 = data['sentence2'][:max_len]
    label = data['gold_label'][:max_len]
    print(v1, v2)
    vocabulary = Vocab(v1, v2)
    return vocabulary.loader(v1, v2, label, batch_size), vocabulary.vocab_size

if __name__ == '__main__':
    data, size = data_set(3)


import torch
from loss import *
from utils import *
from bert_model import BERT_Arch
from transformers import AutoModel, BertTokenizerFast
import pickle as pk
from fusion import *

def train_func(dataloader, model, text_model_weights, optimizer, criterion, criterion2, dl_loss_function,client_idx, lamda=0):
    t_loss = []
    s_loss = []

    with torch.set_grad_enabled(True):
        model.train()
        for i, (v_input, t_input, label, multi_label, t_id) in enumerate(dataloader):
        # for i, (v_input, t_input, label, multi_label) in enumerate(dataloader):
            seq_len = torch.sum(torch.max(torch.abs(v_input), dim=2)[0] > 0, 1)
            v_input = v_input[:, :torch.max(seq_len), :]
            v_input = v_input.float().cuda(non_blocking=True)
            t_input = t_input.float().cuda(non_blocking=True)
            label = label.float().cuda(non_blocking=True)
            multi_label = multi_label.cuda(non_blocking=True)

            logits, v_feat = model(v_input, seq_len)

            # Prompt-Enhanced Learning
            logit_scale = model.logit_scale.exp()
            video_feat, token_feat, video_labels = get_cas(v_feat, t_input, logits, multi_label)

            v2t_logits, v2v_logits = create_logits(video_feat, token_feat, logit_scale)
            ground_truth = torch.tensor(gen_label(video_labels), dtype=v_feat.dtype).cuda()

            loss2 = KLV_loss(v2t_logits, ground_truth, criterion2)

            loss1 = CLAS2(logits, label, seq_len, criterion)

            loss = loss1 + lamda * loss2

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            t_loss.append(loss1)
            s_loss.append(loss2)

    return sum(t_loss) / len(t_loss), sum(s_loss) / len(s_loss)

def public_train_func(dataloader, global_model,visual_model, optimizer, criterion, criterion2,dl_loss_function, lamda=0):
    t_loss = []
    s_loss = []
    mse_criterion = nn.MSELoss()
    with torch.set_grad_enabled(True):
        global_model.train().cuda()
        visual_model.eval().cuda()
        feature_dim = 512
        num_heads = 8
        feature_fusion_model = FeatureFusionMHSA(feature_dim, num_heads).to("cuda")
        for i, (v_input, t_input, label, multi_label, t_id) in enumerate(dataloader):
            seq_len = torch.sum(torch.max(torch.abs(v_input), dim=2)[0] > 0, 1)
            v_input = v_input[:, :torch.max(seq_len), :]
            v_input = v_input.float().cuda(non_blocking=True)
            t_input = t_input.float().cuda(non_blocking=True)
            label = label.float().cuda(non_blocking=True)
            multi_label = multi_label.cuda(non_blocking=True)

            logits, v_feat = global_model(v_input, seq_len)
            logits2, v_feat2 = visual_model(v_input, seq_len)

            # t_feature = get_xd_text_feature(t_id)
            t_feature = get_sh_text_feature(t_id)
            t_feature_expanded = t_feature.unsqueeze(2).cuda(non_blocking=True)  # shape: [128, 512, 1]
            t_feature_expanded = t_feature_expanded.expand(-1, -1, v_feat.size(-1))

            fused_feature = feature_fusion_model(v_feat,t_feature_expanded)

            mse_loss = mse_criterion(v_feat,fused_feature)

            # Prompt-Enhanced Learning
            logit_scale = global_model.logit_scale.exp()
            video_feat, token_feat, video_labels = get_cas(v_feat, t_input, logits, multi_label)

            v2t_logits, v2v_logits = create_logits(video_feat, token_feat, logit_scale)
            ground_truth = torch.tensor(gen_label(video_labels), dtype=v_feat.dtype).cuda()

            loss2 = KLV_loss(v2t_logits, ground_truth, criterion2)

            loss1 = CLAS2(logits, label, seq_len, criterion)

            loss = loss1 + lamda * loss2 + 0.7 * mse_loss

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            t_loss.append(loss1)
            s_loss.append(loss2)

    return global_model.state_dict()

def get_text_id_based_name(name):
    import csv
    data_dict = {}
    csv_file =  name # 替换为你的 CSV 文件路径
    with open(csv_file, 'r') as file:
        csv_reader = csv.DictReader(file)
        for row in csv_reader:
            video_name = row['name']
            sentence = row['id']
            data_dict[sentence] = video_name
    return data_dict
def get_sh_text_feature(t_id):
    fe = np.zeros((len(t_id), 512))
    linear_layer = create_linear_layer(768, 512)

    with open('all sh_text_feature path','rb') as tf:
        infos = pk.load(tf)
    ids = get_text_id_based_name('Path to the id of the text corresponding to the video in the public dataset SH.')
    for i, id in  enumerate(t_id):
        name = ids[str(id)]

        feature = infos[name].reshape(768)
        f = linear_layer(feature).reshape(1, 512)
        fe[i] = f.cpu().detach().numpy()
    fe_tensor = torch.from_numpy(fe).float()

    return fe_tensor

import torch.nn as nn

def create_linear_layer(input_dim, output_dim):
    return nn.Linear(input_dim, output_dim)

# 使用函数
get_sh_text_feature([10])


import pygame
from settings import Settings
from slime import Slime
import game_functions as gf

def run_game():
    # Initialize pygame, settings and create screen object.
    pygame.init()
    ai_settings = Settings()
    screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption("Meandering Muck - Level " + str(ai_settings.level))

    # Make a Slime.
    slime = Slime(ai_settings, screen)

    # Start main loop for the game.
    while True:
        if ai_settings.gamedone:
            ai_settings.gamedone = False
            ai_settings.level += 1
            pygame.display.set_caption("Meandering Muck - Level " + str(ai_settings.level))
            ai_settings.loadnewsettings()
            slime = None
            slime = Slime(ai_settings, screen)
        gf.check_events(slime)
        slime.update()
        gf.update_screen(ai_settings, screen, slime)

        # Make the most recently drawn screen visible.
        pygame.display.flip()

run_game()


import pandas as pd
import json
from collections import OrderedDict

from hacks_to_code.models import (UserProfile, Blog, BlogDescriptionModel, ListTopicsModels, TOPIC_CHOICES)
from utils.basic_response import (ok_resp,
                                  err_resp,
                                  err_resp_with_data)

class JobUtil(object):
    """ this is the utility class for view"""

    @staticmethod
    def get_user_details_by_username(username):
        """This is to get user details
        ** for now user authentication is not done is users
        are manually added.
        """
        user_obj = UserProfile()
        success, obj = user_obj.get_objects_by_username(username)

        if success:
            return ok_resp(obj)
        else:
            return err_resp(obj)

    @staticmethod
    def get_user_details_by_id(user_id):
        """This is to get user details
        ** for now user authentication is not done is users
        are manually added.
        """
        user_obj = UserProfile()
        success, obj = user_obj.get_objects_by_id(user_id)

        if success:
            return ok_resp(obj)
        else:
            return err_resp(obj)

    @staticmethod
    def get_topics_details():
        """ list of topics"""
        topic_obj = ListTopicsModels()
        success, obj = topic_obj.get_all_objects()

        if success:
            print("topics", obj)
            return ok_resp(obj)
        else:
            return err_resp(obj)

    @staticmethod
    def get_blog_list_by_id(topic_id):
        """ list of blogs for a topic"""

        blog_obj = BlogDescriptionModel()
        success, blog_list = blog_obj.get_objects_by_topic_id(topic_id)

        if success:
            for obj in blog_list:
                print("blog list", obj.as_dict())
            return ok_resp(blog_list)
        else:
            return err_resp(blog_list)

    @staticmethod
    def add_blog_description(**data):
        """ add the blog desc"""
        print(" data submitted", data)
        blog_obj = BlogDescriptionModel(**data)
        blog_obj.save()

        if blog_obj.id:
            return ok_resp(blog_obj.as_dict())

        else:
            return err_resp(blog_obj)

    @staticmethod
    def add_blog(my_id, **data):
        """add the blog"""
        print('data we get Blog des id ---------', my_id)
        print('data we get from form', data)
        blog_id = BlogDescriptionModel.objects.get(id=my_id)
        print("blog_id instance we get", blog_id)
        # if not success:
        #     return err_resp(blog_id)
        # print('blog_id', blog_id)
        #
        # input_data = dict(blog_id=blog_id,user_Id=data.get('user_Id'),
        #                 blog_image=data.get('blog_image'),
        #                 tags=data.get('tags'),
        #                 tinymce=data.get('tinymce'))
        blog_obj = Blog(blog_id=blog_id, **data)
        blog_obj.save()

        if blog_obj.id:
            return ok_resp(blog_obj)

        else:
            return err_resp(blog_obj)

    @staticmethod
    def delete_blog_desc(blog_id):
        """ delete blog desc model"""
        success, blog_del = BlogDescriptionModel.delete_blog_description(blog_id)

        if success:
            return ok_resp(blog_del)
        else:
            return err_resp(blog_del)

    @staticmethod
    def get_blog_data(blog_id):
        """ get the blog"""
        obj = Blog()
        success, blog_data = obj.get_objects_by_blog_id(blog_id)

        if not success:
            return err_resp(blog_data)

        return ok_resp(blog_data)

    @staticmethod
    def get_blog_description(blog_id):
        obj = BlogDescriptionModel()
        success, blog_des_data = obj.get_objects_by_blog_id(blog_id)
        if not success:
            return err_resp(blog_des_data)
        print(" topic_data ---", blog_des_data)
        return ok_resp(blog_des_data)

    # @staticmethod
    # def get_home_collection(topic_id):
    #     """ get details for home needed for home"""
    #     user_detail = {}
    #     topics_list = {}
    #     final = []
    #     blog_lists = {}
    #     # success_user, user_detail = JobUtil.get_user_details(1)
    #     success_topic_list, topic_list = JobUtil.get_topics_details()
    #     success_topic, topic = JobUtil.get_blog_list_by_id(topic_id)
    #     print("This is creating problem", topic)
    #     if not success_topic_list:
    #         return err_resp(topic_list)
    #
    #     if not success_topic:
    #         print("no suchtopicfound")
    #         blog_lists = []
    #         return err_resp(topic)
    #
    #     print("This is creating problem", topic)
    #
    #     for items in topic:
    #         print("item list", items)
    #
    #         user_id = items.user_Id_id
    #         success_user, user_obj = JobUtil.get_user_details(user_id)
    #         if not success_user:
    #             pass
    #
    #         blog_lists[str(items.id)]['user_detail'] = user_obj.as_dict()
    #         blog_lists[str(items.id)]['topic'] = items.as_dict()
    #
    #         final.append(blog_lists)
    #
    #     # print(final)
    #     return ok_resp(final)

"""
from hacks_to_code.models import (UserProfile, Blog, BlogDescriptionModel, ListTopicsModels, TOPIC_CHOICES)
from utils.basic_response import (ok_resp,
                                  err_resp,
                                  err_resp_with_data)
from hacks_to_code.job_util import JobUtil
import json

success, obj = JobUtil.get_home_collection('ft001')
print(json.dumps(obj))

"""


from tqdm import tqdm
import jieba.analyse
import pandas
def readXls(path=r'C:\Users\glodon\Desktop\jobCollect\zhilian\智联造价员0.xlsx'):
    # 打开文件：
    from openpyxl import load_workbook
    excel = load_workbook(path)
    # 获取sheet：
    table = excel.get_sheet_by_name('Sheet2')  # 通过表名获取
    # 获取行数和列数：
    rows = table.max_row  # 获取行数
    cols = table.max_column  # 获取列数
    jobNames=[]
    jobDess=[]
    for i in range(2,rows+1):
        jobName=table.cell(row=i, column=1).value
        jobDes=table.cell(row=i, column=2).value
        if jobDes not in jobDess:
            jobNames.append(jobName)
            jobDess.append(jobDes)
    return jobNames,jobDess
def tfidfDeal(jobs=[]):
    from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer,TfidfVectorizer
    text = jobs[:1]
    singeText=text

    # text=["I come to China to travel",
    #     "This is a car polupar in China",
    #     "I love tea and Apple ",
    #     "The work is to write some papers in science"]

    # text=["岗位职责:1、大专及以上学历，工程造价专业1年及以上工作经验；2、熟练应用广联达等造价软件，以及office、autocad等相关的办公软件；"+
    #       "能独立完成:编审工程项目概算、预算、结算、竣工决算、工程审核、工程量清单、标底及对量等工作；3、工作严谨，善于沟通，具备良好的团队合作精神和职业操守；"+
    #       "4、卓越的执行能力，学习能力和独立工作能力。5、掌握新技术，了解新材料和国内工程造价动态；6、责任心强，有敬业精神，能吃苦耐劳，品质优良。任职要求："+
    #       "1.五官端正，非民办正规院校毕业相关专业大专及以上学历，招投标、造价等工作，上岗证一项以上，符合条件者可来应聘；2.具有较强的工作责任感和事业心；"
    #       "3.具有良好的专业素质和职业化素养。4.具有注册类证书者优先。"
    # ,
    #     "协助造价工程师完成工程项目。岗位要求：专业：土建、工程管理、安装、水暖、工程造价类相关专业；学历：大学专科，本科，应届毕业生；其他："
    #     "a. 具备较强的责任心、语言表达、沟通协作能力。b.积极主动、有上进心、求知欲；c.有社会实践经验。d.抗压能力强"
    # ]

    tfidf=TfidfVectorizer()
    weight=tfidf.fit_transform(singeText).toarray()
    word=tfidf.get_feature_names()
    print('单词数量', len(word),word)

    # print(weight)

    # for i in range(len(weight)):
    #     print('第{}句，关键词权重'.format(i))
    #     for j in range(len(word)):
    #         print(word[j],weight[i][j])

def jiebaDeal(jobs=[]):
    txt=jobs[0][1]
    keywords=jieba.analyse.extract_tags(txt, topK=100, withWeight=False, allowPOS=())
    print(len(keywords),keywords)
if __name__ == '__main__':
    _,text=readXls()
    # jiebaDeal(jobs=text)
    tfidfDeal(jobs=text)


"""Object definitions for the game"""
import logging
from typing import Tuple
from rich.table import Table
from rich.box import ASCII
from utils import Utils
import level as mf

logger = logging.getLogger(__name__)

class Game:
    """Game Class, may be deprecated by using game mem obj,
    I may split up gamemem object to further divide and silo objects"""
    def __init__(self):
        self.players_turn = True
        self.level_grid = None

class Actor:
    """Actors such as (Player, Enemy, Creature, vehicle)"""
    def __init__(self):
        self._position = None

    @property
    def position(self):
        return self._position

    @position.setter
    def position(self, position):
        self._position = position

    def current_tile(self):
        """compute current tile based on position attr.
        ex. enemy.current_tile.cover_value
        """
        # Return the tile object that is in this actors position
        pass

class Item:
    """Item object parent class with basic attrs"""
    def __init__(self, name, description, value, weight, info_panel):
        self.name = name
        self.description = description
        self.weight = weight
        self.value = value
        self.info_panel = info_panel
        # self.is_equipped = False use in a subclass object

class Attributes:
    """Player attribute container"""
    def __init__(self):
        self.stats = {
            "aim": 0,
            "strength": 0,
            "dexterity": 0,
            "intelligence": 0,
            "charisma": 0,
            "luck": 0
        }

        self.skills = {
            "Sacred Scrounger": ("You sometimes find extra things.", False),
            "Lethal Shot": ("More likely to get critical hits with guns.", False),
        }

        self.injuries = {
            "Broken Leg": ("Your leg is broken", False),
        }

        self.buffs = {
            "Coffee": ("You are feeling alert", False),
        }

    def increase_stat(self, stat: str, amount: int) -> None:
        """
        Increases the player stat by the desired amount

        :param stat: the stat to increase
        :param amount: amount to increase stat by
        :type stat: str
        :type amount: int
        :return: None
        """
        self.stats[stat] += amount

    def decrease_stat(self, stat: str, amount: int) -> None:
        """Decreases user stat unless it would go negative in which case it sets to 0"""
        if (self.stats[stat] - amount) < 0:
            self.stats[stat] = 0
        else:
            self.stats[stat] -= amount

class Player(Actor):
    """Player Actor class, will handle player actions and information"""
    def __init__(self):
        super(Actor).__init__()

        self.inv = Inventory()
        self.name = "Jack Bower"
        self.level = 1
        self.attributes = Attributes()
        self.health = 100
        self.armor_value = 0
        self.actions = []
        self.concealed = True
        self.ammo = {
            "9mm": "0",
            ".45": "0",
            ".22": "0"
        }

    def reload(self):
        pass

    def use_consumable(self, item: Item):
        pass

    def equip_item(self, item: Item):
        pass

class Inventory:
    """Inventory class with methods for managing inventory Table"""
    def __init__(self):
        # Dict for storing inv data
        self._inv = []
        # Name Description qty val(total) weight(total)
        # Setup visual inv repr Table object
        self.inv_table = Table(box=ASCII, expand=True)
        self.inv_table.add_column("Active", justify="center")
        self.inv_table.add_column("Name", justify="center")
        self.inv_table.add_column("Description", justify="left")
        self.inv_table.add_column("Qty", justify="center")
        self.inv_table.add_column("Value", justify="right")
        self.inv_table.add_column("Weight", justify="right")

    def get_inv_table(self) -> Tuple[Table, list]:
        # Refresh inv table them return it
        self.refresh_inv_table()
        return self.inv_table, self._inv

    def refresh_inv_table(self):
        # Recreate Table object (empty)
        del self.inv_table
        self.inv_table = Table(box=ASCII, expand=True)
        self.inv_table.add_column("Active", justify="center")
        self.inv_table.add_column("Name", justify="center")
        self.inv_table.add_column("Description", justify="left")
        self.inv_table.add_column("Qty", justify="center")
        self.inv_table.add_column("Value", justify="right")
        self.inv_table.add_column("Weight", justify="right")

        # Rebuild the table using the current self._inv data
        for row in self._inv:
            self.inv_table.add_row(*row[:-1])

    def add_item(self, item: Item, qty: int):
        """
        Adds item to the players inventory

        :param item: Item object to be added to inventory
        :param qty: int for the amount of the item to add
        :return: None
        """
        # If there is an item in the database already
        for row in self._inv:
            if item.name in row:
                # Find item in inventory
                old_qty = int(row[3])
                old_qty += qty
                return

        #  If this is the first item in players inv
        if len(self._inv) == 0:
            self._inv.append(
                ["-->", item.name, item.description, str(qty), str(item.value), str(item.weight), item.info_panel]
            )
        #  Else add a new item row to the inv
        else:
            self._inv.append(
                ["   ", item.name, item.description, str(qty), str(item.value), str(item.weight), item.info_panel]
            )
        logger.info(f"x{qty} {item.name} added to inventory.")
        self.refresh_inv_table()

    def remove_item(self, item: Item, qty: int):
        for item_row in self._inv:
            # Find matching item
            if item.name in item_row:
                # If new qty in negatives, just set at 0
                if int(item_row[3]) - qty < 0:
                    item_row[3] = 0
                # Else perform the subtraction
                else:
                    new_qty = int(item_row[3]) - qty
                    item_row[3] = new_qty
        logger.info(f"x{qty} {item.name} removed from inventory.")

    def move_selection(self, direction: str) -> None:
        """Handles moving the active item arrow in the Item table"""

        if direction == "up":
            #  Find which index the active item is at
            indx = Utils.find_index(self._inv)
            #  If it's the first item, move to the bottom
            if indx < 1:
                self._inv[-1][0] = "-->"
                self._inv[indx][0] = "   "
            #  Else move up one row
            else:
                self._inv[indx][0] = "   "
                self._inv[indx - 1][0] = "-->"

        elif direction == "down":
            #  Find which index the active item is at
            indx = Utils.find_index(self._inv)
            #  If it's the last item, move to the top
            if len(self._inv) - 1 == indx:
                self._inv[0][0] = "-->"
                self._inv[-1][0] = "   "
            #  Else move down one row
            else:
                self._inv[indx][0] = "   "
                self._inv[indx + 1][0] = "-->"

        # Redraw the table with the updated row data
        self.refresh_inv_table()

    def select_item(self):
        # Find active item index
        # indx = Utils.find_index(self._inv)
        pass
        # self._inv[indx]

class Enemy(Actor):
    """Enemy actor, which will hold AI methods"""
    pass

class GameMap:
    """Object which holds specific maps as objects"""
    def __init__(self, map_path, info_path, intro_path):
        self.name = "Default Name"
        self.lvl_view = ""  # Computed view/read from file
        self.intro_view = ""
        self.map_path = map_path
        self.info_path = info_path
        self.intro_path = intro_path

        with open(self.intro_path, "r", encoding="utf-8") as intro_file:
            self.intro_view = intro_file.read()

        with open(self.map_path, "r", encoding="utf-8") as lvl_file:
            self.lvl_view = lvl_file.read()

        map_factory = mf.Loader()
        self.level_obj_grid = map_factory.get_map_strings(
            self.map_path,
            self.info_path
        )

    def get_map_str(self):
        for x in self.level_obj_grid:
            print(x)

# class Levels:
#     """This will hold all the loaded levels"""
#     NH1 = GameMap("Neighborhood House", "./levels/NH/NH1_intro.txt", "./levels/NH/NH1_map.txt")