#!/user/bin/env python
# encoding: utf-8
"""
@author: zwnong
@project: HogwartsSDE17
@file: base_page.py
@time: 2021/3/9 21:52
"""
import os
from time import sleep

import yaml
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.webdriver import WebDriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.wait import WebDriverWait
from decorator.handle_black_list import handle_black
from utils.get_file import GetFile
from utils.logger import log

class BasePage:
    def __init__(self, driver: WebDriver = None):
        self.driver = driver

    @handle_black
    def find(self, locator, element):
        """
        重构查找元素
        :param locator: 定位方式
        :param element: 元素信息
        :return:
        """
        # appium_log.debug('find' + element)
        return WebDriverWait(self.driver, 10, 0.1).until(lambda x: x.find_element(locator, element))
        # return self.driver.find_element(locator, element)
        # black_list = ['//android.widget.TextView[@resource-id="com.xueqiu.android:id/tv_agree" and @text="同意"]',
        #               '//android.widget.TextView[@resource-id="com.xueqiu.android:id/tv_left" and @text="取消"]']
        # try:
        #     return self.driver.find_element(locator, element)
        # except Exception:
        #         for i in black_list:
        #             ele_path = self.finds(locator, i)
        #             if len(ele_path) > 0:
        #                 ele_path[0].click()
        #         return self.find(locator, element)
        # black_list = ['//android.widget.TextView[@resource-id="com.xueqiu.android:id/tv_agree" and @text="同意"]',
        #               '//android.widget.TextView[@resource-id="com.xueqiu.android:id/tv_left" and @text="取消"]']
        # try:
        #     return self.driver.find_element(locator, element)
        # except Exception:
        #     for i in black_list:
        #         ele_path = self.finds(locator, i)
        #         if len(ele_path) > 0:
        #             ele_path[0].click()
        #             return self.find(locator, element)

    def find_and_click(self, locator, element):
        """
        重构查找元素并点击
        :param locator: 定位方式
        :param element: 元素信息
        :return:
        """
        self.find(locator, element).click()

    def find_and_sendkeys(self, locator, element, value):
        return self.find(locator, element).send_keys(value)

    def finds(self, locator, value):
        return self.driver.find_elements(locator, value)

    def web_driver_wait(self, locator, value):
        return WebDriverWait(self.driver, 10, 0.1).until(lambda x: x.find_element(locator, value))

    # def get_yaml_data(self, file_path=None, value=None):
    #     if file_path is None:
    #         self.file_path = r'../config\data.yaml'
    #     else:
    #         self.file_path = file_path
    #     data = yaml.safe_load(open(str(self.file_path), 'r', encoding='utf-8'))
    #     try:
    #         value = data.get()
    #     except EOFError:
    #         value = None
    #     return value

    def lunch_driver(self):
        self.driver.launch_app()

    # 获取屏幕的宽高
    def get_size(self):
        size = self.driver.get_window_size()
        width = size['width']
        height = size['height']
        return width, height

    # 向左边滑动
    def swipe_left(self):
        # [100,200]
        x1 = self.get_size()[0] / 10 * 9
        y1 = self.get_size()[1] / 2
        x = self.get_size()[0] / 10
        self.driver.swipe(x1, y1, x, y1, 2000)

    # 向右边滑动
    def swipe_right(self):
        # [100,200]
        x1 = self.get_size()[0] / 10
        y1 = self.get_size()[1] / 2
        x = self.get_size()[0] / 10 * 9
        self.driver.swipe(x1, y1, x, y1, 2000)

    # 向上滑动
    def swipe_up(self):
        # [100,200]direction
        x1 = self.get_size()[0] / 2
        y1 = self.get_size()[1] / 10 * 9
        y = self.get_size()[1] / 10
        self.driver.swipe(x1, y1, x1, y, 2000)

    # 向下滑动
    def swipe_down(self):
        x1 = self.get_size()[0] / 2
        y1 = self.get_size()[1] / 10
        y = self.get_size()[1] / 10 * 9
        self.driver.swipe(x1, y1, x1, y, 2000)

    def swipe_on(self, direction=None):
        if direction == 'up':
            self.swipe_up()
        elif direction == 'down':
            self.swipe_down()
        elif direction == 'left':
            self.swipe_left()
        else:
            self.swipe_right()

    @handle_black
    def swipe_find(self, function_name, num=10, file_path=None):
        """
        # 上下滑动查找元素
        :param file_path:
        :param function_name:
        :param num:
        :return:
        """
        if file_path is None:
            file_path = fr'{self.father_path()}\yaml\main_page.yml'
        else:
            file_path = file_path
        get_file = GetFile(file_path)
        elements = get_file.get_value(function_name)
        for element in elements:
            for i in range(num):
                if i == num - 1:
                    self.driver.implicitly_wait(5)
                    raise NoSuchElementException(f'滑动{num}次，没找到元素')

                self.driver.implicitly_wait(1)
                try:
                    # 查找元素并点击
                    # return self.find_and_click(MobileBy.XPATH,element.get('element'))
                    return self.driver.find_element(MobileBy.XPATH, element.get('element')).click()

                    # 仅返元素是否为真
                    # element = self.driver.find_element(MobileBy.XPATH, element.get('element'))
                    # self.driver.implicitly_wait(5)
                    # return element
                except Exception:
                    self.swipe_up()

    def parse(self, yaml_path, fun_name):
        """
        # 解析关键字 解析yaml文件并调用相应的方法 实现相应功能
        :param yaml_path: yaml文件路径
        :param fun_name: yaml文件定义的方法名
        :return:
        """
        with open(yaml_path, 'r', encoding='utf-8') as f:
            functance = yaml.load(f)
        steps = functance.get(fun_name)
        for step in steps:
            if step.get('action') == 'find_and_click':
                self.find_and_click(step.get('locator'), step.get('element'))
            elif step.get('action') == 'find_and_sendkeys':
                self.find_and_sendkeys(step.get('locator'), step.get('element'), step.get('contents'))

    def screenshot(self):
        return self.driver.get_screenshot_as_png()

    def get_web_view(shelf, driver):
        webview = driver.contexts
        for viw in webview:
            if 'WEBVIEW_cn.com.open.mooc' in viw:
                driver.switch_to.context(viw)
                break
        driver.find_element_by_link_text('C').click()
        try:
            driver.find_element_by_id('cn.com.open.mooc:id/left_icon').click()
        except Exception as e:
            driver.switch_to.context(webview[0])
            driver.find_element_by_id('cn.com.open.mooc:id/left_icon').click()
            raise e

    def pwd_path(self):
        return os.getcwd()

    def father_path(self):
        father_path = os.path.abspath(os.path.dirname(self.pwd_path()) + os.path.sep + ".")
        return father_path

    def grader_father_path(self):
        grader_father_path = os.path.abspath(os.path.dirname(self.pwd_path()) + os.path.sep + "..")
        return grader_father_path

    def get_yml_value(self, file_path, *args):
        return GetFile(file_path=file_path).get_value(args)

    def isElement(self, locator, ele):
        """
        Determine whether elements exist
        Usage:
        isElement(By.XPATH,"//a")
        """
        sleep(1)
        flag = None
        try:
            if locator == "id":
                # self.driver.implicitly_wait(60)
                self.driver.find_element_by_id(ele)
            elif locator == "xpath":
                # self.driver.implicitly_wait(60)
                self.driver.find_element_by_xpath(ele)
            elif locator == "class":
                self.driver.find_element_by_class_name(ele)
            elif locator == "link text":
                self.driver.find_element_by_link_text(ele)
            elif locator == "partial link text":
                self.driver.find_element_by_partial_link_text(ele)
            elif locator == "name":
                self.driver.find_element_by_name(ele)
            elif locator == "tag name":
                self.driver.find_element_by_tag_name(ele)
            elif locator == "css selector":
                self.driver.find_element_by_css_selector(ele)
            flag = True
        except NoSuchElementException as e:
            flag = False
        finally:
            return flag


from Tkinter import *
import spidev, time
spi = spidev.SpiDev()
spi.open(0, 0)
def analog_read(channel):
    r = spi.xfer2([1, (8 + channel) << 4, 0])
    adc = ((r[1]&3) << 8) + r[2]
    return adc

class App:

    def __init__(self, master):
        self.master = master
        frame = Frame(master)
        frame.pack()
        label = Label(frame, text='ARUS (mA)', font=("Helvetica", 32))
        label.grid(row=0)
        self.reading_label = Label(frame, text='12.34', font=("Helvetica", 52))
        self.reading_label.grid(row=1)
        self.update_reading()

    def update_reading(self):
        adc_arus = analog_read(0)
        Vadc_arus = adc_arus * 3.3 / 1024
        R = 10 # Resistor sensor
        I_ukur = Vadc_arus/R # Rumus arus dalam ampere
        I_mili = I_ukur*1000 #ARumus arus dalam miliampere
        reading_str = "{:.2f}".format(I_mili)
        self.reading_label.configure(text=reading_str)
        self.master.after(500, self.update_reading)

root = Tk()
root.wm_title('Amperemeter')
app = App(root)
root.geometry("400x300+0+0")
root.mainloop()


import requests
import dateutil.parser
import time

from bs4 import BeautifulSoup
from datetime import datetime
from urllib.request import urlopen, Request
from urllib.parse import urlparse

####################################
######## NEWS SCRAPER UTILS ########
####################################

MONTH_DICT = {'Januari': 'January',
            'Februari': 'February',
            'Maret': 'March',
            'April': 'April',
            'Mei': 'May',
            'Juni': 'June',
            'Juli': 'July',
            'Agustus': 'August',
            'September': 'September',
            'Oktober': 'October',
            'November': 'November',
            'Desember': 'December'
            }

MONTH_ACR_DICT = {'Jan': 'Jan',
                'Feb': 'Feb',
                'Mar': 'Mar',
                'Apr': 'Apr',
                'Mei': 'May',
                'Jun': 'Jun',
                'Jul': 'Jul',
                'Agu': 'Aug',
                'Sep': 'Sep',
                'Okt': 'Oct',
                'Nov': 'Nov',
                'Des': 'Dec'
                }

USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)\
     AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36"

MAX_RETRIES = 20

def retrieve_date_year(url, html_tag, attribute, attribute_value):
    """
        Retrieve year from dates of content
    """

    assert isinstance(url, str), f"Argument required str, but a {type(url)} was given."

    headers = {
        'User-Agent': USER_AGENT
    }

    session = requests.Session()
    adapter = requests.adapters.HTTPAdapter(max_retries=MAX_RETRIES)

    session.mount('https://', adapter)
    session.mount('http://', adapter)

    # Get content from source
    content_request = session.get(url, headers=headers)

    soup = BeautifulSoup(content_request.content)

    date_text = soup.find(
        html_tag,
        {attribute: attribute_value}
    ).text

    # Parsed date if month is not acronym
    for month in MONTH_DICT.keys():
        if month in date_text:
            date_text = date_text.replace(month, MONTH_DICT[month])
        else:
            pass
    # Parsed date if month is an acronym
    for month in MONTH_ACR_DICT.keys():

        if month in date_text:
            date_text = date_text.replace(month, MONTH_ACR_DICT[month])
        else:
            pass

    date_year = dateutil.parser.parse(date_text, fuzzy=True).year

    return date_year

