import pygame

from UI.base_object import BaseObject
from Structures.unlimited_grid import UnlimitedGrid
from square import Square
from consts import WinningOptions, Direction

class Board(BaseObject):
    class Tracker:
        def __init__(self):
            self.row = 0
            self.col = 0

        def __repr__(self):
            return f"{self.row} {self.col}"

    def __init__(self,
                 window,
                 x, y, side_size,
                 bg_color, fg_color, strike_through_color,
                 showed_grid_size=3):

        # <editor-fold desc="Helper Init Functions">
        def get_line_thickness() -> int:
            if self.showed_grid_size <= 4:
                return 8
            if self.showed_grid_size <= 10:
                return 4
            return 2

        def get_square_size() -> float:
            return (self.width - self.line_thickness * (self.showed_grid_size - 1)) / self.showed_grid_size

        def get_unit() -> float:
            return self.square_size + self.line_thickness

        # </editor-fold>

        super().__init__(window, x, y, side_size, side_size)

        self.showed_grid_size = showed_grid_size

        self.line_thickness = get_line_thickness()
        self.square_size = get_square_size()
        self.unit_size = get_unit()

        self.fg_color = fg_color
        self.bg_color = bg_color
        self.strike_through_color = strike_through_color

        Square.set_globals(
            self.fg_color,
            None,
            pygame.font.SysFont("Comic Sans MS", int(self.square_size * 0.9)),
            self.square_size,
            self.window,
        )

        self.tracker = Board.Tracker()
        self.grid = UnlimitedGrid(Square.new_square, self.__get_base_grid())
        self.showed_grid = []
        self.__update_showed_grid()

    @property
    def squares(self):
        return [sq for row in self.showed_grid for sq in row]

    # <editor-fold desc="Private Methods">
    def __get_base_grid(self):
        return [
            [Square(row=i, col=j, **self.__get_square_pos(i, j)) for j in range(self.showed_grid_size)]
            for i in range(self.showed_grid_size)
        ]

    def __get_square_pos(self, row, col) -> dict[str, float]:
        x = self.x + col * self.unit_size
        y = self.y + row * self.unit_size
        return {"x": x, "y": y}

    def __update_showed_grid(self):
        # get new squares
        self.showed_grid = [
            [self.grid[i+self.tracker.row, j+self.tracker.col] for j in range(self.showed_grid_size)]
            for i in range(self.showed_grid_size)
        ]

        # update squares' (x, y)
        for i, row in enumerate(self.showed_grid):
            for j, sq in enumerate(row):
                sq.set_pos(**self.__get_square_pos(i, j))

    # </editor-fold>

    def draw_squares(self):
        for sq in self.squares:
            if sq.is_clicked:
                sq.draw_mark()

    def move(self, direction):
        if direction == Direction.up:
            self.tracker.row -= 1
        elif direction == Direction.down:
            self.tracker.row += 1
        elif direction == Direction.left:
            self.tracker.col -= 1
        elif direction == Direction.right:
            self.tracker.col += 1
        else:
            raise ValueError("Invalid direction", direction)

        self.__update_showed_grid()
        self.draw_grid()
        self.draw_squares()

    def draw_grid(self):
        self.window.fill(self.bg_color, (self.x, self.y, self.width, self.height))

        # vertical lines
        x = self.x + self.square_size + self.line_thickness / 2
        y = self.y
        for i in range(self.showed_grid_size - 1):
            pygame.draw.line(
                self.window,
                self.fg_color,
                (x, y),
                (x, y + self.height),
                self.line_thickness
            )
            x += self.square_size + self.line_thickness

        # horizontal lines
        x = self.x
        y = self.y + self.square_size + self.line_thickness / 2
        for i in range(self.showed_grid_size - 1):
            pygame.draw.line(
                self.window,
                self.fg_color,
                (x, y),
                (x + self.width, y),
                self.line_thickness
            )
            y += self.square_size + self.line_thickness

        pygame.display.update()

    def clear_grid(self):
        self.draw_grid()

    def draw_strike_through(self, sequence: list[Square], winning_option):
        # horizontal
        if winning_option == WinningOptions.horizontal:
            sequence.sort(key=lambda x: x.col)
            first, last = sequence[0], sequence[-1]
            start_x, start_y = first.x, first.y + first.side_size / 2
            end_x, end_y = last.x + last.side_size, start_y
            pygame.draw.line(
                self.window,
                self.strike_through_color,
                (start_x, start_y),
                (end_x, end_y),
                self.line_thickness)

        # vertical
        elif winning_option == WinningOptions.vertical:
            sequence.sort(key=lambda x: x.row)
            first, last = sequence[0], sequence[-1]
            start_x, start_y = first.x + first.side_size / 2, first.y
            end_x, end_y = start_x, last.y + last.side_size
            pygame.draw.line(
                self.window,
                self.strike_through_color,
                (start_x, start_y),
                (end_x, end_y),
                self.line_thickness)

        # diagonal \
        elif winning_option == WinningOptions.neg_diagonal:
            sequence.sort(key=lambda x: x.col)
            first, last = sequence[0], sequence[-1]
            start_x, start_y = first.x, first.y
            end_x, end_y = last.x + last.side_size, last.y + last.side_size
            pygame.draw.line(
                self.window,
                self.strike_through_color,
                (start_x, start_y),
                (end_x, end_y),
                int(self.line_thickness * 1.5)
            )

        # diagonal /
        elif winning_option == WinningOptions.pos_diagonal:
            sequence.sort(key=lambda x: x.col)
            first, last = sequence[0], sequence[-1]
            start_x, start_y = first.x, first.y + first.side_size
            end_x, end_y = last.x + last.side_size, last.y
            pygame.draw.line(
                self.window,
                self.strike_through_color,
                (start_x, start_y),
                (end_x, end_y),
                int(self.line_thickness * 1.5)
            )

        pygame.display.update()

    def reset(self):
        self.tracker = Board.Tracker()
        self.grid = UnlimitedGrid(Square.new_square, self.__get_base_grid())
        self.__update_showed_grid()


#!/usr/bin/python
# -*- coding: utf-8 -*-
# Author: Andreas Buttenschoen
import warnings
import numpy as np
import scipy.sparse as sps

try:
    from scipy.sparse import csr_array, csc_array
except ImportError:
    from scipy.sparse import csr_matrix as csr_array
    from scipy.sparse import csc_matrix as csc_array

from ..fun import Mapping
from ..cheb import chebtech

from .projection import RectangularProjection

class OpDiscretization:
    """ Converts an infinite dimensional operator to discrete form """
    def __init__(self, source=None, *args, **kwargs):
        self.dimension = np.atleast_1d(kwargs.get('dimension', 1))
        self.domain = np.asarray(kwargs.get('domain', [-1, 1]))
        self.numIntervals = self.domain.size - 1

        # the linear operator that we are discretizing
        self.source = source

        # create a domain mapping
        self.mapping = Mapping(ends=self.domain)

        # TEMP -> these should be a part of the source!
        self.constraints = self.source.constraints if self.source is not None else []
        self.continuity  = kwargs.pop('continuity', [])

        # the return type
        self.returnTech = chebtech

        # the projection
        self.projection = None

        # Setup shape
        self.shape = kwargs.pop('shape',
                                (self.dimension.squeeze().item(),
                                 self.source.quasiOp.shape[0]) if self.source else None)

        # the default change of basis matrix
        self.S0 = None

    @property
    def numConstraints(self):
        return len(self.constraints) + len(self.continuity)

    def getDimAdjust(self):
        """ size of the input space relative to disc.dicretization """
        return self.source.getDimAdjust()

    def getProjOrder(self):
        """ projection order for the rectangualization """
        return self.source.getProjOrder()

    def matrix(self, *args, **kwargs):
        """ Creates the discretized approximation of the linear or nonlinear
        operator. Currently this function uses rectangularization to
        impose functional constraints on solutions.
        """
        M, Pc, S0 = self.instantiate(self.source.quasiOp, *args, **kwargs)
        PM, P, PS = self.reduce(M, S0)

        # If we have defined constraints add them!
        if self.numConstraints > 0:
            B = self.getConstraints(PM.shape[1])

            # Check that B-rows are not zero
            if np.all(np.sum(np.abs(B), axis=1) == 0.0):
                warnings.warn('OpDiscretization: Boundary condition rows have zero l1 norm!\nMost likely the resulting matrix will be singular! Double check your boundary conditions!')

            # Append the functional constraints to the constructed linear operators
            B  = csr_array(B)
            M  = sps.vstack((B, PM))
        else:
            M = PM

        # Create the projection operator
        self.proj = RectangularProjection(P)
        self.projection = RectangularProjection(PS)

        # create the block matrix for S
        return M, None, self.projection

    def linop(self, *args, **kwargs):
        """ Creates the discretized approximation of the linear or nonlinear
        operator. Currently this function uses rectangularization to
        impose functional constraints on solutions.
        """
        # Create matrix representation of the operator
        M, Pc, S0 = self.instantiate(self.source.quasiOp, *args, **kwargs)
        PM, P, PS = self.reduce(M, S0)

        # Create matrix representation of the operator adjoint
        N, Qc, T0 = self.instantiate(self.source.quasiOp, adjoint=True, format='csr', *args, **kwargs)
        QN, Q, QT = self.reduce(N, T0, adjoint=True)

        # Get the constraints
        B = self.getConstraints(PM.shape[1])

        # Check that B-rows are not zero
        if np.all(np.sum(np.abs(B), axis=1) == 0.0):
            warnings.warn('OpDiscretization: Boundary condition rows have zero l1 norm!\nMost likely the resulting matrix will be singular! Double check your boundary conditions!')

        # Append the functional constraints to the constructed linear operators
        BB = csc_array(self.toFunction(B))
        B  = csr_array(B)
        M  = sps.vstack((B, PM))

        # Add the correct options to the adjoint
        # N = sps.hstack((BB, QN))  # BB here!
        N = sps.vstack((B, QN))

        # Create the projection operator
        self.proj = RectangularProjection(P, Q)
        self.projection = RectangularProjection(PS, QT)

        # create the block matrix for S
        return M, N, self.projection

    def instantiate(self, source, *args, **kwargs):
        return NotImplemented

    def reduce(self, A, S):
        return NotImplemented

    def toFunctionOut(self, coeffs):
        return NotImplemented

    def toFunctionIn(self, coeffs):
        return NotImplemented

    def toValues(self, coeffs):
        return NotImplemented


