from sys import argv
def get_max_val(dict_to_search:dict) -> str:
    """
    Returns the key of the max value of a dict
    """
    return max(dict_to_search,key = dict_to_search.get,default = 0)

def print_map(dict_to_print:dict) -> None:
    d = {k:v for k,v in dict_to_print.items() if v != 0}
    for k,v in d.items():
        print(f"\t{k}: {v}")

def change(amt:float):
    """
    This will make the optimal amount of change given the amount. The amount is represented in terms of dollars
    """
    mapping = {
        'Penny': 1,
        'Nickel': 5,
        'Dime': 10,
        'Quarter': 25,
        'Dollar1': 100,
        'Dollar5': 500,
        'Dollar10': 1000,
        'Dollar20': 2000,
        'Dollar50': 5000,
        'Dollar100': 10000
    }
    cent_val = amt * 1 ## convert the amount to cents to match the mapping
    change_amt = 0
    change_map = {x:0 for x in mapping.keys()}

    while change_amt < cent_val:
        delta_amt = cent_val - change_amt ## the remaining balance of change that is due
        filtered = {k:v for k,v in mapping.items() if v <= delta_amt}
        max_key = get_max_val(filtered) ## the key of the max
        change_amt += mapping[max_key]
        change_map[max_key] += 1

    print_map(change_map)
    print("====================================")
    return change_amt

if __name__  == '__main__':
    for (i,arg) in enumerate(argv):
        if i == 0:
            continue
        amt = float(arg) ## convert command line args to float
        print(f"For ${amt}:")
        amt = round(amt * 100,0) ## convert the value to cents, and round just in case of floating point errors
        change(amt)


import os
from imutils import paths

def path_image(link_dir):
    imagePaths = list(paths.list_images(link_dir))
    list_link_image = []
    for (i, imagePath) in enumerate(imagePaths):
        link_cup = imagePath.split(os.path.sep)
        link_cup.insert(0, i+1)
        list_link_image.append(link_cup)
    return list_link_image


from pytest_bdd import when, then, given

from model.contact import Contact
import random

@given('a contact list')
def contact_list(db):
    return db.get_contact_list()

@given('contact with <first_name>, <middle_name> and <last_name>')
def new_contact(first_name, middle_name, last_name):
    return Contact(first_name=first_name, middle_name=middle_name, last_name=last_name)

@when('I add the contact to list')
def add_new_contact(app, new_contact):
    app.contact.create(new_contact)

@then('the new contact list is equal to the old contact list with the added contact')
def verify_contact_added(db, contact_list, new_contact):
    old_contacts = contact_list
    new_contacts = db.get_contact_list()
    old_contacts.append(new_contact)
    assert sorted(old_contacts, key=Contact.id_or_max) == sorted(new_contacts, key=Contact.id_or_max)

@given('a non-empty contact list')
def non_empty_contact_list(db, app):
    if len(db.get_contact_list()) == 0:
        app.contact.create(Contact(first_name="empty_name", middle_name="empty_name", last_name="empty_name"))
    return db.get_contact_list()

@given('a random contact from list')
def random_contact(non_empty_contact_list):
    return random.choice(non_empty_contact_list)

@when('I delete a contact from list')
def delete_contact(app, random_contact):
    app.contact.delete_by_id(random_contact.id)

@then('the new contact list is equal to the old list without deleted contact')
def verify_contact_deleted(db, non_empty_contact_list, random_contact, app, check_ui):
    old_contacts = non_empty_contact_list
    new_contacts = app.contact.get_contact_list()
    assert len(old_contacts) == len(new_contacts) + 1
    old_contacts.remove(random_contact)
    assert sorted(old_contacts, key=Contact.id_or_max) == sorted(new_contacts, key=Contact.id_or_max)
    if check_ui:
        assert sorted(new_contacts, key=Contact.id_or_max) == sorted(app.contact.get_contact_list(),
                                                                     key=Contact.id_or_max)

@when('I edit a random contact from list')
def edit_random_contact(app, random_contact):
    id = random_contact.id
    new_contact.id = id
    app.contact.edit_by_id(random_contact.id, new_contact)

@then('the new contact list is equal to the old contact list with the edited contact')
def verify_contact_edited(db, non_empty_contact_list, random_contact, app, check_ui, new_contact):
    new_contacts = db.get_contact_list()
    old_contacts = non_empty_contact_list
    contact_for_edit = random_contact
    contact = new_contact
    assert len(old_contacts) == len(new_contacts)
    for i in range(len(old_contacts)):
        if old_contacts[i].id == contact_for_edit.id:
            old_contacts[i] = contact
    assert sorted(old_contacts, key=Contact.id_or_max) == sorted(new_contacts, key=Contact.id_or_max)
    if check_ui:
        assert sorted(new_contacts, key=Contact.id_or_max) == sorted(app.contact.get_contact_list(),
                                                                     key=Contact.id_or_max)


s = input()

for i in range(ord('a'), ord('z') + 1):
    i = chr(i)
    for j in range(0, len(s)):

        if i == s[j]:
            print('{0} ' .format(j), end = '')
            break
        if j == len(s) - 1:
            print('-1 ' , end = '')
            break


questionnaire = [
            ["География", "Какое государство самое маленькое в мире?",
                ["Ватикан", "Лихтенштейн", "Монако", "Андорра"], 0],
            ["География", "Назовите наибольшее по площади озеро Америки",
                ["Верхнее", "Гурок", "Мичиган", "Онтарио"], 0],
            ["География", "Чья экспедиция совершила первое кругосветное путешествие?",
                ["Магеллана", "Врангеля", "Лисянского", "Кука"], 0],

            ["Путешествия", "Какой из перечисленных вулканов является действующим?",
                ["Везувий", "Килиманджаро", "Карадаг", "Кетой"], 0],
            ["Путешествия", "Когда отмечается всемирный день туризма?",
                ["27 сентября", "1 июня", "6 июля", "15 мая"], 0],
            ["Путешествия", "Как называют людей, отдыхающих на курорте без путевки?",
                ["Дикари", "Туземцы", "Варвары", "Отшельники"], 0],

            ["Мир животных", "Разновидность какой из этих ящериц является крупнейшей в мире?",
                ["Геккон", "Варан", "Агама", "Игуана"], 1],
            ["Мир животных", "Какое из этих животных не бывает ангорской породы?",
                ["Кошка", "Коза", "Собака", "Кролик"], 2],
            ["Мир животных", "Какой из этих морских обитателей является рыбой?",
                ["Морской лев", "Морской черт", "Морской заяц", "Морской слон"], 1],
        ]


from classes import *

def menu():

    in_menu = True
    while in_menu:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()

        WIN.fill(BLACK)

        RETURN_TO_MAIN_MENU_BUTTON = Button("Z: Return to Main Menu", (WIDTH / 3 - 125, HEIGHT * .25), font=30, bg="navy",
                                        feedback="Returning to Main Menu")

        SAVE_GAME_BUTTON = Button("X: Save Game", (WIDTH / 3 - 125, HEIGHT * .35), font=30, bg="navy",
                                        feedback="Saving...")

        QUIT_BUTTON = Button("C: Quit Game", (WIDTH / 3 - 125, HEIGHT * .45), font=30, bg="navy",
                                        feedback="Closing Game")

        BACK_BUTTON = Button("Back (backspace)", (0, 0), font=30, bg="navy", feedback="You chose to go back")

        keys = pygame.key.get_pressed()

        if keys[pygame.K_BACKSPACE]:
            in_menu = False
            print(BACK_BUTTON.feedback)

        if keys[pygame.K_z]:
            in_menu = False
            print(RETURN_TO_MAIN_MENU_BUTTON.feedback)

        if keys[pygame.K_x]:
            in_menu = True
            print(SAVE_GAME_BUTTON.feedback)

        if keys[pygame.K_c]:
            print(QUIT_BUTTON.feedback)
            pygame.quit()

        RETURN_TO_MAIN_MENU_BUTTON.show(RETURN_TO_MAIN_MENU_BUTTON)
        SAVE_GAME_BUTTON.show(SAVE_GAME_BUTTON)
        QUIT_BUTTON.show(QUIT_BUTTON)
        BACK_BUTTON.show(BACK_BUTTON)

        pygame.display.update()

    return LAST_LOCATION[0], LAST_LOCATION[1], LAST_LOCATION[2]


#!/usr/bin/python
#
# Python implementation of the Eclat frequent itemset mining algorithm.
# See "New algorithms for fast discovery of association rules" by Zaki et al.
# for details.
# Implementation by Michael Mampaey,  version 0.1.20091008.
#

from classes import GeneralMethods

class Itemset:
    """Itemset Class
    """
    def __init__(self, suffix=0):
        self.suffix = suffix
        self.support = 0
        self.tids = set()

    def __cmp__(self, other):
        return cmp(self.support, other.support)

