from discord.ext import commands, tasks
import discord
import asyncio
import os
import json
import sqlite3
from dotenv import load_dotenv
import requests
from datetime import datetime,time

load_dotenv()

class Birthday(commands.Cog):
    """Birthday commands."""

    def __init__(self, client):
        self.client = client
        self.birthday_announcments.start()

    @commands.command(hidden = True)
    @commands.is_owner()
    async def force_add_user(self, ctx, user: discord.Member, day: int, month: int):
        """Adds a user to the birthday list."""
        if day > 31 or day < 1 or month > 12 or month < 1:
            await ctx.send("Invalid date.")
            return
        con = sqlite3.connect("databases/user_brithdays.db")
        cur = con.cursor()
        cur.execute("SELECT * FROM birthday WHERE user_id = ?", (user.id,))
        if cur.fetchone() is not None:
            await ctx.send("User already exists.")
            return
        cur.execute("INSERT INTO birthday VALUES (?, ?, ?)", (user.id, day, month))
        con.commit()
        con.close()
        await ctx.send("Added user to birthday list.")

    @commands.command(hidden=True)
    @commands.is_owner()
    async def makeservertablebirthday(self,ctx):
        con = sqlite3.connect("databases/server_brithdays.db")
        cur = con.cursor()
        cur.execute("CREATE TABLE server(ServerID int, Servertoggle, birthdaychannel int,birthdaymessage text)")
        con.commit()
        con.close()
        con = sqlite3.connect("databases/user_brithdays.db")
        cur = con.cursor()
        cur.execute("CREATE TABLE birthday(UsersID int, birthday)")
        con.commit()
        con.close()
        await ctx.send("Done")
