import pygame
import random
import boardgen_points as boardgen
from boardconst import *
import pathfind
import json
import os
import base64
import io

pygame.font.init()

# Colors
BACKGROUND = (0, 0, 0)
TEXTCOLOR = (255, 255, 255)
TILEEMPTY = (30, 30, 200)
TILEWALL = (255, 40, 40)
TILEDOOR = (217, 106, 22)
TILEBOARDWALK = (102, 53, 34)
PLAYERCOLOR = (0, 0, 0)

# Setup
ZOOM = 50
BOARD = [
	[
		{"state": state, "light": True}
			for state in row
	] for row in boardgen.board
]
FONT = pygame.font.SysFont("monospace", 30)
FONTHEIGHT = FONT.render("0", True, TEXTCOLOR).get_height()
validspawn = [(x, y) for x in range(len(BOARD[0])) for y in range(len(BOARD)) if BOARD[y][x]["state"] == 1]
playerpos = [*random.choice(validspawn)]
SCREENSIZE = [500, 500 + FONTHEIGHT]
maxhealth = 20
health = maxhealth + 0
TARGET: "list[int]" = [*playerpos]
INVENTORY: "list[Item]" = []
ITEMS: "list[DroppedItem]" = []
INVENTORY_MAINHAND = None
ITEMDEFS = {}
for f in os.listdir("items"):
	i = open("items/" + f, "r")
	ITEMDEFS[f[:-4]] = json.loads(i.read())
	i.close()
TIME = 0

def getPathfindingBoard():
	"""Returns a list of lists of integers representing the board."""
	def isValidCell(x: int, y: int) -> bool:
		"""Checks whether the given cell is valid."""
		for e in ENTITIES:
			if e.x == x and e.y == y:
				return False
		return BOARD[y][x]["state"] not in WALLBLOCKS
	return [[isValidCell(x, y) for x in range(len(BOARD[y]))] for y in range(len(BOARD))]

# Textures

def base64ToSurface(b: str) -> pygame.Surface:
	"""Converts a base64 string to a pygame surface."""
	data = base64.b64decode(b)
	img = pygame.image.load(io.BytesIO(data), ".png")
	return img

TEXTURES: "list[pygame.Surface]" = []
DARKTEXTURES: "list[pygame.Surface]" = []
colors = [(0, 0, 0), (30, 30, 200), (255, 40, 40), (217, 106, 22), (102, 53, 34)]
for i in ALLBLOCKS:
	TEXTURES.append(None)
	TEXTURES[i] = pygame.Surface([ZOOM, ZOOM])
	TEXTURES[i].fill(colors[i])
	DARKTEXTURES.append(TEXTURES[i].copy())
	# Dim the texture.
	s = pygame.Surface([ZOOM, ZOOM], pygame.SRCALPHA)
	s.fill((0, 0, 0, 200))
	DARKTEXTURES[i].blit(s, (0, 0))

class Monster:
	def __init__(self, x: int, y: int):
		self.x = x
		self.y = y
		self.health = maxhealth // 5
		self.time = TIME + 1
		self.texture = base64ToSurface("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAdVJREFUaEPtmOGSwjAIhPX9H9obO9ZLUgjLAq3Tyf07TQgfC4T4fNzk73kTjscC+TUllyKKIi+nUmmBZAypzgYoGD+6mHkNvLzOIgp9nPD6QoNsDBUgb7sNBQWEbipRQlKLBbJASlWYpZ033UyQqlTKrh0N5DIlRkBUGRXkTCV2J7QzERgJRC1s60AkXZSIbx9ngky7U0udpRgaHEuVURGzzaIHI+p4AzOD6WwhUfYergExdlJBhluYvukZZdNBWhhERabAJ7e+2Gm7wHicYlJjdy5h7wHm/cHXfw9IJMWYtBqCoIN4IUaQysm4TTOtTjZFGAjBOF34SKuGFImCeByJri1VJOqcZ/8C8UTrjLVLEU+UxTeBxwCwtlQRcWYQnMrojjOQ7S5jDtEAdlvW94AAhyWpIIyDh4cPQ/H/+5c4ouwmIVUiDkWGxWYkmk6/EEwEYpx8A6mcC8I4kvSOgUCmhR8Zv8mS6LahL8R2k1gvV4LMIKQnRQdz1hsDUSsC8m0AVwNZEJYiY6Au+z04GwRq0UiaoGua9mROQeYCaWRiWy8KMNw5kI/QIm3+qwLyKDFetN5gdY1A/IewyABkgYgNgWAI+8OmVsDXmq0LpCauvNXbKPIHEVtxMxbvwcwAAAAASUVORK5CYIIA")
	def frame(self):
		global health
		while self.time <= TIME:
			self.doaction()
		# Check if we're dead
		if self.health <= 0:
			self.die()
			print("Monster died...")
	def die(self):
		if self in ENTITIES: ENTITIES.remove(self)
		self.time += 10
	def doaction(self):
		global health
		global TARGET
		# Pathfind to player
		path = pathfind.pathfind(getPathfindingBoard(), (self.x, self.y), playerpos)
		if path:
			if len(path) > 2:
				# Move towards player
				self.x, self.y = path[1]
				self.time += 1
			else:
				# We're at the player, attack!
				health -= 1
				self.time += 1.5
		else:
			# can't find the player...
			self.die()
			# so we kill ourselves. logical course of action.
			print("Monster died")
	def draw(self, screen: pygame.Surface, offset):
		# Check if we're on a hidden tile
		if not BOARD[self.y][self.x]["light"]:
			return
		screen.blit(self.texture, ((self.x * ZOOM) + offset[0], (self.y * ZOOM) + offset[1]))

def addItemStackToPlayerInventory(item: "Item"):
	numLeftToAdd = item.stacksize
	maxStack = item.getdef()["stacksize"]
	for existing in INVENTORY:
		if existing.name == item.name:
			space = maxStack - existing.stacksize
			toAdd = min(space, numLeftToAdd)
			existing.stacksize += toAdd
			numLeftToAdd -= toAdd
			if numLeftToAdd == 0:
				return
	INVENTORY.append(item)

def addItemToPlayerInventory(item: "Item"):
	if not item:
		return # sometimes we get None when adding extra items
	for i in INVENTORY:
		if i.name == item.name and i.stacksize < i.getdef()["stacksize"]:
			i.stacksize += item.stacksize
			extras = i.chop_extra_items()
			if extras:
				INVENTORY.append(extras)
			return
	INVENTORY.append(item)

class Item:
	def __init__(self, name, stacksize: int = 1):
		self.name = name
		self.stacksize = stacksize
	def draw(self):
		s = base64ToSurface(self.getdef()["texture"])
		return s
	def getdef(self):
		return ITEMDEFS[self.name]
	def chop_extra_items(self):
		"""Checks whether we have too many items in this stack. Chops off the extras and returns the remaining items."""
		if self.stacksize > self.getdef()["stacksize"]:
			returnItem = Item(self.name, self.stacksize - self.getdef()["stacksize"])
			self.stacksize = self.getdef()["stacksize"]
			return returnItem

class DroppedItem:
	def __init__(self, pos: "list[int]", i: Item):
		self.item = i
		self.x, self.y = pos
	def collect(self):
		addItemToPlayerInventory(self.item)
		ITEMS.remove(self)
	def draw(self, screen: pygame.Surface, offset):
		if not BOARD[self.y][self.x]["light"]:
			return
		screen.blit(self.item.draw(), ((self.x * ZOOM) + offset[0], (self.y * ZOOM) + offset[1]))

def newItem():
	i = random.choices([n for n in ITEMDEFS.keys()], weights=[n["chance"] for n in ITEMDEFS.values()], k=1)[0]
	ITEMS.append(DroppedItem(random.choice(validspawn), Item(i)))

ENTITIES = [Monster(*random.choice(validspawn)) for x in range(10)]
[newItem() for i in range(20)];

def insideBoard(x: int, y: int) -> bool:
	"""Checks whether the given coordinates are inside the board."""
	return (0 <= x < len(BOARD[0])) and (0 <= y < len(BOARD))

def getPlayerBlock() -> "dict[str, int] | None":
	"""Returns the block the player is on."""
	try:
		return BOARD[playerpos[1]][playerpos[0]]
	except IndexError:
		return None

def isCellThatPlayerCanMoveInto(pos):
	x, y = pos
	return BOARD[y][x]["state"] not in WALLBLOCKS

def posAfterMoved(pos, dir):
	if dir == "up":
		return [pos[0], pos[1]-1]
	elif dir == "down":
		return [pos[0], pos[1]+1]
	elif dir == "left":
		return [pos[0]-1, pos[1]]
	elif dir == "right":
		return [pos[0]+1, pos[1]]

def finalPlayerPos():
	return TARGET

def playerMove(direction: str) -> None:
	"""Moves the player in the given direction."""
	global TARGET
	newPos = posAfterMoved(finalPlayerPos(), direction)
	if not isCellThatPlayerCanMoveInto(newPos):
		return
	TARGET = [*newPos]

def addBlock(x: int, y: int) -> None:
	"""Adds a block to the board."""
	global portalroom
	s = newBlockState(x, y)
	if s == 3: portalroom = True
	BOARD.append({"x": x, "y": y, "state": s, "light": True})

def newBlockState(x: int, y: int) -> int:
	"""Generates a new block state."""
	try:
		return BOARD[y][x]
	except IndexError:
		return 1

def checkLight():
	"""Checks whether the player has a line of sight for each block."""
	from line_points import get_line as get_line_points
	# Iterate over every block
	for y in range(len(BOARD)):
		for x in range(len(BOARD[y])):
			block = BOARD[y][x]
			# Check whether the player has a line of sight to the block.
			# 1. Get list of points from player to block.
			p = get_line_points((playerpos[0], playerpos[1]), (x, y))
			# 3. Check whether any of the points are walls.
			walls = 0
			for point in p:
				b = BOARD[point[1]][point[0]]
				# Make sure we are not checking the target block or the player position.
				if point != (x, y) and [*point] != playerpos:
					# Check if the block is a wall.
					if b["state"] not in SEETHROUGHBLOCKS:
						walls += 1
			# 4. If there are no walls, set the block to light.
			block["light"] = walls == 0

screen = pygame.display.set_mode(SCREENSIZE, pygame.RESIZABLE)
pygame.key.set_repeat(300, 50)