class FIByEclat:
    """Eclat Class
    Modified the implementation of this algorithm by Michael Mampaey (http://adrem.ua.ac.be/michael.mampaey/implementations)
    """
    def __init__(self, transactionIterator, minsup, maxdepth=0):
        self.transactionIterator = transactionIterator
        self.minsup      = minsup
        self.item_count  = 0
        self.trans_count = 0
        self.maxdepth    = maxdepth
        self.data        = None
        self.frequentItemsets = []
        self.itemToItemIdMap = {}

    def read_data(self):
        """Read data and return list of itemsets, in vertical format
        """
        self.item_count  = 0
        self.trans_count = 0
        self.data = []
        self.data.append(Itemset(0))

        for itemset in self.transactionIterator:
            self.trans_count += 1
            for item in itemset:
                if item not in self.itemToItemIdMap: self.itemToItemIdMap[item]=len(self.itemToItemIdMap)+1
                item = self.itemToItemIdMap[item]
                if item > self.item_count:
                    for i in range(self.item_count+1, item+1): self.data.append(Itemset(i))
                    self.item_count = item
                self.data[item].tids.add(self.trans_count)
        for itemset in self.data: itemset.support = len(itemset.tids)
        return

    def prune_items(self):
        """Prune the non-frequent items from the data
        """
        for i in range(len(self.data)-1, -1, -1):
            if self.data[i].support < self.minsup: del self.data[i]
        self.data.sort()
        return

    def eclat_mine(self, data=[], prefix=[], closure=[], clen = 0, depth=0):
        """Mines vertical data depth-first, rightmost for frequent itemsets
        """
        if self.maxdepth and depth+clen >= self.maxdepth: return 0

        counter = 0
        if depth == 0: counter = 1
        for i in range(len(data)):
            set1 = data[i]
            prefix.append(set1.suffix)
            children = []
            cl = clen

            for j in range(i+1, len(data)):
                set2 = data[j]
                tmpset = Itemset()
                tmpset.suffix = set2.suffix
                if depth < 1:
                    tmpset.tids = set1.tids & set2.tids
                    tmpset.support = len(tmpset.tids)
                elif depth == 1:
                    tmpset.tids = set1.tids - set2.tids
                    tmpset.support = set1.support - len(tmpset.tids)
                else:
                    tmpset.tids = set2.tids - set1.tids
                    tmpset.support = set1.support - len(tmpset.tids)
                if tmpset.support >= self.minsup:
                    if set1.support == tmpset.support:
                        if len(closure) <= cl: closure.append(tmpset.suffix)
                        else: closure[cl] = tmpset.suffix
                        cl += 1
                    else: children.append(tmpset)
            self.saveset(prefix, set1.support, closure[:cl])
            counter += 2**cl

            if len(children):
                children.sort()
                counter += self.eclat_mine(children, prefix, closure, cl, depth+1)

            prefix.remove(set1.suffix)
            del children

        return counter

    def saveset(self, prefix, supp, closure=[]):
        self.frequentItemsets.append((prefix[:], supp))
        for i, item in enumerate(closure):
            prefix.append(item)
            self.saveset(prefix, supp, closure[i+1:])
            prefix.remove(item)
        return

    def getFrequentItemsets(self, maxdepth=0):
        self.read_data()
        self.prune_items()
        self.eclat_mine(self.data)
        itemIdToItemMap = GeneralMethods.reverseDict(self.itemToItemIdMap)
        return [([itemIdToItemMap[itemId] for itemId in itemset[0]], itemset[1]) for itemset in self.frequentItemsets]


#Ejemplo de distribución de manzanas

#IMPORTAMOS "matplotlib".
import matplotlib.pyplot as plt

#DEFINIMOS ETIQUETAS
manzanas = [20,10,25,30]
nombres = ["Ana","Juan","Diana","Catalina"]

#DIBUJAMOS GRÁFICA.
plt.pie(manzanas, labels=nombres, autopct="%0.1f %%")

#MOSTRAMOS GRÁFICA.
plt.show()


from torch.utils.data import Dataset
from torchvision import transforms
from skimage import io
import os
import numpy as np
import torch
from PIL import Image, ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

class CLEVR(Dataset):
    def __init__(self, root, mode):
        # path = os.path.join(root, mode)
        self.root = root
        assert os.path.exists(root), 'Path {} does not exist'.format(root)

        self.img_paths = []
        for file in os.scandir(os.path.join(root, 'images')):
            img_path = file.path
            self.img_paths.append(img_path)

        self.img_paths.sort()

    def __getitem__(self, index):
        img_path = self.img_paths[index]
        img = io.imread(img_path)[:, :, :3]
        transform = transforms.Compose([
            transforms.ToPILImage(),
            transforms.CenterCrop(192),
            transforms.Resize(128),
            transforms.ToTensor(),
        ])
        img = transform(img)

        mask_transform = transforms.Compose([
            transforms.ToPILImage(),
            transforms.CenterCrop(192),
            transforms.Resize(128, interpolation=Image.NEAREST),
        ])
        filename = os.path.split(img_path)[-1]
        mask_path = os.path.join(self.root, 'masks', filename)
        mask = None
        if os.path.exists(mask_path):
            mask = io.imread(mask_path)
            mask = self.sep(mask)
            mask = [np.array(mask_transform(x[:, :, None].astype(np.uint8))) for x in mask]
            mask = np.stack(mask, axis=0)
            mask = torch.from_numpy(mask.astype(np.float)).float()
        # mask = None

        return img, mask

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

    def sep(self, img):
        """
        Seperate a color image into masks
        :img: (H, W, 3)
        :return: (K, H, W), bool array
        """
        img = img[:, :, :3]
        # a = set()
        # for i in range(img.shape[0]):
        #     for j in range(img.shape[1]):
        #         pixel = tuple(img[i, j][:3])
        #         if pixel not in a and pixel != (64, 64, 64):
        #             a.add(pixel)
        H, W, _ = img.shape
        pixels = list(tuple(pix) for pix in img.reshape(H * W, 3))
        a = set(pixels)
        # background
        a.remove((64, 64, 64))
        masks = []
        for pixel in a:
            pixel = np.array(pixel)
            # (h, w, 3)
            mask = img == pixel
            mask = np.all(mask, 2)
            masks.append(mask)

        return masks


""" Floyd Wallshall algorithm

D[ab] = min(D[ab], D[ak]+D[kb]

input data:
- node count, line count
    - loop line count
        node1 node2 distance

output
- loop nodes
    - loop nodes
        - print nodes to nodes distance

[input]
4 7
1 2 4
1 4 6
2 1 3
2 3 7
3 1 5
3 4 4
4 3 2
"""
INF = int(1e9)

def floyd_wallshall_algorithm(graph):
    """
    Floyd Wallshall Algorithm:
    D[ab] = min(D[ab], D[ak]+D[kb]
    """
    count = len(graph)
    for a in range(count):
        for b in range(count):
            for k in range(count):
                graph[a][b] = min(graph[a][b], graph[a][k]+graph[k][b])

    return graph

def main():
    # Input User Data
    node_count, line_count = map(int, input().split())
    graph = [[INF]*node_count for _ in range(node_count)]

     # Same node distance should be 0
    for node1 in range(node_count):
        for node2 in range(node_count):
            if node1 == node2 :
                graph[node1][node2] = 0

    # input user data.
    for _ in range(line_count):
        node1, node2, distance = map(int, input().split())
        graph[node1-1][node2-1] = distance

    for item in floyd_wallshall_algorithm(graph):
        print(item)

if __name__ == '__main__':
    main()


# -*- coding: utf-8 -*-
"""A module defining hydrogen-like orbitals with non-collinear spin component."""

from aiida.common.exceptions import ValidationError
from aiida.tools.data.orbital.realhydrogen import RealhydrogenOrbital

def validate_spin(value):
    """Validate the value of the spin projection s_z."""
    if not isinstance(value, (int, float)):
        raise ValidationError('spin projection (s_z) must be float')

    return value

class NoncollinearHydrogenOrbital(RealhydrogenOrbital):
    """Orbitals for hydrogen, with non-collinear spin.

    The class largely follows the conventions used by wannier90 Object to
    handle the generation of real hydrogen orbitals and their hybrids, has
    methods for producing s, p, d, f, and sp, sp2, sp3, sp3d, sp3d2 hybrids.
    This method does not deal with the cannonical hydrogen orbitals which
    contain imaginary components. The orbitals described here are chiefly
    concerned with the symmetric aspects of the oribitals without the context
    of space. Therefore diffusitivity, position and atomic labels should be
    handled in the OrbitalData class. Following the notation of table 3.1, 3.2
    of Wannier90 user guide http://www.wannier.org/doc/user_guide.pdf A brief
    description of what is meant by each of these labels: :param radial_nodes:
    the number of radial nodes (or inflections) if no radial nodes are
    supplied, defaults to 0 :param angular_momentum: Angular quantum number,
    using real orbitals :param magnetic_number: Magnetic quantum number, using
    real orbitals :param spin: spin z-projection s_z The conventions regarding
    L and M correpsond to those used in wannier90 for all L greater than 0 the
    orbital is not hyrbridized see table 3.1 and for L less than 0 the orbital
    is hybridized see table 3.2. M then indexes all the possible orbitals from
    0 to 2L for L > 0 and from 0 to (-L) for L < 0.
    """

    _base_fields_required = RealhydrogenOrbital._base_fields_required

    _base_fields_optional = tuple(
        list(filter(lambda x: x[0] != 'spin', RealhydrogenOrbital._base_fields_optional)) + [
            ('spin', validate_spin, 0.0),
        ]
    )

    def __str__(self):
        """Printable representation of the orbital."""
        orb_dict = self.get_orbital_dict()
        try:
            orb_name = self.get_name_from_quantum_numbers(
                orb_dict['angular_momentum'], magnetic_number=orb_dict['magnetic_number']
            )
            pos = orb_dict['position']
            pos_string = f'{pos[0]:.4f},{pos[1]:.4f},{pos[2]:.4f}'
            orb = f"for kind {orb_dict['kind_name']}" if orb_dict['kind_name'] else ''
            out_string = f"r{orb_dict['radial_nodes']} {orb_name} (s_z={orb_dict['spin']}) orbital {orb} @ {pos_string}"
        except KeyError:
            # Should not happen, but we want it not to crash in __str__
            out_string = '(not all parameters properly set)'
        return out_string


