#!/usr/bin/python3

import requests
import json
import atexit
import time
import unicodedata
import random
import os
from tokens import *
from game import *

def get_name(user):
	if ('username' in user):
		return user['username']
	else:
		return user['first_name'] + " " + user['last_name']

def from_json(s):
	s = s.replace("'", "\"")
	return json.loads(s)

def get_params(s, command):
	pos = s.find(command) + len(command)
	s = s[pos:]
	return s.split()

def get_command(s):
	pos = s.find("/") + 1
	if (pos == 0):
		return ""
	res = "/"
	while (pos < len(s) and unicodedata.category(s[pos]) in ('Ll', 'Pc')):
		res += s[pos]
		pos += 1
	return res

def suffix(s, command):
	pos = s.find(command) + len(command)
	return s[min(pos + 1, len(s)):]

WRONG_MESSAGE_RESPONSE = "Я тебя не понимаю :("
HELP_MESSAGE = "Хэлп"
CANT_CHANGE_NAME_MESSAGE = "Менять имя можно только тогда, когда этого никто не видит"
WRONG_CHARECTERS_IN_NAME_MESSAGE = "Имя может содержать только буквы и цифры"
ALREADY_IN_GAME_MESSAGE = "Сначала выйди из текущей игры (/leave)"

def text_message(text):
	return {'command' : 'sendMessage', 'text' : text}

def markdown_message(text):
	return {'command' : 'sendMessage', 'parse_mode' : 'Markdown', 'text' : text}

def correct(s):
	for c in s:
		cat = unicodedata.category(c)
		if cat not in ('Ll', 'Lu', 'Lo', 'Nd', 'Zs'):
			return 0
	return 1

class chat_with_bot:

	def __init__(self, _id, _url, _token, _name):
		self.id = _id
		self.rev = 0
		self.url = _url
		self.token = _token
		self.name = _name
		self.game_id = -1
		self.waiting_for_file = 0

	def setparams(self, string):
		params = from_json(string)
		self.name = params['name']
		#self.game_id = params['game_id']!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

	def __str__(self):
		params = {'name' : self.name, 'game_id' : self.game_id}
		return str(params)

class game_group:

	def __init__(self, _id, _admin_id, _is_private, _params):
		self.game_id = _id
		self.players = [_admin_id]
		self.whose_turn = -1
		self.last_turn_time = -1
		self.is_private = _is_private
		self.params = _params
		self.filename = ""
		self.players_cnt = 1
		self.tl = DEFALUT_TL
		self.started = 0

	def join(self, player_id):
		self.players.append(player_id)
		self.players_cnt += 1

	def leave(self, player_id):
		self.players_cnt -= 1
		if (self.whose_turn == -1):
			self.players.remove(player_id)
		else:
			for i in range(len(self.players)):
				if (self.players[i] == player_id):
					self.players[i] = 0

	def isadmin(self, player_id):
		if (self.players[0] == player_id):
			return 1
		else:
			return 0

	def make_next_turn(self):
		self.whose_turn = (self.whose_turn + 1) % self.all_players_cnt
		self.last_turn_time = time.time()

	def start(self, names):
		self.game = game(self.params, self.filename, self.players_cnt, names)
		self.started = 1
		self.whose_turn = 0
		self.last_turn_time = int(time.time())
		self.all_players_cnt = len(self.players)

MAX_GAME_ID = 100000

class telegram_bot:

	def load_from_file(self):
		try:
			f = open(self.name + ".botconfig", 'r')
		except:
			return
		x = f.readlines()
		for i in range(len(x)):
			x[i] = x[i][:len(x[i]) - 1]
		self.last_update = int(x[1])
		founded_chats = json.loads(x[2])
		for chat in founded_chats:
			self.chats[chat[0]] = chat_with_bot(chat[0], self.url, self.token, "")
			self.chats[chat[0]].setparams(chat[1])
			self.all_names.add(self.chats[chat[0]].name)

	def __init__(self, _token, _name):
		self.token = _token
		self.name = _name
		self.url = "https://api.telegram.org/bot" + self.token + "/"
		self.chats = {}
		self.games = {}
		self.last_update = -1
		self.all_names = set()
		self.load_from_file()

	def get_updates(self):
		if (self.last_update == -1):
			response = requests.get(self.url + "getUpdates")
		else:
			data = {'timeout' : 5, 'offset' : self.last_update + 1}
			response = requests.get(self.url + "getUpdates", params = data)
		return response.json()['result']

	def get_new_messages(self):
		upd = self.get_updates()
		res = []
		for i in range(1, len(upd) + 1):
			if (upd[-i]['update_id'] > self.last_update):
				if ('message' in upd[-i]):
					message = upd[-i]['message']
					chat_id = message['chat']['id']
					if (chat_id >= 0):
						res.append(message)
						if (chat_id not in self.chats):
							self.chats[chat_id] = chat_with_bot(chat_id, self.url, self.token, get_name(message['from']))
			else:
				break
		if (len(upd) > 0):
			self.last_update = upd[-1]['update_id']
		return res

	def send_command(self, response_element, chat_id):
		command = response_element['command']
		response_element.pop('command')
		params = response_element
		params['chat_id'] = chat_id
		requests.post(self.url + command, data = params)

	def game_event_handler(self, game_id, event, chat_id):
		players = self.games[game_id].players
		for player_id in players:
			if (player_id == 0):
				continue
			if ('all_message' in event):
				self.send_command(markdown_message(event['all_message']), player_id)
			if (('public_message' in event) and (player_id != chat_id)):
				self.send_command(markdown_message(event['public_message']), player_id)
			if (('private_message' in event) and (player_id == chat_id)):
				self.send_command(markdown_message(event['private_message']), player_id)

	def create_game(self, player_id, is_private, params):
		print("creating game", player_id, is_private, params)
		game_id = random.randint(0, MAX_GAME_ID - 1)
		while (game_id in self.games):
			game_id = random.randint(0, MAX_GAME_ID - 1)
		self.games[game_id] = game_group(game_id, player_id, is_private, params)
		self.chats[player_id].game_id = game_id
		self.send_command(markdown_message("*ID: " + str(game_id) + "*"), player_id)

	def get_names(self, game_id):
		names = []
		for other_player_id in self.games[game_id].players:
			names.append(self.chats[other_player_id].name)
		return names

	def share_game_message(self, game_id, text):
		self.game_event_handler(game_id, {'all_message' : text}, 0)

	def player_join(self, chat_id, game_id):
		if (not(game_id in self.games)):
			self.send_command(text_message("Такой игры не существует"), chat_id)
			return
		if (self.games[game_id].started == 1):
			self.send_command(text_message("Игра уже началась"), chat_id)
			return
		self.share_game_message(game_id, self.chats[chat_id].name + " присоединился")
		names = self.get_names(game_id)
		self.chats[chat_id].game_id = game_id
		self.games[game_id].join(chat_id)
		text = "Ты в игре " + str(game_id) + " вместе с " + ", ".join(names) + ". " + description_params(self.games[game_id].params)
		self.send_command(text_message(text), chat_id)

	def player_leave(self, player_id, game_id):
		self.chats[player_id].game_id = -1
		self.games[game_id].leave(player_id)
		if (self.games[game_id].players_cnt == 0):
			self.games.pop(game_id)
			print("games.pop")
		else:
			self.share_game_message(game_id, self.chats[player_id].name + " покинул комнату")
		self.send_command(text_message("Ты покинул(а) игру"), player_id)

	def show_list(self, chat_id):
		text = ""
		index = 0
		for game_id in self.games.keys():
			if (self.games[game_id].is_private == 0):
				names = self.get_names(game_id)
				index += 1
				text = text + "Комната #" + str(index) + " (" + ", ".join(names) + "). " + description_params(self.games[game_id].params) + " /join" + str(game_id) + "\n"
		if (text == ""):
			text = "Список пуст"
		self.send_command(markdown_message(text), chat_id)

	def say(self, chat_id, game_id, message):
		text = "*" + self.chats[chat_id].name + ":* " + message
		self.share_game_message(game_id, text)

	def invite(self, chat_id, name):
		game_id = self.chats[chat_id].game_id
		if (self.games[game_id].started):
			return
		found = 0
		for player_id in self.chats.keys():
			print("id =", player_id)
			if (self.chats[player_id].name == name):
				found += 1
			self.send_command(text_message("Инвайт от " + self.chats[chat_id].name + ". /join" + str(game_id)), player_id)
		if (found == 0):
			self.send_command(text_message("Игрок не найден"), chat_id)
			return
		self.send_command(text_message("Игрок приглашён"), chat_id)

	def check_if_admin(self, chat_id, game_id):
		if (self.games[game_id].started == 1):
			self.send_command(text_message("Игра уже началась"), chat_id)
			return 0
		if (self.games[game_id].isadmin(chat_id) == 0):
			self.send_command(text_message("Чтобы изменить параметры игры, нужно быть создателем комнаты"), chat_id)
			return 0
		return 1

	def changetl(self, chat_id, game_id, tl):
		if (self.check_if_admin(chat_id, game_id)):
			self.games[game_id].tl = tl
			self.share_game_message(game_id, "Время хода изменено на " + str(tl) + " секунд")

	def load(self, chat_id):
		if (self.check_if_admin(chat_id, self.chats[chat_id].game_id)):
			self.chats[chat_id].waiting_for_file = 1
			self.send_command(text_message("Теперь отправь файл. Напиши /cancel, чтобы отменить"), chat_id)

	def remove_file(self, chat_id, game_id):
		if (self.check_if_admin(chat_id, game_id)):
			self.games[game_id].filename = ""
			self.send_command(text_message("Файл удалён"), chat_id)

	def send_turn_reminder(self, game_id):
		room = self.games[game_id]
		chat_id = room.players[room.whose_turn]
		if (chat_id != 0):
			self.send_command(text_message("Твой ход"), chat_id)

	def start_game(self, chat_id):
		game_id = self.chats[chat_id].game_id
		if (self.check_if_admin(chat_id, game_id)):
			names = []
			for player_id in self.games[game_id].players:
				names.append(self.chats[player_id].name)
			self.games[game_id].start(names)
			self.share_game_message(game_id, "Игра началась!")
			self.send_turn_reminder(game_id)

	def get_id_query(self, chat_id, player):
		if (player.game_id == -1):
			self.send_command(markdown_message("Ты не в игре"), chat_id)
		else:
			self.send_command(markdown_message("Ты в игре " + str(player.game_id)), chat_id)

	def numeric_parameter(self, chat_id, text, command, description):
		params = get_params(text, command)
		if ((len(params) == 0) or params[0].isdigit() == 0):
			self.send_command(text_message(command + " <" + description + ">"), chat_id)
			return -1
		else:
			return int(params[0])

	def game_turn(self, player_id, game_id, turn):
		room = self.games[game_id]
		player_game_id = room.players.index(player_id)
		response = room.game.turn(player_game_id, turn)
		self.game_event_handler(game_id, response, player_id)
		if (response['next_turn']):
			room.make_next_turn()
			self.send_turn_reminder(game_id)

	def handle_message(self, message):
		print("GOT MESSAGE")
		chat_id = message['chat']['id']
		player = self.chats[chat_id]

		if (('document' in message) and player.waiting_for_file == 1):
			file_id = message['document']['file_id']
			_params = {'file_id' : file_id}
			response = requests.get(self.url + "getFile", params = _params).json()
			file_path = response['result']['file_path']
			download_url = "https://api.telegram.org/file/bot" + self.token + "/" + file_path
			os.system("wget -O map" + str(player.game_id) + " " + download_url)
			player.waiting_for_file = 0
			self.games[player.game_id].filename = "map" + str(player.game_id)
			self.send_command(markdown_message("Файл загружен"), chat_id)
			return

		player.waiting_for_file = 0

		if ('text' in message):
			text = message['text']
			command = get_command(text)

			print("text", text)
			print("command", command)

			if (command == '/start'):
				self.send_command(markdown_message(INTRO), chat_id)
			if (command == '/rules'):
				self.send_command(markdown_message(RULES), chat_id)
			if (command == '/help'):
				self.send_command(markdown_message(HELP_MESSAGE), chat_id)
			if (command == '/getname'):
				self.send_command(markdown_message("Тебя зовут _" + self.name + "_"))
			if (command == '/list'):
				self.show_list(chat_id)
			if (command == '/getid'):
				self.get_id_query(chat_id, player)

			if (player.game_id == -1):
				if (command == '/setname'):
					params = get_params(text, "/setname")
					if (len(params) == 0):
						self.send_command(text_message("/setname <name>"), chat_id)
					name = ' '.join(params)
					if (not correct(name)):
						self.send_command(text_message(WRONG_CHARECTERS_IN_NAME_MESSAGE), chat_id)
					if (name in all_names):
						self.send_command(text_message("Это имя занято"), chat_id)
					all_names.remove(player.name)
					player.name = name
					all_names.add(player.name)
					self.send_command(markdown_message("Теперь ты _" + name + "_"), chat_id)

				if (command == '/create_game'):
					params = get_params(text, '/create_game')
					self.create_game(chat_id, 0, params)

				if (command == '/create_private_game'):
					params = get_params(text, '/create_private_game')
					self.create_game(chat_id, 1, params)

				if (command == '/join'):
					game_id = self.numeric_parameter(chat_id, text, '/join', 'GAME_ID')
					if (game_id != -1):
						self.player_join(chat_id, game_id)
			else:
				room = self.games[player.game_id]

				if (command == '/say'):
					to_say = suffix(text, '/say')
					self.say(chat_id, player.game_id, to_say)

				if (command == '/leave'):
					self.player_leave(chat_id, player.game_id)
					return

				if (command == '/join'):
					self.send_command(text_message("Сначала выйди из этой игры (/leave)"), chat_id)

				if (room.started == 0):
					if (command == '/invite'):
						invited = suffix(text, '/invite')
						self.invite(chat_id, invited)

					if (command == '/changetl'):
						tl = self.numeric_parameter(chat_id, text, '/changetl', 'TL')
						if (tl != -1):
							self.changetl(chat_id, player.game_id, tl)

					if (command == '/load'):
						self.load(chat_id)

					if (command == '/remove_file'):
						self.remove_file(chat_id)

					if (command == '/start_game'):
						self.start_game(chat_id)
				else:
					self.game_turn(chat_id, player.game_id, text)
		else:
			self.send_command(text_message(WRONG_MESSAGE_RESPONSE), chat_id)

	def update_game(self, game_id):
		room = self.games[game_id]
		while (room.players[room.whose_turn] == 0):
			response = room.game.random_turn(self.whose_turn)
			self.game_event_handler(game_id, response, 0)
			room.make_next_turn()
			self.send_turn_reminder(game_id)

		if (time.time() - room.last_turn_time >= room.tl):
			afk_player_id = room.players[room.whose_turn]
			afk_player_name = self.chats[afk_player_id].name
			self.chats[afk_player_id].game_id = -1
			room.players[room.whose_turn] = 0
			room.players_cnt -= 1
			self.send_command(text_message("Время хода истекло"), afk_player_id)
			self.share_game_message(game_id, 'Игрок _' + afk_player_name + '_ афк')
			if (room.players_cnt == 0):
				self.games.pop(game_id)

	def update(self):
		print("updating bot...", int(time.time()))
		messages = self.get_new_messages()[::-1]
		for msg in messages:
			self.handle_message(msg)

		game_keys = list(self.games.keys())
		for game_id in game_keys:
			if (self.games[game_id].started == 1):
				self.update_game(game_id)

	def save_to_file(self):
		f = open(self.name + ".botconfig", 'w')
		f.write("Configuration to bot " + self.name + "\n")
		f.write(str(self.last_update) + "\n")
		stringchats = '['
		it = []
		for x in self.chats.items():
			it.append(x)
		for i in range(len(it)):
			x = it[i]
			stringchats = stringchats + '[' + str(x[0]) + ', "' + str(x[1]) + '"]'
			if (i < len(it) - 1):
				stringchats += ', '
		stringchats += ']'
		f.write(stringchats + "\n")

