import logging
from enum import Enum
from typing import Tuple

import numpy as np
from numpy.typing import ArrayLike

from .utils import complex_pchip

MAX_TAYLOR_ITERATIONS = 1000

class InterpolationMode(Enum):
    PCHIP = "pchip"
    LINEAR = "linear"

def _lambda(x: ArrayLike) -> np.ndarray:
    """Calculates the Lambda function defined in equations E.136 in [N.Mounet-PhD]_, which is given by:

    Lambda(x) = -j*exp(j*x)/x + (exp(j*x)-1)/x^2,

    where j = sqrt(-1) is the imaginary unit.

    For \|x\| < 1, a Taylor series approximation is summed until convergence is reached.

    :param x: The input variable x, given as a single float or an array of floats.
    :type x: ArrayLike
    :raises RuntimeError: If the Taylor series summation did not converge after 1000 iterations.
    :return: Lambda, an array with the same shape as x
    :rtype: np.ndarray
    """
    # Make input into array if it is not already, and prepare output arrays
    x = np.asarray(x)
    result = np.zeros_like(1j*x)

    # Set relative tolerance to machine precision
    rel_tolerance = np.finfo(x.dtype).eps

    # Define a mask of where to use a Taylor series approximation
    taylor_mask = np.abs(x) < 1.0

    # Calculate phi and psi for x >= 1
    xx = x[~taylor_mask]
    exp_jx = np.exp(1j*xx)
    result[~taylor_mask] = -1j*exp_jx/xx + (exp_jx-1)/xx**2

    # Set up for convergence loop for x < 1
    xx = x[taylor_mask]
    inv_factorial = 1.
    jx_to_n = np.ones_like(1j*xx) # Starts as x**0
    abs_x_to_n_plus_1 = np.abs(xx) # Starts as x**(0+1)
    exp_abs_x = np.exp(np.abs(xx))

    # Run convergence loop until phi and psi converged
    for n in range(MAX_TAYLOR_ITERATIONS+1):

        # Add next term
        result[taylor_mask] += 1/(n+2) * jx_to_n * inv_factorial

        # Check convergence
        min_component = np.min([np.abs(np.real(result[taylor_mask])), np.abs(np.imag(result[taylor_mask]))], axis=0)
        remaining_term_bound = abs_x_to_n_plus_1*exp_abs_x * inv_factorial * 1/((n+3)*(n+1))
        if np.all(remaining_term_bound < rel_tolerance * min_component):
            break

        # Update variables
        jx_to_n *= 1j*xx
        abs_x_to_n_plus_1 *= np.abs(xx)
        inv_factorial /= n + 1

    # If loop finished without converging, raise error
    if n == MAX_TAYLOR_ITERATIONS:
        raise RuntimeError(f"Lambda calculation failed to converge after {MAX_TAYLOR_ITERATIONS} iterations")

    return result

def _phi_and_psi(x: ArrayLike) -> Tuple[np.ndarray, np.ndarray]:
    """Calculates the Phi and Psi functions defined in equations E.142 and E.143 in [N.Mounet-PhD]_, which are given by:

    Phi(x) = -j*exp(j*x)/x - 6j*(exp(j*x)+1)/x^3 + 12(exp(j*x)-1)/x^4,

    Psi(x) = exp(j*x)/x^2 + 2j*(2*exp(j*x)+1)/x^3 - 6(exp(j*x)-1)/x^4,

    Where j = sqrt(-1) is the imaginary unit.

    For \|x\| < 1, a Taylor series approximation is summed until convergence is reached.

    :param x: The input variable x, given as a single float or an array of floats.
    :type x: ArrayLike
    :raises RuntimeError: If the Taylor series summation did not converge after 1000 iterations.
    :return: Tuple of two arrays: Phi and Psi, with the same shape as x
    :rtype: Tuple[np.ndarray, np.ndarray]
    """

    # Make input into array if it is not already, and prepare output arrays
    x = np.asarray(x)
    phi = np.zeros_like(1j*x)
    psi = np.zeros_like(phi)

    # Set relative tolerance to machine precision
    rel_tolerance = np.finfo(x.dtype).eps

    # Define a mask of where to use a Taylor series approximation
    taylor_mask = np.abs(x) < 1.0

    # Calculate phi and psi for x >= 1
    xx = x[~taylor_mask]
    exp_jx = np.exp(1j*xx)
    phi[~taylor_mask] = (-1j*xx**3 * exp_jx - 6j*xx*(exp_jx+1) + 12*(exp_jx-1))/xx**4
    psi[~taylor_mask] = ( xx**2 * exp_jx + 2j*xx*(2*exp_jx+1) - 6*(exp_jx-1))/xx**4

    # Set up for convergence loop for x < 1
    xx = x[taylor_mask]
    inv_factorial = 1.
    jx_to_n = np.ones_like(1j*xx) # Starts as x**0
    abs_x_to_n_plus_1 = np.abs(xx) # Starts as x**(0+1)
    exp_abs_x = np.exp(np.abs(xx))

    # Run convergence loop until phi and psi converged
    phi_converged = False
    psi_converged = False
    for n in range(MAX_TAYLOR_ITERATIONS+1):

        # Stop loop if converged
        if phi_converged and psi_converged:
            break

        # Only calculate phi if not yet converged (to save computation time)
        if not phi_converged:
            phi[taylor_mask] += (n+6)/((n+3)*(n+4)) * jx_to_n * inv_factorial

            # Check for convergence
            min_phi_component = np.min([np.abs(np.real(phi[taylor_mask])), np.abs(np.imag(phi[taylor_mask]))], axis=0)
            phi_remaining_terms_bound = 2 * abs_x_to_n_plus_1 * exp_abs_x * inv_factorial / ((n+1)*(n+5))
            phi_converged = np.all(phi_remaining_terms_bound < rel_tolerance * min_phi_component)

        # Only calculate psi if not yet converged
        if not psi_converged:
            psi[taylor_mask] += - 1/((n+3)*(n+4)) * jx_to_n * inv_factorial

            # Check for convergence
            min_psi_component = np.min([np.abs(np.real(psi[taylor_mask])), np.abs(np.imag(psi[taylor_mask]))], axis=0)
            psi_remaining_terms_bound = abs_x_to_n_plus_1 * exp_abs_x * inv_factorial / ((n+1)*(n+4)*(n+5))
            psi_converged = np.all(psi_remaining_terms_bound < rel_tolerance*min_psi_component)

        # Update variables
        jx_to_n *= 1j*xx
        abs_x_to_n_plus_1 *= np.abs(xx)
        inv_factorial /= n+1

    # If loop finished without converging, raise error
    if not (phi_converged and psi_converged):
        raise RuntimeError(f"Phi and Psi calculation failed to converge after {MAX_TAYLOR_ITERATIONS} iterations")

    return phi, psi

def _fourier_integral_inf_correction(
    times: ArrayLike,
    omega_end: float,
    func_value_end: ArrayLike,
    func_derivative_end: ArrayLike=0.,
    positive_inf: bool=True
) -> np.ndarray:
    """Calculate the asymptotic correction term as omega -> +-inf of a Fourier integral for the given times.
    Uses a first or second (if func_derivative_end is given) order Taylor expansion around the angular frequency omega_end.

    :param times: Float or 1D array of floats of length M, the time(s) [s]* to compute the fourier integral for
    :type times: ArrayLike
    :param omega_end: An angular frequency [rad/s]* to expand the Taylor series from. If ``positive_inf == True``, this should be the highest angular frequency used. Otherwise, it should be the lowest (closest to -inf).
    :type omega_end: float
    :param func_value_end: An array of shape (X1, X2, ...) containing the values of the function to be transformed evaluated at omega_end
    :type func_value_end: ArrayLike
    :param func_derivative_end: An array of shape (X1, X2, ...) containing the derivative of the function to be transformed, evaluated at omega_end, defaults to 0
    :type func_derivative_end: ArrayLike, optional
    :param positive_inf: Flag set to True if the asymptotic correction towards +inf should be calculated, and False if the correction towards -inf should be calculated
    :type positive_inf: bool, optional
    :return: The asymptotic terms of the Fourier Integral for all times, given as an array of shape (M, X1, X2, ...)
    :rtype: np.ndarray

    \*Though the units s and rad/s are used here, any coherent set of time and angular frequency units will work
    """

    sign = (1 if positive_inf else -1)

    times = np.asarray(times)
    func_value_end = np.asarray(func_value_end)
    func_derivative_end = np.asarray(func_derivative_end)

    # Add axes from function output
    for _ in range(func_value_end.ndim):
        times = times[..., np.newaxis]

    # Add time axis
    func_value_end = func_value_end[np.newaxis, ...]
    func_derivative_end = func_derivative_end[np.newaxis, ...]

    return sign * np.exp(1j*times*omega_end) * (1j*func_value_end/times - func_derivative_end/times**2)

def fourier_integral_fixed_sampling(
    times: ArrayLike,
    frequencies: ArrayLike,
    func_values: ArrayLike,
    pos_inf_correction_term: bool,
    neg_inf_correction_term: bool,
    interpolation: str
) -> np.ndarray:
    """Calculates the fourier integral of a function for the time values given as input:

    integral from fmin to fmax of : exp(2*pi*j*f*t)*func(f)*df,

    where t is the time, fmin is the first frequency in the input ``frequencies``, fmax is either the highest frequency or (positive) infinity, depending on ``inf_correction_term``,
    and func(f) is the input function of frequency. The function is given as an array of outputs corresponding to the array of frequencies given.

    A Filon type algorithm using a either a piecewise cubic Hermite interpolating polynomial ([PCHIP]_) or a piecewise linear polynomial, depending on the interpolation argument.
    Optionally, an asymptotic correction term can also be computed at each end.
    For details on implementation, see [N.Mounet-PhD]_.

    :param times: Float or 1D array of floats of length M, the time(s) [s]* to compute the fourier integral for
    :type times: ArrayLike
    :param frequencies: Float or 1D array of floats of length N, the frequencies [Hz]* the function to be transformed have been evaluated at
    :type frequencies: ArrayLike
    :param func_values: Complex or ND array of complex of shape (N, X1, X2, ...), the outputs of the function to be transformed at the frequencies given as input
    :type func_values: ArrayLike
    :param pos_inf_correction_term: True if an asymptotic correction term towards +infinity should be added, otherwise the integral is effectively truncated at the highest frequency
    :type pos_inf_correction_term: bool
    :param neg_inf_correction_term: True if an asymptotic correction term towards -infinity should be added, otherwise the integral is effectively truncated at the lowest (closest to -inf) frequency
    :type neg_inf_correction_term: bool
    :param interpolation: String either equal to "pchip" or "linear", to select the integration methods using PCHIP or piecewise linear interpolation, respectively.
    :type interpolation: str
    :return: The fourier integral of the input function at the input times, given as an array of shape (M, X1, X2, ...)
    :rtype: np.ndarray

    \*Though the units s and Hz are used here, any coherent set of time and frequency units will work
    """

    assert interpolation in [mode.value for mode in InterpolationMode]
    interpolation_mode = InterpolationMode(interpolation)

    # Turn inputs into arrays if they are not already, switch to angular frequencies
    # Filter out infinities and nan's
    isfinite = np.isfinite(frequencies) & np.all(np.isfinite(func_values), axis=tuple(range(1, len(func_values.shape))))
    if not np.all(isfinite):
        logging.info("Removing infinite frequencies and values from arrays.")

    omegas = 2 * np.pi * np.asarray(frequencies[isfinite])
    func_values = np.asarray(func_values[isfinite])
    times = np.asarray(times)

    # Set up result array, shape (M, X1, X2, ...)
    result = np.zeros((len(times), *[axis_size for axis_size in func_values.shape[1:]]), dtype=complex)

    # Do mode specific setup
    if interpolation_mode == InterpolationMode.PCHIP:
        # Calculate derivatives
        func_derivatives = complex_pchip(omegas, func_values, omegas, derivative_order=1)
        func_derivative_high_end = func_derivatives[-1]
        func_derivative_low_end = func_derivatives[0]

    elif interpolation_mode == InterpolationMode.LINEAR:
        # Set derivative at end to 0
        func_derivative_high_end = 0
        func_derivative_low_end = 0

    else:
        raise NotImplementedError(f"This state should be unreachable. Need to implement derivative calculation for {interpolation_mode}")

    # Add asymptotic correction terms
    if pos_inf_correction_term:
        result += _fourier_integral_inf_correction(
            times=times,
            omega_end=omegas[-1],
            func_value_end=func_values[-1],
            func_derivative_end=func_derivative_high_end,
            positive_inf=True
        )

    if neg_inf_correction_term:
        result += _fourier_integral_inf_correction(
            times=times,
            omega_end=omegas[0],
            func_value_end=func_values[0],
            func_derivative_end=func_derivative_low_end,
            positive_inf=False
        )

    # Reshape arrays for correct broadcasting
    # Now in all arrays except result:
    # - Axis 0  : times
    # - Axis 1  : frequencies
    # - Axis 2+ : func output dims
    # In result, the frequency axis is absent, and axes 1+ correspond to the func output dims

    # Add frequency axis
    times = times[..., np.newaxis]

    # Add time axis
    omegas = omegas[np.newaxis, ...]
    func_values = func_values[np.newaxis, ...]

    # Add new axes for each axis of func_values except the frequency and time axes
    for _ in range(func_values.ndim - 2):
        omegas = omegas[..., np.newaxis]
        times = times[..., np.newaxis]

    # Do the fourier integration
    if interpolation_mode == InterpolationMode.PCHIP:
        func_derivatives = func_derivatives[np.newaxis, ...] # Add time axis
        result += _fourier_integral_fixed_sampling_pchip(times, omegas, func_values, func_derivatives)

    elif interpolation_mode == InterpolationMode.LINEAR:
        result += _fourier_integral_fixed_sampling_linear(times, omegas, func_values)

    else:
        raise NotImplementedError(f"This state should be unreachable. Need to implement fourier integral calculation for {interpolation_mode}")

    return result