import openai
from tenacity import retry, stop_after_attempt
import setting

import logging

logger = logging.getLogger(__name__)

class MyBotWrapper:
    def __init__(self, parser, model=setting.DEFAULT_MODEL, temperature=0.5) -> None:
        self.parser = parser
        self.model = model
        self.temperature = temperature

    @retry(stop=stop_after_attempt(3))
    def run(self, inputs):
        prompt = self.parser.compose_prompt(inputs=inputs)
        logger.debug(f"PROMPT: {prompt}")
        response = self.get_completion(
            user_content=prompt.get("user_content"),
            system_content=prompt.get("system_content")
        )
        logger.debug(f"RAW RESPONSE: {response}")
        res = self.parser.parse_response(prompt=prompt, response=response)
        logger.debug(f"PARSED RESPONSE: {res}")
        return res

    def get_completion(self, user_content, system_content=None):
        messages = []
        system_content and messages.append(
            {"role": "system", "content": system_content}
        )
        messages.append({"role": "user", "content": user_content})
        response = openai.ChatCompletion.create(
            model=self.model,
            messages=messages,
            temperature=self.temperature,  # this is the degree of randomness of the model's output
            request_timeout=setting.REQUEST_TIMEOUT_SECS,
        )
        return response.choices[0].message["content"]

    @property
    def task_name(self):
        return self.parser.task_name if self.parser else ""


import setuptools

with open("README.md", "r", encoding="utf-8") as fh:
    long_description = fh.read()

setuptools.setup(
    name="hackertype", # Replace with your own username
    version="0.1",
    author="Denis Daletski",
    author_email="daletskidenis@gmail.com",
    description="Type like a holywood movie hacker",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/ddaletski/hackertype",

    py_modules=['hackertype'],
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires='>=3.5',
    install_requires=[
        'Click',
    ],
    entry_points='''
        [console_scripts]
        hackertype=hackertype:cli
    '''
)


from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager

import pandas as pd
import random
import requests
import selenium
import selenium.webdriver.support.ui as ui
import time

from Backend.WebsiteParser import WebsiteParser

class BlocketParser(WebsiteParser):
    def __init__(self) -> None:
        # Setup Chromedriver for selenium
        self.service = Service(executable_path=ChromeDriverManager().install())
        # Default page containing 'all' objects for sale
        self.default_website_url = "https://www.blocket.se/annonser/"
        supported_query_keys = ["ELLER", "EJ", "*", '""']
        super().__init__(self.default_website_url, supported_query_keys)

    def scrape_data(self, search_query: str) -> pd.DataFrame:
        relevant_links = pd.DataFrame()
        query_url = self.create_url_from_query(search_query)

        try:
            continue_parsing = True
            current_page = 1
            query_url += f"&page={current_page}"

            with webdriver.Chrome(service=self.service) as driver:
                while continue_parsing:
                    print(f"Parsing {query_url}...")
                    driver.get(query_url)

                    # This part is added to make sure the page is fully loaded before parsing it. Selenium has functions
                    # that takes care of this in a proper way but this works "good enough" for this project.
                    sleep_time = random.random() * 10 + 10
                    print(f"Page opened. Will wait for {sleep_time} before parsing page...")
                    time.sleep(sleep_time)

                    # First page will have a cookie pop up that needs to be accepted
                    self.check_and_approve_cookies(driver)
                    ui.WebDriverWait(driver, 10).until(lambda d: d.find_elements(By.TAG_NAME, "article"))
                    new_links, continue_parsing = self.find_links_and_scrape_data(driver)
                    relevant_links = relevant_links.append(new_links, ignore_index=True)

                    current_page += 1
                    query_url = query_url.replace(f"&page={current_page - 1}", f"&page={current_page}")

        except requests.exceptions.HTTPError as e:
            pass

        return relevant_links

    def check_and_approve_cookies(self, driver: webdriver) -> None:
        for element in driver.find_elements(By.TAG_NAME, "aside"):
            if "cookie" in element.accessible_name:
                for button in element.find_elements(By.TAG_NAME, "button"):
                    if "Jag samtycker" in button.accessible_name:
                        button.click()
                        return

    def find_links_and_scrape_data(self, driver: webdriver) -> pd.DataFrame:
        link_data = pd.DataFrame()
        continue_parsing = True

        articles = driver.find_elements(By.TAG_NAME, "article")
        for article in articles:
            article_dict = {
                "category": "",
                "location": "",
                "time": "",
                "link": ""
            }

            try:
                article_data = article.find_element(By.CSS_SELECTOR, "div[class^='styled__Content']")
                header_wrapper = article_data.find_element(By.CSS_SELECTOR, "div[class^='styled__LocationTimeWrapper']")
                subject_wrapper = article_data.find_element(By.CSS_SELECTOR, "div[class^='styled__SubjectWrapper']")

                for p_element in header_wrapper.find_elements(By.TAG_NAME, "p"):
                    class_name = p_element.get_attribute("class")
                    if "TopInfoWrapper" in class_name:
                        category_location = p_element.text.split(" · ")
                        article_dict["category"] = category_location[0]
                        article_dict["location"] = category_location[1] if len(category_location) > 1 else ""
                    elif "Time" in class_name:
                        article_dict["time"] = p_element.text

                article_dict["link"] = subject_wrapper.find_element(By.CSS_SELECTOR, "a[class^='Link']").get_attribute("href")

                # Only keep the articles uploaded today
                if "Idag" in article_dict["time"]:
                    link_data = link_data.append(article_dict, ignore_index=True)
                else:
                    continue_parsing = False
                    break

            except selenium.common.exceptions.NoSuchElementException as e:
                print(f"Got {e} while trying to parse {article}")

        if link_data.empty:
            continue_parsing = False

        return link_data, continue_parsing

    def get_url_search_category(self) -> str:
        combined_string = ""
        if self.website_url == self.default_website_url:
            combined_string = "hela_sverige_alla_annonser"
        else:
            url_parts = self.website_url.replace(self.default_website_url, "").split("?")[0].split("/")
            combined_string = "_".join(url_parts)

        return combined_string

    def create_url_from_query(self, search_query: str) -> str:
        query_url = self.website_url

        if "&sort=date" not in query_url:
            query_url += "&sort=date"

        if search_query:
            query_url+= f"&q={search_query.replace(' ', '+')}"

        return query_url


import sys
import time
from re import sub as substitute
from faker import Faker

from config.CrudModule import UserCrud

class MultiInsert:
    def process_insert(self,no_records):
        uc=UserCrud()
        uc.create() # Create table if not exists
        counter=1
        st = time.process_time()
        while counter<no_records+1:
            insert_list=self.get_thousand_list_rows()
            for fd in insert_list:
                uc.pg_insert(fd,counter)
                ## Print the inserted rows after every 10,000 rows inserted.
                if(counter%10000==0):
                    ed=time.process_time()
                    print('[Batch:10,000]Inserted ',counter,' Records In Total ',ed-st,' sec.')
                counter+=1

    @staticmethod
    def get_thousand_list_rows():
        fake = Faker()
        append_list=list()
        st = time.process_time()
        for counter in range(10000):
            data=list()
            data.append(fake.name())
            data.append(substitute('[^0-9\-\(\)]','',fake.phone_number()))
            data.append(fake.email())
            data.append(fake.sentence())
            data.append(fake.date())
            data.append('M' if counter%3==0 else 'F' if counter %2==0 else 'O' )
            data.append(substitute('\\n',' ',fake.address()))
            data.append(float(fake.latitude()) )
            data.append(float(fake.longitude()))
            data.append(fake.image_url())
            data.append(fake.uri())
            append_list.append(data)
        ed = time.process_time()
        print('\nGenerated 10,000 Fake Data in ' ,ed -st,' sec.\n' )
        return append_list

def main():
    mi = MultiInsert()
    mi.process_insert(int(sys.argv[1]))

if __name__ == '__main__':
    main()


# Adapted from https://github.com/kekeblom/DeepCGP
import numpy as np
import tensorflow as tf

from .kernels import Kernel
from . import settings
from .params import Parameter

class AdditivePatchKernel(Kernel):
    """This conv kernel sums over each patch assuming the output is produced independently from each patch.
        K(x, x') = \sum_{i} w_i k(x[i], x'[i])
    """
    def __init__(self, base_kernel, view, patch_weights=None, name='AdditivePatch'):
        super().__init__(input_dim=np.prod(view.input_size), name=name)
        self.base_kernel = base_kernel
        self.view = view
        self.patch_length = view.patch_length
        self.patch_count = view.patch_count
        self.image_size = self.view.input_size
        if patch_weights is None or patch_weights.size != self.patch_count:
            patch_weights = np.ones(self.patch_count, dtype=settings.float_type)
        with tf.variable_scope(self._name):
            self._patch_weights = Parameter(patch_weights)
        self._parameters = self._parameters + self.base_kernel.parameters + [self._patch_weights]

    @property
    def patch_weights(self):
        return self._patch_weights.value

    def _reshape_X(self, ND_X):
        ND = tf.shape(ND_X)
        return tf.reshape(ND_X, [ND[0]] + list(self.view.input_size))

    def K(self, ND_X, X2=None):
        NHWC_X = self._reshape_X(ND_X)
        patch_length = self.patch_length
        PNL_patches = self.view.extract_patches_PNL(NHWC_X)

        if X2 is None:
            PNL_patches2 = patches
        else:
            PNL_patches2 = self.view.extract_patches_PNL(self._reshape_X(X2))

        def compute_K(tupled):
            NL_patches1, NL_patches2, weight = tupled
            return weight * self.base_kernel.K(NL_patches1, NL_patches2)

        PNN_K = tf.map_fn(compute_K, (PNL_patches, PNL_patches2, self.patch_weights), settings.float_type,
                parallel_iterations=self.patch_count)

        return tf.reduce_mean(PNN_K, [0])

    def Kdiag(self, ND_X):
        NHWC_X = self._reshape_X(ND_X)
        PNL_patches = self.view.extract_patches_PNL(NHWC_X)
        def compute_Kdiag(tupled):
            NL_patches, weight = tupled
            return weight * self.base_kernel.Kdiag(NL_patches)
        PN_K = tf.map_fn(compute_Kdiag, (PNL_patches, self.patch_weights), settings.float_type,
                parallel_iterations=self.patch_count)
        return tf.reduce_mean(PN_K, [0])

    def Kzx(self, ML_Z, ND_X):
        NHWC_X = self._reshape_X(ND_X)
        # Patches: N x patch_count x patch_length
        PNL_patches = self.view.extract_patches_PNL(NHWC_X)
        def compute_Kuf(tupled):
            NL_patches, weight = tupled
            return weight * self.base_kernel.K(ML_Z, NL_patches)

        KMN_Kuf = tf.map_fn(compute_Kuf, (PNL_patches, self.patch_weights), settings.float_type,
                parallel_iterations=self.patch_count)

        return tf.reduce_mean(KMN_Kuf, [0])

    def Kzz(self, Z):
        return self.base_kernel.K(Z)