bot = telegram_bot(TOKEN, BOT_NAME)

def exit_handler():
	bot.save_to_file()

atexit.register(exit_handler)

while (True):
	try:
		bot.update()
		bot.save_to_file()
	except KeyboardInterrupt:
		break


"""Corrected the lowercase Column

Revision ID: dda7a1ca7a04
Revises: f2b849ffb71f
Create Date: 2022-08-13 20:14:00.669172

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = 'dda7a1ca7a04'
down_revision = 'f2b849ffb71f'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('Artist', sa.Column('past_shows_count', sa.Integer(), nullable=True))
    op.add_column('Venue', sa.Column('past_shows_count', sa.Integer(), nullable=True))
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column('Venue', 'past_shows_count')
    op.drop_column('Artist', 'past_shows_count')
    # ### end Alembic commands ###


"""
You are given an array prices where prices[i] is the price of a given stock on the ith day.

You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock.

Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0.

Input: prices = [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.

"""
from typing import List

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        print (prices)
        ans = 0
        buy_index = 0
        sell_index = 0
        for i in range(1, len(prices)):
            if prices[i] < prices[buy_index]:
                buy_index = i
            profit = prices[i] - prices[buy_index]
            if profit > ans:
                sell_index = i
                ans = profit
        print (buy_index, sell_index)
        return ans


#!/usr/bin/env python3
# coding: utf8
import typing
import argparse
import functools
import os
import re
import shutil
import sys
import subprocess as P
import os.path as path

# The background image is of size 1024x1024, the transparent margin on each
# edge is 100px.
BG_IMG = path.join(path.dirname(__file__), "white_bg_1024x1024.png")
BG_WIDTH = 1024
BG_MARGIN = 100
BG_MARGIN_RATIO = 2 * BG_MARGIN / BG_WIDTH

# Original icon png file name
ORIG_PNG_NAME = "icon_512x512.png"

def gm_cmd(cmd: str, debug: bool = False) -> str:
    """
    GraphicsMagick CLI wrapper
    """
    full_cmd = "gm {}".format(cmd)
    if debug:
        print(full_cmd)
    with os.popen(full_cmd) as f:
        return f.read()

def get_width(filename: str) -> int:
    return parse_width(gm_cmd("identify {}".format(filename)))

def parse_width(s: str) -> int:
    m = re.search(r"(\d+)x(\d+)", s)
    if m is None:
        raise Exception("Unknown dimension string")
    return int(m.group(1))

def overlay(size: int, fg_img: str, output_dir: str, scale: int = 1, delta_x: int = 0, delta_y: int = 0, bg_img: str = BG_IMG) -> str:
    inner_size = int(size * (1 - BG_MARGIN_RATIO) * scale)
    offset = int((size - inner_size) / 2)
    gm_cmd("composite -resize {inner_size}x{inner_size} -geometry +{offset_x}+{offset_y} '{icon}' \
                      -resize {outer_size}x{outer_size} '{background}' '{output}'".format(
        inner_size=inner_size,
        outer_size=size,
        offset_x=offset+delta_x,
        offset_y=offset+delta_y,
        icon=fg_img,
        background=bg_img,
        output=path.join(output_dir, "icon_{0}x{0}.png".format(size))
    ))
    return path.join(output_dir, "icon_{0}x{0}.png".format(size))

def resize(size: int, img: str, output_dir: str) -> None:
    new_name = path.join(output_dir, "icon_{0}x{0}.png".format(size))
    gm_cmd("convert -resize {size}x{size} '{img}' '{new_name}'".format(
        size=size, img=img, new_name=new_name))

def convert_icns_to_iconset(icns_file: str) -> str:
    """
    the `.iconset` file is a folder with PNG images of different size
    """
    output_path = path.abspath(path.basename(icns_file).replace(".icns", ".iconset"))
    __ensure_path_not_exist(output_path)
    c = P.call("iconutil -c iconset -o '{}' '{}'".format(output_path, icns_file), shell=True)
    if c != 0:
        raise Exception("Failed to convert icns")
    return output_path

def convert_iconset_to_icns(iconset_file: str) -> str:
    output_path = path.abspath(iconset_file.replace(".iconset", ".icns"))
    __ensure_path_not_exist(output_path)
    c = P.call("iconutil -c icns -o '{}' '{}'".format(output_path, iconset_file), shell=True)
    if c != 0:
        raise Exception("Failed to convert iconset")
    return output_path

def __ensure_path_not_exist(p: str) -> None:
    if path.exists(p):
        raise Exception("Path {} will be overriden".format(p))

def process(iconset_dir: str, output_dir: str) -> None:
    guess_best_size = None
    for s in [512, 256, 128]:
        if path.exists(path.join(iconset_dir, "icon_{0}x{0}.png".format(s))):
            guess_best_size = s
            break
    if guess_best_size is None:
        raise Exception("The icns doesn't contain icon image with good resolution")
    orig_img = path.join(iconset_dir, "icon_{0}x{0}.png".format(guess_best_size))
    img = overlay(guess_best_size, orig_img, output_dir, scale=0.8)
    for s in [16, 32, 128, 256]:
        if s < guess_best_size:
            resize(s, img, output_dir)

def parse_args():
    p = argparse.ArgumentParser("BigSur icon converter")
    p.add_argument("file", metavar="FILE", type=str)
    p.add_argument("-x", help="x offset", type=int, default=0)
    p.add_argument("-y", help="y offset", type=int, default=0)
    return p.parse_args()

if __name__ == "__main__":
    args = parse_args()
    iconset_dir = convert_icns_to_iconset(args.file)
    output_dir = os.path.abspath("new-" + path.basename(iconset_dir))
    os.mkdir(output_dir)
    try:
        process(iconset_dir, output_dir)
        convert_iconset_to_icns(output_dir)
    except Exception as e:
        print(e)
    finally:
        shutil.rmtree(output_dir)
        shutil.rmtree(iconset_dir)


from applications.biblioteca.models import Author
from django.shortcuts import render

# Create your views here.
from django.views.generic import (
    TemplateView,
    ListView,
    CreateView,
)

from .models import Author, Book

class AuthorsList(ListView):
    template_name = "biblioteca/authors-list.html"
    model = Author
    context_object_name = 'authors'

#View to list books by author
class AuthorBooksList(ListView):
    template_name = "biblioteca/books-list.html"
    context_object_name = 'books'

    def get_queryset(self):
        # Identify the author
        id = self.kwargs['id'] #From url get the arg 'id'
        # Filter books by author
        books = Book.objects.filter(
            author=id
        )
        # Return results
        return books

class AddAuthor(CreateView):
    """View to add new author"""
    template_name = 'biblioteca/add-author.html'
    model = Author
    fields = ['name', 'nationality']
    success_url =  '/' #This reload the page when author is added.


from ehcmodel.common.kdl_template import *
from ehcmodel.common.data_preproc import *
from ehcmodel.common.exp_preproc import exp_preprocess, gen_save_path

import os
import inspect

from collections import defaultdict
import itertools
import pickle
import time
from pprint import pprint
from sklearn.decomposition import FastICA

exp_name = 'lab2_big_20v_10t'
_,posori_all,es_all = load_boxworld_raw(exp_name)
X_all,y_all,es_all = load_boxworld_data(exp_name);
X_all = X_all.astype("float32").astype(theano.config.floatX)
y_all = y_all.astype("int32")

cmap_name = 'hot_r'
#generate each experiment parameters and run eval_grid_point
def eval_on_grid(eval_funcs,**kwargs):
    sub_exp_num = len(glob.glob(plot_root+kwargs['dir_name']+'/eval_results*.pkl'))

    changing_param_names = [k for k in kwargs.keys() if isinstance(kwargs[k],list) and len(kwargs[k])>1]
    not_changing_param_names = [k for k in kwargs.keys() if not (isinstance(kwargs[k],list) and len(kwargs[k])>1)]
    assert 'dir_name' in not_changing_param_names

    grid_comps = []
    for k,v in kwargs.iteritems():
        if isinstance(v,list):
            grid_comps.append(v)
        else:
            grid_comps.append([v])
    print(grid_comps)
    not_changing_params = dict(kwargs)
    for k in changing_param_names:
        del not_changing_params[k]

    results =defaultdict(dict)

    for grid_vertex in itertools.product(*grid_comps):
        params = dict(zip(kwargs.keys(),grid_vertex))
        changing_params = dict(params)
        for k in not_changing_param_names:
            del changing_params[k]
        starttime = time.time()
        values = eval_grid_point(eval_funcs,**params)
        results['eval_time'][tuple(changing_params.values())] = (time.time()-starttime)
        for key in values.keys():
            results[key][tuple(changing_params.values())] = values[key]
        pprint(dict(results))
    if not os.path.isdir(plot_root+kwargs['dir_name']):
        os.makedirs(plot_root+kwargs['dir_name'])
    pprint((not_changing_params,changing_params.keys(),dict(results)),open(plot_root+kwargs['dir_name']+'/eval_results'+str(sub_exp_num)+'.txt','w'))

    pickle.dump((not_changing_params,changing_params.keys(),dict(results)),open(plot_root+kwargs['dir_name']+'/eval_results'+str(sub_exp_num)+'.pkl','w'))
    return results

def eval_grid_point(eval_methods,dir_name,description,n_code,n_coding_layer,sparsity_mode,sparsity_k,dropout_p,preprocess,
                    sampling_rate,minibatch_size,view_angle,turn_angle,reconst_mask,early_stop,n_epochs):

    frame = inspect.currentframe()
    _, _, _, values = inspect.getargvalues(frame)

    del values['frame']
    del values['eval_methods']
    random_state = np.random.RandomState(1999)
    use_cache = 'use_cache' in eval_methods
    plot_types = ['z','z_lin','z_lin_wta','bin_lin_wta','z_lin_thres','bin_lin_thres','z_lin_ll1','z_lin_ll1_bin']

    Z_PLOT_TYPE = 0
    Z_LIN_PLOT_TYPE = 1
    Z_LIN_WTA_PLOT_TYPE = 2
    FIRE_LIN_WTA_PLOT_TYPE = 3
    Z_LIN_THRES_PLOT_TYPE = 4

    if use_cache:
        save_path = gen_save_path(values)
        values = {}
    else:
        save_path, X,Y,posori,_,_,_,es  = \
                                exp_preprocess(X_all = X_all,y_all=y_all,posori_all=posori_all,es_all=es_all,
                                               split=False,random_state=random_state,**values)
        checkpoint_dict = load_checkpoint(dir_name+'/'+save_path+".pkl" )
        try:
            checkpoint_dict = load_checkpoint(dir_name+'/'+save_path+".pkl" )
        except Exception as e:
            print (dir_name+'/'+save_path+".pkl couldnt be loaded\n"+str(e))
            return {}
        if n_coding_layer== 'ica':
            fica = checkpoint_dict["fica_object"]
            z_lin_all = fica.transform(X)
            z_all = fica.transform(X)
        else:
            test_function = checkpoint_dict["test_function"]
            encode_function = checkpoint_dict["encode_function"]
            encode_linear_function = checkpoint_dict["encode_linear_function"]
            #decode_function = checkpoint_dict["decode_function"]
            #predict_function = checkpoint_dict["predict_function"]

            z_lin_all, = encode_linear_function(X)
            z_all, = encode_function(X)

        values = {}
        dead_neuron_map = np.sum(z_all>0,axis=0)<=0
        dead_neuron_count = np.sum(dead_neuron_map)

        values['dead_neuron_count'] = dead_neuron_count
        values['num_samples'] = X.shape[0]

        #xs,ys = discretize(posori,es)
        #xs = xs / sampling_rate
        #ys = ys / sampling_rate

        discr_posori = np.round(posori[:,0:2]/es['step_size']).astype(int)
        xsize,ysize = np.max(discr_posori,axis=0)+1

        angles = posori[:,2].round().astype(int)

        fit_angles = (np.arange(es['num_angles'])*360/es['num_angles'])#[::36]#[0]
        act_2d = np.zeros([len(plot_types),len(fit_angles),z_all.shape[1],xsize,ysize])
        for ai,angle in enumerate(fit_angles):
            angle_mask = angles == angle
            discr_places = discr_posori[angle_mask]
            discr_place_inv_idx = {tuple(r):i for i,r in enumerate(discr_places)}
            X_angle = X[angle_mask]

            for pi,plot_type in enumerate(plot_types):
                if plot_type in ['z'] :
                    #z, = encode_function(X_angle)
                    z = z_all[angle_mask]
                elif plot_type == 'z_lin':
                    #z, = encode_linear_function(X_angle)
                    z = z_lin_all[angle_mask]
                elif plot_type in ['z_lin_wta'] :
                    z = wta_np(z_lin_all)[angle_mask]
                elif plot_type in ['bin_lin_wta']:
                    #z = (z_all[angle_mask]>0).astype(int)
                    z = (wta_np(z_lin_all)[angle_mask]>0).astype(int)
                elif plot_type == 'z_lin_thres':
                    z = z_lin_all[angle_mask]
                    z_max = np.max(z,axis=0)
                    mask =np.kron(z_max*0.8,np.ones((z.shape[0],1)))
                    z[z<mask] = 0
                elif plot_type == 'bin_lin_thres':
                    z = z_lin_all[angle_mask]
                    z_max = np.max(z,axis=0)
                    mask =np.kron(z_max*0.5,np.ones((z.shape[0],1)))
                    z[z<mask] = 0
                    z = (z>0).astype(int)
                elif plot_type == 'z_lin_ll1':
                    z = llsparsity_np(z_lin_all,1./z.shape[1])[angle_mask]
                elif plot_type == 'z_lin_ll1_bin':
                    z = (llsparsity_np(z_lin_all,1./z.shape[1])[angle_mask]>0).astype(int)

                #pprint(discr_place_inv_idx)
                for x1 in range(0,xsize):
                    for y1 in range(0,ysize):
                        #print(x1,y1)
                        if not ((x1,y1) in discr_place_inv_idx):
                            print(str((x1,y1))+' is blocked')
                            continue
                        zxy = z[discr_place_inv_idx[(x1,y1)]]
                        act_2d[pi,ai,:,x1,y1] = zxy
        #pickle.dump([z_all,z_lin_all,yoh],open('zzzz0301.pkl','wb'))
        mins = np.min(z_lin_all,axis=0).tolist()
        maxs = np.max(z_lin_all,axis=0).tolist()
        minmax = ({'mins':mins,'maxs':maxs})
        lims = np.max(np.array([minmax['mins'],minmax['maxs']]),axis=0)
        #print(lims)

    if 'activations' in eval_methods:

        dir_path = plot_root+dir_name+'/'+save_path+"/activations/"
        if not os.path.isdir(dir_path):
            os.makedirs(dir_path)

        for ai,angle in enumerate(fit_angles):
            print(angle)
            for pi,plot_type in enumerate(plot_types[:4]):
                if not os.path.isdir(dir_path+plot_type+"/"):
                    os.makedirs(dir_path+plot_type+"/")
                fig = plt.figure()
                subplotdata = []
                for di in range(z_all.shape[1]):
                    #print(di)
                    ax = fig.add_subplot(math.ceil(math.sqrt(z_all.shape[1])),math.ceil(math.sqrt(z_all.shape[1])),di+1)
                    plt.axis('off')
                    im = ax.imshow(act_2d[pi,ai,di],interpolation='none')
                    subplotdata.append(act_2d[pi,ai,di])
                    """
                    if plot_type == 'fire_lin_wta':
                        im = ax.imshow(act_2d[pi,ai,di],interpolation='none',clim=(-1,1))
                    elif lims[di]>0:
                        im = ax.imshow(act_2d[pi,ai,di],interpolation='none',clim=(-lims[di],lims[di]))
                    else:
                        im = ax.imshow(act_2d[pi,ai,di],interpolation='none',clim=(-1,1))
                    """
                    plt.colorbar(im)

                plt.savefig(dir_path+plot_type+"/"+plot_type+"_"+str(angle).zfill(3)+'.png')
                pickle.dump(subplotdata,open(dir_path+plot_type+"/z"+plot_type+"_"+str(angle).zfill(3)+'.pkl','w'))
                #plt.show()
                plt.close()
                #print(act_2d)

    if 'summed_activations' in eval_methods:
        print('Plotting summed activations')
        dir_path = plot_root +dir_name+ "/all/"
        if not os.path.isdir(dir_path):
            os.makedirs(dir_path)

        for pi,plot_type in enumerate(plot_types):#zip([3],['sum']):#zip([0,1],['sum','firesum']):
            if not os.path.isdir(dir_path+plot_type+"/"):
                os.makedirs(dir_path+plot_type+"/")
            fig = plt.figure()
            if use_cache:
                cached_d2plot = pickle.load(open(dir_path+plot_type+"/zsum_act_"+save_path+'.pkl','r'))
            subplotdata = []
            for di in range(n_code):
                ax = fig.add_subplot(math.ceil(math.sqrt(n_code)),math.ceil(math.sqrt(n_code)),di+1)
                plt.axis('off')
                if use_cache:
                    d2plot = cached_d2plot[di]
                else:
                    d2plot = np.sum(act_2d[pi,:,di],axis=0)

                if np.max(d2plot)>0:
                    im = ax.imshow(d2plot,interpolation='none',clim=(0,np.max(d2plot)),cmap=plt.get_cmap(cmap_name))
                else:
                    im = ax.imshow(d2plot,interpolation='none',cmap=plt.get_cmap(cmap_name))
                subplotdata.append(d2plot)
                plt.colorbar(im)

            plt.savefig(dir_path+plot_type+"/sum_act_"+save_path+'.png')
            if not use_cache:
                pickle.dump(subplotdata,open(dir_path+plot_type+"/zsum_act_"+save_path+'.pkl','w'))
            plt.close()

    if 'spatial_coverage_plot' in eval_methods:
        print('Plotting spatial coverage')
        dir_path = plot_root +dir_name+"/all/"
        if not os.path.isdir(dir_path):
            os.makedirs(dir_path)
        for pi,plot_type in enumerate(plot_types):#zip([0,1],['sum','firesum']):
            if not os.path.isdir(dir_path+plot_type+"/"):
                os.makedirs(dir_path+plot_type+"/")
            fig = plt.figure()
            plt.axis('off')
            if use_cache:
                d2plot = pickle.load(open(dir_path+plot_type+"/zcov_"+save_path+'.pkl','r'))
            else:
                if plot_type == 'bin_lin_wta':
                    d2plot = np.max(np.sum(act_2d[pi,:],axis=0),axis=0)
                else:
                    d2plot = np.sum(np.sum(act_2d[pi,:],axis=0),axis=0)
            #im = plt.imshow(d2plot,interpolation='none',clim=(0,np.max(d2plot)))
            if np.max(d2plot)>0:
                im = plt.imshow(d2plot,interpolation='none',clim=(0,np.max(d2plot)),cmap=plt.get_cmap(cmap_name))
            else:
                im = plt.imshow(d2plot,interpolation='none',cmap=plt.get_cmap(cmap_name))
            plt.colorbar(im)
            plt.savefig(dir_path+plot_type+"/cov_"+save_path+".png")
            if not use_cache:
                pickle.dump(d2plot,open(dir_path+plot_type+"/zcov_"+save_path+'.pkl','w'))
            plt.close()

    if 'epoch_metrics' in eval_methods:
        dir_path = plot_root+dir_name+'/'+save_path+"/epoch_metrics/"
        if not os.path.isdir(dir_path):
            os.makedirs(dir_path)

        train_epoch_results = checkpoint_dict["train_epoch_results"]
        val_epoch_results = defaultdict(list,checkpoint_dict["val_epoch_results"])
        val_epoch_results['cost']= val_epoch_results['val_cost']

        #print (train_epoch_results.keys())
        #print (val_epoch_results.keys())
        values['last_val_cost'] = val_epoch_results['cost'][-1]
        values['last_train_cost'] = train_epoch_results['cost'][-1]
        values['num_epochs'] = len(train_epoch_results['cost'])

        for k in train_epoch_results:
            plt.figure()
            plt.plot(train_epoch_results[k],label = 'train')

            if k in val_epoch_results:
                assert len(val_epoch_results[k])-1 % len(train_epoch_results[k])
                plt.plot(range(0,len(train_epoch_results[k]),len(train_epoch_results[k])/(len(val_epoch_results[k])-1)),
                                val_epoch_results[k][1:],label = 'val')
            plt.title(str(k))
            plt.legend()
            plt.savefig(dir_path+str(k)+'.png')
            plt.close()

    return values


import utils

data = [{
  'country': 'colombia',
  'population': 500
}, {
  'country': 'argentina',
  'population': 700
}]

def run():
  keys, values = utils.get_population()
  print(keys, values)

  print(utils.a)

  country = input("type country=> ")

  result = utils.population_by_country(data, country)
  print(result)

#Entry point
if __name__ == '__main__':
  run()


# this is my first actually useful program. my gratitude to nick winn, pyslackers chat room (EdKeyes and dd82),
# /r/learnpython, learnprogramming.academy, real python, and others for helping me get this far!

import requests
import time
import hmac
import hashlib
import decimal
from decimal import Decimal
from typing import Tuple

decimal.getcontext().prec = 100
decimal_zero = Decimal()

# buy/bid and sell/ask always refers to the quote asset (the first asset) (ex: ARDRETH : buy ARDR or sell ARDR)
# the second asset is the 'base' asset (ex: ETH is base asset in ARDRETH)

class Exchange(object):

    # for functions that should be applicable to every exchange. I imagine most exchange APIs don't work
    # the same way, so most functions will be part of subclasses tailored to each exchange

    def __init__(self, api_token: str = None, api_token_secret: str = None):
        self.api_token = api_token
        self.api_token_secret = api_token_secret

    def get_signature(self, query_string: str) -> str:
        # signing the param_strings used to interact with the exchange APIs should be the same everywhere
        undigested_sig = hmac.new(self.api_token_secret.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256)
        return undigested_sig.hexdigest()

    # get_tax_due() will need to be formatted at some point to however the specific exchange needs its values formatted
    # my take is to implement that in a get_tax_due() function in the subclass that
    # returns a formatted super().get_tax_due()
    @staticmethod
    def get_tax_due(spend_total_usd: Decimal, cost_basis_usd: Decimal = None, term: str = 'short') \
            -> Decimal or str:
        term = term.lower()
        if term != 'short' and term != 'long':
            invalid_term = list()
            invalid_term.append(term)
            return tuple(invalid_term)
        if cost_basis_usd is None:
            cost_basis_usd = decimal_zero
        tax_due_usd = decimal_zero
        based_total = spend_total_usd - cost_basis_usd
        if term == 'short':
            tax_due_usd = based_total * Decimal('0.3')
        elif term == 'long':
            tax_due_usd = based_total * Decimal('0.16')
        return tax_due_usd

class Binance(Exchange):
    # https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md

    def __init__(self, api_token: str = None, api_token_secret: str = None):
        super().__init__(api_token, api_token_secret)
        self.API_URL = 'https://api.binance.com/api/'
        self.headers = {
            'X-MBX-APIKEY': self.api_token
        }

    # takes a Decimal and returns it with 6 decimal places, rounded up or down depending on round_direction
    # round_direction: ROUND_DOWN, ROUND_UP
    @staticmethod
    def format_a_decimal(dec: Decimal, lot_size: str, round_direction: str = 'ROUND_DOWN') -> Decimal:
        lot_size = Decimal(lot_size)
        return Decimal(dec.quantize(Decimal(lot_size), rounding=round_direction))

    # Binance gets its own get_tax_due() because it only works with up to 6 decimal places, so it needs
    # to be formatted as such
    def get_tax_due(self, spend_total_usd: Decimal, cost_basis_usd: Decimal = None, term: str = 'short') \
            -> Decimal or str:
        return self.format_a_decimal(super().get_tax_due(spend_total_usd, cost_basis_usd, term),
                                     lot_size='.01', round_direction='ROUND_UP')
        # LOT_SIZE of .01 here because although though usdc supports more decimal places,
        # this will be getting rounded up for the tax man anyway

    # The following functions work with information from Binance using the following formats:

    #   Examples:
    #       pairing: 'ETHUSDC'
    #       side: 'buy' or 'sell'
    #       qty: decimal.Decimal('4.513')
    #       symbol: 'ETH'
    #       pairing_side: 'quote' or 'base'

    # with 'ETHUSDC' as 'pairing' in get_pairing_converted_value():
    # side = 'buy' to convert USDC value to ETH value
    # side = 'sell' to convert ETH value to USDC value
    # API seems to only return the order books about 1,000,000 USD deep
    # TODO make this function estimate spends for crazy large amounts quickly
    def get_pairing_converted_value(self, pairing: str, spend_amount: Decimal, side: str = 'buy') -> tuple:
        side = side.lower()
        pairing = pairing.upper()
        book = None
        input_check = self._input_check(pairing=pairing, side=side, qty=spend_amount)
        if input_check is not True:
            return input_check
        if side == 'buy':
            book = 'asks'
        if side == 'sell':
            book = 'bids'
        api_url = self.API_URL + "v1/depth"
        orders = requests.get(api_url, params={'symbol': pairing, 'limit': 1000})
        if orders.status_code >= 400:
            return orders.status_code
        running_cost = decimal_zero
        qty_counter = decimal_zero
        quote, base = self.split_a_pairing(pairing)
        lot_size = self._get_pairing_lot_size(pairing=pairing, side=side)
        for order in orders.json()[book]:
            order_0, order_1 = Decimal(order[0]), Decimal(order[1])
            cost = order_0 * order_1
            if side == 'buy':
                if cost + running_cost >= spend_amount:
                    left_to_spend = spend_amount - running_cost
                    remaining_qty_to_buy = left_to_spend/order_0
                    total_bought = qty_counter + remaining_qty_to_buy
                    total_bought = self.format_a_decimal(dec=total_bought, lot_size=lot_size)
                    return total_bought, quote
                running_cost += cost
                qty_counter += order_1
            if side == 'sell':
                if order_1 + running_cost >= spend_amount:
                    left_to_spend = spend_amount - running_cost
                    remaining_qty_to_buy = order_0 * left_to_spend
                    total_bought = qty_counter + remaining_qty_to_buy
                    total_bought = self.format_a_decimal(dec=total_bought, lot_size=lot_size)
                    return total_bought, base
                running_cost += order_1
                qty_counter += cost

    # get_price_usdc() is like a get_pairing_price(), except it is exclusively USDC, and if a pairing
    # doesn't exist, it uses BTC as a go between and returns the appropriate values as though it did
    # so now we can get a USDC price for every asset available on Binance
    # if symbol is 'XMR': 'buy' means send usdc value return xmr value; 'sell' means send xmr value return usdc value
    def get_price_usdc(self, symbol: str, qty: Decimal, side: str = 'buy') -> tuple:
        symbol = symbol.upper()
        side = side.lower()
        input_check = self._input_check(None, side, qty, symbol)
        if input_check is not True:
            return input_check
        path_to_usdc = self._get_pairing_path_to_usdc(symbol=symbol)
        if len(path_to_usdc) == 1:
            return self.get_pairing_converted_value(pairing=path_to_usdc[0], spend_amount=qty, side=side)
        if side == 'sell':
            btc_qty = self.get_pairing_converted_value(pairing=path_to_usdc[0], spend_amount=qty, side='sell')
            return self.get_pairing_converted_value(pairing=path_to_usdc[1], spend_amount=btc_qty[0], side='sell')
        btc_qty = self.get_pairing_converted_value(pairing=path_to_usdc[1], spend_amount=qty, side='buy')
        return self.get_pairing_converted_value(pairing=path_to_usdc[0], spend_amount=btc_qty[0], side='buy')

    # get_balances() takes any number of symbols passed in as parameters, and yields balances in tuples
    # if all_symbols is True, it yields all balances
    # ex: get_balances('ETH', 'XMR', 'USDC', 'BNB')
    # zero_balances does nothing if all_symbols isn't True
    # sending symbols as *argv parameter with all_symbols turned on and zero balances off results
    # in specified zero balances being displayed along with all nonzero balances
    def get_balances(self, *args, all_symbols: bool = False, show_zero_balances: bool = False):
        query_string = 'timestamp=' + str(int(time.time()) * 1000)
        sig = self.get_signature(query_string)
        balances = requests.get(self.API_URL + 'v3/account?' +
                                query_string + '&signature=' + sig, headers=self.headers)
        if balances.status_code >= 400:
            return balances.status_code
        if all_symbols:
            for asset_dict in balances.json()['balances']:
                return_dec = self.format_a_decimal(Decimal(asset_dict['free']), lot_size='.000001')
                if not show_zero_balances and return_dec != decimal_zero:
                    yield return_dec, asset_dict['asset']
                elif show_zero_balances:
                    yield return_dec, asset_dict['asset']
        for symbol in args:
            symbol = symbol.upper()
            input_check = self._input_check(None, None, None, symbol)
            if input_check is not True:
                return input_check
            else:
                for asset_dict in balances.json()['balances']:
                    if asset_dict['asset'] == symbol:
                        yield self.format_a_decimal(Decimal(asset_dict['free']), lot_size='.000001'), symbol

    # make the tax trade(s) before the main trade's function gets called
    # figures out the necessary trades to convert the given asset to the USDC amount given
    # then executes those trades using execute_trade()
    def execute_tax_trade(self, asset_being_sold: str,  tax_due_usd: Decimal) -> tuple:
        path_to_usdc = self._get_pairing_path_to_usdc(symbol=asset_being_sold)
        tax_due_as_sym = self.get_price_usdc(symbol=asset_being_sold, qty=tax_due_usd, side='buy')[0]
        if len(path_to_usdc) == 1:
            symusdc = path_to_usdc[0]
            return self.execute_trade(pairing=symusdc, qty=tax_due_as_sym, side='sell')
        symbtc = path_to_usdc[0]
        btcusdc = path_to_usdc[1]
        tax_to_btc = self.execute_trade(pairing=symbtc, qty=tax_due_as_sym, side='sell')[0]
        return self.execute_trade(pairing=btcusdc, qty=tax_to_btc, side='sell')
        # format_a_decimal() isn't necessary in either of these conditionals because execute_trade() calls it
        # before returning
    #     TODO this is untested, spun it while running a different OS where I don't have my API keys
    #     TODO add commit description to record on ubuntu

    # execute_trade() actually executes the trade
    def execute_trade(self, pairing: str, qty: Decimal, side: str = 'buy') -> tuple:
        pairing = pairing.upper()
        side = side.lower()  # make it lower because that's how i made my _input_check() want it
        input_check = self._input_check(pairing=pairing, side=side, qty=qty)
        if input_check is not True:
            return input_check
        side = side.upper()  # making it upper now to format for insertion into the query string
        lot_size = self._get_pairing_lot_size(pairing, side)
        qty = self.format_a_decimal(qty, lot_size=lot_size)
        qty = str(qty)

        # split the pairing, determine the balance of the asset being gained,
        # store the balance compare with new balance after the order is executed
        # so it can be returned, I don't see a way to do this through Binance API
        # an alternative approach might've been to use newOrderRespType=FULL below, and
        # derive it from the 'fills' values, but this seemed easier
        quote_asset, base_asset = self.split_a_pairing(pairing)
        if side == 'BUY':
            asset_to_use = quote_asset
        else:
            asset_to_use = base_asset
        bal_before_acquiring = tuple(self.get_balances(asset_to_use))

        # construct the query_string and signature
        symbol = 'symbol=' + pairing + '&'
        side = 'side=' + side + '&'
        type_ = 'type=' + 'MARKET&'  # TODO implement limit orders someday maybe
        quantity = 'quantity=' + qty + '&'
        new_order_resp_type = 'newOrderRespType=RESULT&'
        timestamp = 'timestamp=' + str(int(time.time()) * 1000)
        query_string = symbol + side + type_ + quantity + new_order_resp_type + timestamp
        sig = self.get_signature(query_string)

        # POST the order
        order = requests.post(self.API_URL + 'v3/order?' + query_string + '&signature=' + sig, headers=self.headers)
        if order.status_code >= 400:
            return order.status_code

        # parse and return results
        result = order.json()
        bal_after_acquiring = tuple(self.get_balances(asset_to_use))  # returns a Decimal
        amt_of_asset_acquired = Decimal(bal_after_acquiring[0][0]) - Decimal(bal_before_acquiring[0][0])
        # these are only casted as Decimal to humor my IDE ^
        amt_of_asset_acquired = self.format_a_decimal(amt_of_asset_acquired, lot_size=lot_size)
        return amt_of_asset_acquired, asset_to_use, result
        # returns a tuple: (Decimal containing amount acquired, asset acquired, binance's response to POST)

    # get_pairing_list() returns a tuple of possible pairings available on binance
    # oddly, USDCBTC returns as a valid pairing, when it is not, resulting in changes to several of
    # this class' functions
    def get_pairing_list(self) -> tuple:
        symbols_string = requests.get(self.API_URL + 'v1/exchangeInfo')
        symbols_json = symbols_string.json()
        return_list = []
        for item in symbols_json['symbols']:
            return_list.append(item['symbol'])
        return_list.remove('USDCBTC')
        return_list.remove('USDCBNB')
        return_list.remove('USDCUSDT')
        return_list.remove('USDCTUSD')
        return_list.remove('USDCPAX')
        return tuple(return_list)

    # _get_asset_symbols() returns a tuple of asset symbols
    # pairing_side:'quote' produces a list of symbols that are the first part of a pairing
    # pairing_side:'base' produces a list of symbols that are in the second part (all of them,
    # in one pairing or another. use 'base to generate a list of every asset binance handles
    def _get_asset_symbols(self, pairing_side: str = 'base') -> tuple:
        pairing_side = pairing_side.lower()
        input_check = self._input_check(None, None, None, None, pairing_side)
        if input_check is not True:
            return input_check
        symbols_string = requests.get(self.API_URL + 'v1/exchangeInfo')
        symbols_json = symbols_string.json()
        assets_set = set()
        if pairing_side == 'base':
            assets_set.add('USDT')
            assets_set.add('USDC')
        for item in symbols_json['symbols']:
            assets_set.add(item[pairing_side + 'Asset'])  # add each asset to a set to remove duplicates
        return tuple(assets_set)

    # get_valid_pairing() returns a tuple for a valid pairing if one exists for the given assets
    # it returns the side assuming you want to acquire the first symbol in the parameters
    # so if the asset sides (quote, base) had to be switched for a valid pairing, it also switches the side
    # (ex: ARDRETH only exists but you send ETH as quote asset and ARDR as base), then it returns sell instead of buy
    def get_valid_pairing(self, quote_asset: str, base_asset: str) -> Tuple[str, str, str, str] or tuple:

        base_asset, quote_asset = base_asset.upper(), quote_asset.upper()

        input_check_q = self._input_check(None, None, None, quote_asset, None)
        input_check_b = self._input_check(None, None, None, base_asset, None)
        input_check_pqb = self._input_check(quote_asset + base_asset)
        input_check_pbq = self._input_check(base_asset + quote_asset)

        if input_check_b is not True:
            return input_check_b
        if input_check_q is not True:
            return input_check_q
        if input_check_pqb is not True and input_check_pbq is not True:
            return input_check_pqb

        if input_check_pqb is True:
            return quote_asset + base_asset, \
                   quote_asset, \
                   base_asset, \
                   'buy'
        elif input_check_pbq is True:
            return base_asset + quote_asset, \
                   base_asset, \
                   quote_asset, \
                   'sell'
        # returns: (pairing, base asset symbol, quote asset symbol, side)

    # _split_a_pairing() takes a pairing and returns two separate asset symbols
    # if ret_valid_pairing is False it returns two valid symbols in the order passed in,
    # regardless of if there's a valid pairing
    # if ret_valid_pairing is True it will flip the symbols around to make a valid pairing if necessary
    def split_a_pairing(self, pairing_to_split: str, ret_valid_pairing: bool = False) -> Tuple[str, str] or str:
        quote_asset, base_asset = self._pair_splitter(pairing_to_split)
        input_check_qa = self._input_check(symbol=quote_asset)
        input_check_ba = self._input_check(symbol=base_asset)
        if input_check_qa is not True:
            return input_check_qa
        elif input_check_ba is not True:
            return input_check_ba
        if ret_valid_pairing is False:
            return quote_asset, base_asset

        qa_plus_ba = quote_asset + base_asset
        ba_plus_qa = base_asset + quote_asset
        input_check_p1 = self._input_check(pairing=qa_plus_ba)
        input_check_p2 = self._input_check(pairing=ba_plus_qa)

        if input_check_p1 is True:  # this has to have 'is True,' a tuple is returned otherwise, tuple isn't false
            return quote_asset, base_asset
        elif input_check_p2 is True:
            return base_asset, quote_asset
        else:
            if input_check_p1 is not True:
                return input_check_p1
            if input_check_p2 is not True:
                return input_check_p2

    # does the actual splitting for _split_a_pairing()
    def _pair_splitter(self, pairing_to_split: str) -> Tuple[str, str]:
        # input will be checked in _split_a_pairing(), so no need for that here
        while True:
            for symbol in self._get_asset_symbols():
                if symbol == pairing_to_split[0:len(symbol)]:
                    quote = symbol
                    base = pairing_to_split[len(symbol):]
                    base_check = self._input_check(symbol=base)
                    if base_check is True:
                        return quote, base

    # USDC is the asset this program has to use every single transaction, so if a pairing with it
    # doesn't exist this function returns a 'pairing path' to USDC so I can pay the tax man
    def _get_pairing_path_to_usdc(self, symbol: str) -> Tuple[str] or Tuple[str, str]:
        symbol = symbol.upper()
        pairings_with_asset = []
        input_check = self._input_check(None, None, None, symbol, None)
        if input_check is not True:
            return input_check
        else:
            for pairing in self.get_pairing_list():  # grabs all possible pairings for the asset
                if symbol in pairing:
                    pairings_with_asset.append(pairing)
            pairing_path = []
            for pairing in pairings_with_asset:  # cycles through all possible pairings
                if 'USDC' in pairing:   # if there's a direct pairing with USDC, then great!
                    pairing_path.append(pairing)
                    return tuple(pairing_path)
            for pairing in pairings_with_asset:  # if not, add the asset's BTC pairing to a list, then add BTCUSDC to it
                if 'BTC' in pairing:
                    pairing_path.append(pairing)
                    pairing_path.append('BTCUSDC')
                    return tuple(pairing_path)
        # this only works because every single asset on Binance has a BTC pairing. if that changes later
        # then this logic has to change
        # TODO rethinking this to work around that sounds like a fun challenge for later

    # formatting for these parameters (like pairing.upper() or side.lower()
    # in the following functions should done in the functions that send them
    # since they use those arguments too

    # these functions check user input in the cli, and tells you if you constructed something wrong in a gui

    def _confirm_pairing_valid(self, pairing: str) -> bool:
        for item in self.get_pairing_list():
            if pairing == item:
                return True
        return False

    def _confirm_symbol_valid(self, symbol: str) -> bool:
        for item in self._get_asset_symbols():
            if symbol == item:
                return True
        return False

    @staticmethod
    def _confirm_valid_side(side: str) -> bool:
        if side == 'buy' or side == 'sell':
            return True
        return False

    @staticmethod
    def _confirm_nonzero_qty(qty: Decimal) -> bool:
        if qty > decimal_zero:
            return True
        return False

    @staticmethod
    def _confirm_valid_pairing_side(pairing_side: str) -> bool:
        if pairing_side == 'quote' or pairing_side == 'base':
            return True
        return False

    # makes sure that all the parameters of a function being called are valid
    def _input_check(self, pairing: str = None, side: str = None,
                     qty: Decimal = None, symbol: str = None,
                     pairing_side: str = None) -> bool or tuple:
        error_list = []
        if pairing is not None:
            if not self._confirm_pairing_valid(pairing) or pairing == 'USDCBTC' \
                    or pairing == 'USDCBNB' or pairing == 'USDCUSDT' or pairing == 'USDCTUSD' \
                    or pairing == 'USDCPAX':
                error_list.append('invalidPairing')
        if side is not None:
            if not self._confirm_valid_side(side):
                error_list.append('invalidSide')
        if qty is not None:
            if not self._confirm_nonzero_qty(qty):
                error_list.append('invalidDecimal')
        if symbol is not None:
            if not self._confirm_symbol_valid(symbol):
                error_list.append('invalidSymbol')
        if pairing_side is not None:
            if not self._confirm_valid_pairing_side(pairing_side):
                error_list.append('invalidPairingSide')
        if not error_list:
            return True
        return tuple(error_list)

    #   Examples:
    #       pairing: 'ETHUSDC'
    #       side: 'buy' or 'sell'
    #       qty: decimal.Decimal('4.513')
    #       symbol: 'ETH'
    #       pairing_side: 'quote' or 'base'

    # I need these to determine the lot size in execute_trade()
    def _get_pairing_lot_size(self, pairing: str, side: str) -> str:
        # fetches this pairing's lot size
        this_lot = self._get_lot_size(pairing)
        if side == 'buy':
            return this_lot
        # below corrects a sell side issue with IOTA, but will apply to other cryptos with very large supply
        # fetches an alternate size
        alt_pairing = self._get_alt_lot_pairing(pairing)
        alt_lot = self._get_lot_size(alt_pairing)
        # goes with whichever's bigger if side sent is 'sell'
        if len(alt_lot) > len(this_lot):
            return alt_lot
        return this_lot

    def _get_lot_size(self, pairing: str):
        symbols_string = requests.get(self.API_URL + 'v1/exchangeInfo')
        if symbols_string.status_code >= 400:
            return symbols_string.status_code
        symbols_json = symbols_string.json()
        for item in symbols_json['symbols']:
            if item['symbol'] == pairing:
                for filter_dict in item['filters']:
                    if filter_dict['filterType'] == 'LOT_SIZE':
                        return str(filter_dict['minQty']).rstrip('0')

    # if there's any pairings where the sent base can be used as a quote, _pairing_with_given_base_as_quote()
    # returns it, otherwise it returns None
    # binance appears to default to the larger lot size for a symbol in a pair, so I have to compare two pairings
    # to get an appropriate lot size
    def _get_alt_lot_pairing(self, pairing: str) -> str:
        quote, base = self.split_a_pairing(pairing)
        if base == 'USDC':
            return 'USDCBTC'
        if base == 'ETH':
            return 'ETHBTC'
        if base == 'TUSD':
            return 'TUSDBTC'
        if base == 'USDS':
            return 'USDSPAX'
        if base == 'PAX':
            return 'PAXBTC'
        if base == 'TRX':
            return 'TRXBTC'
        if base == 'BNB':
            return 'BNBBTC'
        if base == 'BTC':
            return 'BTCUSDT'
        if base == 'XRP':
            return 'XRPBTC'
        if base == 'USDT':
            return pairing


from socket import *
import json
import threading
import time

# map x in range in_min - in_max to the new range out_min - out_max
def valueMap(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

def progress_bar(x, x_min, x_max, width=30, pchar='#'):
    print("[ ", end='')
    converted = int(valueMap(x, x_min, x_max, 0, width))
    for i in range(converted):
        print(pchar, end='')
    for i in range(width-converted):
        print(" ", end='')
    print(f" ]  {x} / {x_max}")

class UdpDummySender():
    def __init__(self):
        self.cs = socket(AF_INET, SOCK_DGRAM)
        self.cs.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        self.cs.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
        self.load_gps_data()

    def send_object(self, obj):
        """
        test out all paket types

        """
        as_str = json.dumps(obj).encode(encoding='ascii')
        self.cs.sendto(as_str, ('255.255.255.255', 5005))
        print("sending:", as_str)

    def load_gps_data(self):
        with open('gps_data.json', 'r') as file:
            data = file.read()
            self.gps_data = json.loads(data)

    def send_gps_data(self, freq = 60):
        for payload in self.gps_data:
            self.send_object(payload)
            time.sleep(1 / freq)

if __name__ == '__main__':
    sender = UdpDummySender()
    while 1:
        sender.send_gps_data(freq = 60)


import pymysql
import warnings
import keras
from keras.preprocessing.sequence import pad_sequences
from keras.preprocessing.text import Tokenizer
from keras.models import load_model
import jieba
import pickle
import json
import numpy as np
import re
from env_paras import *

def load_models():
    tokenizer_maincat = pickle.load(open(MODEL_MAIN_TOKEN, 'rb'))
    cnn_maincat = load_model(MODEL_MAIN, compile=False)
    tokenizer_cat = pickle.load(open(MODEL_SUB_TOKEN, 'rb'))
    cnn_cat = load_model(MODEL_SUB, compile=False)
    jieba.load_userdict(MODEL_DICC)

    cnn_maincat.predict(pad_sequences([[0]], maxlen=37))
    cnn_cat.predict(pad_sequences([[0]], maxlen=55))

    return (tokenizer_maincat, cnn_maincat, tokenizer_cat, cnn_cat)

tokenizer_maincat, cnn_maincat, tokenizer_cat, cnn_cat = load_models()

def remove_puncs(x, puncs):
    for s in puncs:
        x = x.replace(s, ' ')
    return x

def remove_units(x, units):
    for u in units:
        if u in x:
            x.remove(u)
    return x

def preclean(df, col_name):
    if col_name not in list(df.columns):
        puncs = PUNCS
        df[col_name] = df['goods_name'].apply(lambda x: re.sub(r'\d+', ' ', str(x)))
        df[col_name] = df[col_name].apply(lambda x: remove_puncs(x, puncs))

    return df

def predict_maincat(df, maxlen, col_name, tokenizer, cnn):
    units = UNITS.split('|')
    df[col_name] = df[col_name].astype('str')
    df['segmentation'] = df[col_name].apply(
        lambda x: list(' '.join([' '.join(jieba.cut(seg)) for seg in x.split()]).split()))
    df['segmentation'] = df['segmentation'].apply(lambda x: remove_units(x, units))

    x = df['segmentation']
    x = tokenizer.texts_to_sequences(x)
    x = pad_sequences(x, maxlen=maxlen)
    predict = cnn.predict_classes(x)
    df['CNN_cat1'] = predict
    labelmap = {CLASS_NAME_LIST[0]: 0, CLASS_NAME_LIST[1]: 1, CLASS_NAME_LIST[2]: 2, CLASS_NAME_LIST[3]: 3, CLASS_NAME_LIST[4]: 4}
    df['CNN_cat1'] = df['CNN_cat1'].map(dict(zip(labelmap.values(), labelmap.keys())))

    return df

def predict_category(df, maxlen, col_name, prob_threshold, tokenizer_cat, cnn_cat):
    # 读取模型
    with open(MODEL_LABEL_JSON, 'r', encoding='utf8')as f:
        label_cat_dicc = json.load(f)
        label_cat_dicc = dict(zip(map(int, label_cat_dicc.keys()), label_cat_dicc.values()))

    with open(MODEL_NAME_JSON, 'r', encoding='utf8')as f:
        cat_name_dicc = json.load(f)

    pred_category = []

    for idx, row in df.iterrows():
        if row['CNN_cat1'] == CLASS_NAME_LIST[1] or row['CNN_cat1'] == CLASS_NAME_LIST[2]:
            seqs = pad_sequences(tokenizer_cat.texts_to_sequences([row['segmentation']]), maxlen)
            pred = cnn_cat.predict_proba(seqs)[0]
            max_idx = np.argmax(pred)
            if np.max(pred) >= prob_threshold:
                pred_category.append(cat_name_dicc[label_cat_dicc[max_idx]])
            else:
                pred_category.append(row['CNN_cat1'])
        else:
            pred_category.append(row['CNN_cat1'])
    df['CNN_cat2'] = pred_category

    return df.drop([col_name, 'CNN_cat1', 'segmentation'], axis=1)


import argparse
import copy

import numpy as np
import torch
import torch.nn as nn
from torch.optim.lr_scheduler import StepLR

from data_loader import ToyDataset
from model.model import GraphPairNN

def get_optimizer(name, parameters, lr, weight_decay=0):
    if name == 'sgd':
        return torch.optim.SGD(parameters, lr=lr, weight_decay=weight_decay)
    elif name == 'rmsprop':
        return torch.optim.RMSprop(parameters, lr=lr, weight_decay=weight_decay)
    elif name == 'adagrad':
        return torch.optim.Adagrad(parameters, lr=lr, weight_decay=weight_decay)
    elif name == 'adam':
        return torch.optim.Adam(parameters, lr=lr, weight_decay=weight_decay)
    elif name == 'adamax':
        return torch.optim.Adamax(parameters, lr=lr, weight_decay=weight_decay)
    else:
        raise Exception("Unsupported optimizer: {}".format(name))

# Early stopping class
class EarlySopping():
    def __init__(self, patience, delta):
        self.patience = patience
        self.delta = delta
        self.model = None
        self.counter = 0
        self.best_score = None
        self.early_stop = False
        self.val_loss_min = np.Inf

    def __call__(self, val_loss, model):
        if self.best_score is None:
            self.best_score = -val_loss
            self.checkpoint(val_loss, model)
        elif -val_loss < self.best_score - self.delta:
            self.counter += 1
            if self.counter >= self.patience:
                self.early_stop = True
        else:
            self.best_score = -val_loss
            self.checkpoint(val_loss, model)
            self.counter = 0

    def checkpoint(self, val_loss, model):
        torch.save(model.state_dict(), 'checkpoint.pt')
        self.val_loss_min = val_loss

def train(model, optimizer, scheduler, loss_fn, x_data, y_data):
    """Train the model on `num_steps` batches
    Args:
        model: (torch.nn.Module) the neural network
        optimizer: (torch.optim) optimizer for parameters of model
        scheduler: (torch.optim.lr_scheduler) scheduler to adapt learning rate of optimizer
        loss_fn: a function that takes batch_output and batch_labels and computes the loss for the batch
        x_data: input training data
        y_data: output training data
    """

    # set model to training mode
    model.train()

    # clear previous gradients, compute gradients of all variables wrt loss
    optimizer.zero_grad()

    # reshape data for loss function

    logits = model(x_data)
    logits = logits.reshape(shape=(x_data.shape[0]*x_data.shape[1], x_data.shape[1]))
    target = y_data.reshape(shape=(y_data.shape[0]*y_data.shape[1],))
    loss = loss_fn(logits, target)
    loss.backward()

    # performs updates using calculated gradients
    optimizer.step()
    scheduler.step()

    return loss.item()

def evaluate(model, criterion, x_data, y_data):
    model.eval()

    logits = model(x_data)
    logits = logits.reshape(shape=(x_data.shape[0] * x_data.shape[1], x_data.shape[1]))
    target = y_data.reshape(shape=(y_data.shape[0] * y_data.shape[1],))
    loss = criterion(logits, target)
    preds = torch.max(logits, dim=1)[1]
    correct = preds.eq(target).double()
    accuracy = correct.sum() / logits.shape[0]

    return loss.item(), preds, accuracy.item()

def train_and_evaluate(model, data, optimizer, scheduler, loss_fn, params, dev):
    """Train the model and evaluate every epoch.
    Args:
        model: (torch.nn.Module) the neural network
        data: (tuple of ndarrays) x and y data
        optimizer: (torch.optim) optimizer for parameters of model
        loss_fn: a function that takes batch_output and batch_labels and computes the loss for the batch
        scheduler: scheduler to adapt learning rate during training
        params: (Params) hyperparameters
        dev: the device to which to copy tensor objects
    """

    # Splitting data into train, val, test
    x_train, x_validate, x_test = np.split(data[0], [int(.6*len(data[0])), int(.8*len(data[0]))])
    y_train, y_validate, y_test = np.split(data[1], [int(.6 * len(data[1])), int(.8 * len(data[1]))])

    x_train = torch.from_numpy(x_train).type(torch.FloatTensor)
    y_train = torch.from_numpy(y_train).type(torch.LongTensor)
    x_validate = torch.from_numpy(x_validate).type(torch.FloatTensor)
    y_validate = torch.from_numpy(y_validate).type(torch.LongTensor)
    x_test = torch.from_numpy(x_test).type(torch.FloatTensor)
    y_test = torch.from_numpy(y_test).type(torch.LongTensor)

    # Copying the data to the correct device
    x_train.to(dev)
    x_validate.to(dev)
    x_test.to(dev)
    y_train.to(dev)
    y_validate.to(dev)
    y_test.to(dev)

    # Early stopping setup
    stop = EarlySopping(params['patience'], params['delta'])

    best = 0.0
    results = []

    for epoch in range(0, opt['epochs']):

        # compute number of batches in one epoch (one full pass over the training set)
        # -----------------------
        # Train Model
        # -----------------------
        loss = train(model, optimizer, scheduler, loss_fn, x_train, y_train)
        # -----------------------
        # Evaluate Model
        # -----------------------
        _, preds, accuracy_dev = evaluate(model, loss_fn, x_validate, y_validate)
        # -----------------------
        # Test Model
        # -----------------------
        _, preds, accuracy_test = evaluate(model, loss_fn, x_test, y_test)

        print(
            'Epoch: {} | Loss: {:.3f} | Dev acc: {:.3f} | Test acc: {:.3f}'.format(
                epoch,
                loss,
                accuracy_dev,
                accuracy_test))
        results += [(accuracy_dev, accuracy_test)]
        if accuracy_dev > best:
            best = accuracy_dev
            state = dict([('model', copy.deepcopy(model.state_dict())),
                          ('optim', copy.deepcopy(optimizer.state_dict()))])
        # -----------------------
        # Early stopping
        # -----------------------
        # stop(accuracy_dev, model)
        # if stop.early_stop:
        #     print("Early stopping")
        #     break

    _, preds, accuracy_test = evaluate(model, loss_fn, x_test, y_test)
    print(str(accuracy_test))

def main(params, dev):

    # Load data (for now toy data)
    data = ToyDataset(1,size=1024,n_pools=10,samples=10,input_size=32,dist='perm')

    # Creating model
    model = GraphPairNN(params['input_size'], params['input_size'], params['input_size'])
    model_param = [p for p in model.parameters() if p.requires_grad]

    # Creating optimizer and scheduler
    optimizer = get_optimizer(params['optimizer'], model_param, params['lr'], params['decay'])
    scheduler = StepLR(optimizer, params['step'], params['gamma'])

    train_and_evaluate(model, (data.get_x(), data.get_y()), optimizer, scheduler, nn.CrossEntropyLoss(), params, dev)

    return None

if __name__ == '__main__':
    #-------------------------------
    # Parsing program input
    #-------------------------------
    parser = argparse.ArgumentParser()

    parser.add_argument('--dataset', type=str, default='data')
    parser.add_argument('--save', type=str, default='/')
    parser.add_argument('--input_size', type=int, default=32, help='Size of input to neural net.')
    parser.add_argument('--dropout', type=float, default=0.5, help='Dropout rate.')
    parser.add_argument('--optimizer', type=str, default='adam', help='Optimizer.')
    parser.add_argument('--lr', type=float, default=0.01, help='Learning rate.')
    parser.add_argument('--decay', type=float, default=5e-4, help='Weight decay for optimization')
    parser.add_argument('--epochs', type=int, default=200, help='Number of training epochs per iteration.')
    parser.add_argument('--seed', type=int, default=1)
    parser.add_argument('--step', type=int, default=50,
                        help='Step size on epochs after which learning rate is changed.')
    parser.add_argument('--gamma', type=float, default=1.0, help='Multiplicative factor applied to the learning after '
                                                                 'step many epochs.')
    parser.add_argument('--patience', type=int, default=5,
                        help='Patience for early stopping.')
    parser.add_argument('--delta', type=float, default=0.001, help='Delta for early stopping.')
    parser.add_argument('--cpu', action='store_true', help='Ignore CUDA, else cuda is used if available.')

    args = parser.parse_args()

    use_cuda = torch.cuda.is_available() and not args.cpu
    device = torch.device('cuda' if use_cuda else 'cpu')
    np.random.seed(args.seed)
    torch.manual_seed(args.seed)
    if use_cuda:
        torch.cuda.manual_seed(args.seed)

    opt = vars(args)

    main(opt, device)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np
import arviz as az
import pandas as pd
import matplotlib.pyplot as plt
import stan as ps
import time

# data from Gossner et al (2022)
data = pd.read_csv("https://raw.githubusercontent.com/SimonErnesto/risk_dengue_2015-2019/main/dengue_travel_europe.csv")

infected = data["infected travellers"].values.astype("int")
total = data["total travellers"].values.astype("int")
N = len(data)
country_id = data['codes'] = np.arange(1,100, dtype = int)

mod = '''
data{
int<lower=0> N;
int<lower = 1> N_countries;
array[N] int y_i;
array[N] int y_t;
array[N] int<lower = 1, upper = N_countries> country_id;
}
parameters{
vector<lower = 0>[4] hp; // hyperpriors
vector<lower = 0>[N_countries] T;
vector<lower = 0>[N_countries] I;
}
model{
hp ~ normal(0,1);
T ~ lognormal(hp[1], hp[2]);
I ~ lognormal(hp[3], hp[4]);
y_t ~ poisson(T[country_id]);
y_i ~ poisson(I[country_id]);
}
'''

datDic = {'N': N,
	  'y_i': infected,
	  'y_t': total,
	  'N_countries': N,
	  'country_id': country_id}

sm = ps.build(mod, data = datDic)
start_time = time.time()
fit = sm.sample(num_chains = 4, num_samples = 1000, num_warmup = 1000)
print("--- %s seconds ---" % (time.time() - start_time))

print(az.summary(fit))
#az.plot_pair(fit, var_names = ['I', 'T'])
#fig = plt.gcf() # to get the current figure...
#fig.savefig("pair.png")


from matplotlib import lines
import scipy
import cmath
import math
from math import pi, sin, cos, sqrt, exp
import matplotlib

import numpy as np
import progressbar

import matplotlib.pyplot as plt
matplotlib.use('Agg')
from matplotlib.path import Path
from matplotlib.patches import PathPatch
'''
# int
'''
a = 2.46               #A
b = 4*pi/(sqrt(3)*a)    #1/A, dot(a,b)=sqrt(3)a*b/2 = 2pi
S = sqrt(3)/2 * a**2    #A^2
a1 = np.array([a*sqrt(3)/2,  -a/2])
a2 = np.array([a*sqrt(3)/2,  a/2])
l_list=np.array([a1,a2])

def rotate(in_list,theta):
    # rotate k theta in raduis
    T_rotate=np.array([[cos(theta),-sin(theta)],[sin(theta),cos(theta)]])
    out_list=[]
    for i in range(2):
        k = in_list[i]
        kr = np.matmul(T_rotate,k)
        out_list.append( kr )
    out_list = np.array(out_list)
    return out_list

def rotate_2D(in_list,theta):
    # rotate k theta in raduis
    T_rotate=np.array([[cos(theta),-sin(theta)],[sin(theta),cos(theta)]])
    kr = np.matmul(T_rotate, in_list)
    out_list = np.array(kr)
    return out_list

def rotate_3D(in_list,theta):
    # rotate k theta in raduis
    T_rotate=np.array([[cos(theta),-sin(theta), 0],[sin(theta),cos(theta), 0], [0, 0, 1]])
    kr = np.matmul(T_rotate, in_list)
    out_list = np.array(kr)
    return out_list

def strian(in_list,theta,ex,ey):
    # give strain ex in diraction theta
    # and strain ey in diraction theta+pi/2
    T_rotate=np.array([[cos(theta),-sin(theta)],[sin(theta),cos(theta)]])
    T_rotate_back=np.array([[cos(-theta),-sin(-theta)],[sin(-theta),cos(-theta)]])
    T_strian = np.array([[1/(1+ex),0],[0,1/(1+ey)]])
    T_sum = np.matmul(T_rotate,np.matmul(T_strian,T_rotate_back))
    out_list=[]
    for i in range(2):
        k = in_list[i]
        kr = np.matmul(T_sum,k)
        out_list.append( kr )
    out_list = np.array(out_list)
    return out_list

def gen_revise_vectors(input_vectors):
    """
    Generate reciprocal lattice vectors from real-space lattice vectors.
    or Generate real-space lattice vectors from reciprocal lattice vectors.

    NOTE: Here we evaluate reciprocal lattice vectors via
        dot_product(a_i, b_j) = 2 * pi * delta_{ij}
    The formulae based on cross-products are not robust in some cases.

    :param input_vectors: (3, 3) float64 array
        Cartesian coordinates of input lattice vectors
    :return: output_vectors: (3, 3) float64 array
        Cartesian coordinates of output lattice vectors.
    """
    output_vectors = np.zeros((2, 2))
    product = 2 * pi * np.eye(2)
    for i in range(2):
        output_vectors[i] = np.linalg.solve(input_vectors, product[i])
    return output_vectors

def cart2frac(k_base, k_in):
    """
    Convert k_in to combination of k_base.

    :param k_base: (2, 2) float64 array
        Cartesian coordinates of base k vectors
    :param k_in: (num_coord, 2) float64 array
        Cartesian coordinates to convert
    :return: fractional_coordinates: (num_coord, 3) float64 array
        fractional coordinates in basis of lattice vectors
    """
    fractional_coordinates = np.zeros(k_in.shape)
    conversion_matrix = np.linalg.inv(k_base.T)
    for i, row in enumerate(k_in):
        fractional_coordinates[i] = np.matmul(conversion_matrix, row.T)
    return fractional_coordinates

def plot_reciprocal(k_top,k_bottom,k_moire,k_list):
    fig, ax = plt.subplots()
    ax.set_aspect('equal')

    #   Gamma vector
    ax.arrow(0, 0, k_top[0,0]-k_list[0,0], k_top[0,1]-k_list[0,1], head_width=0.01, head_length=0.01,fc='r', ec='r',label="dK_top")
    ax.arrow(0, 0, k_top[1,0]-k_list[1,0], k_top[1,1]-k_list[1,1], head_width=0.01, head_length=0.01,fc='r', ec='r')
    ax.arrow(0, 0, k_bottom[0,0]-k_list[0,0], k_bottom[0,1]-k_list[0,1], head_width=0.01, head_length=0.01,fc='b', ec='b',label="dK_bottom")
    ax.arrow(0, 0, k_bottom[1,0]-k_list[1,0], k_bottom[1,1]-k_list[1,1], head_width=0.01, head_length=0.01,fc='b', ec='b')
    ax.arrow(0, 0, k_moire[0,0], k_moire[0,1], head_width=0.01, head_length=0.01,fc='k', ec='k',label="K_Moire")
    ax.arrow(0, 0, k_moire[1,0], k_moire[1,1], head_width=0.01, head_length=0.01,fc='k', ec='k')

    plt.text(0.5, 0.35,'k_top=\n'+str(cart2frac(k_moire, k_top))+"\n*k_moire", horizontalalignment='center',
     verticalalignment='center', transform=ax.transAxes)
    plt.text(0.5, 0.15, 'k_bottom=\n'+str(cart2frac(k_moire, k_bottom))+"\n*k_moire", horizontalalignment='center',
     verticalalignment='center', transform=ax.transAxes)
    plt.legend()
    dk1=np.linalg.norm(k_moire[0,:])
    dk2=np.linalg.norm(k_moire[1,:])
    kmax=sqrt(3)*max(dk1,dk2)
    plt.xlim((-kmax, kmax))
    plt.ylim((-kmax, kmax))
    plt.xlabel("kx (1/A)")
    plt.ylabel("ky (1/A)")
    plt.savefig(fname='reciprocal_space.png',dpi=600)
    plt.close

def plot_lattice(l_top,l_bottom,l_moire):
    fig, ax = plt.subplots()
    ax.set_aspect('equal')

    #   Gamma vector
    ax.arrow(0, 0, l_top[0,0], l_top[0,1], head_width=0.01, head_length=0.01,fc='r', ec='r',label="l_top")
    ax.arrow(0, 0, l_top[1,0], l_top[1,1], head_width=0.01, head_length=0.01,fc='r', ec='r')
    ax.arrow(0, 0, l_bottom[0,0], l_bottom[0,1], head_width=0.01, head_length=0.01,fc='b', ec='b',label="l_bottom")
    ax.arrow(0, 0, l_bottom[1,0], l_bottom[1,1], head_width=0.01, head_length=0.01,fc='b', ec='b')
    ax.arrow(0, 0, l_moire[0,0], l_moire[0,1], head_width=0.01, head_length=0.01,fc='k', ec='k',label="l_Moire")
    ax.arrow(0, 0, l_moire[1,0], l_moire[1,1], head_width=0.01, head_length=0.01,fc='k', ec='k')

    plt.text(0.5, 0.35,'L_moire=\n'+str(cart2frac(l_top, l_moire))+"\n*L_top", horizontalalignment='center',
     verticalalignment='center', transform=ax.transAxes)
    plt.text(0.5, 0.15, 'L_moire=\n'+str(cart2frac(l_bottom, l_moire))+"\n*L_bottom", horizontalalignment='center',
     verticalalignment='center', transform=ax.transAxes)
    plt.legend()
    L1=np.linalg.norm(l_moire[0,:])
    L2=np.linalg.norm(l_moire[1,:])
    theta= np.arccos(np.inner(l_moire[0,:],l_moire[1,:]) /(L1*L2))
    lmax=max(L1,L2)
    plt.xlim((-lmax, lmax))
    plt.ylim((-lmax, lmax))
    plt.xlabel("x (A)")
    plt.ylabel("y (A)")
    plt.title("L1: %3.3f A  L2:% 3.3f A\ntheta:%3.3f °" %(L1,L2, 180*theta/pi))
    plt.savefig(fname='real_space.png',dpi=600)
    plt.close

def normalization_lattice(l_top,l_bottom,l_moire):

    #print('old_L_moire=\n'+str(cart2frac(l_top, l_moire))+"\n*L_top")
    #print('old_L_moire=\n'+str(cart2frac(l_bottom, l_moire))+"\n*L_bottom")

    Matrixtop=cart2frac(l_top, l_moire)
    Matrixbottom=cart2frac(l_bottom, l_moire)
    topmin =min(np.min((np.abs(Matrixtop))),1)
    bottomin=min(np.min((np.abs(Matrixbottom))),1)
    l_moire_new = l_moire/topmin
    for i in range(0,2):
        for j in range(0,2):
            Matrixtop[i,j] = int(Matrixtop[i,j]/topmin)
            Matrixbottom[i,j] = int(Matrixbottom[i,j]/bottomin)
    l_top_new = np.matmul(np.linalg.inv(Matrixtop),l_moire_new)
    l_bottom_new = np.matmul(np.linalg.inv(Matrixbottom),l_moire_new)

    #print('L_moire=\n'+str(cart2frac(l_top_new, l_moire_new))+"\n*L_top")
    #print('L_moire=\n'+str(cart2frac(l_bottom_new, l_moire_new))+"\n*L_bottom")
    return l_top_new,l_bottom_new,l_moire_new

class tBG():
    def __init__(self):
        """
        initialize all required parameters
        """
        # def hopping constants
        self.a0 =  1.42            #: [A] C-C bond length
        self.a  =  2.46            #: [A] C-C cell length
        self.d0 =  3.35             #: [A] interlayer distance normal:3.35

    def Lattice(self,l_top,l_bottom,l_moire,topx,topy,botx,boty,zstrain,twist):
        """
        bilayerGraphene-hBN lattice.
        orbital_coords: orbital_coords[2i] is sub-lattice A,
                        orbital_coords[2i+1] is sub-lattice B,
                        and spin down part is a copy of spin up.
        """
        L = np.linalg.norm(l_moire[0,:])            #: [A] Moire period length
        print ('Moire period/nm=',L)

        def judge_and_swap(l_moire):
            L1 = np.array([l_moire[0,0], l_moire[0,1], 0])
            L2 = np.array([l_moire[1,0], l_moire[1,1], 0])
            cross_a1_a2 = np.cross(L1,L2)
            if cross_a1_a2[2] > 0: #z value of cross product of a1, a2
                #print("a2 on the anti-clockwise direction of a2, no swapping needed")
                return l_moire
            if cross_a1_a2[2] < 0:
                #print("a2 on the clockwise direction of a1, now swap a1 and a2")
                l_moire[0,0], l_moire[1,0] = l_moire[1,0], l_moire[0,0]
                l_moire[0,1], l_moire[1,1] = l_moire[1,1], l_moire[0,1]
                return l_moire

        l_moire = judge_and_swap(l_moire)
        #print("Swapped l_moire matrix is\n",l_moire)

        a1= np.array([l_moire[0,0], l_moire[0,1], 0])              #: [A] Supercell vector
        a2= np.array([l_moire[1,0], l_moire[1,1], 0])              #: [A] Supercell vector
        a3= np.array([0, 0, 6*self.d0])      #: [A] Supercell vector

        theta_old_1 = np.arctan2(a1[1], a1[0])#angle with respect to x-axis of original a1 vector
        theta_old_2 = np.arctan2(a2[1], a2[0]) #angle with respect to x-axis of original a2 vector

        #print("the old theta of a1 and a2 w.r.t. x-axis is", theta_old_1, theta_old_2)

        theta_rotate = -theta_old_1
        #print("The rotate theta is", theta_rotate)

        l_moire = rotate(l_moire, theta_rotate)

        a1= np.array([l_moire[0,0], l_moire[0,1], 0])              #: [A] Supercell vector
        a2= np.array([l_moire[1,0], l_moire[1,1], 0])
        self.vectors = [a1, a2, a3]
        #print('lattice_vectors is ',self.vectors)

        r1 = l_bottom[0,:]   #: [nm] layer1 vector
        r2 = l_bottom[1,:]   #: [nm] layer1 vector
        r1p = l_top[0,:]     #: [nm] layer3 vector
        r2p = l_top[1,:]     #: [nm] layer3 vector

       #print(r1,r2,r1p,r2p)

        r1 = rotate_2D(r1, theta_rotate)
        r2 = rotate_2D(r2, theta_rotate)
        r1p = rotate_2D(r1p, theta_rotate)
        r2p = rotate_2D(r2p, theta_rotate)
        #print(r1,r2,r1p,r2p)

        l_bottom[0,:] = r1
        l_bottom[1,:] = r2
        l_top[0,:] = r1p
        l_top[1,:] = r2p

        delta =np.append((r1 +r2 )/3,0)     #: [nm] layer1 AB vector
        deltap=np.append((r1p+r2p)/3,0)     #: [nm] layer2 AB vector
        height=np.array([0, 0, self.d0])    #: [nm] height vector
        #print(r1,r2,delta)

        orbital_coords = []
        L1= l_moire[0,:]
        L2= l_moire[1,:]
        SL= np.cross(L1,L2)
        #print(SL,L1,L2)

        def judge(orb, L1, L2):
            """
            private method:
            move the bottom-layer/layer1,2 i,j atom location
              or the    top-layer/layer3,4 j,i atom location
            """
            if (0<=np.cross(L1,orb)<SL) and (0<=np.cross(orb,L2)<SL):
                return True
            else:
                #print(np.cross(L1,orb)/SL,np.cross(orb,L2)/SL)
                return False
        bar = progressbar.ProgressBar(max_value=1600)
        print("Making TBG sample.")
        for  i in range(-800,800):
            for j in range(-800,800):
                rr1=i*r1 +j*r2
                if judge(rr1, L1, L2):
                    ra1 = np.append(rr1,-self.d0/2)
                    rb1=ra1+delta
                    orbital_coords.append(ra1) # A1
                    orbital_coords.append(rb1) # B1

                rr3=i*r1p+j*r2p
                if judge(rr3, L1, L2):
                    ra3 = np.append(rr3,self.d0/2)
                    rb3=ra3+deltap
                    orbital_coords.append(ra3) # A3
                    orbital_coords.append(rb3) # B3
            bar.update(i+800)
        #print("Done1!")

        #-Near Origin=ABBC-
        #--A3--B3--
        #--A1--B1--
        self.n_atom = len(orbital_coords)
        #print(self.n_atom)
        #print(len(orbital_coords))
        #fw = open("strain_TBG_"+str(int(round(L/10,0)))+"nm.data",'w+')
        fw = open(f"./TBG_top_x_{topx}_topy_{topy}_botx_{botx}_boty_{boty}_zstrain_{zstrain}_twist_{twist}/Strain.data",'w+')
        fw.write(("#L/Angstroms = %.4f" %(float(L))))
        fw.write(("\n%d atoms" %(int(len(orbital_coords)))))
        fw.write(("\n4 atom types"))
        fw.write(("\n"))

        fw.write(("\n%10.8f %10.8f   xlo xhi" %(float(0.),float(L1[0]))))
        fw.write(("\n%10.8f %10.8f   ylo yhi" %(float(0.),float(L2[1]))))
        fw.write(("\n%10.8f %10.8f   zlo zhi" %(float(-a3[2]),float(a3[2]))))
        fw.write(("\n"))

        fw.write(("\n %10.7f %10.7f %10.7f  xy xz yz" %(float(L2[0]),float(0.),float(0.))))
        fw.write(("\n"))

        fw.write(("\nAtoms"))
        fw.write(("\n"))
        #print("Done2!")
        for i in range(self.n_atom):
            coord = orbital_coords[i]
            if coord[2] >0:
                type =2
            else:
                type =0
            fw.write(('\n%6d %4d      %12.6f %12.6f %12.6f'
                    %(int(i+1),
                    int(type+i%2+1),
                    float(coord[0]),
                    float(coord[1]),
                    float(coord[2]))
                    ))
        #print("Done3!")
    def Sample(self,l_top,l_bottom,l_moire, topx,topy,botx,boty,zstrain,twist):
        """
        Calculate and plot tBG sample
        """
        self.Lattice(l_top,l_bottom,l_moire, topx,topy,botx,boty,zstrain,twist)

def make_sample(l_top,l_bottom,l_moire,topx,topy,botx,boty,zstrain,twist):
    tBG_sample = tBG()
    tBG_sample.d0 = zstrain
    tBG_sample.Sample(l_top,l_bottom,l_moire, topx,topy,botx,boty,zstrain,twist)
    return  tBG_sample

def make_strain_twisted_sample(ktop_x, ktop_y, kbot_x, kbot_y, twist_angle,z_strain):

    t = twist_angle*pi/180
    print("twist angle: %3.3f °"%(t*180/pi))

    k_list   = gen_revise_vectors(l_list)
    #k_top    = rotate(strian(k_list,0,x*t,y*t),t)
    #k_bottom = strian(k_list,0,z*t,0)
    k_top    = rotate(strian(k_list, 0, ktop_x, ktop_y),t)
    #k_top = strian(k_list,0, ktop_x, k_top_y)
    k_bottom = strian(k_list,0, kbot_x, kbot_y)
    k_moire  = k_top-k_bottom
    plot_reciprocal(k_top,k_bottom,k_moire,k_list)

    l_top = gen_revise_vectors(k_top)
    l_bottom = gen_revise_vectors(k_bottom)
    l_moire = gen_revise_vectors(k_moire)
    print("l_top is:",l_top)
    print("l_bot is:",l_bottom)
    l_top_new,l_bottom_new,l_moire_new=normalization_lattice(l_top,l_bottom,l_moire)
    print("l_top_new is:",l_top_new)
    print("l_bot_new is:",l_bottom_new)
    plot_lattice(l_top_new,l_bottom_new,l_moire_new)

    make_sample(l_top_new,l_bottom_new,l_moire_new, ktop_x,ktop_y,kbot_x,kbot_y,z_strain,twist_angle)


# -*- coding: utf-8 -*-
"""
Created on Fri Jul 21 10:29:18 2017

@author: X.X
"""

from pycqed.measurement.waveform_control.viewer import *
from qcodes.data.data_set import load_data, new_data, DataSet
from qcodes.data.data_array import DataArray

import numpy as np
from io import StringIO
import matplotlib.pyplot as plt
from qcodes.data.hdf5_format import HDF5Format, HDF5FormatMetadata
from qcodes.data.io import DiskIO

NewIO = DiskIO(base_location = 'C:\\Users\\LocalAdmin\\Documents')

datalocation = 'data/2017-07-21/#003_T1_10-55-59'

datalocation2 = 'data/test/T1'
#formatter = HDF5Format()

#data = load_data(location=datalocation, formatter=None, io=NewIO)

original_data = np.genfromtxt('C:/Users/LocalAdmin/Documents/data/test/T1.dat', delimiter='\t', dtype=np.float)

data = original_data[:,(0,2)]

#%% Plot
import scipy
from qtt.algorithms.functions import exp_function

datax=data.T.reshape( (2,8,-1))
datax=np.transpose(datax, (0,2,1) )

plt.figure(10); plt.clf()
for ii in range(8):
    dd=datax[:,:,ii]

    plt.plot(dd[0],dd[1], '.-')

#%% Fitting

def fitT1(xdata, ydata, verbose=1, fig=None):
    """ Determine T1 time by fitting exponential

    Arguments:
        xdata, ydata (array): independent and dependent variable data

    Returns:
        p (array): fitted function parameters
        pp (dict): extra fitting data

    .. seealso:: exp_function
    """
    xdata = np.array(xdata)
    ydata = np.array(ydata)

    timescale = np.percentile(xdata, 99)- np.percentile(xdata, 1)
    # initial values
    p0 = [np.percentile(ydata, 1), np.percentile(ydata, 99)-np.percentile(ydata, 1), 1./timescale]

    if verbose:
        print('fitT1: initial parameters %s' % (p0, ))

    # fit
    pp = scipy.optimize.curve_fit(exp_function, xdata, ydata, p0=p0)
    p = pp[0]

    if fig is not None:
        y = exp_function(xdata, *list(p))
        plt.figure(fig)
        plt.clf()
        plt.plot(xdata, ydata, '.b', label='data')
        plt.plot(xdata, y, 'm-', label='fitted exponential')
        plt.legend(numpoints=1)
    return p, dict({'pp': pp, 'p0': p0})

xdata=dd[0]
ydata=dd[1]
p, r=fitT1(xdata, ydata, verbose=1, fig=100)
#==============================================================================
#
#==============================================================================
#%%
plt.figure(10); plt.clf()
for ii in range(8):
    dd=datax[:,:,ii]
    xdata=dd[0]
    ydata=dd[1]
    p, r=fitT1(xdata, ydata, verbose=0, fig=None)
    yfit = exp_function(xdata, *list(p))

    print('fitted: %s, T1 %.3f [ms]' % (p, 1e3*1./p[2]))

    plt.plot(dd[0],dd[1], '.')
    plt.plot(dd[0],yfit, '-')

#%%

data1 = DataArray(preset_data = data)

#file = open('C:/Users/LocalAdmin/Documents/data/test/T1.dat')

#datanew = new_data(io = NewIO, name = 'testest', arrays = data1)
#dataset = DataSet(arrays = data1, io = NewIO, location = 'data/test/xiao')

#datata = np.loadtxt(name = )
Npoints = 100

#
#plt.ion()
#plt.figure()
#
#
#plt.pcolor(np.linspace(1, Npoints, num=Npoints), data.arrays[data.action_id_map[()]], res_avg)


from dataclasses import dataclass
from json import dumps as dump_json
from typing import Union

@dataclass(frozen=True)
class RocketStatsEvent:
    """Class to represent an event from the RocketStats websocket"""
    name: str
    type: str
    data: Union[str, dict]
    states: dict

    def __str__(self):
        tdata = '\n           '.join(dump_json(self.data, indent=4).split('\n'))
        tstates = '\n             '.join(dump_json(self.states, indent=4).split('\n'))

        return (
            f'RocketStatsEvent(\n'
            f'    name = {self.name},\n'
            f'    type = {self.type},\n'
            f'    data = {tdata},\n'
            f'    states = {tstates}\n'
            f')'
        )


from django.urls import path
from .views import UploadFeed, Profile, Main, UploadReply, ToggleLike, ToggleBookmark
from . import views

urlpatterns = [
    path('upload', UploadFeed.as_view()),
    path('reply', UploadReply.as_view()),
    path('like', ToggleLike.as_view()),
    path('bookmark', ToggleBookmark.as_view()),
    path('profile', Profile.as_view()),
    path('<int:pk>/delete/', views.feed_delete),
    path('<int:pk>/update/', views.feed_update),
]


import pandas as pd

from utils import ordinal

def update_readme_with_prediction(
    readme_path,
    draw_no,
    predicted_numbers_text,
):
    # README 파일 읽기
    with open(readme_path, "r", encoding="utf-8") as file:
        lines = file.readlines()

    # 새로운 예측 내용 추가
    new_content = f"{predicted_numbers_text}\n- {ordinal(draw_no)} actual numbers:\n"

    # 예측 번호 추가
    for i, line in enumerate(lines):
        if line.strip() == "### Latest Prediction":
            lines.insert(i + 2, new_content)
            break

    # README 파일 다시 쓰기
    with open(readme_path, "w", encoding="utf-8") as file:
        file.writelines(lines)

if __name__ == "__main__":
    # 예시 사용
    readme_path = "README.md"
    df = pd.read_json("data/lotto_numbers.jsonl", lines=True)
    draw_no = df.iloc[-1]["drwNo"] + 1  # 회차 번호

    with open(f"predicted/{ordinal(draw_no)}_lottery_numbers.txt", "r") as f:
        predicted_numbers_text = f.read().strip()

    update_readme_with_prediction(readme_path, draw_no, predicted_numbers_text)


#from collections import deque
import collections
def countStudents(students, sandwiches):
    queue = collections.deque(students)
    # queue = deque(students) #Doubly ended queue

    for sandwich in sandwiches:

        if sandwich in queue:
            while queue[0] != sandwich:
                x = queue.popleft()
                queue.append(x)  # append is always right side

            queue.popleft()   # student took sandwich of his choice and left. At the end, it is better to count the num of students left.

        else:
            return len(queue)

    return 0   # if sandwich hi nahi hai toh students bhi nahi bache hain, isliye hungry students = 0

# Driver Code
if __name__ == "__main__":
    students = [1,1,1,0,0,1]
    sandwiches = [1,0,0,0,1,1]

    studentsUnableToEatLunch = countStudents(students, sandwiches)
    print("Student Unable to Eat Lunch: ", studentsUnableToEatLunch)


import time
import board
import adafruit_dht
import pymongo
import datetime

#連線DB
client = pymongo.MongoClient('mongodb://localhost:27017/')
db = client["database"]
col = db["weathers1"]

dhtDevice = adafruit_dht.DHT22(board.D24, use_pulseio=False)

while True:
    try:
        # Print the values to the serial port
        temperature_c = dhtDevice.temperature
        temperature_f = temperature_c * (9 / 5) + 32
        humidity = dhtDevice.humidity

        post={"temperature_c":temperature_c,
              "humidity":humidity,
              "date":datetime.datetime.now()}
        x=col.insert_one(post);
        print(x);

    except RuntimeError as error:
        # Errors happen fairly often, DHT's are hard to read, just keep going
        print(error.args[0])
        time.sleep(2.0)
        continue
    except Exception as error:
        dhtDevice.exit()
        raise error

    time.sleep(60*60)