def DIALOG_INVENTORY():
	global screen
	global SCREENSIZE
	global INVENTORY_MAINHAND
	c = pygame.time.Clock()
	running = True
	while running:
		clicked = False
		for event in pygame.event.get():
			if event.type == pygame.QUIT:
				return False
			elif event.type == pygame.VIDEORESIZE:
				SCREENSIZE = event.size
				screen = pygame.display.set_mode(SCREENSIZE, pygame.RESIZABLE)
			elif event.type == pygame.KEYDOWN:
				if event.key == pygame.K_ESCAPE:
					return True
			elif event.type == pygame.MOUSEBUTTONDOWN:
				clicked = True
		# Background
		p = pygame.Surface((SCREENSIZE[0], SCREENSIZE[1]), pygame.SRCALPHA)
		p.fill((255, 255, 255, 1))
		screen.blit(p, (0, 0))
		# Header
		pygame.draw.rect(screen, BACKGROUND, pygame.Rect(0, 0, SCREENSIZE[0], FONTHEIGHT))
		screen.blit(FONT.render("Inventory", True, TEXTCOLOR), (0, 0))
		# Grid
		num_cols = 4
		cell_size = SCREENSIZE[0] // num_cols
		# Main hand
		if INVENTORY_MAINHAND:
			row = 0 // num_cols
			col = 0 % num_cols
			x = col * cell_size
			y = FONTHEIGHT + (row * cell_size)
			cellrect = pygame.Rect(x, y, cell_size, cell_size)
			pygame.draw.rect(screen, TEXTCOLOR, cellrect)
			screen.blit(INVENTORY_MAINHAND.draw(), (x, y))
			# Text
			if INVENTORY_MAINHAND.stacksize > 1:
				t = FONT.render(f"(x{INVENTORY_MAINHAND.stacksize})", True, TILEBOARDWALK)
				screen.blit(t, (x + cell_size - t.get_width(), y + cell_size - t.get_height()))
			if cellrect.collidepoint(pygame.mouse.get_pos()):
				pygame.draw.rect(screen, BACKGROUND, pygame.Rect(0, 0, SCREENSIZE[0], FONTHEIGHT))
				screen.blit(FONT.render(f"- In Main Hand - {INVENTORY_MAINHAND.getdef()['name']}", True, TEXTCOLOR), (0, 0))
				if clicked:
					addItemToPlayerInventory(INVENTORY_MAINHAND)
					INVENTORY_MAINHAND = None
		# Rest of inventory
		for i in [i + 1 for i in range(len(INVENTORY))]:
			row = i // num_cols
			col = i % num_cols
			x = col * cell_size
			y = FONTHEIGHT + (row * cell_size)
			cellrect = pygame.Rect(x, y, cell_size, cell_size)
			if cellrect.collidepoint(pygame.mouse.get_pos()):
				pygame.draw.rect(screen, TEXTCOLOR, cellrect)
				pygame.draw.rect(screen, BACKGROUND, pygame.Rect(0, 0, SCREENSIZE[0], FONTHEIGHT))
				screen.blit(FONT.render(f"- {INVENTORY[i - 1].getdef()['name']}", True, TEXTCOLOR), (0, 0))
				if clicked and not INVENTORY_MAINHAND and ITEMDEFS[INVENTORY[i - 1].name]["type"] == "melee":
					INVENTORY_MAINHAND = INVENTORY[i - 1]
					INVENTORY.remove(INVENTORY[i - 1])
					break
			else:
				pygame.draw.rect(screen, BACKGROUND, cellrect)
				pygame.draw.rect(screen, TEXTCOLOR, cellrect, 1)
			# Text
			if INVENTORY[i - 1].stacksize > 1:
				t = FONT.render(f"(x{INVENTORY[i - 1].stacksize})", True, TILEBOARDWALK)
				screen.blit(t, (x + cell_size - t.get_width(), y + cell_size - t.get_height()))
			# Item
			screen.blit(INVENTORY[i - 1].draw(), (x, y))
		# Flip
		pygame.display.flip()
		c.tick(60)
	return True

c = pygame.time.Clock()
running = True
checkLight()
while running:
	clicked = None
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			running = False
		elif event.type == pygame.VIDEORESIZE:
			SCREENSIZE = event.size
			screen = pygame.display.set_mode(SCREENSIZE, pygame.RESIZABLE)
		elif event.type == pygame.KEYDOWN:
			if event.key == pygame.K_UP:
				playerMove("up")
			elif event.key == pygame.K_DOWN:
				playerMove("down")
			elif event.key == pygame.K_LEFT:
				playerMove("left")
			elif event.key == pygame.K_RIGHT:
				playerMove("right")
			elif event.key == pygame.K_e:
				running = DIALOG_INVENTORY()
		elif event.type == pygame.MOUSEBUTTONDOWN:
			clicked = pygame.mouse.get_pos()
	# Route
	route = pathfind.pathfind(boardgen.board, playerpos, TARGET)
	if route and len(route) > 2:
		playerpos = [*route[1]]
		TIME += 1
		# Tick the entities
		for entity in ENTITIES:
			entity.frame()
		checkLight()
	elif route and len(route) == 2:
		move = True
		for entity in ENTITIES:
			if [entity.x, entity.y] == [*route[1]]:
				move = False
				entity.health -= 1
				if INVENTORY_MAINHAND:
					entity.health -= INVENTORY_MAINHAND.getdef()["params"]["damage"]
					TIME += INVENTORY_MAINHAND.getdef()["params"]["speed"]
				else: TIME += 1
			entity.frame()
		if move:
			playerpos = [*route[1]]
			TIME += 1
		else:
			# We're attacking-- don't move
			TARGET = [*playerpos]
		checkLight()
	# Drawing
	offset = [(SCREENSIZE[0] / 2) + (ZOOM / -2) + (playerpos[0] * -ZOOM), (SCREENSIZE[1] / 2) + (ZOOM / -2) + (playerpos[1] * -ZOOM)]
	screen.fill(BACKGROUND)
	for y in range(len(BOARD)):
		for x in range(len(BOARD[y])):
			cell = BOARD[y][x]
			# Draw the cell
			cellrect = pygame.Rect(x * ZOOM, y * ZOOM, ZOOM, ZOOM)
			cellrect.move_ip(*offset)
			player_on = (x == playerpos[0]) and (y == playerpos[1])
			screen.blit((TEXTURES if cell["light"] else DARKTEXTURES)[cell["state"]], cellrect)
			# Pathfinding
			if clicked and cellrect.collidepoint(clicked):
				TARGET = [x, y]
	# Draw the entities
	for entity in ENTITIES:
		entity.draw(screen, offset)
	# Draw the items
	for i in ITEMS:
		i.draw(screen, offset)
		if [i.x, i.y] == playerpos:
			i.collect()
	# Draw the player
	playerrect = pygame.Rect((playerpos[0] * ZOOM) + (ZOOM / 3), (playerpos[1] * ZOOM) + (ZOOM / 3), ZOOM / 3, ZOOM / 3)
	playerrect.move_ip(*offset)
	pygame.draw.rect(screen, PLAYERCOLOR, playerrect)
	# Add health bar
	toolbarrect = pygame.Rect(0, SCREENSIZE[1] - FONTHEIGHT, SCREENSIZE[0], FONTHEIGHT)
	pygame.draw.rect(screen, BACKGROUND, toolbarrect)
	healthbarrect = toolbarrect.copy()
	healthbarrect.width = healthbarrect.width * (health / maxhealth)
	pygame.draw.rect(screen, TEXTCOLOR, healthbarrect)
	# Flip
	pygame.display.flip()
	c.tick(60)


import sys
sys.stdin = open('matrix_input.txt', 'r')
"""
풀이 접근
1. 0이 아닌 수를 발견하면 그 자리에서 오른쪽과 아래쪽으로 탐색을 시작
2. 0이 나올 때까지 탐색을 하고, 탐색을 끝마치면 중복 탐색을 방지하기 위해 0으로 바꾼다.
3. 이때 0이 아닌 부분의 가로와 세로 길이를 리스트에 넣는다.
"""

T = int(input())
for tc in range(1, T+1):
    N = int(input())    #행렬 크기
    arr = [list(map(int, input().split())) for _ in range(N)]

    matrix = []

    for i in range(N):
        for j in range(N):
            k = 1
            l = 1
            if arr[i][j] != 0:              #0이 아닌 수를 발견하면
                arr[i][j]=0                 #0으로 바꿔 넣는다 (중복탐색 방지)
                while arr[i][j+k] != 0:     #0이 나올 때까지 열의 길이를 센다
                    arr[i][j+k] = 0
                    k += 1
                while arr[i+l][j] != 0:     #0이 나올 때까지 행의 길이를 센다
                    arr[i+l][j] = 0
                    l += 1
                for r in range(k):          #해당 행렬에 숫자 값이 남지 않도록 0으로 모두 없앤다.
                    for c in range(l):
                        arr[i+ c][j + r] = 0
                m = []
                m.append(l)
                m.append(k)
                matrix.append(m)

    #순서 정하기 - 가로x세로가 큰 순서대로 정렬(버블소트)
    for j in range(len(matrix)-1):
        for i in range(len(matrix)-1):
            size = matrix[i][0] * matrix[i][1]
            next_size = matrix[i+1][0] * matrix[i+1][1]

            if size > next_size:
                matrix[i], matrix[i+1] = matrix[i+1], matrix[i]

            if size == next_size:
                if matrix[i][0] > matrix[i+1][0]:
                    matrix[i], matrix[i + 1] = matrix[i + 1], matrix[i]

    matrix_num = len(matrix)
    numbers = str(matrix_num)+' '
    for i in matrix:
        for j in i:
            numbers = numbers + str(j) + ' '

    print('#{} {}'.format(tc, numbers))


import torch
import intel_extension_for_pytorch

from torch.nn.modules.utils import _pair

zero_point = 0
dtype_inputs = torch.quint8
dtype_filters = torch.qint8

scale_in = 0.4
scale_weight = 0.5
scale_out = 4.0
scale_out_2 = 8.0

inputs = torch.randn(1, 2, 5, 5)
filters = torch.randn(4, 2, 3, 3)
bias = torch.randn(4)

with torch.autograd.profiler_legacy.profile(True, use_xpu=True, with_calling_stack=True) as prof:
    q_inputs = torch.quantize_per_tensor(inputs, scale_in, zero_point, dtype_inputs)
    q_filters = torch.quantize_per_tensor(filters, scale_weight, zero_point, dtype_filters)

    packed_params = torch.ops.quantized.conv2d_prepack(q_filters, bias, _pair(1), _pair(0), _pair(1), 1)
    #output_int8 = torch.ops.quantized.conv2d_relu(q_inputs, packed_params, _pair(1), _pair(0), _pair(1), 1, scale_out, zero_point)
    output_int8_ref = torch.ops.quantized.conv2d(q_inputs, packed_params, _pair(1), _pair(0), _pair(1), 1, scale_out, zero_point)
print(prof.table(sort_by="id", max_depth=10, row_limit=10000000))

print("output_int8_ref={}".format(output_int8_ref))
output = torch.nn.functional.leaky_relu(output_int8_ref, 0.5)
print("output={}".format(output))