#
    #@commands.command(hidden = True)
    #@commands.is_owner()
    #async def setallbithday(self,ctx):
    #    for i in self.client.guilds:
    #        con = sqlite3.connect("databases/server_brithdays.db")
    #        cur = con.cursor()
    #        cur.execute("INSERT INTO server(ServerID, Servertoggle,birthdaychannel) VALUES(?, ?,?)", (i.id, False,None))
    #        await ctx.send(f"{i} has been set")
    #        con.commit()
    #        con.close()

    @commands.Cog.listener()
    async def on_guild_join(self, guild):

        con = sqlite3.connect("databases/server_brithdays.db")
        cur = con.cursor()
        cur.execute("INSERT INTO server(ServerID, Servertoggle) VALUES(?, ?)", (guild.id, False))
        con.commit()
        con.close()

    @commands.command(help = " enable and disable Birthday")
    @commands.has_permissions(administrator=True)
    async def toggle_birthday(self,ctx):
        con = sqlite3.connect("databases/server_brithdays.db")
        cur = con.cursor()
        datas = cur.execute("SELECT * FROM server WHERE ServerID=?", (ctx.guild.id,))
        datas = cur.fetchall()
        toggle = datas[0][1]
        if toggle == True:
            cur.execute("UPDATE server SET Servertoggle = ? WHERE ServerID=?", (False, ctx.guild.id,))
            con.commit()
            con.close()
            await ctx.send("Birthday reminders has been turned off")
        if toggle == False:
            cur.execute("UPDATE server SET Servertoggle = ? WHERE ServerID=?", (True, ctx.guild.id,))
            con.commit()
            con.close()
            await ctx.send("Birthday reminders has been turrned on")

    @commands.slash_command(name="toggle_birthday", description="enable and disable Birthday")
    @commands.has_permissions(administrator=True)
    async def _toggle_birthday(self,ctx):
        con = sqlite3.connect("databases/server_brithdays.db")
        cur = con.cursor()
        datas = cur.execute("SELECT * FROM server WHERE ServerID=?", (ctx.guild.id,))
        datas = cur.fetchall()
        toggle = datas[0][1]
        if toggle == True:
            cur.execute("UPDATE server SET Servertoggle = ? WHERE ServerID=?", (False, ctx.guild.id,))
            con.commit()
            con.close()
            await ctx.respond("Birthday reminders has been turned off")
        if toggle == False:
            cur.execute("UPDATE server SET Servertoggle = ? WHERE ServerID=?", (True, ctx.guild.id,))
            con.commit()
            con.close()
            await ctx.respond("Birthday reminders has been turrned on")
        await ctx.followup.send("If you like the bot, please consider voting for it at https://top.gg/bot/902240397273743361 \n It helps a lot! :D", ephemeral=True)

    @commands.slash_command(name="setbirthday", description="Set your birthday use day then month")
    async def setbirthday__slash(self, ctx, day: int, month: int):
        tocken = os.getenv("TOPGG_TOKEN")
        api = requests.get(f"https://top.gg/api/bots/902240397273743361/check?userId={ctx.author.id}", headers={"Authorization": tocken, "Content-Type": "application/json"})
        data = api.json()
        print(api)
        print(data)
        voted = data["voted"]
        #if the api does not return a 200 status code
        if api.status_code != 200:
            voted = 1
            print("api error")
        if voted == 0:
            await ctx.respond("You need to have voted for simplex in the last 24 hours to set your birthday. Please vote and then try again, you can vote here: https://top.gg/bot/902240397273743361/vote",ephemeral=True)
            return
        else:
            if day > 31 or day < 1 or month > 12 or month < 1:
                await ctx.respond("Invalid date.")
            else:
                #force 2 digit date
                if day < 10:
                    day = f"0{day}"
                if month < 10:
                    month = f"0{month}"

                con = sqlite3.connect("databases/user_brithdays.db")
                cur = con.cursor()
                data = cur.execute("SELECT * FROM birthday WHERE UsersID=?", (ctx.author.id,))
                data = cur.fetchall()
                if data == []:
                    cur.execute("INSERT INTO birthday(UsersID, birthday) VALUES(?, ?)", (ctx.author.id, f"{day}/{month}"))
                    con.commit()
                    con.close()
                    await ctx.respond("Your birthday has been set")
                else:
                    cur.execute("UPDATE birthday SET birthday = ? WHERE UsersID=?", (f"{day}/{month}", ctx.author.id,))
                    con.commit()
                    con.close()
                    await ctx.respond("Your birthday has been updated")

    @commands.command(name="setbirthday", help = "Set your birthday use day then month")
    async def setbirthday_commands(self, ctx, day: int, month: int):
        if day > 31 or day < 1 or month > 12 or month < 1:
            await ctx.send("Invalid date.")
        else:
            #formate date 2 digit
            if len(str(day)) == 1:
                day = f"0{day}"
            if len(str(month)) == 1:
                month = f"0{month}"

            con = sqlite3.connect("databases/user_brithdays.db")
            cur = con.cursor()
            data = cur.execute("SELECT * FROM birthday WHERE UsersID=?", (ctx.author.id,))
            data = cur.fetchall()
            if data == []:
                cur.execute("INSERT INTO birthday(UsersID, birthday) VALUES(?, ?)", (ctx.author.id, f"{day}/{month}"))
                con.commit()
                con.close()
                await ctx.send("Your birthday has been set")
            else:
                cur.execute("UPDATE birthday SET birthday = ? WHERE UsersID=?", (f"{day}/{month}", ctx.author.id,))
                con.commit()
                con.close()
                await ctx.send("Your birthday has been updated")

    @commands.command(name="set_birthday_channel",help = "Set the birthday channel")
    @commands.has_permissions(administrator=True)
    async def set_birthday_channel_command(self,ctx, channel: commands.TextChannelConverter):
        con = sqlite3.connect("databases/server_brithdays.db")
        cur = con.cursor()
        cur.execute("UPDATE server SET birthdaychannel = ? WHERE ServerID=?", (channel.id, ctx.guild.id,))
        con.commit()
        con.close()
        await ctx.send(f"Birthday channel has been set to {channel} \n To enable birthday reminders use the command `/toggle_birthday` \n To set a custom message use the command `/birthday_message`")

    @commands.slash_command(name="set_birthday_channel",help = "Set the birthday channel")
    @commands.has_permissions(administrator=True)
    async def set_birthday_channel__slash(self,ctx, channel: commands.TextChannelConverter):
        con = sqlite3.connect("databases/server_brithdays.db")
        cur = con.cursor()
        cur.execute("UPDATE server SET birthdaychannel = ? WHERE ServerID=?", (channel.id, ctx.guild.id,))
        con.commit()
        con.close()
        await ctx.respond(f"Birthday channel has been set to {channel}")

    @commands.slash_command(name="findbirthday", description="Find a users birthday")
    async def findbirthday__slash(self, ctx, user: discord.Member):
        con = sqlite3.connect("databases/user_brithdays.db")
        cur = con.cursor()
        data = cur.execute("SELECT * FROM birthday WHERE UsersID=?", (user.id,))
        data = cur.fetchall()
        if data == []:
            await ctx.respond(f"{user} has not set their birthday")
        else:
            await ctx.respond(f"{user} birthday is {data[0][1]}")
        await ctx.followup.send("If you like the bot, please consider voting for it at https://top.gg/bot/902240397273743361 \n It helps a lot! :D", ephemeral=True)

    @tasks.loop(time=time(7,00))
    async def birthday_announcments(self):
        print("Birthday announcments")
        for server in self.client.guilds:
                print(server)
                con = sqlite3.connect("databases/server_brithdays.db")
                cur = con.cursor()
                datas = cur.execute("SELECT * FROM server WHERE ServerID=?", (server.id,))
                datas = cur.fetchall()
                if datas == []:
                    cur.execute("INSERT INTO server(ServerID, Servertoggle, birthdaychannel) VALUES(?, ?, ?)", (server.id, False, None))
                    con.commit()
                    con.close()
                else:
                    pass
                con = sqlite3.connect("databases/user_brithdays.db")
                cur = con.cursor()
                data = cur.execute("SELECT * FROM birthday")
                data = cur.fetchall()
                if data == []:
                    print("No birthday")
                    #does not work below here
                else:
                    for x in data:
                        if datas[0][1] == True:
                            if datas[0][2] == None:
                                pass
                            else:
                                user = await self.client.fetch_user(x[0])
                                if user in server.members:
                                    channel = await self.client.fetch_channel(datas[0][2])
                                    message = datas[0][3]
                                    if message == None:
                                        message = ":tada:"

                                    print(channel)
                                    print(x[1])
                                    print(datetime.now().strftime("%d/%m"))
                                    if x[1] == datetime.now().strftime("%d/%m"):
                                        print("Birthday")
                                        print(x[0])
                                        await channel.send(f"Happy birthday <@{x[0]}>! \n {message}")
                                else:
                                    username = await self.client.fetch_user(x[0])
                                    print(f"User {username} not in server {x[0]} {server}")
                        else:
                            pass

    #@commands.command()
    #@commands.is_owner()
    #async def foramt_all_birthdays(self,ctx):
    #    con = sqlite3.connect("databases/user_brithdays.db")
    #    cur = con.cursor()
    #    data = cur.execute("SELECT * FROM birthday")
    #    data = cur.fetchall()
    #    for i in data:
    #        day = i[1].split("/")[0]
    #        month = i[1].split("/")[1]
    #        if len(day) == 1:
    #            day = "0" + day
    #        if len(month) == 1:
    #            month = "0" + month
    #        cur.execute("UPDATE birthday SET Birthday = ? WHERE UsersID=?", (f"{day}/{month}", i[0],))
    #        con.commit()
    #    con.close()
    #

    @commands.command()
    @commands.is_owner()
    async def add_message_to_birthday(self,ctx,*,message):
        con = sqlite3.connect("databases/server_brithdays.db")
        cur = con.cursor()
        #creat a new column
        cur.execute("ALTER TABLE server ADD COLUMN birthdaymessage TEXT")
        #set the message
        cur.execute("UPDATE server SET birthdaymessage = ?", (message,))
        con.commit()
        con.close()
        await ctx.send("Done")

    @commands.slash_command(name="birthday_message", description="Add a message to the birthday announcment")
    @commands.has_permissions(administrator=True)
    async def add_message_to_birthday__slash(self,ctx,*,message):
        con = sqlite3.connect("databases/server_brithdays.db")
        cur = con.cursor()
        data = cur.execute("SELECT * FROM server WHERE ServerID=?", (ctx.guild.id,))
        data = cur.fetchall()
        if data == []:
            await ctx.respond("You have not set a birthday channel")
        else:
            cur.execute("UPDATE server SET birthdaymessage = ? WHERE ServerID=?", (message, ctx.guild.id,))
            con.commit()
            con.close()
            await ctx.respond("Done")
            await ctx.followup.send("If you like the bot, please consider voting for it at https://top.gg/bot/902240397273743361 \n It helps a lot! :D", ephemeral=True)

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


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Ambre chamber
"""
__author__ = "Dennis van Gils"
__authoremail__ = "vangils.dennis@gmail.com"
__url__ = "https://github.com/Dennis-van-Gils/project-Ambre-chamber"
__date__ = "31-08-2020"
__version__ = "2.0"
# pylint: disable=bare-except, broad-except, try-except-raise

import os
import sys
import time

import numpy as np
import psutil

from PyQt5 import QtCore, QtGui
from PyQt5 import QtWidgets as QtWid
from PyQt5.QtCore import QDateTime
import pyqtgraph as pg

from dvg_debug_functions import tprint, dprint, print_fancy_traceback as pft
from dvg_pyqt_controls import (
    create_LED_indicator,
    create_Toggle_button,
    SS_TEXTBOX_READ_ONLY,
    SS_GROUP,
)
from dvg_pyqt_filelogger import FileLogger
from dvg_pyqtgraph_threadsafe import (
    HistoryChartCurve,
    LegendSelect,
    PlotManager,
)

from dvg_devices.Arduino_protocol_serial import Arduino
from dvg_qdeviceio import QDeviceIO

TRY_USING_OPENGL = True
if TRY_USING_OPENGL:
    try:
        import OpenGL.GL as gl  # pylint: disable=unused-import
    except:
        print("OpenGL acceleration: Disabled")
        print("To install: `conda install pyopengl` or `pip install pyopengl`")
    else:
        print("OpenGL acceleration: Enabled")
        pg.setConfigOptions(useOpenGL=True)
        pg.setConfigOptions(antialias=True)
        pg.setConfigOptions(enableExperimental=True)

# Global pyqtgraph configuration
# pg.setConfigOptions(leftButtonPan=False)
pg.setConfigOption("foreground", "#EEE")

# Constants
# fmt: off
DAQ_INTERVAL_MS    = 1000  # [ms]
CHART_INTERVAL_MS  = 500   # [ms]
CHART_HISTORY_TIME = 3600  # [s]
# fmt: on

# Show debug info in terminal? Warning: Slow! Do not leave on unintentionally.
DEBUG = False

def get_current_date_time():
    cur_date_time = QDateTime.currentDateTime()
    return (
        cur_date_time.toString("dd-MM-yyyy"),  # Date
        cur_date_time.toString("HH:mm:ss"),  # Time
        cur_date_time.toString("yyMMdd_HHmmss"),  # Reverse notation date-time
    )

# ------------------------------------------------------------------------------
#   Arduino state
# ------------------------------------------------------------------------------

class State(object):
    """Reflects the actual readings, parsed into separate variables, of the
    Arduino. There should only be one instance of the State class.
    """

    def __init__(self):
        self.time = np.nan  # [s]
        self.ds18b20_temp = np.nan  # ['C]
        self.dht22_temp = np.nan  # ['C]
        self.dht22_humi = np.nan  # [%]
        self.is_valve_open = False

        # Automatic valve control
        self.humi_threshold = np.nan  # [%]
        self.open_valve_when_super_humi = np.nan

state = State()

# ------------------------------------------------------------------------------
#   MainWindow
# ------------------------------------------------------------------------------

class MainWindow(QtWid.QWidget):
    def __init__(self, parent=None, **kwargs):
        super().__init__(parent, **kwargs)

        self.setWindowTitle("Ambre chamber")
        self.setGeometry(350, 50, 960, 800)
        self.setStyleSheet(SS_TEXTBOX_READ_ONLY + SS_GROUP)

        # -------------------------
        #   Top frame
        # -------------------------

        # Left box
        self.qlbl_update_counter = QtWid.QLabel("0")
        self.qlbl_DAQ_rate = QtWid.QLabel("DAQ: nan Hz")
        self.qlbl_DAQ_rate.setStyleSheet("QLabel {min-width: 7em}")

        vbox_left = QtWid.QVBoxLayout()
        vbox_left.addWidget(self.qlbl_update_counter, stretch=0)
        vbox_left.addStretch(1)
        vbox_left.addWidget(self.qlbl_DAQ_rate, stretch=0)

        # Middle box
        self.qlbl_title = QtWid.QLabel(
            "Ambre chamber",
            font=QtGui.QFont("Palatino", 14, weight=QtGui.QFont.Bold),
        )
        self.qlbl_title.setAlignment(QtCore.Qt.AlignCenter)
        self.qlbl_cur_date_time = QtWid.QLabel("00-00-0000    00:00:00")
        self.qlbl_cur_date_time.setAlignment(QtCore.Qt.AlignCenter)
        self.qpbt_record = create_Toggle_button(
            "Click to start recording to file", minimumWidth=300
        )
        # fmt: off
        self.qpbt_record.clicked.connect(lambda state: log.record(state)) # pylint: disable=unnecessary-lambda
        # fmt: on

        vbox_middle = QtWid.QVBoxLayout()
        vbox_middle.addWidget(self.qlbl_title)
        vbox_middle.addWidget(self.qlbl_cur_date_time)
        vbox_middle.addWidget(self.qpbt_record)

        # Right box
        self.qpbt_exit = QtWid.QPushButton("Exit")
        self.qpbt_exit.clicked.connect(self.close)
        self.qpbt_exit.setMinimumHeight(30)
        self.qlbl_recording_time = QtWid.QLabel(alignment=QtCore.Qt.AlignRight)

        vbox_right = QtWid.QVBoxLayout()
        vbox_right.addWidget(self.qpbt_exit, stretch=0)
        vbox_right.addStretch(1)
        vbox_right.addWidget(self.qlbl_recording_time, stretch=0)

        # Round up top frame
        hbox_top = QtWid.QHBoxLayout()
        hbox_top.addLayout(vbox_left, stretch=0)
        hbox_top.addStretch(1)
        hbox_top.addLayout(vbox_middle, stretch=0)
        hbox_top.addStretch(1)
        hbox_top.addLayout(vbox_right, stretch=0)

        # -------------------------
        #   Bottom frame
        # -------------------------

        #  Charts
        # -------------------------

        self.gw = pg.GraphicsLayoutWidget()

        # Plot: Temperature: DS18B20
        p = {"color": "#EEE", "font-size": "10pt"}
        self.pi_ds18b20_temp = self.gw.addPlot(row=0, col=0)
        self.pi_ds18b20_temp.setLabel("left", text="temperature (°C)", **p)

        # Plot: Temperature: DHT 22
        self.pi_dht22_temp = self.gw.addPlot(row=1, col=0)
        self.pi_dht22_temp.setLabel("left", text="temperature (°C)", **p)

        # Plot: Humidity: DHT22
        self.pi_dht22_humi = self.gw.addPlot(row=2, col=0)
        self.pi_dht22_humi.setLabel("left", text="humidity (%)", **p)

        self.plots = [
            self.pi_ds18b20_temp,
            self.pi_dht22_humi,
            self.pi_dht22_temp,
        ]
        for plot in self.plots:
            plot.setClipToView(True)
            plot.showGrid(x=1, y=1)
            plot.setLabel("bottom", text="history (s)", **p)
            plot.setMenuEnabled(True)
            plot.enableAutoRange(axis=pg.ViewBox.XAxis, enable=False)
            plot.enableAutoRange(axis=pg.ViewBox.YAxis, enable=True)
            plot.setAutoVisible(y=True)
            plot.setRange(xRange=[-CHART_HISTORY_TIME, 0])

        # Curves
        capacity = round(CHART_HISTORY_TIME * 1e3 / DAQ_INTERVAL_MS)
        PEN_01 = pg.mkPen(color=[255, 255, 0], width=3)
        PEN_02 = pg.mkPen(color=[0, 255, 255], width=3)

        self.tscurve_ds18b20_temp = HistoryChartCurve(
            capacity=capacity,
            linked_curve=self.pi_ds18b20_temp.plot(
                pen=PEN_01, name="DS18B20 temp."
            ),
        )
        self.tscurve_dht22_temp = HistoryChartCurve(
            capacity=capacity,
            linked_curve=self.pi_dht22_temp.plot(
                pen=PEN_01, name="DHT22 temp."
            ),
        )
        self.tscurve_dht22_humi = HistoryChartCurve(
            capacity=capacity,
            linked_curve=self.pi_dht22_humi.plot(
                pen=PEN_02, name="DHT22 humi."
            ),
        )
        self.tscurves = [
            self.tscurve_ds18b20_temp,
            self.tscurve_dht22_temp,
            self.tscurve_dht22_humi,
        ]

        #  Group `Readings`
        # -------------------------

        legend = LegendSelect(
            linked_curves=self.tscurves, hide_toggle_button=True
        )

        p = {
            "readOnly": True,
            "alignment": QtCore.Qt.AlignRight,
            "maximumWidth": 54,
        }
        self.qlin_ds18b20_temp = QtWid.QLineEdit(**p)
        self.qlin_dht22_temp = QtWid.QLineEdit(**p)
        self.qlin_dht22_humi = QtWid.QLineEdit(**p)

        # fmt: off
        legend.grid.setHorizontalSpacing(6)
        legend.grid.addWidget(self.qlin_ds18b20_temp  , 0, 2)
        legend.grid.addWidget(QtWid.QLabel("± 0.5 °C"), 0, 3)
        legend.grid.addWidget(self.qlin_dht22_temp    , 1, 2)
        legend.grid.addWidget(QtWid.QLabel("± 0.5 °C"), 1, 3)
        legend.grid.addWidget(self.qlin_dht22_humi    , 2, 2)
        legend.grid.addWidget(QtWid.QLabel("± 3 %")   , 2, 3)
        # fmt: on

        qgrp_readings = QtWid.QGroupBox("Readings")
        qgrp_readings.setLayout(legend.grid)

        #  Group 'Log comments'
        # -------------------------

        self.qtxt_comments = QtWid.QTextEdit()
        grid = QtWid.QGridLayout()
        grid.addWidget(self.qtxt_comments, 0, 0)

        qgrp_comments = QtWid.QGroupBox("Log comments")
        qgrp_comments.setLayout(grid)

        #  Group 'Charts'
        # -------------------------

        self.plot_manager = PlotManager(parent=self)
        self.plot_manager.add_autorange_buttons(linked_plots=self.plots)
        self.plot_manager.add_preset_buttons(
            linked_plots=self.plots,
            linked_curves=self.tscurves,
            presets=[
                {
                    "button_label": "00:30",
                    "x_axis_label": "history (sec)",
                    "x_axis_divisor": 1,
                    "x_axis_range": (-30, 0),
                },
                {
                    "button_label": "01:00",
                    "x_axis_label": "history (sec)",
                    "x_axis_divisor": 1,
                    "x_axis_range": (-60, 0),
                },
                {
                    "button_label": "10:00",
                    "x_axis_label": "history (min)",
                    "x_axis_divisor": 60,
                    "x_axis_range": (-10, 0),
                },
                {
                    "button_label": "30:00",
                    "x_axis_label": "history (min)",
                    "x_axis_divisor": 60,
                    "x_axis_range": (-30, 0),
                },
                {
                    "button_label": "60:00",
                    "x_axis_label": "history (min)",
                    "x_axis_divisor": 60,
                    "x_axis_range": (-60, 0),
                },
            ],
        )
        self.plot_manager.add_clear_button(linked_curves=self.tscurves)
        self.plot_manager.perform_preset(1)

        qgrp_chart = QtWid.QGroupBox("Charts")
        qgrp_chart.setLayout(self.plot_manager.grid)

        #  Group 'Valve control'
        # -------------------------

        self.LED_is_valve_open = create_LED_indicator()
        self.qlin_humi_threshold = QtWid.QLineEdit(
            "%d" % state.humi_threshold,
            alignment=QtCore.Qt.AlignRight,
            maximumWidth=36,
        )
        self.qlin_humi_threshold.editingFinished.connect(
            self.process_qlin_humi_threshold
        )
        self.qpbt_open_when_super_humi = QtWid.QPushButton(
            (
                "humidity > threshold"
                if state.open_valve_when_super_humi
                else "humidity < threshold"
            ),
            checkable=True,
            checked=state.open_valve_when_super_humi,
        )
        self.qpbt_open_when_super_humi.clicked.connect(
            self.process_qpbt_open_when_super_humi
        )

        # fmt: off
        grid = QtWid.QGridLayout()
        grid.addWidget(QtWid.QLabel("Is valve open?")    , 0, 0)
        grid.addWidget(self.LED_is_valve_open            , 0, 1)
        grid.addWidget(QtWid.QLabel("Humidity threshold"), 1, 0)
        grid.addWidget(self.qlin_humi_threshold          , 1, 1)
        grid.addWidget(QtWid.QLabel("%")                 , 1, 2)
        grid.addWidget(QtWid.QLabel("Open valve when")   , 2, 0)
        grid.addWidget(self.qpbt_open_when_super_humi    , 2, 1, 1, 2)
        grid.setAlignment(QtCore.Qt.AlignTop)
        # fmt: on

        qgrp_valve = QtWid.QGroupBox("Valve control")
        qgrp_valve.setLayout(grid)

        # Round up right frame
        vbox = QtWid.QVBoxLayout()
        vbox.addWidget(qgrp_readings)
        vbox.addWidget(qgrp_comments)
        vbox.addWidget(qgrp_valve)  # , alignment=QtCore.Qt.AlignLeft)
        vbox.addWidget(qgrp_chart, alignment=QtCore.Qt.AlignLeft)
        vbox.addStretch()

        # Round up bottom frame
        hbox_bot = QtWid.QHBoxLayout()
        hbox_bot.addWidget(self.gw, 1)
        hbox_bot.addLayout(vbox, 0)

        # -------------------------
        #   Round up full window
        # -------------------------

        vbox = QtWid.QVBoxLayout(self)
        vbox.addLayout(hbox_top, stretch=0)
        vbox.addSpacerItem(QtWid.QSpacerItem(0, 10))
        vbox.addLayout(hbox_bot, stretch=1)

    # --------------------------------------------------------------------------
    #   Handle controls
    # --------------------------------------------------------------------------

    @QtCore.pyqtSlot()
    def process_qlin_humi_threshold(self):
        try:
            humi_threshold = float(self.qlin_humi_threshold.text())
        except (TypeError, ValueError):
            humi_threshold = 50
        except:
            raise

        state.humi_threshold = np.clip(humi_threshold, 0, 100)
        self.qlin_humi_threshold.setText("%.0f" % state.humi_threshold)
        qdev_ard.send(ard.write, "th%.0f" % state.humi_threshold)

    @QtCore.pyqtSlot()
    def process_qpbt_open_when_super_humi(self):
        if self.qpbt_open_when_super_humi.isChecked():
            state.open_valve_when_super_humi = True
            self.qpbt_open_when_super_humi.setText("humidity > threshold")
            qdev_ard.send(ard.write, "open when super humi")

        else:
            state.open_valve_when_super_humi = False
            self.qpbt_open_when_super_humi.setText("humidity < threshold")
            qdev_ard.send(ard.write, "open when sub humi")

    @QtCore.pyqtSlot()
    def update_GUI(self):
        str_cur_date, str_cur_time, _ = get_current_date_time()
        self.qlbl_cur_date_time.setText(
            "%s    %s" % (str_cur_date, str_cur_time)
        )
        self.qlbl_update_counter.setText("%i" % qdev_ard.update_counter_DAQ)
        self.qlbl_DAQ_rate.setText(
            "DAQ: %.1f Hz" % qdev_ard.obtained_DAQ_rate_Hz
        )
        if log.is_recording():
            self.qlbl_recording_time.setText(log.pretty_elapsed())

        self.qlin_ds18b20_temp.setText("%.1f" % state.ds18b20_temp)
        self.qlin_dht22_temp.setText("%.1f" % state.dht22_temp)
        self.qlin_dht22_humi.setText("%.1f" % state.dht22_humi)
        self.qlbl_title.setText(
            "Interior:  %.1f °C,  %.1f %%"
            % (state.dht22_temp, state.dht22_humi)
        )

        if state.is_valve_open:
            self.LED_is_valve_open.setText("1")
            self.LED_is_valve_open.setChecked(True)
        else:
            self.LED_is_valve_open.setText("0")
            self.LED_is_valve_open.setChecked(False)

    @QtCore.pyqtSlot()
    def update_chart(self):
        if DEBUG:
            tprint("update_chart")

        for tscurve in self.tscurves:
            tscurve.update()

# ------------------------------------------------------------------------------
#   Program termination routines
# ------------------------------------------------------------------------------

def stop_running():
    app.processEvents()
    qdev_ard.quit()
    log.close()

    print("Stopping timers................ ", end="")
    timer_GUI.stop()
    timer_charts.stop()
    print("done.")

@QtCore.pyqtSlot()
def notify_connection_lost():
    stop_running()

    window.qlbl_title.setText("! ! !    LOST CONNECTION    ! ! !")
    str_cur_date, str_cur_time, _ = get_current_date_time()
    str_msg = "%s %s\nLost connection to Arduino." % (
        str_cur_date,
        str_cur_time,
    )
    print("\nCRITICAL ERROR @ %s" % str_msg)
    reply_ = QtWid.QMessageBox.warning(
        window, "CRITICAL ERROR", str_msg, QtWid.QMessageBox.Ok
    )

    if reply_ == QtWid.QMessageBox.Ok:
        pass  # Leave the GUI open for read-only inspection by the user

@QtCore.pyqtSlot()
def about_to_quit():
    print("\nAbout to quit")
    stop_running()
    ard.close()

# ------------------------------------------------------------------------------
#   Your Arduino update function
# ------------------------------------------------------------------------------

def DAQ_function():
    # Date-time keeping
    str_cur_date, str_cur_time, str_cur_datetime = get_current_date_time()

    # Query the Arduino for its state
    success_, tmp_state = ard.query_ascii_values("?", delimiter="\t")
    if not (success_):
        dprint(
            "'%s' reports IOError @ %s %s"
            % (ard.name, str_cur_date, str_cur_time)
        )
        return False

    # Parse readings into separate state variables
    try:
        (
            state.time,
            state.ds18b20_temp,
            state.dht22_temp,
            state.dht22_humi,
            state.is_valve_open,
        ) = tmp_state
        state.time /= 1000  # Arduino time, [msec] to [s]
        state.is_valve_open = bool(state.is_valve_open)
    except Exception as err:
        pft(err, 3)
        dprint(
            "'%s' reports IOError @ %s %s"
            % (ard.name, str_cur_date, str_cur_time)
        )
        return False

    # We will use PC time instead
    state.time = time.perf_counter()

    # Add readings to chart histories
    window.tscurve_ds18b20_temp.appendData(state.time, state.ds18b20_temp)
    window.tscurve_dht22_temp.appendData(state.time, state.dht22_temp)
    window.tscurve_dht22_humi.appendData(state.time, state.dht22_humi)

    # Logging to file
    log.update(filepath=str_cur_datetime + ".txt", mode="w")

    # Return success
    return True

def write_header_to_log():
    log.write("[HEADER]\n")
    log.write(window.qtxt_comments.toPlainText())
    log.write("\n\n[DATA]\n")
    log.write("time\tDS18B20 temp.\tDHT22 temp.\tDHT22 humi.\tvalve\n")
    log.write("[s]\t[±0.5 °C]\t[±0.5 °C]\t[±3 pct]\t[0/1]\n")

def write_data_to_log():
    log.write(
        "%.1f\t%.1f\t%.1f\t%.1f\t%i\n"
        % (
            log.elapsed(),
            state.ds18b20_temp,
            state.dht22_temp,
            state.dht22_humi,
            state.is_valve_open,
        )
    )

# ------------------------------------------------------------------------------
#   Main
# ------------------------------------------------------------------------------

if __name__ == "__main__":
    # Set priority of this process to maximum in the operating system
    print("PID: %s\n" % os.getpid())
    try:
        proc = psutil.Process(os.getpid())
        if os.name == "nt":
            proc.nice(psutil.REALTIME_PRIORITY_CLASS)  # Windows
        else:
            proc.nice(-20)  # Other
    except:
        print("Warning: Could not set process to maximum priority.\n")

    # --------------------------------------------------------------------------
    #   Connect to Arduino
    # --------------------------------------------------------------------------

    ard = Arduino(name="Ard", connect_to_specific_ID="Ambre chamber")
    ard.serial_settings["baudrate"] = 115200
    ard.auto_connect()

    if not (ard.is_alive):
        print("\nCheck connection and try resetting the Arduino.")
        print("Exiting...\n")
        sys.exit(0)

    # Get the initial state of the valve control
    success, reply = ard.query("th?")
    if success:
        state.humi_threshold = float(reply)

    success, reply = ard.query("open when super humi?")
    if success:
        state.open_valve_when_super_humi = bool(int(reply))

    # --------------------------------------------------------------------------
    #   Create application and main window
    # --------------------------------------------------------------------------
    QtCore.QThread.currentThread().setObjectName("MAIN")  # For DEBUG info

    app = QtWid.QApplication(sys.argv)
    app.aboutToQuit.connect(about_to_quit)

    window = MainWindow()

    # --------------------------------------------------------------------------
    #   File logger
    # --------------------------------------------------------------------------

    log = FileLogger(
        write_header_function=write_header_to_log,
        write_data_function=write_data_to_log,
    )
    log.signal_recording_started.connect(
        lambda filepath: window.qpbt_record.setText(
            "Recording to file: %s" % filepath
        )
    )
    log.signal_recording_stopped.connect(
        lambda: window.qpbt_record.setText("Click to start recording to file")
    )

    # --------------------------------------------------------------------------
    #   Set up multithreaded communication with the Arduino
    # --------------------------------------------------------------------------

    # Create QDeviceIO
    qdev_ard = QDeviceIO(ard)

    # Create workers
    # fmt: off
    qdev_ard.create_worker_DAQ(
        DAQ_function             = DAQ_function,
        DAQ_interval_ms          = DAQ_INTERVAL_MS,
        critical_not_alive_count = 1,
        debug                    = DEBUG,
    )
    # fmt: on
    qdev_ard.create_worker_jobs()

    # Connect signals to slots
    qdev_ard.signal_DAQ_updated.connect(window.update_GUI)
    qdev_ard.signal_connection_lost.connect(notify_connection_lost)

    # Start workers
    qdev_ard.start(DAQ_priority=QtCore.QThread.TimeCriticalPriority)

    # --------------------------------------------------------------------------
    #   Timers
    # --------------------------------------------------------------------------

    timer_GUI = QtCore.QTimer()
    timer_GUI.timeout.connect(window.update_GUI)
    timer_GUI.start(100)

    timer_charts = QtCore.QTimer()
    timer_charts.timeout.connect(window.update_chart)
    timer_charts.start(CHART_INTERVAL_MS)

    # --------------------------------------------------------------------------
    #   Start the main GUI event loop
    # --------------------------------------------------------------------------

    window.show()
    sys.exit(app.exec_())


import cv2
import numpy as np
from imageclassifier import ImageClassifier

n_clusters = [3, 4, 5, 6, 7, 8]
kmeans_keys = [
    [0], [1], [2],
    [0, 1], [0, 2], [1, 2],
    [0, 1, 2]
]

sorting_lambdas = [
    lambda pixel: pixel[0],
    lambda pixel: pixel[1],
    lambda pixel: pixel[2],
    lambda pixel: sum(pixel),
    lambda pixel: max(pixel)
]

cl_sorting_lambdas = [
    lambda cluster: cluster[0][0][0],
    lambda cluster: cluster[0][0][1],
    lambda cluster: cluster[0][0][2],
    lambda cluster: sum(cluster[0][0]),
    lambda cluster: max(cluster[0][0])
]

coeffs = []
for i in range(5):
    for j in range(5):
        for k in range(5):
            coeffs.append([i, j, k])

sorting_keys = [i for i in range(len(sorting_lambdas))]

colorspaces = [None, cv2.COLOR_BGR2HSV, cv2.COLOR_BGR2LAB, cv2.COLOR_BGR2HLS]

def str_colorspace(colorspace):
    if colorspace == None:
        return "BGR"
    if colorspace == cv2.COLOR_BGR2HSV:
        return "HSV"
    if colorspace == cv2.COLOR_BGR2LAB:
        return "LAB"
    if colorspace == cv2.COLOR_BGR2HLS:
        return "HLS"

def save(folder, img, n_cluster, key, color_in, sorting_key, color_sort):

    filename = folder + "/c{0}_k".format(n_cluster)
    filename = filename + '-'.join([str(s) for s in key])
    filename = filename + '_' + str_colorspace(color_in) + "_"
    filename = filename + 's{0}_'.format(sorting_key)
    filename = filename + str_colorspace(color_sort) + ".png"
    cv2.imwrite(filename, img)
    print("saved: " + filename)

def bruteforce(target, folder):
    for n_cluster in n_clusters:
        classifier = ImageClassifier(n_cluster, target)
        for color_in in colorspaces:
            df = classifier.get_dataframe(colorspace=color_in)
            for key in kmeans_keys:
                cluster_map = classifier.run_kmeans(df, key)
                clusters = classifier.get_clusters(cluster_map)
                clusters_bak = clusters.copy()
                for color_sort in colorspaces:
                        for sorting_key in sorting_keys:
                            cmp1 = sorting_lambdas[sorting_key]
                            cmp2 = cl_sorting_lambdas[sorting_key]
                            clusters = classifier.sort_clusters(clusters, cmp1, color_sort=color_sort)
                            res = classifier.merge_clusters(clusters, cmp2)
                            save(folder, res, n_cluster, key, color_in, sorting_key, color_sort)
                            clusters = clusters_bak.copy()

def process():
    n_cluster = 4
    classifier = ImageClassifier(n_cluster, 'src.jpg')
    df = classifier.get_dataframe(colorspace=cv2.COLOR_BGR2HSV)
    cluster_map = classifier.run_kmeans(df, [0])
    clusters = classifier.get_clusters(cluster_map)

    clusters_bak = clusters.copy()

    #cmp = lambda pixel: (255 - int(pixel[1])) * 2 - (200 if pixel[1] < pixel[2] else 0)
    cmp = lambda pixel: int(pixel[0])
    #cmp = lambda pixel: pixel[1]
    clusters = classifier.sort_clusters(clusters, cmp, color_sort=cv2.COLOR_BGR2LAB)
    res = classifier.merge_clusters(clusters, lambda cluster: sum(cluster[0][0]))
    #filename = 'res_sort/res_{0}_{1}_{2}.png'.format(coeff[0], coeff[1], coeff[2])
    filename="res.png"
    cv2.imwrite(filename, res)
    print('saved {0}'.format(filename))

    clusters = clusters_bak.copy()

def compare(target1, target2):

    cl1 = ImageClassifier(4, target1)
    cl2 = ImageClassifier(4, target2)

    df1 = cl1.get_dataframe()
    df2 = cl2.get_dataframe()

    print(df1.describe())
    print(df2.describe())
    exit()
    img1 = cv2.imread(target1)
    img2 = cv2.imread(target2)
    shape1 = img1.shape
    shape2 = img2.shape

    img1 = np.reshape(img1, (shape1[0] * shape1[1], 3))
    img2 = np.reshape(img2, (shape2[0] * shape2[1], 3))

    img1 = sorted(img1, key = lambda pixel: sum(pixel))
    img2 = sorted(img2, key = lambda pixel: sum(pixel))

    img1 = np.reshape(img1, (shape1))
    img2 = np.reshape(img2, (shape2))

    cv2.imwrite('img1.png', img1)
    cv2.imwrite('img2.png', img2)

# bruteforce("town.jpg", "result/town")
# compare("res.png", "town.jpg")
process()


import gspread
import numpy as np
import pandas as pd
from datetime import date
from datetime import datetime
import csv
import pytz
from oauth2client.service_account import ServiceAccountCredentials
import requests
#authorization
service_account = gspread.service_account(filename = 'capstone-362722-f3745d9260b7.json' )

worksheet = service_account.open('TeamLiftCyberPhysical').sheet1
rows = worksheet.row_count

scope = ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/spreadsheets"]
credentials = ServiceAccountCredentials.from_json_keyfile_name('capstone-362722-f3745d9260b7.json', scope)

gc = gspread.authorize(credentials)
wb = gc.open_by_url('https://docs.google.com/spreadsheets/d/10g0fkjjrK0k9sa_ynw3O0Stdfp3leNJiJWS0MOM_b94/edit#gid=0')

#this function gets the last time the spreadsheet was updated
def getLastTimeModified():
    revisions_uri = f'https://www.googleapis.com/drive/v3/files/{wb.id}/revisions'
    headers = {'Authorization': f'Bearer {credentials.get_access_token().access_token}'}
    response = requests.get(revisions_uri, headers=headers).json()
    return response['revisions'][-1]['modifiedTime']

#this function adds data row to spreadsheets with given params
def addData(rowEntry):
    worksheet.append_row(rowEntry)

#sends a csv file line by line to the spreadhseets file on the cloud
def sendFile(filename):
    #mod_time_before = getLastTimeModified()
    sent_data = np.loadtxt(filename,delimiter=",",dtype = str, ndmin = 2)

    #lines= data_file.readlines()
    #for iter in range(len(lines)):
        #lines[iter] = lines[iter].replace('\n' , '')
        #lines[iter] = lines[iter].split(',')
    worksheet.append_rows(sent_data.tolist());
    print("sent to spreadsheet");

def replaceNewline(str):
    return str.replace("\n","")

#this function gets acknowledgement from google spreadsheets, by retreiving the last n-nows that were previously populated on the spreadsheet
# and doing an elementwise comparison with the numpy array that was just sent
def getSpreadsheetAck(filename):
    ackSuccess = False
    agg_array= np.loadtxt(filename,delimiter=",",dtype=str, ndmin = 2)
    print(agg_array)
    rowsSent = np.shape(agg_array)[0]
    colsSent = np.shape(agg_array)[1]
    #rowsSent =  np.shape(agg_array)[0]
    #colsSent = 3
    #if(len(np.shape(agg_array)) == 2):
        #colsSent = np.shape(agg_array)[1]
    #else:
        #colsSent = len(agg_array)

    all_data = np.array(worksheet.get_all_values())
    all_data_rows = np.shape(all_data)[0]
    numRemoteFields = np.shape(all_data)[1]
    print("rowsSent = ",rowsSent,"colsSent = ",colsSent,"rows in database= ", all_data_rows)
    if((numRemoteFields - 1) == rowsSent):
        print("The Number of Fields match between the local and remote database")
    remote_array = all_data[all_data_rows -rowsSent :all_data_rows:1 , 0:colsSent]

    print(remote_array)
    correctDataSent = np.array_equal(agg_array,remote_array)
    if(correctDataSent == True):
        print("The Correct Data was sent to the Database\n")
        ackSuccess = True

    if(correctDataSent == False):
         print("The Wrong Data was Sent\n")
         print("Attempting to send data again")
         print(agg_array == remote_array)
         ackSuccess = False
    return ackSuccess

        # timezone_oregon = pytz.timezone('US/Pacific')
        # time_now = (datetime.now(timezone_oregon)).strftime('%Y-%m-%d %H:%M:%S')
        # print("Data Was Updated at " + str(time_now) )

#this function updates a row in the spreadsheets file, by looking up the value of a column
#parameter columtype is the column of the data we are updating
#column val is the value of the column to look for
#rowdata is the new data that we are updating it to
def updateData(columntype,columnval,rowdata):
    mod_time_before = getLastTimeModified()
    #gets all the tabulated data is a 2D array
    full_data = worksheet.get_all_values()

    # print(full_data)
    num_rows = len(full_data)
    index = 0
    #depending on the columntype, we assign an index,
    #this index tells us which column to look inside of
    if(columntype == 'pumpvelocity'):
        index = 0
    if(columntype == 'pressure'):
        index = 1

    if(columntype == 'timestamp'):
        index = 2

    #iterates through data
    for k in range(0,num_rows):
        # print((worksheet.row_values(k))[index])
        #finds the row with the target value
        #updates that row's data with new values
        if((full_data[k])[index] == columnval):
            # print("yes")
            worksheet.update_cell(k+1,1,rowdata[0])
            worksheet.update_cell(k+1,2,rowdata[1])
            worksheet.update_cell(k+1,3,rowdata[2])
            break
    mod_time_after = getLastTimeModified()
    print("mod time before update",mod_time_before)
    print("mod time after update",mod_time_after)
    if(mod_time_before != mod_time_after):
        print("Modified at ",mod_time_after )

#this method fetches a data point given the value of a certain column
#for example it might search the data point where flow is equal to 55
def getRecord(columntype,columnval):
    full_data = worksheet.get_all_values()

    # print(full_data)
    num_rows = len(full_data)
    index = 0
    if(columntype == 'pumpvelocity'):
        index = 0
    if(columntype == 'pressure'):
        index = 1

    if(columntype == 'timestamp'):
        index = 2

    #iterates through data and returns data point that has certain value
    for k in range(0,num_rows):
        # print((worksheet.row_values(k))[index])
        if((full_data[k])[index] == columnval):
            # print("yes")
            print(full_data[k])
            record = full_data[k]
            printed_record = {"pumpvelocity":record[0],"pressure":record[1],"timestamp":record[2] }
            print(printed_record)
            return printed_record


from flask import Flask
from flask_apscheduler import APScheduler

# config scheduling class
from statuschecker import get_health_status

class Config(object):
    JOBS = [
        {
            'id': 'check_health',
            'func': 'app:check_health',
            'trigger': 'interval',
            'seconds': 1800
        }
    ]

    SCHEDULER_API_ENABLED = True

# function triggered every 30 minutes
def check_health():
    return get_health_status();

# flask startup
app = Flask(__name__)
app.config.from_object(Config())

# initiate scheduler
scheduler = APScheduler()
scheduler.init_app(app)
scheduler.start()

if __name__ == '__main__':
    app.run(host='0.0.0.0')


import functools
import os
import sys
from typing import Any, Callable, Iterable, Optional, TextIO, Tuple

import click
from click import Command
from click_option_group import MutuallyExclusiveOptionGroup

from . import __version__
from .core import (
    CheckHashLineError,
    HashFileReader,
    HashFileWriter,
    ParseHashLineError,
    check_hash_line,
    generate_hash_line,
)
from .hasher import HashContext, Hasher
from .utils.click import CommandX, PathWithSuffix
from .utils.glob import glob_filters, sorted_path

class ParseHashFileError(ValueError):
    def __init__(self, hash_line: str, lineno: int) -> None:
        super().__init__(hash_line, lineno)
        self.hash_line = hash_line
        self.lineno = lineno

class Output:
    """Determine the output mode and provide the output interface."""

    def __init__(
        self, agg: Optional[str] = None, sep: Optional[bool] = None, null: Optional[bool] = None, sync: bool = False
    ) -> None:
        if (agg and sep) or (agg and null) or (sep and null):
            raise ValueError("require exactly one argument")

        # Use the null mode by default.
        if not (agg or sep or null):
            null = True

        # Determine the output mode and dump method.
        if agg:
            self.agg_file = HashFileWriter(agg)
            self._dump = self.output_agg
        elif sep:
            self._dump = self.output_sep
        elif null:
            self._dump = self.output_null

        self.sync = sync
        self.maxmtime = 0.0

    def close(self) -> None:
        try:
            agg_file = self.agg_file
        except AttributeError:
            pass
        else:
            agg_file.close()
            if self.sync:
                os.utime(agg_file.name, (self.maxmtime, self.maxmtime))

    def dump(self, hash_line: str, hash_path: str, path: str) -> None:
        self._dump(hash_line, hash_path, path)

    def output_agg(self, hash_line: str, hash_path: str, path: str) -> None:
        self.agg_file.write_hash_line(hash_line)
        if self.sync:
            mtime = os.path.getmtime(path)
            self.maxmtime = max(self.maxmtime, mtime)

    def output_sep(self, hash_line: str, hash_path: str, path: str) -> None:
        with HashFileWriter(hash_path) as f:
            f.write_hash_line(hash_line)
        if self.sync:
            mtime = os.path.getmtime(path)
            os.utime(hash_path, (mtime, mtime))

    def output_null(self, hash_line: str, hash_path: str, path: str) -> None:
        pass

class Gethash:
    """Provide uniform interface for CLI scripts."""

    stdout: TextIO
    stderr: TextIO

    glob_mode: int
    glob_type: str

    inplace: bool
    root: Optional[str]

    start: Optional[int]
    stop: Optional[int]
    dir_ok: bool

    def __init__(self, ctx: HashContext, **kwargs: Any) -> None:
        self.ctx = ctx
        self.sync = kwargs.pop("sync", False)
        self.suffix = kwargs.pop("suffix", ".sha")

        self.stdout = kwargs.pop("stdout", sys.stdout)
        self.stderr = kwargs.pop("stderr", sys.stderr)

        self.glob_mode = kwargs.pop("glob", 1)
        self.glob_type = kwargs.pop("type", "a")

        # Determine the path format.
        self.inplace = kwargs.pop("inplace", False)
        self.root = kwargs.pop("root", None)

        # Determine the output mode.
        agg = kwargs.pop("agg", None)
        sep = kwargs.pop("sep", None)
        null = kwargs.pop("null", None)
        self.output = Output(agg, sep, null, sync=self.sync)

        # Prepare arguments and construct the hash function.
        self.start = kwargs.pop("start", None)
        self.stop = kwargs.pop("stop", None)
        self.dir_ok = kwargs.pop("dir", False)
        tqdm_args = {
            "file": self.stderr,
            "ascii": kwargs.pop("tqdm_ascii", False),
            "disable": kwargs.pop("tqdm_disable", False),
            "leave": kwargs.pop("tqdm_leave", False),
        }
        self.hasher = Hasher(ctx, tqdm_args=tqdm_args)

    def __call__(self, files: Iterable[str], *, check: bool) -> None:
        if check:
            self.check_hash(files)
        else:
            self.generate_hash(files)

    def __enter__(self) -> "Gethash":
        return self

    def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
        self.close()

    def close(self) -> None:
        self.output.close()

    def generate_hash(self, patterns: Iterable[str]) -> None:
        for path in self.glob_function(patterns):
            try:
                root = self.check_root(path)
                hash_line = generate_hash_line(path, self.hash_function, root=root)
                hash_path = path + self.suffix
                self.output.dump(hash_line, hash_path, path)
            except Exception as e:
                self.echo_exception(path, e)
            else:
                # The hash line already has a newline.
                self.echo(hash_line, nl=False)

    def check_hash(self, patterns: Iterable[str]) -> None:
        for hash_path in self.glob_function(patterns):
            try:
                self._check_hash(hash_path)
            except ParseHashFileError as e:
                # Strip newline for pretty printing.
                hash_line = e.hash_line.rstrip("\n")
                msg = f"[ERROR] invalid hash '{hash_line}' in '{hash_path}' at line {e.lineno}"
                self.echo_error(msg, fg="white", bg="red")
            except Exception as e:
                self.echo_exception(hash_path, e)

    def _check_hash(self, hash_path: str) -> None:
        maxmtime = 0.0
        for i, hash_line in enumerate(HashFileReader(hash_path)):
            try:
                root = self.check_root(hash_path)
                path = check_hash_line(hash_line, self.hash_function, root=root)
                maxmtime = max(maxmtime, os.path.getmtime(path))
            except ParseHashLineError as e:
                raise ParseHashFileError(e.hash_line, i)
            except CheckHashLineError as e:
                self.echo(f"[FAILURE] {e.path}", fg="red")
            else:
                self.echo(f"[SUCCESS] {path}", fg="green")
        if self.sync:
            os.utime(hash_path, (maxmtime, maxmtime))

    def check_root(self, path: str) -> Optional[str]:
        if self.inplace:
            return os.path.dirname(path)
        return self.root

    def glob_function(self, paths: Iterable[str]) -> Iterable[str]:
        return sorted_path(
            glob_filters(paths, mode=self.glob_mode, type=self.glob_type, recursive=True, user=True, vars=True)
        )

    def hash_function(self, path: str) -> bytes:
        return self.hasher(path, self.start, self.stop, dir_ok=self.dir_ok)

    def echo(self, msg: str, **kwargs: Any) -> None:
        click.secho(msg, file=self.stdout, **kwargs)

    def echo_error(self, msg: str, **kwargs: Any) -> None:
        click.secho(msg, file=self.stderr, **kwargs)

    def echo_exception(self, path: str, exc: Exception) -> None:
        msg = f"[ERROR] {path}\n\t{type(exc).__name__}: {exc}"
        click.secho(msg, file=self.stderr, fg="red")

def script_main(ctx: HashContext, files: Tuple[str, ...], **options: Any) -> None:
    """Execute the body for the main function."""

    no_stdout = options.pop("no_stdout", False)
    no_stderr = options.pop("no_stderr", False)
    stdout = open(os.devnull, "w") if no_stdout else sys.stdout  # noqa
    stderr = open(os.devnull, "w") if no_stderr else sys.stderr  # noqa

    check = options.pop("check", False)
    with Gethash(ctx, stdout=stdout, stderr=stderr, **options) as gethash:
        gethash(files, check=check)

def gethashcli(command_name: str, display_name: str, **extras: Any) -> Callable[[Callable], Command]:
    """Apply click decorators to the main function."""

    suffix = extras.pop("suffix", "." + command_name.replace("-", "_"))
    doc = extras.pop("doc", None)

    def decorator(func: Callable) -> Command:
        if doc is not None:
            func.__doc__ = doc

        context_settings = {"help_option_names": ["-h", "--help"], "max_content_width": 120}

        path_format = MutuallyExclusiveOptionGroup("Path Format")
        output_mode = MutuallyExclusiveOptionGroup("Output Mode")

        @click.command(command_name, cls=CommandX, context_settings=context_settings, no_args_is_help=True)
        @click.argument("files", nargs=-1)
        @click.option(
            "-c",
            "--check",
            is_flag=True,
            help=f"Read {display_name} from FILES and check them.",
        )
        @click.option(
            "-y",
            "--sync",
            is_flag=True,
            help="Update mtime of hash files to the same as data files.",
        )
        @click.option(
            "-g",
            "--glob",
            type=click.IntRange(0, 2),
            metavar="[0|1|2]",
            default=1,
            show_default=True,
            help="Set glob mode. If ``0``, disable glob pathname pattern; if ``1``, "
            "resolve ``*`` and ``?``; if ``2``, resolve ``*``, ``?`` and ``[]``.",
        )
        @click.option(
            "-t",
            "--type",
            type=click.Choice(["a", "d", "f"]),
            default="a",
            show_default=True,
            help="Set file type. If ``a``, include all types; if ``d``, include "
            "directories; if ``f``, include files.",
        )
        @path_format.option("-i", "--inplace", is_flag=True, help="Use basename in checksum files.")
        @path_format.option(
            "-z",
            "--root",
            type=click.Path(exists=True, file_okay=False),
            help="The path field in checksum files is relative to the root directory.",
        )
        @output_mode.option(
            "-o",
            "--agg",
            type=PathWithSuffix(suffix=suffix, dir_okay=False),
            help="Set the aggregate output file.",
        )
        @output_mode.option("-s", "--sep", is_flag=True, help="Separate output files.")
        @output_mode.option(
            "-n",
            "--null",
            is_flag=True,
            help="Do not output to files. This is the default output mode.",
        )
        @click.option("--start", type=click.IntRange(min=0), help="The start offset of files.")
        @click.option("--stop", type=click.IntRange(min=0), help="The stop offset of files.")
        @click.option(
            "-d",
            "--dir",
            is_flag=True,
            help="Allow checksum for directories. Just xor each checksum of files in a given directory.",
        )
        @click.option("--no-stdout", is_flag=True, help="Do not output to stdout.")
        @click.option("--no-stderr", is_flag=True, help="Do not output to stderr.")
        @click.option("--tqdm-ascii", type=click.BOOL, default=False, show_default=True)
        @click.option("--tqdm-disable", type=click.BOOL, default=False, show_default=True)
        @click.option("--tqdm-leave", type=click.BOOL, default=False, show_default=True)
        @click.version_option(__version__, "-V", "--version", prog_name=command_name)
        @functools.wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            kwargs.setdefault("suffix", suffix)
            return func(*args, **kwargs)

        return wrapper

    return decorator


import os
import sys
import time

from acbbs.drivers.ate.ClimCham import ClimCham
from acbbs.drivers.ate.DCPwr import DCPwr
from acbbs.drivers.ate.PwrMeter import PwrMeter
from acbbs.drivers.ate.RFSigGen import RFSigGen
from acbbs.drivers.ate.RFSigGenV import RFSigGenV
from acbbs.drivers.ate.SpecAn import SpecAn
from acbbs.drivers.ate.Swtch import Swtch
from acbbs.tools.log import get_logger
from pymongo import MongoClient
from pymongo.errors import ServerSelectionTimeoutError, DuplicateKeyError

import configuration
from .drivers.PwrMeterCal import PowerMeterCal
from .drivers.RFSigGenCal import RFSigGenCal

logger = get_logger('calib')

CHANNELS = configuration.CHANNELS
INPUTS = configuration.INPUTS
OUTPUTS = configuration.OUTPUTS

CONF_PATH = configuration.CONF_PATH

LIST_PATH = configuration.LIST_PATH

class NetworkEquipment(object):
    def __init__(self, simu):
        logger.info('class Ping init')
        self.PwrMeter = PwrMeter(simulate=simu)
        self.SpecAn = SpecAn(simulate=simu)
        self.RFSigGen = RFSigGen(simulate=simu)
        self.RFSigGenV = RFSigGenV(simulate=simu)
        self.Swtch = Swtch(simulate=simu)
        self.ClimCham = ClimCham(simulate=simu)
        self.DCPwr = DCPwr(simulate=simu)
        self.PwrMeterCal = PowerMeterCal(simulate=simu)
        self.RFSigGenCal = RFSigGenCal(simulate=simu)

        self.get_ip()

    def get_ip(self):
        ip_specAn = self.SpecAn.SpecAnConf['ip']
        ip_sigGen = self.RFSigGen.sigGenConf['ip']
        ip_pwMeter = self.PwrMeter.PwrMeterConf['ip']
        ip_sigGenV = self.RFSigGenV.sigGenConf['ip']
        ip_ClimCham = self.ClimCham.dcConf['ip']
        ip_dc1 = self.DCPwr.dcConf['powerDevice1-ip']
        ip_dc2 = self.DCPwr.dcConf['powerDevice2-ip']

        self.listIP = {'rx': {'RFSigGen': ip_sigGen, 'RFSigGenV': ip_sigGenV},
                       'tx': {'PwrMeter': ip_pwMeter, 'SpecAn': ip_specAn},
                       'DC': {'DC1': ip_dc1, 'DC2': ip_dc2},
                       'Chamber': {'climCham': ip_ClimCham},
                       }

    def ping_one(self, IP):
        response = os.system("ping -c 1 " + IP)
        if response == 0:
            logger.info("Network Equipement Active at adresse:{0}".format(IP))
            return 0
        else:
            logger.error('Network Equipement Error : {0}'.format(IP))
            return 1

    def check_one_instrument(self, instrum):
        global result
        for mode, instrums in self.listIP.items():
            if instrum in instrums.keys():
                result = self.ping_one(self.listIP[mode][instrum])
                break
        return result

    def ping_all(self):
        list_pingReturn = self.listIP
        for mode, instrums in self.listIP.items():
            for instrum, ip in instrums.items():
                list_pingReturn[mode][instrum] = self.ping_one(ip)
        return list_pingReturn

    def check_all_instruments(self):
        listPing = self.ping_all()
        if all(i == 0 for i in listPing):
            return 0
        else:
            return 1  # renvoyer un tableau qui indique quel instrument est disconnected

class database(object):

    def __init__(self):
        self.__openDataBase()

    def __openDataBase(self):
        # get server, port and database from json configuration file
        server = configuration.DATABASE_IP
        port = configuration.DATABASE_PORT
        database = configuration.DATABASE_NAME_CALIB
        maxSevSelDelay = configuration.DATABASE_MAXDELAY

        try:
            # open MongoDB server
            self.client = MongoClient(server, int(port), serverSelectionTimeoutMS=maxSevSelDelay)

            # check if connection is well
            self.client.server_info()
        except ServerSelectionTimeoutError as err:
            print("{0}".format(err))
            exit(0)

        # open MongoDB database
        self.db = self.client[database]

    def get_available_collection(self):
        return self.db.list_collection_names()

    def get_collection(self, collection):
        if collection not in self.get_available_collection():
            print("Error: conf {0} does not exist. You can list available collection with --list".format(collection))
        return self.db[collection].find({})

    def writeDataBase(self, document, collection):
        if collection in self.get_available_collection():
            print("Error: conf {0} exist. You can delete it with --delete {0}".format(collection))

        self.db_collection = self.db[collection]
        try:
            self.db_collection.insert_one(document).inserted_id
        except DuplicateKeyError as err:
            print("{0}".format(err))

    def delete_collection(self, collection):
        if collection not in self.get_available_collection():
            print("Error: conf {0} does not exist. You can list available collection with --list".format(collection))
        self.db.drop_collection(collection)

class MatrixCal(object):
    def __init__(self):
        self.calibFile = {"date": "", "loss": {}}
        self.db = database()

    def get_cal(self, date):
        for doc in self.db.get_collection(date):
            calibFile = doc
        return calibFile

    def getlossPath(self, port_in, port_out, date):
        cal = self.get_cal(date)
        data = cal[port_in][port_out]
        return data

    def write_cal(self, data):
        self.calibFile["loss"] = data
        self.calibFile["date"] = time.strftime("%Y-%m-%d %H:%M:%S")
        self.db.writeDataBase(self.calibFile["loss"], self.calibFile["date"])

    def readPath_loss(self, port_in, port_out):
        return self.data["loss"][port_in][port_out]

    def del_cal(self, cal_name):
        self.db.delete_collection(cal_name)

    def history(self):
        return self.db.get_available_collection()

class Calibration(object):
    def __init__(self, simu):
        self.equipement = NetworkEquipment(simu=simu)
        self.channels = CHANNELS
        self.simu = simu

        self.iteration = 0
        self.totalProgress = 0

        self.paths = LIST_PATH

        self.message = ""
        self.response = 0

        self.matrixCal = MatrixCal()

        self.loss = {INPUTS[4]: {}, INPUTS[2]: {}, INPUTS[3]: {}, INPUTS[0]: {}, INPUTS[1]: {}, INPUTS[5]: {}}
        self.delta = {}

        self.pathlist = list()
        for i in self.paths.keys():
            self.pathlist.append(i)

    def calibrate(self, tab_freq, pwr):
        self.tab_freq = tab_freq
        self.OUTPUT_POWER_CALIBRATION = int(pwr)

        self.totalProgress = (len(INPUTS) - 2 + len(OUTPUTS)) * len(tab_freq)

        print('calibration start')
        self.SMBCal()
        self.SMBVCal()
        self.PwrMeterCal()
        self.FSWCal()
        self.NoiseCal()

        self.makeDelta()
        self.makeMatrixCal()

        self.matrixCal.write_cal(self.loss)

    def SMBCal(self):
        loss = configuration.PORT_SMB
        pathJ4Jx = self.pathlist[1]

        # calibration of J4_20dB - J9
        print("calibration of SMB, plug the power meter cal to J9")
        while self.response == 0:
            self.message = " calibration of SMB, plug the power meter cal to J9 "
            time.sleep(0.8)
            print('wait')
        self.message = ""
        self.response = 0

        self.equipement.Swtch.setSwitch(sw1=1, sw3=self.paths[pathJ4Jx]["sw3"], sw4=self.paths[pathJ4Jx]["sw4"])
        for freq in self.tab_freq:
            self.equipement.RFSigGen.freq = freq
            self.equipement.RFSigGen.power = self.OUTPUT_POWER_CALIBRATION
            self.equipement.RFSigGen.status = 1
            time.sleep(1)
            loss["J4_20dB"][str(freq)] = self.OUTPUT_POWER_CALIBRATION - self.equipement.PwrMeterCal.power(nbr_mes=1)
            self.equipement.RFSigGen.status = 0
            self.iteration += 1
        self.loss["J4_20dB"]["J9"] = loss["J4_20dB"]

        # calibration of J4 - Jx
        for channel in self.channels:
            print(" plug the power meter cal to J{0}".format(channel + 8))

            while self.response == 0:
                self.message = " plug the power meter cal to {0}".format(channel + 8)
                time.sleep(0.8)
                print('wait')
            self.message = ""
            self.response = 0

            port = pathJ4Jx.replace("Jx", "J" + str(channel + 8))
            self.equipement.Swtch.setSwitch(sw1=channel, sw3=self.paths[pathJ4Jx]["sw3"],sw4=self.paths[pathJ4Jx]["sw4"])

            for freq in self.tab_freq:
                self.equipement.RFSigGen.freq = freq
                self.equipement.RFSigGen.power = self.OUTPUT_POWER_CALIBRATION
                self.equipement.RFSigGen.status = 1
                time.sleep(1)
                loss["J4"][str(freq)] = self.OUTPUT_POWER_CALIBRATION - self.equipement.PwrMeterCal.power(nbr_mes=1)
                self.equipement.RFSigGen.status = 0
                self.iteration += 1
            self.loss["J4"]["J" + str(channel + 8)] = loss["J4"]

    def SMBVCal(self):
        loss = configuration.PORT_SMBV
        pathJ3Jx = self.pathlist[3]

        print(" calibration of SMBV, plug the power meter of the cal to J9")

        while self.response == 0:
            self.message = "plug the power meter cal to J9 "
            time.sleep(0.8)
            print('wait')
        self.message = ""
        self.response = 0

        # calibration of J3 - J9
        self.equipement.Swtch.setSwitch(sw1=1, sw3=self.paths[pathJ3Jx]["sw3"], sw4=self.paths[pathJ3Jx]["sw4"])
        for freq in self.tab_freq:
            self.equipement.RFSigGenV.freq = freq
            self.equipement.RFSigGenV.power = self.OUTPUT_POWER_CALIBRATION
            # self.equipement.PowerMeterCal = freq
            self.equipement.RFSigGenV.status = 1
            time.sleep(1)
            loss["J3"][str(freq)] = self.OUTPUT_POWER_CALIBRATION - self.equipement.PwrMeterCal.power(nbr_mes=1)
            self.equipement.RFSigGenV.status = 0
            self.iteration += 1
        self.loss["J3"]["J9"] = loss["J3"]

    def PwrMeterCal(self):
        loss = configuration.PORT_PowerMeter
        pathJ2Jx = self.pathlist[5]

        print(" calibration of Power Meter, plug the RF generator cal to J9")

        while self.response == 0:
            self.message = "plug the RF generator cal to J9"
            time.sleep(0.8)
            print('wait')
        self.message = ""
        self.response = 0

        # calibration of J2 - J9
        self.equipement.Swtch.setSwitch(sw1=1, sw3=self.paths[pathJ2Jx]["sw3"], sw4=self.paths[pathJ2Jx]["sw4"])
        for freq in self.tab_freq:
            self.equipement.PwrMeter.freq = freq
            time.sleep(1)
            loss["J2"][str(freq)] = self.OUTPUT_POWER_CALIBRATION - self.equipement.PwrMeter.power
            self.iteration += 1
        self.loss["J2"]["J9"] = loss["J2"]

    def FSWCal(self):
        loss = configuration.PORT_FSW
        pathJ2Jx = self.pathlist[4]

        print(" calibration of FSW, plug the RF generator cal to J9")

        while self.response == 0:
            self.message = "plug the RF generator cal to J9"
            time.sleep(0.8)
            print('wait')
        self.message = ""
        self.response = 0

        # calibration of J5 - J9
        self.equipement.Swtch.setSwitch(sw1=1, sw3=self.paths[pathJ2Jx]["sw3"], sw4=self.paths[pathJ2Jx]["sw4"])
        for freq in self.tab_freq:
            self.equipement.SpecAn.freqSpan = 10000000
            pic = self.equipement.SpecAn.markerPeakSearch()
            time.sleep(1)
            loss["J5"][str(freq)] = self.OUTPUT_POWER_CALIBRATION - pic[1]
            self.iteration += 1
        self.loss["J5"]["J9"] = loss["J5"]

    ######### NON CODE ################
    def NoiseCal(self):
        loss = configuration.PORT_NOISE
        pathJ18Jx = self.pathlist[0]
        print(" calibration of Noise, plug the RF generator cal to J18 and the power meter to J9")

        while self.response == 0:
            self.message = "plug the RF generator cal to J18 and the power meter to J9"
            time.sleep(0.8)
            print('wait')
        self.message = ""
        self.response = 0

        # calibration of J5 - J9
        self.equipement.Swtch.setSwitch(sw1=1, sw3=self.paths[pathJ18Jx]["sw3"], sw4=self.paths[pathJ18Jx]["sw4"])
        for freq in self.tab_freq:
            loss["J18"][str(freq)] = self.OUTPUT_POWER_CALIBRATION
            self.iteration += 1
        self.loss["J18"]["J9"] = loss["J18"]

    def makeDelta(self):
        for channel in self.channels:
            Jout = "J" + str(channel + 8)
            delta_freq = {}
            self.delta[Jout] = {}
            for freq in self.tab_freq:
                delta_freq[str(freq)] = self.loss["J4"][Jout][str(freq)] - self.loss["J4"]["J9"][str(freq)]
            self.delta[Jout] = delta_freq

    def makeMatrixCal(self):
        for Jin in self.loss.keys():
            for channel in self.channels[1:]:
                Jout = "J" + str(channel + 8)
                self.loss[Jin][Jout] = {}
                estimate_loss = {}
                for freq in self.tab_freq:
                    estimate_loss[str(freq)] = self.loss[Jin]["J9"][str(freq)] + self.delta[Jout][str(freq)]
                self.loss[Jin][Jout] = estimate_loss


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
import embed_video.fields
from django.conf import settings

class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('tracks', '0006_auto_20150604_1856'),
    ]

    operations = [
        migrations.CreateModel(
            name='Video',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('title', models.CharField(default=b'untitled', max_length=128, verbose_name='Title')),
                ('video', embed_video.fields.EmbedVideoField(help_text=b'Link to youtube or vimeo', verbose_name='Video Link')),
                ('user', models.ForeignKey(related_name='videos', to=settings.AUTH_USER_MODEL)),
            ],
        ),
    ]


import os

from django.conf import settings
from django.db import connection, close_old_connections
from django.db.utils import OperationalError
from fastapi import FastAPI
from fastapi.responses import JSONResponse

from racetrack_client.utils.shell import shell, CommandError
from lifecycle.django.registry.database import db_access
from lifecycle.config import Config

def setup_health_endpoint(api: FastAPI, config: Config):

    @api.get("/live", tags=['root'])
    async def _live():
        """Report service liveness: whether it has started"""
        return {
            'service': 'lifecycle',
            'live': True,
        }

    @api.get("/ready", tags=['root'])
    async def _ready():
        """Report service readiness: whether it's available for accepting traffic"""
        return {
            'service': 'lifecycle',
            'ready': True,
        }

    @api.get("/health", tags=['root'])
    def _health():
        """Report current application status"""
        db_connected = is_database_connected()
        status_code = 200 if db_connected else 500
        content = {
            'service': 'lifecycle',
            'live': True,
            'ready': db_connected,
            'database_connected': db_connected,
            'git_version': os.environ.get('GIT_VERSION', 'dev'),
            'docker_tag': os.environ.get('DOCKER_TAG', ''),
            'auth_required': config.auth_required,
        }
        return JSONResponse(content=content, status_code=status_code)