def _fourier_integral_fixed_sampling_pchip(
    times: np.ndarray,
    omegas: np.ndarray,
    func_values: np.ndarray,
    func_derivatives: np.ndarray,
) -> np.ndarray:

    # Calculate intermediate values
    delta_omegas = np.diff(omegas, axis=1)
    exp_omegas = np.exp(1j * omegas[:, :-1] * times)
    x = delta_omegas*times
    exp_x = np.exp(1j * x)
    phi_x, psi_x = _phi_and_psi(x)
    phi_minus_x, psi_minus_x = _phi_and_psi(-x)

    # Calculate integral by summing over frequency axis
    result = np.sum(delta_omegas*exp_omegas*(
        func_values[:, :-1] * phi_minus_x * exp_x +
        func_values[:, 1: ] * phi_x -
        delta_omegas*func_derivatives[:, :-1] * psi_minus_x * exp_x +
        delta_omegas*func_derivatives[:, 1: ] * psi_x
    ), axis=1) # Sum over frequency axis

    return result

def _fourier_integral_fixed_sampling_linear(
    times: np.ndarray,
    omegas: np.ndarray,
    func_values: np.ndarray
) -> np.ndarray:

    delta_omegas = np.diff(omegas, axis=1)

    # Calculate integral by summing over frequency axis
    result = np.sum(delta_omegas*(
        func_values[:, :-1]  * np.exp(1j*omegas[:, 1: ]*times) * _lambda(-delta_omegas*times)
        + func_values[:, 1:] * np.exp(1j*omegas[:, :-1]*times) * _lambda( delta_omegas*times)
    ), axis=1) # Sum over frequency axis

    return result


#!/usr/common/env python3
# -*- coding: utf-8 -*-
#
# describe:
# author: cg
# time: 2018-10-24 21:55

import os
import json
import configparser
from util.configMsg import ConfigMsg

class ConfigureUtil:

    '''
    describe: .conf为后缀的文件操作类, 这里用来操作配置文件
    '''

    def __init__(self, logUtilObj, strDir, strFileName):

        '''
        describe: 构造函数
        :param logUtilObj: 日志文件操作对象
        :param strDir:
        :param strFileName:
        '''

        self.logUtilObj = logUtilObj
        self.strDir = strDir
        self.strFileName = strFileName

        self.configMsgObj = ConfigMsg()

        # self.fileUtilObj = FileUtil()
        # self.strRootPath = os.getcwd()
        # self.configParserObj = configparser.ConfigParser(allow_no_value=True, delimiters=':')

    def initConfig(self, configParserObj):

        '''
        describe: 初始化配置文件, 编码格式为utf-8
        :param configParserObj: configparser的对象
        :return: 1: 初始化成功, -1: 初始化出错
        '''

        # self.fileUtilObj.checkAndCreateDir(self.strDir)
        # if not os.path.exists(self.strDir+self.strFileName):
        #     self.logUtilObj.writerLog('将初始化配置文件')

        intIndex = 0

        try:

            configParserObj.add_section(self.configMsgObj.strExportSessionName)

            configParserObj.set(self.configMsgObj.strExportSessionName, self.configMsgObj.strExportDescribe)
            configParserObj.set(self.configMsgObj.strExportSessionName, self.configMsgObj.strHtmlUrlKey,
                                self.configMsgObj.strHtmlUrlValue)
            configParserObj.set(self.configMsgObj.strExportSessionName, self.configMsgObj.strParCateGoryNameKey,
                                self.configMsgObj.strParCateGoryNameValue)

            configParserObj.set(self.configMsgObj.strExportSessionName, self.configMsgObj.strChiCategoryLabelNameKey,
                                self.configMsgObj.strChiCategoryLabelNameValue)

            configParserObj.set(self.configMsgObj.strExportSessionName, self.configMsgObj.strChiCategoryKeyNameKey,
                                self.configMsgObj.strChiCategoryKeyNameValue)

            configParserObj.set(self.configMsgObj.strExportSessionName, self.configMsgObj.strChiCateGoryNameKey,
                                self.configMsgObj.strChiCateGoryNameValue)
            configParserObj.set(self.configMsgObj.strExportSessionName, self.configMsgObj.strSpiderSleepTimeKey,
                                self.configMsgObj.strSpiderSleepTimeValue)
            configParserObj.set(self.configMsgObj.strExportSessionName, self.configMsgObj.strSaveFilePathKey,
                                self.configMsgObj.strSaveFilePathValue)

            with open(self.strDir + self.strFileName, 'w', encoding='utf-8') as configureFile:
                configParserObj.write(configureFile, space_around_delimiters=True)

        except Exception as error:

            intIndex = -1
            self.logUtilObj.writerLog('配置文件初始化出错' + str(error))

        else:

            intIndex = 1
            self.logUtilObj.writerLog('配置文件已初始化完成(' + self.strDir + self.strFileName + ')')

        return intIndex
        # else:
        #     self.logUtilObj.writerLog('配置文件已经存在(' + self.strDir + self.strFileName + ')')

    def checkAndInitConfigure(self, configParserObj):

        '''
        describe: 检测配置文件是否存在, 若存在则执行检测, 若不存在则初始化创建
        :param configParserObj: configparser的对象
        :return: 1: 存在(也可能是创建后), -1:
        '''

        # 检测配置文件是否存在, 若存在则执行检测, 若不存在则初始化创建
        # configParserObj: configparser的对象

        if not os.path.exists(self.strDir + self.strFileName):
            intIndex = self.initConfig(configParserObj)
        else:

            intIndex = self.checkConfigHasExist(configParserObj, self.configMsgObj.strExportSessionName,
                                     self.configMsgObj.listKey)

            if intIndex == 1:

                self.logUtilObj.writerLog('配置文件已经存在(' + self.strDir + self.strFileName + ')')

        return intIndex

    def getConfig(self, configParserObj):

        '''
        describe: 读取配置文件内容, 注释了不读取，值为空会读取, 读取写入的key名字全部小写
        :param configParserObj: configparser的对象
        :return: 返回一个字典, dict类型
        '''

        dictConfMsg = {}
        if os.path.exists(self.strDir + self.strFileName):
            configParserObj.read(self.strDir + self.strFileName, encoding='utf-8')
            try:
                listSectionName = configParserObj.sections()
            except:

                self.logUtilObj.writerLog("读取配置文件出错")
            else:
                for sectionItem in listSectionName:

                    listKeyName = configParserObj.options(sectionItem)
                    sectionObj = configParserObj[sectionItem]

                    if len(listKeyName) != 0:
                        for keyItem in listKeyName:

                            if '#' not in keyItem:

                                valueItem = sectionObj[keyItem]
                                if valueItem is None:
                                    dictConfMsg[sectionItem] = listKeyName
                                else:
                                    dictConfMsg[keyItem] = valueItem
                            else:
                                continue
                    else:
                        dictConfMsg[sectionItem] = ''

        strConfigMsg = json.dumps(dictConfMsg, indent=3, ensure_ascii=False)
        self.logUtilObj.writerLog('配置文件中读取到的配置有: ' + strConfigMsg)
        return dictConfMsg

    def updateConfigSingleKey(self, configParserObj, strSessionName, strKey, strValue):

        '''
        修改改配置文件, 针对单个key
        :param configParserObj: configparser的对象
        :param strSessionName: 需要更改的strKey对应的上一级名字
        :param strKey: 需要更改的key
        :param strValue: 需要更改的strKey的值
        :return:
        '''

        try:
            configParserObj.set(strSessionName, strKey, strValue)
            with open(self.strDir + self.strFileName, 'w', encoding='utf-8') as configureFile:
                configParserObj.write(configureFile, space_around_delimiters=True)
        except:
            self.logUtilObj.writerLog('更新修改出错: [' + strSessionName + ']' + strKey + ' = ' + strValue)
        else:
            self.logUtilObj.writerLog('已更新修改: [' + strSessionName + ']' + strKey + ' = ' + strValue)

    def updateConfigSingleSession(self, configParserObj, strSessionName, dictMsg):

        '''
        describe: 修改配置文件, 针对单个session块
        :param configParserObj: configparser的对象
        :param strSessionName: 块名字
        :param dictMsg: 块对应的新内容, 字典类型
        :return:
        '''

        configParserObj.read(self.strDir + self.strFileName)
        try:
            for strKey, strValue in dictMsg.items():
                configParserObj.set(strSessionName, strKey, strValue)

            with open(self.strDir + self.strFileName, 'w', encoding='utf-8') as configureFile:
                configParserObj.write(configureFile, space_around_delimiters=True)
        except:
            self.logUtilObj.writerLog('更新修改出错')
        else:
            self.logUtilObj.writerLog('已经更新修改: [' + strSessionName + ']配置块')

    def checkConfigHasExist(self, configParserObj, strSession, listKey):

        '''
        describe: 检测判断配置文件中是否存在session块配置信息,及配置信息的key是否完全
        :param configParserObj: configparser的对象
        :param strSession: 块名字
        :param listKey: list类型, 其元素为strSession块中的配置项的key名字
        :return: 1: 检查的配置项存在, -1: session配置块存在, 但缺少某项key, -2: session配置块不存在
        '''

        intIndex = 0

        configParserObj.read(self.strDir + self.strFileName, encoding='utf-8')
        if configParserObj.has_section(strSession):

            for strKeyItem in listKey:
                if not configParserObj.has_option(strSession, strKeyItem):
                    self.logUtilObj.writerLog('配置文件中的' + strSession + '配置中' + strKeyItem + '的配置项不存在')
                    intIndex = -1
                    break
                else:
                    intIndex = 1
                    pass
        else:
            intIndex = -2
            self.logUtilObj.writerLog('配置文件中不存在' + strSession + '的配置块')

        return intIndex

    @staticmethod
    def getCustomizeConfigParserObj():

        '''
        describe: 静态方法, 获取configparser对象, 返回一个实例化的configparser对象, 实例化时参数可改, 参数的配置需要根据自己的需求
        :return:
        '''

        return configparser.ConfigParser(allow_no_value=True, delimiters=':')