####################################
######## PDF SCRAPER UTILS ########
####################################

def datetime_to_str(date):
    if isinstance(date, datetime):
        return date.strftime("%m-%d")
    else:
        return date

def get_range(range_str):
    """
        Get page range from the 'Page' column
    """
    if isinstance(range_str, datetime):
        range_str = datetime_to_str(range_str)
    if "-" in range_str:
        nums = range_str.split("-")
        return (int(nums[0]), int(nums[1]))
    else:
        nums = range_str.split("to")
        return (int(nums[0]), int(nums[1]))

####################################
###### YOUTUBE SCRAPER UTILS ######
####################################

def youtube_links(links):
    links = links.split(",")

    if len(links) == 1:
        return ""
    else:
        return links[1]


import altair as alt
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

from shared import app, data_raw

state_choice = data_raw.state.unique()
state_choice.sort()

company_size_choice = data_raw.no_employees.unique()
company_size_choice.sort()

tab_company_support_content = dbc.Card(
    dbc.CardBody([
        dbc.Row([
            dbc.Col(dbc.FormGroup([
                dbc.Label('State'),
                dcc.Dropdown(
                    id='company-support-state-dropdown',
                    value=[],
                    multi=True,
                    options=[{'label': col, 'value': col} for col in state_choice]),
                dbc.FormText('The state or territory where the respondents live in'),
                html.Br(),
                dbc.Label('Company Size'),
                dcc.Dropdown(
                    id='company-support-company-size-dropdown',
                    value=[],
                    multi=True,
                    options=[{'label': col, 'value': col} for col in company_size_choice]),
                dbc.FormText('Size of the companies the respondents working for: "Small" (0 - 100 employees), "Medium" (100 - 1000 employees), and "Large" (more than 1000 employees)'),
                html.Br(),
                dbc.Label('Tech Company'),
                dbc.RadioItems(
                    id='company-support-tech-company-radioitems',
                    options=[
                        {'label': 'All', 'value': 'All'},
                        {'label': 'Yes', 'value': 'Yes'},
                        {'label': 'No', 'value': 'No'}
                    ],
                    inline=True,
                    value='All'
                ),
                dbc.FormText('Are the respondents\' companies primarily tech companies or organizations?'),
                html.Br(),
                dbc.Label('Remote Work'),
                dbc.RadioItems(
                    id='company-support-remote-work-radioitems',
                    options=[
                        {'label': 'All', 'value': 'All'},
                        {'label': 'Yes', 'value': 'Yes'},
                        {'label': 'No', 'value': 'No'}
                    ],
                    inline=True,
                    value='All'
                ),
                dbc.FormText('Are the respondents\' work remotely (outside of an office) at least 50% of the time?')
            ]), md=2, align='baseline'),
            dbc.Col(dcc.Loading(
                id='company-support-loading',
                type='default',
                children=dbc.Col([
                    html.Iframe(id='iframe-company-support',
                                style={'border-width': '0', 'width': '100%', 'height': '90vh'}),
                    dbc.Col([
                        html.Hr(),
                        dbc.Card([
                        dbc.CardHeader('Full description of question labels:'),
                        dbc.CardBody(
                            dbc.Table([
                                html.Thead(html.Tr([html.Th('Label'), html.Th('Full Description')])),
                                html.Tr([html.Td('Anonymity'), html.Td('Is your anonymity protected if you choose to take '
                                                                    'advantage of mental health or substance abuse '
                                                                    'treatment resources?')]),
                                html.Tr(
                                    [html.Td('Benefits'), html.Td('Does your employer provide mental health benefits?')]),
                                html.Tr([html.Td('Mental vs physical'), html.Td('Do you feel that your employer takes '
                                                                                'mental health as seriously as physical '
                                                                                'health?')]),
                                html.Tr([html.Td('Resources'), html.Td(
                                    'Does your employer provide resources to learn more about mental health issues and how '
                                    'to seek help?')]),
                                html.Tr([html.Td('Wellness program'), html.Td(
                                    'Has your employer ever discussed mental health as part of an employee wellness '
                                    'program?')]),
                                html.Tr([html.Td('Coworkers'), html.Td('Would you be willing to discuss a mental health '
                                                                    'issue with your coworkers?')]),
                                html.Tr([html.Td('Supervisors'), html.Td('Would you be willing to discuss a mental health '
                                                                        'issue with your direct supervisor(s)?')])
                            ], bordered=False, dark=False, responsive=True, striped=True, size='sm'),
                            style={'width':'100%'}
                        )])],
                        md=12, align='center'),
                ], md=12, align='center')
            ), align='center')
        ])
    ]),
    className='mt-3')

# Set up callbacks/backend
@app.callback(
    Output('iframe-company-support', 'srcDoc'),
    Input('company-support-state-dropdown', 'value'),
    Input('company-support-company-size-dropdown', 'value'),
    Input('company-support-tech-company-radioitems', 'value'),
    Input('company-support-remote-work-radioitems', 'value'))
def plot_general_overview(state, company_size, is_tech, is_remote_work):
    """
    Callback function to be responsible for refreshing the dashboard. This function will read in the latest parameters,
    apply appropriate filters and generate plots

    :param state: States in the US that should be included in the result
    :param company_size: Company size that should be included in the result
    :param is_tech: Are the companies traditional tech companies?
    :param is_remote_work: Are the companies allow remote work?
    :return: The rendered html of the dashboard
    """
    data = data_raw

    if len(state) != 0:
        data = data.query('state == @state')

    if len(company_size) != 0:
        data = data.query('no_employees == @company_size')

    if is_tech.lower() != 'all':
        data = data.query('tech_company == @is_tech')

    if is_remote_work.lower() != 'all':
        data = data.query('remote_work == @is_remote_work')

    # melt dataframe for questions plot
    df_melted = data[['benefits', 'wellness_program', 'seek_help', 'anonymity', 'mental_vs_physical']] \
        .melt(var_name='Question',
              value_name='Answer')

    # replace question names
    df_melted = df_melted.replace({'benefits': 'Benefits', 'anonymity': 'Anonymity',
                                   'seek_help': 'Resources', 'wellness_program': 'Wellness program',
                                   'mental_vs_physical': 'Mental vs physical'})

    # question plot
    plot_question = alt.Chart(df_melted, title='Survey Questions (refer to detailed questions below)').mark_bar().encode(
        x=alt.X('count()', stack='normalize', axis=alt.Axis(format='%')),
        y=alt.Y('Question'),
        color=alt.Color('Answer', scale=alt.Scale(scheme='blues')),
        tooltip=[alt.Tooltip('count()', title='Respondent count')]
    ).properties(height=250, width=425,
                title={
                "text": ["Survey Questions"],
                "subtitle": ["(refer to detailed questions below)"],
                "color": "Black",
                "subtitleColor": "Grey"}
                )

    # boxplot
    plot_box = alt.Chart(data).mark_boxplot(size=50).encode(
        alt.X('mental_health_consequence', title=' '),
        alt.Y('Age'),
        alt.Color('Gender', scale=alt.Scale(scheme='tableau10'), legend=None)
    ).properties(
        height=300,
        width=305
    ).facet(facet='Gender',
            title='Do employees feel that there might be consequences discussing mental health conditions?')

    # heatmap plot
    plot_heat = alt.Chart(data, title=['Discussing with', 'Coworkers & Supervisors']).mark_rect().encode(
        x=alt.X('supervisor', title='Supervisors'),
        y=alt.Y('coworkers', sort='-y', title='Coworkers'),
        color=alt.Color('count()', legend=alt.Legend(title='Count'), scale=alt.Scale(scheme='greenblue')),
        tooltip=[alt.Tooltip('count()', title='Respondent count')]
    ).properties(height=250, width=220)

    return (plot_box & (plot_question|plot_heat)) \
        .resolve_scale(color ='independent') \
        .configure_axisX(labelAngle=360) \
        .configure_legend(titleFontSize=15,labelFontSize=13, gradientLength=100, gradientThickness=20)\
        .configure_title(fontSize=18, anchor='middle') \
        .configure_axis(labelFontSize=13,titleFontSize=13) \
        .to_html()


import os
import json
import pytest
import gzip
import numpy as np
from panqec.error_models import PauliErrorModel
from panqec.codes import Toric2DCode
from panqec.decoders import BeliefPropagationOSDDecoder
from panqec.simulation import (
    read_input_json, run_once, DirectSimulation, expand_input_ranges, run_file,
    BatchSimulation
)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, 'data')

@pytest.fixture
def required_fields():
    return [
        'effective_error', 'success'
    ]

@pytest.mark.parametrize(
    'file_name, expected_runs',
    [
        ('single_input.json', 1),
        ('range_input.json', 27),
        ('single_input.json.gz', 1),
        ('range_input.json.gz', 27),
    ]
)
def test_read_json_input(file_name, expected_runs):
    input_json = os.path.join(DATA_DIR, file_name)
    output_json = os.path.join(DATA_DIR, 'results.json')
    batch_simulation = read_input_json(input_json, output_json)
    assert batch_simulation is not None
    assert len(batch_simulation._simulations) == expected_runs
    parameters = [
        {
            'code': list(s.code.size),
            'error_model': s.error_model.direction,
            'error_rate': s.error_rate
        }
        for s in batch_simulation._simulations
    ]
    for i in range(len(parameters)):
        for j in range(len(parameters)):
            if i != j:
                assert parameters[i] != parameters[j]

class TestRunOnce:
    @pytest.fixture
    def code(self):
        return Toric2DCode(3, 3)

    @pytest.fixture
    def error_model(self):
        return PauliErrorModel(1/3, 1/3, 1/3)

    def test_run_once(self, required_fields, code, error_model):
        error_rate = 0.5
        decoder = BeliefPropagationOSDDecoder(code, error_model, error_rate)
        results = run_once(
            code, error_model, decoder, error_rate=error_rate
        )
        assert set(required_fields).issubset(results.keys())
        assert results['error'].shape == (2*code.n,)
        assert results['syndrome'].shape == (code.stabilizer_matrix.shape[0],)
        assert isinstance(results['success'], bool)
        assert results['effective_error'].shape == (
            2*code.logicals_x.shape[0],
        )
        assert isinstance(results['codespace'], bool)

    def test_run_once_invalid_probability(self, code, error_model):
        error_rate = -1
        decoder = BeliefPropagationOSDDecoder(
            code, error_model, error_rate=error_rate
        )
        with pytest.raises(ValueError):
            run_once(code, error_model, decoder, error_rate=error_rate)