@db_access
def is_database_connected() -> bool:
    try:
        django_db_type = os.environ.get('DJANGO_DB_TYPE', 'sqlite')
        if django_db_type == 'postgres':
            db_name = settings.DATABASES['default']['NAME']
            user = settings.DATABASES['default']['USER']
            host = settings.DATABASES['default']['HOST']
            port = settings.DATABASES['default']['PORT']
            shell(f'pg_isready -h {host} -p {port} -U {user} -d {db_name}', print_stdout=False)

        close_old_connections()
        with connection.cursor() as cursor:
            cursor.execute('select 1')
            cursor.fetchone()
            cursor.close()
        connection.close()
        return True
    except CommandError:
        return False
    except OperationalError:
        return False


import errno
import os
import requests
from pathlib import Path

import sly_globals as g
import supervisely as sly
from supervisely.app.v1.widgets.progress_bar import ProgressBar

progress5 = ProgressBar(g.task_id, g.api, "data.progress5", "Download weights", is_size=True, min_report_percent=5)

local_weights_path = None

def get_models_list():
    from train import model_list
    res = []
    for name, data in model_list.items():
        res.append({
            "model": name,
            "description": data["description"]
        })
    return res

def get_table_columns():
    return [
        {"key": "model", "title": "Model", "subtitle": None},
        {"key": "description", "title": "Description", "subtitle": None},
    ]