import tkinter as tk
from tkinter.messagebox import showinfo
import re

class Statistika:
	def getName(self):
		return 'Statistika'
	def getDescription(self):
		'Tells you how many lines, words and letters there are in a file'
	def execute(self, model, undoManager, clipboardStack):
		words = 0
		letters = 0
		text = model.lines
		ln = len(text)

		for line in text:
			letters = letters + len(line) # pretpostavljam da su razmaci letters
			words = words + len(re.findall(r'\w+', line))

		toShow = 'Lines: ' + str(ln) + '\nWords: ' + str(words) + '\nLetters: ' + str(letters)
		showinfo('Statistika', toShow)


st = input('Input start of the range\n')
end = int(input('Input end of the range\n'))
step = input('Input step\n')
if step:
	step = int(step)
else:
	step = 0
if st:
	st = int(st)
else:
	st = 0
def range_(st, end, step):
	i = st
	while st <= i <= end:
		if step > 0:
			print (i)
			i += step
		elif step < 0:
			i = end
			print (i)
			end += step
			i = end
		else:
			print (i)
			i += 1
range_(st, end, step)


from ll1_parser import *
from lalr1_parser import *

class Generator():
    def __init__(self):
        self.SourceFile = open("..\\code\\parse-table.c", "w")
        self.HeaderFile = open("..\\header\\parse-table.h", "w")
        self.CommonHeaderFile = open("..\\..\\script-eval\\header\\ScriptEngineCommonDefinitions.h", "w")
        self.ll1 = LL1Parser(self.SourceFile, self.HeaderFile, self.CommonHeaderFile)
        self.lalr = LALR1Parser(self.SourceFile, self.HeaderFile)

    def Run(self):

        self.WriteCommonHeader()
        self.ll1.Run()
        self.HeaderFile.write("\n\n")
        self.lalr.ReadGrammar()

        self.gr = get_grammar(self.lalr)
        self.lalr_table = lalr_one.ParsingTable(self.gr)
        self.lalr.ParseTable = self.lalr_table
        self.ll1.SetLalr(self.lalr, self.lalr_table)

        self.lalr.Run()

        self.CommonHeaderFile.write("#endif\n")

        # Closes Output Files
        self.SourceFile.close()
        self.HeaderFile.close()
        self.CommonHeaderFile.close()

    def WriteCommonHeader(self):
        self.CommonHeaderFile.write(
         """#pragma once
#ifndef SCRIPT_ENGINE_COMMON_DEFINITIONS_H
#define SCRIPT_ENGINE_COMMON_DEFINITIONS_H
typedef struct SYMBOL {
	long long unsigned Type;
	long long unsigned Value;
} SYMBOL, * PSYMBOL;
typedef struct SYMBOL_BUFFER {
	PSYMBOL Head;
	unsigned int Pointer;
	unsigned int Size;
	char* Message;
} SYMBOL_BUFFER, * PSYMBOL_BUFFER;
typedef struct SYMBOL_MAP
{
    char* Name;
    long long unsigned Type;
} SYMBOL_MAP, * PSYMBOL_MAP;
typedef struct ACTION_BUFFER {
  long long unsigned Tag;
  long long unsigned CurrentAction;
  char ImmediatelySendTheResults;
  long long unsigned Context;
  char CallingStage;
} ACTION_BUFFER, *PACTION_BUFFER;

#define SYMBOL_GLOBAL_ID_TYPE 0
#define SYMBOL_LOCAL_ID_TYPE 1
#define SYMBOL_NUM_TYPE 2
#define SYMBOL_REGISTER_TYPE 3
#define SYMBOL_PSEUDO_REG_TYPE 4
#define SYMBOL_SEMANTIC_RULE_TYPE 5
#define SYMBOL_TEMP_TYPE 6
#define SYMBOL_STRING_TYPE 7
#define SYMBOL_VARIABLE_COUNT_TYPE 8
#define SYMBOL_MEM_VALID_CHECK_MASK (1 << 31)
#define SYMBOL_INVALID 9
#define INVALID -999
#define LALR_ACCEPT 999

\n\n""")

    def Parse(self, Tokens):
        Stack = self.ll1.Parse(Tokens)
        print(Stack)

if __name__ == "__main__":

    gen = Generator()
    gen.Run()

    Tokens = ['print', '(', '+', '_hex',  ')', ';', '$']
    gen.Parse(Tokens)


__all__ = (
    'RegistryDict',
    'REGISTRY',
)

import os
from os.path import abspath, expanduser

import json
from logging import getLogger

from spotifyd_controller import actions

LOGGER = getLogger(__name__)

class RegistryDict(dict):
    '''
    Class which can be used to retreive and write RFID tags to the registry.
    '''

    registry_path = abspath(expanduser("~/.config/spotifyd_controller/tags.json"))

    def __init__(self):
        '''
        Constructor.
        Automatically reads the registry if it exists.
        '''
        super().__init__()

        if os.path.exists(self.registry_path):
            self.read()
        else:
            LOGGER.warning('Registry not existing yet on "%s"', self.registry_path)

    @classmethod
    def unserialize_item(cls, item):
        '''
        Unserialize an item from the persistent storage on filesystem to a
        native action.
        :param tuple item: The item
        :return: The action
        :rtype: actions.Action
        '''
        if 'tag_class' in item:
            item['action_class'] = item.pop('tag_class')

        return item['uid'], cls.init_action(**item)

    @classmethod
    def init_action(cls, action_class, uid, alias=None, parameter=None):
        '''
        Initialise a new action instance.
        :param str action_class: The action class
        :param str uid: The RFID UID
        :param str alias: The alias
        :param str parameter: The parameter
        :return: The action instance
        :rtype: actions.Action
        '''
        uid          = str(uid).strip()
        action_class = getattr(actions, action_class)

        return action_class(uid, alias, parameter)

    def read(self):
        '''
        Read registry from disk.
        :raises IOError: When registry file on disk is missing
        '''
        LOGGER.debug('Reading registry from %s', self.registry_path)

        with open(self.registry_path) as f:
            data = json.load(f)
            self.clear()
            self.update((self.unserialize_item(item) for item in data))

    def write(self):
        '''
        Write registry to disk.
        '''
        LOGGER.debug('Writing registry to %s', self.registry_path)

        config    = self.registry_path
        directory = os.path.dirname(config)

        if not os.path.exists(directory):
            os.makedirs(directory)

        with open(config, 'w') as f:
            json.dump([action.as_dict() for action in self.values()], f, indent=4)

    def register(self, action_class, uid, alias=None, parameter=None):
        '''
        Register a new tag in the registry.
        :param str action_class: The action class
        :param str uid: The UID
        :param str alias: The alias
        :param str parameter: The parameter (optional)
        :return: The action
        :rtype: actions.Action
        '''
        LOGGER.info('Registering %s tag %s with parameter "%s"', action_class, uid, parameter)

        action = self.init_action(
            action_class=action_class,
            uid=uid,
            alias=alias,
            parameter=parameter
        )

        action.validate()

        self[uid] = action
        self.write()

        return action

    def unregister(self, uid):
        '''
        Unregister a tag from the registry.
        :param str uid: The UID
        '''
        LOGGER.info('Unregistering tag %s', uid)

        del self[uid]
        self.write()

REGISTRY = RegistryDict()


from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
import time
import xlrd
import datetime
import os

workbook = xlrd.open_workbook('Milestone_TECO_Done.xlsx')
worksheet = workbook.sheet_by_name('Sheet1')

file = open("credentials.txt", "r")
cred=file.read().splitlines()

passw = cred[1]
user = cred[0]

count=0
fail=0
list=[]

current_dir = os.path.dirname(os.path.abspath(__file__))
driver_location = current_dir + '\\chromedriver.exe'
print(driver_location)

# for i in range(1,worksheet.nrows):

    # try:
driver = webdriver.Chrome(driver_location)
driver.get("http://rocapp.robi.com.bd/ROC/ROCPages/Pages/ROBIROC_Login.aspx")
driver.maximize_window()
driver.implicitly_wait(15)

elem = driver.find_element_by_id('txtUsername')
elem.send_keys(user)
elem = driver.find_element_by_id('txtPassword')
elem.send_keys(passw)

elem = driver.find_element_by_xpath('//*[@id="btnLogin"]').click()

time.sleep(3)

try:

    elem = driver.switch_to.alert.accept()

except:

    driver.refresh()

elem = driver.find_element_by_xpath("""//*[@id="nav"]/li[4]/a""").click()
elem = driver.find_element_by_xpath("""//*[@id="nav"]/li[4]/ul/li[1]""").click()

########################### LOOP ##################