'''
inputs_gpu=inputs.to("xpu")
filters_gpu = filters.to("xpu")
bias_gpu = bias.to("xpu")

q_inputs_gpu = torch.quantize_per_tensor(inputs_gpu, scale_in, zero_point, dtype_inputs)
q_filters_gpu = torch.quantize_per_tensor(filters_gpu, scale_weight, 128, dtype_filters)

packed_params_gpu = torch.ops.quantized.conv2d_prepack(q_filters_gpu, bias_gpu, _pair(1), _pair(0), _pair(1), 1)
#output_int8 = torch.ops.quantized.conv2d_relu(q_inputs_gpu, packed_params, _pair(1), _pair(0), _pair(1), 1, scale_out, zero_point)

#output_int8_gpu = torch.ops.quantized.conv2d_relu(q_inputs_gpu, packed_params_gpu, scale_out, zero_point)
#output_int8_gpu = intel_extension_for_pytorch._C.qconv2d_leakyrelu(q_inputs_gpu, packed_params_gpu, scale_out, zero_point, 0.5)

#output_gpu = torch.nn.functional.leaky_relu(output_int8_gpu, 0.5)
print("output_input8_gpu={}".format(output_int8_gpu))
#print("output_gpu={}".format(output_gpu))
'''


import sys
import pathlib
import re
import csv
import pickle

# method 2 of using sysarg on GitHub
def setfilepath(filepath):
    with open(pathlib.Path.cwd().joinpath(filepath), 'r') as f:
        text_in = f.read()
   # print(text_in)

def process(filepath):
    csv_file = csv.reader(filepath)
    #delete header row, skip when reading and write to new

    with open(filepath, 'r') as in_file:
        reader = csv.reader(in_file)
        next(reader) # Skipping the header row
        text_csv = []
        for row in reader: #iterate thru reader
            for entry in row:
                text_csv.append(entry.lower())#append text to text list as lowercase to capitalize later
    #break down pure data list into new lists based on original columns we overlooked
    last_list = [text_csv[0], text_csv[5], text_csv[10], text_csv[15], text_csv[20]]
    first_list = [text_csv[1], text_csv[6], text_csv[11], text_csv[16], text_csv[21]]
    mi_list = [text_csv[2], text_csv[7], text_csv[12], text_csv[17], text_csv[22]]
    id_list = [text_csv[3], text_csv[8], text_csv[13], text_csv[18], text_csv[23]]
    phone_list = [text_csv[4], text_csv[9], text_csv[14], text_csv[19], text_csv[24]]

    #captialize first/last names in first_list and last_list
    #acheive this by copying lists and making edits.
    first_list[:] = [i.capitalize() for i in first_list]
    last_list[:] = [j.capitalize() for j in last_list]
    mi_list[:] = [k.capitalize() for k in mi_list]
    #capitalize ID alphabet characters
    id_list[:] = [l.upper() for l in id_list]
    #check for no mi
    for i in range(len(mi_list)):
        if mi_list[i] == '': #find empty cell
            mi_list[i] = 'X' #replcae w/ X

    #regex to format id section
    id_pattern = re.compile(r"^[A-Z]{2}\d{4}$")
    for i in range(len(id_list)):
        if id_pattern.match(id_list[i]):
            pass #id matches pattern, so we don't return error
        else:
            print("Invalid ID: Enter a two letter/four digit ID.")

    #regex for phone num
    phone_pattern = re.compile(r"^\d{3}-\d{3}-\d{4}$")
    for i in range(len(phone_list)):
        if phone_pattern.match(phone_list[i]):
            pass
        else:
            print("Invalid Phone Number: Enter a number in the format 123-456-7890.")

    #data to person obj
    pers1 = Person(first_list[0], last_list[0], mi_list[0], id_list[0], phone_list[0])
    pers2 = Person(first_list[1], last_list[1], mi_list[1], id_list[1], phone_list[1])
    pers3 = Person(first_list[2], last_list[2], mi_list[2], id_list[2], phone_list[2])
    pers4 = Person(first_list[3], last_list[3], mi_list[3], id_list[3], phone_list[3])
    pers5 = Person(first_list[4], last_list[4], mi_list[4], id_list[4], phone_list[4])

    #dict for person
    emp_dict = {
        pers1.id: pers1,
        pers2.id: pers2,
        pers3.id: pers3,
        pers4.id: pers4,
        pers4.id: pers5,
    }

    #pickle dict from process()
    pickle.dump(emp_dict, open('dict.p', 'wb'))
    return emp_dict

def main():
    # prompt file path
    print("Please enter in a filepath as a sysarg. ('data/data.csv')\n")
    if len(sys.argv) > 1:
        arg_input = sys.argv[1]
      #  print('Filepath: ', arg_input)
        setfilepath(arg_input)
    else:
        print('No sys.arg detected. Terminating.')
        sys.exit()

    process(arg_input)
    dict_in = pickle.load(open('dict.p', 'rb'))

# person class

class Person:
    def __init__(self, first, last, mi, id, phone):
        self.first = first
        self.last = last
        self.mi = mi
        self.id = id
        self.phone = phone

    def display(self):
        print("Employee ID: ", self.id, "\n")
        print('{} {} {}'.format(self.first, self.mi, self.last), "\n")
        print(self.phone, "\n")

if __name__ == "__main__":
    main()


"""
The PolicyEngine server logic (Flask-based).
"""
import os
from pathlib import Path
from typing import Tuple, Type
from flask import Flask, request, send_from_directory
from flask_cors import CORS
from time import time
from policyengine.utils.general import (
    get_cached_result,
    after_request_func,
    set_cached_result,
)
from policyengine.countries import UK, US, PolicyEngineCountry
from policyengine import VERSION
from policyengine.utils.social_card import add_social_card_metadata

class PolicyEngine:
    version: str = VERSION
    cache_bucket_name: str = "uk-policy-engine.appspot.com"
    countries: Tuple[Type[PolicyEngineCountry]] = (UK, US)

    def _init_countries(self):
        self.countries = list(map(lambda country: country(), self.countries))

    def _init_forwarding(self):
        def static_site(e):
            with open(
                str(Path(__file__).parent / "static" / "index.html")
            ) as f:
                text = f.read()
                modified = add_social_card_metadata(request.path, text)
            with open(
                str(Path(__file__).parent / "static" / "index_mod.html"), "w"
            ) as f:
                f.write(modified)
            response = send_from_directory(
                str(Path(__file__).parent / "static"), "index_mod.html"
            )
            return response

        self.static_site = self.app.errorhandler(404)(static_site)

        def timed_endpoint(fn):
            def new_fn(*args, **kwargs):
                start_time = time()
                result = fn(*args, **kwargs)
                duration = time() - start_time
                self.app.logger.info(
                    f"{fn.__name__} completed in {round(duration, 1)}s."
                )
                return result

            new_fn.__name__ = "timed_" + fn.__name__
            return new_fn

        def pass_params_and_cache(fn):
            def new_fn(*args, **kwargs):
                params = {**request.args, **(request.json or {})}
                cached_result = None
                cache = (
                    self.cache
                    if not hasattr(fn, "_exclude_from_cache")
                    else None
                )
                if cache is not None:
                    cached_result = get_cached_result(
                        params, fn.__name__, self.version, self.cache
                    )
                if cached_result is not None:
                    return cached_result
                else:
                    result = fn(*args, params=params, **kwargs)
                    if cache is not None:
                        set_cached_result(
                            params,
                            fn.__name__,
                            self.version,
                            self.cache,
                            result,
                        )
                    return result

            new_fn.__name__ = (
                "cached_" if not hasattr(fn, "_exclude_from_cache") else ""
            ) + fn.__name__
            return new_fn

        self.api_decorators = (
            pass_params_and_cache,
            timed_endpoint,
        )

        for country in self.countries:
            for route, handler in country.api_endpoints.items():
                fn = handler
                for decorator in (
                    *self.api_decorators,
                    self.app.route(
                        f"/{country.name}/api/{route.replace('_', '-')}",
                        methods=["GET", "POST"],
                        endpoint=f"{country.name}_{route}",
                    ),
                ):
                    fn = decorator(fn)
                    setattr(self, fn.__name__, fn)

        self.after_request_func = self.app.after_request(after_request_func)

    def _init_flask(self):
        self.app = Flask(
            type(self).__name__,
            static_url_path="",
            static_folder=str((Path(__file__).parent / "static").absolute()),
        )
        CORS(self.app)

    @property
    def debug_mode(self):
        return bool(os.environ.get("POLICYENGINE_DEBUG"))

    def _init_cache(self):
        if self.cache_bucket_name is not None and not self.debug_mode:
            from google.cloud import storage

            self.cache = storage.Client().get_bucket(self.cache_bucket_name)
        else:
            self.cache = None

    def __init__(self):
        self._init_flask()
        self.app.logger.info("Initialising server.")
        self._init_countries()
        self._init_cache()
        self._init_forwarding()
        self.app.logger.info("Initialisation complete.")

app = PolicyEngine().app


import math
def primeFactors(n):
    v=set()
    # Print the number of two's that divide n
    while n % 2 == 0:
        v.add(2)
        n = n / 2

    # n must be odd at this point
    # so a skip of 2 ( i = i + 2) can be used
    for i in range(3, int(math.sqrt(n))+1, 2):

        # while i divides n, print i ad divide n
        while n % i == 0:
            v.add(i)
            n = n / i

    # Condition if n is a prime
    # number greater than 2
    if n > 2:
        v.add(n)
    return v
n=int(input())
s=primeFactors(n)

if len(s)==1:
    for i in s:
        print(i)
else:
    print(1)


import wav_decoder
import wav_encoder
import wav_visualizer
import string_to_binary_encoder
import argparse

if __name__ == '__main__':

    # Add our command line arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('--input_string', type=str, required=True)
    parser.add_argument('--sample_rate', type=int, required=False, default=4410)
    parser.add_argument('--duration_per_bit', type=int, required=False, default=2)
    parser.add_argument('--wav_file_name', type=str, required=False, default="wav_file.wav")

    # Parse arguments
    args = parser.parse_args()
    data_in = args.input_string
    sample_rate = args.sample_rate
    max_amplitude = 1 # the floating point value we want to assign to our 1 bits
    duration_ms_per_bit = args.duration_per_bit  # The duration of the wav
    fn = args.wav_file_name

    # Call the encoder
    encoded_wav = wav_encoder.encode_wav_as_step_function(
        data_arr=string_to_binary_encoder.encode_string(data_in),
        sample_rate=sample_rate,
        max_amplitude=max_amplitude,
        duration_ms_per_bit=duration_ms_per_bit)

    # Save the encoded values to wav file
    wav_encoder.convert_wav_data_to_wav_file(wav_encoded_data=encoded_wav, sample_rate=sample_rate, fn=fn)

    # Visualize both the binary wav data and the wav file
    wav_visualizer.visualize_wav_file(fn, duration_ms_per_bit)
    wav_visualizer.visualize_wav_data(encoded_wav, duration_ms_per_bit)

    # Decode wav file
    decoded_string = wav_decoder.decode_wave(fn=fn, duration_ms_per_bit=duration_ms_per_bit, max_amplitude=max_amplitude)

    # Print out the interesting stuff
    print(f"Binary Data In Per Character: \n {string_to_binary_encoder.encode_string(data_in)}")
    print(f".Wav encoded binary data: \n {encoded_wav}")
    print(f"Output decoded string: {decoded_string}")