"""Task3
Створіть ієрархію класів із використанням множинного успадкування.
Виведіть на екран порядок вирішення методів для кожного класу.
Поясніть, чому лінеаризація даних класів виглядає саме так.
"""

from task3_2_employee import Employee
from task3_3_salary import Salary

class SchoolEmployee(Employee, Salary):
    POSITIONS = ['teacher', 'deputy director', 'director',
                 'psychologist', 'security guard', 'cleaner']

    def __init__(self, name, age, position, monthly_rate, overtime_rate=0, overtime_hours=0):
        Employee.__init__(self, name, age, position)
        Salary.__init__(self, monthly_rate, overtime_rate, overtime_hours)

    @classmethod
    def _verify_position(cls, position):
        if type(position) != str:
            raise TypeError("The position must be a string")
        if position not in cls.POSITIONS:
            raise ValueError(f"Incorrect position, available positions {cls.POSITIONS}")

# test
if __name__ == "__main__":
    teacher = SchoolEmployee('Alice Bishop', 30, 'teacher', 2000)

    print('Print Info method:')
    teacher.print_info()
    print()

    print('Print attributes:')
    print(f'{teacher.name} is {teacher.age}, salary: {teacher.salary}')
    print()

    print("Set overtime and print salary:")
    teacher.overtime_rate = 8
    teacher.overtime_hours = 9
    print(f'{teacher.name} is {teacher.age}, salary with overtime: {teacher.salary}')


from ev3.lego import MediumMotor
import unittest
import time
from util import get_input

class TesMediumMotor(unittest.TestCase):
    def test_medium_motor(self):
        get_input('Attach a MediumMotor then continue')
        d = MediumMotor()
        print(d.type)
        d.run_forever(100, regulation_mode=False)
        print(d.run)
        time.sleep(5)
        d.stop()
if __name__ == '__main__':
    unittest.main()


import tkinter as tk
from tkinter import *
from tkinter import messagebox as mb
from datetime import datetime
from Reuniao import Reuniao
from tkcalendar import *
from tkinter import ttk

class ReuniaoView:

    def __init__(self, win):

        self.ReuniaoCRUD = Reuniao()
        self.ReuniaoCRUD.criar()

        #self.reuniaoSelected = None
        #self.reuniaoResult = None

        #self.apartamentoSelected = None
        #self.apartamentoResult = None

        #self.temaSelected = None
        #self.temaResult = None

        #Tabela Reuniao

        self.temaLabel = tk.Label(win, text="Tema: ")
        self.temaEdit = tk.Entry(win, width=20, bd=3)

        self.localLabel = tk.Label(win, text="Local: ")
        self.localEdit = tk.Entry(win, width=15, bd=3)

        self.dataLabel = tk.Label(win, text="Data: ")
        self.dataEdit = DateEntry(win, width=10, bd=3)

        self.btnCadastrar = tk.Button(win,
                                      text="Cadastrar", width=7, command=self._on_cadastrar_clicked)
        self.btnAlterar = tk.Button(win,
                                    text="Alterar", width=7, command=self._on_alterar_clicked)
        self.btnExcluir = tk.Button(win,
                                    text="Excluir", width=7, command=self._on_excluir_clicked)

        #Localização itens

        self.temaLabel.place(x=40, y=10)
        self.temaEdit.place(x=40, y=30)

        self.localLabel.place(x=180, y=10)
        self.localEdit.place(x=180, y=30)

        self.dataLabel.place(x=300, y=10)
        self.dataEdit.place(x=300, y=30)

        #TreeView Reuniao
        self.reuniaoList = ttk.Treeview(
            win, columns=(1, 2, 3), show='headings')
        self.verscrlbar = ttk.Scrollbar(
            win, orient="vertical", command=self.reuniaoList.yview)
        self.verscrlbar.pack(side='right', fill='x')
        self.reuniaoList.configure(yscrollcommand=self.verscrlbar.set)

        self.reuniaoList.heading(1, text='ID')
        self.reuniaoList.heading(2, text='Tema')
        self.reuniaoList.heading(3, text='Local')

        self.reuniaoList.column(1, minwidth=0, width=80)
        self.reuniaoList.column(2, minwidth=0, width=130)
        self.reuniaoList.column(3, minwidth=0, width=130)
        self.reuniaoList.pack()

        self.reuniaoList.bind("<<TreeviewSelect>>", self._on_mostrar_clicked)

        #Posicionar List e scroll
        self.reuniaoList.place(x=40, y=73, height=185)
        self.verscrlbar.place(x=387, y=98, height=159)

        self.carregar_dados_iniciais()

        #-> self.carregar_dados_iniciais_Ata()

        #Botoes
        self.btnCadastrar.place(x=40, y=260)
        self.btnAlterar.place(x=110, y=260)
        self.btnExcluir.place(x=180, y=260)

    def carregar_dados_iniciais(self):
        resultado = self.ReuniaoCRUD.consultar_reuniao()
        self.reuniaoList.delete(*self.reuniaoList.get_children())

        count = 0
        for registro in resultado:
            self.reuniaoList.insert('', 'end', iid=count, values=(
                str(registro[0]), str(registro[1]), (registro[2]), (registro[3])))
            count = count + 1

    def _on_mostrar_clicked(self, event):
        selection = self.reuniaoList.selection()
        item = self.reuniaoList.item(selection[0])

        data = item["values"][1]
        tema = item["values"][2]
        local = item["values"][3]

        self.localEdit.delete(0, tk.END)
        self.localEdit.insert(0, local)

        self.temaEdit.delete(0, tk.END)
        self.temaEdit.insert(0, tema)

        self.dataEdit.delete(0, tk.END)
        self.dataEdit.insert(0, data)

    def _on_cadastrar_clicked(self):
        tema = self.temaEdit.get()
        local = self.localEdit.get()
        data = self.dataEdit.get()

        teste = self.ReuniaoCRUD.insertReuniao( data, tema, local )

        mb.showinfo("Mensagem", teste)
        # if self.ReuniaoCRUD.insertReuniao(tema, local) == True:

            # mb.showinfo("Mensagem", "Registro executado com sucesso!")

            # self.temaEdit.delete(0, tk.END)
            # self.localEdit.delete(0, tk.END)
        # else:
            # mb.showinfo("Mensagem", "Erro no Registro!")
            # self.temaEdit.focus_set()
            # self.localEdit.focus_set()

        self.carregar_dados_iniciais()

    def _on_alterar_clicked(self):
        linhaSelecionada = self.reuniaoList.selection()
        if (len(linhaSelecionada) != 0):
            reuni_id = self.reuniaoList.item(
                linhaSelecionada[0])["values"][0]
            reuni_data = self.dataEdit.get()
            reuni_tema = self.temaEdit.get()
            reuni_local = self.localEdit.get()

            teste = self.ReuniaoCRUD.updateReuniao(reuni_id, reuni_data, reuni_tema, reuni_local)

            mb.showinfo("Mensagem", type(teste))

        """ else:
                mb.showinfo("Mensagem", "Erro no alteração!")
                self.presencaEdit.focus_set() """

        self.carregar_dados_iniciais()

    def _on_excluir_clicked(self):
        linhaSelecionada = self.reuniaoList.selection()

        if len(linhaSelecionada) != 0:
            id_presenca = self.reuniaoList.item(
                linhaSelecionada[0])["values"][0]

            if self.ReuniaoCRUD.excluirP(id_presenca):
                self.reuniaoList.delete(linhaSelecionada)

                mb.showinfo("Mensagem", "Exclusão executada com sucesso.")
                self.presencaEdit.delete(0, tk.END)
            else:
                mb.showinfo("Mensagem", "Erro na exclusão.")
                self.presencaEdit.focus_set()

    #Janela
janela = tk.Tk()
principal = ReuniaoView(janela)
janela.title("Controle de Reuniões")
janela.geometry("430x290+0+0")
janela.resizable(False, False)
janela.mainloop()


import sys
from typing import Callable

from PyQt6 import QtGui
from PyQt6.QtWidgets import QApplication
from PyQt6.QtWidgets import QGridLayout
from PyQt6.QtWidgets import QLabel
from PyQt6.QtWidgets import QLineEdit
from PyQt6.QtWidgets import QPushButton
from PyQt6.QtWidgets import QWidget
from savings import PresentRequiredEarningsObserver
from savings import SavingsObserver

class QtRequiredEarningsObserver(PresentRequiredEarningsObserver):
    def __init__(self):
        super().__init__()
        self.required_earnings = None

    def did_present_required_earnings(self, required_earnings: float):
        self.required_earnings = required_earnings

class QtSavingsObserver(SavingsObserver):
    def register_savings_functions(self, present_required_earnings: Callable[[int,
                                                                              float,
                                                                              PresentRequiredEarningsObserver],
                                                                             None]):
        qt_application = QApplication(sys.argv)
        screen_center = QtGui.QGuiApplication.primaryScreen().availableGeometry().center()

        main_window = QWidget()

        desired_savings_title_label = QLabel('Desired Savings')
        desired_savings_value_edit = QLineEdit()

        tax_rate_title_label = QLabel('Tax Rate')
        tax_rate_value_edit = QLineEdit()

        required_earnings_title_label = QLabel('Need to earn')
        required_earnings_value_label = QLabel('-')

        calculate_button = QPushButton('Calculate')

        def handle_calculate_event():
            tax_rate = int(tax_rate_value_edit.text())
            desired_savings = float(desired_savings_value_edit.text())
            observer = QtRequiredEarningsObserver()
            present_required_earnings(tax_rate, desired_savings, observer)
            required_earnings = observer.required_earnings
            required_earnings_value_label.setText('{}'.format(required_earnings))

        calculate_button.clicked.connect(handle_calculate_event)
        desired_savings_value_edit.returnPressed.connect(handle_calculate_event)
        tax_rate_value_edit.returnPressed.connect(handle_calculate_event)

        grid = QGridLayout()
        grid.setSpacing(20)

        grid.addWidget(desired_savings_title_label, 1, 0)
        grid.addWidget(desired_savings_value_edit, 1, 1)

        grid.addWidget(tax_rate_title_label, 2, 0)
        grid.addWidget(tax_rate_value_edit, 2, 1)

        grid.addWidget(required_earnings_title_label, 3, 0)
        grid.addWidget(required_earnings_value_label, 3, 1)

        grid.addWidget(calculate_button, 4, 1)

        main_window.setLayout(grid)

        main_window.setGeometry(300, 300, 300, 150)
        main_window.setWindowTitle('Buttons')

        widget_frame_geometry = main_window.frameGeometry()
        widget_frame_geometry.moveCenter(screen_center)
        main_window.show()
        sys.exit(qt_application.exec())


"""
购买促销商品
"""
from common.base import open_app
from page.browser_home_page import BrowserHomePage
from page.firm_order_page import FirmOrderPage
from page.sales_goods_page import SalesGoodsPage
import time,pytest,allure

class TestPromotion:
    def setup(self):
        self.driver = open_app()

    def teardown(self):
        self.driver.quit()

    @pytest.allure.severity(pytest.allure.severity_level.CRITICAL)
    @allure.step(title="使用余额购买商品")
    def test_promotion(self):
        allure.attach("点击购买商品", "促销商品")
        b = BrowserHomePage(self.driver) # 实例化主页页面
        b.click_cx_goods()  # 点击促销
        s = SalesGoodsPage(self.driver)  # 实例化促销商品页面
        time.sleep(3)
        allure.attach("点击商品", "立即购买")
        s.click_goods() # 点击商品
        s.click_bay()   # 点击立即购买
        s.click_true()  # 点击确认购买
        # 跳转到确认订单页面
        time.sleep(3)
        f = FirmOrderPage(self.driver) # 先实例化确认订单页面
        time.sleep(3)
        # 获取当前余额
        proice = float(f.get_proice())
        allure.attach("获取购买前的余额", f"{proice}")
        # # 点击使用积分购买
        # f.click_integer()
        # 点击余额购买
        f.click_balance()
        # 获取商品价格
        goodsproice = float(f.get_goods_proice())
        allure.attach("获取需要购买商品的价格", f"{goodsproice}")
        # 点击立即购买
        f.click_order()
        # 输入密码
        f.send_passwd("123456")
        # 点击确定
        allure.attach("点击确认订单", "确认")
        f.click_qtrue()
        time.sleep(3)
        # 返回 获取余额
        f.click_back()
        time.sleep(3)
        f.click_back()
        time.sleep(3)
        f.click_back()
        f.click_my()
        # 获取新的余额
        newproice = float(f.get_new_proice())
        # 获取购物前余额
        allure.attach("获取购买后的余额", f"{newproice}")
        if proice - goodsproice == newproice:
            assert 1
        else:
            assert 0