class TestSimulationToric2DCode():

    error_rate = 0.5

    @pytest.fixture
    def code(self):
        return Toric2DCode(3, 3)

    @pytest.fixture
    def decoder(self, code, error_model):
        return BeliefPropagationOSDDecoder(code, error_model, self.error_rate)

    @pytest.fixture
    def error_model(self):
        direction = np.ones(3)/3
        return PauliErrorModel(*direction)

    def test_run(self, code, error_model, decoder, required_fields):
        error_rate = 0.5
        simulation = DirectSimulation(code, error_model, decoder, error_rate)
        simulation.run(10)
        assert len(simulation._results['success']) == 10
        assert set(required_fields).issubset(simulation._results.keys())

class TestBatchSimulationOneFile():

    n_trials: int = 5

    @pytest.fixture
    def output_file(self, tmpdir):
        out_file = os.path.join(tmpdir, 'results.json.gz')

        batch_sim = BatchSimulation(
            label='mylabel',
            save_frequency=1,
            output_file=out_file,
        )

        for size, error_rate in [(3, 0.1), (4, 0.5)]:
            code = Toric2DCode(size, size)
            error_model = PauliErrorModel(1/3, 1/3, 1/3)
            decoder = BeliefPropagationOSDDecoder(
                code, error_model, error_rate
            )
            simulation = DirectSimulation(
                code, error_model, decoder, error_rate
            )
            batch_sim.append(simulation)

        assert len(batch_sim) == 2

        batch_sim.run(self.n_trials)
        batch_sim.save_results()

        return out_file

    def test_output_to_one_file(self, output_file):
        assert os.path.isfile(output_file)

        with gzip.open(output_file, 'rb') as gz:
            results = json.loads(gz.read().decode('utf-8'))

        # Check integrity of results.
        assert len(results) == 2
        expected_input_keys = [
            'code', 'error_model', 'decoder',
            'error_rate', 'method'
        ]
        expected_results_keys = [
            'effective_error', 'success', 'codespace', 'wall_time',
        ]
        for key in expected_input_keys:
            assert key in results[0]['inputs']
            assert key in results[1]['inputs']

        for key in expected_results_keys:
            assert key in results[0]['results']
            assert key in results[1]['results']

        # Numerical tests on the results.
        assert len(results[0]['results']['effective_error']) == self.n_trials
        assert len(results[0]['results']['success']) == self.n_trials
        assert len(results[0]['results']['codespace']) == self.n_trials

@pytest.fixture
def example_ranges():
    input_json = os.path.join(DATA_DIR, 'range_input.json')
    with open(input_json) as f:
        data = json.load(f)
    return data['ranges']

def test_expand_inputs_ranges(example_ranges):
    ranges = example_ranges
    expanded_inputs = expand_input_ranges(ranges)
    assert len(expanded_inputs) == 27

def test_run_file_range_input(tmpdir):
    input_json = os.path.join(DATA_DIR, 'range_input.json')
    output_json = os.path.join(tmpdir, 'results', 'results.json')
    n_trials = 2
    run_file(input_json, output_json, n_trials)

    assert os.path.isfile(output_json)

class TestReadInputJson:

    def test_multiple_ranges(self):
        input_json = os.path.join(DATA_DIR, 'toric_input.json')
        output_json = os.path.join(DATA_DIR, 'toric_output.json')

        batch_sim = read_input_json(input_json, output_json)
        assert len(batch_sim) == 126


import requests
import logging
import json
from datetime import datetime

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)

def publish_to_zenodo(zenodo_url, recid, token, files, version = None):
    ''' Publish files to zenodo repository.

    :param zenodo_url: "https://sandbox.zenodo.org/api" or "https://zenodo.org/api"
    :param doi: the destination record id, such as 541234
    :param token: the access token to write to zenodo repository
    :param files: a list of filename and content pair to upload.
    :param version: the new version string, such as 1.0.1, or 2021.09.20
    '''
    headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"}
    params = {'access_token': token}

    logger.info(f'start uploading and publishing to zenodo for record {recid}')
    logger.info(f'\tto the zenodo url {zenodo_url}')
    # first, check the status of this repository
    r = requests.get(f'{zenodo_url}/deposit/depositions/{recid}', headers=headers)
    if not r.ok:
        raise r.raise_for_status()

    rj_links = r.json()['links']
    draft_url =  rj_links.get('latest_draft', None)
    if not draft_url:
        # switch to the latest version
        latest_url = rj_links['latest']
        latest_doi = get_doi_from_record_link(latest_url, zenodo_url)
        r = requests.get(f'{zenodo_url}/deposit/depositions/{latest_doi}', headers=headers)
        if not r.ok:
            raise r.raise_for_status()
        rj_links = r.json()['links']
        # create draft from the latest version
        draft_url = create_new_draft(rj_links['newversion'], params)
    # switch to draft
    logger.info('\tchange to draft version')
    r = requests.get(draft_url, headers=headers)
    if not r.ok:
        raise r.raise_for_status()
    rj = r.json()
    rj_files = rj['files']
    metadata = rj['metadata']

    # delete all the old files!
    logger.info('\tdelete old files from draft')
    for f in rj_files:
        of_id = f['id']
        of_url = f'{draft_url}/files/{of_id}'
        print ( f'deleting old file: {of_url}' )
        r = requests.delete(of_url, params=params)
        if not r.ok:
            raise r.raise_for_status()

    # upload new files
    logger.info('\tupload new files')
    draft_files = f'{draft_url}/files'
    upload_url = f'{draft_files}?access_token={token}'
    for nf in files:
        data = {'name': nf['filename']}
        r = requests.post(upload_url, data=data, files={'file': nf['content']})
        if not r.ok:
            raise r.raise_for_status()

    # update the new version in metadata
    if version:
        metadata['version'] = version
        r = requests.put( draft_url, headers=headers, data = json.dumps({'metadata': metadata}) )
        if not r.ok:
            raise r.raise_for_status()

    # publish
    logger.info('\tstart publishing')
    r = requests.post(f'{draft_url}/actions/publish', headers=headers)
    if not r.ok:
        raise r.raise_for_status()
    logger.info('Publish successfully!')

def get_doi_from_record_link(rec_url, zenodo_url):
    # get '917028' from 'https://sandbox.zenodo.org/api/records/917028'
    return rec_url[len(zenodo_url) + len('/records/'):]

def create_new_draft(nv_url, params):
    logger.info('\tcreate a new draft version')
    r = requests.post(nv_url, params=params)
    if not r.ok:
        raise r.raise_for_status()
    return r.json()['links']['latest_draft']


import pandas as pd
import seaborn as sns
import numpy as np
import streamlit as st
import matplotlib.pyplot as plt

st.title("Analyse de l'évolution des performances mécanique par continent")

df = pd.read_csv('https://raw.githubusercontent.com/murpi/wilddata/master/quests/cars.csv')

# supprimer '.' et espaces de la colonne continent
df.continent = df.continent.apply(lambda x: x.replace(' ', '').replace('.', ''))

st.subheader('Heatmap')

# display heatmap
plt.figure(figsize = (20, 10))
viz_correlation = sns.heatmap(df.corr(), center = 0, cmap = "vlag", annot=True, vmin = -1, vmax = 1, mask = np.triu(np.ones_like(df.corr())))

st.pyplot(viz_correlation.figure)

st.subheader('Analyse de la corrélation')
st.markdown("On constate qu'entre 1971 et 1983, il n'y a pas de corrélation significative concernant l'évolution du nombre de cylindre, la puissance de la cylindré, la puissance du moteur (hp) et le time-to-60. Concretement, il n'y a aps d'évolution ordonnée de tous ces paramètres entre 1971 et 1983 En revanche (toutes années confondues), il y a une corrélation, positive, forte, évidente entre le poids, la puissance du moteur et la cylindré.")

continent = st.multiselect(label = 'Choisi un continent', options = ['Europe', 'US', 'Japan'])

if len(continent) == 0:
  print()
else:
  df_continent = df.loc[((df.continent.isin(continent)))]

  st.subheader(', '.join(continent))

  # pivot table for mean by hp evolution
  pt = pd.pivot_table(df_continent, index = 'year', values = 'hp', aggfunc = 'mean')
  pt['year'] = pt.index

  # Evolution de la puissance moyenne du moteur
  sns.set()
  plt.figure(figsize = (20, 10))
  plt.title('Evolution de la puissance moyenne du moteur', size = 20)
  viz = sns.barplot(data = pt, x = pt.year, y = pt.hp, color = "steelblue")

  st.pyplot(viz.figure)

  st.subheader(' '.join(continent))

  # pivot table for mean by cubicinches evolution
  pt_1 = pd.pivot_table(df_continent, index = 'year', values = 'cubicinches', aggfunc = 'mean')
  pt_1['year'] = pt.index

  # Evolution de la cylindré moyenne
  sns.set()
  plt.figure(figsize = (20, 10))
  plt.title('Evolution de la cylindré moyenne', size = 20)
  viz_1 = sns.barplot(data = pt_1, x = pt_1.year, y = pt_1.cubicinches, color = "steelblue")

  st.pyplot(viz_1.figure)

  st.subheader(' '.join(continent))

  # pivot table for mean by weightlbs evolution
  pt_2 = pd.pivot_table(df_continent, index = 'year', values = 'weightlbs', aggfunc = 'mean')
  pt_2['year'] = pt.index

  # Evolution du poids moyen
  sns.set()
  plt.figure(figsize = (20, 10))
  plt.title('Evolution du poids moyen', size = 20)
  viz_2 = sns.barplot(data = pt_2, x = pt_2.year, y = pt_2.weightlbs, color = "steelblue")

  st.pyplot(viz_2.figure)

  st.subheader(' '.join(continent))

  # pivot table for mean by time-to-60 evolution
  pt_3 = pd.pivot_table(df_continent, index = 'year', values = 'time-to-60', aggfunc = 'mean')
  pt_3['year'] = pt.index

  # Evolution du time to 60 moyen
  sns.set()
  plt.figure(figsize = (20, 10))
  plt.title('Evolution du time to 60 moyen', size = 20)
  viz_3 = sns.barplot(data = pt_3, x = pt_3.year, y = pt_3['time-to-60'], color = "steelblue")

  st.pyplot(viz_3.figure)


from django.contrib import admin

# Register your models here.
from .models import UserProfile

class UserProfileAdmin(admin.ModelAdmin):
    list_display = ("user",
                    "organisation_name",
                    "timestamp",)
    list_filter = ("user",
                   "organisation_name",
                   )
    search_fields = ('organisation_name',)