import logging
from pathlib import Path
from typing import List, Union

import geopandas as gpd
import pandas as pd
from prefect import task
from sqlalchemy import DDL
from sqlalchemy.engine import Connection
from sqlalchemy.sql import Select

from src.db_config import create_engine
from src.pipeline import utils
from src.pipeline.processing import prepare_df_for_loading
from src.pipeline.utils import get_table, psql_insert_copy
from src.read_query import read_query, read_saved_query

def extract(
    db_name: str,
    query_filepath: Union[Path, str],
    dtypes: Union[None, dict] = None,
    parse_dates: Union[list, dict, None] = None,
    params=None,
    backend: str = "pandas",
    geom_col: str = "geom",
    crs: Union[int, None] = None,
) -> Union[pd.DataFrame, gpd.GeoDataFrame]:
    """Run SQL query against the indicated database and return the result as a
    `pandas.DataFrame`.

    Args:
        db_name (str): name of the database to extract from : "fmc", "ocan",
            "monitorfish_local" or "monitorfish_remote"
        query_filepath (Union[Path, str]): path to .sql file, starting from the saved
            queries folder. example : "ocan/nav_fr_peche.sql"
        dtypes (Union[None, dict], optional): If specified, use {col: dtype, …}, where
            col is a column label and dtype is a numpy.dtype or Python type to cast
            one or more of the DataFrame’s columns to column-specific types.
            Defaults to None.
        parse_dates (Union[list, dict, None], optional):

          - List of column names to parse as dates.
          - Dict of ``{column_name: format string}`` where format string is
            strftime compatible in case of parsing string times or is one of
            (D, s, ns, ms, us) in case of parsing integer timestamps.
          - Dict of ``{column_name: arg dict}``, where the arg dict corresponds
            to the keyword arguments of :func:`pandas.to_datetime`

          Defaults to None.
        params (Union[dict, None], optional): Parameters to pass to execute method.
            Defaults to None.
        backend (str, optional) : 'pandas' to run a SQL query and return a
            `pandas.DataFrame` or 'geopandas' to run a PostGIS query and return a
            `geopandas.GeoDataFrame`. Defaults to 'pandas'.
        geom_col (str, optional): column name to convert to shapely geometries when
            `backend` is 'geopandas'. Ignored when `backend` is 'pandas'. Defaults to
            'geom'.
        crs (Union[None, str], optional) : CRS to use for the returned GeoDataFrame;
            if not set, tries to determine CRS from the SRID associated with the first
            geometry in the database, and assigns that to all geometries. Ignored when
            `backend` is 'pandas'. Defaults to None.

    Returns:
        Union[pd.DataFrame, gpd.GeoDataFrame]: Query results
    """

    res = read_saved_query(
        query_filepath,
        db=db_name,
        parse_dates=parse_dates,
        params=params,
        backend=backend,
        geom_col=geom_col,
        crs=crs,
    )

    if dtypes:
        res = res.astype(dtypes)

    return res

def load(
    df: Union[pd.DataFrame, gpd.GeoDataFrame],
    *,
    table_name: str,
    schema: str,
    logger: logging.Logger,
    how: str = "replace",
    db_name: str = None,
    pg_array_columns: list = None,
    handle_array_conversion_errors: bool = True,
    value_on_array_conversion_error: str = "{}",
    jsonb_columns: list = None,
    table_id_column: str = None,
    df_id_column: str = None,
    nullable_integer_columns: list = None,
    timedelta_columns: list = None,
    enum_columns: list = None,
    connection: Connection = None,
    init_ddls: List[DDL] = None,
    end_ddls: List[DDL] = None,
):
    """
    Load a DataFrame or GeoDataFrame to a database table using sqlalchemy. The table
    must already exist in the database.

    Args:
        df (Union[pd.DataFrame, gpd.GeoDataFrame]): data to load
        table_name (str): name of the table
        schema (str): database schema of the table
        logger (logging.Logger): logger instance
        how (str): one of

          - 'replace' to delete all rows in the table before loading
          - 'append' to append the data to rows already in the table
          - 'upsert' to append the rows to the table, replacing the rows whose id is
            already

        db_name (str, optional): Required if a `connection` is not provided.
          'monitorfish_remote', 'monitorenv_remote' or 'monitorfish_local'.
          Defaults to None.
        pg_array_columns (list, optional): columns containing sequences that must be
          serialized before loading into columns with Postgresql `Array` type
        handle_array_conversion_errors (bool): whether to handle or raise upon error
          during the serialization of columns to load into Postgresql `Array` columns.
          Defaults to True.
        value_on_array_conversion_error (str, optional): if
          `handle_array_conversion_errors`, the value to use when an error must be
          handled. Defaults to '{}'.
        jsonb_columns (list, optional): columns containing values that must be
          serialized before loading into columns with Postgresql `JSONB` type
        table_id_column (str, optional): name of the table column to use an id.
          Required if `how` is "upsert".
        df_id_column (str, optional): name of the DataFrame column to use an id.
          Required if `how` is "upsert".
        nullable_integer_columns (list, optional): columns containing values
          that must loaded into columns with Postgresql `Integer` type. If these
          columns contain `NA` values, pandas will automatically change the dtype to
          `float` and the loading into Postgreql `Integer` columns will fail, so it is
          necessary to serialize these values as `Integer`-compatible `str` objects.
        timedelta_columns (list, optional): columns containing `Timedelta` values to
          load into Postgresql `Interval` columns. If these columns contain `NaT`
          values, the loading will fail, so it is necessary to serialize these values
          as `Interval`-compatible `str` objects.
        enum_columns (list, optional): columns containing Enum values to
          load into Postgresql. Values in these columns will be converted to string
          using the enum's `.value`. Null values will remain null.
        connection (Connection, optional): Databse connection to use for the insert
          operation. If not provided, `db_name` must be given and a connection to the
          designated database will be created for the insert operation.
          Defaults to None.
        init_ddls: (List[DDL], optional): If given, these DDLs will be executed before
          the loading operation. Defaults to None.
        end_ddls: (List[DDL], optional): If given, these DDLs will be executed after
          the loading operation. Defaults to None.
    """

    df = prepare_df_for_loading(
        df,
        logger,
        pg_array_columns=pg_array_columns,
        handle_array_conversion_errors=handle_array_conversion_errors,
        value_on_array_conversion_error=value_on_array_conversion_error,
        jsonb_columns=jsonb_columns,
        nullable_integer_columns=nullable_integer_columns,
        timedelta_columns=timedelta_columns,
        enum_columns=enum_columns,
    )

    if connection is None:
        e = create_engine(db_name)
        with e.begin() as connection:
            load_with_connection(
                df=df,
                connection=connection,
                table_name=table_name,
                schema=schema,
                logger=logger,
                how=how,
                table_id_column=table_id_column,
                df_id_column=df_id_column,
                init_ddls=init_ddls,
                end_ddls=end_ddls,
            )
    else:
        load_with_connection(
            df=df,
            connection=connection,
            table_name=table_name,
            schema=schema,
            logger=logger,
            how=how,
            table_id_column=table_id_column,
            df_id_column=df_id_column,
            init_ddls=init_ddls,
            end_ddls=end_ddls,
        )

def load_with_connection(
    df: Union[pd.DataFrame, gpd.GeoDataFrame],
    *,
    connection: Connection,
    table_name: str,
    schema: str,
    logger: logging.Logger,
    how: str = "replace",
    table_id_column: Union[None, str] = None,
    df_id_column: Union[None, str] = None,
    init_ddls: List[DDL] = None,
    end_ddls: List[DDL] = None,
):
    if init_ddls:
        for ddl in init_ddls:
            connection.execute(ddl)

    table = get_table(table_name, schema, connection, logger)
    if how == "replace":
        # Delete all rows from table
        utils.delete(table, connection, logger)

    elif how == "upsert":
        # Delete rows that are in the DataFrame from the table

        try:
            assert df_id_column is not None
        except AssertionError:
            raise ValueError("df_id_column cannot be null if how='upsert'")
        try:
            assert table_id_column is not None
        except AssertionError:
            raise ValueError("table_id_column cannot be null if how='upsert'")

        ids_to_delete = set(df[df_id_column].unique())

        utils.delete_rows(
            table=table,
            id_column=table_id_column,
            ids_to_delete=ids_to_delete,
            connection=connection,
            logger=logger,
        )

    elif how == "append":
        # Nothing to do
        pass

    else:
        raise ValueError(f"how must be 'replace', 'upsert' or 'append', got {how}")

    # Insert data into table
    logger.info(f"Loading into {schema}.{table_name}")

    if isinstance(df, gpd.GeoDataFrame):
        logger.info("GeodateFrame detected, using to_postgis")
        df.to_postgis(
            name=table_name,
            con=connection,
            schema=schema,
            index=False,
            if_exists="append",
        )

    elif isinstance(df, pd.DataFrame):
        df.to_sql(
            name=table_name,
            con=connection,
            schema=schema,
            index=False,
            method=psql_insert_copy,
            if_exists="append",
        )

    else:
        raise ValueError("df must be DataFrame or GeoDataFrame.")

    if end_ddls:
        for ddl in end_ddls:
            connection.execute(ddl)

def delete_rows(
    *,
    table_name: str,
    schema: str,
    db_name: str,
    table_id_column: str,
    ids_to_delete: set,
    logger: logging.Logger,
):
    """
    Delete rows from a database table.

    Args:
        table_name (str): name of the table
        schema (str): database schema of the table
        db_name (str): name of the database. One of
          - 'monitorfish_remote'
          - 'monitorfish_local'
        table_id_column (str): name of the id column in the database.
        ids_to_delete (set): the ids of the rows to delete.
        logger (logging.Logger): logger instance.
    """

    e = create_engine(db_name)
    table = get_table(table_name, schema, e, logger)

    with e.begin() as connection:
        n_rows = len(ids_to_delete)
        if n_rows == 0:
            logger.info("No rows to delete, skipping.")

        else:
            utils.delete_rows(
                table=table,
                id_column=table_id_column,
                ids_to_delete=ids_to_delete,
                connection=connection,
                logger=logger,
            )

@task(checkpoint=False)
def read_query_task(database: str, query: Select) -> pd.DataFrame:
    """
    Prefect `task` decorated version of `read_query`.
    """

    return read_query(query, db=database)