def get_model_info_by_name(name):
    models = get_models_list()
    for info in models:
        if info["model"] == name:
            return info
    raise KeyError(f"Model {name} not found")

def init(data, state):
    models = get_models_list()
    data["models"] = models
    data["modelColumns"] = get_table_columns()
    state["selectedModel"] = models[0]["model"]
    state["weightsInitialization"] = "random"  # "custom"
    state["collapsed5"] = True
    state["disabled5"] = True

    progress5.init_data(data)

    state["weightsPath"] = ""
    data["done5"] = False

def restart(data, state):
    data["done5"] = False

@g.my_app.callback("download_weights")
@sly.timeit
@g.my_app.ignore_errors_and_show_dialog_window()
def download_weights(api: sly.Api, task_id, context, state, app_logger):
    #"https://download.pytorch.org/models/vgg11-8a719046.pth" to /root/.cache/torch/hub/checkpoints/vgg11-8a719046.pth
    from train import model_list

    global local_weights_path
    try:
        if state["weightsInitialization"] == "custom":
            weights_path_remote = state["weightsPath"]
            if not weights_path_remote.endswith(".pth"):
                raise ValueError(f"Weights file has unsupported extension {sly.fs.get_file_ext(weights_path_remote)}. "
                                 f"Supported: '.pth'")

            # get architecture type from previous UI state
            prev_state_path_remote = os.path.join(str(Path(weights_path_remote).parents[1]), "info/ui_state.json")
            prev_state_path = os.path.join(g.my_app.data_dir, "ui_state.json")
            api.file.download(g.team_id, prev_state_path_remote, prev_state_path)
            prev_state = sly.json.load_json_file(prev_state_path)
            api.task.set_field(g.task_id, "state.selectedModel", prev_state["selectedModel"])

            local_weights_path = os.path.join(g.my_app.data_dir, sly.fs.get_file_name_with_ext(weights_path_remote))
            if sly.fs.file_exists(local_weights_path) is False:
                file_info = g.api.file.get_info_by_path(g.team_id, weights_path_remote)
                if file_info is None:
                    raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), weights_path_remote)
                progress5.set_total(file_info.sizeb)
                g.api.file.download(g.team_id, weights_path_remote, local_weights_path, g.my_app.cache, progress5.increment)
                progress5.reset_and_update()
        else:
            weights_url = model_list[state["selectedModel"]].get("pretrained")
            if weights_url is not None:
                default_pytorch_dir = "/root/.cache/torch/hub/checkpoints/"
                #local_weights_path = os.path.join(g.my_app.data_dir, sly.fs.get_file_name_with_ext(weights_url))
                local_weights_path = os.path.join(default_pytorch_dir, sly.fs.get_file_name_with_ext(weights_url))
                if sly.fs.file_exists(local_weights_path) is False:
                    response = requests.head(weights_url, allow_redirects=True)
                    sizeb = int(response.headers.get('content-length', 0))
                    progress5.set_total(sizeb)
                    os.makedirs(os.path.dirname(local_weights_path), exist_ok=True)
                    sly.fs.download(weights_url, local_weights_path, g.my_app.cache, progress5.increment)
                    progress5.reset_and_update()
                sly.logger.info("Pretrained weights has been successfully downloaded",
                                extra={"weights": local_weights_path})
    except Exception as e:
        progress5.reset_and_update()
        raise e

    fields = [
        {"field": "data.done5", "payload": True},
        {"field": "state.collapsed6", "payload": False},
        {"field": "state.disabled6", "payload": False},
        {"field": "state.activeStep", "payload": 6},
    ]
    g.api.app.set_fields(g.task_id, fields)