admin.site.register(UserProfile, UserProfileAdmin)


from flet import AlertDialog, TextButton, RoundedRectangleBorder, MainAxisAlignment, Text

class ConfirmDialog(AlertDialog):
    """Creates an AlertDialog that, if "yes" clicked, executes the function passed as a parameter.

    Args:
        function (method): method to be executed
        title (string): title of the dialog
        content (string): content of the question to be confirmed
    """
    def __init__(self, function, title="", content=""):
        super().__init__()
        self.function = function

        self.modal=True
        self.title=Text(title)
        self.content=Text(content)
        self.actions=[
            TextButton("Não", on_click=self.canceled),
            TextButton(content=Text("Sim", color="red"), on_click=self.confirmed),
        ]
        self.actions_alignment=MainAxisAlignment.END
        self.shape=RoundedRectangleBorder(radius=10)

    def build(self):
        return self

    def confirmed(self, e):
        self.open = False
        self.update()
        self.function(self.data)

    def canceled(self, e):
        self.open = False
        self.update()


import torch
import numpy as np
import scipy.io as scio
from ..builder import DATASETS

from .utils import TimeSeriesShiftAugmentation

# import external modules
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))),
                             'external'))

from SRU_for_GCI.utils.utilFuncs import loadTrainingData, loadTrueNetwork

@DATASETS.register_module()
class Dream3(torch.utils.data.Dataset):
    def __init__(
        self,
        data_root=None,
        max_length=1000,
        percentage=1.0,
        shift_range=None,
    ):
        # Set all input args as attributes
        self.__dict__.update(locals())
        self.subject = self.data_root[0].split("/")[-1].strip(".pt")
        self.check_files()
        if shift_range is not None:
            self.transform = TimeSeriesShiftAugmentation(shift_range)

    def check_files(self):
        # if isinstance(self.percentage, float):
        #     self.percentage = [0, self.percentage]

        if self.data_root is None or len(self.data_root) != 2:
            raise Exception("Invalid dataset path, should be a tuple of (seq_path, net_path)")

        # data_root = (seq_path, net_path)
        Xtrain = loadTrainingData(self.data_root[0], 'cpu')

        self.seqs = Xtrain
        n, l = Xtrain.shape
        Gref = loadTrueNetwork(self.data_root[1], n).T

        # Load data
        # duration = 21
        # self.examples = []
        # for i in range(n):
        #     for j in range(n):
        #         # skip the diag elements
        #         if i == j:
        #             continue
        #         # parse it into 46 snippets of sequences (the length of each one is 21 )
        #         for start in range(0, l, duration):
        #             self.examples.append(
        #                 {
        #                     "cause": i,
        #                     "effect": j,
        #                     "start_index": start,
        #                     "end_index": start + duration,
        #                     "label": 1 if Gref[i, j] != 0 else 0,
        #                 }
        #             )

        # percentage
        # self.examples = self.examples[int(len(self.examples) * self.percentage[0]):int(len(self.examples) * self.percentage[1])]

        self.examples = []
        for i in range(n):
            for j in range(n):
                # skip the diag elements
                if i == j:
                    continue
                self.examples.append(
                    {
                        "cause": i,
                        "effect": j,
                        "label": 1 if Gref[i, j] != 0 else 0,
                    }
                )

    def __getitem__(self, idx):
        example = self.examples[idx]
        seq = np.stack(
            [
                self.seqs[
                example["cause"]
                ],
                self.seqs[
                example["effect"]
                ],
            ],
            axis=-1,
        )
        seq = torch.tensor(seq, dtype=torch.float32)

        if hasattr(self, "transform"):
            seq = self.transform(seq)

        label = torch.tensor(example["label"], dtype=torch.int64)
        return seq, label

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


"""Can Driver tests."""
from typing import AsyncGenerator

import pytest
from can import Bus, Message

from opentrons_shared_data.errors.exceptions import CANBusBusError
from opentrons_hardware.drivers.can_bus import CanDriver, ArbitrationId, CanMessage

@pytest.fixture
def bus_channel() -> str:
    """The virtual can bus channel."""
    return "test_channel"

@pytest.mark.slow
@pytest.fixture
def can_bus(bus_channel: str) -> Bus:
    """A virtual can bus fixture."""
    bus = Bus(bus_channel, interface="virtual")
    yield bus
    bus.shutdown()

@pytest.fixture
async def subject(bus_channel: str) -> AsyncGenerator[CanDriver, None]:
    """The can driver under test."""
    driver = await CanDriver.build(channel=bus_channel, interface="virtual", bitrate=0)
    yield driver
    driver.shutdown()

async def test_send(subject: CanDriver, can_bus: Bus) -> None:
    """It should send a message."""
    message = CanMessage(
        arbitration_id=ArbitrationId(id=0x1FFFFFFF), data=bytearray([1, 2, 3, 4])
    )
    await subject.send(message)

    recv = can_bus.recv()
    assert recv.data == bytearray([1, 2, 3, 4])
    assert recv.arbitration_id == 0x1FFFFFFF

async def test_receive(subject: CanDriver, can_bus: Bus) -> None:
    """It should receive a message."""
    m = Message(
        arbitration_id=0x1FFFFFFF,
        is_extended_id=True,
        is_fd=True,
        data=bytearray([1, 2, 3, 4]),
    )
    can_bus.send(m)
    recv = await subject.read()

    assert recv.data == bytearray([1, 2, 3, 4])
    assert recv.arbitration_id.id == 0x1FFFFFFF

async def test_receive_iter(subject: CanDriver, can_bus: Bus) -> None:
    """It should receive messages using iterator."""
    m = [
        Message(
            arbitration_id=0x1FFFFFFF,
            is_extended_id=True,
            is_fd=True,
            data=bytearray([1, 2, 3, 4]),
        ),
        Message(
            arbitration_id=0,
            is_extended_id=True,
            is_fd=True,
            data=bytearray([4, 3, 2, 1]),
        ),
    ]

    for message in m:
        can_bus.send(message)

    received = []
    async for recv in subject:
        received.append(recv)
        if len(received) == len(m):
            break

    assert received[0].data == bytearray([1, 2, 3, 4])
    assert received[0].arbitration_id.id == 0x1FFFFFFF
    assert received[1].data == bytearray([4, 3, 2, 1])
    assert received[1].arbitration_id.id == 0

async def test_raise_error_frame_error(subject: CanDriver, can_bus: Bus) -> None:
    """It should raise an error when an error frame is received."""
    m = Message(
        arbitration_id=0x1FFFFFFF,
        is_extended_id=True,
        is_error_frame=True,
        is_fd=True,
        data=bytearray([1, 2, 3, 4]),
    )
    can_bus.send(m)
    with pytest.raises(CANBusBusError):
        await subject.read()


import datetime
import sys

import discord
from discord.ext import commands
from sqlalchemy.exc import DBAPIError
from sqlalchemy.sql import func

from sweeperbot.cogs.utils import time
from sweeperbot.cogs.utils.timer import Timer
from sweeperbot.db import models
from sweeperbot.utilities.helpers import set_sentry_scope