for i in range(1,worksheet.nrows):

    # try:
    wr = worksheet.cell(i, 0).value

    print('Attempting Entry:', wr)

    elem = driver.find_element_by_xpath("""//*[@id="ctl00_ContentPlaceHolder1_txtWRNO"]""")
    elem.clear()
    elem.send_keys(wr)

    # elem = driver.find_element_by_xpath("""//*[@id="ctl00_ContentPlaceHolder1_pnlSearch"]/table/tbody/tr[5]/td[6]""").click()

    elem = driver.find_element_by_xpath('//*[@value="  Search  "]').click()

    name = '//*[text()="' + wr + '"]'
    # print(name)

    elem = driver.find_element_by_xpath(name).click()

    # elem =driver.find_element_by_xpath("""//*[@id="ctl00_ContentPlaceHolder1_gdvWFList"]/tbody/tr[2]/td[1]""").click()

    # text_found = re.search(r'TECO', src)
    # print(text_found)

    tt = driver.find_element_by_link_text("TECO")
    tt.click()

    ed = worksheet.cell(i, 1).value

    if ed == 'N/A':
        elem = Select(driver.find_element_by_xpath("""//*[@id="ctl00_ContentPlaceHolder1_drpMILESTONE_STATUS"]"""))
        elem.select_by_value("Not Applicable")

        elem = driver.find_element_by_xpath("""//*[@id="ctl00_ContentPlaceHolder1_txtAddMilestoneComments"]""")
        elem.send_keys("N/A")

    else:

        driver.switch_to.frame("frmMilestoneAction")
        elem = driver.find_element_by_id('ctl00_ContentPlaceHolder1_txtTecoDoneDate')
        elem.clear()

        dt = datetime.datetime(*xlrd.xldate_as_tuple(ed, workbook.datemode))

        a = dt.strftime("%d")
        b = dt.strftime("%b")
        c = dt.strftime("%y")

        str = [a, b, c]

        string = '-'.join(str)

        elem.send_keys(string)
        elem.send_keys(Keys.RETURN)

        ############################## SAVE BUTTON for date #######################
        elem = driver.find_element_by_xpath("""//*[@id="ctl00_ContentPlaceHolder1_btnSave"]""").is_enabled()

        if elem:
            elem = driver.find_element_by_xpath("""//*[@id="ctl00_ContentPlaceHolder1_btnSave"]""").click()

            time.sleep(4)
            elem = driver.switch_to.alert
            print(elem.text)
            list.append(wr)
            list.append('[Considered as passed]')
            list.append(elem.text)
            elem.accept()
        # elem = driver.switch_to.alert
        # elem.dismiss()
        # print(elem.text)

        ###########################################################################

        driver.switch_to.parent_frame()
        elem = Select(driver.find_element_by_xpath("""//*[@id="ctl00_ContentPlaceHolder1_drpMILESTONE_STATUS"]"""))
        elem.select_by_value("Done")

        #################### SAVE and SUBMIT Button##########################
    # elem = driver.find_element_by_xpath('//*[@id="ctl00_ContentPlaceHolder1_btnSaveMilestone"]').click()

    elem = driver.find_element_by_xpath('//*[@id="ctl00_ContentPlaceHolder1_btnSaveMilestone"]').is_enabled()
    # print(elem)
    if elem:
        elem = driver.find_element_by_xpath('//*[@id="ctl00_ContentPlaceHolder1_btnSaveMilestone"]').click()
        time.sleep(6)
        print('Successful Entry.')
        count += 1
        try:
            driver.switch_to.alert.accept()
        except:
            pass

    else:
        print('failed')
        list.append(wr)
        fail += 1

        driver.refresh()
        driver.get("http://rocapp.robi.com.bd/ROC/Pages/WorkFlow/WFMaster.aspx")
        driver.refresh()

    # except:
    #     print('failed')
    #     list.append(wr)
    #     fail += 1
    #
    #     # driver.refresh()
    #     driver.get("http://rocapp.robi.com.bd/ROC/Pages/WorkFlow/WFMaster.aspx")
    #     driver.refresh()

        # driver.get("http://rocapp.robi.com.bd/ROC/Pages/WorkFlow/WFMaster.aspx")
    # except:
    #     print('failed')
    #     list.append(wr)
    #
    #     driver.close()
    #     fail+=1
driver.close()

print('Entries done ', count)
print('Failed ', fail)
print(list)
print('creating log')
with open("log.txt", "w") as text_file:
    text_file.write("\nEntries: %s" % count)
    text_file.write("\nFail: %s" % fail)
    for item in list:
        text_file.write("\n%s\n" % item)
print('log done')


#!/usr/bin/env python
import constants as c
from buttons import Buttons
from media_group import media_group
import expited_chats_checker
from database_connection import DatabaseConnection

import json
import datetime
import random
from asyncio import sleep
import os

from aiogram import Bot, Dispatcher, executor, types, utils
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.contrib.fsm_storage.memory import MemoryStorage

WEBHOOK = True
WEBHOOK_HOST = c.app  # heroku app url
WEBHOOK_PATH = '/webhook/'
WEBHOOK_URL = f"{WEBHOOK_HOST}{WEBHOOK_PATH}"

WEBAPP_HOST = '0.0.0.0'
WEBAPP_PORT = os.environ.get('PORT')

bot = Bot(c.token)
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)

class Activate(StatesGroup): code = State()
class Export(StatesGroup): code = State()
class Delete(StatesGroup): code = State()
class Settings(StatesGroup): option = State()

class Chat(StatesGroup):
    code = State()
    send = State()

class NewOrder(StatesGroup):
    contact = State()
    subject = State()
    level = State()
    q_type = State()  # short / multiple choice
    m_choice = State()
    s_answers = State()
    timed = State()
    duration = State()
    timezone_city = State()
    additions = State()
    accepting = State()

@dp.message_handler(commands=['start'], state=Chat)
async def message_handler(message: types.Message, state: FSMContext):
    await state.finish()
    await start_menu(message)

@dp.message_handler(commands=['start'], state=Export)
async def message_handler(message: types.Message, state: FSMContext):
    await state.finish()
    await start_menu(message)

@dp.message_handler(commands=['start'])
async def message_handler(message: types.Message):
    if message.chat.id == c.moderator_chat:
        await message.answer("Moderator mode", reply_markup=moderator_keyboard())
    else:
        await start_menu(message)

def client_keyboard() -> types.ReplyKeyboardMarkup:
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.my_chats_client, Buttons.new_order)
    key.add(Buttons.support)
    return key

def moderator_keyboard() -> types.ReplyKeyboardMarkup:
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.m_activate, Buttons.m_delete)
    key.add(Buttons.m_export, Buttons.m_show)
    return key

async def start_menu(message: types.Message):
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.introduction_client)
    key.add(Buttons.introduction_tutor)
    await message.answer("Just a heads up, if the buttons disappear you might want to press the button on the right "
                         "side of your keyboard. Make sure that nothing is typed in.", reply_markup=key)
    await bot.send_animation(message.chat.id, c.instruction_gif)

async def _send_message(func, **kwargs):
    try:
        await func(**kwargs)
    except utils.exceptions.BotBlocked: return
    except utils.exceptions.UserDeactivated: return
    except utils.exceptions.ChatNotFound: return
    except utils.exceptions.BadRequest: return 0
    return True

async def _back_client(message, state):
    if message.text == Buttons.back:
        await state.finish()
        await client_main(message)
        return True
    return

def create_new_code():
    color = random.choice(c.random_colors)
    word = random.choice(c.random_words)
    suffix = random.randint(0, 99)
    return f'{color}{word}{suffix}'

def save_data(chat: int, name: str, text: str = None, data_type: str = None, data: str = None):
    insertTextQuery = "INSERT INTO text_messages (chat, user, text) VALUES (%s, %s, %s)"
    insertMediaQuery = "INSERT INTO media_messages (chat, type, file_id) VALUES (%s, %s, %s)"
    if text:
        with DatabaseConnection() as db:
            conn, cursor = db
            cursor.executemany(insertTextQuery, [(chat, name, text)])
            conn.commit()
    if data:
        with DatabaseConnection() as db:
            conn, cursor = db
            cursor.executemany(insertMediaQuery, [(chat, data_type, data)])
            conn.commit()

def _media_group_builder(data, caption=True):
    media = types.MediaGroup()
    first = True
    for photo in data['media']['photo']:
        if first:
            first = False
            if caption:
                media.attach_photo(photo, data['media']['caption'])
            else:
                media.attach_photo(photo)
        else:
            media.attach_photo(photo)
    for video in data['media']['video']:
        if first:
            first = False
            if caption:
                media.attach_photo(video, data['media']['caption'])
            else:
                media.attach_photo(video)
        else:
            media.attach_video(video)
    return media

def get_price(data) -> float:
    with open('prices.json', 'r') as f:
        prices = json.load(f)

    price: float = 0
    level: str = data['level']
    m_choice: int = data.get('m_choice', 0)
    s_answers: int = data.get('s_answers', 0)
    duration_inc: int = prices['duration_inc'] if data.get('duration') is not None else 0
    questions = m_choice + s_answers
    if questions > 300:
        discount = 0.75
    elif questions > 250:
        discount = 0.71
    elif questions > 200:
        discount = 0.7
    elif questions > 150:
        discount = 0.6
    elif questions > 100:
        discount = 0.5
    elif questions > 50:
        discount = 0.4
    elif questions > 40:
        discount = 0.35
    elif questions > 30:
        discount = 0.25
    elif questions > 20:
        discount = 0.2
    elif questions > 10:
        discount = 0.1
    else:
        discount = 0

    if level == Buttons.level[0]:
        level_multiplier = prices['level_multiplier_1']
    elif level == Buttons.level[1]:
        level_multiplier = prices['level_multiplier_2']
    elif level == Buttons.level[2]:
        level_multiplier = prices['level_multiplier_3']
    else:
        level_multiplier = prices['level_multiplier_4']

    price += m_choice * prices['m_choice']
    price += s_answers * prices['s_answers']
    price *= level_multiplier
    price -= price * discount
    price += duration_inc

    return price.__round__(2)

async def tutor_main(message):
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.my_chats_tutor)
    key.add(Buttons.support)
    await message.answer("Choose action", reply_markup=key)

async def client_main(message):
    await message.answer("First of all, relax, because we have your back 🤓!\n\n"
                         "If you already created an order, click on “MyChats”.\n\n"
                         "If you want to create a new order, click on “New Order”.\n\n"
                         "Didn't receive an order ID? No worries! Contact our support team and we’ll sort things out.",
                         reply_markup=client_keyboard())