def restart(data, state):
    data["done5"] = False


# Licensed under a 3-clause BSD style license - see LICENSE
from __future__ import print_function, division

from astropy.table import Table, Column

from .import_modules import *

##----- ----- ----- ----- ----- ----- ----- ----- ----- -----##
## Miscellaneous utilities
## Contain functions that do not pertain to a particular class.
##----- ----- ----- ----- ----- ----- ----- ----- ----- -----##

def Fit_linear(y, x=None, err=1.0, m=None, b=None, output=None, inline=False):
    """
    Fit_linear(y, x=None, err=1.0, m=None, b=None, output=None, inline=False):
    return (sol, res, rank, s)
    Uses the scipy.linalg.lstsq function to solve the equation y = mx + b
    sol -> [b, m]
    N.B. Uses the scipy.linalg.lstsq algorithm.
    If inline = True, flattens the results.
    """
    #x = array([52997., 53210., 53310., 53380.])
    #y = array([1.66, 1.54, 1.4, 1.4])
    # standard error of the y-variable:
    #sy = array([0.05, 0.05, 0.05, 0.05])

    if x is None:
        x = np.arange(y.shape[0], dtype=float)
    if (b is not None) and (m is not None):
        sol = [b, m]
        res = (((b + m*x - y)/err)**2).sum()
        rank = 0.
        s = 0.
    else:
        if b is not None:
            A = np.reshape(x/err,(x.shape[0],1))
            y1 = y-b
            y1 /= err
            sol, res, rank, s = scipy.linalg.lstsq(A, y1)
            sol = [b,sol[0]]
        elif m is not None:
            A = np.resize(1/err,(x.shape[0],1))
            y1 = y-m*x
            y1 /= err
            sol, res, rank, s = scipy.linalg.lstsq(A, y1)
            sol = [sol[0],m]
        else:
            A = (np.vstack([np.ones(x.shape[0], dtype=float),x])/err).T
            y1 = y/err
            sol, res, rank, s = scipy.linalg.lstsq(A, y1)
    if output:
        b, m = sol
        fit_y = b + m*x
        print('b -> ' + str(b))
        print('m -> ' + str(m))
        print('Reduced chi-square: ' + str(res/(len(y)-rank)))
        plotxy(y, x, line=None, symbol=2, color=2)
        plotxy(fit_y, x)
    if res.shape == (0,):
        res = np.r_[0.]
    if inline:
        return np.hstack((sol, res, rank, s))
    else:
        return (sol, res, rank, s)