class Reminder(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    def _remind(
        self, guild_id: int, remind_user_id: int, creator_user_id: int, remind_text: str
    ):

        try:
            guild = self.bot.get_guild(guild_id)
            if not guild:
                raise ValueError(f"Bot can't find guild {guild_id}")
            member = guild.get_member(remind_user_id)
            if not member:
                raise ValueError(
                    f"Bot can't find member {remind_user_id} in guild {guild} ({guild.id})"
                )
            creator_user = self.bot.get_user(creator_user_id)
        except ValueError:
            self.bot.log.exception(f"Can't execute reminder")
            raise

        settings = self.bot.guild_settings.get(member.guild.id)
        has_modmail_server = settings.modmail_server_id

        footer_text = (
            self.bot.constants.footer_with_modmail.format(guild=member.guild)
            if has_modmail_server
            else self.bot.constants.footer_no_modmail.format(guild=member.guild)
        )

        try:
            self.bot.loop.create_task(
                member.send(
                    f"Here is the reminder requested by **{creator_user}** from the **{guild}** server.\n\n'{remind_text}'{footer_text}"
                )
            )

            self.bot.log.info(
                f"Sent reminder to: {member} ({member.id}) in guild {member.guild}"
            )
        except Exception as e:
            if not (type(e) == discord.errors.Forbidden and e.code == 50007):
                self.bot.log.exception(
                    f"There was an error while informing {member} ({member.id}) about their reminder. Unable to send messages to this user."
                )
            return False

        return True

    @commands.has_permissions(manage_messages=True)
    @commands.guild_only()
    @commands.command()
    @commands.cooldown(3, 120, commands.BucketType.user)
    async def remind(
        self,
        ctx,
        remind_user: str,
        remind_time: time.UserFriendlyTime(commands.clean_content, default="\u2026"),
        *,
        remind_text: str,
    ):
        """Creates a reminder that the bot will remind you of. If the person creating the reminder has 'Manage Messages' permission then any user or role pings will be left alone. If they don't (aka regular user) then the user and role pings will be not be allowed.

        Things to figure out/do
        - Does it DM the user the reminder or put it in chat? What if it has a role mention, that we'd want in chat 'remind me in 1day There is a @moderators meeting'
        - Create a delete reminder command - use note delete as an example
        - Future: Allow it to recognize time in format of datestamp vs duration

        Requires Permission: Send Messages

        Parameters
        -----------
        ctx: context
            The context message involved.
        remind_user: str
            The user the reminder is for. For self can use 'me' or a user mention or user ID of someone else.
        remind_time: time
            When to be reminded. Format of 1m (minute), 2h (hours), 3d (days), 4mo (months), 5y (years)
        remind_text: str
            The text to be reminded of.
        """

        session = self.bot.helpers.get_db_session()
        try:
            self.bot.log.info(
                f"CMD {ctx.command} called by {ctx.message.author} ({ctx.message.author.id})"
            )
            # Check if user is blacklisted, if so, ignore.
            if await self.bot.helpers.check_if_blacklisted(
                ctx.message.author.id, ctx.message.guild.id
            ):
                self.bot.log.debug(
                    f"User {ctx.message.author} ({ctx.message.author.id}) Blacklisted, unable to use command {ctx.command}"
                )
                return

            # If we were provided an ID, let's try and use it
            if remind_user.lower() in ["me", "myself"]:
                remind_user = ctx.message.author
            else:
                remind_user = await self.bot.helpers.get_member_or_user(
                    remind_user, ctx.message.guild
                )
                if not remind_user:
                    return await ctx.send(
                        f"Sorry, I am unable to find the person you are trying to set the reminder for. Please make sure you are using a proper @ mention of the user or their User ID."
                    )

            # Variables used for the database/later on
            creator_user = ctx.message.author
            remind_time = remind_time.dt
            guild = ctx.message.guild

            # Save in the database
            # Get the DB profile for the guild
            db_guild = await self.bot.helpers.db_get_guild(session, guild.id)
            # Get the DB profile for the remind_user
            db_remind_user = await self.bot.helpers.db_get_user(session, remind_user.id)
            # DB Entry
            db_remind = models.Reminder(
                creator_user_id=ctx.message.author.id,
                remind_user=db_remind_user,
                server=db_guild,
                expires=remind_time,
                text=remind_text,
            )
            session.add(db_remind)
            session.commit()

            # Add timer to send the reminder
            timer = Timer.temporary(
                guild.id,
                remind_user.id,
                creator_user.id,
                remind_text,
                event=self._remind,
                expires=remind_time,
                created=datetime.datetime.now(datetime.timezone.utc),
            )
            timer.start(self.bot.loop)

            # Tell user reminder is created
            # TO DO - Make this look a little nicer.
            await ctx.send(
                f"{ctx.message.author.mention}, I have now created the reminder for {remind_user.mention}."
            )

        except discord.HTTPException as err:
            set_sentry_scope(ctx)
            self.bot.log.error(
                f"Discord HTTP Error responding to {ctx.command} request. {sys.exc_info()[0].__name__}: {err}"
            )
            await ctx.send(
                f"Error processing {ctx.command}. Error has already been reported to my developers."
            )
        except DBAPIError as err:
            set_sentry_scope(ctx)
            self.bot.log.exception(
                f"Error processing database query. {sys.exc_info()[0].__name__}: {err}"
            )
            await ctx.send(
                f"Error processing {ctx.command}. Error has already been reported to my developers."
            )
            session.rollback()
        except Exception as err:
            set_sentry_scope(ctx)
            self.bot.log.exception(
                f"Error responding to {ctx.command}. {sys.exc_info()[0].__name__}: {err}"
            )
            await ctx.send(
                f"Error processing {ctx.command}. Error has already been reported to my developers."
            )
        finally:
            session.close()

    @commands.has_permissions(send_messages=True)
    @commands.guild_only()
    @commands.command()
    async def reminders(self, ctx):
        """Sends you a DM with a list of all reminders for you."""

        session = self.bot.helpers.get_db_session()
        try:
            self.bot.log.info(
                f"CMD {ctx.command} called by {ctx.message.author} ({ctx.message.author.id})"
            )
            # Check if user is blacklisted, if so, ignore.
            if await self.bot.helpers.check_if_blacklisted(
                ctx.message.author.id, ctx.message.guild.id
            ):
                self.bot.log.debug(
                    f"User {ctx.message.author} ({ctx.message.author.id}) Blacklisted, unable to use command {ctx.command}"
                )
                return

            # Get the DB profile for the remind_user
            db_remind_user = await self.bot.helpers.db_get_user(
                session, ctx.message.author.id
            )

            reminders = (
                session.query(
                    func.coalesce(
                        models.Reminder.updated, models.Reminder.created
                    ).label("created"),
                    models.Reminder.id,
                    models.Reminder.creator_user_id,
                    models.Reminder.remind_user_id,
                    models.Server,
                    models.Reminder.expires,
                    models.Reminder.text,
                )
                .join(models.Server, models.Server.id == models.Reminder.server_id)
                .filter(
                    models.Reminder.expires
                    > datetime.datetime.now(datetime.timezone.utc),
                    models.Reminder.remind_user_id == db_remind_user.id,
                )
                .all()
            )

            # TO DO - Use pagination to accomplish this - look at tag list command for example
            msg_text = ""
            for item in reminders:
                msg_text += f"{item.id}. **Expires**: [{item.expires} UTC]\n**Reminder Text:** [{item.text}]\n"

            await ctx.message.author.send(
                f"Here's a list of your reminders:\n\n{msg_text if len(reminders) >0 else 'You do not have any reminders.'}"
            )
        except discord.HTTPException as err:
            set_sentry_scope(ctx)
            self.bot.log.error(
                f"Discord HTTP Error responding to {ctx.command}. {sys.exc_info()[0].__name__}: {err}"
            )
            await ctx.send(
                f"Error processing {ctx.command}. Error has already been reported to my developers."
            )
        except DBAPIError as err:
            set_sentry_scope(ctx)
            self.bot.log.exception(
                f"Error processing database query. {sys.exc_info()[0].__name__}: {err}"
            )
            await ctx.send(
                f"Error processing {ctx.command}. Error has already been reported to my developers."
            )
            session.rollback()
        except Exception as err:
            set_sentry_scope(ctx)
            self.bot.log.exception(
                f"Error responding to {ctx.command}. {sys.exc_info()[0].__name__}: {err}"
            )
            await ctx.send(
                f"Error processing {ctx.command}. Error has already been reported to my developers."
            )
        finally:
            session.close()

def setup(bot):
    bot.add_cog(Reminder(bot))


import pygame
from pygame.sprite import Sprite
from pygame.math import Vector2

class Boss(Sprite):
    """Класс, представляющий одного боса."""

    def __init__(self, ai_game):
        #"""Инициализирует боса и задает его начальную позицию."""
        super().__init__()
        self.screen = ai_game.screen
        self.screen_rect = ai_game.screen.get_rect()
        self.settings = ai_game.settings
        self.explois_sound = pygame.mixer.Sound('sounds/Explosion3.wav')
        # Загрузка изображения боса и назначение атрибута rect.
        self.image_norm = pygame.image.load('images/turrel2.bmp')
        self.image = self.image_norm.copy()
        self.image_explois = pygame.image.load('images/ship_destroy.bmp')
        self.is_explois = 0
        self.rect = self.image.get_rect()
        self.normal_center = self.rect.center
        # Каждый новый босс появляется в центре экрана.
        self.rect.x = self.screen_rect.centerx
        self.rect.y = self.screen_rect.centery
        # Уровень здоровья орудий
        self.boss_turrel_health = self.settings.boss_turrel_health_max
        self.turrel_health_color = self.settings.boss_turrel_health_color
        # Создание полосы здоровья в позиции (0,0) и назначение правильной позиции.
        self.turrel_health_rect = pygame.Rect(0, 0,
                                              self.settings.boss_turrel_health_width,
                                              self.settings.boss_turrel_health_height)
        self.rect_health_heigth = self.settings.boss_turrel_health_height
        self.rect_health_weigth = self.settings.boss_turrel_health_width
        # Сохранение точной горизонтальной позиции боса.
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)
        self.index_in_station = 0
        self.x_aim = ai_game.ship.rect.x
        self.y_aim = ai_game.ship.rect.y

    def check_edges(self):
        """Возвращает True, если босс находится у краев экрана."""
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right or self.rect.x <= 10:
            return True

    def _explois(self):
        """Отрисовываем взрыв"""
        rect_explois = self.image_explois.get_rect()
        rect_explois.center = (self.rect.width / 2, self.rect.height / 2)
        self.image.blit(self.image_explois, rect_explois)

    def update(self):
        #"""Перемещает боса вправо и вниз."""

        self.rect.x = int(self.x)
        self.rect.y = int(self.y)
        if self.is_explois >= 1:
            self._explois()
            self.is_explois += 1
            if self.is_explois >= self.settings.exlois_timer:
                self.boss_turrel_health -= self.settings.boss_turrel_bullet_damge
                if self.boss_turrel_health >= 0:
                    self.is_explois = 0
        else:
            self._rotate_to_ship()
        self._draw_turrel_health()

    def _draw_turrel_health(self):
        """Вывод уровня здоровья пушки на экран."""
        # Расчёт позиции жизни смерти
        kill_level = int(self.boss_turrel_health * self.rect_health_weigth / 100)
        boader = self.settings.boss_turrel_health_boader_thick
        # Параметры прямоугольника бара здороья
        rect_health = (int((self.rect.width / 2) - (self.rect_health_weigth / 2)),
                       int((self.rect.height / 2) - (self.rect_health_heigth / 2)),
                       self.rect_health_weigth,
                       self.rect_health_heigth)
        pygame.draw.rect(self.image, (254, 254, 254), (rect_health[0]-boader, rect_health[1]-boader, rect_health[2]+boader*2, rect_health[3]+boader*2))
        pygame.draw.rect(self.image, self.settings.boss_turrel_health_color, (rect_health[0], rect_health[1], kill_level, rect_health[3]))
        pygame.draw.rect(self.image, pygame.SRCALPHA, (rect_health[0] + kill_level, rect_health[1], rect_health[2], rect_health[3]))

    def draw_boss(self):
        """Вывод босса на экран."""
        self.screen.blit(self.image, self.rect)

    def _rotate_to_ship(self):
        """Вращает в сторону корабля"""
        #Вычисления угла между векторами в позицию башни и в позицию корабля
        turrel_ship_diff = pygame.Vector2(self.x_aim, self.y_aim) - pygame.Vector2(self.rect.center)
        radius, angle = pygame.math.Vector2.as_polar(turrel_ship_diff)
        # Сохранение позиции центра картинки
        self.rect = self.image.copy().get_rect()
        self.center = (int(self.x + self.rect.width / 2), int(self.y + self.rect.height / 2))
        # Поворот изображения
        self.image = self.rotate(self.image_norm, self.normal_center, 90 - angle)
        self.rect = self.image.get_rect()
        # Возвращение картинки в изначальный центр после поворота
        self.rect.center = self.center
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)

    def rotate(self, img, pos, angle):
        """Поворот изображения с предварительным увеличением в два раза"""
        w, h = img.get_size()
        img2 = pygame.Surface((w * 2, h * 2), pygame.SRCALPHA)
        img2.blit(img, (w - pos[0], h - pos[1]))
        return pygame.transform.rotate(img2, angle)


import requests
from bs4 import BeautifulSoup

class Parse_weather():
    def get_data(self):
        result = requests.get('https://yandex.ru/pogoda/saint-petersburg')
        self.soup = BeautifulSoup(result.text, 'html.parser')
        div = self.soup.findAll('div')
        soup = self.soup
        div = soup.find( 'div', {'class': 'content__row'} )
        place = div.find( 'h1', {'class': True} )
        temp = div.find( 'span', {'class': 'temp__value'} )
        status = div.find( 'div', {'class': 'link__condition day-anchor i-bem'} )
        feeling = div.find( 'div', {'class': 'term term_orient_h fact__feels-like'} ). \
            find( 'span', {'class': 'temp__value'} )
        wind_speed = div.find( 'span', {'class': 'wind-speed'} )
        wind_way = div.find( 'abbr', {'class': 'icon-abbr'} )
        humidity = div.find( 'div', {'class': 'term term_orient_v fact__humidity'} ). \
            find( 'div', {'class': 'term__value'} )

        pressure = div.find( 'div', {'class': 'term term_orient_v fact__pressure'} ). \
            find( 'div', {'class': 'term__value'} )

        reply = place.text + '\n' + \
                'Температура:' + temp.text + '°C' + '\n' + \
                'На улице:' + status.text + '\n' + \
                'Ощущается как: ' + feeling.text + '°C' + '\n' + \
                'Ветер: ' + wind_speed.text + ' м/с ' + wind_way.text + '\n' + \
                'Влажность: ' + humidity.text + '\n' + \
                'Давление: ' + pressure.text + '\n'
        return reply