async def my_chats(message, who_am_i, state):
    selectQuery = "SELECT ID, code FROM chats WHERE {}=(%s)"
    with DatabaseConnection() as db:
        conn, cursor = db
        cursor.execute(selectQuery.format(who_am_i), [message.chat.id])
        chats = cursor.fetchall()
    if not chats:
        await message.answer("You haven't any chats")
        return

    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.back)
    inline_key = types.InlineKeyboardMarkup()
    for code in chats:
        inline_key.add(types.InlineKeyboardButton(code[1], callback_data=code[0]))

    await Chat.code.set()
    await state.update_data({'who_am_i': who_am_i})
    await message.answer("There are all your chats", reply_markup=inline_key)
    await message.answer("Choose the chat", reply_markup=key)

async def chat_answer(callback_query, state):
    who_am_i = 'tutor' if callback_query.data[6:7] == 'c' else 'client'
    chat_id = callback_query.data[7:]
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.back)
    await Chat.send.set()
    await state.update_data({'chat_id': chat_id, 'who_am_i': who_am_i})
    await callback_query.answer()
    await callback_query.message.answer("Now all messages will be send to this interlocutor", reply_markup=key)

async def new_order_start(message):
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(types.KeyboardButton("Share contact", request_contact=True))
    await NewOrder.contact.set()
    await message.answer("Please share your contact details with us. This allows our support team to be more efficient "
                         "in helping you. Don't worry your information is only visible to our support specialists.",
                         reply_markup=key)

async def generate_new_chat(callback_query):
    await callback_query.message.edit_reply_markup()
    text = callback_query.data[3:].split('_')
    client = int(text[0])
    price = float(text[1])
    code = create_new_code()

    insetQuery = "INSERT INTO chats (code, client, tutor) VALUES (%s, %s, %s)"
    with DatabaseConnection() as db:
        conn, cursor = db
        cursor.executemany(insetQuery, [(code, client, callback_query.from_user.id)])
        conn.commit()

    with open('prices.json', 'r') as f:
        prices = json.load(f)
    price_tutor = (price * prices['tutor_share']).__round__(2)

    key = types.InlineKeyboardMarkup()
    key.add(types.InlineKeyboardButton("Pay", url=c.paypal))
    await _send_message(bot.send_message, chat_id=client,
                        text=f"Hey! One of our tutors accepted your order. Your chat ID is: `{code}`\n"
                             f"Please deposit $*{price}* to the following PayPal account. "
                             "Don't forget to add a note with your order id to your payment.\n"
                             "Don't worry you are protected by our money back guarantee as well as PayPals buyer "
                             "protection policy. Your tutor will not get the money until your order is complete.\n\n"
                             "Your chat ID is active but will be deactivated in 30 min if the payment is not made."
                             "Thanks!\n\nTo access your chat click on 'my chats' and then your order ID.",
                        reply_markup=key, parse_mode='Markdown')
    await _send_message(bot.send_message, chat_id=callback_query.from_user.id,
                        text=f"Hey! Your chat ID is: `{code}`\nThe client has 30 min to make a deposit. "
                             f"You will be notified.", parse_mode='Markdown')
    await callback_query.answer("See your private messages with the bot", show_alert=True)

    await bot.send_message(c.moderator_chat, f"*New order!*\n*Chat ID:* `{code}`\n"
                                             f"*Price:* ${price}\n*Tutor share:* ${price_tutor}\n"
                                             f"[Client](tg://user?id={client}) "
                                             f"[Tutor](tg://user?id={callback_query.from_user.id})",
                           parse_mode='Markdown')

async def activate_chat_init(message: types.Message):
    if message.chat.id not in (c.moderator_chat, c.admin_id):
        return
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.back)
    await Activate.code.set()
    await message.answer("Send me the chat ID to activate", reply_markup=key)

async def export_chat_init(message: types.Message):
    if message.chat.id not in (c.moderator_chat, c.admin_id):
        return
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.back)
    await Export.code.set()
    await message.answer("Send me the chat ID to export", reply_markup=key)

async def delete_chat_init(message: types.Message):
    if message.chat.id not in (c.moderator_chat, c.admin_id):
        return
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.back)
    await Delete.code.set()
    await message.answer("Send me the chat ID to delete", reply_markup=key)

async def show_all_chats_init(message: types.Message):
    if message.chat.id not in (c.moderator_chat, c.admin_id):
        return

    selectQuery = "SELECT code, created FROM chats"
    with DatabaseConnection() as db:
        conn, cursor = db
        cursor.execute(selectQuery)
        chats = cursor.fetchall()

    buffer = ''
    for chat in chats:
        buffer += chat[0] + datetime.datetime.strftime(chat[1], "\t- %d.%m / %H:%M\n")
    with open('chats.txt', 'w') as f:
        f.write(buffer)
    await bot.send_document(message.chat.id, types.InputFile('chats.txt'), 'chats.txt')

@dp.message_handler(commands=['settings'])
async def message_handler(message: types.Message):
    if message.chat.id != c.admin_id:
        return
    with open('prices.json', 'r') as f:
        prices = json.load(f)
    buffer = ''
    for option in prices:
        buffer += f'`{option}` - {prices[option]}\n'
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.back)
    await Settings.option.set()
    await message.answer(buffer + "Send me the option which you want to change with the new value separated by space",
                         parse_mode='Markdown', reply_markup=key)

async def support_send(message):
    await _send_message(bot.send_message, chat_id=c.moderator_chat,
                        text=f"❗ Request for help ❗\n[User](tg://user?id={message.chat.id})", parse_mode='Markdown')
    await message.answer("Thanks for reaching out!\nOne of our support team members will get in touch with you as soon as possible.")

@dp.message_handler(content_types=['text'])
async def message_handler(message: types.Message, state: FSMContext):
    if message.text == Buttons.back:
        await start_menu(message)
    elif message.text == Buttons.introduction_tutor:
        await tutor_main(message)
    elif message.text == Buttons.introduction_client:
        await client_main(message)
    elif message.text == Buttons.my_chats_client:
        await my_chats(message, 'client', state)
    elif message.text == Buttons.my_chats_tutor:
        await my_chats(message, 'tutor', state)
    elif message.text == Buttons.new_order:
        await new_order_start(message)
    elif message.text == Buttons.support:
        await support_send(message)

    elif message.text == Buttons.m_activate:
        if message.chat.id == c.moderator_chat:
            await activate_chat_init(message)
    elif message.text == Buttons.m_delete:
        if message.chat.id == c.moderator_chat:
            await delete_chat_init(message)
    elif message.text == Buttons.m_export:
        if message.chat.id == c.moderator_chat:
            await export_chat_init(message)
    elif message.text == Buttons.m_show:
        if message.chat.id == c.moderator_chat:
            await show_all_chats_init(message)

@dp.message_handler(content_types=['text'], state=Activate.code)
async def message_handler(message: types.Message, state: FSMContext):
    await state.finish()
    if message.text == Buttons.back:
        await message.answer("Canceled", reply_markup=moderator_keyboard())
        return
    code: str = message.text.lower()

    active = None
    selectQuery = "SELECT active, client, tutor FROM chats WHERE code=(%s)"
    updateQuery = "UPDATE chats SET active=1 WHERE code=(%s)"
    with DatabaseConnection() as db:
        conn, cursor = db
        cursor.execute(selectQuery, [code])
        chat = cursor.fetchone()
        if chat:
            if chat[0] == 1:
                active = True
            else:
                active = False
                cursor.execute(updateQuery, [code])
                conn.commit()

    if active is None:
        await message.answer("Chat ID does not exist!", reply_markup=moderator_keyboard())
        return
    elif active:
        await message.answer("Chat ID is already activated!", reply_markup=moderator_keyboard())
        return

    client, tutor = chat[1], chat[2]
    await _send_message(bot.send_message, chat_id=client, text="We have received the payment, the chat is now fully active!")
    await _send_message(bot.send_message, chat_id=tutor, text="We have received the payment, the chat is now fully active!")
    await message.answer("Activated", reply_markup=moderator_keyboard())

@dp.message_handler(content_types=['text'], state=Export.code)
async def message_handler(message: types.Message, state: FSMContext):
    await state.finish()
    if message.text == Buttons.back:
        await message.answer("Canceled", reply_markup=moderator_keyboard())
        return
    code: str = message.text.lower()

    selectChatQuery = "SELECT ID FROM chats WHERE code=(%s)"
    selectMediaQuery = "SELECT type, file_id FROM media_messages WHERE chat=(%s)"
    selectTextQuery = "SELECT user, time, text FROM text_messages WHERE chat=(%s)"
    text, media = None, None
    with DatabaseConnection() as db:
        conn, cursor = db
        cursor.execute(selectChatQuery, [code])
        chat_id = cursor.fetchone()
        if chat_id:
            cursor.execute(selectMediaQuery, [chat_id[0]])
            media = cursor.fetchall()
            cursor.execute(selectTextQuery, [chat_id[0]])
            text = cursor.fetchall()

    if not chat_id:
        await message.answer("Chat does not exist!", reply_markup=moderator_keyboard())
        return
    if not text:
        await message.answer("There are no text messages")
    else:
        buffer = ''
        for t in text:
            user, time, text = t[0], t[1], t[2]
            buffer += f'{datetime.datetime.strftime(time, "%d.%m / %H:%M")} - {user}:\n{text}\n\n'
        with open(code, 'wt', encoding='utf-8') as f:
            f.write(buffer)
        del buffer
        await bot.send_document(message.chat.id, types.InputFile(code, f'{code} text messages.txt'))
        try: os.remove(code)
        except Exception as e: print(e)

    if not media:
        await message.answer("There are no media messages")
    else:
        for m in media:
            filetype, fileid = m[0], m[1]
            try:
                if filetype == c.PHOTO:
                    await bot.send_photo(message.chat.id, fileid)
                elif filetype == c.VIDEO:
                    await bot.send_video(message.chat.id, fileid)
                elif filetype == c.DOCUMENT:
                    await bot.send_document(message.chat.id, fileid)
            except Exception as e:
                await message.answer(str(e))
            await sleep(.05)
    await message.answer("Sending finished", reply_markup=moderator_keyboard())