def Pprint(arr, show_index=False, max_lines=None):
    arr = np.atleast_2d(arr)
    if show_index:
        cols = np.arange(arr.shape[1]).astype(str)
        #rows = np.arange(arr.shape[0]).astype(str)
        rows = np.array([r+' |' for r in np.arange(arr.shape[0]).astype(str)])
        t = Table(data=arr, names=cols, copy=True)
        t.add_column(Column(data=rows, name=' '), index=0)
    else:
        t = Table(data=arr, copy=True)
    t.pprint(show_name=show_index, max_lines=max_lines)

def Sort_list(lst, cols):
    """Sort_list(lst, cols)
    Sorts inplace a list by multiple columns.

    lst: List to be sorted.
    cols: Columns to be sorted, cols[0] first,
        cols[1] second, etc.

    >>> lst = [(1,2,4),(3,2,1),(2,2,2),(2,1,4),(2,4,1)]
    >>> Sort_list(lst, [2,1])
    """
    from operator import itemgetter
    for keycolumn in reversed(cols):
        lst.sort(key=itemgetter(keycolumn))
    return


# Необходимо парсить страницу со свежими статьями (вот эту) и выбирать те статьи, в которых встречается хотя бы одно из ключевых слов (эти слова определяем в начале скрипта). Поиск вести по всей доступной preview-информации (это информация, доступная непосредственно с текущей страницы). Вывести в консоль список подходящих статей в формате: <дата> - <заголовок> - <ссылка>.

