"""
Module instead for bot command "/weather"
"""

from telebot.types import Message, CallbackQuery
from loader import bot
from database.functions import get_user_city
from .city import change_city
from utils import weather_requests
from keyboards.inline import inline_keyboad_by_dict
from datetime import datetime as dt

@bot.message_handler(commands=["weather"])
def weather_start(message: Message) -> None:
    """
    Message handler which catching the command "/weather".
    Send a keyboard with choice of view a weather

    Args:
        message (Message): user's message
    """
    city_info = get_user_city(message.chat.id)
    if city_info:
        keyboard = inline_keyboad_by_dict(
            {
                "Погода сьогодні": "today",
                "Наступні 24 години (погодинно)": "hourly",
                "10 днів": "10 days",
            }
        )
        bot.send_message(
            message.chat.id, "Як саме хочете переглядати погоду?", reply_markup=keyboard
        )
    else:
        change_city(message)

@bot.callback_query_handler(func=lambda data: data.data in ("today", "hourly", "10 days"))
def get_weather(callback: CallbackQuery):
    """
    Function which catching callback from keyboard of choice the view a weather and returned a message with weather
    which user selected earlier.

    Args:
        callback (CallbackQuery): callback from inline keyboard
    """
    msg = bot.send_message(callback.message.chat.id, "Одну секунду, дізнаюсь погоду...")
    city = get_user_city(callback.from_user.id)

    if callback.data == "hourly":
        weather = weather_requests.get_weather_hourly(
            city.get("latitude"), city.get("longitude")
        )
        bot.delete_message(msg.chat.id, msg.id)
        if weather:
            text = ""
            text_template = (
                "{smile} {time} ({day})\n"
                "🌡 Температура: {temp}°С, відчувається як {temp_like}°С\n"
                "💦 Вологість повітря: {humidity}%\n"
                "🔆 УФ-індекс: {uv_index} з 10 ({uv_description})\n"
                "Опади: {precip_type} {precip_chance}% {precip_quantity}мм\n\n"
            )

            for hour in range(24):
                precip = weather.get("precipType")[hour]

                text += text_template.format(
                    smile="☀" if weather.get("dayOrNight")[hour] == "D" else "🌙",
                    time=dt.fromisoformat(weather.get("validTimeLocal")[hour][:-5]).strftime("%H:%M"),
                    day=weather.get("dayOfWeek")[hour],
                    temp=weather.get("temperature")[hour],
                    temp_like=weather.get("temperatureFeelsLike")[hour],
                    humidity=weather.get("relativeHumidity")[hour],
                    uv_index=weather.get("uvIndex")[hour],
                    uv_description=weather.get("uvDescription")[hour],
                    precip_type="Дощ 💧" if precip == "rain" else "Сніг ❄",
                    precip_chance=weather.get("precipChance")[hour],
                    precip_quantity=weather.get("qpf")[hour] if precip == "rain" else weather.get("qpfSnow")[hour]
                )
        else:
            text = "Сталася непередбачувана помилка 😳"
        bot.send_message(callback.message.chat.id, text)

    elif callback.data == "today":
        weather = weather_requests.get_today_weather(
            city.get("latitude"), city.get("longitude")
        )
        bot.delete_message(msg.chat.id, msg.id)
        if weather:
            text = (
                "{day_part} Погода сьогодні ({day}) в {city_name}\n\n"
                "{description}\n\n"
                "⬇ Тиск: {pressure} мбар\n\n"
                "🌡 Температура зараз: {temp}°С, відчувається як {temp_like}°С\n\n"
                "🌡 Мінімальна: {temp_min}°С, максимальна {temp_max}°С\n\n"
                "💦 Вологість повітря: {humidity}%\n\n"
                "🔆 УФ-індекс: {uv_index} з 10\n\n"
                "👀 Видимість: {visibility}\n\n"
                "💧 Точка роси: {dew_point}°С"
            ).format(
                day_part="☀" if weather.get("dayOrNight") == "D" else "🌙",
                day=weather.get("dayOfWeek"),
                city_name=city.get("city_name"),
                description=weather.get("wxPhraseLong"),
                pressure=weather.get("pressureMeanSeaLevel"),
                temp=weather.get("temperature"),
                temp_like=weather.get("temperatureFeelsLike"),
                temp_min=weather.get("temperatureMin24Hour"),
                temp_max=weather.get("temperatureMax24Hour"),
                humidity=weather.get("relativeHumidity"),
                uv_index=weather.get("uvIndex"),
                visibility=weather.get("visibility"),
                dew_point=weather.get("temperatureDewPoint")
            )
        else:
            text = "Сталася непередбачувана помилка 😳"

        bot.send_message(callback.message.chat.id, text)

    elif callback.data == "10 days":
        weather = weather_requests.get_10_days_weather(
            city.get("latitude"), city.get("longitude")
        )
        bot.delete_message(msg.chat.id, msg.id)
        if weather:
            text_template = (
                "{smile} {daypart_name}\n"
                "🌡 Температура: {temp}°С\n"
                "☁ Хмарність: {clouds}%\n"
                "🔆 УФ-індекс: {uv_index} з 10\n"
                "Опади: {precip_type} {precip_chance}% {precip_quantity}мм\n"
                "{description}\n\n"
            )

            for day in range(0, 20, 2):
                text = ""
                night = day + 1

                if weather.get("dayOrNight")[day]:
                    precip = weather.get("precipType")[day]
                    text += text_template.format(
                        daypart_name=weather.get("daypartName")[day],
                        smile="☀",
                        temp=weather.get("temperature")[day],
                        clouds=weather.get("cloudCover")[day],
                        uv_index=weather.get("uvIndex")[day],
                        precip_chance=weather.get("precipChance")[day],
                        precip_type="Дощ 💧" if precip == "rain" else "Сніг ❄",
                        precip_quantity=weather.get("qpf")[day] if precip == 'rain'
                        else weather.get("qpfSnow")[day],
                        description=weather.get("wxPhraseLong")[day]
                    )

                if weather.get("dayOrNight")[night]:
                    precip = weather.get("precipType")[night]
                    text += text_template.format(
                        daypart_name=weather.get("daypartName")[night],
                        smile="🌙",
                        temp=weather.get("temperature")[night],
                        clouds=weather.get("cloudCover")[night],
                        uv_index=weather.get("uvIndex")[night],
                        precip_chance=weather.get("precipChance")[night],
                        precip_type="Дощ 💧" if weather.get("precipType")[night] == "rain" else "Сніг ❄",
                        precip_quantity=weather.get("qpf")[night] if precip == 'rain'
                        else weather.get("qpfSnow")[night],
                        description=weather.get("wxPhraseLong")[night],
                    )
                bot.send_message(callback.message.chat.id, text)
        else:
            bot.send_message(callback.message.chat.id, "Сталася непередбачувана помилка 😳")
    weather_start(callback.message)


#!/usr/bin/python
# coding=utf-8

import django,os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djtest.settings")
django.setup()
from tools.db import Db_MySql
# from djcelery import models as djcelery_model
from rbmapi import rbm_manage
from tools.ms import ms_exec_test
from test1.models import Routing_keys
from djcelery import loaders
from celery import registry

b = Db_MySql('10.10.6.11', 'root', 'root', 'djtest')

def get_all_tasks_info():
    sql = '''select a.id, a.task_id, a.status, a.result, b.log_date, a.date_done, b.`first`, b.`second`
from celery_taskmeta a , test1_add b
where a.task_id = b.task_id order by a.id'''

    res = b.ExecQuery(sql)
    return res

def add_task_to_db(name, task, queue, exchange, routing_key, enabled, date_changed, interval_id, args='[]', kwargs='{}'):
    if interval_id == 0:
        sql = '''
        insert into djcelery_periodictask(name,task,args,kwargs,queue,exchange,routing_key,enabled,total_run_count,date_changed,description)
        values(%s,%s,%s,%s,%s,%s,%s,%s,0,%s,'')
        '''
        para = (name, task, args, kwargs, queue, exchange, routing_key,enabled, date_changed)
    else:
        sql = '''
        insert into djcelery_periodictask(name,task,args,kwargs,queue,exchange,routing_key,enabled,total_run_count,date_changed,description,interval_id)
        values(%s,%s,%s,%s,%s,%s,%s,%s,0,%s,'',%s)
        '''
        para = (name, task, args, kwargs, queue, exchange, routing_key,enabled, date_changed, interval_id)

    res = b.ExecNoQuery(sql, para)
    return res