class ConvKernel(AdditivePatchKernel):
    # Loosely based on https://github.com/markvdw/convgp/blob/master/convgp/convkernels.py
    def K(self, ND_X, X2=None):
        NHWC_X = self._reshape_X(ND_X)
        patch_length = self.patch_length
        # N * P x L
        patches = tf.reshape(self.view.extract_patches(NHWC_X), [-1, patch_length])

        if X2 is None:
            patches2 = patches
        else:
            patches2 = tf.reshape(self.view.extract_patches(X2), [-1, patch_length])

        # K: batch * patches x batch * patches
        K = self.base_kernel.K(patches, patches2)
        X_shape = tf.shape(NHWC_X)
        # Reshape to batch x patch_count x batch x patch_count
        K = tf.reshape(K, (X_shape[0], self.patch_count, X_shape[0], self.patch_count))

        w = self.patch_weights
        W = w[None, :] * w[:, None] # P x P
        W = W[None, :, None, :] # 1 x P x 1 x P
        K = K * W

        # Sum over the patch dimensions.
        return tf.reduce_sum(K, [1, 3]) / (self.patch_count ** 2)

    def Kdiag(self, ND_X):
        NHWC_X = self._reshape_X(ND_X)
        # Compute auto correlation in the patch space.
        # patches: N x patch_count x patch_length
        patches = self.view.extract_patches(NHWC_X)
        w = self.patch_weights
        W = w[None, :] * w[:, None]
        def sumK(p):
            return tf.reduce_sum(self.base_kernel.K(p) * W)
        return tf.map_fn(sumK, patches, parallel_iterations=self.patch_count) / (self.patch_count ** 2)

    def Kzx(self, Z, ND_X):
        NHWC_X = self._reshape_X(ND_X)
        # Patches: N x patch_count x patch_length
        patches = self.view.extract_patches(NHWC_X)
        patches = tf.reshape(patches, (-1, self.patch_length))
        # Kzx shape: M x N * patch_count
        Kzx = self.base_kernel.K(Z, patches)
        M = tf.shape(Z)[0]
        N = tf.shape(NHWC_X)[0]
        # Reshape to M x N x patch_count then sum over patches.
        Kzx = tf.reshape(Kzx, (M, N, self.patch_count))

        w = self.patch_weights
        Kzx = Kzx * w

        Kzx = tf.reduce_sum(Kzx, [2])
        return Kzx / self.patch_count

    def Kzz(self, Z):
        return self.base_kernel.K(Z)


import socket

IP_ADDRESS = '192.168.0.109'
PORT = 139

#Socket Object......Scans TCP
with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s:
    try:

        s.connect((IP_ADDRESS, PORT))   #Tuple
        print(f'port {PORT} is open and listening')
    except:
        print(f'failed to Connect to {PORT}')


import sys
import requests
import time
import xml.etree.ElementTree as ET
from collections import defaultdict

debug = False
print_rank = True
YOUR_BGG_NAME = 'Your_BGG_Username'

def extract_game_data(xml_str, debug=False):
    root = ET.fromstring(xml_str)
    games = root.findall('.//item')
    i = 0
    game_data = []
    if debug:
        print(f'extract_game_data: {len(games)} games found')
    for game in games:
        game_id = game.attrib['objectid']
        if debug:
            i += 1
            print(f'game {i}: {game_id} ...')
        name = game.find('name').text
        rank = game.find('.//rank[@type="subtype"]').attrib['value']
        numplays = game.find('numplays').text
        rating_value = game.find('stats/rating').attrib['value']
        average_rating = game.find('stats/rating/average').attrib['value']
        bayes_average_rating = game.find('stats/rating/bayesaverage').attrib['value']

        game_info = {
            'game_id': game_id,
            'name': name,
            'rank': rank,
            'numplays': numplays,
            'rating_value': rating_value,
            'average_rating': average_rating,
            'bayes_average_rating': bayes_average_rating
        }

        game_data.append(game_info)
    return game_data

def map_rating(rating, spaces=1):
    spacer = ' ' * int(spaces)
    k = int(rating) if rating.isdigit() else -1
    return {
        10: '[BGCOLOR=#00CC00] [b]' + str(rating) + '[/b] [/BGCOLOR]',
        9: '[BGCOLOR=#33CC99] [b]' + str(rating) + '[/b] [/BGCOLOR]',
        8: '[BGCOLOR=#66FF99] [b]' + str(rating) + '[/b] [/BGCOLOR]',
        7: '[BGCOLOR=#99FFFF] [b]' + str(rating) + '[/b] [/BGCOLOR]',
        6: '[BGCOLOR=#9999FF] [b]' + str(rating) + '[/b] [/BGCOLOR]',
        5: '[BGCOLOR=#CC99FF] [b]' + str(rating) + '[/b] [/BGCOLOR]',
        4: '[BGCOLOR=#FF66CC] [b]' + str(rating) + '[/b] [/BGCOLOR]',
        3: '[BGCOLOR=#FF6699] [b]' + str(rating) + '[/b] [/BGCOLOR]',
        2: '[BGCOLOR=#FF3366] [b]' + str(rating) + '[/b] [/BGCOLOR]',
        1: '[BGCOLOR=#FF0000] [b]' + str(rating) + '[/b] [/BGCOLOR]'
    }.get(k, '[BGCOLOR=#A3A3A3] [b]--[/b] [/BGCOLOR]') + spacer

if __name__ == "__main__":
    # Retrieve command line arguments
    if len(sys.argv) < 3:
        print("Please provide mindate (yyyy-mm-dd) and maxdate (yyyy-mm-dd) parameters, and (optionally) your BGG username as the third parameter.")
        sys.exit(1)

    mindate = sys.argv[1]
    maxdate = sys.argv[2]

    if len(sys.argv) == 4:
        YOUR_BGG_NAME = sys.argv[3]

    # API request URL
    url = f'https://boardgamegeek.com/xmlapi2/plays?username={YOUR_BGG_NAME}&mindate={mindate}&maxdate={maxdate}&type=thing&subtype=boardgame&brief=1'

    # Make the API request
    response = requests.get(url)

    while response.status_code == 202:
        print("Waiting for response...")
        time.sleep(0.33)
        response = requests.get(url)

    if response.status_code != 200:
        print(f'url request failed with code {response.status_code}')
        exit(1)

    xml_str = response.text

    # Parse the XML string
    root = ET.fromstring(xml_str)

    # Extract game IDs and number of plays
    gameplays = root.findall('.//play')
    plays_per_game = defaultdict(int)

    for gameplay in gameplays:
        game = gameplay.find('item')
        assert game
        game_id = game.attrib['objectid']
        play_count = gameplay.attrib.get('quantity', 1)
        plays_per_game[game_id] += int(play_count)

    # look up the game rank and name for each id
    game_ids = [int(k) for k in plays_per_game.keys()]
    game_ids_str = ",".join(map(str, game_ids))

    # Print the number of plays per game
    if debug:
        for game_id, play_count in plays_per_game.items():
            print(f"Game ID: {game_id}, Plays: {play_count}")

    url2 = f'https://boardgamegeek.com/xmlapi2/collection?username={YOUR_BGG_NAME}&id=' + game_ids_str + '&stats=1'
    # Make the API request
    if debug:
        print(url2 + ' ...')
    response = requests.get(url2)

    while response.status_code == 202:
        print("Waiting for response...")
        time.sleep(0.33)
        response = requests.get(url)

    if response.status_code != 200:
        print(f'url request failed with code {response.status_code}')
        exit(1)

    game_bgg_data = extract_game_data(response.text, debug=False)
    for game in game_bgg_data:
        game['play_count'] = plays_per_game[game['game_id']]
    game_bgg_data.sort(key=lambda x: x['play_count'], reverse=True)

    for game in game_bgg_data:
        rating = game['rating_value']
        rating_str = map_rating(rating, 1)
        name = game['name']
        rank = game['rank']
        plays = game['play_count']
        plays_str = f' x{plays}' if int(plays) > 1 else ''
        total = game['numplays']
        if int(plays) == int(total):
            total_str = '[b][COLOR=#FF0000][size=7]NEW![/size][/COLOR][/b]'
        else:
            total_str = f'[size=7]({total} so far)[/size]'
        if print_rank:
            if 'Not' in str(rank):
                rank_str = '[size=8]' + 'unranked' + ' [/size]'
            else:
                rank_str = '[size=8]' + str(rank).rjust(8,' ') + ' [/size]'
            print(f'[c]{rank_str} [/c]{rating_str} {name}{plays_str} {total_str}')
        else:
            print(f'{rating_str} {name}{plays_str} {total_str}')


