import numpy as np
import matplotlib.pyplot as plt
import os
from tqdm import tqdm
import torch
from torch.utils.data import Dataset, DataLoader
from transformers import SamModel, SamProcessor
from PIL import Image
from skimage import transform, io, segmentation
from segment_anything import sam_model_registry, SamPredictor
from segment_anything.utils.transforms import ResizeLongestSide
from torch.nn.utils.rnn import pad_sequence
from torch.nn import functional as F
import re
from utils import *
from experiment_setup import*

# set seeds
torch.manual_seed(231)
np.random.seed(231)

join = os.path.join

sam_checkpoint = "models/sam_vit_b_01ec64.pth"
model_type = "vit_b"
device = "cuda"

sam = sam_model_registry[model_type](checkpoint=sam_checkpoint)
resize_transform = ResizeLongestSide(sam.image_encoder.img_size)
resize_transform = ResizeLongestSide(sam.image_encoder.img_size)

def create_npz_dataset(data):
    data_path = f"dataset/{data}"
    img_names = os.listdir(f"{data_path}/images")
    resize_transform = ResizeLongestSide(sam.image_encoder.img_size)
    for i, img_name in enumerate(img_names):
        print(f"Processing image ... {i}")
        # Since images are in grayscale, all three channels have the same value
        img = io.imread(f"{data_path}/images/{img_name}") # shape (img_width, img_height, 3)
        label = io.imread(f"{data_path}/labels/{img_name}") # shape (img_width, img_height, 1)

        processed_img = prepare_image(img, resize_transform, sam)
        original_size = img.shape[:2]
        with torch.no_grad():
            img_embeddings = sam.image_encoder(preprocess(processed_img.unsqueeze(dim=0)))

        img_num = int(re.findall(r'\d+', img_name)[0])

        np.savez(f'dataset/npz_base/{data}/{img_name}.npz',
                image=processed_img.cpu(),
                label=label,
                original_size=original_size,
                img_embeddings=img_embeddings.cpu(),
                img_num=img_num)

        # if i == 210: break

# create a dataset class to load npz data and return back image embeddings and ground truth
class NpzDataset(Dataset):
    def __init__(self, data_root, exp_config):
        self.data_root = data_root
        self.npz_files = sorted(os.listdir(self.data_root))
        self.npz_data = [np.load(join(self.data_root, f)) for f in self.npz_files]
        self.bbox_size = exp_config.get('bbox_size', None)
        self.num_pts = exp_config.get('num_pts', None)

        # max_length = max(len(d['label']) for d in self.npz_data)
        # # Pad all arrays with zeros using NumPy
        # padded_labels = [np.pad(d['label'], (0, max_length - len(d['label'])), 'constant') for d in self.npz_data]

        self.labels = [data['label'] for data in self.npz_data]
        self.images = [data['image'] for data in self.npz_data]
        self.original_sizes = [data['original_size'] for data in self.npz_data]
        self.embeddings = [data['img_embeddings'] for data in self.npz_data]
        self.img_nums = [data['img_num'] for data in self.npz_data]
        print(f"loaded {len(self.images)} images from {data_root}")

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

    def __getitem__(self, index):
        image = self.images[index]
        label = self.labels[index]

        # bboxes = torch.tensor(np.array([get_bbox_from_mask(label, self.bbox_size)]))
        original_size = self.original_sizes[index]
        img_embeddings = self.embeddings[index]
        img_num = self.img_nums[index]

        img_info = {
            'image': image,
            # 'point_coords': resize_transform.apply_coords_torch(torch.tensor(point_coords), original_size),
            # 'original_coords': point_coords,
            'original_size': original_size,
            # 'point_labels': torch.tensor(point_labels),
            # 'boxes': resize_transform.apply_boxes_torch(torch.tensor(np.array([bbox])), original_size),
            'img_embeddings': img_embeddings,
            'img_num': img_num
            }

        if self.bbox_size is not None:
            bbox = get_bbox_from_mask(label, self.bbox_size)
            img_info['boxes'] = resize_transform.apply_boxes_torch(torch.tensor(np.array([bbox])), original_size)

        # fg_point_coords, fg_point_labels = get_random_fg(label, self.num_pts)
        # bg_point_coords, bg_point_labels = get_random_bg(label, bbox, 1)
        # point_coords = np.concatenate((fg_point_coords, bg_point_coords))
        # point_labels = np.concatenate((fg_point_labels, bg_point_labels))
        if self.num_pts:
            point_coords, point_labels = get_random_fg(label, self.num_pts)
            img_info['point_coords'] = resize_transform.apply_coords_torch(torch.tensor(point_coords), original_size)
            img_info['original_coords'] = point_coords
            img_info['point_labels'] = torch.tensor(point_labels)

        # return {
        #  'image': image,
        #  'point_coords': resize_transform.apply_coords_torch(torch.tensor(point_coords), original_size),
        #  'original_coords': point_coords,
        #  'original_size': original_size,
        #  'point_labels': torch.tensor(point_labels),
        #  'boxes': resize_transform.apply_boxes_torch(torch.tensor(np.array([bbox])), original_size),
        #  'img_embeddings': img_embeddings,

        #  'img_num': img_num # Apparently dataloader doesn't like strings
        # }
        return img_info

    # def collate_fn(self, data):

    #     # image = self.images[index]
    #     # label = self.labels[index]
    #     # bboxes = torch.tensor(np.array([get_bbox_from_mask(label)]))
    #     # original_size = self.original_sizes[index]

    #     # return {
    #     #  'image': image,
    #     # #  'boxes': resize_transform.apply_boxes_torch(bboxes, original_size),
    #     #  'original_size': original_size
    #     # }

    #     images = [torch.tensor(d['image']) for d in data] #(3)
    #     labels = [d['label'] for d in data]
    #     original_sizes = [d['original_size'] for d in data]

    #     images = pad_sequence(images, batch_first=True) #(4)
    #     # labels = torch.tensor(labels) #(5)

    #     return { #(6)
    #         'image': images,
    #         'boxes': torch.tensor(np.array([get_bbox_from_mask(label)])),
    #         'original_size': original_size
    #         # 'label': labels
    #     }

def prepare_image(image, transform, device):
    image = transform.apply_image(image)
    image = torch.as_tensor(image, device=device.device)
    return image.permute(2, 0, 1).contiguous()

def preprocess(x: torch.Tensor) -> torch.Tensor:
    """Normalize pixel values and pad to a square input."""
    # Normalize colors
    x = (x - sam.pixel_mean) / sam.pixel_std

    # Pad
    h, w = x.shape[-2:]
    padh = sam.image_encoder.img_size - h
    padw = sam.image_encoder.img_size - w
    x = F.pad(x, (0, padw, 0, padh))
    return x

# if __name__ == "__main__":

    # create_npz_dataset('malignant')
    # create_npz_dataset('benign')


import scrapy
from scrapy import Spider
from crawler.items import BookItem
import json
import glob, os

class BooksOfflineSpider(Spider):
    name = "books_offline"

    def start_requests(self):
        self.logger.info("Start crawling ............")
        absoluteDir = os.getcwd()

        # Change current dir to html/
        os.chdir("./crawler/html")
        urls = []
        for file in glob.glob("*.html"):
            urls.append("file://" + absoluteDir + "/crawler/html/" + file)
        # Delete old contents of json files
        open("data.json", "w").close()
        open("data.csv", "w").close()

        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):

        books = response.xpath('//ul[@id="products_grid"]/li')
        genre = response.xpath('//link[@rel="canonical"]/@href').get()

        if genre:
            genre.split("/")[-1].replace(".html", "")

        if len(books) < 1:
            self.logger.info("--------------------html empty ")

        for book in books:

            item = BookItem()

            item["genre"] = genre
            item["title"] = book.xpath('//h2[has-class("p-name-list")]/a/@title').get()

            item["author"] = ""
            current_price = book.xpath('//p[@class="special-price"]/span/text()').extract_first()
            old_price = book.xpath('//p[has-class("old-price")]/span[@class="price"]/text()').extract_first()
            item["imgURL"] = book.xpath('//span[@class="product-image"]/img/@data-src').get()

            if current_price:
                item["price"] = current_price.split("\xa0")[0]
            else:
                item["price"] = 0

            if old_price:
                item["old_price"] = old_price.split("\xa0")[0]
            else:
                item["old_price"] = 0

            filename = f"data.json"
            with open(filename, "r+", encoding="utf-8") as file:
                try:
                    data = json.load(file)
                except:
                    data = {"books": []}

                data["books"].append(
                    {
                        "genre": item["genre"],
                        "title": item["title"],
                        "author": item["author"],
                        "price": item["price"],
                        "old_price": item["old_price"],
                        "imgURL": item["imgURL"],
                    }
                )
                file.seek(0)
                json.dump(data, file, ensure_ascii=False)

            yield item


"""
*Problem:
    Znaleźć w tablicy index równowagi j - suma elementów po lewej stronie j jest równa sumie po prawej stronie j.
*Rozwiązanie:
    Obliczamy sumę wszystkich elementów zadanej tablicy.
    Iterujac po kolejnych wartościach w tablicy. Sprawdzamy czy nie zachodzi warunek:
    2*(suma dotychczas napotkanych elementów) = suma - (aktualna wartość)
    jeśli zachodzi to i jest indexem równowagi.
*Złożoności:
    !Obliczeniowa: O(n)
    !Pamięciowa: O(1)
https://www.techiedelight.com/find-equilibrium-index-array/
"""

def findIndexes(A):
    s = 0
    for i in A:
        s += i

    left = 0
    for i in range(len(A)):
        if 2*(left) == s - A[i]:
            print(i)
        left += A[i]

A = [0, -3, 5, -4, -2, 3, 1, 0]
findIndexes(A)


import sys
from collections import deque
input = sys.stdin.readline

VERTICAL, HORIZONTAL = True, False
dr = (-1, 1, 0, 0)
dc = (0, 0, -1, 1)

N = int(input())

board = []
start_point = []
end_point = []
visited = set()
for i in range(N):
    board.append(list(input().rstrip()))
    for j in range(N):
        if board[i][j] == 'B':
            start_point.append((i, j))
            board[i][j] = '0'
        elif board[i][j] == 'E':
            end_point.append((i, j))
            board[i][j] = '0'

# U, D, L, R 방법으로 움직이는 게 가능한지 검사
def check(row, col, direction):
    if direction == VERTICAL:
        if not (1 <= row < N - 1):
            return False
        if board[row - 1][col] == '0' and board[row][col] == '0' and board[row + 1][col] == '0':
            return True
        else:
            return False
    else:
        if not (1 <= col < N - 1):
            return False
        if board[row][col - 1] == '0' and board[row][col] == '0' and board[row][col + 1] == '0':
            return True
        else:
            return False

# T 방법으로 움직이는 게 가능한지 검사
def turn_check(row, col):
    if not (1 <= row < N - 1) or not (1 <= col < N - 1):
        return False
    for i in range(row - 1, row + 2):
        for j in range(col - 1, col + 2):
            if board[i][j] != '0':
                return False
    return True

def bfs():
    q = deque()
    # q에 (row, col, direction, cnt) 형태로 넣음
    q.append((start[0], start[1], start[2], 0))
    # (row, col, direction) 형태를 set에 넣어서 visited 관리
    visited.add((start[0], start[1], start[2]))
    while q:
        row, col, direction, cnt = q.popleft()
        # 최종 위치에 도달하면 return
        if row == end[0] and col == end[1] and direction == end[2]:
            return cnt

        # U, D, L, R 방법으로 움직이는 경우
        for d in range(4):
            mv_r, mv_c = row + dr[d], col + dc[d]
            if not (0 <= mv_r < N) or not (0 <= mv_c < N):
                continue
            if (mv_r, mv_c, direction) in visited:
                continue

            if check(mv_r, mv_c, direction):
                visited.add((mv_r, mv_c, direction))
                q.append((mv_r, mv_c, direction, cnt + 1))

        # T 방법으로 움직이는 경우
        if (row, col, not direction) in visited:
            continue

        if turn_check(row, col):
            visited.add((row, col, not direction))
            q.append((row, col, not direction, cnt + 1))

    return 0