# определяем список ключевых слов
KEYWORDS = ['дизайн', 'фото', 'web', 'python']

import requests
from bs4 import BeautifulSoup
# from pprint import pprint
# import string
import re

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,sv;q=0.6',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
'Cookie': '_ym_uid=1661790138398573269; _ym_d=1661790138; habr_web_home_feed=/all/; hl=ru; fl=ru; _ym_isad=1; _ga=GA1.2.1864422457.1661790139; _gid=GA1.2.2059705457.1661790139; _gat_gtag_UA_726094_1=1',
'DNT': '1',
'Host': 'habr.com',
'Referer': 'https://yandex.ru/',
'sec-ch-ua': '"Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'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 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
}

url = 'https://habr.com'

responce = requests.get(url+'/ru/all', headers=headers)
text = responce.text

soup = BeautifulSoup(text, 'html.parser')

articles = soup.find_all(class_='tm-articles-list__item')

for article in articles:
    preview = article.find(class_=['article-formatted-body article-formatted-body article-formatted-body_version-2', 'article-formatted-body article-formatted-body article-formatted-body_version-1']).text

    # Вариант со сравнением множеств
    # for p in string.punctuation:
    #   if p in preview:
    #       preview = preview.replace(p, '')
    # preview = set(preview.split())

    # if preview & set(KEYWORDS):
      # data_1 = article.find(class_='tm-article-snippet__datetime-published')
      # data_2 = data_1.find('time')
      # data = data_2.attrs['title']
      # print(f'Дата статьи: {data}')
      # title = article.find(class_='tm-article-snippet__title-link').text.strip()
      # print(f'Название статьи: {title}')
      # link = article.find(class_='tm-article-snippet__title tm-article-snippet__title_h2')
      # link = link.find('a')
      # href = link.attrs['href']
      # print(f'Ссылка на статью: {url + href}')
      # print()

    # Вариант с регуляркой
    for i in KEYWORDS:
        if re.search(i, preview):
            data = article.find(class_='tm-article-snippet__datetime-published').find('time').attrs['title']
            print(f'Дата: {data}')
            title = article.find(class_='tm-article-snippet__title-link').text.strip()
            print(f'Заголовок: {title}')
            link = article.find(class_='tm-article-snippet__title tm-article-snippet__title_h2').find('a').attrs['href']
            print(f'Ссылка: {url + link}')
            print()