answer = Parse_weather()
weather = answer.get_data()

print(weather)


import requests
import bs4

KEYWORDS = ['дизайн', 'фото', 'web', 'python', 'программирование']
HEADERS = {'Accept': 'text/html,application/xhtml+xml,'
                     'application/xml;q=0.9,image/avif,'
                     'image/webp,image/apng,'
                     '*/*;q=0.8,application/signed-exchange;'
                     'v=b3;q=0.9 ',
           'Accept-Encoding': 'gzip, deflate, br',
           'Accept-Language': 'ru-RU,ru;q=0.9,en-US;'
                              'q=0.8,en;q=0.7',
           'Cache-Control': 'max-age=0',
           'Connection': 'keep-alive',
           'Cookie':
               '_ym_uid=1639934666860889724; '
               '_ym_d=1639934666; '
               '_ga=GA1.2.122808168.1639934666; '
               '_gid=GA1.2.1540720803.1639934666; '
               'habr_web_home=ARTICLES_LIST_ALL; '
               'hl=ru; fl=ru; _ym_isad=2; '
               '__gads=ID=3bca2fb12a84bfaa:T=1639934668:'
               'S=ALNI_MagABWot_b98koFdCB4lM3aLC2RAA; '
               'cto_bundle'
               '=0wD_Y19KQmE2VSUyQmdwbFBWOGlDVGdGNlhL'
               'NnpDNEVUdGNKOWtQSlpHVjRXTXZqQVdoYkVkM'
               'kJDSGFHemd2OHhFY1lLT0g1UVlweEZYOWlBTmR'
               'GaGdlaW4zOEhCQlI1RWVNcEJEUjJHRWdjVTRFN'
               'mx3bmxhcnFMODlSWCUyRkdETmpOUnloWHZGQU1'
               'CV2hNV2duOG03aUNHcEpPTFhXS2dWRGFkMVNyT'
               'Tlyb1pwZ3psVlZ1b0ZyJTJCcVlEcFN3VEx3eE'
               'NCbEpEZ3o ',
           'Host': 'habr.com',
           'If-None-Match': 'W/"3a406-HWoKTAp/3V+g6gWQdD8MLds+0Ns"',
           'sec-ch-ua': '" Not A;Brand";v="99", '
                        '"Chromium";v="96", "Google Chrome";v="96"',
           'sec-ch-ua-mobile': '?0',
           'sec-ch-ua-platform': "macOS",
           'Sec-Fetch-Dest': 'document',
           'Sec-Fetch-Mode': 'navigate',
           'Sec-Fetch-Site': 'same-origin',
           'Sec-Fetch-User': '?1',
           'Upgrade-Insecure-Requests': '1',
           'User-Agent':
               'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) '
               'AppleWebKit/537.36 (KHTML, like Gecko) '
               'Chrome/96.0.4664.110 Safari/537.36 '
           }

response = requests.get('https://habr.com/ru/all/', headers=HEADERS)
response.raise_for_status()
text = response.text

soup = bs4.BeautifulSoup(text, features='html.parser')
articles = soup.find_all('article')
print(len(articles))

for article in articles:
    hubs = article.find_all('a', class_="tm-article-snippet__hubs-item-link")
    hubs = [hub.find('span').text for hub in hubs]
    # print(hubs)
    title = article.find('a', class_="tm-article-snippet__title-link").text
    # print(title)
    link = article.find('a', class_="tm-article-snippet__title-link").\
        get('href')
    # print(link)
    article_preview = article.find('div', class_='article-formatted-body').text
    # print(article_preview)
    date = article.find('span',
                        class_='tm-article-snippet__datetime-published')
    datetime = date.find('time')['title']
    # print(datetime)

    for word in KEYWORDS:
        if (word.lower() in title.lower()) \
                or (word.lower() in article_preview.lower()) \
                or (word.capitalize() in hubs):
            print(f'Дата: {datetime} - Заголовок: {title} '
                  f'- Ссылка: {"habr.com" + link}')


import requests
from html import unescape
from question_model import Question

# Option 1
# question_data = requests.get("https://opentdb.com/api.php?amount=10&type=boolean")

def extract_questions():
    parameter = {
        "amount": 10,
        "type": "boolean"
    }
    question_data = requests.get("https://opentdb.com/api.php", params=parameter)
    question_data.raise_for_status()
    questions = question_data.json()
    return questions["results"]

def generate_questions():
    raw_questions = extract_questions()

    question_bank = []
    for question in raw_questions:
        question_text = question["question"]
        question_answer = question["correct_answer"]
        new_question = Question(unescape(question_text), unescape(question_answer))
        question_bank.append(new_question)
    return question_bank


# Импортируем необходимые компоненты
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
from settings import TG_TOKEN
from handlers import *
import logging

logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s',
                    level=logging.INFO,
                    filename='bot.log')

# Создаем (объявляем) функцию main, которая соединяется с платформой Telegram
def main():
    my_bot = Updater(TG_TOKEN, use_context=True)
    logging.info('Start bot')
    my_bot.dispatcher.add_handler(CommandHandler('start', sms))    # обработчик команды \start

    my_bot.dispatcher.add_handler(MessageHandler(Filters.text, parrot))    # обработчик тектового сообщения

    my_bot.start_polling()  # проверяет о наличии сообщений с платформы Telegram
    my_bot.idle()   # бот будет работать по его не остановят

if __name__ == '__main__':
    main()


import codecs
import sys

import xml.etree.ElementTree as ET

from bs4 import BeautifulSoup, Tag

weeks = [int(w) for w in sys.argv[1:]]

file = codecs.open("./temp/index.html", "r", "utf-8")
soup = BeautifulSoup(file.read(), 'html.parser')
accordianfile = codecs.open("./templates/accordian.html", "r", "utf-8")
accordian_soup = BeautifulSoup(accordianfile.read(), 'html.parser')

for i in weeks:
    tree = ET.parse('calendar/week%s.xml' % i)
    root = tree.getroot()

    button = accordian_soup.find(id="week%s" % i)
    if i == weeks[-1]:
        button['class'].remove('collapsed')
        body = accordian_soup.find(id="collapse%i" % i)
        body['class'].append('show')
    button.append(root[0].text)

    for column in root[1:]:
        materials = accordian_soup.find(id="materials%s" % i)
        col = accordian_soup.new_tag("div")
        col['class'] = ['col-md-6']

        header = accordian_soup.new_tag("h5")
        header.string = column.text
        col.append(header)
        col.append(accordian_soup.new_tag("hr"))

        for section in column:
            title = accordian_soup.new_tag("span")
            title.string = section.text.rstrip()
            col.append(title)
            list = accordian_soup.new_tag("ul")
            listItem = accordian_soup.new_tag("li")

            for item in section:
                lk = accordian_soup.new_tag("a")
                lk['class'] =  ['bordered']
                lk.string = item.text.rstrip()
                lk['href'] = item[0].text.rstrip()
                lk['target'] = ['_blank']
                if item[1].text == "True":
                    lk['class'].extend(['btn-link', 'disabled'])
                listItem.append(lk)
            list.append(listItem)
            col.append(list)
        materials.append(col)

# print(accordian_soup.prettify())

for i in range(weeks[-1] + 1, len(weeks)+1):
    button = accordian_soup.find(id="week%s" % i)
    button['class'].append('disabled')

    tree = ET.parse('calendar/week%s.xml' % i)
    root = tree.getroot()
    button.append(root[0].text)

accordian = soup.find(id="weekly-info")
accordian.append(str(accordian_soup))

stringy = str(soup.prettify())
stringy = stringy.replace('<', '<')
stringy = stringy.replace('>', '>')
outfile = codecs.open("./temp/index.html", "w+", "utf-8")
outfile.write(stringy)


import spacy

import logging
acidity_logger = logging.getLogger(__name__)

try:
    # Acidity Model
    model_dir = "models_acidity/wines_acidity/model-best"
    nlp_acidity = spacy.load(model_dir)
except Exception as e:
    acidity_logger.critical('ACIDTY MODEL: {}'.format(str(e)))
else:
    acidity_logger.info('SUCCESS - LOADED ACIDITY MODEL')

def extract_acidity(review: str, source: str) -> dict:
    """Extract acidity from review"""
    if isinstance(review, str):
        doc = nlp_acidity(review)
        acidity_terms = [ent.text for ent in doc.ents]
        if len(acidity_terms) > 0:
            acidity_list = [acidity.lower().strip() for acidity in acidity_terms if len(acidity.strip()) > 4]
            if len(acidity_list) > 0:
                result = {
                    'data': acidity_list,
                    'source': source
                }
                return result
            else:
                return None
        else:
            return None
    else:
        return None

if __name__ == "__main__":
    pass


from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.welcome, name='welcome'),
    url(r'^accounts/register/$', views.register, name='register'),
    url(r'^accounts/register/complete/$', views.registration_complete, name='registration_complete'),
    url(r'^accounts/login/$', 'django.contrib.auth.views.login', name='login'),
    url(r'^accounts/logout/$', 'django.contrib.auth.views.logout', { 'template_name': 'registration/loggedout.html',}, name='logout',),
    url(r'^accounts/loggedin/$', views.loggedin, name='loggedin'),
    url(r'^administration/$', views.administration, name='administration'),
    url(r'^finduser/$', views.finduser, name='finduser'),
    url(r'^friendshiprequests/$', views.friendshiprequestslist, name='friendshiprequests'),
    url(r'^myfriends/$', views.myfriends, name='myfriends'),
    url(r'^connections/$', views.connections, name='connections'),
]


"""
https://leetcode.com/problems/my-calendar-iii/

this tree only return overlapping count
so only need the update function
"""

from sortedcontainers import SortedDict
class SegmentTreeNode:
    def __init__(self, start=0, end=0, count=0, left=None, right=None) -> None:
        self.start = start
        self.end = end

        self.count = count
        self.left = left
        self.right = right