#更新任务
def update_task_with_id(id, task, queue, exchange, routing_key, enabled, date_changed, interval_id, kwargs='{}'):
    sql = '''
    update djcelery_periodictask set task=%s,kwargs=%s,queue=%s,exchange=%s,routing_key=%s,enabled=%s,date_changed=%s,interval_id=%s
    where id=%s
    '''
    para = (task, kwargs, queue, exchange, routing_key,enabled, date_changed, interval_id, id)
    res = b.ExecNoQuery(sql, para)
    return res

#添加 interval 2 db
def add_interval_to_db(every, period):
    sql = '''
    insert into djcelery_intervalschedule(every,period) values(%s,%s)
    '''
    para = (every, period)
    res = b.ExecNoQuery(sql, para)
    return res

#获取 interval 列表
def get_interval_list():
    sql = '''
    select id,concat_ws(" ",cast(every as char),period) period from djcelery_intervalschedule
    '''
    r = b.ExecQuery(sql)
    return r

def get_interval_list_sep_all():
    sql = '''
    select id, every, period from djcelery_intervalschedule
    '''
    r = b.ExecQuery(sql)
    return r

def update_interval_data(id, every, period):
    sql = '''
    update djcelery_intervalschedule set every=%s,period=%s where id=%s
    '''
    para = (every, period, id)
    res = b.ExecNoQuery(sql, para)
    return res

def delete_interval_data(id_list):
    res_list = []
    sql = """
            delete from djcelery_intervalschedule where id=%s
            """
    res_list = [b.ExecNoQuery(sql, id) for id in id_list]
    # for id in id_list:
    #     res = b.ExecNoQuery(sql, id)
    #     # res = djcelery_model.IntervalSchedule.objects.filter(id=id).delete()
    #     res_list.append(res)
    for r in res_list:
        if r == 'False':
            return False
    return True

def get_crontab_list_sep_all():
    sql = '''
    select id, hour, minute, day_of_week, day_of_month, month_of_year from djcelery_crontabschedule
    '''
    r = b.ExecQuery(sql)
    return r

def update_crontab_data(id, hour, minute, day_of_week, day_of_month, month_of_year):
    sql = '''
    update djcelery_crontabschedule set hour=%s, minute=%s, day_of_week=%s,
    day_of_month=%s, month_of_year=%s where id=%s
    '''
    para = (hour, minute, day_of_week, day_of_month, month_of_year, id)
    res = b.ExecNoQuery(sql, para)
    return res

def add_crontab_to_db(hour, minute, day_of_week, day_of_month, month_of_year):
    sql = '''
    insert into djcelery_crontabschedule(hour, minute, day_of_week, day_of_month, month_of_year)
    values(%s,%s,%s,%s,%s)
    '''
    para = (hour, minute, day_of_week, day_of_month, month_of_year)
    res = b.ExecNoQuery(sql, para)
    return res

def delete_crontab_data(id_list):
    res_list = []
    sql = """
            delete from djcelery_crontabschedule where id=%s
            """
    res_list = [b.ExecNoQuery(sql, id) for id in id_list]
    # for id in id_list:
    #     res = b.ExecNoQuery(sql, id)
    #     # res = djcelery_model.IntervalSchedule.objects.filter(id=id).delete()
    #     res_list.append(res)
    for r in res_list:
        if r == 'False':
            return False
    return True

def get_tasks_status():
    sql = '''
    select DISTINCT(a.name), a.task, a.enabled, a.last_run_at, b.state, a.id
    from djcelery_periodictask a
    LEFT JOIN djcelery_taskstate b
    on a.task = b.name
    '''
    res = b.ExecQuery(sql)
    return res

#获取任务明细
def get_task_detail(tid):
    sql = '''
    select a.id, a.name, a.task, a.kwargs, a.queue, a.exchange, a.routing_key, b.id interval_id, concat_ws(" ",cast(b.every as char),b.period) period
    from djcelery_periodictask a, djcelery_intervalschedule b
    where a.interval_id = b.id and a.id=%s
    '''

    res = b.ExecQuery(sql, tid)
    return res

def get_running_tasks():
    sql = '''
    SELECT a.name, a.state,a.kwargs,a.result,a.runtime ,b.date_done,c.hostname
    FROM djcelery_taskstate a
    LEFT JOIN celery_taskmeta b
    on a.task_id = b.task_id
    LEFT JOIN djcelery_workerstate c
    on a.worker_id = c.id
    order by b.date_done desc
    limit 50
    '''
    res = b.ExecQuery(sql)
    return res

def get_all_tasks():
    exclude_task = [
        'celery.backend_cleanup',
        'celery.chain',
        'celery.chord',
        'celery.chord_unlock',
        'celery.chunks',
        'celery.group',
        'celery.map',
        'celery.starmap',
        'djtest.celery.debug_task'
    ]
    loaders.autodiscover()
    task_list_all = list(sorted(registry.tasks.regular().keys()))
    for t in exclude_task:
        task_list_all.remove(t)
    return task_list_all

'''
rabbitmq
'''
#同步 exchanges 2 db
def rbt_sync_exchanges(name):
    sql = 'insert into test1_exchanges(name) values(%s)'
    try:
        res = b.ExecNoQuery(sql, name)
    except Exception as e:
        res = False
    return res

#同步 queues 2 db
def rbt_sync_queues(name):
    sql = 'insert into test1_queues(name) values(%s)'
    try:
        res = b.ExecNoQuery(sql, name)
    except Exception as e:
        res = False
    return res

#同步 routing_keys 2 db
def rbt_sync_routingkey(name, eid, qid):
    rk = Routing_keys.objects.get_or_create(name=name,exchange_id=eid,queue_id=qid)
    return rk[1]

def get_exchanges_db(cp=None, ps=None):
    if cp is None and ps is None:
        sql = 'select * from test1_exchanges'
        res = b.ExecQuery(sql)
    else:
        p1 = (cp-1)*ps
        sql = 'select * from test1_exchanges limit %s,%s'
        para = (p1, ps)
        res = b.ExecQuery(sql, para)
    return res

def get_queues_db(cp=None, ps=None):
    if cp is None and ps is None:
        sql = 'select * from test1_queues'
        res = b.ExecQuery(sql)
    else:
        #分页  cp 当前页，ps 每页显示数量
        p1 = (cp-1)*ps
        sql = 'select * from test1_queues limit %s,%s'
        para = (p1, ps)
        res = b.ExecQuery(sql, para)
    return res

#根据 exchange和 queue id获取 routing_key 列表
def get_routing_key_with_eq_id(eid, qid):
    rk = list(Routing_keys.objects.filter(exchange_id=eid, queue_id=qid).values('id','name'))
    return rk

if __name__ == '__main__':
    r = get_exchanges_db()
    # s = add_interval_to_db(55555, 'hours')
    # d = delete_interval_data([11,10])
    print(r)
    print(get_all_tasks())

    print(get_exchanges_db(cp=1,ps=5))

    # args = ('exec insertTestTable', 'None')
    # m = ms_exec_test(args)
    # print(m)

    # print(d)
    # el = ['11','12']
    # for e in el:
    #     print(rbt_sync(e))

    # a = add_task_to_db(name='ttt',task='ttt',enabled=0,interval_id=2,kwargs='{11}',queue='11',exchange='11',routing_key='11',date_changed='2018-08-04 01:01:01')
    # print(a)


import numpy as np
from flask import Flask, request, jsonify, render_template
import pickle

app = Flask(__name__)
model = pickle.load(open('model.pkl', 'rb'))

@app.route('/')
def home():
    return render_template('index.html')

def ValuePredictor(to_predict_list):
    to_predict = np.array(to_predict_list).reshape(1, 13)
    result = model.predict(to_predict)
    return result[0]