if __name__ == '__main__':
    pytest.main("-s test_promotion.py")


# papier kamień nożce
import random

def get_level_winers(choice_level):
    WINERS_T = {
        'k': ('n', 'j'),
        'm': ('p', 'j'),
        'p': ('k', 's'),
        'j': ('p', 's'),
        's': ('n', 'k')
    }
    WINERS_P = {
        'k': 'n',
        'm': 'p',
        'p': 'k'
    }

    if choice_level == 'p':
        return WINERS_P
    else:
        return WINERS_T

def get_level_correct(choice_level):
    CORRECT_VALUES_T = ['k', 'n', 'p', 'j', 's']
    CORRECT_VALUES_P = ['k', 'n', 'p']
    if choice_level == 'p':
        return CORRECT_VALUES_P
    else:
        return CORRECT_VALUES_T

def get_comp_choice(CORRECT_VALUES):
    return random.choice(CORRECT_VALUES)

def get_user_choice(CORRECT_VALUES):
    while True:
        user_choice = input(f"Podaj wartości {CORRECT_VALUES}:").lower()
        if user_choice in CORRECT_VALUES:
            return user_choice
        else:
            print('nieprwidłowa watrość')

def show_result(comp, user, WINERS):
    if comp == user:
        print('Remis')
    elif comp in WINERS[user]:
        print('Wygrana użytkownika')
    else:
        print('Wygrywa komputer')

def start(CORRECT_VALUES, WINERS):
    play_again = 't'
    while play_again == 't':
        comp = get_comp_choice(CORRECT_VALUES)
        user = get_user_choice(CORRECT_VALUES)
        print(f"Comp: {comp}, user {user}")
        show_result(comp, user, WINERS)
        play_again = input("Jeszcze raz t/n: ").lower()
    print("dzięki")

def level():
    play_again = 't'
    while play_again == 't':
        choice_level = input("""Podaj poziom:
            P - Prosty
            T - Trudny - """).lower()
        if choice_level == 'p' or choice_level == 't':
            start(get_level_correct(choice_level), get_level_winers(choice_level))
            play_again = start(get_level_correct(choice_level), get_level_winers(choice_level))
        else:
            print("Niepoprawny wybór poziomu. Dostępne opcje: P - prosty, T - Trudny")

def main():
    choice = input("""Welcome:
        S - Start,
        P - Poziom
        W - Wyjście - """).lower()
    if choice == 's':
        start(get_level_correct('p'), get_level_winers('p'))
    elif choice == 'w':
        print("PA!")
    elif choice == 'p':
        level()
    else:
        print("Wybór z poza zakresu")
        main()

main()


import sys

from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox, QFileDialog
from PyQt5.QtGui import QImage, QPixmap, QTextCursor
from PyQt5.QtCore import pyqtSignal, QThread, QSize, Qt
from Registration import Ui_MainWindow

import os
import time
import datetime as dt
import threading as th
import ctypes
import inspect
import copy
import numpy as np

import pyrealsense2 as rs
import open3d as o3d
import cv2

DELAY = 0

class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        # Set up the user interface from Designer.
        self.setupUi(self)

        self.dis_update.connect(self.camera_view)

        # Show current 2d depth png pic
        self.pushButton_takephotos.clicked.connect(self.pushButton_takephotos_clicked)

        # Show current 3d pointcloud button
        self.show_current_pointcloud.clicked.connect(self.show_current_pointcloud_clicked)

        # Select and show target 3d pointcloud button
        self.show_target_pointcloud.clicked.connect(self.show_target_pointcloud_clicked)

        self.registration_button.clicked.connect(self.registration_button_clicked)

        # change cmd output to text browser
        self.th = MyThread()
        self.th.signalForText.connect(self.onUpdateText)
        sys.stdout = self.th

        self.thread_camera = None
        self.takePhotos = False
        self.showCurrent3dPointCloud = False

    # 在对应的页面类的内部，与def定义的函数同级
    dis_update = pyqtSignal(QPixmap)

    def onUpdateText(self,text):
        cursor = self.cmd.textCursor()
        cursor.movePosition(QTextCursor.End)
        cursor.insertText(text)
        self.cmd.setTextCursor(cursor)
        self.cmd.ensureCursorVisible()

    def pushButton_takephotos_clicked(self):
        self.takePhotos = True

    def show_current_pointcloud_clicked(self):
        self.showCurrent3dPointCloud = True
        #print(self.showCurrent3dPointCloud)

    def show_target_pointcloud_clicked(self,Filepath):
        global target_dir

        c = QFileDialog.getOpenFileName(None, "Select the target file","C:/", "(*.ply)")
        print("Showing Target 3D pointcloud...")
        if c is not None:
            print("File dir is ", c[0])
            print("Succeed...")
            target_file_dir = str(c[0])
            pcd = o3d.io.read_point_cloud(target_file_dir)
            o3d.visualization.draw_geometries([pcd])

            target_dir = target_file_dir

    # add an event for exit the GUI
    def closeEvent(self, event):
        """我们创建了一个消息框，上面有俩按钮：Yes和No.第一个字符串显示在消息框的标题栏，第二个字符串显示在对话框，
              第三个参数是消息框的俩按钮，最后一个参数是默认按钮，这个按钮是默认选中的。返回值在变量reply里。"""

        reply = QMessageBox.question(self, 'Message', "Are you sure to quit?",
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        # 判断返回值，如果点击的是Yes按钮，我们就关闭组件和应用，否则就忽略关闭事件
        if reply == QMessageBox.Yes:
            self.stop_thread(self.thread_camera)
            event.accept()
            sys.stdout = sys.__stdout__
        else:
            event.ignore()

    # click event and register
    def registration_button_clicked(self):

        start = time.time()
        voxel_size = 0.05  # means 5cm for this dataset

        print(":: Load two point clouds and disturb initial pose.")
        source_reg = o3d.io.read_point_cloud(source_dir)
        target_reg = o3d.io.read_point_cloud(target_dir)

        # process data
        print(":: Downsample with a voxel size %.3f." % voxel_size)
        source_down = source_reg.voxel_down_sample(voxel_size)
        target_down = target_reg.voxel_down_sample(voxel_size)

        radius_normal = voxel_size * 2
        print(":: Estimate normal with search radius %.3f." % radius_normal)

        source_down.estimate_normals(
            o3d.geometry.KDTreeSearchParamHybrid(radius=radius_normal, max_nn=30))
        target_down.estimate_normals(
            o3d.geometry.KDTreeSearchParamHybrid(radius=radius_normal, max_nn=30))

        radius_feature = voxel_size * 5
        print(":: Compute FPFH feature with search radius %.3f." % radius_feature)
        source_fpfh = o3d.pipelines.registration.compute_fpfh_feature(
            source_down,
            o3d.geometry.KDTreeSearchParamHybrid(radius=radius_feature, max_nn=100))
        target_fpfh = o3d.pipelines.registration.compute_fpfh_feature(
            target_down,
            o3d.geometry.KDTreeSearchParamHybrid(radius=radius_feature, max_nn=100))

        print("prepare_dataset took %.3f sec.\n" % (time.time() - start))

        # global registration
        distance_threshold = voxel_size * 1.5
        print(":: RANSAC registration on downsampled point clouds.")
        print("   Since the downsampling voxel size is %.3f," % voxel_size)
        print("   we use a liberal distance threshold %.3f." % distance_threshold)
        result_ransac = o3d.pipelines.registration.registration_ransac_based_on_feature_matching(
            source_down, target_down, source_fpfh, target_fpfh, True,
            distance_threshold,
            o3d.pipelines.registration.TransformationEstimationPointToPoint(False),
            3, [
                o3d.pipelines.registration.CorrespondenceCheckerBasedOnEdgeLength(
                    0.9),
                o3d.pipelines.registration.CorrespondenceCheckerBasedOnDistance(
                    distance_threshold)
            ], o3d.pipelines.registration.RANSACConvergenceCriteria(100000, 0.999))

        print(result_ransac)

        print("execute_global_registration took %.3f sec.\n" % (time.time() - start))

        # refine registration (ICP registration)
        distance_threshold = voxel_size * 0.4
        print(":: Point-to-plane ICP registration is applied on original point")
        print("   clouds to refine the alignment. This time we use a strict")
        print("   distance threshold %.3f." % distance_threshold)

        print(":: Downsample with a voxel size %.3f." % voxel_size)
        source_down = source_reg.voxel_down_sample(voxel_size)
        target_down = target_reg.voxel_down_sample(voxel_size)

        radius_normal = voxel_size * 2
        print(":: Estimate normal with search radius %.3f." % radius_normal)

        source_down.estimate_normals(
            o3d.geometry.KDTreeSearchParamHybrid(radius=radius_normal, max_nn=30))
        target_down.estimate_normals(
            o3d.geometry.KDTreeSearchParamHybrid(radius=radius_normal, max_nn=30))

        radius_feature = voxel_size * 5
        print(":: Compute FPFH feature with search radius %.3f." % radius_feature)
        source_fpfh = o3d.pipelines.registration.compute_fpfh_feature(
            source_down,
            o3d.geometry.KDTreeSearchParamHybrid(radius=radius_feature, max_nn=100))
        target_fpfh = o3d.pipelines.registration.compute_fpfh_feature(
            target_down,
            o3d.geometry.KDTreeSearchParamHybrid(radius=radius_feature, max_nn=100))

        print(source_reg, target_reg, source_down, target_down, source_fpfh, target_fpfh)

        result_icp = o3d.pipelines.registration.registration_icp(
            source_down, target_down, distance_threshold, result_ransac.transformation,
            o3d.pipelines.registration.TransformationEstimationPointToPlane())

        print(result_icp)
        print("refine_registration took %.3f sec.\n" % (time.time() - start))

        self.show_results.setText("The transform Matrix is \n" + str(result_icp.transformation))

        source_temp = copy.deepcopy(source_reg)
        target_temp = copy.deepcopy(target_reg)
        source_temp.paint_uniform_color([1, 0.706, 0])
        target_temp.paint_uniform_color([0, 0.651, 0.929])
        source_temp.transform(result_icp.transformation)

        o3d.visualization.draw_geometries([source_temp, target_temp])

    def open_camera(self):
        # target选择开启摄像头的函数
        self.thread_camera = th.Thread(target=self.open_realsense)
        self.thread_camera.start()
        print('Open Camera...')

    def camera_view(self, c):
        # 调用setPixmap函数设置显示Pixmap
        self.label_show.setPixmap(c)
        # 调用setScaledContents将图像比例化显示在QLabel上
        self.label_show.setScaledContents(True)

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

    def stop_thread(self, thread):
        self._async_raise(thread.ident, SystemExit)

    def open_realsense(self):

        global source_dir

        print('open_realsense')

        # Create a pipeline
        pipeline = rs.pipeline()

        # Create a config and configure the pipeline to stream
        #  different resolutions of color and depth streams
        config = rs.config()
        config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
        config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)

        # Start streaming
        profile = pipeline.start(config)

        # Getting the depth sensor's depth scale (see rs-align example for explanation)
        depth_sensor = profile.get_device().first_depth_sensor()
        depth_scale = depth_sensor.get_depth_scale()
        print("Depth Scale is: ", depth_scale)

        # We will be removing the background of objects more than
        #  clipping_distance_in_meters meters away
        clipping_distance_in_meters = 1  # 1 meter
        clipping_distance = clipping_distance_in_meters / depth_scale

        # Processing blocks
        pc = rs.pointcloud()
        thr_filter = rs.threshold_filter()
        thr_filter.set_option(rs.option.min_distance, 0)
        thr_filter.set_option(rs.option.max_distance, 1.830)

        # Color Intrinsics
        # intr = color_frame.profile.as_video_stream_profile().intrinsics

        # Create an align object
        # rs.align allows us to perform alignment of depth frames to others frames
        # The "align_to" is the stream type to which we plan to align depth frames.
        align_to = rs.stream.color
        align = rs.align(align_to)

        # Streaming loop
        try:
            while True:
                # Get frameset of color and depth
                frames = pipeline.wait_for_frames()
                # frames.get_depth_frame() is a 640x360 depth image

                # Align the depth frame to color frame
                aligned_frames = align.process(frames)

                # Get aligned frames
                aligned_depth_frame = aligned_frames.get_depth_frame()  # aligned_depth_frame is a 640x480 depth image
                color_frame = aligned_frames.get_color_frame()

                # Validate that both frames are valid
                if not aligned_depth_frame or not color_frame:
                    continue

                aligned_depth_frame = thr_filter.process(aligned_depth_frame)

                depth_image = np.asanyarray(aligned_depth_frame.get_data())
                color_image = np.asanyarray(color_frame.get_data())

                #aligned_depth_frame = aligned_frames.first(aligned_depth_frame).as_video_frame()

                points = pc.calculate(aligned_depth_frame)

                if(self.takePhotos == True):

                    now_date = dt.datetime.now().strftime('%F')
                    now_time = dt.datetime.now().strftime('%F_%H%M%S')

                    path_ok = os.path.exists(now_date)
                    if(path_ok == False):
                        os.mkdir(now_date)

                    if(os.path.isdir(now_date)):
                        #id = "1"

                        depth_full_path = ''
                        color_full_path = ''

                        depth_col = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.03), cv2.COLORMAP_JET)

                        depth_full_path = os.path.join('./', now_date, now_time + '_depth.png')
                        depth_col_full_path = os.path.join('./', now_date, now_time + '_depth_col.png')
                        color_full_path = os.path.join('./', now_date, now_time + '_color.png')
                        ply_full_path = os.path.join('./', now_date, now_time + '_pointcloud.ply')

                        cv2.imencode('.png', depth_image)[1].tofile(depth_full_path)
                        cv2.imencode('.png', color_image)[1].tofile(color_full_path)
                        cv2.imencode('.png', depth_col)[1].tofile(depth_col_full_path)
                        points.export_to_ply(ply_full_path, color_frame)

                        print('Saved Successful...')

                        # show current depth pic
                        # zoom
                        scale = 0.8
                        img = QImage(depth_col_full_path)
                        mgnWidth = int(640 * scale)
                        mgnHeight = int(480 * scale)
                        size = QSize(mgnWidth, mgnHeight)
                        pixImg = QPixmap.fromImage(img.scaled(size, Qt.IgnoreAspectRatio))
                        self.show_currentPointCloud.resize(mgnWidth, mgnHeight)
                        self.show_currentPointCloud.setPixmap(pixImg)

                        source_dir = ply_full_path
                    self.takePhotos = False

                if(self.showCurrent3dPointCloud == True and self.takePhotos == False):
                    print(ply_full_path)
                    pcd = o3d.io.read_point_cloud(ply_full_path)
                    o3d.visualization.draw_geometries([pcd])
                    print("Showing the current 3D Pointcloud in Open3D GUI")

                    self.showCurrent3dPointCloud = False

                # Remove background - Set pixels further than clipping_distance to grey
                grey_color = 153
                depth_image_3d = np.dstack(
                    (depth_image, depth_image, depth_image))  # depth image is 1 channel, color is 3 channels
                bg_removed = np.where((depth_image_3d > clipping_distance) | (depth_image_3d <= 0), grey_color,
                                      color_image)

                images = bg_removed

                qimage = QImage(images, 640, 480, QImage.Format_RGB888)
                pixmap = QPixmap.fromImage(qimage)
                self.dis_update.emit(pixmap)

                time.sleep(DELAY)

        finally:
            pipeline.stop()