def printSegmentTree(node):

    q = [(node, 0, '^')]
    idx = 1
    pIdx = 0
    while q:
        count = len(q)
        level = ""
        while count:
            node, pIdx, lr = q[0]
            q = q[1:]
            if node:
                level = f"{level}  {pIdx}-{lr}-{idx}:[{node.start},{node.end},{node.count}]"
                if node.left:
                    q.append((node.left, idx, 'l'))
                if node.right:
                    q.append((node.right, idx, 'r'))
            else:
                level = f"{level}  {idx}-None"
            count-=1
            idx+=1

        print(level)
    print()

# don't think start,end as two separate things
# it is the vals here..
# I confuse it as a range
# I came from that dicrete examples.. that l,r is truly a range (afterall, that is range sum exmaple)

def query(root, start, end):
    if start >= end or root is None:
        # root is None meaning there is no interval existing yet
        # it can happen when it walks off the edge into the void
        # e..g root is now 10,30... on incoming 50,60.. it walks to right and its a void

        return 0

    if root.start >= end:
        return query(root.left, start, end)

    if root.end <= start:
        return query(root.right, start, end)

    # the max overlapping among root range, left range and right range
    return max(root.count, query(root.left, start, end), query(root.right, start, end))

# WARNING: this version has that push-down loss
class MyCalendarThree:

    def __init__(self):
        self.root = SegmentTreeNode()
        self.max = 0

    def book(self, start: int, end: int) -> int:
        def update(root, start, end):
            if start >= end:
                # it is none of your business
                # or it is an empty range.. no need to build a node for empty range
                return root
            if root is None:
                # this is a new interval
                self.max = max(self.max, 1)
                return SegmentTreeNode(start, end, 1)

            if root.end <= start:
                root.right = update(root.right, start, end)

            elif root.start >= end:
                root.left = update(root.left, start, end)
            else:
                # span both left/right
                # e.g. [10,30] with incoming [15,25]
                # it will split int [10,15].. [15. 25].. and [25,30]
                # the mid range(b,c) will have one more count here +=1
                # the left/right ranges (a,b) and (c,d) will form new ranges.. and could populate downwards...
                a = min(start, root.start)
                b = max(start, root.start)
                c = min(end, root.end)
                d = max(end, root.end)

                root.start = b
                root.end = c
                root.count += 1
                self.max = max(self.max, root.count)

                root.left = update(root.left, a, b)
                root.right = update(root.right, c, d)

            return root

        update(self.root, start, end)
        return self.max

# trying to fix that push down loss
# firstly, trying to use the old value after it gets updated
# a so bad logical error
class MyCalendarThree:
    def __init__(self):
        self.root = SegmentTreeNode()
        self.max = 0

    def book(self, start: int, end: int) -> int:
        pushDownMap = {}
        def update(root, start, end):
            if start >= end:
                # it is none of your business
                # or it is an empty range.. no need to build a node for empty range
                return root
            if root is None:
                # this is a new interval
                count = 1
                if (start,end) in pushDownMap:
                    count = pushDownMap[(start, end)]

                self.max = max(self.max, count)
                return SegmentTreeNode(start, end, count)

            if root.end <= start:
                root.right = update(root.right, start, end)

            elif root.start >= end:
                root.left = update(root.left, start, end)
            else:
                # span both left/right
                # e.g. [10,30] with incoming [15,25]
                # it will split int [10,15].. [15. 25].. and [25,30]
                # the mid range(b,c) will have one more count here +=1
                # the left/right ranges (a,b) and (c,d) will form new ranges.. and could populate downwards...
                a = min(start, root.start)
                b = max(start, root.start)
                c = min(end, root.end)
                d = max(end, root.end)

                if root.start <= a and b <= root.end:
                    pushDownMap[(a, b)] = root.count

                if root.start <= c and d <= root.end:
                    pushDownMap[(c, d)] = root.count

                root.start = b
                root.end = c
                root.count += 1
                self.max = max(self.max, root.count)

                root.left = update(root.left, a, b)
                root.right = update(root.right, c, d)

            return root

        update(self.root, start, end)
        return self.max

"""
Runtime: 342 ms, faster than 96.32% of Python3 online submissions for My Calendar III.
Memory Usage: 15.4 MB, less than 18.61% of Python3 online submissions for My Calendar III.

okay.. so agnoy comes from
                if root.start <= a and b <= root.end:
                    pushDownMap[(a, b)] = root.count

                if root.start <= c and d <= root.end:
                    pushDownMap[(c, d)] = root.count

                root.start = b
                root.end = c
                root.count += 1
                self.max = max(self.max, root.count)

I wrote it as beow -- update root before I need its old value
                root.start = b
                root.end = c
                root.count += 1
                self.max = max(self.max, root.count)

                if root.start <= a and b <= root.end:
                    pushDownMap[(a, b)] = root.count

                if root.start <= c and d <= root.end:
                    pushDownMap[(c, d)] = root.count

gives me idea maybe I can still do that push down
"""

class MyCalendarThree:
    def __init__(self):
        self.root = SegmentTreeNode()
        self.max = 0

    def book(self, start: int, end: int) -> int:
        def update(root, start, end, pushDownCount):
            # pushDownCount is how many should the split child inherits
            # edge case being if it is total subset of root.. it must inherit root.count
            # e.g. 10,30,3 with incoming 5,20
            # it will become 1-10, which is new 1
            # also 1-20, which is 3+1 = 4
            # also 20-30, which is? absolutely not 1.. it should be 3

            if start >= end:
                # it is none of your business
                # or it is an empty range.. no need to build a node for empty range
                return root
            if root is None:
                # this is a new interval
                self.max = max(self.max, pushDownCount)
                return SegmentTreeNode(start, end, pushDownCount)

            if root.end <= start:
                root.right = update(root.right, start, end, pushDownCount)

            elif root.start >= end:
                root.left = update(root.left, start, end, pushDownCount)
            else:
                # span both left/right
                # e.g. [10,30] with incoming [15,25]
                # it will split int [10,15].. [15. 25].. and [25,30]
                # the mid range(b,c) will have one more count here +=1
                # the left/right ranges (a,b) and (c,d) will form new ranges.. and could populate downwards...
                a = min(start, root.start)
                b = max(start, root.start)
                c = min(end, root.end)
                d = max(end, root.end)

                leftPushDown=rightPushDown=1
                if root.start <= a and b <= root.end:
                    leftPushDown = root.count
                if root.start <= c and d <= root.end:
                    rightPushDown = root.count

                root.start = b
                root.end = c
                root.count += 1
                self.max = max(self.max, root.count)

                root.left = update(root.left, a, b, leftPushDown)
                root.right = update(root.right, c, d, rightPushDown)

            return root

        update(self.root, start, end,1)
        return self.max

"""
Runtime: 311 ms, faster than 96.75% of Python3 online submissions for My Calendar III.
Memory Usage: 14.6 MB, less than 55.41% of Python3 online submissions for My Calendar III.

okay... it is still right...
I am still not familiar with this enough
"""

class MyCalendarThree:

    def __init__(self):
        self.sMap = SortedDict()

    def book(self, startTime: int, endTime: int) -> int:
        if startTime not in self.sMap:
            self.sMap[startTime] = 0
        self.sMap[startTime] += 1

        if endTime not in self.sMap:
            self.sMap[endTime] = 0
        self.sMap[endTime] -= 1

        # curr will meet +1, -1, so it kind of reflect the curr most bookings
        # res will only be the max bookings..
        # genius idea ...
        res = curr = 0
        for time, count in self.sMap.items():
            curr += count
            res = max(res, curr)

        return res

if __name__ == '__main__':
    # op = ["book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book","book"]
    # # args = [[97,100],[51,65],[27,46],[90,100],[20,32],[15,28],[60,73],[77,91],[67,85],[58,72],[74,93],[73,83],[71,87],[97,100],[14,31],[26,37],[66,76],[52,67],[24,43],[6,23],[94,100],[33,44],[30,46],[6,20],[71,87],[49,59],[38,55],[4,17],[46,61],[13,31],[94,100],[47,65],[9,25],[4,20],[2,17],[28,42],[26,38],[72,83],[43,61],[18,35]]
    # args = [[27, 46], [20, 32], [15, 28], [14, 31], [26, 37], [24, 43], [6, 23], [
    #     33, 44], [30, 46], [6, 20], [4, 17], [4, 20], [2, 17], [28, 42], [26, 38]]

    # this input shows something wrong with logic
    args = [[27, 46], [20, 32], [15, 28]]
    mycal3 = MyCalendarThree()
    for arg in args:
        print(mycal3.book(*arg), arg)
        printSegmentTree(mycal3.root.right)
    """
okay.. above reveals what is wrong
1 [27, 46]
    0-^-1:[27,46,1]

2 [20, 32]
  0-^-1:[27,32,2]
  1-l-2:[20,27,1]  1-r-3:[32,46,1]

3 [15, 28]
  0-^-1:[27,28,3]
  1-l-2:[20,27,2]  1-r-3:[32,46,1]
  2-l-4:[15,20,1]  3-l-5:[28,32,1]
                            ^^ here 28-32 should have appeared twice now already

    the reason is maybe here
    when 15-28 + 27-32.. it pushes 28-32 to right..
    it should bear its 2 to start.. not 1 to start..
    let me see where to make the fix

    to keep the scene I'll copy a new class

    """

    args = [[27, 46], [20, 32], [15, 28], [14, 31], [26, 37], [24, 43], [6, 23], [
        33, 44], [30, 46], [6, 20], [4, 17], [4, 20], [2, 17], [28, 42], [26, 38]]

    # this input shows something wrong with logic
    mycal3 = MyCalendarThree()
    for arg in args:
        print(mycal3.book(*arg), arg)
        printSegmentTree(mycal3.root.right)


#-*-encoding:utf-8-*-
"""
Django settings for StudentEvaluation project.

For more information on this file, see
https://docs.djangoproject.com/en/1.6/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.6/ref/settings/
"""

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
import sys
reload(sys)
sys.setdefaultencoding('gbk')

from django.conf.global_settings import MEDIA_ROOT, STATICFILES_FINDERS,\
    TEMPLATE_DIRS, LOGGING
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'sw#awbm3umd+q5w!ma19@cg6-@@ccbg!dj-6*!=(a0ihvap63n'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

TEMPLATE_DEBUG = True

ALLOWED_HOSTS = []

ADMINS = (
          ('baoan_008', '1025804905@qq.com'),
          )

MANAGFRS = ADMINS

# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'engine',
    'captcha',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'StudentEvaluation.urls'

WSGI_APPLICATION = 'StudentEvaluation.wsgi.application'

# Database
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'StudentEvaluation.db'),
    }
}

# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/

LANGUAGE_CODE = 'zh-CN'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.6/howto/static-files/
STATIC_ROOT = os.path.join(BASE_DIR, 'static').replace('\\', '/')
STATIC_URL = '/static/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

#验证码
#CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'