@app.route('/predict',methods=['POST'])
def predict():
    '''
    For rendering results on HTML GUI
    '''
    int_features = [float(x) for x in request.form.values()]
    final_features = [np.array(int_features)]
    prediction = model.predict(final_features)

    output = round(prediction[0], 2)
    if int(output)== 1:
            prediction ='High chances of heart disease'
    else:
            prediction ='Chances of heart disease is less'
    return render_template('index.html', prediction_text='{}'.format(prediction))

# @app.route('/result', methods = ['POST'])
# def result():
#     if request.method == 'POST':
#         to_predict_list = request.form.to_dict()
#         to_predict_list = list(to_predict_list.values())
#         to_predict_list = list(map(int, to_predict_list))
#         result = ValuePredictor(to_predict_list)
#         if int(result)== 1:
#             prediction ='Income more than 50K'
#         else:
#             prediction ='Income less that 50K'
#         return render_template("result.html", prediction = prediction)

@app.route('/predict_api',methods=['POST'])
def predict_api():
    '''
    For direct API calls trought request
    '''
    data = request.get_json(force=True)
    prediction = model.predict([np.array(list(data.values()))])

    output = prediction[0]
    return jsonify(output)

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


from selenium import webdriver
import time

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

driver = webdriver.Chrome(executable_path="../drivers/chromedriver.exe")
driver.maximize_window()
driver.get("https://rahulshettyacademy.com/seleniumPractise/#/")
driver.find_element_by_css_selector("input.search-keyword").send_keys("ber")
time.sleep(2)
total_item = driver.find_elements_by_xpath("//div[@class='products']/div")
assert len(total_item) == 3

filtered_item = driver.find_elements_by_css_selector("div.product-action")
for item in filtered_item:
    item.click()

driver.find_element_by_css_selector("img[alt='Cart']").click()
driver.find_element_by_xpath("//button[text()='PROCEED TO CHECKOUT']").click()
wait = WebDriverWait(driver, 10)
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".promoCode")))
driver.find_element_by_css_selector(".promoCode").send_keys("rahulshettyacademy")
driver.find_element_by_css_selector(".promoBtn").click()

wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".promoInfo")))
promo_info_ele = driver.find_element_by_css_selector(".promoInfo")
promo_info = promo_info_ele.text
assert "Code applied" in promo_info
# print(promo_info)
driver.close()


import os
import datetime as dt
import json

import pandas as pd

from .CA import fetch_production_by_fuel, fetch_production, fetch_price
from .core import CLEAN_DATA_PATH, download_raw_data, download_raw_data_pre2019, cleanup_yearly_data

def main():
    TZ = "America/Toronto"
    now = dt.datetime.utcnow()

    # Get historical output data
    print("Download raw data")
    download_raw_data()
    download_raw_data_pre2019()

    print("Cleanup yearly data")
    cleanup_yearly_data()

    # Get latest data
    production_by_source = fetch_production_by_fuel(target_datetime=now)
    if production_by_source:
        production_by_source[-1]['datetime'] = pd.to_datetime(
            production_by_source[-1]['datetime']
        ).tz_convert(TZ).isoformat()
        with open(os.path.join(CLEAN_DATA_PATH, "latest", "production_by_source.json"), "w") as f:
            f.write(json.dumps(production_by_source[-1], indent=4))

    production_data = fetch_production(target_datetime=now)
    if len(production_data):
        timestamp = production_data["dt"].unique()[-1].tz_convert(TZ)
        production_data = production_data[production_data["dt"] == timestamp]

        plants = {
            "datetime": timestamp.isoformat(),
            "plants": production_data[["name", "fuel"]].set_index("name").to_dict()["fuel"]
        }
        with open(os.path.join(CLEAN_DATA_PATH, "latest", "plants.json"), "w") as f:
            f.write(json.dumps(plants, indent=4))

        production_by_plant = production_data[["name", "production"]].set_index("name").to_dict()["production"]
        output = {
            "datetime": timestamp.isoformat(),
            "production_by_plant": production_by_plant
        }
        with open(os.path.join(CLEAN_DATA_PATH, "latest", "production_by_plant.json"), "w") as f:
            f.write(json.dumps(output, indent=4))

    price = fetch_price(target_datetime=now)
    if price:
        price[-1]['datetime'] = pd.to_datetime(
            price[-1]['datetime']
        ).tz_convert("America/Toronto").isoformat()
        with open(os.path.join(CLEAN_DATA_PATH, "latest", "price.json"), "w") as f:
            f.write(json.dumps(price[-1], indent=4))

if __name__ == "__main__":
    main()


from datetime import datetime

from sqlalchemy.sql.elements import and_
from sqlalchemy.sql.expression import delete, select
from sqlalchemy.sql.functions import func
from sqlalchemy import Boolean, Column, Integer, String, ForeignKey, Table, DateTime
from sqlalchemy.orm import Session, relationship
from sqlalchemy.sql.schema import UniqueConstraint

from app.utils.i18n import trans
from app.utils.exceptions import CustomException
from app.core.database import BaseModel
from app.authnz.models import User

user_feed_table = Table(
    "user_feed",
    BaseModel.metadata,
    Column("user_id", Integer, ForeignKey("users.id", ondelete="CASCADE")),
    Column("feed_id", Integer, ForeignKey("feeds.id", ondelete="CASCADE")),
)

class Feed(BaseModel):
    __refrence_context__ = __name__
    __tablename__ = "feeds"

    subscribers = relationship(
        "User",
        secondary=user_feed_table,
    )
    url = Column(String, unique=True, index=True)
    title = Column(String)
    priority = Column(Integer, default=0, index=True)

    def add_subscriber(self, db: Session, user: User):
        try:
            self.subscribers.append(user)
        except:
            raise CustomException(detail=trans(
                "Already subscribed to this feed"))
        self.save(db)

    def remove_subscriber(self, db: Session, user: User):
        filter_statement = and_(
            user_feed_table.c.feed_id == self.id, user_feed_table.c.user_id == user.id
        )
        item = db.bind.execute(
            select(user_feed_table).where(filter_statement)
        ).fetchone()
        if item:
            db.bind.execute(delete(user_feed_table).where(filter_statement))
        else:
            raise CustomException(detail=trans(
                "You do not subsribe to this feed"))

    def increase_priority(self, db: Session):
        self.priority += 1
        self.save(db)

    def decrease_priority(self, db: Session):
        if self.priority > 0:
            self.priority -= 1
            self.save(db)

class UserFeedState(BaseModel):
    __refrence_context__ = __name__
    __tablename__ = "user_feed_states"

    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"))
    user = relationship("User", backref="feed_states")
    feed_id = Column(Integer, ForeignKey("feeds.id", ondelete="CASCADE"))
    feed = relationship("Feed", backref="states")

    last_entry_fetch_time = Column(DateTime(timezone=True), default=func.now())

    __table_args__ = (
        UniqueConstraint("user_id", "feed_id", name="user_feed_state_unique"),
    )

    @classmethod
    def get_item(cls, db: Session, feed_id: int, user_id: int):
        return (
            db.query(cls).filter(cls.feed_id == feed_id,
                                 cls.user_id == user_id).first()
        )

    @classmethod
    def update_fetch_time(cls, db: Session, feed_id: int, user_id: int):
        feed_state = cls.get_item(db, feed_id, user_id)
        if not feed_state:
            feed_state = cls(feed_id=feed_id, user_id=user_id)
        feed_state.last_entry_fetch_time = datetime.now()
        feed_state.save(db)

class FeedEntry(BaseModel):
    __refrence_context__ = __name__
    __tablename__ = "entries"

    feed_id = Column(Integer, ForeignKey("feeds.id", ondelete="CASCADE"))
    feed = relationship("Feed", backref="entries")
    title = Column(String)
    subtitle = Column(String)
    link = Column(String)
    author = Column(String)
    content = Column(String)
    summary = Column(String)
    published_at = Column(DateTime(timezone=True), default=func.now())