class MyThread(QThread):
    signalForText = pyqtSignal(str)

    def __init__(self,data=None, parent=None):
        super(MyThread, self).__init__(parent)
        self.data = data

    def write(self, text):
        self.signalForText.emit(str(text))  # 发射信号

    def flush(self):
        pass

if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.aboutToQuit.connect(app.deleteLater)
    w = MainWindow()
    w.show()

    w.open_camera()

    sys.exit(app.exec_())


def solution(n, times):
    answer = 0
    # 소요 최소시간(start), 최대시간(end) 구하기
    start = min(times)
    if n % len(times):
        end = max(times) * (n // len(times) + 1)
    else:
        end = max(times) * (n // len(times))

    # 이진탐색 진행
    while start <= end:
        mid = (start + end) // 2
        # 처리가능한 인원 수 구하기
        cnt = 0
        for time in times:
            cnt += mid // time
            if cnt >= n:
                break
        # mid time 내 처러 가능한 인원 수 >= n
        if cnt >= n:
            answer = mid
            end = mid - 1
        else:
            start = mid + 1

    # test log

    return answer


from django.db import transaction
from rest_framework import serializers

from back.models.invoice import Invoice, InvoiceStatus
from back.models.invoicing_month import InvoicingMonth
from back.models.payment import Payment
from back.serializers.invoice import InvoiceShortSerializer
from back.serializers.payment import PaymentSerializer

class InvoicingMonthSerializer(serializers.ModelSerializer):
    id_mes_facturacion = serializers.ReadOnlyField()
    invoices = InvoiceShortSerializer(many=True, write_only=True, required=False)

    class Meta:
        model = InvoicingMonth
        fields = "__all__"

    @transaction.atomic
    def create(self, validated_data):
        invoicing_month_to_close_query = InvoicingMonth.objects.filter(is_open=True)
        if invoicing_month_to_close_query.count() > 1:
            raise serializers.ValidationError(
                "Existen varios meses de facturación abiertos. Debe revisar este problema."
            )
        invoicing_month_to_close = invoicing_month_to_close_query.first()

        invoicing_month_to_close_payments = Payment.objects.filter(
            mes_facturacion=invoicing_month_to_close
        ).count()
        if invoicing_month_to_close_payments == 0:
            raise serializers.ValidationError(
                "El mes anterior no ha importado ningún pago. Revise si la facturación del mes que va a cerrar está correcta."
            )

        if invoicing_month_to_close is not None:
            invoicing_month_to_close.is_open = False
            invoicing_month_to_close.save()

            last_month_invoices = Invoice.objects.filter(
                mes_facturacion=invoicing_month_to_close
            )
            for last_month_invoice in last_month_invoices:
                if (
                    last_month_invoice.estado == InvoiceStatus.NUEVA
                    or last_month_invoice.estado == InvoiceStatus.PENDIENTE_DE_COBRO
                ):
                    if (
                        last_month_invoice.total is not None
                        and (
                            last_month_invoice.pago_1_al_10
                            + last_month_invoice.pago_11_al_30
                        )
                        >= last_month_invoice.total
                    ):
                        last_month_invoice.estado = InvoiceStatus.COBRADA
                    else:
                        last_month_invoice.estado = InvoiceStatus.NO_COBRADA
                    last_month_invoice.save()

        invoices = validated_data.pop("invoices", [])
        validated_data["id_mes_facturacion"] = validated_data.get(
            "anho"
        ) + validated_data.get("mes")
        validated_data["is_open"] = True
        invoicing_month = InvoicingMonth.objects.create(**validated_data)
        for invoice in invoices:
            invoice["mes_facturacion"] = invoicing_month
            Invoice.objects.create(**invoice)
        return invoicing_month


import os
import numpy
from typing import Dict
from flax.traverse_util import flatten_dict
from flax.serialization import msgpack_restore
import torch
torch.set_grad_enabled(False)

def load_vqgan_torch_params(path: str) -> Dict[str, torch.Tensor]:
    with open(os.path.join(path, 'flax_model.msgpack'), "rb") as f:
        params: Dict[str, numpy.ndarray] = msgpack_restore(f.read())

    P: Dict[str, numpy.ndarray] = flatten_dict(params, sep='.')

    for i in list(P.keys()):
        j = i
        if 'up' in i or 'down' in i:
            j = i.replace('_', '.')
            j = j.replace('proj.out', 'proj_out')
            j = j.replace('nin.short', 'nin_short')
        if 'bias' in i:
            P[j] = P.pop(i)
        elif 'scale' in i:
            j = j.replace('scale', 'weight')
            P[j] = P.pop(i)
        elif 'kernel' in i:
            j = j.replace('kernel', 'weight')
            P[j] = P.pop(i).transpose(3, 2, 0, 1)

    for i in P:
        P[i] = torch.tensor(P[i])

    P['embedding.weight'] = P.pop('quantize.embedding.embedding')

    for i in list(P):
        if i.split('.')[0] in ['encoder', 'quant_conv']:
            P.pop(i)

    return P

def load_dalle_bart_flax_params(path: str) -> Dict[str, numpy.ndarray]:
    with open(os.path.join(path, "flax_model.msgpack"), "rb") as f:
        params = msgpack_restore(f.read())

    for codec in ['encoder', 'decoder']:
        k = 'FlaxBart{}Layers'.format(codec.title())
        P: dict = params['model'][codec]['layers'][k]
        P['pre_self_attn_layer_norm'] = P.pop('LayerNorm_0')
        P['self_attn_layer_norm'] = P.pop('LayerNorm_1')
        P['self_attn'] = P.pop('FlaxBartAttention_0')
        if codec == 'decoder':
            P['pre_encoder_attn_layer_norm'] = P.pop('LayerNorm_2')
            P['encoder_attn_layer_norm'] = P.pop('LayerNorm_3')
            P['encoder_attn'] = P.pop('FlaxBartAttention_1')
        P['glu']: dict = P.pop('GLU_0')
        P['glu']['ln0'] = P['glu'].pop('LayerNorm_0')
        P['glu']['ln1'] = P['glu'].pop('LayerNorm_1')
        P['glu']['fc0'] = P['glu'].pop('Dense_0')
        P['glu']['fc1'] = P['glu'].pop('Dense_1')
        P['glu']['fc2'] = P['glu'].pop('Dense_2')

    for codec in ['encoder', 'decoder']:
        layers_params = params['model'][codec].pop('layers')
        params['model'][codec] = {
            **params['model'][codec],
            **layers_params
        }

    model_params = params.pop('model')
    params = {**params, **model_params}

    params['decoder']['lm_head'] = params.pop('lm_head')

    return params

def convert_dalle_bart_torch_from_flax_params(
    params: dict,
    layer_count: int,
    is_encoder: bool
) -> dict:
    P: Dict[str, numpy.ndarray] = flatten_dict(params, sep='.')

    for i in P:
        P[i] = torch.tensor(P[i]).to(torch.float16)

    for i in list(P):
        if 'kernel' in i:
            j = i.replace('kernel', 'weight')
            P[j] = P.pop(i).transpose(-1, -2)
        elif 'scale' in i:
            j = i.replace('scale', 'weight')
            P[j] = P.pop(i)

    for i in list(P):
        j = 'FlaxBart{}Layers'.format('Encoder' if is_encoder else 'Decoder')
        if j in i:
            for l in range(layer_count):
                k = i.replace(j, 'layers.' + str(l))
                P[k] = P[i][l]
            P.pop(i)

    P['embed_tokens.weight'] = P.pop('embed_tokens.embedding')
    P['embed_positions.weight'] = P.pop('embed_positions.embedding')
    return P

def convert_and_save_torch_params(is_mega: bool, model_path: str):
    print("converting params to torch")
    layer_count = 24 if is_mega else 12
    flax_params = load_dalle_bart_flax_params(model_path)
    encoder_params = convert_dalle_bart_torch_from_flax_params(
        flax_params['encoder'],
        layer_count=layer_count,
        is_encoder=True
    )
    decoder_params = convert_dalle_bart_torch_from_flax_params(
        flax_params['decoder'],
        layer_count=layer_count,
        is_encoder=False
    )

    for i in decoder_params:
        decoder_params[i] = decoder_params[i].to(torch.float16)

    for i in encoder_params:
        encoder_params[i] = encoder_params[i].to(torch.float16)

    detoker_params = load_vqgan_torch_params('./pretrained/vqgan')
    detoker_path = os.path.join('pretrained', 'vqgan', 'detoker.pt')

    torch.save(encoder_params, os.path.join(model_path, 'encoder.pt'))
    torch.save(decoder_params, os.path.join(model_path, 'decoder.pt'))
    torch.save(detoker_params, detoker_path)


from django.conf.urls import url, include
from .views import *

urlpatterns = [
    url(r'^profile/$', user_profile),
    url(r'^profile/(?P<pk>[0-9]+)/$', user_profile_by_id),
    url(r'^update_profile/$', user_update_profile),
    url(r'^follow/(?P<pk>[0-9]+)/$', user_follow),
    url(r'^unfollow/(?P<pk>[0-9]+)/$', user_unfollow),
    url(r'following/$', user_following),
    url(r'following/(?P<pk>[0-9]+)/$', user_following_by_id),
    url(r'followers/$', user_followers),
    url(r'followers/(?P<pk>[0-9]+)/$', user_followers_by_id),
    # ...
]


import numpy as np
from math import *
import math as m
import cmath as cm
from numba import cuda

@cuda.jit
def single_sideband_kernel(G, strides, Qx_all, Qy_all, Kx_all, Ky_all, aberrations, aberration_angles, theta_rot, alpha,
                           Ψ_Qp, Ψ_Qp_left_sb, Ψ_Qp_right_sb, eps, lam, scale):
    """

    :param G: array_like , 4D G-function used in ptychography
    :param strides: array_like shape (4,) contains the strides of the G array
    :param Qx_all: array_like, shape (G.shape[1],)
    :param Qy_all: array_like, shape (G.shape[0],)
    :param Kx_all: array_like, shape (G.shape[3],)
    :param Ky_all: array_like, shape (G.shape[2],)
    :param aberrations: array_like, shape (16,)
    :param aberration_angles: array_like, shape (12,)
    :param theta_rot: float, STEM rotation angle in radians
    :param alpha: float, converge half-angle in radians
    :param Ψ_Qp: array_like, shape (G.shape[0], G.shape[1],) to store the result of the weak phase approximation
    :param Ψ_Qp_left_sb: array_like, shape (G.shape[0], G.shape[1],) to store the result of the left sideband
    :param Ψ_Qp_right_sb: array_like, shape (G.shape[0], G.shape[1],) to store the result of the right sideband
    :param eps: float, threshold for which Γ-function values to include in the summation Γ_abs > eps
    :param lam: float, wavelength in Angstrom
    :param scale: float, scale factor to scale the aperture to the measured intensity
    :return: nothing
    """
    def aperture2(qx, qy, lam, alpha_max, scale):
        qx2 = qx ** 2
        qy2 = qy ** 2
        q = m.sqrt(qx2 + qy2)
        ktheta = m.asin(q * lam)
        return (ktheta < alpha_max) * scale

    def chi3(qx, qy, lam, a, phi):
        """
        Creates an aberration surface from aberration coefficients.

        :param qx: M1 x M2 tensor of x coefficients of reciprocal space
        :param qy: M1 x M2 tensor of y coefficients of reciprocal space
        :param lam: wavelength in Angstrom
        :param a10: shift                               in Angstrom
        :param a11: shift                               in Angstrom
        :param a20: defocus                             in Angstrom
        :param a22: two-fold Astigmatism                in Angstrom
        :param a31: axial coma                          in Angstrom
        :param a33: three-fold astigmatism              in Angstrom
        :param a40: spherical aberration                in um
        :param a42: star aberration                     in um
        :param a44: four-fold astigmatism               in um
        :param a51: fourth order axial coma             in um
        :param a53: three-lobe aberration               in um
        :param a55: five-fold astigmatism               im um
        :param a60: fifth-order spherical               in mm
        :param a62: fifth-order two-fold astigmatism    in mm
        :param a64: fifth-order four-fold astigmatism   in mm
        :param a66: siz-fold astigmatism                in mm
        :param phi11: shift angle
        :param phi22: two-fold Astigmatism angle
        :param phi33: three-fold astigmatism angle
        :param phi44: four-fold astigmatism angle
        :param phi55: five-fold astigmatism angle
        :param phi51: fourth order axial coma angle
        :param phi66: Chromatic aberration angle
        :param phi62: fifth-order two-fold astigmatism angle
        :param phi64: fifth-order four-fold astigmatism angle
        :param phi31: axial coma angle
        :param phi42: star aberration angle
        :param phi53: three-lobe aberration angle
        :return: M1 x M1 x (maximum size of all aberration tensors)
        """
        qx2 = qx ** 2
        qy2 = qy ** 2
        q = sqrt(qx2 + qy2)
        ktheta = m.asin(q * lam)

        kphi = m.atan2(qy, qx)
        # print(a0.shape, scales.shape)
        cos = m.cos
        chi = 2.0 * np.pi / lam * (1.0 * (a[1] * cos(2 * (kphi - phi[0])) + a[0]) * ktheta +
                                   1.0 / 2 * (a[3] * cos(2 * (kphi - phi[1])) + a[2]) * ktheta ** 2 +
                                   1.0 / 3 * (a[5] * cos(3 * (kphi - phi[2])) + a[4] * cos(
                    1 * (kphi - phi[3]))) * ktheta ** 3 +
                                   1.0 / 4 * (a[8] * cos(4 * (kphi - phi[4])) + a[7] * cos(2 * (kphi - phi[5])) + a[
                    6]) * ktheta ** 4 +
                                   1.0 / 5 * (a[11] * cos(5 * (kphi - phi[6])) + a[10] * cos(3 * (kphi - phi[7])) + a[
                    9] * cos(
                    1 * (kphi - phi[8]))) * ktheta ** 5 +
                                   1.0 / 6 * (a[15] * cos(6 * (kphi - phi[9])) + a[14] * cos(4 * (kphi - phi[10])) + a[
                    13] * cos(
                    2 * (kphi - phi[11])) + a[12]) * ktheta ** 6)

        return chi

    gs = G.shape
    N = gs[0] * gs[1] * gs[2] * gs[3]
    n = cuda.blockIdx.x * cuda.blockDim.x + cuda.threadIdx.x
    iqy = n // strides[0]
    iqx = (n - iqy * strides[0]) // strides[1]
    iky = (n - (iqy * strides[0] + iqx * strides[1])) // strides[2]
    ikx = (n - (iqy * strides[0] + iqx * strides[1] + iky * strides[2])) // strides[3]

    if n < N:

        Qx = Qx_all[iqx]
        Qy = Qy_all[iqy]
        Kx = Kx_all[ikx]
        Ky = Ky_all[iky]

        Qx_rot = Qx * cos(theta_rot) - Qy * sin(theta_rot)
        Qy_rot = Qx * sin(theta_rot) + Qy * cos(theta_rot)

        Qx = Qx_rot
        Qy = Qy_rot

        A = aperture2(Ky, Kx, lam, alpha, scale) * cm.exp(1j * chi3(Ky, Kx, lam, aberrations, aberration_angles))
        A_KplusQ = aperture2(Ky + Qy, Kx + Qx, lam, alpha, scale) * cm.exp(1j *
                                                                           chi3(Ky + Qy, Ky + Qx, lam, aberrations,
                                                                                aberration_angles))
        A_KminusQ = aperture2(Ky - Qy, Kx - Qx, lam, alpha, scale) * cm.exp(1j *
                                                                            chi3(Ky - Qy, Kx - Qx, lam, aberrations,
                                                                                aberration_angles))

        Γ = A.conjugate() * A_KminusQ - A * A_KplusQ.conjugate()

        Kplus = sqrt((Kx + Qx) ** 2 + (Ky + Qy) ** 2)
        Kminus = sqrt((Kx - Qx) ** 2 + (Ky - Qy) ** 2)
        K = sqrt(Kx ** 2 + Ky ** 2)
        bright_field = K < alpha / lam
        double_overlap1 = (Kplus < alpha / lam) * bright_field * (Kminus > alpha / lam)
        double_overlap2 = (Kplus > alpha / lam) * bright_field * (Kminus < alpha / lam)

        # print(Γ.real, Γ.imag)
        # Gamma[iqy, iqx, iky, ikx] = Γ
        Γ_abs = abs(Γ)
        take = Γ_abs > eps and bright_field
        if take:
            val = G[iqy, iqx, iky, ikx] * Γ.conjugate()
            cuda.atomic.add(Ψ_Qp.real, (iqy, iqx), val.real)
            cuda.atomic.add(Ψ_Qp.imag, (iqy, iqx), val.imag)
        if double_overlap1:
            val = G[iqy, iqx, iky, ikx]
            cuda.atomic.add(Ψ_Qp_left_sb.real, (iqy, iqx), val.real)
            cuda.atomic.add(Ψ_Qp_left_sb.imag, (iqy, iqx), val.imag)
        if double_overlap2:
            val = G[iqy, iqx, iky, ikx]
            cuda.atomic.add(Ψ_Qp_right_sb.real, (iqy, iqx), val.real)
            cuda.atomic.add(Ψ_Qp_right_sb.imag, (iqy, iqx), val.imag)
        if iqx == 0 and iqy == 0:
            val = abs(G[iqy, iqx, iky, ikx]) + 1j * 0
            cuda.atomic.add(Ψ_Qp.real, (iqy, iqx), val.real)
            cuda.atomic.add(Ψ_Qp_left_sb.real, (iqy, iqx), val.real)
            cuda.atomic.add(Ψ_Qp_right_sb.real, (iqy, iqx), val.real)


from python_multiprocessing_and_multithreading.time_track import time_track
from python_multiprocessing_and_multithreading.volatility_sort_and_print import sort, path_to_file

class VolatilityCounter:

    def __init__(self, file_name):
        self.file_name = file_name
        self.ticker = None
        self.max_price = 0
        self.min_price = 0
        self.volatility = 0

    def run(self):
        with open(self.file_name, 'r', encoding='utf8') as file:
            self.get_max_and_min_price(file=file)
            self.volatility_count()

    def get_max_and_min_price(self, file):
        file.readline()
        for line in file:
            sec_id, trade_time, price, quantity = line[:-1].split(',')
            price = float(price)
            if sec_id != self.ticker:
                self.ticker = sec_id
                self.max_price, self.min_price = price, price
            elif self.max_price < price:
                self.max_price = price
            elif self.min_price > price:
                self.min_price = price

    def volatility_count(self):
        half_sum = (self.max_price + self.min_price) / 2
        self.volatility = round((((self.max_price - self.min_price) / half_sum) * 100), 2)

@time_track
def main():
    for file_name in path_to_file(path=path):
        count_volatility = VolatilityCounter(file_name=file_name)
        count_volatility.run()
        vol_list.setdefault(count_volatility.ticker, count_volatility.volatility)

if __name__ == '__main__':
    path = 'trades'
    vol_list = {}
    main()
    sort(vol_list)


from django.urls import path
from . import views

urlpatterns = [
    path('', views.Landing.as_view(), name="landing"),
    path('home/', views.Home.as_view(), name="home"),
    path('games/new/', views.GameCreate.as_view(), name="game_create"),
    path('games/<int:pk>/', views.GameDetail.as_view(), name="game_detail"),
    path('games/<int:pk>/update',views.GameUpdate.as_view(), name="game_update"),
    path('games/<int:pk>/delete',views.GameDelete.as_view(), name="game_delete"),
    path('library/stoppedplaying/', views.StoppedPlaying.as_view(), name="stopped_playing"),
    path('library/currentlyplaying/', views.CurrentlyPlaying.as_view(), name="currently_playing"),
    path('library/finishedplaying/', views.FinishedPlaying.as_view(), name="finished_playing"),
    path('library/wanttoplay/', views.WantToPlay.as_view(), name="want_to_play"),
    path('accounts/signup/', views.Signup.as_view(), name="signup"),
    path('games/search/', views.Search, name='search'),
    path('games/details/stop', views.Stop, name='stop'),
    path('games/details/current', views.Current, name='current'),
    path('games/details/finish', views.Finish, name='finish'),
    path('games/details/want', views.Want, name='want'),

]


#!/usr/bin/env python3

import argparse as arg
import glob
import os
import subprocess
import sys
#from multiprocessing.pool import ThreadPool
from multiprocessing import Pool
import os

def repexjob(INDEX):
    orig= os.getcwd()
    os.chdir(f"/home/dulyanov/RepExTry/SESSIONS_MULT/KP{INDEX}")
    make_command = ["make"]
    stdout = open(f'{INDEX}-STD.out', 'w')
    stderr = open(f'{INDEX}-STD.err', 'w')
    make_proc = subprocess.Popen(make_command, shell = True, stdout = stdout, stderr = stderr)
    make_proc.wait()
    os.chdir(orig)

if __name__=='__main__':
    parser = arg.ArgumentParser()
    parser.add_argument('--adapters', default='/home/ermolaev/soft/bbmap/resources/adapters.fa')
    parser.add_argument('--bbduk_params', default='ktrim=r k=20 mink=10 hdist=2 threads=10 maxns=0 ftl=19 ftr=139 minlen=120')
    parser.add_argument('--num_runs_simult', default='2')
    parser.add_argument('--comparative', action='store_true')
    parser.add_argument('PATHS', help='EXAMPLE: /home/reads/{ind}/{ind}_read_{read_number}.fastq; {ind} and {read_number} should be left unchanged')
    parser.add_argument('INDEXES', nargs='+')

    args = parser.parse_args()
    COMPARATIVE, PATHS, ADAPTERS, BBDUK_PARAMS, INDEXES, PROCS = args.comparative, args.PATHS, args.adapters, args.bbduk_params, args.INDEXES, args.num_runs_simult

    MAKE_TEMPLATES = glob.glob('/home/dulyanov/RepExTry/**/Makefile_template', recursive=True)

    get_path = lambda ind, read_number: ' '.join(sorted(glob.glob(PATHS.format(ind=ind, read_number=read_number))))

    if not COMPARATIVE:
        for INDEX in INDEXES:
            SOURCE = locals()
            PATHR1FASTQGZ, PATHR2FASTQGZ = get_path(INDEX, '1'), get_path(INDEX, '2')
            print(PATHS.format(ind=INDEX, read_number='1'))
            REPLACER_DICT = dict((i, SOURCE[i]) for i in ('ADAPTERS', 'BBDUK_PARAMS', 'PATHR1FASTQGZ', 'PATHR2FASTQGZ', 'INDEX'))
            for TEMPLATE in MAKE_TEMPLATES:
                with open(TEMPLATE, 'r') as TFILE:
                    TXT = TFILE.read()
                    for NAME, VALUE in REPLACER_DICT.items():
                        TXT=TXT.replace(f'!{NAME}!', f'{VALUE}')
                RUNNER = TEMPLATE.replace('RepExTry/', f'RepExTry/SESSIONS_MULT/KP{INDEX}/').replace('Makefile_template', 'Makefile')
                os.makedirs(os.path.dirname(RUNNER), exist_ok=True)
                with open(RUNNER, 'w') as RFILE:
                    RFILE.write(TXT)
    else:
        for TEMPLATE in MAKE_TEMPLATES:
            SOURCE = locals()
            with open(TEMPLATE, 'r') as TFILE:
                TXT = TFILE.read()
                if TXT[0:8] == 'ADAPTERS':
                    TXTLIST = TXT.split('\n')
                    BBDUK = TXTLIST[9]
                    TXTLIST.pop(9)
                    for INDEX in INDEXES:
                        SOURCE = locals()
                        PATHR1FASTQGZ, PATHR2FASTQGZ = get_path(INDEX, '1'), get_path(INDEX, '2')
                        REPLACER_DICT = dict((i, SOURCE[i]) for i in ('ADAPTERS', 'BBDUK_PARAMS', 'PATHR1FASTQGZ', 'PATHR2FASTQGZ', 'INDEX'))
                        TXTLIST.insert(9, BBDUK.replace('!PATHR1FASTQGZ!', PATHR1FASTQGZ).replace('!PATHR2FASTQGZ!', PATHR2FASTQGZ).replace('!INDEX!', INDEX))
                    TXT = '\n'.join(TXTLIST)
                for NAME, VALUE in REPLACER_DICT.items():
                    TXT=TXT.replace(f'!{NAME}!', f'{VALUE}')
            RUNNER = TEMPLATE.replace('RepExTry/', f'RepExTry/SESSIONS_MULT/comp{"".join(INDEXES)}/').replace('Makefile_template', 'Makefile')
            os.makedirs(os.path.dirname(RUNNER), exist_ok=True)

    pool = Pool(processes=int(PROCS))
    pool.map(repexjob, iter(INDEXES))

# with open('Makefile_template', 'r') as file:


import os
import os.path
import tkinter
from datetime import date
from tkinter import Tk, Listbox, END, messagebox
from tkinter import ttk

import requests
from bs4 import BeautifulSoup

today = date.today()
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0"}

class DeckMGT(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self, parent)
        self.parent = parent
        self.generateIntroGUI()

    def generateIntroGUI(self):
        for widget in self.parent.winfo_children():  # clear frame on load
            widget.destroy()
        self.parent.geometry("450x300")
        self.parent.title("Price Checker | Main Menu")

        self.labelTop = ttk.Label(self.parent, text="View Card History")
        self.labelTop.pack()

        cardNames = []  # populate a list of cards
        if not os.listdir("Cards/"):
            cardNames.append("No cards in system")
        else:
            for each in os.listdir("Cards"):
                cardNames.append(each.replace(".txt", ""))
        self.cardNameComboBox = ttk.Combobox(self.parent, values=cardNames,
                                             postcommand=self.updateList, width=25)  # state="readonly

        self.cardNameComboBox.pack()
        self.cardNameComboBox.current(0)

        self.cardHistoryBtn = ttk.Button(self.parent, text="View", command=self.generateCardHistoryGUI)
        self.cardHistoryBtn.pack()

        self.deleteCardBtn = ttk.Button(self.parent, text="Delete Card", command=self.removeCard)
        self.deleteCardBtn.pack()

        self.cardHistoryBtn = ttk.Button(self.parent, text="Generate Price Report", command=self.generatePriceReport)
        self.cardHistoryBtn.pack()

        self.newURLEntry = ttk.Entry(self.parent)
        self.newURLEntry.pack()

        self.newCardBtn = ttk.Button(self.parent, text="Add New Card", command=self.generateNewCard)
        self.newCardBtn.pack()

        self.exitButton = ttk.Button(self.parent, text="Exit Application", command=self.exitApplication)
        self.exitButton.pack()

    def generateCardHistoryGUI(self):
        listbox = Listbox(Tk())
        listbox.configure(width=75, height=20)
        listbox.winfo_toplevel().title("Results for " + self.cardNameComboBox.get())
        listbox.configure()
        listbox.pack()

        for eachLine in open("Cards/" + self.cardNameComboBox.get() + ".txt", "r+", encoding="utf-8").readlines():
            listbox.insert(END, eachLine)

    def generatePriceReport(self):
        storedReports = []
        buylistURLs = []
        listbox = Listbox(Tk())
        listbox.configure(width=75, height=20)
        listbox.winfo_toplevel().title("Price Report")
        listbox.configure()
        listbox.pack()
        looptest = 0

        for each in open("URLs.txt"):
            print(each)
            buylistURLs.append(each.replace("catalog", "buylist"))
            if(
                BeautifulSoup(requests.get(url=buylistURLs[looptest], headers=headers).content, "html.parser").find(
                    'form', attrs={"class": "add-to-cart-form", "data-variant": "NM-Mint, English"}) is None):
                buylistPrice = 0
            else:
                buylistPrice = BeautifulSoup(requests.get(url=buylistURLs[looptest], headers=headers).content, "html.parser").find(
                    'form', attrs={"class": "add-to-cart-form", "data-variant": "NM-Mint, English"}).get_text()[
                7:].split("/", 1)[0].strip()
            looptest += 1
            soup = BeautifulSoup(requests.get(url=each, headers=headers).content, "html.parser")
            cardName = soup.find('h1', attrs={"class": "title"}).get_text().replace('/', '')
            if (soup.find('span', attrs={"class": "variant-short-info"}).get_text() == "Out of stock."):
                price = soup.find('span', attrs={"class": "price no-stock"}).get_text()[5:]
            else:
                if (soup.find('form', attrs={"class": "add-to-cart-form", "data-variant": "NM-Mint, English",
                                             "data-name": cardName}) is None):
                    price = (
                        soup.find('form',
                                  attrs={"class": "add-to-cart-form"}).get_text()[
                        7:].split("/", 1)[0].rstrip())
                else:
                    price = (
                        soup.find('form',
                                  attrs={"class": "add-to-cart-form", "data-variant": "NM-Mint, English",
                                         "data-name": cardName}).get_text()[
                        7:].split("/", 1)[0].rstrip())
            print(price)
            print(buylistPrice)
            if (os.path.exists("Cards/" + cardName + ".txt")):
                eachLastLine = open("Cards/" + cardName + ".txt", "r+", encoding="utf-8").readlines()[-1].split("|", 1)[
                    0].strip()
            if (eachLastLine != price):
                storedReports.append(cardName + " changed price from " + str(eachLastLine) + " to " + price)
                open("Cards/" + cardName + ".txt", "a", encoding="utf-8").write(
                    price + " | Buylist (cash): " + buylistPrice + " | Credit: " + (
                        str(float(buylistPrice) * 1.25)) + " | " + str((date.today())) + "\n")
            """else:
                eachLastLine = open("Cards/" + cardName + ".txt", "w", encoding="utf-8").write(
                    price + " | " + str(date.today()) + "\n") #overwrites file if same price is met"""

        if (len(storedReports) == 0):
            listbox.insert(END, "NO CHANGES!")
        else:
            for eachLine in storedReports:
                listbox.insert(END, eachLine)

    def generateNewCard(self):
        soup = BeautifulSoup(requests.get(url=self.newURLEntry.get(), headers=headers).content, "html.parser")
        cardName = soup.find('h1', attrs={"class": "title"}).get_text().replace('/', '')
        buylistURLs = self.newURLEntry.get().replace("catalog", "buylist")
        # buylistPrice = (BeautifulSoup(requests.get(url=buylistURLs, headers=headers).content, "html.parser").find('span', attrs={"class": "regular price"}).get_text()[5:].split("/", 1)[0].rstrip())
        if (soup.find('form', attrs={"class": "add-to-cart-form", "data-variant": "NM-Mint, English",
                                     "data-name": cardName}) is None):
            buylistPrice = (
                soup.find('form',
                          attrs={"class": "add-to-cart-form"}).get_text()[
                7:].split("/", 1)[0].rstrip())
        else:
            buylistPrice = (
                soup.find('form',
                          attrs={"class": "add-to-cart-form", "data-variant": "NM-Mint, English",
                                 "data-name": cardName}).get_text()[
                7:].split("/", 1)[0].rstrip())
        """buylistPrice = BeautifulSoup(requests.get(url=buylistURLs, headers=headers).content, "html.parser").find('form',
                                                                                attrs={
                                                                                "class": "add-to-cart-form",
                                                                                "data-variant": "NM-Mint, English",
                                                                                "data-name": cardName}).get_text()[
                       7:].split("/", 1)[0].rstrip()"""

        newCard = open("Cards/" + soup.find('h1', attrs={"class": "title"}).get_text().replace('/', '') + ".txt", "w")
        if (soup.find('span', attrs={"class": "variant-short-info"}).get_text() == "Out of stock."):
            newCard.write(
                soup.find('span', attrs={"class": "price no-stock"}).get_text()[
                5:] + " | Buylist (cash): " + buylistPrice + " | Credit: " + (
                    str(float(buylistPrice) * 1.25)) + " | " + str((date.today())) + "\n")
        else:
            if (soup.find('form', attrs={"class": "add-to-cart-form", "data-variant": "NM-Mint, English",
                                         "data-name": cardName}) is None):
                newCard.write(
                    soup.find('form',
                              attrs={"class": "add-to-cart-form"}).get_text()[
                    7:].split("/", 1)[0].rstrip() + " | Buylist (cash): " + buylistPrice + " | Credit: " + (
                        str(float(buylistPrice) * 1.25)) + " | " + str((date.today())) + "\n")
            else:
                newCard.write(
                    soup.find('form',
                              attrs={"class": "add-to-cart-form", "data-variant": "NM-Mint, English"}).get_text()[
                    7:].split("/", 1)[0].rstrip() + " | Buylist (cash): " + buylistPrice + " | Credit: " + (
                        str(float(buylistPrice) * 1.25)) + " | " + str((date.today())) + "\n")
        newCard = open("URLs.txt", "a")
        newCard.write(self.newURLEntry.get() + "\n")
        newCard.close()
        self.newURLEntry.delete(0, END)

    def updateList(self):
        cardNames = []  # populate a list of cards
        for each in os.listdir("Cards"):
            cardNames.append(each.replace(".txt", ""))

        self.cardNameComboBox.configure(values=list(set(cardNames)))  # updates card combobox on action

    def removeCard(self):
        confirmationBtn = messagebox.askquestion("Delete Card", "Are you sure you want to delete this?",
                                                 icon="warning")
        if confirmationBtn == "yes":
            os.remove("Cards/" + self.cardNameComboBox.get() + ".txt")
            self.updateList()

    def exitApplication(self):
        root.destroy()

if __name__ == '__main__':
    root = tkinter.Tk()
    ttk.Style().configure("TButton", padding=6, relief="flat", background="#666666")
    run = DeckMGT(root)
    root.mainloop()


#5. Faça um programa que leia uma frase e a exiba na tela conforme o exemplo abaixo. Exemplo:
#Entrada: ABCDE
#Saída: A
#BB
#CCC
#DDDD
#EEEEEE
#DDDD
#CCC
#BB
#A

frase = input('Digite uma frase: ')
tam = len(frase)

for i in range(tam):
    print(f'{frase[i]*(i+1)}')

for i in range(tam-2,-1,-1):
    print(f'{frase[i]*(i+1)}')


from typing import Any, Dict, Set
from pathlib import PurePosixPath

from sqlalchemy import create_engine, event, MetaData  # type: ignore
from sqlalchemy.engine import Engine  # type: ignore
from sqlalchemy.sql import select  # type: ignore

from .connection import get_sqlite3_path
from .models import RepositoryMetadata, SourceFileInRepository, MockSourceFile
from ._schema import (
    failure, meta, repository, repository_source, source_file, source_summary,
    metadata
)

from sensibility.language import SourceSummary

class UniquenessError(RuntimeError):
    pass

class NewCorpusError(Exception):
    pass

class FileInfo:
    def __init__(self, mappings: Set[SourceFileInRepository],
                 summary: SourceSummary) -> None:
        assert len(mappings) > 0
        self._mappings = mappings
        self.summary = summary

    @property
    def filehash(self) -> str:
        return self._any.filehash

    @property
    def owner(self) -> str:
        return self._any.owner

    @property
    def name(self) -> str:
        return self._any.name

    @property
    def href(self) -> str:
        return self._any.href

    @property
    def license(self) -> str:
        return self._any.license

    @property
    def path(self) -> PurePosixPath:
        return self._any.path

    @property
    def n_tokens(self) -> int:
        return self.summary.n_tokens

    @property
    def sloc(self) -> int:
        return self.summary.sloc

    @property
    def is_unique(self) -> bool:
        return len(self._mappings) == 1

    @property
    def _any(self) -> SourceFileInRepository:
        return next(iter(self._mappings))

class Corpus:
    def __init__(self, engine=None, url: str=None, read_only=False) -> None:
        if engine is not None:
            self.engine = engine
        else:
            if url is None:
                url = f"sqlite:///{get_sqlite3_path()}"
            self.engine = create_engine(url)

        self._initialize_sqlite3(read_only)

        if self.empty:
            metadata.create_all(self.engine)

        self.conn = self.engine.connect()

    @property
    def language(self) -> str:
        """
        The main laguage of the mined sources.
        """
        query = select([meta.c.value]).\
            where(meta.c.key == 'language')
        try:
            result, = self.conn.execute(query)
        except ValueError:
            raise NewCorpusError
        else:
            return result[meta.c.value]

    @property
    def empty(self) -> bool:
        metadata = MetaData()
        metadata.reflect(self.engine)
        return 'repository' not in metadata

    def __getitem__(self, filehash: str) -> bytes:
        """
        Returns a file from the corpus.
        """
        return self.get_source(filehash)

    def set_metadata(self, **kwargs: Any) -> None:
        """
        Sets the metadata table.
        """
        self.conn.execute(meta.insert(), [
            {'key': key, 'value': str(value)}
            for key, value in kwargs.items()
        ])

    def insert_repository(self, repo: RepositoryMetadata) -> None:
        """
        Insert a repository's metadata into the database.
        """
        self.conn.execute(repository.insert(),
                          owner=repo.owner, name=repo.name,
                          revision=repo.revision, license=repo.license,
                          commit_date=repo.commit_date)

    def insert_source_file_from_repo(self, entry: SourceFileInRepository) -> None:
        """
        Insert a source file from a repository into the database. If the
        source file already exists in the database, only the relation is
        inserted.
        """
        trans = self.conn.begin()
        try:
            self.conn.execute((source_file.insert()
                                .prefix_with('OR IGNORE', dialect='sqlite')),
                              source=entry.source_file.source,
                              hash=entry.filehash)
            self.conn.execute(repository_source.insert(),
                              owner=entry.owner, name=entry.name,
                              hash=entry.filehash, path=str(entry.path))
        except:
            trans.rollback()
            raise
        else:
            trans.commit()

    def insert_source_summary(self, filehash: str, summary: SourceSummary) -> None:
        """
        Insert the word count into the source summary.
        """
        self.conn.execute(source_summary.insert(),
                          hash=filehash,
                          sloc=summary.sloc, n_tokens=summary.n_tokens)

    def insert_failure(self, filehash: str) -> None:
        """
        Insert the word count into the source summary.
        """
        self.conn.execute(failure.insert(), hash=filehash)

    def get_source(self, filehash: str) -> bytes:
        """
        Returns the source code for one file.
        """
        query = select([source_file.c.source])\
            .where(source_file.c.hash == filehash)
        result, = self.conn.execute(query)
        return result[source_file.c.source]

    def get_info(self, filehash: str) -> FileInfo:
        # Do an intense query, combining multiple tables.
        query = select([source_summary, repository_source, repository]).select_from(
            source_file.join(source_summary)\
            .join(repository_source)\
            .join(repository)
        ).where(source_summary.c.hash == filehash)
        results = self.conn.execute(query).fetchall()

        # TODO: what if it's not found?

        mock_file = MockSourceFile(filehash)
        repos = {
            (row[repository.c.owner], row[repository.c.name]): RepositoryMetadata(
                owner=row[repository.c.owner],
                name=row[repository.c.name],
                license=row[repository.c.license],
                revision=row[repository.c.revision],
                commit_date=row[repository.c.commit_date]
            ) for row in results
        }
        mappings = set(
            SourceFileInRepository(
                repository=repos[row[repository.c.owner], row[repository.c.name]],
                source_file=mock_file,
                path=PurePosixPath(row[repository_source.c.path])
            ) for row in results
        )

        row, *_ = results
        summary = SourceSummary(sloc=row[source_summary.c.sloc],
                                n_tokens=row[source_summary.c.n_tokens])
        return FileInfo(mappings, summary)

    def _initialize_sqlite3(self, read_only: bool) -> None:
        """
        Set some pragmas for initialy creating the SQLite3 database.
        """

        @event.listens_for(Engine, "connect")
        def set_sqlite_pragma(dbapi_connection, _connection_record):
            cur = dbapi_connection.cursor()
            cur.execute('PRAGMA encoding = "UTF-8"')
            cur.execute('PRAGMA foreign_keys = ON')
            if not read_only:
                cur.execute('PRAGMA journal_mode = WAL')
                cur.execute('PRAGMA synchronous = NORMAL')
            cur.close()


import time
import platform

from behave import when, step
from selenium import webdriver
from selenium.common.exceptions import ElementNotInteractableException
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWait

from features.configs.automation_config import TIMEOUT

class BasePage:

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

    @staticmethod
    @when('I open {page} page in wui admin')
    def open_page(context, page):
        context.driver.get(context.wui_admin_url + "/" + page)

    @when("I open {page} page in Cloud")
    def open_page(self, context, page):
        context.driver.get(context.cloud_url + "/" + page)

    def find_element(self, locator, timeout=TIMEOUT):
        return WebDriverWait(self.driver, timeout).until(ec.presence_of_element_located(locator),
                                                         message=f"Can't find element by locator {locator}")

    def find_elements(self, locator, timeout=TIMEOUT):
        return WebDriverWait(self.driver, timeout).until(ec.presence_of_all_elements_located(locator),
                                                         message=f"Can't find elements by locator {locator}")

    def wait_element_text(self, locator, text, timeout=TIMEOUT):
        return WebDriverWait(self.driver, timeout).until(ec.text_to_be_present_in_element(locator, text),
                                                         message=f"Text {text} is not present in element {locator}")

    def wait_element_is_visible(self, locator, timeout=TIMEOUT):
        return WebDriverWait(self.driver, timeout).until(ec.visibility_of_any_elements_located(locator),
                                                         message=f"Elements with locator {locator} is not visible")

    def wait_element_is_not_visible(self, locator, timeout=TIMEOUT):
        return WebDriverWait(self.driver, timeout).until(ec.invisibility_of_element(locator),
                                                         message=f"Elements with locator {locator} is visible")

    def send_keys_with_retry(self, locator, text, timeout=TIMEOUT):
        is_typed = False
        start_time = time.time()

        while not is_typed and ((time.time() - start_time) < timeout):
            try:
                self.find_element(locator).send_keys(text)
                is_typed = True
            except ElementNotInteractableException:
                time.sleep(1)

        assert is_typed, "Text " + text + " is not typed into element with locator " + str(
            locator) + " in timeout = " + str(
            timeout) + " secs"

    def switch_to_window_with_retry(self, window_number, timeout=TIMEOUT):
        is_switched = False
        start_time = time.time()

        while not is_switched and ((time.time() - start_time) < timeout):
            try:
                self.driver.switch_to_window(self.driver.window_handles[window_number])
                is_switched = True
            except IndexError:
                time.sleep(1)

        assert is_switched, "Window with number " + str(window_number) + " is not chosen in timeout = " + str(
            timeout) + " secs"

    def click_with_retry(self, locator, condition, timeout=TIMEOUT):
        is_clicked = False
        start_time = time.time()

        while not is_clicked and ((time.time() - start_time) < timeout):
            self.find_element(locator).click()

            if condition():
                is_clicked = True
            else:
                time.sleep(1)

        assert is_clicked, "Element with locator " + str(locator) + " is not clicked in timeout = " + str(
            timeout) + " secs"

    def accept_standard_popup(self):
        alert_obj = self.driver.switch_to.alert
        time.sleep(4)
        alert_obj.accept()