from datetime import datetime
from doctest import master
import threading
from time import strftime, time
from time import sleep
import tkinter as tk
import customtkinter as ctk
from tkinter import *

ctk.set_appearance_mode('system') #dark and light mode from windows
ctk.set_default_color_theme('green')

# Custom_tkinter winsow class
class App(ctk.CTk):
    WIDTH = 780
    HEIGHT = 520

    def __init__ (self):
        super(App,self).__init__()

        self.title("Timer")
        self.geometry(f"{App.WIDTH}x{App.HEIGHT}")
        self.protocol("WM_DELETE_WINDOW", self.on_closing)
        self._alarm_id = None

  # configure grid layout (2x1)
        self.grid_columnconfigure(1, weight=1)
        self.grid_rowconfigure(0, weight=1)

        self.frame_right = ctk.CTkFrame(master=self)
        self.frame_right.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)

        # configure grid layout (3x7)
        self.frame_right.rowconfigure((0, 1, 2, 3), weight=1)
        self.frame_right.rowconfigure(7, weight=10)
        self.frame_right.columnconfigure((0, 1), weight=1)
        self.frame_right.columnconfigure(2, weight=0)

        self.frame_info = ctk.CTkFrame(master=self.frame_right)
        self.frame_info.grid(row=0, column=0, columnspan=2, rowspan=4, pady=20, padx=20, sticky="nsew")

        # ============ frame_info ============
        self.frame_info.rowconfigure(0, weight=1)
        self.frame_info.columnconfigure(0, weight=1)

        #actual time output
        self.ste=strftime('%H:%M:%S')

        #label created with custom tkinter
        self.label_info_1 = ctk.CTkLabel(master=self.frame_info,
                                            text=self.ste,
                                            height=100,
                                            corner_radius=6,  # <- custom corner radius
                                            fg_color=("white", "gray"),  # <- custom tuple-color
                                            justify=tk.LEFT)
        self.label_info_1.grid(column=0, row=0, sticky="nwe", padx=15, pady=15)

        #start button to start the timer
        self.button_1 = ctk.CTkButton(master=self.frame_info,
                                                text="Start",
                                                border_width=2,  # <- custom border_width
                                                fg_color=None,  # <- no fg_color
                                                command=self.toggle
                                                )
        self.button_1.grid(row=2, column=0, columnspan=1, rowspan=2, pady=20, padx=20, sticky="w")

        self.button_2 = ctk.CTkButton(master=self.frame_info,
                                                text="Timestamp",
                                                border_width=2,  # <- custom border_width
                                                fg_color=None,  # <- no fg_color
                                                command=self.timm
                                                )
        self.button_2.grid(row=2, column=2, columnspan=1, pady=20, padx=20, sticky="e")

        self.paused = True
        #timestamp
    def timm(self):
        self.ste1=strftime('%H:%M:%S')
        self.timestamp = (self.ste1)
        for x in self.timestamp:
            print("start time:",self.timestamp)

#button function 'start and stop'
    def toggle(self):
        if self.paused:
            self.paused = False
            self.button_1.configure(text='Stop')
            self.oldtime = time()
            self.run_timer()
        else:
            self.paused = True
            self.oldtime = time()
            self.button_1.configure(text='Start')
#run timer to start
    def run_timer(self):
        if self.paused:
            return
        delta = int(time() - self.oldtime)
        timestr = '{:02}:{:02}'.format(*divmod(delta, 60))
        self.label_info_1.configure(text=timestr)
        self.label_info_1.after(1000, self.run_timer)

#appearance mode
    def change_appearance_mode(self, new_appearance_mode):
        ctk.set_appearance_mode(new_appearance_mode)
#method to close the custom_tkinter window
    def on_closing(self, event=0):
        self.destroy()

#countdown timer
def countdown(t):

        while t:
            mins, secs = divmod(t, 60)
            timer = '{:02d}:{:02d}'.format(mins, secs)
            print(timer, end="\r")
            sleep(1)
            t -= 1

        print('time up!!')

t = input("Enter the time in seconds: ")
countdown(int(t))

#which function should be played
if __name__=="__main__":
    app=App()
    app.mainloop()
    thread1=threading.Thread(target=app).start()
    thread2=threading.Thread(target=countdown()).join
    countdown()


from decouple import config
import requests
import sys
import os
import django
from bs4 import BeautifulSoup as BS

if __name__ == '__main__':
    path = os.path.dirname(__file__)
    os.environ['DJANGO_SETTINGS_MODULE'] = 'telegram.settings'
    django.setup()
    from bus.models import BusGo, BusOut

token = config('TOKEN')
bus_key = config('BUS_KEY')
api_url = f'https://api.telegram.org/bot{token}'

chat_id = sys.argv[1]
minute = sys.argv[2]
direction = sys.argv[3]

station_id = ''
route_id = ''
station_order = ''
region = ''

# minute = sys.argv[2]
# chat_id = context['chat_id']
if direction == 'go':
    busgo = BusGo.objects.filter(chat_id=chat_id).last()
    if busgo is None:
        msg = '출근 버스를 등록하세요.\n' \
              '예시) 출근 버스 등록'
        requests.get(api_url + f'/sendMessage?chat_id={chat_id}&text={msg}')
    else:
        station_id = busgo.go_station_id
        route_id = busgo.go_route_id
        station_order = busgo.go_station_order
        region = busgo.go_region

else:  # direction == 'out'
    busout = BusOut.objects.filter(chat_id=chat_id).last()
    if busout is None:
        msg = '퇴근 버스를 등록하세요.\n' \
              '예시) 퇴근 버스 등록'
        requests.get(api_url + f'/sendMessage?chat_id={chat_id}&text={msg}')

    else:
        station_id = busout.out_station_id
        route_id = busout.out_route_id
        station_order = busout.out_station_order
        region = busout.out_region

if station_id is not None:
    if region == 'gyeonggi':
        url = f'http://openapi.gbis.go.kr/ws/rest/busarrivalservice?serviceKey={bus_key}&stationId={station_id}&routeId={route_id}&staOrder={station_order}'
        request = requests.get(url).text
        soup = BS(request, 'html.parser')
        # 되기는 하지만 너무 길다..
        # test = soup.select_one('response > msgBody > busArrivalItem > locationNo1').contents[0]
        if not soup.find('predicttime1'):
            msg = '버스API 점검, 운행 종료 등의 사유로\n' \
                  '버스 확인이 불가능합니다'
            requests.get(api_url + f'/sendMessage?chat_id={chat_id}&text={msg}')
        else:
            predict1 = soup.find('predicttime1').contents[0]
            location1 = soup.find('locationno1').contents[0]
            seat1 = soup.find('remainseatcnt1').contents[0]

            predict2 = soup.find('predicttime2').contents[0]
            location2 = soup.find('locationno2').contents[0]
            seat2 = soup.find('remainseatcnt2').contents[0]

            msg = f'직전 버스: {predict1}분 ({location1}정류장) [{seat1}좌석]\n' \
                   f'다음 버스: {predict2}분 ({location2}정류장) [{seat2}좌석]\n' \
                   f'알림 정지: "정지", "종료" 입력'

            if int(minute) == 300:
                requests.get(api_url + f'/sendMessage?chat_id={chat_id}&text={msg}')

            elif int(predict1) <= int(minute):
                requests.get(api_url + f'/sendMessage?chat_id={chat_id}&text={msg}')

    else:  # region == 'seoul'
        url = f'http://ws.bus.go.kr/api/rest/arrive/getArrInfoByRoute?serviceKey={bus_key}&stId={station_id}&busRouteId={route_id}&ord={station_order}'
        request = requests.get(url).text
        soup = BS(request, 'html.parser')
        bus1 = soup.find('arrmsg1').contents[0]
        bus2 = soup.find('arrmsg2').contents[0]
        msg = ''

        if bus1.find('분') != -1:
            bus1_minute = bus1[:bus1.find('분')]
            bus1_location = bus1[bus1.find('[') + 1:bus1.find('번')]
            msg = f'직전 버스: {bus1_minute}분 ({bus1_location}정류장)\n'
        else:  # 곧 도착, 운행 종료 등
            bus1_minute = 0
            msg = f'직전 버스: {bus1}\n'

        if bus1.find('분') != -1:
            bus2_minute = bus2[:bus2.find('분')]
            bus2_location = bus2[bus2.find('[') + 1:bus2.find('번')]
            msg += f'다음 버스: {bus2_minute}분 ({bus2_location}정류장)'
        else:
            msg += f'다음 버스: {bus2}'

        if int(minute) == 300:
            requests.get(api_url + f'/sendMessage?chat_id={chat_id}&text={msg}')

        elif int(bus1_minute) <= int(minute):
            requests.get(api_url + f'/sendMessage?chat_id={chat_id}&text={msg}')
else:
    msg = 'DB 읽는 도중 에러가 발생했습니다.\n' \
          '버스를 다시 등록해주세요.'
    requests.get(api_url + f'/sendMessage?chat_id={chat_id}&text={msg}')
    # else:
    #     msg = f'test predict={predict1}, minute={minute}'
    #     requests.get(api_url + f'/sendMessage?chat_id={chat_id}&text={msg}')

# if __name__ == '__main__':
#     path = os.path.dirname(__file__)
#     from .models import BusGo, BusOut


import io
import os
import random

import boto3
import tornado.testing

from service.s3_object import S3Object

class TestS3Object(tornado.testing.AsyncTestCase):
    def setUp(self):
        super().setUp()

        self.s3_object = S3Object(os.environ["AWS_S3_BUCKET"], os.environ["AWS_S3_OBJECT"])

        self.expected_contents = f"data-{random.random()}".encode("utf8")

    @tornado.testing.gen_test
    async def test_download_returns_contents_of_s3_object(self):
        boto3.resource("s3").Bucket(os.environ["AWS_S3_BUCKET"]).upload_fileobj(
            Key=os.environ["AWS_S3_OBJECT"],
            Fileobj=io.BytesIO(self.expected_contents))

        contents = await self.s3_object.download()

        self.assertEqual(self.expected_contents, contents)

    @tornado.testing.gen_test
    async def test_upload_sets_contents_of_s3_object(self):
        await self.s3_object.upload(self.expected_contents)

        contents = io.BytesIO()
        boto3.resource("s3").Bucket(os.environ["AWS_S3_BUCKET"]).download_fileobj(
            Key=os.environ["AWS_S3_OBJECT"],
            Fileobj=contents)
        self.assertEqual(self.expected_contents, contents.getvalue())


def solution(skill, skill_trees):
    answer = 0
    for i in range(len(skill_trees)):
        learned = skill_trees[i]
        order = 0
        pre_order = True
        for book in skill:
            if book in learned:
                where = learned.index(book)
                if where >= order and pre_order:
                    order = where
                else:
                    break
            else:
                pre_order = False
        else:
            answer += 1
    return answer