@dp.message_handler(content_types=['text'], state=Delete.code)
async def message_handler(message: types.Message, state: FSMContext):
    await state.finish()
    if message.text == Buttons.back:
        await message.answer("Canceled", reply_markup=moderator_keyboard())
        return
    code: str = message.text.lower()
    deleteQuery = "DELETE FROM chats WHERE code=(%s)"
    with DatabaseConnection() as db:
        conn, cursor = db
        cursor.execute(deleteQuery, [code])
        conn.commit()
    await message.answer("Chat deleted", reply_markup=moderator_keyboard())

@dp.message_handler(content_types=['text'], state=Settings.option)
async def message_handler(message: types.Message, state: FSMContext):
    if message.text == Buttons.back:
        await state.finish()
        await message.answer("Canceled", reply_markup=client_keyboard())
        return
    text = message.text.split(' ')
    if len(text) != 2:
        await message.answer("Invalid input, please try again", reply_markup=client_keyboard())
        return
    option = text[0]
    value = text[1]
    try:
        value = float(value)
    except ValueError:
        await message.answer("Value is not digit, please try again", reply_markup=client_keyboard())
        return
    await state.finish()
    with open('prices.json', 'r') as f:
        prices = json.load(f)
    prices[option] = value
    with open('prices.json', 'w', encoding='utf-8') as f:
        json.dump(prices, f, indent=2)
    await message.answer("Successfully changed", reply_markup=client_keyboard())

@dp.message_handler(content_types=['text'], state=Chat.code)
async def message_handler(message: types.Message, state: FSMContext):
    if message.text == Buttons.back:
        data = await state.get_data()
        await state.finish()
        if data['who_am_i'] == 'client':
            await client_main(message)
        else:
            await tutor_main(message)

@dp.callback_query_handler(lambda callback_query: True, state=Chat.code)
async def callback_inline(callback_query: types.CallbackQuery, state: FSMContext):
    chat_id = callback_query.data
    existsQuery = "SELECT EXISTS (SELECT ID FROM chats WHERE ID=(%s))"
    with DatabaseConnection() as db:
        conn, cursor = db
        cursor.execute(existsQuery, [chat_id])
        exists = cursor.fetchone()[0]

    if not exists:
        await state.finish()
        await callback_query.answer("ID does not exist!", show_alert=True)
        await client_main(callback_query.message)
        return
    await state.update_data({'chat_id': chat_id})
    await Chat.send.set()
    await callback_query.answer()
    await callback_query.message.answer("Now all messages will be send to this interlocutor")

# SECTION: MESSAGE SEND
@dp.message_handler(content_types=['text', 'photo', 'video', 'document'], state=Chat.send)
async def message_handler(message: types.Message, state: FSMContext):
    data = await state.get_data()
    who_am_i = data.get('who_am_i')
    if message.text == Buttons.back or message.text == '/start' or not who_am_i:
        await state.finish()
        if who_am_i == 'client':
            await client_main(message)
        else:
            await tutor_main(message)
        return
    chat_id = data.get('chat_id')

    selectQuery = "SELECT client, tutor, code FROM chats WHERE ID=(%s)"
    with DatabaseConnection() as db:
        conn, cursor = db
        cursor.execute(selectQuery, [chat_id])
        chat = cursor.fetchone()

    if not chat:
        await message.answer("Chat does not exist or has expired!")
        await state.finish()
        if who_am_i == 'client':
            await client_main(message)
        else:
            await tutor_main(message)
        return
    if who_am_i == 'client':
        ilr = 1
    else:
        ilr = 0
    interlocutor = chat[ilr]
    code = chat[2]
    text = ''
    send = None
    key = None
    name = f'@{message.chat.username}' if message.chat.username else str(message.chat.id)
    state_interlocutor = await state.storage.get_data(chat=interlocutor)
    interlocutor_in_chat = state_interlocutor.get('chat_id')

    if interlocutor_in_chat != chat_id:
        key = types.InlineKeyboardMarkup()
        key.add(types.InlineKeyboardButton("Answer", callback_data=f"answer{data['who_am_i'][0]}{chat_id}"))
    if message.media_group_id:
        data = await media_group(message, state)
        if data is None: return
        await state.update_data({'media_group': True})
        await state.update_data({'media': {'photo': data['media_group']['photo'],
                                           'video': data['media_group']['video'],
                                           'caption': data['media_group']['caption']}})
        data = await state.get_data()
        photo = data['media']['photo']
        video = data['media']['video']
        text = data['media']['caption']

        media = _media_group_builder(data, caption=True)
        send = await _send_message(bot.send_media_group, chat_id=interlocutor, media=media)

        for p in photo:
            save_data(chat_id, name, text, c.PHOTO, p)
        for v in video:
            save_data(chat_id, name, text, c.VIDEO, v)
    elif message.text:
        text = message.text
        send = await _send_message(bot.send_message, chat_id=interlocutor, text=f'{code}:\n{text}', reply_markup=key)
        save_data(chat_id, name, text)
    elif message.photo:
        photo = message.photo[-1].file_id
        if message.caption:
            text = message.caption
        send = await _send_message(bot.send_photo, chat_id=interlocutor, photo=photo, caption=f'{code}:\n{text}', reply_markup=key)
        save_data(chat_id, name, text, c.PHOTO, photo)
    elif message.video:
        video = message.video.file_id
        if message.caption:
            text = message.caption
        send = await _send_message(bot.send_video, chat_id=interlocutor, video=video, caption=f'{code}:\n{text}', reply_markup=key)
        save_data(chat_id, name, text, c.VIDEO, video)
    elif message.document:
        file = message.document.file_id
        send = await _send_message(bot.send_document, chat_id=interlocutor, document=file, caption=f'{code}:\n{text}', reply_markup=key)
        save_data(chat_id, name, text, c.DOCUMENT, file)
    if send:
        await message.answer(f"Message sent to the chat `{code}`", parse_mode='Markdown')
    elif send == 0:
        await message.answer("An error occurred. The message text may be too long.")
    else:
        await message.answer("The message wasn't delivered, the user may have blocked the bot")

# New order zone
@dp.message_handler(content_types=['contact'], state=NewOrder.contact)
async def message_handler(message: types.Message, state: FSMContext):
    country_code = str(message.contact.phone_number)[:-9]
    if country_code[0] == '+': country_code = country_code[1:]
    if country_code in c.forbidden_country_codes:
        await state.finish()
        await message.answer("Sorry, your country is not supported")
        await client_main(message)
        return
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.subjects[0], Buttons.subjects[1], Buttons.subjects[2], Buttons.subjects[3], Buttons.subjects[4])
    key.add(Buttons.back)
    await NewOrder.subject.set()
    await message.answer("Please select the subject you need help with:\n"
                         "Math, Stats, Finance, Business, Chem\n\nThanks!", reply_markup=key)

@dp.message_handler(content_types=['text'], state=NewOrder.subject)
async def message_handler(message: types.Message, state: FSMContext):
    if await _back_client(message, state):
        return
    if message.text not in Buttons.subjects:
        return
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.level[0], Buttons.level[1], Buttons.level[2])
    key.add(Buttons.back)
    await state.update_data({'subject': message.text})
    await NewOrder.level.set()
    await message.answer("Next, we need to know difficulty level of your assignment. "
                         "If you consider your course to be more or less difficult than "
                         "what our level suggestions are select feel free to select level "
                         "you think best fits your course. However, its crucial that you select "
                         "appropriate difficulty level:\n\nLevel 1: High School\nLevel 2: Undergraduate "
                         "(University Year 1-2) AND IB AP courses.\nLevel 3 Undergraduate (Year 3-4)",
                         reply_markup=key)

@dp.message_handler(content_types=['text'], state=NewOrder.level)
async def message_handler(message: types.Message, state: FSMContext):
    if await _back_client(message, state):
        return
    if message.text not in Buttons.level:
        return
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.q_type[0])
    key.add(Buttons.q_type[1])
    key.add(Buttons.q_type[2])
    key.add(Buttons.back)
    await state.update_data({'level': message.text})
    await NewOrder.q_type.set()
    await message.answer("Next, please tell us what type of questions your assignment has? Please note that we can "
                         "only help with short answers and multiple choice questions.", reply_markup=key)

@dp.message_handler(content_types=['text'], state=NewOrder.q_type)
async def message_handler(message: types.Message, state: FSMContext):
    if await _back_client(message, state):
        return
    if message.text not in Buttons.q_type:
        return
    await state.update_data({'q_type': message.text})
    if message.text == Buttons.q_type[0]:
        await NewOrder.s_answers.set()
        answer = "Ok, how many short answer question does your assignment have? (select 0 if none)"
    else:
        await NewOrder.m_choice.set()
        answer = "How many multiple choice questions does your assignment have? (select 0 if none)"
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.back)
    await message.answer(answer, reply_markup=key)

@dp.message_handler(content_types=['text'], state=NewOrder.m_choice)
async def message_handler(message: types.Message, state: FSMContext):
    if await _back_client(message, state):
        return
    if not str(message.text).isdigit():
        return
    data = await state.get_data()
    await state.update_data({'m_choice': int(message.text)})
    if data.get('q_type') == Buttons.q_type[2]:
        await NewOrder.s_answers.set()
        await message.answer("Ok, how many short answer question does your assignment have? (select 0 if none)")
    else:
        if int(message.text) == 0:
            await state.finish()
            await message.answer("So, your assignment doesn't have any questions?")
            return
        else:
            key = types.ReplyKeyboardMarkup(resize_keyboard=True)
            key.add(Buttons.timed[0], Buttons.timed[1])
            key.add(Buttons.back)
            await NewOrder.timed.set()
            await message.answer("Ok, we are almost done!\n\nIs your assignment timed?", reply_markup=key)