class UserFeedEntryState(BaseModel):
    __refrence_context__ = __name__
    __tablename__ = "user_feed_entry_states"

    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"))
    user = relationship("User", backref="feed_entry_states")
    feed_entry_id = Column(Integer, ForeignKey(
        "entries.id", ondelete="CASCADE"))
    feed_entry = relationship("FeedEntry", backref="states")

    is_read = Column(Boolean, default=False)
    read_time = Column(DateTime)

    is_favorite = Column(Boolean, default=False)

    __table_args__ = (
        UniqueConstraint(
            "user_id", "feed_entry_id", name="user_feed_entry_state_unique"
        ),
    )

    @classmethod
    def get_item(cls, db: Session, feed_entry_id: int, user_id: int):
        return (
            db.query(cls)
            .filter(cls.feed_entry_id == feed_entry_id, cls.user_id == user_id)
            .first()
        )

    @classmethod
    def get_or_create(cls, db: Session, feed_entry_id: int, user_id: int):
        user_state = cls.get_item(db, feed_entry_id, user_id)
        if not user_state:
            user_state = cls(feed_entry_id=feed_entry_id, user_id=user_id)
        return user_state

    @classmethod
    def mark_read(cls, db: Session, feed_entry_id: int, user_id: int):
        user_state = cls.get_or_create(db, feed_entry_id, user_id)
        user_state.is_read = True
        user_state.read_time = datetime.now()
        user_state.save(db)

    @classmethod
    def mark_unread(cls, db: Session, feed_entry_id: int, user_id: int):
        user_state = cls.get_item(db, feed_entry_id, user_id)
        if user_state and user_state.is_read:
            user_state.is_read = False
            user_state.save(db)

    @classmethod
    def favorite(cls, db: Session, feed_entry_id: int, user_id: int):
        user_state = cls.get_or_create(db, feed_entry_id, user_id)
        user_state.is_favorite = True
        user_state.save(db)

    @classmethod
    def unfavorite(cls, db: Session, feed_entry_id: int, user_id: int):
        user_state = cls.get_item(db, feed_entry_id, user_id)
        if user_state and user_state.is_favorite:
            user_state.is_favorite = False
            user_state.save(db)

class Comment(BaseModel):
    __refrence_context__ = __name__
    __tablename__ = "comments"

    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"))
    user = relationship("User")
    feed_entry_id = Column(Integer, ForeignKey(
        "entries.id", ondelete="CASCADE"))
    feed_entry = relationship("FeedEntry", backref="comments")
    content = Column(String)


from datetime import datetime

import polars as pl

from polars_queries import utils

Q_NUM = 10
# Note: Q10's answer verification has flakiness due to randomness in sorting on equal revenue values.

def q():
    var1 = datetime(1993, 10, 1)
    var2 = datetime(1994, 1, 1)
    var3 = "R"

    customer_ds = utils.get_customer_ds()
    line_item_ds = utils.get_line_item_ds()
    orders_ds = utils.get_orders_ds()
    nation_ds = utils.get_nation_ds()

    q_final = (
        customer_ds.join(orders_ds, left_on="c_custkey", right_on="o_custkey")
        .join(line_item_ds, left_on="o_orderkey", right_on="l_orderkey")
        .join(nation_ds, left_on="c_nationkey", right_on="n_nationkey")
        .filter(pl.col("o_orderdate") >= var1)
        .filter(pl.col("o_orderdate") < var2)
        .filter(pl.col("l_returnflag") == var3)
        .with_column(
            (pl.col("l_extendedprice") * (1 - pl.col("l_discount"))).alias("revenue")
        )
        .groupby(["c_custkey","c_name", "c_acctbal", "c_phone", "n_name", "c_address", "c_comment"])
        .agg([pl.sum("revenue")])
        .select(
            [
                "c_custkey",
                "c_name",
                "revenue",
                "c_acctbal",
                "n_name",
                "c_address",
                "c_phone",
                "c_comment"
            ]
        )
        .sort(by="revenue", reverse=True)
        .with_column(pl.col(pl.datatypes.Utf8).str.strip().keep_name())
    )

    utils.run_query(Q_NUM, q_final)

if __name__ == "__main__":
    q()


from EVMS import app, db
from organisations.form import OrganisationForm
from organisations.models import Organisation
from flask import render_template, redirect, url_for, request, session

'''
This code controls the creation, editing, viewing and deleting of organisations
'''

@app.route('/neworganisation', methods=['POST', 'GET'])
def add_organisation():
    form = OrganisationForm()

    if request.method == "POST" and form.validate():
        organisation = Organisation (code= form.code.data,
                            name= form.name.data,
                            description= form.description.data,
                            #admin = form.admin.data,
                            is_active= form.is_active.data)
        db.session.add(organisation)
        db.session.commit()
        return redirect(url_for('view_organisations'))

    return render_template('organisations/organisationform.html', form=form, action='new')

@app.route('/vieworganisations')
def view_organisations():
    organisations = Organisation.query.filter_by(is_active=True).all()
    return render_template('organisations/view.html', organisations=organisations)

@app.route('/editorganisation/<id>', methods=['GET', 'POST'])
def edit_organisation(id):
    organisation = Organisation.query.filter_by(id= id).first()
    form = OrganisationForm(obj= organisation)

    if request.method == "POST" and form.validate():
        organisation.code = form.code.data
        organisation.is_active = form.is_active.data
        organisation.name = form.name.data
        organisation.description = form.description.data
        #organisation.admin = form.admin.data

        db.session.add(organisation)
        db.session.flush()
        db.session.commit()
        return redirect(url_for('view_organisations'))
    return render_template('organisations/organisationform.html', form = form, organisation=organisation, action='edit')

@app.route('/deleteorganisation/<id>')
def delete_organisations(id):
    organisation = Organisation.query.filter_by(id= id).first()
    organisation.is_active = False

    db.session.add(organisation)
    db.session.commit()
    return redirect(url_for('view_organisations'))


# from django.shortcuts import render
# from django.db.models import Prefetch
# # Create your views here.
# from rest_framework import viewsets
# from .models import Stock, Borrow
# from .serializers import StockSerializer, BorrowSerializer

# class StockViewSet(viewsets.ModelViewSet):
#     serializer_class = StockSerializer
#     queryset = Stock.objects.all()

# class BorrowViewSet(viewsets.ModelViewSet):
#     serializer_class = BorrowSerializer
#     queryset = Borrow.objects.all()
from datetime import date
from django.shortcuts import render
from django.db import transaction
from django.http.response import JsonResponse
from rest_framework.parsers import JSONParser
from rest_framework import status
from .models import Stock, Borrow
from .serializers import StockSerializer, BorrowSerializer
from rest_framework.decorators import api_view
from django.http import HttpResponse