# 최종 위치의 방향을 구함 ( VERTICAL, HORIZONTAL )
if all(end_point[0][0] == num[0] for num in end_point):
    end = (end_point[1][0], end_point[1][1], HORIZONTAL)
else:
    end = (end_point[1][0], end_point[1][1], VERTICAL)

# 시작 위치의 방향을 구함 ( VERTICAL, HORIZONTAL )
if all(start_point[0][0] == num[0] for num in start_point):
    start = (start_point[1][0], start_point[1][1], HORIZONTAL)
else:
    start = (start_point[1][0], start_point[1][1], VERTICAL)

print(bfs())


class Stop:
    def __init__(self, code) -> None:
        self.code = code

    def get_code(self):
        return self.code

class Route:
    def __init__(self, route_name, stops) -> None:
        self.route_name = route_name
        self.stops = stops

    def details(self):
        details = ""
        details += ("route name:" + self.route_name + " ")
        details += "route stops:"
        for id in self.stops:
            details += (self.stops[id].code + " ")

        return details

class Line:
    def __init__(self, id, routes) -> None:
        self.id = str(id)
        self.routes = routes

    def details(self):
        details = ""
        details += "Line id:" + str(self.id) + "\n"
        for id in self.routes:
            details += self.routes[id].details() + "\n"
        return details

class TimeSchedule:
    def __init__(self, first_arrival_time) -> None:
        self.first_arrival_time = first_arrival_time

    def details(self):
        return self.first_arrival_time

class Bus:
    def __init__(self, id, line=None, time_schedule=None) -> None:
        self.id = str(id)
        self.line = line
        self.time_schedule = time_schedule

    def assign_bus(self, line, time_schedule):
        self.line = line
        self.time_schedule = time_schedule

    def details(self):
        details = ""
        details += "bus id:" + str(self.id) + "\n"
        details += "line:" + self.line.details()
        details += "time schedule:" + str(self.time_schedule.details())
        return details

class Bussystem:
    def __init__(self, buses=None, lines=None, routes=None, stops=None) -> None:
        self.buses = {} if buses == None else buses
        self.lines = {} if lines == None else lines
        self.routes = {} if routes == None else routes
        self.stops = {} if stops == None else stops

    def add_buses(self, buses):
        for bus_id in buses:
            if buses[bus_id].id not in self.buses:
                self.buses[buses[bus_id].id] = buses[bus_id]

    def remove_buses(self, buses):
        for bus_id in buses:
            if int(buses[bus_id].id) in self.buses:
                del self.buses[int(buses[bus_id].id)]

    def define_stop(self, code):
        stop = Stop(code)
        return stop

    def add_stops(self, stop_codes):
        stops = {}
        for code in stop_codes:
            if code not in self.stops:
                stop = self.define_stop(code)
                stops[code] = stop
                self.stops[code] = stop
            else:
                stops[code] = self.stops[code]
                print("stop " + str(code) + " already exist")
        return stops

    def get_stops(self, stop_codes):
        stops = {}
        for stop_code in stop_codes:
            if stop_code in self.stops:
                stops[stop_code] = self.stops[stop_code]
        return stops

    def define_route(self, route_name, stops):
        route = Route(route_name, stops)
        return route

    def add_route(self, route_name, stops):
        route = self.define_route(route_name, stops)
        if route.route_name not in self.routes:
            self.routes[route.route_name] = route
        else:
            print("route " + route.route_name + " already exist")
        return self.routes[route.route_name]

    def define_line(self, line_id, routes):
        line = Line(line_id, routes)
        return line

    def add_line(self, line_id, routes):
        line = self.define_line(line_id, routes)
        if line.id not in self.lines:
            self.lines[line.id] = line
        else:
            print("line " + line.id + " already exist")
        return self.lines[line.id]

    def define_bus(self, bus_id):
        return Bus(bus_id)

    def define_add_bus(self, bus_id):
        if bus_id not in self.buses:
            bus = self.define_bus(bus_id)
            self.buses[bus_id] = bus
        else:
            print("bus " + bus_id + " already exist")
        return self.buses[bus_id]

    def assign_bus(self, bus, line, time):
        bus.assign_bus(line, time)

    def details(self):
        details = ""
        details += "Bus:"
        for id in self.buses:
            details += self.buses[id].id + " "
        details += "\n"

        details += "Line:"
        for id in self.lines:
            details += str(self.lines[id].id) + " "
        details += "\n"

        details += "Route:"
        for id in self.routes:
            details += self.routes[id].route_name + " "
        details += "\n"

        details += "Stop:"
        for id in self.stops:
            details += str(self.stops[id].code) + " "
        details += "\n"
        details += "\n"

        details += "Bus details:\n"
        for id in self.buses:
            details += "bus " + self.buses[id].id + ": Line" + self.buses[id].line.id + \
                " " + self.buses[id].time_schedule.first_arrival_time + "\n"
        details += "\n"

        details += "Line details:\n"
        for id in self.lines:
            details += "Line" + str(self.lines[id].id) + ": "
            for route_id in self.lines[id].routes:
                details += "" + \
                    self.lines[id].routes[route_id].route_name + " "
            details += "\n"
        details += "\n"

        details += "Route details:\n"
        for id in self.routes:
            details += self.routes[id].route_name + ": "
            for stop_id in self.routes[id].stops:
                details += "stop" + \
                    str(self.routes[id].stops[stop_id].code) + " "
            details += "\n"
        return details

def main():
    bussystem = Bussystem()
    stop_codes1 = [1, 2, 3, 4, 5]
    stops1_1 = bussystem.add_stops(stop_codes1)
    route1_1 = bussystem.add_route("route1_1", stops1_1)
    stops1_2 = bussystem.get_stops([5, 4, 3, 2, 1])
    route1_2 = bussystem.add_route("route1_2", stops1_2)
    routes1 = {route1_1.route_name: route1_1, route1_2.route_name: route1_2}
    line1 = bussystem.add_line(1, routes1)
    timeSchedule1 = TimeSchedule("10:00")
    bus1 = bussystem.define_add_bus(1)
    bussystem.assign_bus(bus1, line1, timeSchedule1)

    stop_codes2 = [6,7,8,9,10]
    stops2_1 = bussystem.add_stops(stop_codes2)
    route2_1 = bussystem.add_route("route2_1", stops2_1)
    stops2_2 = bussystem.get_stops([10,9,8,7,6])
    route2_2 = bussystem.add_route("route2_2", stops2_2)
    routes2 = {route2_1.route_name: route2_1, route2_2.route_name: route2_2}
    line2 = bussystem.add_line(2, routes2)
    timeSchedule2 = TimeSchedule("13:00")
    bus2 = bussystem.define_add_bus(2)
    bussystem.assign_bus(bus2, line2, timeSchedule2)

    stop_codes3 = [11, 12, 13, 14, 15]
    stops3_1 = bussystem.add_stops(stop_codes3)
    route3_1 = bussystem.add_route("route3_1", stops3_1)
    stops3_2 = bussystem.get_stops([15,14,13,12])
    route3_2 = bussystem.add_route("route3_2", stops3_2)
    routes3 = {route3_1.route_name: route3_1, route3_2.route_name: route3_2}
    line3 = bussystem.add_line(3, routes3)
    timeSchedule3 = TimeSchedule("15:00")
    bus3 = bussystem.define_add_bus(3)
    bussystem.assign_bus(bus3, line3, timeSchedule3)

    stop_codes4 = [21, 22, 23, 24, 25]
    stops4_1 = bussystem.add_stops(stop_codes4)
    route4_1 = bussystem.add_route("route4_1", stops4_1)
    stops4_2 = bussystem.get_stops([25,14,22,12])
    route4_2 = bussystem.add_route("route4_2", stops4_2)
    routes4 = {route4_1.route_name: route4_1, route4_2.route_name: route4_2}
    line4 = bussystem.add_line(4, routes4)
    timeSchedule4 = TimeSchedule("11:00")
    bus4 = bussystem.define_add_bus(4)
    bussystem.assign_bus(bus4, line4, timeSchedule4)

    print("*******************")
    print("add 4 buses\n")
    print(bussystem.details())
    buses_to_removed = {bus2.id:bus2,bus3.id:bus3,bus4.id:bus4}

    print("*******************")
    print("remove bus 2 3 and 4\n")
    bussystem.remove_buses(buses_to_removed)
    print(bussystem.details())

    print("*******************")
    print("add bus 2 and 4 again\n")
    buses_to_add = {bus2.id:bus2,bus4.id:bus4}
    bussystem.add_buses(buses_to_add)
    print(bussystem.details())

    print("*******************")
    print("assign bus 2 with line 3 and time schedule 3\n")
    bussystem.assign_bus(bus2, line3, timeSchedule3)
    print(bussystem.details())

    print("*******************")
    print("add stops, stop 2 and stop 4 are alreay in it\n")
    stop_codes5 = [31, 2, 33, 4, 35]
    stops5_1 = bussystem.add_stops(stop_codes5)
    route5_1 = bussystem.add_route("route5_1", stops5_1)
    stops5_2 = bussystem.get_stops([35, 4, 33, 2, 31])
    route5_2 = bussystem.add_route("route5_2", stops5_2)
    stops5_3 = bussystem.get_stops([31, 2, 33, 4])
    route5_3 = bussystem.add_route("route5_3", stops5_3)
    routes5 = {route5_1.route_name: route5_1, route5_2.route_name: route5_2, route5_3.route_name: route5_3}
    line5 = bussystem.add_line(5, routes5)
    timeSchedule5 = TimeSchedule("12:00")
    bus5 = bussystem.define_add_bus(5)
    bussystem.assign_bus(bus5, line5, timeSchedule5)

    print(bussystem.details())

if __name__ == "__main__":
    main()


from nltk.tokenize import sent_tokenize

def lines(a, b):
    """Return lines in both a and b"""

    list_a = a.split("\n")
    list_b = b.split("\n")

    return list_compare(list_a, list_b)

def sentences(a, b):
    """Return sentences in both a and b"""

    list_a = sent_tokenize(a)
    list_b = sent_tokenize(b)

    return list_compare(list_a, list_b)

def substrings(a, b, n):
    """Return substrings of length n in both a and b"""

    list_a = get_substrings(a, n)
    list_b = get_substrings(b, n)

    return list_compare(list_a, list_b)

def get_substrings(list, length):

    output = []

    temp = len(list) - length + 1

    for i in range(temp):
        output.append(list[i:length + i])

    return output

def list_compare(a, b):

    output = []

    for i in a:
        for j in b:
            if i == j and j not in output:
                output.append(j)

    return output


from pyecharts.charts import Bar
from pyecharts import options as opts
import pandas as pd

main_file_location = 'Target1.csv'

#--------------------access dataset and clear unuse data-----------------------------#
data1 = pd.read_csv(main_file_location)
# replace NaN value with 'Unspecified' in the last six columns and give it to 'data1_clearNaN'
data1_clearNaN = data1[['Critic_Score','Critic_Count','User_Score','User_Count','Developer','Rating']].fillna('Unspecified')
# Use data1_clearNaN to mearge the original data's last six columns,so the new data will only have NaN value in 'Year_of_Release' column:
data1[['Critic_Score','Critic_Count','User_Score','User_Count','Developer','Rating']] = data1_clearNaN
# drop rows that don't have a specific year.
data1 = data1.dropna(axis=0)
# after dropping NaN values, I can change this column's type to int:
data1['Year_of_Release'] = data1['Year_of_Release'].astype('int')
# drop data belongs to year 2020 and year 2017
# because there are only 4 games in these two year in this dataset,and also the aim is before year 2016.
list1 = list(data1['Year_of_Release'].unique())
list1.remove(2020)
list1.remove(2017)
data1 = data1[data1['Year_of_Release'].isin(list1)]
#------------------------------end clearing-------------------------------------#