import pygame as pg
from pygame.sprite import Sprite

class Ship(Sprite):
    def __init__(self, screen, settings):
        super(Ship, self).__init__()
        self.screen = screen
        self.settings = settings

        self.sprite = pg.image.load('./assets/spaceship.png')
        self.scale_factor = 10
        self.sprite = pg.transform.scale(self.sprite, (self.sprite.get_width() // self.scale_factor , self.sprite.get_height() // self.scale_factor))
        self.rect = self.sprite.get_rect()
        self.screen_rect = self.screen.get_rect()

        self.isMovingRight = False
        self.isMovingLeft = False

        self.rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.bottom - 5

    def update(self):
        if self.isMovingRight and (self.rect.right < self.screen_rect.right):
            self.rect.centerx += self.settings.space_ship_speed
        if self.isMovingLeft and (self.rect.left > self.screen_rect.left):
            self.rect.centerx -= self.settings.space_ship_speed

    def draw(self):
        self.screen.blit(self.sprite, self.rect)

    def center_ship(self):
        self.rect.centerx = self.screen_rect.centerx


import ConfigParser
import io
import sys
import os
import numpy as np
from scipy.stats import cumfreq
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cm as cm
from mpl_toolkits.axes_grid1 import make_axes_locatable
from mpl_toolkits.basemap import Basemap
from matplotlib.backends.backend_pdf import PdfPages
import pickle

configFile = sys.argv[1]

def readConfigFile(configFileName):
  global config
  with open(configFileName) as f:
    sample_config = f.read()
  config = ConfigParser.RawConfigParser(allow_no_value=True)
  config.readfp(io.BytesIO(sample_config))
  return config

def stackedPlotHistogram(metric, catchmentSize, title, legendLoc = 2, ymax=3500):
  plotData = []
  lims = [0,10**4,25000,50000,10**5,25*10**4,25*10**10]
  for lim in range(1,len(lims)):
    sel1 = catchmentSize/10**6 < lims[lim]
    sel2 = catchmentSize/10**6 > lims[lim-1]
    sel = [x and y for x, y in zip(sel1, sel2)]
    plotData.append(metric[sel])
  ax1 = plt.hist(plotData, bins=np.arange(-1,1.01,0.1), width = 0.1, stacked=True, color=plt.get_cmap("Blues")(np.linspace(0, 1, 6)), label = ["$<10*10^3$","$<25*10^3$","$<50*10^3$","$<100*10^3$","$<250*10^3$","$\geq250*10^3$"], edgecolor = "none")
  ax1 = plt.legend(prop={'size': 10}, title="Catchment size ($km^2$)", loc = legendLoc)
  ax1 = plt.title(title)
  ax1 = plt.xlabel("Value")
  ax1 = plt.ylabel("Frequency")
  ax1 = plt.xlim(-1, 1)
  ax1 = plt.ylim(0, ymax)
  ax1 = plt.gcf().set_tight_layout(True)
  pdf.savefig()
  plt.clf()

def plotHistogram(metric, title):
  ax1 = plt.hist(metric, bins=np.arange(-1,1.01,0.1))
  ax1 = plt.title(title)
  ax1 = plt.xlabel("Value")
  ax1 = plt.ylabel("Frequency")
  ax1 = plt.xlim(-1, 1)
  ax1 = plt.gcf().set_tight_layout(True)
  pdf.savefig()
  plt.clf()

def plotCDF(forecast, validation, title, xlims = [-1,1]):
  forecast[forecast < -1.01] = -1.01
  vals, x1, x2, x3 = cumfreq(forecast, len(forecast))
  ax1 = plt.plot(np.linspace(np.min(forecast), np.max(forecast), len(forecast)), vals/len(forecast), label=str(config.get('Main options', 'RunName')))
  validation[validation < -1.01] = -1.01
  vals, x1, x2, x3 = cumfreq(validation, len(validation))
  ax2 = plt.plot(np.linspace(np.min(validation), np.max(validation), len(validation)), vals/len(validation), label=str(config.get('Reference options', 'RunName')))
  ax2 = plt.legend(prop={'size': 10}, loc=2)
  ax1 = plt.title(title)
  ax1 = plt.xlabel("Value")
  ax1 = plt.ylabel("ECDF")
  ax1 = plt.xlim(xlims[0], xlims[1])
  ax1 = plt.ylim(0, 1)
  ax1 = plt.gcf().set_tight_layout(True)
  pdf.savefig()
  plt.clf()

def plotScatter(forecast, validation, title):
  ax1 = plt.plot(validation, forecast, "ro", markersize=8)
  ax1 = plt.plot([-100,100], [-100,100])
  ax1 = plt.title(title)
  ax1 = plt.xlabel(str(config.get('Reference options', 'RunName')))
  ax1 = plt.ylabel(str(config.get('Main options', 'RunName')))
  ax1 = plt.xlim(-1, 1)
  ax1 = plt.ylim(-1, 1)
  ax1 = plt.gcf().set_tight_layout(True)
  pdf.savefig()
  plt.clf()

def plotHexBin(forecast, validation, title):
  forecast[forecast < -1.1] = -1.1
  validation[validation < -1.1] = -1.1
  ax1 = plt.hexbin(validation, forecast, gridsize=20, vmin=1, vmax=20, cmap="OrRd")
  ax1 = plt.plot([-100,100], [-100,100])
  ax1 = plt.title(title)
  ax1 = plt.xlabel(str(config.get('Reference options', 'RunName')))
  ax1 = plt.ylabel(str(config.get('Main options', 'RunName')))
  ax1 = plt.xlim(-1, 1)
  ax1 = plt.ylim(-1, 1)
  ax1 = plt.gcf().set_tight_layout(True)
  pdf.savefig()
  plt.clf()

def plotWorldMap(data, lons, lats, title, vmin = -1., vmax = 1., s=5):
  plt.figure(figsize=(8, 4))
  m = Basemap(projection='mill',lon_0=0, llcrnrlon=-20., llcrnrlat=20.,
    urcrnrlon=50., urcrnrlat=75.)
  x,y = m(lons, lats)

  m.drawcountries(zorder=0, color="white")
  #m.drawcoastlines(zorder=0, color="black")
  m.fillcontinents(color = 'black',zorder=-1)

  m.scatter(x,y, c=data, cmap='RdBu', vmin=vmin, vmax=vmax, s=s, edgecolors='none')
  m.colorbar()

  plt.title(title)
  plt.gcf().set_tight_layout(True)
  pdf.savefig()
  plt.clf()
  plt.figure(figsize=(8, 6))

config = readConfigFile(configFile)
runName = str(config.get('Main options', 'RunName'))
refName = str(config.get('Reference options', 'RunName'))

output, output2 = pickle.load(open('validationResultsPool_%s_%s.obj' %(runName, refName), 'rb') )
sel1 = (np.isnan(output[:,3]+output[:,2]+output[:,4]+output2[:,2]+output2[:,3]+output2[:,4]) == False)
sel2 = np.sum(output[:,3:], axis=1) != 0.0
sel3 = np.sum(output2[:,3:], axis=1) != 0.0
sel = [x and y and z for x, y, z in zip(sel1, sel2, sel3)]
sel5Min = sel

pdf = PdfPages(str(config.get('Output options', 'outputFile')))
matplotlib.rcParams.update({'font.size': 12})

plotWorldMap(output[sel5Min,3], output[sel5Min,0], output[sel5Min,1], 'Correlation with observations (%s)' %(str(config.get('Main options', 'RunName'))))
plotWorldMap(output2[sel,3], output2[sel,0], output2[sel,1], 'Correlation with observations (%s)' %(str(config.get('Reference options', 'RunName'))))
plotWorldMap(output[sel,3]-output2[sel,3], output[sel,0], output[sel,1], 'Correlation difference 5min - 30min', vmin=-0.5, vmax=0.5)

plotWorldMap(output[sel5Min,4], output[sel5Min,0], output[sel5Min,1], 'Anomaly Correlation (%s)' %(str(config.get('Main options', 'RunName'))))
plotWorldMap(output2[sel,4], output2[sel,0], output2[sel,1], 'Anomaly Correlation (%s)' %(str(config.get('Reference options', 'RunName'))))
plotWorldMap(output[sel,4]-output2[sel,4], output[sel,0], output[sel,1], 'Anomaly Correlation difference', vmin=-0.5, vmax=0.5)

plotWorldMap(output[sel5Min,4]-output[sel5Min,3], output[sel5Min,0], output[sel5Min,1], 'Anomaly Correlation - Correlation (%s)' %(str(config.get('Main options', 'RunName'))))

stackedPlotHistogram(output[sel5Min,3], output[sel5Min,2], "Correlation with observations (%s)" %(str(config.get('Main options', 'RunName'))), ymax=750)
stackedPlotHistogram(output2[sel,3], output2[sel,2], "Correlation with observations (%s)" %(str(config.get('Reference options', 'RunName'))), ymax=750)

stackedPlotHistogram(output[sel5Min,4], output[sel5Min,2], "Anomaly Correlation with observations (%s)" %(str(config.get('Main options', 'RunName'))), ymax=750)
stackedPlotHistogram(output2[sel,4], output2[sel,2], "Anomaly Correlation with observations (%s)" %(str(config.get('Reference options', 'RunName'))), ymax=750)

stackedPlotHistogram(output[sel5Min,5], output[sel5Min,2], "Kling-Gupta Efficiency (%s)" %(str(config.get('Main options', 'RunName'))), ymax=500)
stackedPlotHistogram(output2[sel,5], output2[sel,2], "Kling-Gupta Efficiency (%s)" %(str(config.get('Reference options', 'RunName'))), ymax=500)

stackedPlotHistogram(output[sel5Min,4]-output[sel5Min,3], output[sel5Min,2], "AC - R (%s)" %(str(config.get('Main options', 'RunName'))), ymax=550)

plotCDF(output[sel,3], output2[sel,3], "R")
plotCDF(output[sel,4], output2[sel,4], "AC")
plotCDF(output[sel,5], output2[sel,5], "KGE")

plotHexBin(output[sel,3], output2[sel,3], "R")
plotHexBin(output[sel,4], output2[sel,4], "AC")
plotHexBin(output[sel,5], output2[sel,5], "KGE")

pdf.close()


from flask import Flask, render_template, flash, redirect, url_for, session, logging, request
from wtforms import Form, StringField, validators
import Project

import re

app = Flask(__name__)

@app.route("/search")
def search():
    return render_template('search.html')

class WordPredictionForm(Form):
    word = StringField('', [validators.Length(min=1, max=1000)])

# PROJECT NLP

@app.route('/', methods=['GET', 'POST'])
def index():
    form = WordPredictionForm(request.form)
    if request.method == 'POST' and form.validate():
        word = form.word.data
        print(word)

        #Predict the Model
        project = Project

        word = re.sub(r'([^\s\w]|_)+', '', word)
        seq = word[:40].lower()
        # print(seq)
        list = project.predict_completions(seq, 5)
        chosen = list[0]

        print(list)

        flash("loading...")

        # redirect(url_for('index', list=list))
        return render_template('index.html', form=form, list=list, seq=seq, chosen=chosen, scroll='result')
    return render_template('index.html', form=form)

if __name__ == "__main__":
    app.secret_key = "secret123"
    app.run(debug=True)