@dp.message_handler(content_types=['text'], state=NewOrder.s_answers)
async def message_handler(message: types.Message, state: FSMContext):
    if await _back_client(message, state):
        return
    if not str(message.text).isdigit():
        return
    data = await state.get_data()
    if data.get('q_type') == Buttons.q_type[2]:
        if int(message.text) == 0 and data.get('m_choice') == 0:
            await state.finish()
            await message.answer("So, your assignment doesn't have any questions?")
            return
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.timed[0], Buttons.timed[1])
    key.add(Buttons.back)
    await state.update_data({'s_answers': int(message.text)})
    await NewOrder.timed.set()
    await message.answer("Ok, we are almost done!\n\nIs your assignment timed?", reply_markup=key)

@dp.message_handler(content_types=['text'], state=NewOrder.timed)
async def message_handler(message: types.Message, state: FSMContext):
    if await _back_client(message, state):
        return
    if message.text not in Buttons.timed:
        return
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.back)
    if message.text == Buttons.timed[0]:
        await NewOrder.duration.set()
        await message.answer("How long will you have to complete it?", reply_markup=key)
    else:
        await NewOrder.timezone_city.set()
        await message.answer("When is your assignment due?\nPlease indicate your time zone OR "
                             "city in your answer. For example NYC DD/MM/YY and 8:30 PM", reply_markup=key)

@dp.message_handler(content_types=['text'], state=NewOrder.duration)
async def message_handler(message: types.Message, state: FSMContext):
    if await _back_client(message, state):
        return
    if len(message.text) > 50:
        await message.answer("Too long message, please try again")
        return
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.back)
    await state.update_data({'duration': message.text})
    await NewOrder.timezone_city.set()
    await message.answer("When is your assignment due?\nPlease indicate your time zone OR "
                         "city in your answer. For example NYC DD/MM/YY and 8:30 PM", reply_markup=key)

@dp.message_handler(content_types=['text'], state=NewOrder.timezone_city)
async def message_handler(message: types.Message, state: FSMContext):
    if await _back_client(message, state):
        return
    if len(message.text) > 50:
        await message.answer("Too long message, please try again")
        return
    key = types.ReplyKeyboardMarkup(resize_keyboard=True)
    key.add(Buttons.done)
    key.add(Buttons.back)
    await state.update_data({'timezone_city': message.text})
    await NewOrder.additions.set()
    await message.answer("Finally, is there anything else our tutor should know about your assignment? "
                         "If you have past exams, course outline, sample questions upload them here. "
                         "The more you attach the easier it will be for us to find a tutor that can help you. "
                         "When you are done press DONE.", reply_markup=key)

@dp.message_handler(content_types=['text', 'photo', 'document'], state=NewOrder.additions)
async def message_handler(message: types.Message, state: FSMContext):
    if await _back_client(message, state):
        return
    data = await state.get_data()
    if message.text == Buttons.done:
        price = get_price(data)
        key = types.ReplyKeyboardMarkup(resize_keyboard=True)
        key.add(Buttons.accept)
        key.add(Buttons.support)
        key.add(Buttons.back)
        await state.update_data({'price': price})
        await NewOrder.accepting.set()
        await message.answer(f"Our price for your order is ${price}. If you like it just click accept! "
                             "You won't have to pay until one of our tutors accepts your order.", reply_markup=key)
        return
    elif message.text:
        if len(message.text) > 500:
            await message.answer("Too long message, please try again")
            return
        if len(str(data.get('add_text'))) + len(message.text) > 500:
            await message.answer("The text that has already been sent is too long")
            return
        await state.update_data({'add_text': message.text})
    elif message.photo:
        if message.caption:
            if len(str(data.get('add_text'))) + len(message.caption) > 500:
                await message.answer("The text that has already been sent is too long")
            else:
                await state.update_data({'add_text': message.caption})
        await state.update_data({'add_photo': message.photo[-1].file_id})
    elif message.document:
        await state.update_data({'add_document': message.document.file_id})

@dp.message_handler(content_types=['text'], state=NewOrder.accepting)
async def message_handler(message: types.Message, state: FSMContext):
    if await _back_client(message, state):
        return
    await message.answer("Thanks! We are now looking for a tutor that will match your needs. "
                         "This shouldn't take longer than an hour. While you wait why don't you watch this "
                         "[video](https://youtu.be/ZZb_ZtjVxUQ) of cute puppies🐕!",
                         parse_mode='Markdown', reply_markup=client_keyboard())
    data = await state.get_data()
    await state.finish()

    text = data.get('add_text')
    photo = data.get('add_photo')
    document = data.get('add_document')
    media_links = ''

    if text:
        text_m = await bot.send_message(c.media_chat, text)
        media_links += f'[text](https://t.me/{c.media_chat[1:]}/{text_m.message_id}) '
    if photo:
        photo_m = await bot.send_photo(c.media_chat, photo)
        media_links += f'[photo](https://t.me/{c.media_chat[1:]}/{photo_m.message_id}) '
    if document:
        document_m = await bot.send_document(c.media_chat, document)
        media_links += f'[document](https://t.me/{c.media_chat[1:]}/{document_m.message_id}) '

    with open('prices.json', 'r') as f:
        prices = json.load(f)

    price_tutor = (data['price'] * prices['tutor_share']).__round__(2)
    due_date = data['timezone_city'].replace('_', '\\_').replace('*', '\\*').replace('`', '\\`').replace('[', '\\[')
    timed = data.get('duration', 'NO').replace('_', '\\_').replace('*', '\\*').replace('`', '\\`').replace('[', '\\[')
    text_to_channel = f"*{data['subject']}*\n" \
                      f"*{data['level']}*\n" \
                      f"*DUE DATE:* {due_date}\n" \
                      f"*TIMED:* {timed}\n" \
                      f"*SHORT ANSWER:* {data.get('s_answers', '0')}\n" \
                      f"*MULTIPLE CHOICE:* {data.get('m_choice', '0')}\n" \
                      f"*ADDITIONAL INFO WITH FILES:* {media_links}\n" \
                      f"*PRICE:* {price_tutor}"

    key = types.InlineKeyboardMarkup()
    key.add(types.InlineKeyboardButton("Take", callback_data=f"new{message.chat.id}_{data['price']}"))

    await bot.send_message(c.tutors_chat, text_to_channel, parse_mode='Markdown', reply_markup=key, disable_web_page_preview=True)

@dp.callback_query_handler(lambda callback_query: True)
async def callback_inline(callback_query: types.CallbackQuery, state: FSMContext):
    if callback_query.data[:6] == 'answer':
        await chat_answer(callback_query, state)
    elif callback_query.data[:3] == 'new':
        await generate_new_chat(callback_query)

@dp.callback_query_handler(lambda callback_query: True, state=Chat)
async def callback_inline(callback_query: types.CallbackQuery, state: FSMContext):
    if callback_query.data[:3] == 'new':
        await state.finish()
        await generate_new_chat(callback_query)

async def on_startup(dpc):
    await bot.set_webhook(WEBHOOK_URL)

async def on_shutdown(dpc):
    pass

if __name__ == '__main__':
    dp.loop.create_task(expited_chats_checker.check())
    if WEBHOOK:
        executor.start_webhook(dispatcher=dp, webhook_path=WEBHOOK_PATH,
                               on_startup=on_startup, on_shutdown=on_shutdown, host=WEBAPP_HOST, port=WEBAPP_PORT)
    else:
        executor.start_polling(dp, skip_updates=True)


from django.db import models
from django.conf import settings

from projects.models import Project

class Issue(models.Model):

    TAG_CHOICES = [
        ("Bug", "Bug"),
        ("Improve", "Improve"),
        ("Task", "Task"),
    ]
    PRIORITY_CHOICES = [
        ("Low", "Low"),
        ("Middle", "Middle"),
        ("High", "High"),
    ]
    STATUS_CHOICES = [
        ("To do", "To do"),
        ("In progress", "In progress"),
        ("Finished", "Finished"),
    ]

    title = models.CharField(max_length=128)
    description = models.CharField(max_length=250)
    tag = models.CharField(max_length=7, choices=TAG_CHOICES, default="Task")
    priority = models.CharField(max_length=6, choices=PRIORITY_CHOICES, default="Low")
    project = models.ForeignKey(
        to=Project, on_delete=models.CASCADE, blank=True, null=True
    )
    status = models.CharField(max_length=11, choices=STATUS_CHOICES, default="To do")
    author = models.ForeignKey(
        to=settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="author",
        blank=True,
        null=True,
    )
    assignee_user = models.ForeignKey(
        to=settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="assignee_user",
        blank=True,
        null=True,
    )
    created_time = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"PROJECT : {self.project.title}, ISSUE : {self.title}, AUTHOR : {self.author}"


# third party imports
import torch
import torch.nn as nn

# local imports
import config
from .models import perceptual_model

class VGGLoss(nn.Module):
	def __init__(self, layids = None):
		super(VGGLoss, self).__init__()
		self.vgg = perceptual_model.Vgg19()
		self.vgg.to(config.DEVICE)
		self.vgg.eval()

		self.criterion = nn.L1Loss()
		self.weights = [1.0/32, 1.0/16, 1.0/8, 1.0/4, 1.0]
		self.layids = layids

	def forward(self, x, y):
		x_vgg, y_vgg = self.vgg(x), self.vgg(y)
		loss = 0
		if self.layids is None:
			self.layids = list(range(len(x_vgg)))
		for i in self.layids:
			loss += self.weights[i] * self.criterion(x_vgg[i], y_vgg[i].detach())
		return loss


from django.urls import path
from rest_framework.routers import DefaultRouter