import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.naive_bayes import MultinomialNB
import pickle
import os

from DataStructures.GoogleSheet import GoogleSheet

class ProductClassifier:
    test_row = 700
    def __init__(self, spreadsheet_id, cred_file):
        self.ggsheet = GoogleSheet(spreadsheet_id, cred_file)
        self.categories = list(self.ggsheet.categories_id.keys())
        self.training_data = []
        self.model = MultinomialNB()
        self.vectorizer = CountVectorizer()
        self.tfidf_transformer = TfidfTransformer()
        pass

    def get_training_data(self, size):
        for category_i in range(0, len(self.categories)):
            tmp = [[x[0], category_i] for x in (self.ggsheet.get_data(1, size, 1, self.categories[category_i])['values'])]
            for x in tmp:
                self.training_data.append(x)

    def get_testing_data_from_sheet(self, size):
        testing_data = []
        for category_i in range(0, len(self.categories)):
            tmp = [[x[0], category_i] for x in (self.ggsheet.get_data(self.test_row, self.test_row + size, 1, self.categories[category_i])['values'])]
            for x in tmp:
                testing_data.append(x)
        return testing_data

    def train_classifier(self, size):
        self.get_training_data(size)
        X_train_counts = self.vectorizer.fit_transform([data[0] for data in self.training_data])
        X_train_tfidf = self.tfidf_transformer.fit_transform(X_train_counts)
        y_train = np.array([data[1] for data in self.training_data])

        # Train the classifier
        self.model.fit(X_train_tfidf, y_train)

    def get_accuracy(self, testing_data = None):
        if testing_data == None:
            testing_data = self.get_testing_data_from_sheet(500)
        X_test_counts = self.vectorizer.transform([data[0] for data in testing_data])
        X_test_tfidf = self.tfidf_transformer.transform(X_test_counts)
        y_test = np.array([data[1] for data in testing_data])

        # Predict the test data
        y_pred = self.model.predict(X_test_tfidf)

        # Calculate the accuracy
        accuracy = np.mean(y_pred == y_test)
        return accuracy

    def save_model(self):
        pickle.dump(self.model, open("classifier.sav", "wb"))
        pickle.dump(self.vectorizer, open("vectorizer.sav", "wb"))
        pickle.dump(self.tfidf_transformer, open("tfidf_transformer.sav", "wb"))

    def load_model(self):
        if (os.path.isfile("classifier.sav") and os.path.isfile("vectorizer.sav")
            and os.path.isfile("tfidf_transformer.sav")):
            self.model = pickle.load(open("classifier.sav", "rb"))
            self.vectorizer = pickle.load(open("vectorizer.sav", 'rb'))
            self.tfidf_transformer = pickle.load(open("tfidf_transformer.sav", 'rb'))
            return 1
        else:
            return 0

    def predict(self, input_string):
        # Vectorize the input string
        X_input_counts = self.vectorizer.transform([input_string])
        X_input_tfidf = self.tfidf_transformer.transform(X_input_counts)

        # Classify the input string
        y_pred = self.model.predict(X_input_tfidf)[0]
        category = self.categories[y_pred]
        return category

if __name__ == "__main__":
    tester = ProductClassifier("1H5TTOdrTC_T7U7k_ejCUG8BZWn97NuaxD0t4F7LwH8g", "client_secret.json")
    if (tester.load_model()):
        print("model loaded succesfully yay")
        print(tester.predict("Laptop ASUS"))
    else:
        tester.train_classifier()
        tester.get_accuracy()
        print(tester.predict("Laptop ASUS"))
        tester.save_model()


infile = open('UN.txt', 'r')

nations = []

for line in infile:
    line = line.rstrip()
    nations.append(line.split(',')) #

print('Countries data example:', nations[:2])

asia_nations = []
for nation in nations:
    if nation[1] == 'Asia': #
        asia_nations.append(nation) #

print('The total number of Asian countries is', len(asia_nations))

for asia_nation in asia_nations:
    if not 'o' in asia_nation[0] or float(asia_nation[2]) < 30000 or float(asia_nation[1]) < 1.0: #
        idx = asia_nations.index(asia_nation) #
        del asia_nations[idx] #

print('Countries suitable for conditions: ')
for asian_nation in asia_nations[:-8:-2]:
    print(asian_nation[0])

    '''
[RUN]
Countries data example: [['Afghanistan', 'Asia', '31.8', '251772'], ['Albania', 'Europe', '3.0', '11100']]
The total number of Asian countries is 47
Countries suitable for conditions:
Vietnam
Turkey
Syrian Arab Republic
Republic of Korea
'''


import numpy as np
import torch
import scipy.special as sps
from functools import partial
from utils import cart, outer, leja_order, bisection, eval_leg_deriv

class Cubature:

    def __init__(self, deg=[100], quad="leg"):
        self.dim = len(deg)
        self.deg = deg
        self.quad = quad

        self.axes, self.axes_weights, self.axes_leja = self._axes()
        self.leja_axes, self.leja_axes_weights = self._leja_axes()

        self.grid = cart(self.axes)
        self.leja_grid = cart(self.leja_axes)
        self.leja_weights = outer(self.leja_axes_weights)

    def _axes(self):
        axes = []
        axes_weights = []
        axes_leja = []

        for i, _ in enumerate(self.deg):
            if _ in self.deg[0:i]:
                j = self.deg.index(_)

                axis = axes[j]
                axis_weight = axes_weights[j]
                axis_leja = axes_leja[j]

            else:
                axis, axis_weight = getattr(self, self.quad)(_)
                axis_leja = leja_order(axis)

            axes.append(axis)
            axes_weights.append(axis_weight)
            axes_leja.append(axis_leja)

        return axes, axes_weights, axes_leja

    def _leja_axes(self):
        return [self.axes[_][self.axes_leja[_]] for _ in range(self.dim)], \
               [self.axes_weights[_][self.axes_leja[_]] for _ in range(self.dim)], \

    @staticmethod
    def leg(deg):
        axis, axis_weight = sps.roots_legendre(deg+1)
        return axis, axis_weight

    #https://relate.cs.illinois.edu/course/CS450-S20/f/demos/upload/quadrature_and_diff/Gaussian%20quadrature%20weight%20finder.html
    #explicit rule for lobatto barycentric weights in order to reduce numerical error
    #but additionally implement sth which can handle barycentric(nodes)
    @staticmethod
    def leglob(deg):
        n = deg+1
        brackets = sps.legendre(n-1).weights[:, 0]
        axis = np.zeros(n)
        axis[0] = -1
        axis[-1] = 1

        for _ in range(n-2):
            axis[_+1] = bisection(
                partial(eval_leg_deriv, n-1),
                brackets[_], brackets[_+1])

        axis_weight = np.zeros(n)
        axis_weight[0] = 2/n/(n-1)
        axis_weight[-1] = 2/n/(n-1)

        for _ in range(n-2):
            axis_weight[_+1] = 2/n/(n-1)/(sps.eval_legendre(n-1, axis[_+1]))**2

        return axis, axis_weight

    def integral(self, u):
        if torch.is_tensor(self.leja_weights):
            return torch.sum(self.leja_weights*u)
        else:
            return torch.sum(torch.tensor(self.leja_weights)*u)


"""
:mod:`timeseries` - Extract timeseries from each timestep of a simulation
=========================================================================

Extract station timeseries from each timestep of a simulation.
This samples the regional wind speed, not the site-specific wind speed.
To include site-specific effects, you will first need to include the
multiplier values for each site in the station file, then run
tsmultipliers.py to apply said multipliers to the output.

"""

import logging
from os.path import join as pjoin
from configparser import NoOptionError

import numpy as np

from Utilities.config import ConfigParser
from Utilities.files import flLoadFile
from Utilities.maputils import find_index
from Utilities.dynarray import DynamicRecArray
from .shptools import shpGetVertices

#from config import NoOptionError
log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())

ISO_FORMAT = "%Y-%m-%d %H:%M"

OUTPUT_NAMES = ('Station', 'Time', 'Longitude', 'Latitude',
                'Speed', 'UU', 'VV', 'Bearing',
                'Pressure')