@api_view(['GET', 'POST', 'UPDATE'])
def stock_list(request):
    if request.method == 'GET':
        stocks = Stock.objects.all()
        stocks_serializer = StockSerializer(stocks, many=True)
        return JsonResponse(stocks_serializer.data, safe=False)
        # 'safe=False' for objects serialization

    elif request.method == 'POST':
        stock_data = JSONParser().parse(request)
        stock_serializer = StockSerializer(data=stock_data)
        if stock_serializer.is_valid():
            stock_serializer.save()
            return JsonResponse(stock_serializer.data, status=status.HTTP_201_CREATED)
        return JsonResponse(stock_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET', 'POST'])
def borrow_list(request):
    if request.method == 'GET':
        borrows = Borrow.objects.all()
        borrows_serializer = BorrowSerializer(borrows, many=True)
        return JsonResponse(borrows_serializer.data, safe=False)

    elif request.method == 'POST':

        borrow_data = JSONParser().parse(request)
        borrow_serializer = BorrowSerializer(data=borrow_data)

        stocks = Stock.objects.get(itemName = borrow_data["itemName"])

        if(stocks.quantity >= borrow_data["quantity"]):
            stocks.quantity = stocks.quantity - borrow_data["quantity"]
        else:
            return JsonResponse(borrow_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        if borrow_serializer.is_valid():
            borrow_serializer.save()
            stocks.save()
            return JsonResponse(borrow_serializer.data, status=status.HTTP_201_CREATED)
        return JsonResponse(borrow_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@api_view(['POST'])
def return_list(request):
    if request.method == 'POST':

        return_data = JSONParser().parse(request)

        borrows = Borrow.objects.get(id = return_data["id"])
        borrows.returnedDate=date.today()
        borrows.status="Returned"
        borrows.save()

        stocks = Stock.objects.get(itemName = return_data["itemName"])
        stocks.quantity = stocks.quantity + return_data["quantity"]
        stocks.save()

        return HttpResponse("Test")


import time
import logging
import traceback

from compose.cli import command
from compose.config.errors import ConfigurationError

import logger

from cStringIO import StringIO
import sys

class Capturing(list):
    def __enter__(self):
        self._stdout = sys.stdout
        self._stderr = sys.stderr
        sys.stdout = sys.stderr = self._out = StringIO()
        return self

    def __exit__(self, *args):
        self.extend(self._out.getvalue().splitlines())
        del self._out
        sys.stdout = self._stdout
        sys.stderr = self._stderr

class Monitor(object):
    def __init__(self, path, options,
                 norecreate, nodeps, running, filelog=None):
        global log

        if "log" not in globals():
            if filelog is not None:
                log = logging.getLogger(__name__)
                log.addHandler(logger.FileHandler(filelog))
                log.setLevel(logging.DEBUG)
            else:
                log = logging.getLogger(__name__)
                log.addHandler(logger.StreamHandler())
                log.setLevel(logging.DEBUG)

        self.path = path
        self.options = options
        self.norecreate = norecreate
        self.nodeps = nodeps
        self.running = running
        try:
            self.project = command.project_from_options(self.path,
                                                        self.options)
        except ConfigurationError:
            log.error("Can't create a monitor unit\n{}".
                format(traceback.format_exc()))
            raise SystemExit

    def _pullup(self):
        try:
            self.project.pull()
            log.info("Images pulled successfully")
        except Exception:
            log.error("Can't pull images")
            raise

        if self.norecreate:
            return

        if self.running:
            services = self._fully_running_services()
        else:
            services = self.project.services

        if self.nodeps:
            for service in services:
                try:
                    service.execute_convergence_plan(service.convergence_plan())
                    log.info("Service \"{}\" updated successfully".format(service.name))
                except Exception:
                    log.error("Can't update service \"{}\"".format(service.name))
                    raise
        else:
            try:
                self.project.up([el.name for el in services], detached=True)
                log.info("Project updated successfully")
            except Exception:
                log.error("Can't update project")
                raise

    def _fully_running_services(self):
        fully_running = []

        for service in self.project.get_services():
            if all(container.is_running for container in service.containers(stopped=True)):
                fully_running.append(service)
            else:
                log.warning("Some containers for service \"{}\" are down". \
                    format(service.name))

        return fully_running

    def run(self, timeout, scheduler):
        self.project.up(detached=True)
        log.info("Monitor started successfully")
        while True:
            try:
                with Capturing() as output:
                    self._pullup()
            except Exception:
                log.error("Service checking failed\n{}".
                    format(traceback.format_exc()))
            if scheduler:
                break

            log.info("Checked successfully\n{}".format(output))
            time.sleep(timeout)


from abc import ABC, abstractmethod
from collections import UserDict
import csv
from datetime import date, datetime
import re
import os

class AbstractField(ABC):

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

    def __eq__(self, other):
        return self.value == other.value

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, value):
        self.assert_valid_value(value)
        self._value = value

    @abstractmethod
    def assert_valid_value(self, value):
        pass

class Name(AbstractField):

    def assert_valid_value(self, value):
        if not value.isalpha():
            raise Exception("Please enter correct name")

class Phone(AbstractField):
    def assert_valid_value(self, value):
        if not value.isnumeric():
            raise Exception("Please enter correct phone number")

class Birthday(AbstractField):

    @classmethod
    def fromisoformat(cls, value):
        if not datetime.strptime(value, "%Y-%m-%d"):
            raise Exception("Please enter date number as 'YYYY-MM-DD'")
        return cls(date.fromisoformat(value))

    def assert_valid_value(self, value):
        if not isinstance(value, date):
            raise Exception("Please enter number as 'YYYY-MM-DD'")

    def days_diff(self, date):

        delta1 = datetime(date.year, self.value.month, self.value.day)
        delta2 = datetime(date.year + 1, self.value.month, self.value.day)
        if delta1 > date:
            return (delta1 - date).days
        else:
            return (delta2 - date).days

    def __str__(self):
        return self.value.strftime("%Y-%m-%d")

class Email(AbstractField):
    def assert_valid_value(self, value):
        if not re.search(r"[a-zA-Z]\w*[.]?\w*[.]?\w*'@'\w+[.]\w{2}\w*", self.value):
            raise Exception("Please enter correct email")

class Address(AbstractField):
    def assert_valid_value(self, value):
        if len(self.value) >= 256:
            raise Exception("Please enter your address not so large")

class Record:
    def __init__(self, name: Name, phone: Phone = None, birthday: Birthday = None, email: Email = None, address: Address = None):
        self.name = name
        self.phones = [phone] if phone else []
        self.birthday = birthday
        self.email = email
        self.address = address

    def add_phone(self, add_phone: Phone):
        self.phones.append(add_phone)

    def remove_phone(self, removable_phone: Phone):
        self.phones = [n for n in self.phones if n != removable_phone]

    def change_phone(self, changeable_phone: Phone, new_phone: Phone):

        for i, n in enumerate(self.phones):
            if n == changeable_phone:
                self.phones[i] = new_phone
        return self.phones

    def add_phones(self, phones: list[Phone]):
        self.phones += phones
        return self

    def __str__(self):
        return self.name.value + repr(self.phones) + repr(self.birthday) + repr(self.email) + repr(self.address)

    def __repr__(self):
        return str(self)

class AddressBook(UserDict[str, Record]):
    def __init__(self, filename: str):
        super().__init__()
        self.filename = filename
        self.load_from_csv()

    def add_record(self, record: Record) -> None:
        self.data[record.name.value] = record

    def change_record(self, record: Record) -> object:
        if record.name.value in self.data:
            self.data[record.name.value] = record
        else:
            raise Exception(f"This name {record.name.value} is not found. Please input correct name")

    def iterator(self, page_size: int) -> list[Record]:
        page = [None] * page_size
        idx = 0
        for record in self.data.values():
            page[idx] = record
            idx += 1
            if idx == page_size:
                yield page
                idx = 0
        yield page[:idx]

    def search(self, term: str):
        for record in self.data.values():
            if term in record.name.value:
                yield record
            else:
                for phone in record.phones:
                    if term in str(phone):
                        yield record
                        break

    def write_to_csv(self,):
        with open(self.filename, 'w', encoding='UTF8', newline='') as file:
            fieldnames = ["Name", "Phones", "Birthday", "Email", "Address"]
            writer = csv.DictWriter(
                file, fieldnames=fieldnames)
            writer.writeheader()
            for record in self.data.values():
                writer.writerow({
                    "Name": record.name,
                    "Phones": record.phones,
                    "Birthday": record.birthday,
                    "Email": record.email,
                    "Address": record.address
                })

    def load_from_csv(self):
        if not os.path.exists(self.filename):
            return

        with open(self.filename, newline='') as fh:
            reader = csv.DictReader(fh)
            for row in reader:
                name = row["Name"]
                birthday = row["Birthday"]
                email = row["Email"]
                address = row["Address"]
                phones = [Phone(p) for p in row["Phones"][1:-1].split(", ")]
                self.data[name] = Record(
                    Name(name),
                    None,
                    Birthday.fromisoformat(birthday) if birthday else None,
                    Email(email) if email else None,
                    Address(address) if address else None
                ).add_phones(phones)


from Experiments import RuneDBN
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib as mpl
import random
from sklearn.preprocessing import normalize
from sklearn.preprocessing import scale

s, pvals = RuneDBN.run()

# s = {
#     '1': [1, 2, 3, 4, 5, 6, 7, 8, 9],
#     '2': [200, 4,22, 43, 3e-9, 23, 5],
#     '3': [12, 43, 11, 33, 89, 4, 5, 8]
# }

cnt = 0

all_colors = 2 * np.pi * np.random.rand(7)

tt = ['r', 'b', 'g', 'y']

def plot_all(ax):
    cnt = 0
    for trace in s:

        if cnt > 200:
            break

        scores, time = zip(*s[trace])
        trace_np = np.array(scores)
        time_np = np.array(time)

        time_np = np.interp(time_np, (0, 9999), (0, +1))

        # mean = np.mean(trace_np)
        std = np.std(trace_np)

        index_bad = np.where(trace_np < std / 4)
        index_good = np.where(trace_np > std / 4)

        topK_bad = trace_np[index_bad]
        topK_good = trace_np[index_good]

        time_bad = time_np[index_bad]
        time_good = time_np[index_good]

        r_good = (1 / np.sqrt(topK_good)) * topK_good
        theta_good = 2 * np.pi * time_good
        area_good = 5 * (1 / r_good) * r_good

        r_bad = (1 / np.sqrt(topK_bad)) * topK_bad
        theta_bad = 20 * np.pi * time_bad
        area_bad = 1 * (1 / r_bad) * r_bad

        r_good_mean = np.mean(r_good)
        r_bad_mean = np.mean(r_bad)
        theta_good_mean = np.mean(theta_good)
        theta_bad_mean = np.mean(theta_bad)

        ax.scatter(theta_bad_mean, r_bad_mean, c='r', s=area_bad, alpha=1, zorder=2)
        ax.scatter(theta_good_mean, r_good_mean, c='b', s=area_good, alpha=0.55, zorder=3)

        ax.set_yticklabels([])
        cnt+=1

def plot(which, ax):
    scores, time = zip(*s[which])
    trace_np = np.array(scores)
    time_np = np.array(time)

    # time_np = scale(time_np, axis=0, with_mean=True, with_std=True, copy=True)
    time_np = np.interp(time_np, (time_np.min(), time_np.max()), (0, +1))

    # mean = np.mean(trace_np)
    std = np.std(trace_np)

    index_bad = np.where(trace_np < std/4)
    index_good = np.where(trace_np > std/4)

    topK_bad = trace_np[index_bad]
    topK_good = trace_np[index_good]

    time_bad = time_np[index_bad]
    time_good = time_np[index_good]

    r_good = trace_np# topK_good # (1/np.sqrt(topK_good)) * topK_good
    theta_good = 2 * np.pi *  time_np#time_good
    area_good = 5 * (1 / r_good) * r_good

    r_bad = trace_np# topK_bad # (1/np.sqrt(topK_bad)) * topK_bad
    theta_bad = 2 * np.pi * time_np# time_bad
    area_bad = 5 * (1/r_bad) * r_bad

    print("r_good:", r_good)
    print("time_good:", time_good)
    print("theta_good:", theta_good)

    print("-"*50)

    max_lim = np.max(r_good)
    min_lim = np.min(r_good)

    # ax.plot(theta_good[0], r_good[0], c='g', s=50, alpha=1, zorder=2)
    # ax.plot(theta_bad, r_bad, c='r', s=area_bad, alpha=1, zorder=2)
    # ax.plot(theta_good, r_good, c='b', s=area_good, alpha=0.55, zorder=3)

    ax.scatter(theta_good[0], r_good[0], c='g', s=50, alpha=1, zorder=2)
    ax.plot(theta_bad, r_bad, '-o', c='b', linewidth=0.7, markersize=0.9)

    # ax.plot(theta_good, r_good, '-o', c='b', linewidth=0.5, markersize=0.9)
    ax.grid(color='#dddddd', zorder=0)

    ax.set_rlim(0, max_lim + min_lim)
    ax.set_yticklabels([])

def plot_ps(pvs, ax):
    bins = 10
    vals = np.array(pvs[1])

    ws = int(np.floor(len(vals)/bins))
    # print("ws", ws)
    # print([(x+1)*ws for x in range(bins)] + [len(vals)-rem])
    data_bins = np.split(vals, [(x+1)*ws for x in range(bins)])
    bin_height = []

    # print(len(data_bins))

    for b in data_bins:
        mean_b = np.mean(b)
        bin_height.append(mean_b)

    # print(bin_height)
    # exit()

    # top = vals[np.where(vals > -1 * std/40)]
    N = len(bin_height)
    print(np.array(bin_height))
    plot_data = np.array(bin_height) - np.min(bin_height)
    print(plot_data)
    # exit()
    # print(plot_data)
    theta = np.arange(0.0, 2 * np.pi, 2*np.pi/N)
    radii = np.array(plot_data)
    width = np.pi/bins
    bars = ax.bar(theta, radii, width=width)

    for r, bar in zip(radii, bars):
        bar.set_facecolor(cm.jet(r))
        bar.set_alpha(0.5)

keyset = list(s.keys())

rand1 = keyset[random.randint(0, len(s)-1)]
rand2 = keyset[random.randint(0, len(s)-1)]
rand3 = keyset[random.randint(0, len(s)-1)]

fig = plt.figure()
# all data
ax1 = fig.add_subplot(221, projection='polar')
plot_all(ax1)

# plot p-values
ax2 = fig.add_subplot(222, projection='polar')
plot_ps(pvals, ax2)

# plot random trace
ax3 = fig.add_subplot(223, projection='polar')
plot(rand1, ax3)

# plot another random trace
ax4 = fig.add_subplot(224, projection='polar')
plot(rand2, ax4)

#
# for trace in s:
#     # print(trace, tt[cnt%len(tt)])
#
#     # if cnt > 2:
#     #     break
#
#     trace_np = np.array(s[trace])
#     # r = np.random.randint(0, len(trace_np))
#     # trace_np[r] = 20
#     # trace_np[r] = np.random.uniform(0, 5e-39)
#
#     # trace_np.sort(kind='mergesort')
#
#     mean = np.mean(trace_np)
#     std = np.std(trace_np)
#
#     # print(std)
#
#     topK_bad = trace_np[np.where(trace_np < std/4)]
#     topK_good = trace_np[np.where(trace_np > std/4)]
#
#     # print(len(topK_good))
#     # print(len(topK_bad))
#
#     r_good = (1/np.sqrt(topK_good)) * topK_good
#     theta_good = 80 * np.pi * r_good
#     area_good = 5 * (1 / r_good) * r_good
#     # area_good = 50 * r_good
#
#
#
#     r_bad = (1/np.sqrt(topK_bad)) * topK_bad
#     theta_bad = 80 * np.pi * r_bad
#     area_bad = 5 * (1/r_bad) * r_bad
#     # area_bad = 50 * r_bad
#
#     ax.scatter(theta_bad, r_bad, c='r', s=area_bad, alpha=1, zorder=2)
#
#     ax.scatter(theta_good, r_good, c='b', s=area_good, alpha=0.55, zorder=3)
#     cnt += 1

# ax.set_title("A line plot on a polar axis", va='bottom')
plt.show()


import os
import json
from binascii import hexlify, unhexlify
from typing import List
from enum import Enum
from grin.keychain import Keychain, Identifier, ChildKey, KeychainPath
from grin.util import absolute
from grin.transaction import Input, Output, OutputFeatures
from secp256k1.pedersen import Secp256k1, Commitment

class OutputStatus(Enum):
    Unconfirmed = 1,
    Unspent = 2,
    Locked = 3,
    Spent = 4

class OutputEntry:
    def __init__(self, root_key_id: Identifier, key_id: Identifier, n_child: int, value: int, status: OutputStatus,
                 height: int, lock_height: int, is_coinbase: bool):
        self.root_key_id = root_key_id
        self.key_id = key_id
        self.n_child = n_child
        self.value = value
        self.status = status
        self.height = height
        self.lock_height = lock_height
        self.is_coinbase = is_coinbase

    def __repr__(self):
        return "OutputEntry<n={}, value={}, status={}>".format(self.n_child, self.value, self.status.name)

    def to_dict(self) -> dict:
        return {
            "root_key_id": self.root_key_id.to_hex().decode(),
            "key_id": self.key_id.to_hex().decode(),
            "n_child": self.n_child,
            "value": self.value,
            "status": self.status.name,
            "height": self.height,
            "lock_height": self.lock_height,
            "is_coinbase": self.is_coinbase
        }

    def update_from_dict(self, dct: dict):
        self.value = dct['value']
        self.status = OutputStatus[dct['status']]
        self.height = dct['height']
        self.lock_height = dct['lock_height']
        self.is_coinbase = dct['is_coinbase']

    def mark_locked(self):
        self.status = OutputStatus.Locked

    def mark_unspent(self):
        if self.status in (OutputStatus.Unconfirmed, OutputStatus.Locked):
            self.status = OutputStatus.Unspent

    def mark_spent(self):
        if self.status in (OutputStatus.Unspent, OutputStatus.Locked):
            self.status = OutputStatus.Spent

    @staticmethod
    def from_dict(dct: dict):
        root_key_id = Identifier.from_hex(dct['root_key_id'].encode())
        key_id = Identifier.from_hex(dct['key_id'].encode())
        status = OutputStatus[dct['status']]
        return OutputEntry(root_key_id, key_id, dct['n_child'], dct['value'], status, dct['height'],
                           dct['lock_height'], dct['is_coinbase'])

    @staticmethod
    def from_child_key(child_key: ChildKey, value: int, is_coinbase: bool):
        return OutputEntry(child_key.root_key_id, child_key.key_id, child_key.n_child, value,
                           OutputStatus.Unconfirmed, 0, 0, is_coinbase)

class WalletDetails:
    def __init__(self, location: str):
        self.location = location
        self.last_confirmed_height = 0
        self.last_child_index = 0
        if not os.path.exists(location):
            self.save()
        else:
            self.load()

    def to_dict(self) -> dict:
        return {
            "last_confirmed_height": self.last_confirmed_height,
            "last_child_index": self.last_child_index
        }

    def load(self):
        f = open(self.location, "r")
        dct = json.loads(f.read())
        f.close()
        self.last_confirmed_height = dct['last_confirmed_height']
        self.last_child_index = dct['last_child_index']

    def save(self):
        f = open(self.location, "w")
        f.write(json.dumps(self.to_dict(), indent=2))
        f.close()

    def next(self) -> int:
        self.last_child_index += 1
        return self.last_child_index

class NotEnoughFundsException(Exception):
    pass

# File wallet
# TODO: locking, output selection strategies
class Wallet:
    def __init__(self, secp: Secp256k1, location: str, seed: bytes):
        self.dir_in = location
        self.dir = absolute(location)
        assert os.path.isdir(self.dir)
        self.chain = Keychain.from_seed(secp, seed)
        self.details = WalletDetails(absolute(self.dir, "wallet.det"))
        self.cache = {}
        self.outputs = {}
        if not os.path.exists(absolute(self.dir, "wallet.dat")):
            self.save()
        else:
            self.load()

    def load(self):
        self.details.load()
        f = open(absolute(self.dir, "wallet.dat"), "r")
        entries = json.loads(f.read())
        f.close()
        outputs = {}
        for entry in entries:
            key_id = entry['key_id']
            if key_id in self.outputs:
                output = self.outputs[key_id]
                output.update_from_dict(entry)
                outputs[key_id] = output
            outputs[key_id] = OutputEntry.from_dict(entry)
        self.outputs = outputs

    def save(self):
        self.details.save()
        lst = [y.to_dict() for x, y in self.outputs.items()]
        lst = sorted(lst, key=lambda x: x['n_child'])
        f = open(absolute(self.dir, "wallet.dat"), "w")
        f.write(json.dumps(lst, indent=2))
        f.close()

    def get_output(self, key: str) -> OutputEntry:
        return self.outputs[key] if key in self.outputs else None

    def get_output_by_n(self, n: int) -> OutputEntry:
        return self.get_output(self.chain.derive(n).key_id.to_hex().decode())

    def select_outputs(self, amount: int) -> List[OutputEntry]:
        total_amount = 0
        outputs = []
        for n, output in self.outputs.items():
            if output.status != OutputStatus.Unspent:
                continue
            total_amount += output.value
            outputs.append(output)
            if total_amount > amount:
                break
        if total_amount <= amount:
            raise NotEnoughFundsException()
        return outputs

    def create_output(self, value: int, is_coinbase=False) -> (ChildKey, OutputEntry):
        assert isinstance(is_coinbase, bool)
        # TODO: lock
        i = self.details.next()
        key_id = self.chain.derive_key_id(3, 0, 0, i, 0)  # TODO: manage accounts etc
        key_id_hex = key_id.to_hex().decode()
        ext_key = self.chain.derive_key(key_id)
        child_key = ChildKey(i, key_id.parent_path(), key_id, ext_key)
        self.cache[key_id_hex] = child_key
        entry = OutputEntry.from_child_key(child_key, value, is_coinbase)
        self.outputs[key_id_hex] = entry
        # self.save()
        return child_key, entry

    def derive_from_entry(self, entry: OutputEntry) -> ChildKey:
        key_id = entry.key_id.to_hex().decode()
        if key_id not in self.cache:
            ext_key = self.chain.derive_key(entry.key_id)
            self.cache[key_id] = ChildKey(entry.n_child, entry.root_key_id, entry.key_id, ext_key)
        return self.cache[key_id]

    def commit_with_child_key(self, value: int, child_key: ChildKey) -> Commitment:
        return self.chain.commit(value, child_key)

    def commit(self, entry: OutputEntry) -> Commitment:
        return self.commit_with_child_key(entry.value, self.derive_from_entry(entry))

    def entry_to_input(self, entry: OutputEntry) -> Input:
        commitment = self.commit(entry)
        return Input(
            OutputFeatures.COINBASE_OUTPUT if entry.is_coinbase else OutputFeatures.DEFAULT_OUTPUT,
            commitment
        )

    def entry_to_output(self, entry: OutputEntry) -> Output:
        return Output.create(
            self.chain,
            OutputFeatures.COINBASE_OUTPUT if entry.is_coinbase else OutputFeatures.DEFAULT_OUTPUT,
            self.derive_from_entry(entry),
            entry.value
        )

    @staticmethod
    def open(secp: Secp256k1, location: str):
        abs_dir = absolute(location)
        assert os.path.isdir(abs_dir)
        seed_file = absolute(abs_dir, "wallet.seed")
        assert os.path.exists(seed_file)
        f = open(seed_file, "r")
        wallet = Wallet(secp, location, unhexlify(f.readline().encode()))
        wallet.load()
        return wallet

    @staticmethod
    def create(secp: Secp256k1, location: str, seed: bytes):
        assert len(seed) == 32, "Invalid seed length"
        abs_dir = absolute(location)
        if not os.path.exists(abs_dir):
            os.makedirs(abs_dir)
        else:
            assert os.path.isdir(abs_dir), "Wallet location not a directory"
        seed_file = absolute(abs_dir, "wallet.seed")
        assert not os.path.exists(seed_file), "Wallet already exists"
        f = open(seed_file, "x")
        f.write(hexlify(seed).decode())
        f.close()
        return Wallet(secp, location, seed)

    @staticmethod
    def create_random(secp: Secp256k1, location: str):
        return Wallet.create(secp, location, os.urandom(32))


#! /usr/bin/env python3
#
# Listen to a socket for a datagram with status information about the ship board computers
#
# May-2021, Pat Welch, pat@mousebrains.com
# June-2022, Pat Welch, pat@mousebrains.com, rewritten

from argparse import ArgumentParser
import queue
import psycopg2 # Postgresql interface
import socket
from TPWUtils import Thread
import threading
from TPWUtils import Logger
from DataPacket import Packet
from Hosts import Hosts
import time
import logging
import os.path

class Reader(Thread.Thread):
    ''' Common components for reading data packets '''
    def __init__(self, name:str, args:ArgumentParser) -> None:
        Thread.Thread.__init__(self, name, args)
        self.hosts = Hosts(args)
        self.packet = Packet(args)
        self.queues = []

    @staticmethod
    def addArgs(parser:ArgumentParser) -> None:
        Hosts.addArgs(parser)
        grp = parser.add_argument_group(description="TCP/UDP listener options")
        grp.add_argument('--port', type=int, default=11113, metavar='port',
                help='Port to listen on')
        grp.add_argument("--size", type=int, default=8, help="Datagram size, power of 2 >= 8")
        grp = grp.add_mutually_exclusive_group()
        grp.add_argument("--tcp", action="store_true", help="Connect using TCP")
        grp.add_argument("--udp", action="store_true", help="Connect using UDP datagrams")

    def addQueue(self, q:queue.Queue) -> None:
        self.queues.append(q)

    def received(self, data:bytes, addr:tuple) -> None:
        now = time.time()
        (host, temp, free, frac) = self.packet.explode(data, self.hosts)
        if host is not None:
            payload = (now, addr[0], addr[1], host, temp, free, frac)
            logging.debug("Payload %s", payload)
            for q in self.queues: q.put(payload)
        else:
            logging.debug("data %s", data)

class ConsumeTCP(Thread.Thread):
    ''' Consume a TCP connection '''
    def __init__(self, args:ArgumentParser, connection, addr:tuple, rdr:Reader) -> None:
        Thread.Thread.__init__(self, f"TCP:{addr[0]}:{addr[1]}", args)
        self.__connection = connection
        self.__addr = addr
        self.__reader = rdr

    def runIt(self) -> None: # Called on thread start
        sz = self.args.size
        rdr = self.__reader
        addr = self.__addr
        try:
            with self.__connection as conn:
                while True:
                    data = conn.recv(sz)
                    if not data: break
                    rdr.received(data, addr)
        except:
            logging.exception("Connection problem")

class ReaderTCP(Reader):
    ''' Wait on a connection request, then spawn off a TCP consumer '''
    def __init__(self, args:ArgumentParser) -> None:
        Reader.__init__(self, "RdrTCP", args)

    @staticmethod
    def addArgs(parser:ArgumentParser) -> None:
        grp = parser.add_argument_group(description="TCP listener options")
        grp.add_argument("--nThreads", type=int, default=30,
                help="Maximum number of simultaneous connections")

    def runIt(self) -> None: # Called on thread start
        args = self.args
        port = args.port
        sz = args.size
        maxThreads = args.nThreads
        logging.info("Starting port %s size %s", port, sz)
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.bind(('', port))
            s.listen() # Listen for incoming TCP connections
            logging.debug("Listening to port %s", port)
            while True:
                (conn, addr) = s.accept() # Got a connection request, so spin it off
                if threading.active_count() > maxThreads:
                    logging.info("Rejecting connections %s due to maximum number of threads, %s<%s",
                            addr, maxThreads, threading.active_count())
                    conn = None # Close the connection, eventually
                else:
                    thrd = ConsumeTCP(args, conn, addr, self)
                    thrd.start()

class ReaderUDP(Reader):
    ''' Wait for UDP datagrams '''
    def __init__(self, args:ArgumentParser) -> None:
        Reader.__init__(self, "RdrUDP", args)

    @staticmethod
    def addArgs(parser:ArgumentParser) -> None:
        pass

    def runIt(self) -> None: # Called on thread start
        args = self.args
        port = args.port
        sz = args.size
        logging.info("Starting port %s size %s", port, sz)
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
            s.bind(("", port))
            while True:
                (data, addr) = s.recvfrom(sz)
                self.received(data, addr)

class Writer(Thread.Thread):
    ''' Wait on a queue, and write the item to a database '''
    def __init__(self, args:ArgumentParser, rdr:Reader) -> None:
        Thread.Thread.__init__(self, "Writer", args)
        self.__queue = queue.Queue()
        rdr.addQueue(self.__queue)

    @staticmethod
    def addArgs(parser:ArgumentParser) -> None:
        grp = parser.add_argument_group(description="Database writer options")
        grp.add_argument("--table", type=str, default="status", metavar="tblName",
                help="Postgresql table name")
        grp.add_argument("--db", type=str, metavar="dbName",
                help="Postgresql database name")

    def mkTable(self, cur) -> None:
        tbl = self.args.table
        sql = "CREATE TABLE IF NOT EXISTS " + tbl + "(\n"
        sql+= " t REAL, -- Time datagram was received\n"
        sql+= " ipAddr TEXT, -- IP address datagram received from\n"
        sql+= " port INTEGER, -- port number datagram received on\n"
        sql+= " host TEXT, -- Hostname\n"
        sql+= " temp REAL, -- Temperature (C)\n"
        sql+= " free REAL, -- GB available\n"
        sql+= " avail REAL, -- Fraction available\n"
        sql+= " PRIMARY KEY(t, host)\n"
        sql+= " );"
        cur.execute(sql)

    def runIt(self) -> None: # Called on thread start
        args = self.args
        q = self.__queue
        sql = "INSERT INTO " + args.table + " VALUES(%s,%s,%s,%s,%s,%s,%s);"
        dbName = f"dbname={args.db}"
        logging.info("Starting SQL\n%s", sql)
        qMakeTable = True
        while True: # Loop forever
            row = q.get()
            q.task_done()
            (t, addr, port, host, temp, free, avail) = row
            logging.info("Received %s temp %s free %s avail %s", host, temp, free, avail)
            with psycopg2.connect(dbName) as db:
                cur = db.cursor()
                cur.execute("BEGIN;")
                if qMakeTable:
                    self.mkTable(cur)
                    qMakeTable = False
                try:
                    cur.execute(sql, row)
                    cur.execute("COMMIT;")
                except:
                    cur.execute("ROLLBACK;")

class CSV(Thread.Thread):
    ''' Wait on a queue to look at a database and update a CSV file '''
    def __init__(self, args:ArgumentParser, rdr:Reader) -> None:
        Thread.Thread.__init__(self, "CSV", args)
        self.__queue = queue.Queue()
        rdr.addQueue(self.__queue)

    @staticmethod
    def addArgs(parser:ArgumentParser) -> None:
        parser.add_argument("--csv", type=str, help="CSV filename")

    def runIt(self) -> None: # Called on thread start
        args = self.args
        fn = args.csv
        q = self.__queue
        logging.info("Starting %s", fn)
        if not os.path.isfile(fn):
            with open(fn, "w") as fp:
                fp.write(",".join(("t", "host", "temp", "free", "avail")) + "\n")

        while True:
            row = q.get()
            q.task_done()
            (t, addr, port, host, temp, free, avail) = row
            logging.info("Received %s temp %s free %s avail %s", host, temp, free, avail)
            payload = (
                    str(t),
                    host,
                    "" if temp is None else str(temp),
                    "" if free is None else str(free),
                    "" if avail is None else str(avail),
                    )
            with open(fn, "a") as fp:
                fp.write(",".join(payload) + "\n")

parser = ArgumentParser(description="Listen for a LiveGPS message")
Logger.addArgs(parser)
Reader.addArgs(parser)
ReaderTCP.addArgs(parser)
ReaderUDP.addArgs(parser)
Writer.addArgs(parser)
CSV.addArgs(parser)
args = parser.parse_args()

Logger.mkLogger(args)
logging.info("args=%s", args)

try:
    reader = ReaderTCP(args) if args.tcp else ReaderUDP(args)
    if args.db:
        writer = Writer(args, reader) # Create the db writer thread
        writer.start()
    if args.csv:
        csv = CSV(args, reader) # Create the CSV file
        csv.start()

    reader.start() # Start the reader thread

    Thread.Thread.waitForException() # This will only raise an exception from a thread
except:
    logging.exception("Unexpected exception while listening")


import ISAC
isac=ISAC.isac

ISAC_FUNCS={"IRTX":"HEX (32 bits/4 bytes max)"}

import web
import json

urls = (
  '/', 'index',
  '/IRTX/(.*)','IRTX'
)

class index:
    def GET(self):
        web.header('Content-Type', 'application/json')
        return json.dumps({"FUNCS":ISAC_FUNCS})

class IRTX:
    def GET(self,ircode):
        web.header('Content-Type', 'application/json')
        ircode = int(ircode,16)
        reply=isac.IRTX(ircode)
        return json.dumps(reply)

if __name__ == "__main__":
    app = web.application(urls, globals())
    app.run()


"""Add check ondelete='CASCADE' to ShortUrl.owner_id FK

Revision ID: 58b794396519
Revises: d6c155422e16
Create Date: 2021-04-07 15:38:37.100772

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '58b794396519'
down_revision = 'd6c155422e16'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_constraint('shorturl_owner_id_fkey', 'shorturl', type_='foreignkey')
    op.create_foreign_key(None, 'shorturl', 'user', ['owner_id'], ['id'], ondelete='CASCADE')
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_constraint(None, 'shorturl', type_='foreignkey')
    op.create_foreign_key('shorturl_owner_id_fkey', 'shorturl', 'user', ['owner_id'], ['id'])
    # ### end Alembic commands ###