STATICFILES_DIRS = (
                   ('images', os.path.join(STATIC_ROOT, 'images').replace('\\', '/')),
                   ('css', os.path.join(STATIC_ROOT, 'css').replace('\\', '/')),
                   ('js', os.path.join(STATIC_ROOT, 'js').replace('\\', '/')),
                   ('custom-plugins', os.path.join(STATIC_ROOT, 'custom-plugins').replace('\\', '/')),
                   ('jui', os.path.join(STATIC_ROOT, 'jui').replace('\\', '/')),
                   ('plugins', os.path.join(STATIC_ROOT, 'plugins').replace('\\', '/')),
                   ('bootstrap', os.path.join(STATIC_ROOT, 'bootstrap').replace('\\', '/')),
                   ('swf', os.path.join(STATIC_ROOT, 'swf').replace('\\', '/')),
                   # Put strings here, like "/home/html/static" or "C:/www/django/static".
                   # Always use forward slashes, even on Windows.
                   # Don't forget to use absolute paths, not relative paths.
    )

STATICFILES_FINDERS = (
                    'django.contrib.staticfiles.finders.FileSystemFinder',
                    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
                    #'django.contrib.staticfiles.finders.DefaultStorageFinder',
    )

TEMPLATE_DIRS = (
                 'templates',
    )

LOGGING = {
           'version' : 1,
           'disable_existing_loggers' : False,
           'formatters' : {
                           'simple' : {
                                       'format' : '%(levelname)s %(name)s %(asctime)s %(message)s'
                                       },
                           'verbose' : {
                                        'format' : "%(levelname)s %(name)s %(asctime)s %(pathname)s %(module)s %(lineno)d %(message)s",
                                        'datefmt' : '%Y-%m-%d %H:%M:%S'
                                        },
                           'django_request' : {
                                        'format' : '%(levelname)s %(asctime)s %(pathname)s %(module)s %(lineno)d %(message)s status_code:%(status_code)d',
                                         'datefmt' : '%Y-%m-%d %H:%M:%S'
                                        },
                           'django_db_backends' : {
                                        'format' : '%(levelname)s %(asctime)s %(pathname)s %(module)s %(lineno)d %(message)s duration:%(duration).3f sql:%(sql)s params:%(params)s',
                                        'datefmt' : '%Y-%m-%d %H:%M:%S'
                                        },
                    },
           'handlers' : {
                         'null' : {
                                   'level' : 'DEBUG',
                                   'class' : 'django.utils.log.NullHandler',
                                   },
                         'console' :{
                                    'level' : 'DEBUG',
                                    'class' : 'logging.StreamHandler',
                                    'formatter' : 'simple'
                                    },
                         'custom_log_file' : {
                                    'level' : 'WARNING',
                                    'class' : 'logging.handlers.RotatingFileHandler',
                                    'filename' : os.path.join(BASE_DIR, 'logs/django.log'),
                                    'backupCount' : 5,
                                    'maxBytes' : '1000000',
                                    'formatter' : 'verbose'
                                    },
                        'django_request_logfile':{
                                    'level': 'WARNING',
                                    'class': 'logging.handlers.RotatingFileHandler',
                                    'filename': os.path.join(BASE_DIR, 'logs/django_request_logfile.log'),#you need define your VAR_ROOT variable that points to your project path,and mkdir a logs directory in your project root path.
                                    'backupCount': 5,
                                    'maxBytes': '1000000', # 16megabytes(16M)
                                    'formatter': 'django_request'
                                    },

                        'django_db_backends_logfile':{
                                    'level': 'WARNING',
                                    'class': 'logging.handlers.RotatingFileHandler',
                                    'filename': os.path.join(BASE_DIR, 'logs/django_db_backends_logfile.log'),#you need define your VAR_ROOT variable that points to your project path,and mkdir a logs directory in your project root path.
                                    'backupCount': 5,
                                    'maxBytes': '1000000', # 16megabytes(16M)
                                    'formatter': 'django_db_backends'
                                    },

                        'mail_admins': {
                                    'level': 'ERROR',
                                    'class': 'django.utils.log.AdminEmailHandler',
                                    'include_html': True,
                                    }
                    },

           'loggers' : {
                        'django' : {
                                    'handlers' : ['console'],
                                    'level' : 'DEBUG',
                                    'propagate' : False,
                                },
                        'django.request' : {
                                    'handlers' : ['mail_admins', 'django_request_logfile'],
                                    'level' : 'WARNING',
                                    'propagate' : True,
                                },
                        'django.db.backends': {
                                    'handlers': ['django_db_backends_logfile',],
                                    'level': 'WARNING',
                                    'propagate': True,
                                },
                        'customapp': {#then you can change the level to control your custom app whether to output the debug infomation
                                    'handlers': ['console'],
                                    'level': 'DEBUG',
                                    'propagate': False,
                                },
                    },
    }


import json, os
from datetime import date, datetime
from itertools import chain

from django.core.urlresolvers import reverse
from recordlib import RecordParser
from dateutil.parser import parse

APP_BASE_DIR = os.path.dirname(__file__)
COLLECT_LOG_FILE = os.path.join(APP_BASE_DIR, 'logs/collect.log')
MAX_COLLECT_LENGTH = 20
ord_types = {'st': '정기', 'ex': '추가', 'em': '응급', 'op': '퇴원', 'ch': '항암'}
ord_types_reverse = {'정기': 'st', '추가': 'ex', '응급':'em', '퇴원':'op', '항암':'ch'}

class LabelRecordParser:

	def __init__(self, json_path=COLLECT_LOG_FILE):
		self.json_path = json_path
		try:
			with open(json_path) as fp:
				self.label_history_list = json.loads(fp.read())
		except:
			self.label_history_list = []

	def save_queryset(self, agg, detail, ord_tp, form_data):
		today = date.today().strftime('%Y-%m-%d')
		seq_list = [row['seq'] for row in self.label_history_list if row['date'] == today and row['ord_tp'] == ord_types[ord_tp]]
		seq = max(seq_list) + 1 if seq_list else 0
		queryset = []
		recs = RecordParser(detail)

		today_queryset = [history for history in self.label_history_list if history['date'] == today]
		today_subqueryset = []

		for rec in today_queryset:
			collect_seq = rec['seq'] + 1
			for row in rec['records']:
				today_subqueryset.append((collect_seq, row['sub_object_list']))

		for item in agg:
			item['sub_object_list'] = recs.select('*', where = lambda row: row['ord_cd'] == item['ord_cd'], inplace=False).order_by(['ord_ymd', 'rcpt_dt']).records
			item['duplicated'] = False
			for sub in item['sub_object_list']:
				sub['duplicated'] = 0
				for cseq, today_sub_list in today_subqueryset:

					for today_sub in today_sub_list:
						sub_dup_save = sub.pop('duplicated')
						today_sub_save = today_sub.pop('duplicated')
						if sub == today_sub:
							sub['duplicated'] = cseq
							item['duplicated'] = True
						else:
							sub['duplicated'] = sub_dup_save
						today_sub['duplicated'] = today_sub_save

			queryset.append(item)

		log = {
			'date' : today,
			'seq': seq,
			'ord_tp': ord_types[ord_tp],
			'form_data': form_data,
			'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
			'records': queryset
		}
		self.label_history_list.append(log)
		with open(self.json_path, 'w') as fp:
			fp.write(json.dumps(self.label_history_list[-MAX_COLLECT_LENGTH:]))

		return log['records']

	def select_queryset(self, date=date.today().strftime('%Y-%m-%d'), seq=-1):
		queryset_list = [history for history in self.label_history_list if history['date'] == date and (history['seq'] == seq if seq!=-1 else True)]
		if not queryset_list:
			return
		if seq == -1:
			return queryset_list[seq]['records']
		return queryset_list[0]['records']

	def delete_queryset(self, ord_tp, date, seq):
		for idx, history in enumerate(self.label_history_list):
			if history['ord_tp'] == ord_types[ord_tp] and history['seq'] == int(seq) and history['date'] == date:
				self.label_history_list.pop(idx)
				with open(self.json_path, 'w') as fp:
					fp.write(json.dumps(self.label_history_list[-MAX_COLLECT_LENGTH:]))
				return
		return

	def get_collect_object_list(self):
		ret = []
		for collect in self.label_history_list:

			s = '[{}]{} {}차({}건)'.format(collect['date'], collect['ord_tp'], collect['seq']+1, sum(len(rec['sub_object_list']) for rec in collect['records']))
			url = reverse('orderutils:labelcollect-history',
				 kwargs = {'date': collect['date'], 'seq': collect['seq'], 'ord_tp': ord_types_reverse[collect['ord_tp']]}
			)

			ret.append({'description': s, 'url': url})
		return ret[::-1]

	def select_collect(self, date, ord_tp, seq=-1):
		if not self.label_history_list:
			return []

		if seq == -1:
			ord_tp_history = [collect for collect in self.label_history_list if collect['ord_tp'] == ord_types[ord_tp]]
			return ord_tp_history[seq] if ord_tp_history else []

		for collect in self.label_history_list:
			if collect['seq'] == seq and collect['date'] == date and collect['ord_tp'] == ord_types[ord_tp]:
				return collect
		return []

	def get_last_collect(self, date=date.today().strftime('%Y-%m-%d')):
		ret = {}
		for collect in [collect for collect in self.label_history_list if collect['date'] == date]:
			ret[ord_types_reverse[collect['ord_tp']]] = collect['form_data']['end_t']

		return ret

	def clear_history(self):
		if os.path.exists(COLLECT_LOG_FILE):
			os.unlink(COLLECT_LOG_FILE)

# ret = load_collect_log()
# print(create_label_collect_queryset(ret['agg'], ret['detail']))
# l = LabelRecordParser()
# print(l.label_history_list)


import sqlalchemy
import pandas as pd

from app.etl.DataSources.IDataSource import IDataSource
from app.etl.DataSources.Database.EDatabase import DatabaseType
class Database(IDataSource):
    def __init__(self, type,connection_string) -> None:
        # super().__init__(type)
        if(type==DatabaseType.MSSQL):
            connection_string=connection_string.split('::')[1].split('/')
            self.engine = sqlalchemy.create_engine(f'mssql+pyodbc://{connection_string[0]}/{connection_string[1]}?trusted_connection=yes&driver=SQL+Server+Native+Client+11.0')
            self.table_name=connection_string[2]
        elif(type==DatabaseType.SQLLITE):
            cs=connection_string.split('::')[1].split('/')[0]
            self.engine = sqlalchemy.create_engine(f'sqlite:///{cs}')
            self.table_name=connection_string.split('::')[1].split('/')[1]

    def extract(self, file_path):
        data = pd.read_sql(f'select * from {self.table_name}', self.engine)
        return data

    def load(self,data, file_path):
        data.to_sql(self.table_name, self.engine, if_exists='append', index=False)