from .views import PokemonViewSet, TypeViewSet, UserViewSet, CurrentUserView

router = DefaultRouter()
router.register('pokemon', PokemonViewSet, basename='pokemon' ) # register the pokemon
router.register('users', UserViewSet, basename='users')
router.register('type', TypeViewSet, basename='type')

urlpatterns = router.urls + [
    path('currentuser/', CurrentUserView.as_view()),
]


class Node:
    def __init__(self,data):
        self.val = data
        self.right = None
        self.left = None

def delete(root):
    if root==None:
        return
    delete(root.left)
    delete(root.right)
    del root

root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.right.left = Node(5)
delete(root)
root = None


import yfinance as yf
import datetime as dt

default_tickers = ["GOOG", "MMM", "XOM"]

def fetch_weekly_csv(tickers):
	for ticker in tickers:
		symbol = yf.Ticker(ticker)
		data = symbol.history(period="1wk", interval="1d")
		data.to_csv(f"{ticker}_{dt.datetime.now()}.csv")

if __name__ == "__main__":
	fetch_weekly_csv(default_tickers)


import unittest
import numpy as np
import math
import logging
import sys

class BaseTestCase(unittest.TestCase):
    def assert_complex_equal(self, d1: object, d2: object, ndarray_tolerance=None):
        """ Recursive asserts with numpy special cases handled. """
        if isinstance(d1, (list, tuple)) and isinstance(d2, (list, tuple)):
            self.assertEqual(len(d1), len(d2))
            for d1_item, d2_item in zip(d1, d2):
                self.assert_complex_equal(d1_item, d2_item)
        elif isinstance(d1, dict) and isinstance(d2, dict):
            d1_keys = sorted(d1.keys())
            d2_keys = sorted(d2.keys())
            self.assertCountEqual(d1_keys, d2_keys)
            for d1_key, d2_key in zip(d1_keys, d2_keys):
                self.assert_complex_equal(d1[d1_key], d2[d2_key])
        elif isinstance(d1, np.ndarray) and isinstance(d2, np.ndarray):
            if ndarray_tolerance is not None:
                np.testing.assert_allclose(d1, d2, atol=ndarray_tolerance)
            else:
                np.testing.assert_equal(d1, d2)
        elif isinstance(d1, float) and isinstance(d2, float) and math.isnan(d1) and math.isnan(d2):
            pass
        else:
            self.assertEqual(d1, d2)


import folium

mapObj = folium.Map(zoom_start=7, location=[37.566536, 126.977966])
folium.Marker(location=[36.693474, 128.004915],
              icon=folium.DivIcon(html="""

South Korea

                                  """, class_name='mapText')
              ).add_to(mapObj)
mapObj.get_root().html.add_child(folium.Element(
    """

    """
))
mapObj.save('map.html')


"""CVX Utilities"""

import numpy as np
import cvxpy as cvx
from certml.utils.data import get_projection_matrix

def cvx_dot(a, b):
    """ CVX Dot Product

    Parameters
    ----------
    a : ???
    b : ???

    Returns
    -------
    dot : ???
        Dot product of a and b
    """
    return cvx.sum_entries(cvx.mul_elemwise(a, b))

class NearestPointFinder(object):
    """ Nearest Point Finder

    We can speed this up by expressing the constraints in one dimension,
    but let's see how it goes first.

    Solve the optimization problem:

    """

    def __init__(self, d):
        """ Nearest Point Finder

        Parameters
        ----------
        d : ???
            ???
        """

        self.cvx_c = cvx.Variable(1)
        self.cvx_y = cvx.Parameter(1)
        self.cvx_g = cvx.Parameter(d)
        self.cvx_theta = cvx.Parameter(d)
        self.cvx_centroid = cvx.Parameter(d)
        self.cvx_centroid_vec = cvx.Parameter(d)
        self.cvx_sphere_radius = cvx.Parameter(1)
        self.cvx_slab_radius = cvx.Parameter(1)

        # want grad of poisoned point = -g
        # grad of point (cyg, y) = -cg
        # so we want to find c > 0 such that n_poison/n * -cg = -g with 0 < n_poison as low as possible
        # and (cyg, y) in the feasible set.
        # since n_poison/n > 0, c must > 0. Then n_poison/n = 1/c,
        # so we want c to be as large as possible.
        # As a sanity check, we know that g itself is in conv(feasible set of gradients).
        # We can hope that either (-g, 1) or (g, -1) is in the feasible set of inputs,
        # because the gradients at each of those points is g
        # so if we let c = -1 then this should work.

        self.cvx_x = self.cvx_c * self.cvx_y * self.cvx_g
        self.cvx_x_c = self.cvx_x - self.cvx_centroid
        self.constraints = [
            cvx.norm(self.cvx_x_c, 2) < self.cvx_sphere_radius,
            cvx.abs(cvx_dot(self.cvx_centroid_vec, self.cvx_x_c)) < self.cvx_slab_radius,
            self.cvx_y * cvx_dot(self.cvx_theta, self.cvx_x) < 1,
            self.cvx_c > 0]

        self.objective = cvx.Maximize(self.cvx_c)

        self.prob = cvx.Problem(self.objective, self.constraints)

    def find_nearest_point(self, y, g, theta,
                           centroid, centroid_vec, sphere_radius, slab_radius,
                           verbose=False):
        """ Find Nearest Point

        Parameters
        ----------
        y : int
        g : ??
        theta :
        centroid : np.ndarray of shape (classes, dimensions)
        centroid_vec : np.ndarray of shape (dimensions,)
        sphere_radius : np.ndarray of shape (classes,)
        slab_radius : np.ndarray of shape (classes,)
        verbose : bool
            CVX verbose

        Returns
        -------
        c_opt :
            Optimal C value
        """
        self.cvx_y.value = y
        self.cvx_g.value = g.reshape(-1)
        self.cvx_theta.value = theta.reshape(-1)
        self.cvx_centroid.value = centroid.reshape(-1)
        self.cvx_centroid_vec.value = centroid_vec.reshape(-1)
        self.cvx_sphere_radius.value = sphere_radius
        self.cvx_slab_radius.value = slab_radius

        self.prob.solve(verbose=verbose)

        c_opt = self.cvx_c.value
        return c_opt

class Projector(object):
    """ Projector ???

    Solves the optimization problem:
    TODO
    """

    def __init__(self, use_sphere=True, use_slab=True):
        """ Projector ???

        Parameters
        ----------
        use_sphere
        use_slab
        """

        d = 3

        self.cvx_x = cvx.Variable(d)
        self.cvx_z = cvx.Parameter(d)
        self.cvx_centroid = cvx.Parameter(d)
        self.cvx_centroid_vec = cvx.Parameter(d)
        self.cvx_sphere_radius = cvx.Parameter(1)
        self.cvx_slab_radius = cvx.Parameter(1)

        self.cvx_x_c = self.cvx_x - self.cvx_centroid

        self.constraints = []
        if use_sphere:
            self.constraints.append(cvx.norm(self.cvx_x_c, 2) < self.cvx_sphere_radius)
        if use_slab:
            self.constraints.append(cvx.abs(cvx_dot(self.cvx_centroid_vec, self.cvx_x_c)) < self.cvx_slab_radius)

        self.objective = cvx.Minimize(cvx.norm(self.cvx_x - self.cvx_z, 2))

        self.prob = cvx.Problem(self.objective, self.constraints)

    def project_onto_feasible_set(self, z, centroid, centroid_vec, sphere_radius, slab_radius,
                                  verbose=False):
        """ Project onto Feasible Set

        Parameters
        ----------
        z : ??
        centroid : np.ndarray of shape (classes, dimension)
        centroid_vec : np.ndarray of shape (dimensions,)
        sphere_radius : np.ndarray of shape (classes,)
        slab_radius : np.ndarray of shape (classes,)
        verbose : bool

        Returns
        -------
        x_proj :
            Data projected onto feasible set
        """

        P = get_projection_matrix(z, centroid, centroid_vec)

        self.cvx_z.value = P.dot(z.reshape(-1))
        self.cvx_centroid.value = P.dot(centroid.reshape(-1))
        self.cvx_centroid_vec.value = P.dot(centroid_vec.reshape(-1))
        self.cvx_sphere_radius.value = sphere_radius
        self.cvx_slab_radius.value = slab_radius

        self.prob.solve(verbose=verbose)

        x_opt = np.array(self.cvx_x.value).reshape(-1)

        return x_opt.dot(P)


import sys
import requests
from bs4 import BeautifulSoup

from .tenis_nike import TenisNike

urls = [
    "https://www.nike.com.br/tenis-nike-dunk-high-retro-masculino-026963.html?cor=51",
    "https://www.nike.com.br/tenis-nike-renew-ride-3-012944.html?cor=IM",
]

options = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
}

class NikeWebScrapper:
    def start():
        for url in urls:
            response = requests.get(url, headers=options)

            if response.status_code == 200:
                soup = BeautifulSoup(response.content, "html.parser")
                print("============================================================")
                print("\n")

                TenisNike(soup, url).print()

                print("\n")
                print("============================================================")
                print("\n")

def main():
    try:
        NikeWebScrapper.start()
    except Exception as e:
        print(e)
        sys.exit(1)
    except KeyboardInterrupt:
        print("Interrompido pelo usuário")
        sys.exit(0)


import time
from turtle import Screen
import car_manager
from player import Player
from car_manager import CarManager
from scoreboard import Scoreboard
level = 1
score_i = 2

screen = Screen()
screen.setup(width=600, height=600)
screen.tracer(0)
screen.listen()
scoreboard = Scoreboard()
scoreboard.score(level)

player = Player()
cars = CarManager()

screen.onkey(fun=player.run_turtle, key="w")