skill = "CBD"
skill_trees =["BACDE", "CBADF", "AECB", "BDA"]
print(solution(skill, skill_trees))


# coding: utf-8
import pybullet as p
p.connect(p.GUI)
floor_shape = p.createCollisionShape(p.GEOM_PLANE)
floor = p.createMultiBody(floor_shape, floor_shape)
box_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[1,1,1])
box = p.createMultiBody(box_shape, box_shape)
p.setGravity(0,0,-10)
p.setRealtimeSimulation(1)
p.setRealTimeSimulation(1)
import pybullet_data as pd
pd.getDataPath()
robot = p.loadURDF(pd.getDataPath() + '/soccerball.urdf')
robot = p.loadURDF(pd.getDataPath() + '/r2d2.urdf')
rob1 = p.loadURDF('first.urdf')
get_ipython().run_line_magic('more', 'first.urdf')
rob1 = p.loadURDF('first.urdf')
p.setPhysicsEngineParameter(enableFileCaching=0)
rob1 = p.loadURDF('first.urdf')
p.setJountMotorControl2(rob1, 0, controlMode=p.VELOCITY_CONTROL, targetVelocity=1)
p.setJointMotorControl2(rob1, 0, controlMode=p.VELOCITY_CONTROL, targetVelocity=1)
p.setJointMotorControl2(rob1, 0, controlMode=p.VELOCITY_CONTROL, targetVelocity=100000)
rob1 = p.loadURDF('first.urdf')
p.setJointMotorControl2(rob1, 0, controlMode=p.VELOCITY_CONTROL, targetVelocity=100000)
rob1 = p.loadURDF('first.urdf')
p.setJointMotorControl2(rob1, 0, controlMode=p.VELOCITY_CONTROL, targetVelocity=1)
p.setJointMotorControl2(rob1, 0, controlMode=p.VELOCITY_CONTROL, targetVelocity=2)


from pathlib import Path
from typing import Optional, Tuple, Union

import numpy as np
import tensorflow as tf
from skimage.io import imread
from tqdm import tqdm

from utils.utils import color_classes

SUPPORTED_IMAGE_TYPES = [".tif", ".tiff", ".png", ".jpg", ".jpeg", ".bmp"]

def reset_class_values(mask: np.ndarray) -> np.ndarray:
    """Reset the mask values corresponding to classes to start from zero.

    Args:
        mask (np.ndarray): The mask to have its values reset.

    Returns:
        np.ndarray: The reset mask.
    """
    reset_image = np.zeros(mask.shape[:2], dtype=np.uint8)
    for i in range(mask.shape[-1]):
        reset_image[:, :][mask[:, :, i] > 0] = i

    return reset_image

def one_hot_encode(image: Union[np.ndarray, tf.Tensor], classes: int, as_numpy: Optional[bool] = False) -> tf.Tensor:
    """Converts an image to the one-hot-encode format.

    Args:
        image (Union[np.ndarray, tf.Tensor]): The image to be converted.
        classes (int): The number of classes in the image. Each class will be put in a dimension.
        as_numpy: (Optional[bool], optional): Whether to return the listed files as Numpy comparable objects.

    Raises:
        TypeError: If the type of `image` is not `np.ndarray` or `tf.Tensor`.

    Returns:
        tf.Tensor: The one-hot-encoded image.
    """
    if isinstance(image, np.ndarray):
        one_hot_encoded = np.zeros(image.shape[:2] + (classes,), dtype=np.uint8)
        for unique_value in enumerate(np.unique(image)):
            one_hot_encoded[:, :, unique_value][image == unique_value] = 1
        return one_hot_encoded
    elif isinstance(image, tf.Tensor):
        image = tf.cast(image, dtype=tf.int32)
        image = tf.one_hot(image, depth=classes, axis=2, dtype=tf.int32)
        image = tf.squeeze(image)
        image = tf.cast(image, dtype=tf.float32)

        if as_numpy:
            image = image.numpy()

        return image
    else:
        raise TypeError(f"Argument `image` should be `np.ndarray` or `tf.Tensor. Given `{type(image)}`.")

def normalize_image(image: tf.Tensor) -> tf.Tensor:
    """Normalize image in range [0, 1].

    Args:
        image (tf.Tensor): The imput image.

    Returns:
        tf.Tensor: Normalized image.
    """
    image = tf.cast(image, dtype=tf.float32)

    min = tf.reduce_min(image)
    max = tf.reduce_max(image)

    image = (image - min) / (max - min)

    return image

def load_image(
    image_path: Union[str, tf.Tensor],
    shape: Tuple[int, int] = None,
    normalize: Optional[bool] = False,
    as_gray: Optional[bool] = False,
    as_numpy: Optional[bool] = False,
    return_original_shape: Optional[bool] = False) -> tf.Tensor:
    """Read an image from the storage media.

    Args:
        image_path (Union[str, tf.Tensor]): The path to the image file.
        shape (Tuple[int, int], optional): Shape the read image should have after reading it, in the format (HEIGHT, WIDTH). If `None`, the shape will not be changed. Defaults to None.
        normalize (Optional[bool], optional): Whether or not to put the image values between zero and one ([0,1]). Defaults to False.
        as_gray (Optional[bool], optional): Whether or not to read the image in grayscale. Defaults to False.
        as_numpy: (Optional[bool], optional): Whether to return the listed files as Numpy comparable objects.
        return_original_shape: (Optional[bool], optional): Whether to return the original shape of the image. Defaults to False.

    Raises:
        TypeError: If the image type is not supported.
        FileNotFoundError: If `image_path` does not point to a file.
        TypeError: If `image_path` is not a `str` or `tf.Tensor` object.

    Returns:
        tf.Tensor: The read image.
    """
    original_shape = None

    if isinstance(image_path, str):
        image_path = Path(image_path)

        if image_path.is_file():
            if image_path.suffix not in SUPPORTED_IMAGE_TYPES:
                raise TypeError(f"Image type `{image_path.suffix}` not supported.\
                    The supported types are `{', '.join(SUPPORTED_IMAGE_TYPES)}`.")
            else:
                channels = 1 if as_gray else 3

                if image_path.suffix in [".tif", ".tiff"]:
                    image = imread(str(image_path), as_gray=as_gray)
                    original_shape = image.shape
                    image = tf.convert_to_tensor(image, dtype=tf.float32)
                else:
                    image = tf.io.read_file(str(image_path))
                    image = tf.image.decode_png(image, channels=channels)
                    original_shape = tuple(image.shape.as_list())

                if shape:
                    if shape != image.shape[:2]:
                        if "mask" in image_path.stem:
                            image = tf.image.resize(image, shape, method="nearest")
                        else:
                            image = tf.image.resize(image, shape, method="bilinear")

                if normalize:
                    image = normalize_image(image)

                if as_numpy:
                    image = image.numpy()

                    if as_gray:
                        image = image[:, :, 0]

                if return_original_shape:
                    return image, original_shape
                else:
                    return image
        else:
            raise FileNotFoundError(f"The file `{image_path}` was not found.")
    elif isinstance(image_path, tf.Tensor):
        channels = 1 if as_gray else 3
        image = tf.io.read_file(image_path)
        image = tf.image.decode_png(image, channels=channels)

        original_shape = tuple(image.shape.as_list())

        if shape:
            if shape != image.shape[:2]:
                image = tf.image.resize(image, shape, method="nearest")

        if normalize:
            image = tf.cast(image, dtype=tf.float32)
            image = image / 255.

        if return_original_shape:
            return image, original_shape
        else:
            return image
    else:
        raise TypeError("Object `{image_path}` is not supported.")

def list_files(
    files_path: str,
    as_numpy: Optional[bool] = False,
    file_types: Optional[list] = SUPPORTED_IMAGE_TYPES,
    seed: Optional[int] = 1234) -> tf.raw_ops.ShuffleDataset:
    """Lists files under `files_path`.

    Args:
        files_path (str): The path to the directory containing the files to be listed.
        as_numpy: (Optional[bool], optional): Whether to return the listed files as Numpy comparable objects.
        seed (Optional[int], optional): A seed used to shuffle the listed files. Note: If listing images and segmentation masks, the same seed must be used. Defaults to 1234.

    Raises:
        RuntimeError: If no files are found under `files_path`.
        FileNotFoundError: If `files_path` is not a directory.

    Returns:
        tf.raw_ops.ShuffleDataset: The listed files.
    """
    if Path(files_path).is_dir():
        patterns = [str(Path(files_path).joinpath(f"*{image_type}")) for image_type in file_types]
        files_list = tf.data.Dataset.list_files(patterns, shuffle=True, seed=seed)

        if len(files_list) == 0:
            raise RuntimeError(f"No files were found at `{files_path}`.")

        if as_numpy:
            files_list = [file.numpy().decode("utf-8") for file in files_list]
            files_list.sort()

        return files_list
    else:
        raise FileNotFoundError(f"The directory `{files_path}` does not exist.")

def load_dataset_files(
    image_path: Union[str, tf.Tensor],
    mask_path: Union[str, tf.Tensor],
    shape: Tuple[int, int],
    classes: int,
    mask_one_hot_encoded: Optional[bool] = True) -> Tuple[tf.Tensor, tf.Tensor]:
    """Load an image and a segmentation mask.

    Args:
        image_path (Union[str, tf.string, tf.Tensor]): The path to the image file.
        mask_path (Union[str, tf.string, tf.Tensor]): The path to the mask file.
        shape (Tuple[int, int]): The shape the loaded images and mask should have, in the format (HEIGHT, WIDTH).
        classes (int): The number of classes contained in the segmentation mask. It affects the one-hot-encoding of the mask.
        mask_one_hot_encoded (Optional[bool], optional): Whether or not to one-hot-encode the segmentation mask. Defaults to True.

    Returns:
        Tuple[tf.Tensor, tf.Tensor]: The loaded image and mask.
    """
    image = load_image(image_path, shape=shape, normalize=False)
    mask = load_image(mask_path, shape=shape, as_gray=True)

    if mask_one_hot_encoded:
        mask = one_hot_encode(mask, classes=classes)

    return image, mask