OUTPUT_TYPES = ['|U16', '|U16', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8']
OUTPUT_FMT = ['%s', '%s', '%9.5f', '%9.5f',
              '%6.2f', '%6.2f', '%6.2f', '%6.2f',
              '%7.2f']

MINMAX_NAMES = ('Station', 'Time', 'Longitude', 'Latitude',
                'Speed', 'UU', 'VV', 'Bearing', 'Pressure')
MINMAX_TYPES = ['|U16', '|U16', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8']
MINMAX_FMT = ['%s', '%s', '%9.5f', '%9.5f',
              '%6.2f', '%6.2f', '%6.2f', '%6.2f',
              '%7.2f']

CONFIG_DEFAULTS = """
[Timeseries]
StationID=None
"""

class Station(object):
    """Station:

    Description: An object to represent a location for which time series
                 data will be extracted

    Members:
    `id`: Unique id string for the station
    `lon`: Longitude of the station (geographic coordinates)
    `lat`: Latitude of the station (geographic coordinates)
    `data`: A `DynamicRecArray` to hold the time series data

    Methods:
    `insideGrid`: Determine if the station is inside the simulation domain.
    """

    def __init__(self, stationid, longitude, latitude):

        self.id = stationid
        self.lon = longitude
        self.lat = latitude
        self.data = DynamicRecArray(dtype={'names': OUTPUT_NAMES,
                                           'formats':OUTPUT_TYPES})

    def __getattr__(self, key):
        """
        Get the `key` from the `data` object.

        :param str key: the key to lookup in the `data` object.
        """
        if key.startswith('__') and key.endswith('__'):
            return super(Station, self).__getattr__(key)
        return self.data.data[key]

    def insideGrid(self, gridx, gridy):
        """
        Determine if a point is within the defined grid

        """
        if (float(self.lon) >= gridx.min() \
            and float(self.lon) <= gridx.max() and \
            float(self.lat) >= gridy.min() and \
            float(self.lat) <= gridy.max()):
            return True
        else:
            return False

class Timeseries(object):
    """Timeseries:

    Description: Extract data at a set of :class:`Station`s

    Parameters:

    :param str configFile: Path to a TCRM configuration file

    Members:
    `meta`: Boolean whether additional metadata is attached to the `Station`s
    `outputPath`: Directory where extracted data will be stored in csv-format files
    `minfile`: Name of the file where minima for all `Station`s will be stored.
               This will be the `outputPath` folder
    `maxfile`: As above, but for maxima (e.g. maximum wind speeds)
    `stations`: A list of `Station` objects, read from a file containing details of the stations

    Methods:

    Internal methods:

    """

    def __init__(self, configFile):
        """
        Read configuration settings, load station data and set up
        output recarrays.

        :param str configFile: path to a configuration file.
        """

        config = ConfigParser()
        config.read(configFile)

        self.meta = False

        stnFile = config.get('Timeseries', 'LocationFile')
        self.outputPath = pjoin(config.get('Output', 'Path'),
                                'process', 'timeseries')

        self.maxfile = pjoin(config.get('Output', 'Path'),
                             'process', 'maxima.csv')
        self.minfile = pjoin(config.get('Output', 'Path'),
                             'process', 'minima.csv')

        log.info(f"Loading timeseries stations from {stnFile}")
        log.debug(f"Timeseries data will be written into {self.outputPath}")
        self.stations = []
        if stnFile.endswith("shp"):
            try:
                key_name = config.get('Timeseries', 'StationID')
            except NoOptionError:
                key_name = None

            vertices = shpGetVertices(stnFile, key_name=key_name)

            for stn in list(vertices.keys()):
                lat = vertices[stn][0][1]
                lon = vertices[stn][0][0]
                lon = np.where(lon < 0., lon + 360., lon)
                self.stations.append(Station(stn, lon, lat))

        else:
            stndata = flLoadFile(stnFile, delimiter=',')
            # If there are more than 3 columns, save the additional
            # columns as 'metadata'
            if stndata.shape[1] > 3:
                self.metadata = stndata[:, 3:]
                self.meta = True
            stnid = stndata[:, 0]
            stnlon = stndata[:, 1].astype(float)
            stnlat = stndata[:, 2].astype(float)
            for sid, lon, lat in zip(stnid, stnlon, stnlat):
                self.stations.append(Station(sid, lon, lat))
        log.info(f"There are {len(self.stations)} stations that will collect timeseries data")

    def sample(self, lon, lat, spd, uu, vv, prs, gridx, gridy):
        """
        Extract values from 2-dimensional grids at the given lat/lon.

        :param float lon: Longitude of the point to extract.
        :param float lat: Latitude of the point to extract.
        :param spd: :class:`numpy.ndarray` of speed values.
        :param uu: :class:`numpy.ndarray` of eastward wind speed values.
        :param vv: :class:`numpy.ndarray` of northward wind speed values.
        :param prs: :class:`numpy.ndarray` of pressure values.
        :param gridx: :class:`numpy.ndarray` of grid longitudes.
        :param gridy: :class:`numpy.ndarray` of grid latitudes.

        :return: speed, esatward and northward wind components, and pressure
                 values at the given location
        :rtype: tuple
        """
        xx = find_index(gridx, float(lon))
        yy = find_index(gridy, float(lat))
        ss = spd[yy, xx]
        ux = uu[yy, xx]
        vy = vv[yy, xx]
        bb = np.mod((180. / np.pi) * np.arctan2(-ux, -vy), 360.)
        pp = prs[yy, xx]

        return (ss, ux, vy, bb, pp)

    def extract(self, dt, spd, uu, vv, prs, gridx, gridy):
        """
        Extract data from the grid at the given locations.
        Data is stored in a dictionary, with keys as the station id's.

        :param float tstep: time step being evaluated, as a float (output
                            from matplotlib.num2date)
        :param spd: :class:`numpy.ndarray` of speed values.
        :param uu: :class:`numpy.ndarray` of eastward wind speed values.
        :param vv: :class:`numpy.ndarray` of northward wind speed values.
        :param prs: :class:`numpy.ndarray` of pressure values.
        :param gridx: :class:`numpy.ndarray` of grid longitudes.
        :param gridy: :class:`numpy.ndarray` of grid latitudes.

        """
        stns = 0
        for stn in self.stations:
            if stn.insideGrid(gridx, gridy):
                stns += 1
                result = self.sample(stn.lon, stn.lat, spd, uu, vv, prs,
                                     gridx, gridy)
                ss, ux, vy, bb, pp = result
                stn.data.append((str(stn.id), dt, stn.lon, stn.lat, ss,
                                 ux, vy, bb, pp))

            else:
                stn.data.append((str(stn.id), dt, stn.lon, stn.lat, 0.0, 0.0,
                                 0.0, 0.0, prs[0, 0]))
        log.debug("Extracted data for {0} stations".format(stns))

    def shutdown(self):
        """
        Write the data to file, each station to a separate file.
        """

        header = 'Station,Time,Longitude,Latitude,Speed,UU,VV,Bearing,Pressure'
        maxheader = ('Station,Time,Longitude,Latitude,Speed,'
                     'UU,VV,Bearing,Pressure')

        max_data = DynamicRecArray(dtype={'names': MINMAX_NAMES,
                                          'formats':MINMAX_TYPES})

        min_data = DynamicRecArray(dtype={'names': MINMAX_NAMES,
                                          'formats':MINMAX_TYPES})

        for stn in self.stations:

            if np.any(stn.data.data['Speed'] > 0.0):
                fname = pjoin(self.outputPath, 'ts.%s.csv' % str(stn.id))
                log.debug("Saving time series data to {0}".format(fname))
                with open(fname, 'wb') as fh:
                    np.savetxt(fh, np.array(stn.data.data), fmt=OUTPUT_FMT,
                               delimiter=',', header=header, comments='', encoding='ascii')

                max_step = np.argmax(stn.data.data['Speed'])
                min_step = np.argmin(stn.data.data['Pressure'])
                max_data.append(tuple(stn.data.data[max_step]))
                min_data.append(tuple(stn.data.data[min_step]))

        np.savetxt(self.maxfile, max_data.data, fmt=MINMAX_FMT, delimiter=',',
                   header=maxheader, comments='')
        np.savetxt(self.minfile, min_data.data, fmt=MINMAX_FMT, delimiter=',',
                   header=maxheader, comments='')
        """
        for stn in self.stations:
            if type(self.maxdata[stn.id][3]) == datetime.datetime:
                self.maxdata[stn.id][3] = self.maxdata[stn.id][3].strftime(ISO_FORMAT)
                self.mindata[stn.id][3] = self.mindata[stn.id][3].strftime(ISO_FORMAT)
                self.maxdata[stn.id][0] = str(int(stn.id))
                self.mindata[stn.id][0] = str(int(stn.id))
                maxdata.append(self.maxdata[stn.id])
                mindata.append(self.mindata[stn.id])

        for stn in self.stnid:
            if type(self.maxdata[stn][3]) == datetime.datetime:
                self.maxdata[stn][3] = self.maxdata[stn][3].strftime(ISO_FORMAT)
                self.mindata[stn][3] = self.mindata[stn][3].strftime(ISO_FORMAT)
                self.maxdata[stn][0] = str(int(stn))
                self.mindata[stn][0] = str(int(stn))
                maxdata.append(self.maxdata[stn])
                mindata.append(self.mindata[stn])
            else:
                pass

        np.savetxt(maxfname, np.array(maxdata), fmt='%s',
                   header=maxheader, delimiter=',')
                     #['%s','%7.3f','%7.3f','%s','%6.2f','%6.2f',
                     #  '%6.2f','%6.2f','%7.2f'] )
        minfname = pjoin(self.outputPath, 'minpressure.csv')

        np.savetxt(minfname, np.array(mindata), fmt='%s',
                   header=maxheader, delimiter=',')
                   #['%s','%7.3f','%7.3f','%s','%6.2f','%6.2f',
                   #  '%6.2f','%6.2f','%7.2f'] )
        """
        log.info("Station data written to file")


from pathlib import Path

import ape
import click
import structlog
from eth_utils import to_checksum_address

import beamer.artifacts
import beamer.util
from beamer.typing import URL, ChainId

log = structlog.get_logger(__name__)

def _get_contract_unique_name(contract_name: str, chain_id: ChainId) -> str:
    return f"{contract_name}-{chain_id}"

def _get_contract_info(artifacts_dir: Path) -> dict[ChainId, dict[str, dict[str, str]]]:
    contract_info: dict[ChainId, dict[str, dict[str, str]]] = {}
    for file_path in artifacts_dir.glob("*.deployment.json"):
        deployment = beamer.artifacts.Deployment.from_file(file_path)
        related_chain_id = (
            deployment.chain.chain_id if deployment.chain else deployment.base.chain_id
        )
        network = file_path.parent.stem
        chain_id = deployment.base.chain_id
        if chain_id not in contract_info:
            contract_info[chain_id] = {}
        for contract_name, contract in deployment.base.contracts.items():
            unique_contract_name = _get_contract_unique_name(contract_name, related_chain_id)
            contract_info[chain_id][unique_contract_name] = {
                "address": contract.address,
                "ecosystem": "ethereum",
                "network": network,
            }
        if deployment.chain is None:
            continue
        ecosystem_info = file_path.stem.split(".")[0]
        _, ecosystem = ecosystem_info.split("-", 1)
        chain_id = deployment.chain.chain_id
        contracts = deployment.chain.contracts
        if chain_id not in contract_info:
            contract_info[chain_id] = {}
        for contract_name, contract in contracts.items():
            unique_contract_name = _get_contract_unique_name(contract_name, chain_id)
            contract_info[chain_id][unique_contract_name] = {
                "address": contract.address,
                "ecosystem": ecosystem,
                "network": network,
            }

    return contract_info

def _verify_contract(
    unique_contract_name: str, contract_info: dict[str, str], rpc_url: URL, chain_id: ChainId
) -> None:
    try:
        ape_ecosystem = getattr(ape.networks, contract_info["ecosystem"])
        ape_network = getattr(ape_ecosystem, contract_info["network"])
        with ape_network.use_provider(rpc_url):
            etherscan = ape.networks.provider.network.explorer
            contract_name, _ = unique_contract_name.split("-")
            assert etherscan is not None
            getattr(ape.project, contract_name).at(contract_info["address"])
            log.info(
                "Verifying contract",
                contract=contract_name,
                chain_id=chain_id,
                address=contract_info["address"],
            )
            etherscan.publish_contract(to_checksum_address(contract_info["address"]))
    except Exception as err:
        log.error("Failed", err=err)

@click.command()
@click.argument("artifacts_dir", type=click.Path(file_okay=False, dir_okay=True, path_type=Path))
@click.argument("rpc_file", type=click.Path(file_okay=True, dir_okay=False, path_type=Path))
def main(artifacts_dir: Path, rpc_file: Path) -> None:
    contract_info = _get_contract_info(artifacts_dir)
    rpc_info = beamer.util.load_rpc_info(rpc_file)
    for chain_id, contracts in contract_info.items():
        rpc_url = rpc_info[chain_id]
        for contract_name, contract in contracts.items():
            _verify_contract(contract_name, contract, rpc_url, chain_id)

if __name__ == "__main__":
    main()


class Error(Exception):
    """Base class for exceptions in this module."""
    pass

class NoRoot(Error):
    """Exception raised for a tree with no root.

    Attributes:
        message -- explanation of the error
    """

    def __init__(self, message):
        self.message = message

class NoNodeFound(Error):
    """Exception raised for a tree without desired node

    Attributes:
        message -- explanation of the error
    """

    def __init__(self, message):
        self.message = message

class NoCost(Error):
    """Exception raised when trying to find cost of a tree with only a root

    Attributes:
        message -- explanation of the error
    """

    def __init__(self, message):
        self.message = message

class Node:

    def __init__(self, id, capacity = None, cost = None):
        self.children = None
        self.id = id
        self.capacity = capacity
        self.cost = cost

    def setID(self, id):
        self.id = id

    def setCapacity(self, capacity):
        self.id = capacity

    def setCost(self, cost):
        self.cost = cost

    def setChildren(self, children):
        self.children = children

    def getID(self):
        return self.id

    def getCapacity(self):
        return self.capacity

    def getCost(self):
        return self.cost

    def getChildren(self):
        return self.children

class Tree:

    def __init__(self):
        self.root = None

    def setRoot(self, id):
        self.root = Node(id)
        return True

    def insert(self, id_source, id_dest, capacity, cost):
        if (self.root == None):
            return self.setRoot(id_source)
        else:
            return self.insertNode(self.root, id_source, id_dest, capacity, cost)

    def insertNode(self, currentNode, id_source, id_dest, capacity, cost):
        if (currentNode.id == id_source):
            if (currentNode.getChildren() == None):
                children = []
                children.append(Node(id_dest, capacity, cost))
                currentNode.setChildren(children)
            else:
                children = currentNode.getChildren()
                children.append(Node(id_dest, capacity, cost))
                currentNode.setChildren(children)
            return True
        if (currentNode.getChildren() == None):
            return
        for child in currentNode.getChildren():
            success = self.insertNode(child, id_source, id_dest, capacity, cost)
            if (success):
                return success
        return False

    def get(self, id_source):
        if (self.root == None):
            raise NoRoot("Tree does not contain root.")
        try:
            return self.getNode(self.root, id_source)
        except NoNodeFound as fail:
            return fail.message

    def getNode(self, currentNode, id_source):
        if (currentNode.getID() == id_source):
            return currentNode
        if (currentNode.getChildren() == None):
            return
        for child in currentNode.getChildren():
            node = self.getNode(child, id_source)
            if (node):
                return node
        raise NoNodeFound("Tree does not contain desired node.")

    def calculate(self):
        if (self.root == None):
            raise NoRoot("Tree does not contain root.")
        try:
            startList = []
            parents = []
            return self.calculateCost(self.root, startList, 0, 1000, parents)
        except NoCost as fail:
            return fail.message

    # Traversal method to find the cost of paths and minimum capacity for every node from the root.
    # Returns list of nodes, costs, and capacities.

    def calculateCost(self, currentNode, costList, cost, minCapacity, parents): # will only find sum of costs of one path with leaf
        if (currentNode.getChildren() == None):
            if (currentNode.getID() == 1):
                raise NoCost("Root does not have cost.")
            newParents = list(parents)
            costList.append((currentNode.getID(), cost, minCapacity, newParents))
            return costList
        if (currentNode.getID() != 1):
            newParents = list(parents)
            costList.append((currentNode.getID(), cost, minCapacity, newParents))

        newParents = list(parents)
        newParents.append(currentNode.getID())
        parents = newParents

        for child in currentNode.getChildren():
            if (child.getCapacity() < minCapacity):
                minCapacity = child.getCapacity()
            costList = self.calculateCost(child, costList, cost + child.getCost(), minCapacity, parents)

        return costList

# tree = Tree()
# tree.setRoot(1)
# print(tree.insert(1, 2, 2, 5))
# print(tree.insert(1, 3, 2, 5))
# print(tree.insert(3, 4, 1, -2))
# node = tree.get(3)
# print(node)
# print(node.getID())
# node2 = node.getChildren()
# for n in node2:
#     print(n.getCapacity())
#     print(n.getCost())
# listCosts = tree.calculate()
# print(listCosts)

# tree = Tree()
# tree.setRoot(1)
# print(tree.insert(1, 3, 5, 5))
# print(tree.insert(1, 4, 2, -1))
# print(tree.insert(3, 2, 3, -2))
# print(tree.insert(3, 5, 2, -1))
# print(tree.insert(3, 6, 2, 2))
# print(tree.insert(4, 7, 2, 2))
# listCosts = tree.calculate()
# print(listCosts)


import mock
from oslotest import base as test_base
import six

from fuel_agent import errors
from fuel_agent.utils import hardware_utils as hu
from fuel_agent.utils import md_utils as mu
from fuel_agent.utils import utils

if six.PY2:
    OPEN_FUNCTION_NAME = '__builtin__.open'
else:
    OPEN_FUNCTION_NAME = 'builtins.open'

class TestMdUtils(test_base.BaseTestCase):

    @mock.patch.object(utils, 'execute')
    def test_mddisplay(self, mock_exec):
        # should read file /proc/mdstat
        # should get detailed description for all md devices
        # should return list of dicts representing md devices

        mock_open_data = """Personalities : [raid1]
md0 : active raid1 loop5[1] loop4[0]
      102272 blocks super 1.2 [2/2] [UU]

unused devices: <none>

        """
        mock_open = mock.mock_open(read_data=mock_open_data)
        patcher = mock.patch(OPEN_FUNCTION_NAME, new=mock_open)
        patcher.start()

        mock_exec.return_value = (
            """/dev/md0:
        Version : 1.2
  Creation Time : Wed Jun 18 18:44:57 2014
     Raid Level : raid1
     Array Size : 102272 (99.89 MiB 104.73 MB)
  Used Dev Size : 102272 (99.89 MiB 104.73 MB)
   Raid Devices : 2
  Total Devices : 2
    Persistence : Superblock is persistent

    Update Time : Wed Jun 18 18:45:01 2014
          State : clean
 Active Devices : 2
Working Devices : 2
 Failed Devices : 0
  Spare Devices : 0

           Name : localhost.localdomain:0  (local to host
localhost.localdomain)
           UUID : 12dd4cfc:6b2ac9db:94564538:a6ffee82
         Events : 17

    Number   Major   Minor   RaidDevice State
       0       7        4        0      active sync   /dev/loop4
       1       7        5        1      active sync   /dev/loop5""",
            ''
        )

        expected = [{
            'name': '/dev/md0',
            'Version': '1.2',
            'Raid Level': 'raid1',
            'Raid Devices': '2',
            'Active Devices': '2',
            'Spare Devices': '0',
            'Failed Devices': '0',
            'State': 'clean',
            'UUID': '12dd4cfc:6b2ac9db:94564538:a6ffee82',
            'devices': ['/dev/loop4', '/dev/loop5']
        }]

        mds = mu.mddisplay()
        mock_exec.assert_called_once_with(
            'mdadm', '--detail', '/dev/md0', check_exit_code=[0])

        key = lambda x: x['name']
        self.assertEqual(sorted(expected, key=key), sorted(mds, key=key))
        patcher.stop()

    @mock.patch.object(mu, 'mdclean')
    @mock.patch.object(hu, 'list_block_devices')
    @mock.patch.object(mu, 'mddisplay')
    @mock.patch.object(utils, 'execute')
    def test_mdcreate_ok(self, mock_exec, mock_mddisplay,
                         mock_bdevs, mock_mdclean):
        # should check if md already exists
        # should check if md level is valid
        # should check if all necessary devices exist
        # should check if all devices are not parts of some md
        # should clean md metadata which possibly are on all devices
        # should run mdadm command to create new md

        mock_mddisplay.return_value = \
            [{'name': '/dev/md10', 'devices': ['/dev/fake10']}]
        mock_bdevs.return_value = [{'device': '/dev/fake1'},
                                   {'device': '/dev/fake2'}]

        mu.mdcreate('/dev/md0', 'mirror', '/dev/fake1', '/dev/fake2')
        mock_exec.assert_called_once_with(
            'mdadm', '--force', '--create', '/dev/md0', '-e1.2',
            '--level=mirror',
            '--raid-devices=2', '/dev/fake1', '/dev/fake2',
            check_exit_code=[0])

    @mock.patch.object(mu, 'mddisplay')
    def test_mdcreate_duplicate(self, mock_mddisplay):
        # should check if md already exists
        # should raise error if it exists
        mock_mddisplay.return_value = [{'name': '/dev/md0'}]
        self.assertRaises(
            errors.MDAlreadyExistsError, mu.mdcreate,
            '/dev/md0', 'mirror', '/dev/fake')

    @mock.patch.object(mu, 'mddisplay')
    def test_mdcreate_unsupported_level(self, mock_mddisplay):
        # should check if md level is valid
        # should raise error if it is not
        mock_mddisplay.return_value = [{'name': '/dev/md10'}]
        self.assertRaises(
            errors.MDWrongSpecError, mu.mdcreate,
            '/dev/md0', 'badlevel', '/dev/fake')

    @mock.patch.object(hu, 'list_block_devices')
    @mock.patch.object(mu, 'mddisplay')
    def test_mdcreate_device_not_found(self, mock_mddisplay, mock_bdevs):
        # should check if all devices exist
        # should raise error if at least one device does not
        mock_mddisplay.return_value = [{'name': '/dev/md10'}]
        mock_bdevs.return_value = [{'device': '/dev/fake1'},
                                   {'device': '/dev/fake10'}]
        self.assertRaises(
            errors.MDNotFoundError, mu.mdcreate,
            '/dev/md0', 'mirror', '/dev/fake1', '/dev/fake2')

    @mock.patch.object(hu, 'list_block_devices')
    @mock.patch.object(mu, 'mddisplay')
    def test_mdcreate_device_attached(self, mock_mddisplay, mock_bdevs):
        # should check if all necessary devices are not attached to some md
        # should raise error if at least one device is attached
        mock_mddisplay.return_value = [{'name': '/dev/md10',
                                        'devices': ['/dev/fake2']}]
        mock_bdevs.return_value = [{'device': '/dev/fake1'},
                                   {'device': '/dev/fake2'}]
        self.assertRaises(
            errors.MDDeviceDuplicationError, mu.mdcreate,
            '/dev/md0', 'mirror', '/dev/fake1', '/dev/fake2')

    @mock.patch.object(utils, 'execute')
    @mock.patch.object(mu, 'mdclean')
    @mock.patch.object(hu, 'list_block_devices')
    @mock.patch.object(mu, 'mddisplay')
    def test_mdcreate_device_clean(self, mock_mddisplay,
                                   mock_bdevs, mock_mdclean, mock_exec):
        # should clean md metadata on all devices before building new md
        mock_mddisplay.return_value = []
        mock_bdevs.return_value = [{'device': '/dev/fake1'},
                                   {'device': '/dev/fake2'}]
        mu.mdcreate('/dev/md0', 'mirror', '/dev/fake1', '/dev/fake2')
        expected_calls = [mock.call('/dev/fake1'), mock.call('/dev/fake2')]
        self.assertEqual(mock_mdclean.call_args_list, expected_calls)

    @mock.patch.object(utils, 'execute')
    @mock.patch.object(mu, 'mddisplay')
    def test_mdremove_ok(self, mock_mddisplay, mock_exec):
        # should check if md exists
        # should run mdadm command to remove md device
        mock_mddisplay.return_value = [{'name': '/dev/md0'}]
        expected_calls = [
            mock.call('mdadm', '--stop', '/dev/md0', check_exit_code=[0]),
            mock.call('mdadm', '--remove', '/dev/md0', check_exit_code=[0, 1])
        ]
        mu.mdremove('/dev/md0')
        self.assertEqual(mock_exec.call_args_list, expected_calls)

    @mock.patch.object(mu, 'mddisplay')
    def test_mdremove_notfound(self, mock_mddisplay):
        # should check if md exists
        # should raise error if it does not
        mock_mddisplay.return_value = [{'name': '/dev/md0'}]
        self.assertRaises(
            errors.MDNotFoundError, mu.mdremove, '/dev/md1')

    @mock.patch.object(utils, 'execute')
    def test_mdclean(self, mock_exec):
        mu.mdclean('/dev/md0')
        mock_exec.assert_called_once_with('mdadm', '--zero-superblock',
                                          '--force', '/dev/md0',
                                          check_exit_code=[0])


"""
Memory stats
"""

import collections
import requests
import shellish

class Memory(shellish.Command):

    name = 'memory'

    def setup_args(self, parser):
        self.add_subcommand(Show, default=True)

class MemoryMixin(object):

    urn = '/api/v1/memory/'

class Show(MemoryMixin, shellish.Command):

    name = 'show'
    use_pager = True

    def setup_args(self, parser):
        self.add_argument('--type', choices=('mostcommon', 'growth'),
                          default='mostcommon')

    def run(self, args):
        report = requests.get(args.url + self.urn, params=dict(type=args.type))
        if not report.ok:
            print(report.json())
            return
        if args.type == 'growth':
            return self.show_growth(report.json())
        else:
            return self.show_mostcommon(report.json())

    def show_mostcommon(self, report):
        merged = collections.defaultdict(lambda: 0)
        for worker in report:
            for otype, count in worker:
                merged[otype] += count
        stats = sorted(merged.items(), key=lambda x: x[1], reverse=True)
        table = shellish.Table(headers=[
            'Type',
            'Count',
        ])
        table.print(stats)

    def show_growth(self, report):
        merged = collections.defaultdict(lambda: [0, 0])
        for worker in report:
            for otype, count, change in worker:
                merged[otype][0] += count
                merged[otype][1] += change
        stats = sorted(((k, *v) for k, v in merged.items()),
                        key=lambda x: x[2], reverse=True)
        table = shellish.Table(headers=[
            'Type',
            'Count',
            'Change',
        ])
        table.print(stats)


import os
import random
import datetime
import re
import math
import logging
from collections import OrderedDict
import multiprocessing
import numpy as np
import tensorflow as tf
import keras

from MaskRCNN import utils
from sklearn.metrics import matthews_corrcoef

# Requires TensorFlow 1.3+ and Keras 2.0.8+.
from distutils.version import LooseVersion
assert LooseVersion(tf.__version__) >= LooseVersion("1.3")
assert LooseVersion(keras.__version__) >= LooseVersion('2.0.8')

def get_box_center(boxes):
    boxes = np.squeeze(boxes, axis = 1)
    height = boxes[:, 2] - boxes[:, 0]
    width = boxes[:, 3] - boxes[:, 1]

    z_center = boxes[:, 0] + height // 2
    x_center = boxes[:, 1] + width // 2

    return z_center, x_center

def ccc(y_true, y_pred):
    cor=np.corrcoef(y_true,y_pred)[0][1]

    mean_true=np.mean(y_true)
    mean_pred=np.mean(y_pred)

    var_true=np.var(y_true)
    var_pred=np.var(y_pred)

    sd_true=np.std(y_true)
    sd_pred=np.std(y_pred)

    numerator=2*cor*sd_true*sd_pred

    denominator=var_true+var_pred+(mean_true-mean_pred)**2

    return numerator/denominator

def concordance_correlation_coefficient(gt_boxes, pred_centroids):
    gt_z_center, gt_x_center = get_box_center(gt_boxes)
    pred_z_center, pred_x_center = pred_centroids[:, 0], pred_centroids[:, 1]

    cor_z = ccc(gt_z_center, pred_z_center)
    cor_x = ccc(gt_x_center, pred_x_center)

    return cor_z, cor_x

def mad(gt_boxes, pred_centroids):
    gt_z_center, gt_x_center = get_box_center(gt_boxes)
    pred_z_center, pred_x_center = pred_centroids[:, 0], pred_centroids[:, 1]

    z_mad = np.mean(np.abs(gt_z_center - pred_z_center))
    z_std = np.std(np.abs(gt_z_center - pred_z_center))

    x_mad = np.mean(np.abs(gt_x_center - pred_x_center))
    x_std = np.std(np.abs(gt_x_center - pred_x_center))

    return z_mad, z_std, x_mad, x_std

def ad(gt_boxes, pred_boxes):
    gt_z_center, gt_x_center = get_box_center(gt_boxes)
    pred_z_center, pred_x_center = get_box_center(pred_boxes)

    x_ad = np.abs(gt_x_center - pred_x_center)
    z_ad = np.abs(gt_z_center - pred_z_center)

    return z_ad, x_ad