v1 = data1[['Year_of_Release','NA_Sales','EU_Sales','JP_Sales','Other_Sales','Global_Sales',]].groupby('Year_of_Release').sum().sort_values(by='Year_of_Release',ascending=False)
v1 = v1.reset_index().rename(columns = {'Year_of_Release':'Year'})

Year_list=list(v1['Year'])
NA_list=list(v1['NA_Sales'])
EU_list=list(v1['EU_Sales'])
JP_list=list(v1['JP_Sales'])
Other_list=list(v1['Other_Sales'])
Global_list=list(v1['Global_Sales'])

def two_decimal(x):
    for i in range(len(x)):
        a = x[i]
        a = round(a,2)
        x[i] = a
    return x

two_decimal(NA_list)
two_decimal(EU_list)
two_decimal(JP_list)
two_decimal(Other_list)
two_decimal(Global_list)

bar1 = (
       Bar()
       .add_xaxis(Year_list)
       .add_yaxis('NA Sales',NA_list,stack='stack1')
       .add_yaxis('EU Sales',EU_list,stack='stack1')
       .add_yaxis('JP Sales',JP_list,stack='stack1')
       .add_yaxis('Other Sales',Other_list,stack='stack1')
       .set_global_opts(
               title_opts=opts.TitleOpts(
                       title="Each Year's Total Sales in Areas(millions of units)",
                       pos_left='center'
                       ),
               datazoom_opts=opts.DataZoomOpts(),
               legend_opts=opts.LegendOpts(
                       pos_right = 100,
                       pos_top = 70,
                       orient = 'vertical'
                       ),
               )
       .set_series_opts(
               label_opts=opts.LabelOpts(
                       is_show=False,
                       )
               )
       .render("Each Year's Total Sales in Areas.html")
       )

bar2 = (
        Bar()
        .add_xaxis(Year_list)
        .add_yaxis('Global Sales',Global_list,category_gap='35%')
        .set_global_opts(
               title_opts=opts.TitleOpts(
                       title="Total global sales per year(millions of units)",
                       pos_left='center'
                       ),
               legend_opts=opts.LegendOpts(
                       pos_right = 100,
                       pos_top = 70,
                       orient = 'vertical'
                       ),
               datazoom_opts=opts.DataZoomOpts(),
               )
        .render("Total global sales per year.html")
        )


from __future__ import print_function

from rv import commands as rvc
from rv import extra_commands as rve
from rv import rvtypes as rvt

import rv.runtime

import os
import sys
import re

def deb(s):
    if False:
        print("latlong: " + s + "\n", file=sys.stderr)

deb("loading module")

def colorPipeGroups():
    return rve.nodesInEvalPath(rvc.frame(), "RVColorPipelineGroup")

def groupHasViewer(group):
    return len(rve.nodesInGroupOfType(group, "LatLongViewer")) != 0

def viewerOfGroup(group):
    nodes = rve.nodesInGroupOfType(group, "LatLongViewer")
    node = None
    if len(nodes) != 0:
        node = nodes[0]
    return node

class LatLongViewerMode(rvt.MinorMode):
    def modeToggled(self, event):
        deb("local mode toggled: %s" % event.contents())
        event.reject()

        parts = event.contents().split("|")
        if len(parts) != 2 or parts[0] != "sync" or parts[1] != "true":
            return

        self._syncActivated = True
        deb("sync on!")

    def render(self, event):
        if self._syncActivated:
            deb("Adding regex to sync")
            self._syncActivated = False
            code = """
            {
                rvtypes.State s = commands.data();
                sync.RemoteSync mode = s.sync;
                mode.addSendPattern (regex("#LatLongViewer\\..*"));
            }"""
            rv.runtime.eval(code, ["sync", "rvtypes", "commands"])

    def readPrefs(self):

        self.adjustAllowed = bool(
            rvc.readSettings("lat_long_viewer", "adjustAllowed", True)
        )

    def writePrefs(self):

        rvc.writeSettings("lat_long_viewer", "adjustAllowed", self.adjustAllowed)

    def addViewer(self, event):

        for pg in colorPipeGroups():

            deb("addViewer: checking g %s hasViewer %s" % (pg, str(groupHasViewer(pg))))

            if not groupHasViewer(pg):
                nodes = rvc.getStringProperty(pg + ".pipeline.nodes")
                nodes = ["LatLongViewer"] + nodes
                rvc.setStringProperty(pg + ".pipeline.nodes", nodes, True)

            vw = viewerOfGroup(pg)

            deb("new Viewer node: %s" % vw)

            rvc.setIntProperty(vw + ".node.active", [1], True)

            """
            if (self._swapEyes) :
                rvc.setIntProperty(vw + ".parameters.swapEyes", [ 1 ], True)
            else :
                rvc.setIntProperty(vw + ".parameters.swapEyes", [ 0 ], True)
            """

    def removeDisNode(self, event):

        for pg in linPipeGroups():

            deb(
                "removeDisNode: checking g %s hasSD %s"
                % (pg, str(groupHasStereoDis(pg)))
            )

            if groupHasStereoDis(pg):
                nodes = rvc.getStringProperty(pg + ".pipeline.nodes")
                newNodes = []
                for n in nodes:
                    if n != "StereoDisassembly":
                        newNodes.append(n)
                rvc.setStringProperty(pg + ".pipeline.nodes", newNodes, True)

    def toggleTopBotPref(self, event):

        self._expectTopBot = not self._expectTopBot
        self.writePrefs()

    def toggleSwapEyesPref(self, event):

        self._swapEyes = not self._swapEyes
        self.writePrefs()

    def disabledMenuState(self):

        return rvc.DisabledMenuState

    def uncheckedMenuState(self):

        return rvc.UncheckedMenuState

    def haveDisNodesState(self):

        for pg in linPipeGroups():
            if groupHasStereoDis(pg):
                return rvc.UncheckedMenuState

        return rvc.DisabledMenuState

    def expectTopBotState(self):

        if self._expectTopBot:
            return rvc.CheckedMenuState

        return rvc.UncheckedMenuState

    def swapEyesState(self):

        if self._swapEyes:
            return rvc.CheckedMenuState

        return rvc.UncheckedMenuState

    def addTopLevel(self, event):
        newViewer = rvc.newNode("LatLongViewer", "LatLong Viewer")
        rvc.setNodeInputs(newViewer, [rvc.viewNode()])
        rvc.setViewNode(newViewer)

    def toggleViewers(self, event):
        viewers = rve.nodesInEvalPath(rvc.frame(), "LatLongViewer")

        if len(viewers) == 0:
            return

        active = 0
        for v in viewers:
            if rvc.getIntProperty(v + ".node.active")[0] != 1:
                active = 1

        for v in viewers:
            rvc.setIntProperty(v + ".node.active", [active], True)

    def adjustFocalLength(self, event):
        rv.runtime.eval(
            'rvui.startParameterMode("#LatLongViewer.parameters.focalLength", 100.0, 7.0, 1.0)(nil);',
            [],
        )
        pass

    def toggleAdjust(self, event):

        self.adjustAllowed = not self.adjustAllowed
        self.writePrefs()

    def pointerPush(self, event):
        deb("pointerPush")
        deb("pointer %s" % str(event.pointer()))

        # leave the event for the pixel inspector
        if not self.adjustAllowed:
            event.reject()
            return

        viewers = rve.nodesInEvalPath(rvc.frame(), "LatLongViewer")
        if len(viewers) == 0:
            return

        p = event.pointer()
        self.downPointX = p[0]
        self.downPointY = p[1]

        self.downRotateX = rvc.getFloatProperty(viewers[0] + ".parameters.rotateX")[0]
        self.downRotateY = rvc.getFloatProperty(viewers[0] + ".parameters.rotateY")[0]

    def pointerDrag(self, event):
        deb("pointerDrag")
        deb("pointer %s" % str(event.pointer()))

        # leave the event for the pixel inspector
        if not self.adjustAllowed:
            event.reject()
            return

        viewers = rve.nodesInEvalPath(rvc.frame(), "LatLongViewer")
        if len(viewers) == 0:
            return

        p = event.pointer()
        dx = p[0] - self.downPointX
        dy = p[1] - self.downPointY

        domain = event.domain()
        dx = dx / domain[0]
        dy = dy / domain[1]
        deb("dx %s dy %s" % (str(dx), str(dy)))

        rvc.setFloatProperty(
            "#LatLongViewer.parameters.rotateX", [self.downRotateX + -dy * 180.0], True
        )
        rvc.setFloatProperty(
            "#LatLongViewer.parameters.rotateY", [self.downRotateY + dx * 360.0], True
        )

    def missingState(self):

        for pg in colorPipeGroups():

            deb("checking g %s hasViewer %s" % (pg, str(groupHasViewer(pg))))

            if not groupHasViewer(pg):
                return rvc.UncheckedMenuState

        return rvc.DisabledMenuState

    def haveSourcesState(self):
        if len(rvc.sources()) > 0:
            return rvc.UncheckedMenuState
        else:
            return rvc.DisabledMenuState

    def haveInactiveViewerState(self):
        viewers = rve.nodesInEvalPath(rvc.frame(), "LatLongViewer")

        if len(viewers) == 0:
            return rvc.DisabledMenuState

        for v in viewers:
            if rvc.getIntProperty(v + ".node.active")[0] != 1:
                return rvc.UncheckedMenuState

        return rvc.CheckedMenuState

    def haveViewerState(self):
        viewers = rve.nodesInEvalPath(rvc.frame(), "LatLongViewer")

        if len(viewers) == 0:
            return rvc.DisabledMenuState

        return rvc.UncheckedMenuState

    def adjustAllowedState(self):
        if self.adjustAllowed:
            return rvc.CheckedMenuState

        return rvc.UncheckedMenuState

    def __init__(self):

        deb("__init__")
        rvt.MinorMode.__init__(self)

        self.adjustAllowed = True

        self.readPrefs()

        self.downPointX = 0.0
        self.downPointY = 0.0
        self.downRotateX = 0.0
        self.downRotateY = 0.0

        self.init(
            "lat_long_viewer_mode",
            [
                ("mode-toggled", self.modeToggled, ""),
                (
                    "stylus-pen--shift--push",
                    self.pointerPush,
                    "Start LatLong View Adjust",
                ),
                ("stylus-pen--shift--drag", self.pointerDrag, "LatLong View Adjust"),
                (
                    "pointer-1--shift--push",
                    self.pointerPush,
                    "Start LatLong View Adjust",
                ),
                ("pointer-1--shift--drag", self.pointerDrag, "LatLong View Adjust"),
            ],
            None,
            [
                (
                    "Image",
                    [
                        ("_", None, None, None),
                        ("Lat-Long Viewer", None, None, self.disabledMenuState),
                        ("    Add To Source", self.addViewer, None, self.missingState),
                        (
                            "    Add As Top-Level View",
                            self.addTopLevel,
                            None,
                            self.haveSourcesState,
                        ),
                        (
                            "    Enabled",
                            self.toggleViewers,
                            None,
                            self.haveInactiveViewerState,
                        ),
                        (
                            "    Adjust Focal Length",
                            self.adjustFocalLength,
                            None,
                            self.haveViewerState,
                        ),
                        (
                            "    Adjust View with Shift-Drag",
                            self.toggleAdjust,
                            None,
                            self.adjustAllowedState,
                        ),
                    ],
                )
            ],
        )

        deb("__init__ done")
        self._syncActivated = False

def createMode():

    return LatLongViewerMode()


# Time Complexity: O(n)
def powerN(x,y):
    res = 1
    for i in range(y):
        res *= x

    return res