# main loop
game_is_on = True
while game_is_on:
    if level == score_i:
        scoreboard.score(level)
        score_i += 1

    for c in car_manager.cars_moving:
        if player.distance(c) < 23:
            scoreboard.game_over_print(level)
            game_is_on = False

    cars.start_game(level=level)
    level = player.win_level(level)
    time.sleep(0.1)
    screen.update()

screen.exitonclick()


#Divide el arreglo
def sumaGrupos(nums : list, meta1 : int, meta2 : int):
    if len(nums) == 0:
        return True
    cont = 0
    list1 = []
    list2 = []
    while cont < len(nums):
        if meta1 == meta2:
            return True
        else:
            return False

def sumaGruposAux(nums) -> int:
    result = 0
    cont = 0
    while cont < len(nums):
        result = result + nums[cont]
        cont += 2
    return result

def sumaGruposAux2(nums) -> int:
    result = 0
    cont = 1
    while cont < len(nums):
        result = result + nums[cont]
        cont += 2
    return result

n = int(input())
nums = [0]*n
for i in range(n):
    nums[i] = int(input())
nums.sort()
print(sumaGrupos(nums, sumaGruposAux(nums), sumaGruposAux2(nums)))


"""
On a broken calculator that has a number showing on its display, we can perform two operations:

Double: Multiply the number on the display by 2, or;
Decrement: Subtract 1 from the number on the display.
Initially, the calculator is displaying the number X.

Return the minimum number of operations needed to display the number Y.

Example 1:

Input: X = 2, Y = 3
Output: 2
Explanation: Use double operation and then decrement operation {2 -> 4 -> 3}.
Example 2:

Input: X = 5, Y = 8
Output: 2
Explanation: Use decrement and then double {5 -> 4 -> 8}.
Example 3:

Input: X = 3, Y = 10
Output: 3
Explanation:  Use double, decrement and double {3 -> 6 -> 5 -> 10}.
Example 4:

Input: X = 1024, Y = 1
Output: 1023
Explanation: Use decrement operations 1023 times.

Note:

1 <= X <= 10^9
1 <= Y <= 10^9

Solution : Instead of X to Y, try to do Y to X. to do this try to reduce til you are no longer greater than X. Do division by 2 or add by 1
            as appropriate. Then finally answer is ans + (Y-X)

            Time complexity : O(log(Y/X))
            Space complexity : O(1)
"""

class Solution:
    def brokenCalc(self, X: int, Y: int) -> int:
        ans = 0
        while Y > X:
            if Y%2 == 0:
                Y = Y//2
                ans+=1
            else:
                Y = Y+1
                ans+=1
        if Y == X:
            return ans
        else:
            return ans+(X-Y)


from numpy import *
import numpy.random
from sklearn.datasets import fetch_mldata
import sklearn.preprocessing
import os
import numpy as np
# import matplotlib
# matplotlib.use('Agg')
import matplotlib.pyplot as plt
from HW4.PCA import PCA

NOF_EIGENVALUES = 100
NOF_EIGENVECTORS = 5
ITERS = 300

def get_train_validation_test_data():
    """
    This function get MNIST data and split it to train, validation and test data and labels
    :return: train_data, train_labels, validation_data, validation_labels, test_data, test_labels
    """
    mnist = fetch_mldata('MNIST original', data_home=os.getcwd())
    data = mnist['data']
    labels = mnist['target']

    neg, pos = 0, 8
    train_idx = numpy.random.RandomState(0).permutation(where((labels[:60000] == neg) | (labels[:60000] == pos))[0])
    test_idx = numpy.random.RandomState(0).permutation(where((labels[60000:] == neg) | (labels[60000:] == pos))[0])

    train_data_size = 2000
    train_data_unscaled = data[train_idx[:train_data_size], :].astype(float)
    train_labels = (labels[train_idx[:train_data_size]] == pos) * 2 - 1

    # validation_data_unscaled = data[train_idx[6000:], :].astype(float)
    # validation_labels = (labels[train_idx[6000:]] == pos)*2-1

    # test_data_size = 2000
    # test_data_unscaled = data[60000 + test_idx[:test_data_size], :].astype(float)
    # test_labels = (labels[60000 + test_idx[:test_data_size]] == pos) * 2 - 1

    # Preprocessing
    train_data = sklearn.preprocessing.scale(train_data_unscaled, axis=0, with_std=False)
    # validation_data = sklearn.preprocessing.scale(validation_data_unscaled, axis=0, with_std=False)
    # test_data = sklearn.preprocessing.scale(test_data_unscaled, axis=0, with_std=False)
    return train_data, train_labels

def plot_graph(error_lst, x_lst, file_name='', label='', title='', ylabel='', xlabel=''):
    """
    This function is plotting the graph
    :param label: for plotting legend
    :param title: title for the plotting
    :param ylabel: ylabel for the plotting
    :param xlabel: xlabel for the plotting
    :param error_lst: the of errors
    :param x_lst: list of the number of samples
    :param file_name: file_name to be saved
    """
    plt.plot(x_lst, error_lst, label=label)
    plt.title(title)
    plt.ylabel(ylabel)
    plt.xlabel(xlabel)
    plt.savefig('{}.png'.format(file_name))
    plt.close()

def part_a_and_b_and_c(org_train, org_train_labels, label=1, section='a', both=0):
    """
    This function implements part a and b.
    This function will plot Iteration Vs Accuracy training and testing error
    """

    # Both check if the label is 0 and 8 we do not need for scaled the data for one of the labels
    if not both:
        # label 1 is 8 number and -1 is 0 number. The num fields is for saving the figures
        if label > 0:
            num = 8
        else:
            num = 0

        train_data_unscaled = get_label_dataset(org_train, org_train_labels, label)
        train_data_mean = np.mean(train_data_unscaled, axis=0)
        train_dataset = sklearn.preprocessing.scale(train_data_unscaled, axis=0, with_std=False)
    else:
        # the train data should not change (its already for both labels
        num = "0&8"
        train_dataset = org_train
        train_data_mean = np.mean(train_dataset, axis=0)

    # Save the mean image
    plt.figure()
    plt.imshow(np.reshape(train_data_mean, (28, 28)), interpolation='nearest')
    plt.savefig('q6_part_{}_mean_image'.format(section))
    plt.close()

    # Do PCA
    pca = PCA(train_dataset)
    u, d, v = pca.run(dim=100)

    # Save the eigen-vectors
    for i in range(NOF_EIGENVECTORS):
        plt.figure()
        plt.imshow(np.reshape(v[i], (28, 28)), interpolation='nearest')
        plt.savefig('q6_part_{}_i{}_label_{}'.format(section, i, num))
        plt.close()

    # Save the eigenvalues
    plt.figure()
    plot_graph(d, range(1, NOF_EIGENVALUES + 1), "q6_part_{}_label_{}".format(section, num), "",
               "Iteration vs EigenValues",
               "EigenValues", "Iteration")

def part_d(train_dataset, org_train_labels):
    """
    This function implements part d.
    This function will plot Iteration Vs Accuracy training and testing error
    """

    # Do PCA
    pca = PCA(train_dataset)
    u, d, v = pca.run(dim=2)
    mat_data = np.dot(train_dataset, np.transpose(v))
    plt.figure()
    plt.scatter(mat_data[:, 0], mat_data[:, 1], c=org_train_labels)
    plt.savefig("q6_part_d.png")

def part_e(train_dataset, org_train_labels):
    """
    This function implements part e.
    This function will plot Iteration Vs Accuracy training and testing error
    """

    pos_train_data = get_label_dataset(org_train, org_train_labels, 1)
    neg_train_data = get_label_dataset(org_train, org_train_labels, -1)
    images_lst = [pos_train_data[0], pos_train_data[1], neg_train_data[0], neg_train_data[1]]

    for k in [10, 30, 50]:
        # Do PCA
        pca = PCA(train_dataset)
        u, d, v = pca.run(dim=k)
        # Index for saving different names of images
        idx = 0
        for image in images_lst:
            # image is x
            x = image
            plt.figure()
            plt.imshow(np.reshape(x, (28, 28)), interpolation='nearest')
            plt.savefig("q6_part_e_original_{}_k_{}.png".format(idx, k))
            plt.close()
            # Encoding the image
            img_encode = np.dot(v, x)
            # Decoding the image
            img_decode = np.dot(u, img_encode)
            plt.figure()
            plt.imshow(np.reshape(img_decode, (28, 28)), interpolation='nearest')
            plt.savefig("q6_part_e_decode_{}_k_{}.png".format(idx, k))
            plt.close()
            idx += 1

def get_label_dataset(org_train, org_train_labels, label):
    """
    This function create only the necessary label data from the original data
    :param org_train: training original dataset
    :param org_train_labels: training labels dataset
    :return:
    """

    label_idx = np.where(org_train_labels == label)
    training_dataset_label = org_train[label_idx]
    return training_dataset_label

if __name__ == '__main__':
    # Get train, validation and test data
    org_train, org_train_labels = get_train_validation_test_data()

    # Part A - only number 8
    part_a_and_b_and_c(org_train, org_train_labels, label=1, section='a')
    # Part B - only number 0
    part_a_and_b_and_c(org_train, org_train_labels, label=-1, section='b')
    # Part C - both numbers 0 and 1
    part_a_and_b_and_c(org_train, org_train_labels, label=-1, section='c', both=1)

    # Part D
    part_d(org_train, org_train_labels)

    # Part E
    part_e(org_train, org_train_labels)


from bson.objectid import ObjectId
from pymongo import ReturnDocument
from src.services.db import db

accounts = db.accounts

def findByEmail(email: str):
    return accounts.find_one({
        "email": email
    },
        {'_id': False}
    )

def findById(id: str):
    return accounts.find_one({
        "_id": ObjectId(id)
    })

def create(document):
    result = accounts.insert_one(document)
    return str(result.inserted_id)

def update(email, document):
    result = accounts.find_one_and_update({
        "email": email
    }, {
        "$set": document
    }, return_document=ReturnDocument.AFTER,)
    return result