def augment_dataset(
    image: tf.Tensor,
    mask: tf.Tensor,
    threshold: Optional[float] = 0.5,
    brightness_delta: Optional[float] = 0.2,
    contrast_lower: Optional[float] = 0.6,
    contrast_upper: Optional[float] = 1.6,
    hue_delta: Optional[float] = 0.2,
    saturation_lower: Optional[float] = 0.6,
    saturation_upper: Optional[float] = 1.6) -> Tuple[tf.Tensor, tf.Tensor]:
    """
    Applies data augmentation techniques to an image and its corresponding mask.

    Args:
        image (tf.Tensor): The input image tensor.
        mask (tf.Tensor): The corresponding mask tensor.
        threshold (float, optional): The threshold value for determining if augmentation should be applied. If the randomly generated probability is greater than the threshold, augmentation is applied.Defaults to 0.5.
        brightness_delta (float, optional): The maximum delta value for adjusting the brightness of the image.Defaults to 0.4.
        contrast_lower (float, optional): The lower bound for adjusting the contrast of the image. Defaults to 0.6.
        contrast_upper (float, optional): The upper bound for adjusting the contrast of the image. Defaults to 1.6.
        hue_delta (float, optional): The maximum delta value for adjusting the hue of the image. Defaults to 0.2.
        saturation_lower (float, optional): The lower bound for adjusting the saturation of the image. Defaults to 0.6.
        saturation_upper (float, optional): The upper bound for adjusting the saturation of the image. Defaults to 1.6.

    Returns:
        Tuple[tf.Tensor, tf.Tensor]: A tuple containing the augmented image and its corresponding mask tensor.
    """
    probability = tf.random.uniform(shape=[], minval=0.0, maxval=1.0, dtype=tf.float32)
    if probability > threshold:
        image = tf.image.flip_left_right(image)
        mask = tf.image.flip_left_right(mask)

    probability = tf.random.uniform(shape=[], minval=0.0, maxval=1.0, dtype=tf.float32)
    if probability > threshold:
        image = tf.image.flip_up_down(image)
        mask = tf.image.flip_up_down(mask)

    seed = tf.random.uniform(shape=[2], maxval=10000, dtype=tf.int32)

    probability = tf.random.uniform(shape=[], minval=0.0, maxval=1.0, dtype=tf.float32)
    if probability > threshold:
        image = tf.image.stateless_random_brightness(image, brightness_delta, seed=seed)

    probability = tf.random.uniform(shape=[], minval=0.0, maxval=1.0, dtype=tf.float32)
    if probability > threshold:
        image = tf.image.stateless_random_contrast(image, contrast_lower, contrast_upper, seed=seed)

    probability = tf.random.uniform(shape=[], minval=0.0, maxval=1.0, dtype=tf.float32)
    if probability > threshold:
        image = tf.image.stateless_random_hue(image, hue_delta, seed=seed)

    probability = tf.random.uniform(shape=[], minval=0.0, maxval=1.0, dtype=tf.float32)
    if probability > threshold:
        image = tf.image.stateless_random_saturation(image, saturation_lower, saturation_upper, seed=seed)

    return image, mask

def load_dataset(
    dataset_path: str,
    batch_size: Optional[int] = 1,
    shape: Tuple[int, int] = (1920, 2560),
    classes: Optional[int] = 3,
    mask_one_hot_encoded: Optional[bool] = True,
    repeat: Optional[bool] = False,
    shuffle: Optional[bool] = True,
    augment: Optional[bool] = False) -> tf.data.Dataset:
    """Loads a `tf.data.Dataset`.

    Args:
        dataset_path (str): The path to the directory containing a subdirectory name `images` and another `masks`.
        batch_size (Optional[int], optional): The number of elements per batch. Defaults to 1.
        shape (Tuple[int, int], optional): The shape the loaded images should have, in the format `(HEIGHT, WIDTH)`. Defaults to (1920, 2560).
        classes (Optional[int], optional): The number of classes in the masks. Defaults to 3.
        mask_one_hot_encoded (Optional[bool], optional): Converts the masks to one-hot-encoded masks, where one dimension is added per class, and each dimension is a binary mask of that class. Defaults to True.
        repeat (Optional[bool], optional): Whether the dataset should be infinite or not. Defaults to False.
        shuffle (Optional[bool], optional): Whether to shuffle the loaded elements. Defaults to True.
        augment (Optional[bool], optional): Whether to apply augmentation to the dataset. Defaults to False.

    Raises:
        FileNotFoundError: In case the dataset path does not exist.
        FileNotFoundError: In case the directory `images` under the dataset path does not exist.
        FileNotFoundError: In case the directory `masks` under the dataset path does not exist.

    Returns:
        tf.data.Dataset: The loaded dataset.
    """
    dataset_path = Path(dataset_path)
    if dataset_path.is_dir():
        images_path = dataset_path.joinpath("images")
        masks_path = dataset_path.joinpath("masks")

        if not images_path.is_dir():
            raise FileNotFoundError(f"The directory `{str(images_path)}` does not exist.")
        if not masks_path.is_dir():
            raise FileNotFoundError(f"The directory `{str(masks_path)}` does not exist.")

        images_list = list_files(str(images_path))
        masks_list = list_files(str(masks_path))

        dataset = tf.data.Dataset.zip((images_list, masks_list))

        dataset = dataset.cache()

        dataset = dataset.map(
            lambda image_path, mask_path: load_dataset_files(
                image_path=image_path,
                mask_path=mask_path,
                shape=shape,
                classes=classes,
                mask_one_hot_encoded=mask_one_hot_encoded
            )
        )

        if augment:
            dataset = dataset.map(augment_dataset, num_parallel_calls=tf.data.AUTOTUNE)

        def apply_normalization(image: tf.Tensor, mask: tf.Tensor):
            image = normalize_image(image)
            return image, mask

        dataset = dataset.map(apply_normalization)

        dataset = dataset.batch(batch_size)
        dataset = dataset.prefetch(buffer_size=tf.data.AUTOTUNE)

        if shuffle:
            dataset = dataset.shuffle(buffer_size=batch_size * batch_size, reshuffle_each_iteration=True)

        if repeat:
            dataset = dataset.repeat()

        return dataset
    else:
        raise FileNotFoundError(f"The directory `{str(dataset_path)}` does not exist.")

def write_dataset(
    dataset: tf.data.Dataset,
    batches: Optional[int] = None,
    output_path: Optional[str] = "dataset_visualization",
    rgb_masks: Optional[bool] = True) -> None:
    """Write to disk a given `tf.data.Dataset`.

    Args:
        dataset (tf.data.Dataset): The dataset to be written, in the format `((None, HEIGHT, WIDTH, CHANNELS), (None, HEIGHT, WIDTH, CLASSES))`.
        batches (Optional[int], optional): The number of batches of the dataset to write. Defaults to None.
        output_path (Optional[str], optional): The path where to save the written items of the dataset.. Defaults to "dataset_visualization".
        rgb_masks (Optional[bool], optional): Whether to write the masks as RGB images. Defaults to True.
    """
    output = Path(output_path)
    images_path = output.joinpath("images")
    masks_path = output.joinpath("masks")

    images_path.mkdir(exist_ok=True, parents=True)
    masks_path.mkdir(exist_ok=True, parents=True)

    if not batches:
        try:
            batches = len(dataset)
        except Exception:
            batches = 1
            print("It was not possible to determine the number of batches in the dataset, writing only one.")
    else:
        batches = max(0, batches)

    for i, batch in tqdm(enumerate(dataset), total=batches):
        for j, (image, mask) in enumerate(zip(batch[0], batch[1])):

            image_name = str(images_path.joinpath(f"batch_{i}_image_{j}.png"))
            mask_name = str(masks_path.joinpath(f"batch_{i}_mask_{j}.png"))

            tf.keras.preprocessing.image.save_img(image_name, image)

            if not rgb_masks:
                mask = tf.image.rgb_to_grayscale(mask)
                for new_intensity, intensity in enumerate(np.unique(mask)):
                    mask = np.where(mask == intensity, new_intensity, mask)

            mask = color_classes(mask.numpy())
            tf.keras.preprocessing.image.save_img(mask_name, mask, scale=False)

        if i == batches:
            break


from django.conf import settings
from django.urls import reverse
from auth.models import CustomUser as User
from utils.graphing import plot
from utils import DEFAULT_PROTOCOL
from utils.translation import get_language_label
from datetime import datetime
from django.utils.timezone import utc