# print(powerN(2,5))
# print(powerN(8,0))

# Log n soution

def powerR(x,y):
    if y == 0:
        return 1
    temp = powerR(x,y//2)
    temp = temp * temp
    if y % 2 == 0:
        return temp
    else:
        return temp * x

#print(powerR(3,5))

# Iterative Power (Binary Exponentiation)
# Time Complexity - O(log n)
# Space Complexity - O(n)

def power(x,y):
    res = 1
    while y > 0:
        if y % 2 != 0: # can be written as y & 1
            res = res * x
        x = x * x
        y = y // 2 # shift operator can also be used

    return res

print(power(4,5))
'''
Express y as binary and multiply with power of x when bit is one
'''


from typing import Any, Literal, Tuple, Union

import numpy as np
import torch
from scipy.special import softmax
from transformers import CamembertTokenizer

class ThaiSentimentAnalysis:

    """
    A class to handle the Thai sentiment analysis model.

    Attributes
    ----------
    tokenizer : transformers.CamembertTokenizer
        The tokenizer of the model.
    model : torch.nn.Module
        The thai sentiment analysis model in evaluate mode.
    id2label : dict
        The mapping from the label id to the label name.

    Methods
    -------
    infer(text:str)->Tuple[Union[Literal['negative', 'neutral', 'positive'] ,None, Any]]
        Infer the sentiment of the given text.
    """

    def __init__(self) -> None:
        """Load the tokenizer and model. and seting up the defination of the infer result."""
        self.tokenizer = CamembertTokenizer.from_pretrained(
            './nlp/thai_tokenizer')
        self.model:torch.nn.Module = torch.jit.load('./nlp/model_thai_sentiment.pt')
        self.id2label = {
        0: "negative",
        1: "neutral",
        2: "positive"
        }

    def infer(self, text:str)->Tuple[Union[Literal['negative', 'neutral', 'positive'] ,None, Any]]:
        """Infer the sentiment of the given text."""
        encoded_input = self.tokenizer(text, return_tensors='pt')
        output = self.model(**encoded_input)
        scores = output[0][0].detach().numpy()
        scores = softmax(scores)

        scores = scores[:-1]
        scores = scores[::-1]
        sentiment = self.id2label[np.argmax(scores)]

        return sentiment, scores[np.argmax(scores)]


import argparse

import os
import torch

import numpy as np
import skimage
import skimage.measure
import skimage.io
import shapely.geometry
import shapely.ops
from PIL import Image
from multiprocess import Pool
from tqdm import tqdm

from functools import partial

from lydorn_utils import print_utils, geo_utils

from frame_field_learning import polygonize_utils, plot_utils

DEBUG = False

def debug_print(s: str):
    if DEBUG:
        print_utils.print_debug(s)

def get_args():
    argparser = argparse.ArgumentParser(description=__doc__)
    argparser.add_argument(
        '--seg_filepath',
        required=True,
        nargs='*',
        type=str,
        help='Filepath(s) to input segmentation/mask image.')
    argparser.add_argument(
        '--im_dirpath',
        required=True,
        type=str,
        help='Path to the directory containing the corresponding images os the segmentation/mask. '
             'Files must have the same filename as --seg_filepath.'
             'Used for vizualization or saving the shapefile with the same coordinate system as that image.')
    argparser.add_argument(
        '--out_dirpath',
        required=True,
        type=str,
        help='Path to the output directory.')
    argparser.add_argument(
        '--out_ext',
        type=str,
        default="shp",
        choices=['pdf', 'shp'],
        help="File extension of the output. "
             "'pdf': pdf visualization (requires --im_dirpath for the image),  'shp': shapefile")
    argparser.add_argument(
        '--bbox',
        nargs='*',
        type=int,
        help='Selects area in bbox for computation.')

    args = argparser.parse_args()
    return args

def simplify(polygons, probs, tolerance):
    if type(tolerance) == list:
        out_polygons_dict = {}
        out_probs_dict = {}
        for tol in tolerance:
            out_polygons, out_probs = simplify(polygons, probs, tol)
            out_polygons_dict["tol_{}".format(tol)] = out_polygons
            out_probs_dict["tol_{}".format(tol)] = out_probs
        return out_polygons_dict, out_probs_dict
    else:
        out_polygons = [polygon.simplify(tolerance, preserve_topology=True) for polygon in polygons]
        return out_polygons, probs

def shapely_postprocess(out_contours, np_indicator, config):
    height = np_indicator.shape[0]
    width = np_indicator.shape[1]

    # Handle holes:
    line_string_list = [shapely.geometry.LineString(out_contour[:, ::-1]) for out_contour in out_contours]

    # Add image boundary line_strings for border polygons
    line_string_list.append(
        shapely.geometry.LinearRing([
            (0, 0),
            (0, height - 1),
            (width - 1, height - 1),
            (width - 1, 0),
        ]))

    # Merge polylines (for border polygons):
    multi_line_string = shapely.ops.unary_union(line_string_list)

    # Find polygons:
    polygons, dangles, cuts, invalids = shapely.ops.polygonize_full(multi_line_string)

    polygons = list(polygons)

    # Remove small polygons
    polygons = [polygon for polygon in polygons if
                config["min_area"] < polygon.area]

    # Remove low prob polygons
    filtered_polygons = []
    filtered_polygon_probs = []
    for polygon in polygons:
        prob = polygonize_utils.compute_geom_prob(polygon, np_indicator)
        # print("simple:", np_indicator.min(), np_indicator.mean(), np_indicator.max(), prob)
        if config["seg_threshold"] < prob:
            filtered_polygons.append(polygon)
            filtered_polygon_probs.append(prob)

    polygons, probs = simplify(filtered_polygons, filtered_polygon_probs, config["tolerance"])

    return polygons, probs

def polygonize(seg_batch, config, pool=None, pre_computed=None):
    # tic_total = time.time()

    assert len(seg_batch.shape) == 4 and seg_batch.shape[
        1] <= 3, "seg_batch should be (N, C, H, W) with C <= 3, not {}".format(seg_batch.shape)

    # Indicator
    # tic = time.time()
    indicator_batch = seg_batch[:, 0, :, :]
    np_indicator_batch = indicator_batch.cpu().numpy()
    # toc = time.time()
    # debug_print(f"Indicator to cpu: {toc - tic}s")

    if pre_computed is None or "init_contours_batch" not in pre_computed:
        # tic = time.time()
        init_contours_batch = polygonize_utils.compute_init_contours_batch(np_indicator_batch, config["data_level"], pool=pool)
        # toc = time.time()
        # debug_print(f"Init contours: {toc - tic}s")
    else:
        init_contours_batch = pre_computed["init_contours_batch"]

    # tic = time.time()
    # Convert contours to shapely polygons to handle holes:
    if pool is not None:
        shapely_postprocess_partial = partial(shapely_postprocess, config=config)
        polygons_probs_batch = pool.starmap(shapely_postprocess_partial, zip(init_contours_batch, np_indicator_batch))
        polygons_batch, probs_batch = zip(*polygons_probs_batch)
    else:
        polygons_batch = []
        probs_batch = []
        for i, out_contours in enumerate(init_contours_batch):
            polygons, probs = shapely_postprocess(out_contours, np_indicator_batch[i], config)
            polygons_batch.append(polygons)
            probs_batch.append(probs)

    # toc = time.time()
    # debug_print(f"Shapely post-process: {toc - tic}s")

    # toc_total = time.time()
    # debug_print(f"Total: {toc_total - tic_total}s")

    return polygons_batch, probs_batch

def run_one(seg_filepath, out_dirpath, config, im_dirpath, out_ext=None, bbox=None):
    filename = os.path.basename(seg_filepath)
    name = os.path.splitext(filename)[0]

    # Load image
    image = None
    im_filepath = os.path.join(im_dirpath, name + ".tif")
    if out_ext == "pdf":
        image = skimage.io.imread(im_filepath)

    # seg = skimage.io.imread(seg_filepath) / 255
    seg_img = Image.open(seg_filepath)
    seg = np.array(seg_img)
    if seg.dtype == np.uint8:
        seg = seg / 255
    elif seg.dtype == np.bool:
        seg = seg.astype(np.float)

    # Select bbox for dev
    if bbox is not None:
        assert len(bbox) == 4, "bbox should have 4 values"
        # bbox = [1440, 210, 1800, 650]  # vienna12
        # bbox = [2808, 2393, 3124, 2772]  # innsbruck19
        if image is not None:
            image = image[bbox[0]:bbox[2], bbox[1]:bbox[3]]
        seg = seg[bbox[0]:bbox[2], bbox[1]:bbox[3]]
        extra_name = ".bbox_{}_{}_{}_{}".format(*bbox)
    else:
        extra_name = ""

    # Convert to torch and add batch dim
    if len(seg.shape) < 3:
        seg = seg[:, :, None]
    seg_batch = torch.tensor(np.transpose(seg[:, :, :2], (2, 0, 1)), dtype=torch.float)[None, ...]

    out_contours_batch, out_probs_batch = polygonize(seg_batch, config)

    polygons = out_contours_batch[0]

    if out_ext == "shp":
        out_filepath = os.path.join(out_dirpath, name + ".shp")
        geo_utils.save_shapefile_from_shapely_polygons(polygons, im_filepath, out_filepath)
    elif out_ext == "pdf":
        base_filepath = os.path.splitext(seg_filepath)[0]
        filepath = base_filepath + extra_name + ".poly_simple.pdf"
        # plot_utils.save_poly_viz(image, polygons, filepath, linewidths=1, draw_vertices=True, color_choices=[[0, 1, 0, 1]])
        plot_utils.save_poly_viz(image, polygons, filepath, markersize=30, linewidths=1, draw_vertices=True)
    else:
        raise ValueError(f"out_ext should be shp or pdf, not {out_ext}")

def main():
    config = {
        "data_level": 0.5,
        "tolerance": 1.0,
        "seg_threshold": 0.5,
        "min_area": 10
    }
    # --- Process args --- #
    args = get_args()

    pool = Pool()
    list(tqdm(pool.imap(partial(run_one, out_dirpath=args.out_dirpath, config=config, im_dirpath=args.im_dirpath, out_ext=args.out_ext, bbox=args.bbox), args.seg_filepath), desc="Simple poly.", total=len(args.seg_filepath)))

if __name__ == '__main__':
    main()


def str_set(string):
    if len(string) == 9 and "0" not in string:
        return len(set(string))
    else:
        return 0

pan_nums = []
for i in range(1,2000):
    for j in range(1,2000):
        k = i*j
        all_nums = str(i) + str(j) + str(k)
        if str_set(all_nums) == 9:
            pan_nums.append(k)

pan_num = list(set(pan_nums))

print(sum(pan_num))


from uuid import uuid4

from django.core.exceptions import ValidationError
from django.core.validators import int_list_validator
from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _

from django_ledger.models import CreateUpdateMixIn
from django_ledger.models.utils import LazyLoader

lazy_loader = LazyLoader()

class BankAccountModelManager(models.Manager):

    def for_entity(self, entity_slug: str, user_model):
        qs = self.get_queryset()
        return qs.filter(
            Q(ledger__entity__slug__exact=entity_slug) &
            (
                    Q(ledger__entity__admin=user_model) |
                    Q(ledger__entity__managers__in=[user_model])
            )
        )

class BackAccountModelAbstract(CreateUpdateMixIn):
    REL_NAME_PREFIX = 'bank'
    ACCOUNT_TYPES = [
        ('checking', _('Checking')),
        ('savings', _('Savings')),
        ('money_mkt', _('Money Market')),
    ]

    uuid = models.UUIDField(default=uuid4, editable=False, primary_key=True)
    name = models.CharField(max_length=150, null=True, blank=True)
    account_number = models.CharField(max_length=30, null=True, blank=True,
                                      validators=[
                                          int_list_validator(sep='', message=_('Only digits allowed'))
                                      ])
    routing_number = models.CharField(max_length=30, null=True, blank=True,
                                      validators=[
                                          int_list_validator(sep='', message=_('Only digits allowed'))
                                      ])
    aba_number = models.CharField(max_length=30, null=True, blank=True)
    account_type = models.CharField(choices=ACCOUNT_TYPES, max_length=10)
    cash_account = models.ForeignKey('django_ledger.AccountModel',
                                     on_delete=models.CASCADE,
                                     verbose_name=_('Cash Account'),
                                     related_name=f'{REL_NAME_PREFIX}_cash_account',
                                     null=True, blank=True)
    ledger = models.OneToOneField('django_ledger.LedgerModel',
                                  editable=False,
                                  verbose_name=_('Ledger'),
                                  on_delete=models.CASCADE)
    active = models.BooleanField(default=True)
    hidden = models.BooleanField(default=False)
    objects = BankAccountModelManager()

    def configure(self,
                  entity_slug,
                  user_model,
                  posted_ledger: bool = True):
        EntityModel = lazy_loader.get_entity_model()
        if isinstance(entity_slug, str):
            entity_model = EntityModel.objects.for_user(
                user_model=user_model).get(
                slug__exact=entity_slug)
        elif isinstance(entity_slug, EntityModel):
            entity_model = entity_slug
        else:
            raise ValidationError('entity_slug must be an instance of str or EntityModel')

        LedgerModel = lazy_loader.get_ledger_model()
        acc_number = self.account_number
        ledger_model = LedgerModel.objects.create(
            entity=entity_model,
            posted=posted_ledger,
            # pylint: disable=unsubscriptable-object
            name=f'Bank Account {"***" + acc_number[-4:]}'
        )
        ledger_model.clean()
        self.ledger = ledger_model
        return self

    class Meta:
        abstract = True
        verbose_name = _('Bank Account')
        indexes = [
            models.Index(fields=['ledger']),
            models.Index(fields=['account_type']),
            models.Index(fields=['cash_account', 'account_type'])
        ]
        unique_together = [
            ('cash_account', 'account_number', 'routing_number')
        ]

    # pylint: disable=invalid-str-returned
    def __str__(self):
        # pylint: disable=bad-option-value
        return self.name

class BankAccountModel(BackAccountModelAbstract):
    """
    Base Bank Account Model
    """


# coding: utf-8

# In[4]:

import numpy as np

# In[3]:

# Sharp ratio is calculated backwards i.e. in a reverse chronological order

def SharpR(CLOSE, Avg_Prd):

    SR = np.zeros(CLOSE.shape[0])
    Return = np.zeros(CLOSE.shape[0])
    STD = np.zeros(CLOSE.shape[0])

    Last  =  CLOSE.shape[0] - Avg_Prd + 1
    for ii in range(0, Last):
        ii_reverse = CLOSE.shape[0] - ii

        CLOSE_norm = CLOSE[ii_reverse-Avg_Prd : ii_reverse] / CLOSE[ii_reverse-Avg_Prd]
        Return_Daily    = np.diff(CLOSE_norm) *100
        Return[ii_reverse - 1] = np.mean(Return_Daily) * (252**0.5)
        STD[ii_reverse - 1]   = np.std (Return_Daily)

        SR[ii_reverse - 1] = (Return[ii_reverse - 1]/STD[ii_reverse - 1])

    return Return, STD, SR


from __future__ import annotations

from dataclasses import dataclass
import logging
from typing import Any, Dict, Generic, Iterable, Iterator, List, Optional, Set, TypeVar
from urllib.parse import urlparse

import attr
import requests
from tenacity.before_sleep import before_sleep_log

from swh.core.config import load_from_envvar
from swh.core.github.utils import GitHubSession
from swh.core.utils import grouper
from swh.scheduler import get_scheduler, model
from swh.scheduler.interface import SchedulerInterface

from . import USER_AGENT_TEMPLATE
from .utils import http_retry, is_valid_origin_url

logger = logging.getLogger(__name__)

@dataclass
class ListerStats:
    pages: int = 0
    origins: int = 0

    def __add__(self, other: ListerStats) -> ListerStats:
        return self.__class__(self.pages + other.pages, self.origins + other.origins)

    def __iadd__(self, other: ListerStats):
        self.pages += other.pages
        self.origins += other.origins

    def dict(self) -> Dict[str, int]:
        return {"pages": self.pages, "origins": self.origins}

StateType = TypeVar("StateType")
PageType = TypeVar("PageType")

BackendStateType = Dict[str, Any]
CredentialsType = Optional[Dict[str, Dict[str, List[Dict[str, str]]]]]

class Lister(Generic[StateType, PageType]):
    """The base class for a Software Heritage lister.

    A lister scrapes a page by page list of origins from an upstream (a forge, the API
    of a package manager, ...), and massages the results of that scrape into a list of
    origins that are recorded by the scheduler backend.

    The main loop of the lister, :meth:`run`, basically revolves around the
    :meth:`get_pages` iterator, which sets up the lister state, then yields the scrape
    results page by page. The :meth:`get_origins_from_page` method converts the pages
    into a list of :class:`model.ListedOrigin`, sent to the scheduler at every page. The
    :meth:`commit_page` method can be used to update the lister state after a page of
    origins has been recorded in the scheduler backend.

    The :func:`finalize` method is called at lister teardown (whether the run has
    been successful or not) to update the local :attr:`state` object before it's sent to
    the database. This method must set the :attr:`updated` attribute if an updated
    state needs to be sent to the scheduler backend. This method can call
    :func:`get_state_from_scheduler` to refresh and merge the lister state from the
    scheduler before it's finalized (and potentially minimize the risk of race
    conditions between concurrent runs of the lister).

    The state of the lister is serialized and deserialized from the dict stored in the
    scheduler backend, using the :meth:`state_from_dict` and :meth:`state_to_dict`
    methods.

    Args:
      scheduler: the instance of the Scheduler being used to register the
        origins listed by this lister
      url: a URL representing this lister, e.g. the API's base URL
      instance: the instance name, to uniquely identify this lister instance,
        if not provided the URL network location will be used
      credentials: dictionary of credentials for all listers. The first level
        identifies the :attr:`LISTER_NAME`, the second level the lister
        :attr:`instance`. The final level is a list of dicts containing the
        expected credentials for the given instance of that lister.
      max_pages: the maximum number of pages listed in a full listing operation
      max_origins_per_page: the maximum number of origins processed per page
      enable_origins: whether the created origins should be enabled or not

    Generic types:
      - *StateType*: concrete lister type; should usually be a :class:`dataclass` for
        stricter typing
      - *PageType*: type of scrape results; can usually be a :class:`requests.Response`,
        or a :class:`dict`

    """

    LISTER_NAME: str = ""
    github_session: Optional[GitHubSession] = None

    def __init__(
        self,
        scheduler: SchedulerInterface,
        url: str,
        instance: Optional[str] = None,
        credentials: CredentialsType = None,
        max_origins_per_page: Optional[int] = None,
        max_pages: Optional[int] = None,
        enable_origins: bool = True,
        with_github_session: bool = False,
    ):
        if not self.LISTER_NAME:
            raise ValueError("Must set the LISTER_NAME attribute on Lister classes")

        self.url = url
        if instance is not None:
            self.instance = instance
        else:
            self.instance = urlparse(url).netloc

        self.scheduler = scheduler

        if not credentials:
            credentials = {}
        self.credentials = list(
            credentials.get(self.LISTER_NAME, {}).get(self.instance, [])
        )

        # store the initial state of the lister
        self.state = self.get_state_from_scheduler()
        self.updated = False

        self.session = requests.Session()
        # Declare the USER_AGENT is more sysadm-friendly for the forge we list
        self.session.headers.update(
            {"User-Agent": USER_AGENT_TEMPLATE % self.LISTER_NAME}
        )
        self.github_session: Optional[GitHubSession] = (
            GitHubSession(
                credentials=credentials.get("github", {}).get("github", []),
                user_agent=str(self.session.headers["User-Agent"]),
            )
            if with_github_session
            else None
        )

        self.recorded_origins: Set[str] = set()
        self.max_pages = max_pages
        self.max_origins_per_page = max_origins_per_page
        self.enable_origins = enable_origins

    @http_retry(before_sleep=before_sleep_log(logger, logging.WARNING))
    def http_request(self, url: str, method="GET", **kwargs) -> requests.Response:

        logger.debug("Fetching URL %s with params %s", url, kwargs.get("params"))

        response = self.session.request(method, url, **kwargs)
        if response.status_code not in (200, 304):
            logger.warning(
                "Unexpected HTTP status code %s on %s: %s",
                response.status_code,
                response.url,
                response.content,
            )
        response.raise_for_status()

        return response

    def run(self) -> ListerStats:
        """Run the lister.

        Returns:
          A counter with the number of pages and origins seen for this run
          of the lister.

        """
        full_stats = ListerStats()
        self.recorded_origins = set()

        try:
            for page in self.get_pages():
                full_stats.pages += 1
                origins = list(self.get_origins_from_page(page))
                if (
                    self.max_origins_per_page
                    and len(origins) > self.max_origins_per_page
                ):
                    logger.info(
                        "Max origins per page set, truncated %s page results down to %s",
                        len(origins),
                        self.max_origins_per_page,
                    )
                    origins = origins[: self.max_origins_per_page]
                if not self.enable_origins:
                    logger.info(
                        "Disabling origins before sending them to the scheduler"
                    )
                    origins = [attr.evolve(origin, enabled=False) for origin in origins]
                sent_origins = self.send_origins(origins)
                self.recorded_origins.update(sent_origins)
                full_stats.origins = len(self.recorded_origins)
                self.commit_page(page)

                if self.max_pages and full_stats.pages >= self.max_pages:
                    logger.info("Reached page limit of %s, terminating", self.max_pages)
                    break
        finally:
            self.finalize()
            if self.updated:
                self.set_state_in_scheduler()

        return full_stats

    def get_state_from_scheduler(self) -> StateType:
        """Update the state in the current instance from the state in the scheduler backend.

        This updates :attr:`lister_obj`, and returns its (deserialized) current state,
        to allow for comparison with the local state.

        Returns:
          the state retrieved from the scheduler backend
        """
        self.lister_obj = self.scheduler.get_or_create_lister(
            name=self.LISTER_NAME, instance_name=self.instance
        )
        return self.state_from_dict(self.lister_obj.current_state)

    def set_state_in_scheduler(self) -> None:
        """Update the state in the scheduler backend from the state of the current
        instance.

        Raises:
          swh.scheduler.exc.StaleData: in case of a race condition between
            concurrent listers (from :meth:`swh.scheduler.Scheduler.update_lister`).
        """
        self.lister_obj.current_state = self.state_to_dict(self.state)
        self.lister_obj = self.scheduler.update_lister(self.lister_obj)

    # State management to/from the scheduler

    def state_from_dict(self, d: BackendStateType) -> StateType:
        """Convert the state stored in the scheduler backend (as a dict),
        to the concrete StateType for this lister."""
        raise NotImplementedError

    def state_to_dict(self, state: StateType) -> BackendStateType:
        """Convert the StateType for this lister to its serialization as dict for
        storage in the scheduler.

        Values must be JSON-compatible as that's what the backend database expects.
        """
        raise NotImplementedError

    def finalize(self) -> None:
        """Custom hook to finalize the lister state before returning from the main loop.

        This method must set :attr:`updated` if the lister has done some work.

        If relevant, this method can use :meth`get_state_from_scheduler` to merge the
        current lister state with the one from the scheduler backend, reducing the risk
        of race conditions if we're running concurrent listings.

        This method is called in a `finally` block, which means it will also run when
        the lister fails.

        """
        pass

    # Actual listing logic

    def get_pages(self) -> Iterator[PageType]:
        """Retrieve a list of pages of listed results. This is the main loop of the lister.

        Returns:
          an iterator of raw pages fetched from the platform currently being listed.
        """
        raise NotImplementedError

    def get_origins_from_page(self, page: PageType) -> Iterator[model.ListedOrigin]:
        """Extract a list of :class:`model.ListedOrigin` from a raw page of results.

        Args:
          page: a single page of results
        Returns:
          an iterator for the origins present on the given page of results
        """
        raise NotImplementedError

    def commit_page(self, page: PageType) -> None:
        """Custom hook called after the current page has been committed in the scheduler
        backend.

        This method can be used to update the state after a page of origins has been
        successfully recorded in the scheduler backend. If the new state should be
        recorded at the point the lister completes, the :attr:`updated` attribute must
        be set.

        """
        pass

    def send_origins(self, origins: Iterable[model.ListedOrigin]) -> List[str]:
        """Record a list of :class:`model.ListedOrigin` in the scheduler.

        Returns:
          the list of origin URLs recorded in scheduler database
        """
        valid_origins = []
        for origin in origins:
            if is_valid_origin_url(origin.url):
                valid_origins.append(origin)
            else:
                logger.warning("Skipping invalid origin: %s", origin.url)

        recorded_origins = []
        for batch_origins in grouper(valid_origins, n=1000):
            ret = self.scheduler.record_listed_origins(batch_origins)
            recorded_origins += [origin.url for origin in ret]

        return recorded_origins

    @classmethod
    def from_config(cls, scheduler: Dict[str, Any], **config: Any):
        """Instantiate a lister from a configuration dict.

        This is basically a backwards-compatibility shim for the CLI.

        Args:
          scheduler: instantiation config for the scheduler
          config: the configuration dict for the lister, with the following keys:
            - credentials (optional): credentials list for the scheduler
            - any other kwargs passed to the lister.

        Returns:
          the instantiated lister
        """
        # Drop the legacy config keys which aren't used for this generation of listers.
        for legacy_key in ("storage", "lister", "celery"):
            config.pop(legacy_key, None)

        # Instantiate the scheduler
        scheduler_instance = get_scheduler(**scheduler)

        return cls(scheduler=scheduler_instance, **config)

    @classmethod
    def from_configfile(cls, **kwargs: Any):
        """Instantiate a lister from the configuration loaded from the
        SWH_CONFIG_FILENAME envvar, with potential extra keyword arguments
        if their value is not None.

        Args:
            kwargs: kwargs passed to the lister instantiation
        """
        config = dict(load_from_envvar())
        config.update({k: v for k, v in kwargs.items() if v is not None})
        return cls.from_config(**config)

class StatelessLister(Lister[None, PageType], Generic[PageType]):
    def state_from_dict(self, d: BackendStateType) -> None:
        """Always return empty state"""
        return None

    def state_to_dict(self, state: None) -> BackendStateType:
        """Always set empty state"""
        return {}


from flask import Flask, render_template, request
from prometheus_flask_exporter import PrometheusMetrics
from jaeger_client import Config

app = Flask(__name__)

metrics = PrometheusMetrics(app)

metrics.info("frontend_app_info", "Frontend App Info", version="1.0.3")

metrics.register_default(
    metrics.counter(
        'by_path_counter', 'Request count by paths',
        labels={'path': lambda: request.path}
    )
)

by_endpoint_counter = metrics.counter(
    'by_endpoint_counter', 'Request count by endpoint',
    labels={'endpoint': lambda: request.endpoint}
)

config = Config(
    config={
        'sampler': {
            'type': 'const',
            'param': 1,
        },
        'logging': True,
    },
    service_name='frontend'
)

tracer= config.initialize_tracer()

@app.route("/")
@by_endpoint_counter
def homepage():
    with tracer.start_span('html'):
        return render_template("main.html")

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


import struct
import  threading
import time

from PyQt4 import QtCore

from Client.Model import Header

class ThreadServerConn(threading.Thread, QtCore.QThread):

    def __init__(self, id, addr,parent):
        super(ThreadServerConn, self)
        super().__init__()
        threading.Thread.__init__(self)
        self.parent = parent
        self.queue = list()
        self.addr = addr
        self.id = id
        self.file = list()
        self.deamon = True
        self.outstack= list()
        self.lenfile  = 0
        self.end = False
        self.header = Header.Header(0, 0, 0, 0, 0, None)

    def run(self):
        tempo = time.perf_counter()
        while True:
            if len(self.queue) > 0:
                data, addr = self.queue.pop()
                header = self.dump(data)

                if header[4] == 4:

                    self.handShake(header,addr)
                    self.lenfile = header[5].decode('utf-8')
                    break

            if tempo + 10 <= time.perf_counter():
                del self.parent.threads[self.id-1]
                raise ConnectionError("TIME OUT")

        tempo = time.perf_counter()
        while True:

            if len(self.queue) > 0:
                data, addr = self.queue.pop()
                header = self.dump(data)
                if header[4] == 1:
                    self.closeConn(addr)
                    break
                tempo = time.perf_counter()
                if len(header) == 6:

                    self.write(header[5])
                    self.header.setAckNum(header[0]+len(header[5]))
                    self.header.setSeqNum(header[1])

                    Theader = self.makeHeader(self.header.getSeqNum(),
                                             self.header.getAckNum(),
                                             self.id,
                                             0,
                                             None,
                                             True,
                                             False,
                                             False)

                    self.parent.server.socket.sendto(Theader, addr)
                    self.parent.signal(str(self.id), str(header[0] - 12346), str(self.lenfile))

            if tempo + 10 <= time.perf_counter():
                self.write("ERRO".encode(),True)
                self.parent.signal(str(self.id),str(-1),str(self.lenfile))
                self.closeConn(addr,True)
                raise ConnectionError("TIME OUT")

    def setHeader(self, header):
        self.header.setSeqNum(header[0])
        self.header.setAckNum(header[1])
        self.header.setNotUse(header[3])
        self.header.setFlags(header[4])

        if len(header) == 6:
            self.header.setData(header[5])

    def handShake(self,data,addr):
        self.setHeader(data)
        header = self.makeHeader(4321,
                                 12346,
                                 self.id,
                                 0,
                                 None,
                                 True,
                                 True,
                                 False)

        self.parent.server.socket.sendto(header, addr)

    def closeConn(self,addr,error = False):
        if not error:
            header = self.makeHeader(self.header.getSeqNum(),
                                 self.header.getAckNum(),
                                 self.id,
                                 0,
                                 None,
                                 True,
                                 False,
                                 True)
            self.parent.server.socket.sendto(header,addr)

        with open(str(self.id)+".file","wb")as file:
            for x in self.file:
                file.write(x)
        self.parent.threads.remove(self)

    def makeHeader(self, seqNum, ackNum, id, notUse, payload=None, a=False, s=False, f=False):
        flags = (f | (a << 1) | (s << 2))
        if payload:
            return struct.pack('@I I H b B ' + str(len(payload)) + 's', seqNum, ackNum, id, notUse, flags, payload)

        return struct.pack('@I I H b B ', seqNum, ackNum, id, notUse, flags)

    def dump(self, data):
        if len(data)-12 > 0:
            return struct.unpack('@I I H b B '+str(len(data)-12)+'s', data)
        else:
            return struct.unpack('@I I H b B ', data)

    def write(self, data,error= False):
        if error:
             self.file.clear()
             self.file.append("ERROR".encode())

        else:
            if data not in self.file:
                self.file.append(data)
            else:
                self.file = self.file[0:self.file.index(data)+1]

    def placeData(self,data):
        self.queue.append(data)


import calendar
import datetime as dt
from pathlib import Path
from zipfile import ZipFile

import numpy as np

from src import functionsProspecAPI as prospec
from src.arrFiles import main as prep_files

def prep_n_run():
    name, path = model_params() # Recebe nome do modelo e caminho para os arquivos

    idServer = prospec.getIdOfServer("c5.24xlarge") # define o servidor que vai ser usado
    idQueue = prospec.getIdOfFirstQueueOfServer("c5.24xlarge") # define a fila que será usada

    display_studies() # mostra os arquivos criados desde então registrado no arquivo "estudos criados"

    studyId = int(
        input("Para qual estudo deseja enviar os arquivos?\n")) # recebe id do estudo

    prep_files() # baixa os gevazp e as ENAs do pluvia para o tratamento dos dados e os coloca nas pastas apropriadas

    # os decks devem ser inseridos manualmente na pasta de decks do estudo desejado
    # TODO #13 automatizar o download dos decks
    send_decks(path, studyId) # função que organiza e manda um zip com todos os decks necessários para rodar o estudo

    if name == "Curtíssimo prazo": # controle de fluxo para cada modelo

        todayDate, multipleRevision, targetDates = treat_dates() # recebe as datas tratadas para usar de parâmetro

        initialYear = todayDate.year # ano do parâmetro
        initialMonth = todayDate.month # mês do parâmetro
        duration = str(todayDate.month - targetDates[1].month)
        month = [targetDates[0].month, targetDates[1].month] # lista de parâmetros de mês
        year = [targetDates[0].year, targetDates[1].year] # lista de parâmetros de ano
        monthStr = '0' + \
            str(initialMonth) if initialMonth < 10 else str(initialMonth) #formatação da string de mês
        dateToFormat = (initialYear, monthStr)
        newaveFile = "NW%d%s.zip" % dateToFormat # nome do deck newave
        decompFile = "DC%d%s.zip" % dateToFormat # nome do deck decomp

        configFile = "Dados_Prospectivo.xlsx" # arquivo de configuração. obrigatoriamente colocado de forma manual na pasta do modelo

    prospec.sendFileToStudy(studyId, path+'/'+configFile, configFile) # manda arquivo de configuração para a plataforma

    path_prevs = path + "/prevs/" # cria a string de caminho para os prevs

    prospec.sendPrevsToStudy(studyId, path_prevs) # evia os prevs para a plataforma

    send_gevazp(path, studyId) # envia os arquivos do GEVAZP para a plataforma

    prospec.runExecution(studyId, idServer, idQueue, '', '0', '0', '2') # solicita a execução do estudo

# TODO #14 fazer o download dos resultados dos estudos da plataforma
    # prospec.generateNextRev(studyId, newaveFile, decompFile, configFile, [])

    # prospec.generateStudyDecks(studyId, initialYear, initialMonth, [duration], month, year, [False, False], [
    #                            True, True], newaveFile, [newaveFile, newaveFile], [decompFile, decompFile], [configFile, configFile], [])

def treat_dates(): # função que organiza as datas de acordo com a revisão do curtíssimo prazo
    targetDates = []
    multipleRevision = []
    todayDate = dt.date.today()
    firstRevDate = todayDate + dt.timedelta(weeks=1)
    secondRevDate = firstRevDate + dt.timedelta(weeks=1)
    daysDelta = 5 - int(firstRevDate.isoweekday())
    targetDates.append(firstRevDate - dt.timedelta(days=daysDelta))
    targetDates.append(secondRevDate - dt.timedelta(days=daysDelta))
    for target in targetDates:
        rev = get_rev(target)
        multipleRevision.append(rev)
    return todayDate, multipleRevision, targetDates

def get_rev(date_value): # calcula a revisão de interesse baseado num calendário
    day = date_value.day
    month = date_value.month
    year = date_value.year
    x = np.array(calendar.monthcalendar(year, month))
    revision = np.where(x == day)[0][0]
    return(revision)

def send_decks(path, uploadId): # envia arquivos de decks para a plataforma

    path_decks = path + "/Decks/" # cria caminho para a pasta de decks
    create_folder_structure(path_decks) # cria as pastas com os conteúdos no formato que o zip precisa ter
    completeStudyZip = "CompleteStudy.zip" # nome do zip final
    zip_path = path_decks+completeStudyZip # criação do caminho para o zip na pasta

    # TODO #11 criação do zip apropriado para upload
    # os caminhos dentro do zip se referem à pasta raiz do projeto. Eles têm que se referir à pasta study
    # do modelo (e.g. CP/Curtíssimo/study/<pasta>/<arquivo> deveria ser somente /<pasta>/<arquivo>)
    decks = [item for item in Path(path_decks).glob(
        "**/*") if item.suffix == ".zip"] #lista os arquivos zip da pasta de decks

    create_zip(zip_path, path_decks) # função que cria o zip a ser enviado

    prospec.sendFileToStudy(uploadId, zip_path, completeStudyZip) # envia o zip para o estudo de interesse
    zipDecks = Path(zip_path) # cria objeto de caminho
    prospec.completeStudyDecks(uploadId, zipDecks.name, []) # solicita o tratamento do zip na plataforma com os decks completos
    zipDecks.unlink() # remove zip enviado para evitar um zip recursivo

def create_zip(zip_path, path_decks):
    studyFiles = Path(path_decks+'/study') # cria endereço para os arquivos do zip

    # with ZipFile(zip_path, 'w') as zp:
    #     for deck in decks:
    #         if "decomp" in deck.parts:
    #             arcName = "/DECOMP/%s" % deck.name

    #         else:
    #             arcName = "/NEWAVE/%s" % deck.name
    #         zp.write(deck, arcName)

def create_folder_structure(path_decks):
    extract_dc(path_decks) # extrai os arquivos do decomp para a criação de pastas individuais para eles
    folders(path_decks) # extrai os arquivos pertinentes aos decks a serem enviados
    rm_tmp(path_decks) # limpa arquivos temporários

def folders(path_decks):
    files = [item for item in Path(path_decks).glob("**/*") if item.suffix == ".zip"] # lista os zips da pasta de decks
    for file in files:
        if ("sem" in file.name or "NW" in file.name) and not ("Relatorio" in file.name): # acha os zips que não são de relatório
            with ZipFile(file, 'r') as zp:
                zp.extractall(path_decks+"/study/"+file.stem) # extrai para a pasta do zip

def extract_dc(path_decks):
    for file in Path(path_decks).glob("**/*"): # itera arquivos da pasta de decks
        if file.suffix == ".zip" and "DC" in file.name: # condicional para pegar somente os arquivos do DECOMP
            with ZipFile(file) as zp:
                zp.extractall(path_decks+'/tmp') # extração para uma pasta temporária

def rm_tmp(path_decks): # remoção da pasta temporária
    tmp = Path(path_decks+"/tmp")
    for file in tmp.glob('**/*'):
        file.unlink()
    tmp.rmdir()

def send_gevazp(path, uploadId): # envio dos arquivos do GEVAZP para o estudo
    path_gevazp = path + "/GEVAZP/"
    for file in Path(path_gevazp).glob("**/*"):
        if file.is_file():
            prospec.sendFileToDeck(uploadId, "", file, file.name)

def studiesInfo(): # retorna informações de um estudo
    display_studies() # disponibiliza o histórico de estudos criados
    infoId = input("Qual estudo deseja?\n") # recebe id do estudo
    infoStudy = prospec.getInfoFromStudy(infoId) # solicita à plataforma as infos do estudo
    if infoStudy == None: # tratamento de resposta de um estudo que não está mais presente na plataforma
        print("Esse estudo não está mais na plataforma!")
    else:
        print(infoStudy)

def create_study(nameStudy): # cria um estudo
    idStudy = prospec.createStudy(nameStudy, "", 0, 0) # cria um estudo na plataforma com o nome dado bno parâmetro

    with open("estudos criados", 'a') as fp: # registra no histórico a criação do estudo
        fp.write("ID: %s, Nome: %s\n" % (idStudy, nameStudy))

    print("O estudo %s foi criado com ID %s" % (nameStudy, idStudy))

def display_studies(): # imprime na tela o histórico de estudos
    print("Esses são os estudos criados até então:")
    with open("estudos criados", 'r') as fp:
        for line in fp:
            print(line)

def model_params(): # escolhe o nome e caminho do estudo
    nameStudy = "" # recebe o nome apropriado ou continua vazio em caso de erro
    path = "" # mesmo que o nome
    choice = input(
        "Qual o tipo de estudo que deseja?\n1- Curtísimo prazo\n2- ONS CP\n3- Matriz CP\n") # recebe o tipo de estudo a ser feito
    choice = int(choice)
    if choice == 1:
        nameStudy = "Curtíssimo prazo" # define o nome do estudo
        path = "CP/Curtissimo" # define o caminho para os arquivos do estudo

    elif choice < 4:
        # TODO #15 Controle de nomes e caminhos dos demais estudos

        print("Opção em implementação.")

    else:
        print("Opção inválida.")

    return nameStudy, path

def main():
    prospec.authenticateProspec(
        "daniel.mazucanti@skoposenergia.com.br", "Skopos2020") # segurança em primeiro lugar, não é mesmo?

    numRequests = prospec.getNumberOfRequests() # recebe o número de requisições feitas

    print("Foram feitas %s requisições até o momento." % numRequests) # imprime o número de requisições feitas

    while True: # cria laço para impressão do menu
        control_flow = input(
            '1- Criar estudo\n2- Rodar estudo\n3- Abortar execução\n4- Informações do estudo\n0- Sair\n')
            # recebe opção do menu
        if control_flow == "1": # criar estudo

            nameStudy, path_opt = model_params() # recebe os parâmetros do estudo desejado

            create_study(nameStudy) # cria estudo na plataforma

        elif control_flow == "2": # rodar estudo

            prep_n_run() # prepara os arquivos, os envia para a plataforma e solicita a execução

        elif control_flow == "3": # pelo direito de escolher
            display_studies() # mostra histórico de estudos criados
            stopId = int(input("Qual estudo deseja parar?\n")) # recebe id do estudo a ser abortado
            prospec.abortExecution(stopId) # solicita o interrupção do estudo na plataforma

        elif control_flow == "4": # infos do estudo
            studiesInfo() # duh

        else: # qualquer coisa que não esteja nos casos anteriores para aqui
            print("Programa encerrado.")
            break

# create_folder_structure("CP/Curtissimo/Decks/")
# isso aqui era para debugar essa função


"""
Custom converters for the flask router.
"""
import re
from werkzeug.routing import BaseConverter

class ListConverter(BaseConverter):

    def to_python(self, value):
        return value.split(',')

    def to_url(self, values):
        return ','.join(BaseConverter.to_url(value) for value in values)

class LuceneQueryConverter(BaseConverter):
    """
    Quotes and unquote Lucene search strings.
    """

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

        lucene_special_chars = r'+-&|!(){}[]^"~*?:\\'
        self.pattern = re.compile(
            f"""# verbose regex, ignores whitespace during compilation
            (   # Capturing group #1

                # Match any of the lucene special characters exactly once. The chars
                # contain many regex special chars which need to be escaped.
                [{re.escape(lucene_special_chars)}] # Whitespace isn't ignored in [character clauses]
            )
            """,
            re.VERBOSE
        )

    def to_python(self, text: str) -> str:
        """
        Escapes lucene special characters.

        Here's what Lucene says needs to be escaped: `+ - && || ! ( ) { } [ ] ^ " ~ * ? : \`
        From https://lucene.apache.org/core/2_9_4/queryparsersyntax.html#Escaping%20Special%20Characters

        It's not clear whether && (and ||) should be escaped as \&& or \&\&, we're going with the latter.
        """

        replacement = r'\\\1'
        (quoted, number_of_subs_made) = re.subn(self.pattern, replacement, text)
        if self.pattern.match(text):
            print(self.pattern.match(text).groups())
        print(text)
        print(quoted)
        print(number_of_subs_made)
        return quoted

    def to_url(self, text: str):
        """
        Remove quotes added to escape lucene special characters.
        """
        unquoted = re.sub(r'"\\([\+\-!\(\)\{\}\[\]\^\"~\*\?\:\\/&\|])"', r'\1', text)
        return super().to_url(unquoted)

class ReviewServiceConverter(BaseConverter):
    """
    Maps review service names provided as parameter in the url with their internal names used in the database.
    """

    review_services = {
        'reviewcommons': 'review commons',
        'review commons': 'review commons',
        'elife': 'elife',
        'embopress': 'embo press',
        'embo press': 'embo press',
        'rrc19': 'MIT Press - Journals',
        'mit press - journals': 'MIT Press - Journals',
        'pci': 'Peer Community In',
        'peer community in': 'Peer Community In',
        'peerageofscience': 'peerage of science',
        'peerage of science': 'peerage of science',
    }

    def to_python(self, text: str) -> str:
        """
        Returns the internal review service name.
        """
        review_service_name = self.review_services[text.lower()]
        return review_service_name


import os
data_dir = os.path.join(os.path.expanduser('~'), 'Downloads', 'pyqgis_masterclass')

filename = 'seismic_zones.shp'
uri = os.path.join(data_dir, filename)
iface.addVectorLayer(uri, 'seismic_zones', 'ogr')

filename = 'sf.gpkg|layername=zoning'
uri = os.path.join(data_dir, filename)
iface.addVectorLayer(uri, 'zoning', 'ogr')


from base.interfaces import InterfacesBase
from base.modul import Modul
import math

class PGB( Modul ):
    name = "Percepatan Gravitasi Bumi"

    def init_formula( self, interfaces : InterfacesBase ):
        interfaces.get_float("l",
                             brief="panjang tali yang digunakan",
                             deskripsi=
"Panjang adalah dimensi suatu benda yang menyatakan\n\
jarak antar ujung. Panjang tali diukur menggunakan\n\
penggaris",
                             postfix="m")

        interfaces.get_float("T",
                             brief="Periode getaran bandul",
                             deskripsi=
"Periode merupakan waktu yang diperlukan suatu \n\
benda untuk melakukan satu getaran/putaran penuh",
                             postfix="s")

        interfaces.get_float("phi",
                             brief="masukkan bilangan desimal",
                             deskripsi=
"phi adalah sebuah konstanata dalam matematika\n\
yang merupakan perbandingan keliling lingkaran\n\
dengan diameter")

        interfaces.add_func("g",self.percepatan_gravitasi_bumi,
                            brief="Percepatan gravitasi bumi",
                            deskripsi=
"Percepatan gravitasi suatu objek yang berada pada \n\
permukaan laut dikatakan ekuivalen dengan 1 g, yang\n\
didefinisikan memiliki nilai 9,80665 m/s²",
                            postfix="m/s²")

    def percepatan_gravitasi_bumi(self,value : dict):
        l = value ["l"]
        T = value ["T"]
        phi = value["phi"]
        if T == 0:
            return 0

        g = 4*(math.pow(phi, 2))*l / math.pow(T, 2)
        return g


'''You are going to write a program that tests the compatibility between two people.

To work out the love score between two people:

Take both people's names and check for the number of times the letters in the word TRUE occurs.

Then check for the number of times the letters in the word LOVE occurs.

Then combine these numbers to make a 2 digit number.

For Love Scores less than 10 or greater than 90, the message should be:

"Your score is *x*, you go together like coke and mentos."
For Love Scores between 40 and 50, the message should be:

"Your score is *y*, you are alright together."
Otherwise, the message will just be their score. e.g.:

"Your score is *z*."
e.g.

name1 = "Angela Yu"
name2 = "Jack Bauer"
T occurs 0 times

R occurs 1 time

U occurs 2 times

E occurs 2 times

Total = 5

L occurs 1 time

O occurs 0 times

V occurs 0 times

E occurs 2 times

Total = 3

Love Score = 53

Print: "Your score is 53."

Example Input 1
Kanye West
Kim Kardashian
Example Output 1
The Love Calculator is calculating your score...
Your score is 42, you are alright together.
Example Input 2
Brad Pitt
Jennifer Aniston
Example Output 2
The Love Calculator is calculating your score...
Your score is 73.
Hint
You can check your values against mine using this table:

Name 1	Name 2	Score
Brad Pitt	Jennifer Aniston	73
Prince William	Kate Middleton	67
Ashton Kutcher	Mila Kunis	63
Angela Yu	Jack Bauer	53
David Beckham	Victoria Beckham	45
Mario	Princess Peach	43
Kanye West	Kim Kardashian	42
'''

#method 1
'''
print("The Love Calculator is calculating your score...")
name1 = input() # What is your name?
name2 = input() # What is their name?
# ðŸš¨ Don't change the code above ðŸ‘†
# Write your code below this line ðŸ‘‡
name=name1+name2
name=name.strip()
count1=0
count2=0
for i in range(len(name)):
  if name[i]=="T" or name[i]=="t" or name[i]== "R" or name[i]== "r" or name[i]== "U" or name[i]== "u" or name[i]=="E" or name[i]== "e":
   count1+=1
  if name[i]=="L" or name[i]=="l" or name[i]== "O" or name[i]== "o" or name[i]== "V" or name[i]== "v" or name[i]=="E" or name[i]=="e":
   count2+=1
final_score = count1*10 + count2
if final_score<10 or final_score>90:
  print(f"Your score is {final_score}, you go together like coke and mentos.")
elif 40<final_score<50:
  print(f"Your score is {final_score}, you are alright together.")
else:
 print(f"Your score is {final_score}.")
 '''
#method 2
print("The Love Calculator is calculating your score...")
name1 = input()  # What is your name?
name2 = input()  # What is their name?
# Your code below this line ðŸ‘‡
combined_names = name1 + name2
lower_names = combined_names.lower()
t = lower_names.count("t")
r = lower_names.count("r")
u = lower_names.count("u")
e = lower_names.count("e")
first_digit = t + r + u + e

l = lower_names.count("l")
o = lower_names.count("o")
v = lower_names.count("v")
e = lower_names.count("e")
second_digit = l + o + v + e

score = int(str(first_digit) + str(second_digit))
if (score < 10) or (score > 90):
  print(f"Your score is {score}, you go together like coke and mentos.")
elif (score >= 40) and (score <= 50):
  print(f"Your score is {score}, you are alright together.")
else:
  print(f"Your score is {score}.")


qtde = int(input())
qtde_in = qtde_out = 0

for i in range(qtde):
    num = int(input())
    if (num >= 10) and (num <= 20):
        qtde_in += 1 # qtde = qtde + 1
    else:
        qtde_out += 1

print(qtde_in, 'in')
print(qtde_out, 'out')


# -*- coding: utf-8 -*-
import os
import threading
import tkinter as tk # imports
from tkinter import ttk
# from performance_function_test.write_performance_data import getPerformance_data
from tkinter import messagebox
import time
import yaml
import inspect
import ctypes

from openpyxl import load_workbook

# from performance_function_test.write_performance_data import write_performance_data
from performance_function_test.write_performance_data import creat_excel, write_data_to_excel

import sys
sys.path.append("..")
from file_util import *

global projectid,path_report
projectid=1
path_report=get_base_path() + 'performance_function_test\\report'
path_yaml = get_base_path() + 'performance_function_test\\yaml'

def init_tab2(tab_page):
    global text_monkey_info
    monty = ttk.LabelFrame(tab_page, text=' ')
    monty.grid(column=0, row=0, padx=20, pady=20)

    tk.Button(monty, text='点击配置文件 ', font=("Arial", 11), width=30, height=1,command=lambda: openReport(path_yaml)).grid(column=0, row=0, sticky='W', padx=20, pady=10)
    tk.Button(monty, text='点击开始运行 ', font=("Arial", 11), width=30, height=1,command=run_function_test).grid(column=0, row=5, sticky='W', padx=20,
                                                                                pady=10)
    tk.Button(monty, text='查看测试结果 ', font=("Arial", 11), width=30, height=1,command=lambda: openReport(path_report)).grid(column=0, row=9, sticky='W', padx=20,
                                                                                pady=10)

def get_function():
    log_path = get_base_path() + 'performance_function_test\\log\\log.txt'
    path_log = os.path.abspath(log_path)
    excel_path = creat_excel(path_yaml)

    with open(get_base_path() + 'performance_function_test\\yaml\\performance_caps.yaml', 'r', encoding='utf-8') as file:
        data = yaml.load(file)
    scene_info = data['scene']
    # print(scene_info)
    process_info = data['process']
    lens_process = len(process_info)
    lens_scene = len(scene_info)

    averageValueLog_path = get_base_path() + 'performance_function_test\log\\averageValueLog.txt'
    path_averageValueLog = os.path.abspath(averageValueLog_path)
    file_averageValueLog= open(path_averageValueLog, 'w')

    isCustomStop = False # 是否用户取消
    all_times_total = [0] * len(scene_info) # 保存每次的平均值总和，每个item是一个场景的平均值列表
    has_value_times = [0] * len(scene_info) # 保存每个场景有数据的次数是多少次
    all_times_average = [0] * len(scene_info)
    for n in range(1,4):
        # ask = messagebox.askquestion('APP性能测试', '是否开始第 '+ str(n)+' 轮测试（测试会有3轮测试）')
        # print(ask)
        # while askquestion == 'yes':

        y =2
        scene_index =0
        for temp_scene in scene_info.values():
            # f = open(path_log, 'w')
            # f.closed
            f = open(path_log, 'w')

            start_info = tk.messagebox.askquestion(title='第'+ str(n) +'轮测试：' + temp_scene,message='请对页面进行操作，操作完成后，点击“确定”，进行数据采集')
            print(start_info)
            th = threading.Thread(target=set_text_test, args=(f,))
            if start_info=='yes':
                print('数据采集中')
                th.setDaemon(True)  # 守护线程
                th.start()
            else:
                isCustomStop = True
                break
            end_info=tk.messagebox.showinfo('数据采集中', '正在采集数据，请至少采集30S的数据，\n点击" 确定 "可结束数据采集')

            # tk.Label(monty,text='路径为：', font=("Arial", 11), width=20, height=2).grid(column=1,row=6, sticky='W')
            if end_info =='ok':
                _async_raise(th.ident,SystemExit)
                print('关闭txt文件')
                f.close()
                averageValue=write_data_to_excel(path_log, excel_path, 4, y, '第' + str(n) + '次测试')

                if len(averageValue)>0:
                    has_value_times[scene_index] = has_value_times[scene_index] + 1

                tmp = all_times_total[scene_index]
                if type(tmp).__name__ == 'list' and len(tmp)==len(averageValue):
                    for m in range(len(tmp)):
                        tmp[m] =tmp[m] + averageValue[m]
                    all_times_total[scene_index] = tmp
                else:
                    all_times_total[scene_index]=averageValue

            print('写入成功')
            scene_index = scene_index +1
            y = y + lens_process*2 + 2

            with open('结果存放.txt', 'a') as file_handle:  # .txt可以不自己新建,代码会自动新建
                file_handle.write('\n')  # 有时放在循环里面需要自动转行，不然会覆盖上一条数据
        # print(file=file_averageValueLog, end='\n')
        if isCustomStop:
            break
    if not isCustomStop:
        tk.messagebox.showinfo('APP性能测试', '测试已完成，请查看测试结果')

        # 求总平均值
        for v1 in range(len(all_times_total)):
            tmp = [0] * len(all_times_total[v1])

            for v2 in range(len(all_times_total[v1])):
                if has_value_times[v1] == 0:
                    break
                tmp[v2] = all_times_total[v1][v2]/has_value_times[v1]
            all_times_average[v1] =tmp
        print("has_value_times:",has_value_times)
        print("all_times_average:",all_times_average)

        print('将平均值写入excel')

        workbook = load_workbook(excel_path)
        workbook.guess_types = True  # 猜测格式类型
        sheet_average = workbook.get_sheet_by_name('APP性能测试')

        begin_row = 2
        begin_col = 2

        for i in range(len(all_times_average)):
            if (len(all_times_average[i]) == 0):
                continue
            for j in range(len(all_times_average[i])):
                sheet_average.cell(row=begin_row + j, column=begin_col + i, value=round(all_times_average[i][j], 2))

        workbook.save(excel_path)
        workbook.close()

    # file_averageValueLog.close()
# #运行多线程
# def get_function(project_id,insert_text):
#     getPerformance_data(project_id,insert_text)

def set_text_test(f):
    global get_adb_kugou_isrun
    get_adb_kugou_isrun = True

    while get_adb_kugou_isrun:
        get_adb_info(f)

def get_adb_kugou_stop(log_path,excel_path,n,y):
    global get_adb_kugou_isrun
    get_adb_kugou_isrun = False
    write_data_to_excel(log_path, excel_path, 4, y, '第' + str(n) + '次测试')
    # insert_text( '第 ' + str(n) + ' 次测试__' + '场景 ' + str(y) + ' 测试结束了\n')

def run_function_test():
    th = threading.Thread(target=get_function())
    th.setDaemon(True)  # 守护线程
    th.start()

#往txt中插入数据
def insert_text(message):
    if(message==None):
        message = ""

    text_monkey_info.insert(tk.END,message)

def openReport(path_report):

    path = os.path.abspath(path_report)  # 获取当前脚本所在的路径
    os.startfile(path)

def _async_raise(tid, exctype):
   """raises the exception, performs cleanup if needed"""
   tid = ctypes.c_long(tid)
   if not inspect.isclass(exctype):
      exctype = type(exctype)
   res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
   if res == 0:
      raise ValueError("invalid thread id")
   elif res != 1:
      # """if it returns a number greater than one, you're in trouble,
      # and you should call it again with exc=NULL to revert the effect"""
      ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
      raise SystemError("PyThreadState_SetAsyncExc failed")


from operator import index
import pandas as pd
import joblib
import os
import argparse
import numpy as np

from tqdm import tqdm
from sklearn.preprocessing import LabelBinarizer

def main(input_path, output_path):
    all_paths = os.listdir(input_path)
    folder_paths = [folder_path for folder_path in all_paths if os.path.isdir(os.path.join(input_path, folder_path))]
    print(f"Folder paths: {folder_paths}")
    print(f"Number of folders :{len(folder_paths)}")

    # create_labels = ["basketball", "boxing", "chess"]

    data = pd.DataFrame()

    image_formats = ['jpg', 'JPG', 'PNG', 'png']
    labels = []
    counter = 0
    for i, folder_path in tqdm(enumerate(folder_paths), total=len(folder_paths)):
        # if folder_path not in create_labels:
        #     continue
        image_paths = os.listdir(os.path.join(input_path, folder_path))
        label = folder_path

        for image_path in image_paths:
            if image_path.split('.')[-1] in image_formats:
                data.loc[counter, 'image_path'] = f"{input_path}/{folder_path}/{image_path}"
                labels.append(label)
                counter += 1

    labels = np.array(labels)
    lb = LabelBinarizer()
    labels = lb.fit_transform(labels)

    print(labels.shape)
    if len(labels[0]) == 1:
        for i in range(len(labels)):
            index = labels[i]
            data.loc[i, 'target'] = int(index)
    elif len(labels[0]) > 1:
        for i in range(len(labels)):
            index = np.argmax(labels[i])
            data.loc[i, 'target'] = int(index)

    # shuffle the dataset
    data = data.sample(frac=1).reset_index(drop=True)

    print(f"Number of classes: {len(lb.classes_)}")
    print(f"Total instances: {len(data)}")

    # save to csv
    data.to_csv(os.path.join(input_path,"data.csv"), index=False)

    # saving the binarized labels
    print("Saving the binarized labels in pickled file")
    joblib.dump(lb, os.path.join(output_path, "lb.pkl"))

    print(data.head(5))

if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--input_path", required=True, help="Path to the root folder containing dataset images")
    ap.add_argument("-o", "--output_path", required=True, help="Path to save the preprocessed data")

    args = ap.parse_args()
    arguments = args.__dict__

    main(**arguments)