def compute_statistics(team, stats_type):
    """computes a bunch of statistics for the team, either at
    the video or member levels.
    """
    from views import TableCell
    summary = ''
    graph = ''
    graph_recent = ''
    summary_recent = ''
    graph_additional = ''
    graph_additional_recent = ''
    summary_additional = ''
    summary_additional_recent = ''
    summary_table = ''
    if stats_type == 'videosstats':
        (complete_languages, incomplete_languages) = team.get_team_languages()
        languages = complete_languages + incomplete_languages
        unique_languages = set(languages)
        total = 0
        numbers = []
        y_title = "Number of edited subtitles"
        for l in unique_languages:
            count_complete = complete_languages.count(l)
            count_incomplete = incomplete_languages.count(l)
            numbers.append((get_language_label(l), count_complete + count_incomplete, "Published: %s, total edits:" % count_complete))
            total += count_complete + count_incomplete
        summary = 'Top languages (all time)'
        title = ""
        graph = plot(numbers, title=title, graph_type='HorizontalBar', labels=True, max_entries=20, y_title=y_title)

        (complete_languages_recent, incomplete_languages_recent, new_languages) = team.get_team_languages(since=30)
        languages_recent = complete_languages_recent + incomplete_languages_recent
        unique_languages_recent = set(languages_recent)
        summary_recent = "Top languages (past 30 days)"
        numbers_recent = []
        total_recent = 0
        for l in unique_languages_recent:
            count_complete_recent = complete_languages_recent.count(l)
            count_incomplete_recent = incomplete_languages_recent.count(l)
            numbers_recent.append((get_language_label(l), count_complete_recent + count_incomplete_recent, "Published: %s, total edits:" % count_complete_recent))
            total_recent += count_complete_recent + count_incomplete_recent
        title_recent = ""
        graph_recent = plot(numbers_recent, title=title_recent, graph_type='HorizontalBar', labels=True, max_entries=20, y_title=y_title)

        summary_table = []
        summary_table.append([TableCell("", header=True), TableCell("all time", header=True), TableCell("past 30 days", header=True)])
        summary_table.append([TableCell("videos added", header=True), TableCell(str(team.videos_count)), TableCell(str(team.videos_count_since(30)))])
        summary_table.append([TableCell("languages edited", header=True), TableCell(str(len(unique_languages))), TableCell(str(len(unique_languages_recent)))])
        summary_table.append([TableCell("subtitles edited", header=True), TableCell(str(total)), TableCell(str(total_recent))])

    elif stats_type == 'teamstats':
        languages = list(team.languages())
        unique_languages = set(languages)
        summary = u'Members by language (all time)'
        numbers = []
        for l in unique_languages:
            numbers.append((get_language_label(l), languages.count(l),
                            get_language_label(l)))
        title = ''
        graph = plot(numbers, graph_type='HorizontalBar', title=title, max_entries=25, labels=True, total_label="Members: ")
        languages_recent = list(team.languages(members_joined_since=30))
        unique_languages_recent = set(languages_recent)
        summary_recent = u'New members by language (past 30 days)'
        numbers_recent = []
        for l in unique_languages_recent:
            numbers_recent.append(
                (get_language_label(l),
                 languages_recent.count(l),
                 get_language_label(l),
                 "%s://%s%s" % (DEFAULT_PROTOCOL, settings.HOSTNAME, reverse('teams:members', args=[], kwargs={'slug': team.slug}) + "?sort=-joined&lang=%s" % l))
                )
        title_recent = ''
        graph_recent = plot(numbers_recent, graph_type='HorizontalBar', title=title_recent, max_entries=25, labels=True, xlinks=True, total_label="Members: ")

        summary_table = []
        summary_table.append([TableCell("", header=True), TableCell("all time", header=True), TableCell("past 30 days", header=True)])
        summary_table.append([TableCell("members joined", header=True), TableCell(str(team.members_count)), TableCell(str(team.members_count_since(30)))])
        summary_table.append([TableCell("member languages", header=True), TableCell(str(len(unique_languages))), TableCell(str(len(unique_languages_recent)))])

        active_users = {}
        for sv in team.active_users():
            if sv[0] in active_users:
                active_users[sv[0]].add(sv[1])
            else:
                active_users[sv[0]] = set([sv[1]])

        most_active_users = active_users.items()
        most_active_users.sort(reverse=True, key=lambda x: len(x[1]))
        if len(most_active_users) > 20:
            most_active_users = most_active_users[:20]

        active_users_recent = {}
        for sv in team.active_users(since=30):
            if sv[0] in active_users_recent:
                active_users_recent[sv[0]].add(sv[1])
            else:
                active_users_recent[sv[0]] = set([sv[1]])

        most_active_users_recent = active_users_recent.items()
        most_active_users_recent.sort(reverse=True, key=lambda x: len(x[1]))
        if len(most_active_users_recent) > 20:
            most_active_users_recent = most_active_users_recent[:20]

        def displayable_user(user, users_details):
            user_details = users_details[user[0]]
            return ("%s %s (%s)" % (user_details[1], user_details[2], user_details[3]),
                    len(user[1]),
                    "%s %s (%s)" % (user_details[1], user_details[2], user_details[3]),
                    "%s://%s%s" % (DEFAULT_PROTOCOL, settings.HOSTNAME, reverse("profiles:profile", kwargs={'user_id': str(user[0])}))
            )

        user_details = User.displayable_users(map(lambda x: int(x[0]), most_active_users))
        user_details_dict = {}
        for user in user_details:
            user_details_dict[user[0]] = user

        most_active_users = map(lambda x: displayable_user(x, user_details_dict), most_active_users)

        summary_additional = u'Top contributors (all time)'
        graph_additional = plot(most_active_users, graph_type='HorizontalBar', title='', labels=True, xlinks=True, total_label="Contributions: ")

        user_details_recent = User.displayable_users(map(lambda x: int(x[0]), most_active_users_recent))
        user_details_dict_recent = {}
        for user in user_details_recent:
            user_details_dict_recent[user[0]] = user

        most_active_users_recent = map(lambda x: displayable_user(x, user_details_dict_recent), most_active_users_recent)

        summary_additional_recent = u'Top contributors (past 30 days)'
        graph_additional_recent = plot(most_active_users_recent, graph_type='HorizontalBar', title='', labels=True, xlinks=True, total_label="Contributions: ")

    statistics = {
        'computed_on': datetime.utcnow().replace(tzinfo=utc).strftime("%A %d. %B %Y %H:%M:%S UTC"),
        'summary': summary,
        'summary_recent': summary_recent,
        'activity_tab': stats_type,
        'graph': graph,
        'graph_recent': graph_recent,
        'graph_additional': graph_additional,
        'graph_additional_recent': graph_additional_recent,
        'summary_additional': summary_additional,
        'summary_additional_recent': summary_additional_recent,
        'summary_table': summary_table,
    }
    return statistics


import ocifs
import pandas as pd

# per la confusion matrix ed altre metriche uso sklearn
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import roc_auc_score
from sklearn.metrics import recall_score
from sklearn.metrics import precision_score
from sklearn.metrics import accuracy_score

SEED = 42

#
# read the csv from Object storage and return a pandas df
#
def read_from_object_storage(prefix, file_name):
    # get access to OSS as an fs
    # config={} assume RESOURCE PRINCIPAL auth
    fs = ocifs.OCIFileSystem(config={})

    FILE_PATH = prefix + file_name

    # reading data from Object Storage
    with fs.open(FILE_PATH, 'rb') as f:
        df = pd.read_csv(f)

    return df

#
# compute the number of distinct values for each column of the df
#
def compute_distinct(data, columns):
    l_count = []
    for col in columns:
        l_count.append(data[col].nunique())

    count_dict = {}
    count_dict['col'] = columns
    count_dict['count'] = l_count

    count_df = pd.DataFrame(count_dict)

    return count_df

#
# my split in train, test set
#
def my_train_test_split(df, frac):
    # frac: the fraction used for train
    # df: the dataframe

    # shuffle before split
    df = df.sample(frac=1., random_state=SEED)

    # FRAC = 0.90
    tot_rec = df.shape[0]
    NUM_TRAIN = int(frac*tot_rec)
    NUM_TEST = tot_rec - NUM_TRAIN

    data_train = df[:NUM_TRAIN]
    data_test = df[NUM_TRAIN:]

    print()
    print('Numero totale di campioni:', tot_rec)
    print('Numero di campioni nel TRAIN SET:', data_train.shape[0])
    print('Numero di campioni nel TEST SET:', data_test.shape[0])

    return data_train, data_test

#
# easy plot of the confusion matrix
#
def plot_cm(model, x_test, y_test):
    y_pred_labels = model.predict(x_test)
    cm = confusion_matrix(y_test, y_pred_labels)
    disp = ConfusionMatrixDisplay(confusion_matrix=cm)
    disp.plot();

#
# Compute metrics
#
def compute_auc(model, x_test, y_test):
    y_pred = model.predict_proba(x_test)
    y_pred = y_pred[:, 1]
    auc = round(roc_auc_score(y_test, y_pred), 4)

    return auc

def compute_prec_rec(model, x_test, y_test):
    y_pred_labels = model.predict(x_test)

    rec = round(recall_score(y_test, y_pred_labels), 4)
    prec = round(precision_score(y_test, y_pred_labels), 4)

    return prec, rec

def compute_accuracy(model, x_test, y_test):
    y_pred_labels = model.predict(x_test)
    acc = accuracy_score(y_test, y_pred_labels)

    return round(acc, 3)


#coding:utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.webdriver.chrome.options import Options
import time
import sys

class WhatsApp :
    "La class du bot whatsapp "
    def connect(self) :

        self.driver = webdriver.Firefox()
        self.driver.get("https://web.whatsapp.com/")
        input('Taper Entrer après le scannage du code Qr')

        self.driver.implicitly_wait(10)
        time.sleep(10.1)
        try :
            self.attente = WebDriverWait(driver, 10)
            self.element = self.attente.until(EC.element_to_be_clickable((By.XPATH,'/html/body/div[1]/div/div/div[3]/div/div[1]/div/button')))
        except :
            time.sleep(10.10)
            print('chargement complet de la page en cours ')
        print("Vous êtes connecté !")

    def SendMessage(self) :

        def Contact() :#SearchContact.send_keys(contact)
            XpathS = "//input[@title='Rechercher ou démarrer une nouvelle discussion']"
            contact = input('Enter le nom de votre contact __-> ')
            print("Tentatif de recherche de votre contact")
            self.driver.implicitly_wait(5)
            SearchContact = self.driver.find_element_by_xpath(XpathS)
            SearchContact.click()
            self.driver.implicitly_wait(30)
            print('typologie')
            SearchContact.send_keys(Keys.CONTROL + contact)
        Contact()

    def personal_Message(self) :

            driver = self.driver

            Message = "c'est gratuit chef  !"
            try:
                attente = WebDriverWait(driver, 125)
                self.element = attente.until(EC.element_to_be_clickable((By.XPATH, '//span[@title = "{}"]'.format('Rostant'))))
            except Exception :
                print("Domm1 !")

            dest = driver.find_element_by_xpath('//span[@title = "{}"]'.format('Rostant')) #Le Destinatair du Message
            dest.click()
            Message_input = driver.find_element_by_xpath('/html/body/div[1]/div/div/div[4]/div/footer/div[1]/div[2]/div/div[2]')
            Message_input.send_keys(Message)
            try:
                elem = WebDriverWait(driver, 125)
                self.poil = attente.until(EC.element_to_be_clickable((By.XPATH, '/html/body/div[1]/div/div/div[4]/div/footer/div[1]/div[3]/button')))
            except Exception :
                print("Domm2 !")
            driver.find_element_by_xpath('/html/body/div[1]/div/div/div[4]/div/footer/div[1]/div[3]/button').click()

    def disconnect(self) :

        driver = self.driver
        driver.close()

bot = WhatsApp()
bot.SendMessage()

"""contact = input("Enter le nom ")
text = input("Entrer le message !")
driver = webdriver.Firefox()
driver.get("https://web.whatsapp.com")
print("Scan QR Code, And then Enter")
input()
print("Logged In")
inp_xpath_search = "//input[@title='Rechercher ou démarrer une nouvelle discussion']"
input_box_search = WebDriverWait(driver,50).until(lambda driver: driver.find_element_by_xpath(inp_xpath_search))
input_box_search.click()
time.sleep(2)
input_box_search.send_keys(contact)
time.sleep(2)
selected_contact = driver.find_element_by_xpath("//span[@title='"+contact+"']")
selected_contact.click()
inp_xpath = '//div[@class="_2S1VP copyable-text selectable-text"][@contenteditable="true"][@data-tab="1"]'
input_box = driver.find_element_by_xpath(inp_xpath)
time.sleep(2)
input_box.send_keys(text + Keys.ENTER)
time.sleep(2)"""


# %% Multivariate distribution
#
# In this example a multivariate distribution |z| with expectation |mu| and co-variance matrix |Sigma| (Qyy) is simulated.
# We use the Choleski decomposition to factor the co-variance matrix,  such that |Sigma = R*R'|, with |R| the Choleski factor.

# %% importing libraries
import numpy as np
import matplotlib.pyplot as plt

# %%
mu = np.array([1, 2])
sigma = np.array([[1, 0.5], [0.5, 2]])

# %%
# Cholesky factor
R = np.linalg.cholesky(sigma)
# Generate samples (why numpy.kron?)
z = np.kron(np.ones((10000, 1)), mu) + np.dot(np.random.randn(10000, 2), R)

# %%
plt.figure(figsize=(6, 6))
plt.plot(z[:, 0], z[:, 1], '.')
plt.axis('equal')
plt.xlabel(r'$z_1$')
plt.ylabel(r'$z_2$')
plt.title('Multivariate')