from config import *
from utils import DatabaseDeal

"""
:params:
    data: {
        "account: ""
    }

:return
    {
        status: "",
        info : {
                name: "",
                phone: "",
                email: "",
                introduction: "",
                direction: "",
                workplace: ""
        }
    }
"""

def t_t_view_own_info(data):
    sql = "select name, phone, email, introduction, direction, workplace from TeacherInfo where account = '%s'"
    baser = DatabaseDeal()
    results, status = baser.select(sql=sql % (data['account']))
    result = results.iloc[0].to_dict()
    return result, status

'''
:params
    data: {
        name: '',
        email: '',
        direction: '',
        introduction: '',
        workplace: '',
        phone: '',
        account: ''
    }

:return
    {
        status: ''
    }
'''

def t_t_submit_own_info(data):
    print('t submit own info data: ', data)
    sql = "update TeacherInfo set name = '%s', introduction = '%s', direction = '%s', email = '%s', phone = '%s', " \
          "workplace = '%s' where account = '%s';"
    baser = DatabaseDeal()
    results, status = baser.insert_like(sql=sql % (
        data['name'], data['introduction'], data['direction'], data['email'], data['phone'], data['workplace'],
        data['account']))
    if status == 200:
        sql = "update ReservationInfo set t_name = (select name from TeacherInfo where account = '%s') where t_account = '%s';"
        results, status = baser.insert_like(sql=sql % (data['account'], data['account']))

    return results, status

'''
    :params
        data: {
            account: '',
            reservations: [
                {
                    week: int,
                    weekday: int,
                    segment: int,
                    place: '',
                    tips: ''
                },
                ...
            ]
        }

    :return
        {
            status: ''
        }
'''

def t_t_release_reservation(data):
    sql_insert = "insert into ReservationInfo (t_account, week, weekday, segment, place, tips) values ('%s', '%s', '%s', '%s', '%s', '%s');"
    baser = DatabaseDeal()
    ress = data['reservations']
    results = None
    status = None
    for res in ress:
        results, status = baser.insert_like(
            sql_insert % (data['account'], res['week'], res['weekday'], res['segment'], res['place'], res['tips']))
        if status == 201:
            return results, status
    sql_update = "update ReservationInfo set t_name = (select name from TeacherInfo where TeacherInfo.account = ReservationInfo.t_account), t_email = (select email from TeacherInfo where TeacherInfo.account = ReservationInfo.t_account), t_phone = (select phone from TeacherInfo where TeacherInfo.account = ReservationInfo.t_account) where t_name is null;"
    results, status = baser.insert_like(sql=sql_update)
    return results, status

'''
:params:
    data: {
        account: ''
    }

    :return
        {
            status: '',
            ress:  [
                {
                    week: '第1周',
                    weekday: '周五',
                    segment: '10:30 ~ 11:00',
                    student: '***',
                    place: '宋健一号院北***',
                    reason: '答疑',
                    score: str,
                    tips: '',
                    score: '',
                },
                ...
            ]
        }
'''

def t_t_view_reservation(data):
    print('t_t_view_reservation data: ', data)
    sql = "select week, weekday, segment, s_name as student, place, reason, tips, concat(is_canceled) as is_canceled, concat(is_finished) as is_finished, concat(serial) as serial, concat(score) as score, concat(is_selected) as is_selected from ReservationInfo where t_account = '%s' and is_canceled != 3 and is_finished = 0;"
    baser = DatabaseDeal()
    temp_ress, status = baser.select(sql=sql % data['account'])
    ress = []
    if temp_ress is not None:
        for i in range(0, temp_ress.shape[0]):
            ress.append(temp_ress.iloc[i].to_dict())
    print('t view reservation ress: ', ress)
    return ress, status

'''
教师发布考试信息

:params
    data: {
        account: '',
        week: '',
        weekday: '',
        e_name: '',
        start: '',
        end: '',
        place: '',
        tips: ''
    }

:return
    {
        status: ''
    }
'''

def t_release_exam(data):
    print('t_release_exam: ', data)

    sql = "insert into ExamInfo (t_account, e_name, week, weekday, start, end, place, tips) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s');"
    baser = DatabaseDeal()
    results, status = baser.insert_like(
        sql=sql % (
            data['account'], data['e_name'], data['week'], data['weekday'],
            data['start'].replace('T', ' ').replace('.000Z', ''), data['end'].replace('T', '').replace('.000Z', ''),
            data['place'], data['tips']))

    if status == 200:
        # 更新，向表中插入姓名
        sql_update = "update ExamInfo set t_name = (select name from TeacherInfo where TeacherInfo.account = ExamInfo.t_account) where t_name = '';"
        results, status = baser.insert_like(sql=sql_update)
    else:
        return results, status
    print('t_release_exam status: ', status, '\n\tresults: ', results)
    return results, status

'''
教师查看自己发布的考试内容

:params
    data: {
        account: '' // 教师
    }

:return
    {
        status: '',
        exams: [
            {
                'name': '', // 考试名
                'place': '',
                start: '',
                end: '',
                week: '',
                weekday: '',
                tips: ''
            }
        ]
    }

'''

def t_view_own_release_exams(data):
    print('t view own release exams data: ', data)
    baser = DatabaseDeal()
    sql = "select e_name as name, start, end, week, weekday, place, tips, concat(serial) as serial from ExamInfo where t_account = '%s' order by week asc, weekday asc, start asc;"
    results, status = baser.select(sql=sql % data['account'])

    exams = []
    for i in range(0, results.shape[0]):
        exams.append(results.iloc[i].to_dict())
    print('t view own release exams status: ', status, 'results', results)
    return exams, status

'''

14 修改发布的考试

接口名
    edit_exam

:params
    data: {
        account: '',
        week: '',
        weekday: '',
        e_name: '',
        start: '',
        end: '',
        place: '',
        serial: ''
    }

:return
    {
        status: ''
    }
'''

def t_edit_exam(data):
    print('t edit exam data: ', data)
    baser = DatabaseDeal()
    sql = "update ExamInfo set e_name = '%s', start = '%s', end = '%s', place = '%s', week = '%s', weekday = '%s', tips = '%s' where serial = '%s';"
    try:
        results, status = baser.insert_like(sql % (
            data['e_name'], data['start'], data['end'], data['place'], data['week'], data['weekday'], data['tips'],
            data['serial']))
    except Exception as e:
        results, status = None, 500
        print('t edit exam error!', e)

    return results, status


import numpy as np
import torch
from pytt.batching.postprocessor import StandardOutputBatch
from .model import statistics_func

class OutputBatchApplications(StandardOutputBatch):
    @classmethod
    def from_outputs(cls, postprocessor, batch, outputs):
        loss, stats = cls.get_loss_stats(batch, outputs)
        with torch.autograd.no_grad():
            return loss, cls(len(batch), stats, batch=batch, outputs=outputs)

    @classmethod
    def loss(cls, batch, outputs):
        return None

    @classmethod
    def stats(cls, batch, outputs):
        results, stats = cls.test_func(batch, **outputs)
        stats['results'] = results
        return stats

    @classmethod
    def test_func(cls, batch, total_num_codes, num_codes, attention, traceback_attention, article_sentences_lengths, clustering, codes=None, labels=None):
        results = {'attention':attention, 'traceback_attention':traceback_attention, 'article_sentences_lengths':article_sentences_lengths,
                   'tokenized_text':batch.instances[0]['tokenized_sentences'], 'sentence_spans':batch.instances[0]['sentence_spans'], 'original_reports':batch.instances[0]['original_reports'],
                   'clustering':clustering}
        if codes is not None:
            stats = statistics_func(total_num_codes, num_codes, attention, traceback_attention, article_sentences_lengths, clustering, codes, labels=labels)
        else:
            stats = {}
        return results, stats

    def __init__(self, batch_length, batch_stats, batch=None, outputs=None):
        super(OutputBatchApplications, self).__init__(batch_length, batch_stats, batch=batch, outputs=outputs)
        if 'results' in batch_stats.keys():
            self.results = batch_stats['results']
            del batch_stats['results']

class OutputBatchTest(OutputBatchApplications):
    @classmethod
    def from_outputs(cls, postprocessor, batch, outputs):
        postprocessor.add_summary_stats(batch, outputs)
        return super(OutputBatchTest, cls).from_outputs(postprocessor, batch, outputs)


import feapder
import unicodedata
import urllib3
import threading
import time
import jieba
import logging
import hashlib
import os

from tools import get_feature, SpiderDataItem
from feapder import setting
from simhash import Simhash, SimhashIndex
from create_db import delete_values

# 去除警告
urllib3.disable_warnings()
jieba.setLogLevel(logging.INFO)

# 已经爬取的页面数量
num_pages = 0

# 爬虫配置
setting.SPIDER_MAX_RETRY_TIMES = 0
setting.MYSQL_IP = "localhost"
setting.MYSQL_PORT = 80
setting.MYSQL_DB = "search_engine_db"
setting.MYSQL_USER_NAME = "root"
setting.MYSQL_USER_PASS = "hww74520i"
setting.EXPORT_DATA_MAX_FAILED_TIMES = 1  # 导出数据时最大的失败次数，包括保存和更新，超过这个次数报警
setting.EXPORT_DATA_MAX_RETRY_TIMES = 1  # 导出数据时最大的重试次数，包括保存和更新，超过这个次数则放弃重试

# 数据库表名
TABLE_NAME = "sina"
# 声明条件变量
cLock = threading.Condition()
# 列表中存在的url
exist_urls = []
# 用于保存simhash
index = SimhashIndex(objs=[], k=3)

# 最大爬取的页面数量(实际爬取的页面数量会小于这个值，所以建议设大一点)
max_pages = 15000

class AirSpiderTest(feapder.AirSpider):

    def start_requests(self):
        yield feapder.Request("https://news.sina.com.cn/")

    def parse(self, request, response):
        global exist_urls

        href_list = response.xpath('//a/@href').extract()
        href_list = list(set(href_list))  # 去重
        exist_urls += href_list  # 加入已存在的链接
        for href in href_list:  # 发请求
            yield feapder.Request(href, callback=self.parser_news)

    def parser_news(self, request, response):
        global num_pages, exist_urls
        if response.encoding.lower() != 'utf-8':
            raise Exception("encoding  error")

        title = response.xpath('//h1[@class="main-title"]/text()').extract_first().strip()
        contents = response.xpath('//div[@id="article"]//p/text()').extract()  # 获取正文的列表
        contents = [unicodedata.normalize('NFKC', i) for i in contents]
        content = "".join(contents).strip()  # 拼接正文

        if len(title) < 5 or len(content) < 50:
            raise Exception("pass this url")

        else:
            hrefs = response.xpath('//a/@href').extract()  # 提取链接
            hrefs = list(set(hrefs))  # 去重
            hrefs = [href for href in hrefs if href.startswith("http") or href.startswith("https")]

            cLock.acquire()

            s = Simhash(get_feature(title + content))

            if not index.get_near_dups(s):
                index.add(str(num_pages), s)

                # 数据入库
                item = SpiderDataItem()
                item.table_name = TABLE_NAME  # 表名
                ans = hashlib.md5(request.url.encode(encoding='UTF-8')).hexdigest()
                item.id = int(ans[8:-8], 16)  # id, 这条数据的唯一标识
                item.title = title
                item.content = content
                item.link = request.url
                item.urls = " ".join(hrefs)

                yield item

            num_pages += 1
            if num_pages == max_pages:
                print('exit')
                os._exit(0)

            unique_urls = list(set(hrefs) - set(exist_urls))  # 提取未爬取过的链接
            exist_urls += unique_urls

            cLock.notify_all()  # 通知wait()
            cLock.release()
            time.sleep(0.1)

            # 未爬取的链接继续爬取
            for unique_url in unique_urls:
                yield feapder.Request(unique_url, callback=self.parser_news)

    def validate(self, request, response):
        if response.status_code != 200:
            raise Exception("response code not 200")  # 抛出异常

    # 下载中间件用于在请求之前，对请求做一些处理，如添加cookie、header等。写法如下：
    def download_midware(self, request):
        request.timeout = (6, 6)
        return request

if __name__ == "__main__":
    delete_values(TABLE_NAME)
    AirSpiderTest(thread_count=8).start()


# -*- coding: utf-8 -*-
"""
Created on Thu Jul  6 23:50:37 2023

@author: vitmcs
"""

import pandas as pd
import numpy as np
import torch
import math
import time
import torch.utils.data as Data
import torch.nn as nn
import torch.nn.functional as F
from torch.optim import SGD
import scipy
from sklearn.metrics import mean_squared_error,mean_absolute_error
import tushare as ts
from sklearn.preprocessing import StandardScaler
from Quantdata.catchsignal import catch,catch_norm0
import multiprocessing
from multiprocessing import Pool, cpu_count
from functools import partial

pro = ts.pro_api("92bfb7a5df70a386927cf4cb1c2b5809df1f45ba402f32dc605111f6")
data=pd.read_feather('Database/20212022std2.feather')
stock = pro.stock_basic()
stock=stock.loc[stock['symbol'].isin(data['ts_code'])]
tslist=stock[['ts_code']]
df300 = pro.index_weight(**{
    "index_code": "000300.SH"
}, fields=[
    "index_code",
    "con_code",
    "trade_date",
    "weight"
])
ts300=df300.loc[df300['con_code'].isin(tslist['ts_code'])]
ts300=ts300[['con_code']]
ts300.drop_duplicates(inplace=True)
ts300=ts300['con_code'].tolist()
#ts300.append('600552.SH')
res=pd.DataFrame()
std=pd.read_feather('Database/标准化信息.feather')
sc=StandardScaler(with_mean=False, with_std=False)
sc.mean_=std['mean']
sc.scale_=std['std']

class MLPrg(nn.Module):
    def __init__(self):
        super(MLPrg,self).__init__()
        self.hidden1=nn.Linear(in_features=100,out_features=512,bias=True)
        self.drop=nn.Dropout(0.2)
        self.hidden2=nn.Linear(in_features=512,out_features=256)
        self.predict=nn.Linear(256,1)
        self.bn1=nn.BatchNorm1d(512)
        self.bn2=nn.BatchNorm1d(256)
    def forward(self,x):
        x=F.tanh(self.hidden1(x))
        x=self.drop(x)
        x=F.tanh(self.hidden2(x))
        x=self.drop(x)
        output=self.predict(x)
        return output[:,0]
if __name__ == '__main__':
    #rg = torch.load('modelbase/bestks0.025.pt').cpu()
    rg = torch.load('modelbase/bestks0.025.pt', map_location=torch.device('cpu'))
    with Pool(processes=cpu_count()-1) as pool:
        catchsignal1 = partial(catch_norm0, stddata=data)
        catchsignal2 = partial(catchsignal1, rg=rg)
        catchsignal3 = partial(catchsignal2, sc=sc)
        #results=pool.map(catchsignal3, tslist.sample(500)['ts_code'].tolist())
        results=pool.map(catchsignal3, ts300)
    res=pd.concat(results)
    res.index=range(res.shape[0])
    res.to_feather('Database/autodata.feather')


from dateutil.relativedelta import relativedelta
from datetime import datetime
from io import BytesIO
from odoo import models, fields
import xlsxwriter
from xlsxwriter import utility
import logging

_logger = logging.getLogger(__name__)
INIT_LINES = 1

class WizardAccountingInvoice(models.TransientModel):
    _name = "wizard.accounting.reports"
    _description = "Wizard para generar reportes de libro de compra y ventas"
    _check_company_auto = True

    def _default_date_from(self):
        current_day = fields.Date.today()
        return current_day

    def _default_date_to(self):
        current_day = self._default_date_from()
        final_day_month = relativedelta(months=1, days=-1)
        increment_date = current_day + final_day_month
        return increment_date

    def _default_company_id(self):
        company_id = self.env.company.id
        return company_id

    report = fields.Selection(
        [("purchase", "Libro de Compras"), ("sale", "Libro de Ventas")],
        required=True,
    )

    date_from = fields.Date(string="Date Start", required=True, default=_default_date_from)

    date_to = fields.Date(
        string="Date End",
        required=True,
        default=_default_date_to,
    )

    company_id = fields.Many2one("res.company", default=_default_company_id)

    def _fields_sale_book_line(self, move):
        return {
            "_id": move.id,
            "espec": "2",
            "document_date": self._format_date(move.invoice_date),
            "document_number": move.n_factura,
            "n_autorizacion": move.n_autorizacion,
            "vat": move.partner_id.vat,
            "complement": move.partner_id.complement or "",
            "partner_name": move.invoice_partner_display_name,
            "amount_total": move.amount_total,
            "amount_ice": 0,
            "amount_iehd": 0,
            "amount_ipi": 0,
            "amount_tasas": 0,
            "amount_not_iva": 0,
            "amount_export_and_others": 0,
            "amount_sale_rate_zero": 0,
            "subtotal": move.amount_untaxed,
            "des_bon_reb": 0,
            "import_gift_card": 0,
            "amount_base_fiscal_debit": move.amount_untaxed,
            "amount_fiscal_debit": move.amount_untaxed * 0.13,
            "code_num": move.codigo_control,
            "type_sale": 0,
            "state": "V",
        }

    def _fields_purchase_book_line(self, move):
        return {
            "_id": move.id,
            "espec": "1",
            "vat": move.partner_id.vat,
            "partner_name": move.invoice_partner_display_name,
            "n_autorizacion": move.n_autorizacion,
            "document_number": move.n_factura,
            "document_dui": move.dui,
            "document_date": self._format_date(move.invoice_date),
            "complement": move.partner_id.complement or "",
            "amount_total": move.amount_total,
            "amount_ice": 0,
            "amount_iehd": 0,
            "amount_ipi": 0,
            "amount_tasas": 0,
            "amount_not_iva": 0,
            "amount_export_and_others": 0,
            "amount_sale_rate_zero": 0,
            "subtotal": move.amount_untaxed,
            "des_bon_reb": 0,
            "import_gift_card": 0,
            "amount_base_fiscal_debit": move.amount_untaxed,
            "amount_fiscal_debit": move.amount_untaxed * 0.13,
            "code_num": move.codigo_control,
            "type_sale": 1,
            "state": "V",
        }

    def parse_sale_book_data(self):
        sale_book_lines = []
        moves = self.search_moves()

        for move in moves:
            sale_book_line = self._fields_sale_book_line(move)
            sale_book_lines.append(sale_book_line)
        return sale_book_lines

    def parse_purchase_book_data(self):
        purchase_book_lines = []
        moves = self.search_moves()

        for move in moves:
            purchase_book_line = self._fields_purchase_book_line(move)
            purchase_book_lines.append(purchase_book_line)

        return purchase_book_lines

    def sale_book_fields(self):
        return [
            {
                "name": "N°",
                "field": "index",
            },
            {
                "name": "Especificacion",
                "field": "espec",
            },
            {
                "name": "Fecha de la Factura",
                "field": "document_date",
                "size": 15,
            },
            {
                "name": "Nº Factura",
                "field": "document_number",
                "size": 20,
            },
            {
                "name": "Codigo de Autorización",
                "field": "n_autorizacion",
                "size": 20,
            },
            {"name": "NIT/CI CLIENTE", "field": "vat", "size": 15},
            {"name": "Complemento", "field": "complement", "size": 15},
            {
                "name": "Nombre o Razón Social",
                "field": "partner_name",
                "size": 25,
            },
            {
                "name": "Importe Total de la Ventas",
                "field": "amount_total",
                "format": "number",
                "size": 15,
            },
            {
                "name": "Importe ICE",
                "field": "amount_ice",
                "format": "number",
                "size": 15,
            },
            {
                "name": "Importe IEHD",
                "field": "amount_iehd",
                "format": "number",
                "size": 15,
            },
            {
                "name": "Importe IPI",
                "field": "amount_ipi",
                "format": "number",
                "size": 15,
            },
            {
                "name": "TASAS",
                "field": "amount_tasas",
                "format": "number",
                "size": 15,
            },
            {
                "name": "OTROS NO SUJETOS AL IVA",
                "field": "amount_not_iva",
                "format": "number",
                "size": 15,
            },
            {
                "name": "Exportaciones y Operaciones Exentas",
                "field": "amount_export_and_others",
                "format": "number",
                "size": 15,
            },
            {
                "name": "VENTAS GRAVADAS A TASA CERO",
                "field": "amount_sale_rate_zero",
                "format": "number",
                "size": 15,
            },
            {
                "name": "SUBTOTAL",
                "field": "subtotal",
                "format": "number",
                "size": 15,
            },
            {
                "name": "DESCUENTOS, BONIFICACIONES Y REBAJAS SUJETAS AL IVA",
                "field": "des_bon_reb",
                "format": "number",
                "size": 15,
            },
            {
                "name": "IMPORTE GIFT CARD",
                "field": "import_gift_card",
                "format": "number",
                "size": 15,
            },
            {
                "name": "IMPORTE BASE PARA DEBITO FISCAL",
                "field": "amount_base_fiscal_debit",
                "format": "number",
            },
            {
                "name": "DEBITO FISCAL",
                "field": "amount_fiscal_debit",
                "format": "number",
            },
            {"name": "Estado", "field": "state"},
            {"name": "Codigo de control", "field": "code_num"},
            {"name": "Tipo de venta", "field": "type_sale"},
        ]

    def purchase_book_fields(self):
        return [
            {
                "name": "N°",
                "field": "index",
            },
            {
                "name": "Especificacion",
                "field": "index",
            },
            {"name": "NIT PROVEEDOR", "field": "vat", "size": 15},
            {
                "name": "Nombre o Razón Social",
                "field": "partner_name",
                "size": 25,
            },
            {
                "name": "Codigo de Autorización",
                "field": "n_autorizacion",
                "size": 20,
            },
            {
                "name": "Nº Factura",
                "field": "document_number",
                "size": 20,
            },
            {
                "name": "Numero DUI/DIM",
                "field": "document_dui",
                "size": 20,
            },
            {
                "name": "Fecha de Factura/DUI/DIM",
                "field": "document_date",
                "size": 15,
            },
            {
                "name": "Importe Total compra",
                "field": "amount_total",
                "format": "number",
                "size": 15,
            },
            {
                "name": "Importe ICE",
                "field": "amount_ice",
                "format": "number",
                "size": 15,
            },
            {
                "name": "Importe IEHD",
                "field": "amount_iehd",
                "format": "number",
                "size": 15,
            },
            {
                "name": "Importe IPI",
                "field": "amount_iehd",
                "format": "number",
                "size": 15,
            },
            {
                "name": "TASAS",
                "field": "amount_tasas",
                "format": "number",
                "size": 15,
            },
            {
                "name": "OTROS NO SUJETOS A CREDITO FISCAL",
                "field": "amount_not_iva",
                "format": "number",
                "size": 15,
            },
            {
                "name": "Importes Exentos",
                "field": "amount_export_and_others",
                "format": "number",
                "size": 15,
            },
            {
                "name": "VENTAS GRAVADAS A TASA CERO",
                "field": "amount_sale_rate_zero",
                "format": "number",
                "size": 15,
            },
            {
                "name": "SUBTOTAL",
                "field": "subtotal",
                "format": "number",
                "size": 15,
            },
            {
                "name": "DESCUENTOS, BONIFICACIONES Y REBAJAS SUJETAS AL IVA",
                "field": "des_bon_reb",
                "format": "number",
                "size": 15,
            },
            {
                "name": "IMPORTE GIFT CARD",
                "field": "import_gift_card",
                "format": "percent",
                "size": 15,
            },
            {
                "name": "IMPORTE BASE PARA CREDITO FISCAL",
                "field": "amount_base_fiscal_debit",
                "format": "number",
            },
            {
                "name": "CREDITO FISCAL",
                "field": "amount_fiscal_debit",
                "format": "number",
            },
            {"name": "Tipo de compra", "field": "type_sale"},
            {"name": "Codigo de control", "field": "code_num"},
        ]

    def _get_domain(self, current_company_id=False):
        search_domain = []
        is_purchase = self.report == "purchase"

        field_date = "date" if is_purchase else "invoice_date"

        if current_company_id:
            search_domain += [("company_id", "=", current_company_id)]

        move_type = (
            ["out_invoice", "out_refund"]
            if not is_purchase
            else ["in_invoice", "in_refund", "in_debit"]
        )

        search_domain += [(field_date, ">=", self.date_from)]
        search_domain += [(field_date, "<=", self.date_to)]
        search_domain += [
            ("state", "not in", ["draft"]),
            ("move_type", "in", move_type),
        ]

        return search_domain

    def generate_report(self):
        is_sale = self.report == "sale"

        if is_sale:
            return self.download_sales_book()

        return self.download_purchases_book()

    def download_sales_book(self):
        self.ensure_one()
        url = "/web/download_sales_book"
        return {"type": "ir.actions.act_url", "url": url, "target": "self"}

    def download_purchases_book(self):
        self.ensure_one()
        url = "/web/download_purchase_book"
        return {"type": "ir.actions.act_url", "url": url, "target": "self"}

    def _format_date(self, date):
        _fn = datetime.strptime(str(date), "%Y-%m-%d")
        return _fn.strftime("%d/%m/%Y")

    def search_moves(self):
        order = "invoice_date asc"
        env = self.env
        move_model = env["account.move"]
        domain = self._get_domain()
        moves = move_model.search(domain, order=order)
        return moves

    def generate_sales_book(self):
        sale_book_lines = self.parse_sale_book_data()
        file = BytesIO()

        workbook = xlsxwriter.Workbook(file, {"in_memory": True, "nan_inf_to_errors": True})
        worksheet = workbook.add_worksheet()

        merge_format = workbook.add_format({"border": 1, "align": "center", "valign": "vcenter"})
        cell_formats = {
            "number": workbook.add_format({"num_format": "#,##0.00"}),
            "percent": workbook.add_format({"num_format": "0.00%"}),
        }

        name_columns = self.sale_book_fields()
        total_idx = 0

        for index, field in enumerate(name_columns):
            worksheet.set_column(index, index, len(field.get("name")) + 4)
            worksheet.write(0, index, field.get("name").upper(), merge_format)

            for index_line, line in enumerate(sale_book_lines):
                total_idx = (INIT_LINES + index_line) + 1

                if field["field"] == "index":
                    worksheet.write(INIT_LINES + index_line, index, index_line + 1)
                else:
                    cell_format = cell_formats.get(field.get("format"), workbook.add_format())
                    worksheet.write(
                        INIT_LINES + index_line, index, line.get(field["field"]), cell_format
                    )

            if field.get("format") == "number":
                col = utility.xl_col_to_name(index)
                worksheet.write_formula(
                    total_idx, index, f"=SUM({col}2:{col}{total_idx})", cell_formats.get("number")
                )

        workbook.close()
        return file.getvalue()

    def generate_purchases_book(self):
        purchase_book_lines = self.parse_purchase_book_data()
        file = BytesIO()

        workbook = xlsxwriter.Workbook(file, {"in_memory": True, "nan_inf_to_errors": True})
        worksheet = workbook.add_worksheet()

        merge_format = workbook.add_format({"border": 1, "align": "center", "valign": "vcenter"})
        cell_formats = {
            "number": workbook.add_format({"num_format": "#,##0.00"}),
            "percent": workbook.add_format({"num_format": "0.00%"}),
        }

        name_columns = self.purchase_book_fields()
        total_idx = 0

        for index, field in enumerate(name_columns):
            worksheet.set_column(index, index, len(field.get("name")) + 4)
            worksheet.write(0, index, field.get("name").upper(), merge_format)

            for index_line, line in enumerate(purchase_book_lines):
                total_idx = (INIT_LINES + index_line) + 1

                if field["field"] == "index":
                    worksheet.write(INIT_LINES + index_line, index, index_line + 1)
                else:
                    cell_format = cell_formats.get(field.get("format"), workbook.add_format())
                    worksheet.write(
                        INIT_LINES + index_line, index, line.get(field["field"]), cell_format
                    )

            if field.get("format") == "number":
                col = utility.xl_col_to_name(index)
                worksheet.write_formula(
                    total_idx, index, f"=SUM({col}2:{col}{total_idx})", cell_formats.get("number")
                )

        workbook.close()
        return file.getvalue()


from treelib import Tree

rfs = Tree()
rfs.create_node('/', '/')
current_folder = None
current_path = []

def get_initial_rfs():
    return rfs

def change_directory(location):
    global current_folder, current_path

    if location == '..':
        current_path.pop()
        current_path.pop()

        if not current_path:
            current_path.append('/')
    else:
        if len(current_path) > 1 and len(current_path) % 2 == 0:
            current_path.append('/')
        current_path.append(location)

    current_folder = rfs.get_node("".join(p for p in current_path))

def get_current_node():
    global current_folder
    return current_folder.identifier

def make_dir(dirname):
    global current_folder, current_path
    absolute_path = ''.join(p for p in current_path)

    if absolute_path == "/":
        rfs.create_node(dirname, f'{absolute_path}{dirname}', parent=current_folder)
    else:
        rfs.create_node(dirname, f'{absolute_path}/{dirname}', parent=current_folder)

def touch_file(file_info):
    global current_folder
    size, name = file_info.split(' ')
    absolute_path = ''.join(p for p in current_path)
    rfs.create_node(name, f'{absolute_path}/{name}', data=int(size), parent=current_folder)

def process_terminal_history(history):
    for line in history:
        if line.startswith('$ cd'):
            change_directory(line.split(' ')[2])
        elif line.startswith('$ ls'):
            continue
        elif line.startswith('dir'):
            make_dir(line.split(' ')[1])
        else:
            touch_file(line)

    return rfs.to_json(with_data=True)

def get_usage(location):
    size = 0
    for f in rfs.expand_tree(location):
        n = rfs.get_node(f)
        size += n.data if n.data else 0
    return size

def get_total_usage_for_directories_smaller_than_100k():
    current_folder_size, total_size = 0, 0
    for f in rfs.expand_tree('/'):
        n = rfs.get_node(f)
        if n.fpointer:
            current_folder_size = get_usage(n.identifier)
            if current_folder_size < 100000:
                total_size += current_folder_size

    return total_size

def get_needed_space():
    current_disk_usage = get_usage('/')
    unused_space = 70000000 - current_disk_usage
    return 30000000 - unused_space

def get_deletion_candidates(needed_space):
    candidates = []
    current_folder_size, total_size = 0, 0
    for f in rfs.expand_tree('/'):
        n = rfs.get_node(f)
        if n.fpointer:
            current_folder_size = get_usage(n.identifier)
            if current_folder_size > needed_space:
                candidates.append(n.identifier)

    return candidates

def get_folder_size_to_be_deleted(candidates, needed_space):
    usages = []
    for c in candidates:
        usages.append(get_usage(c))

    usages.sort()
    for u in usages:
        if u >= needed_space:
            return u

if __name__ == '__main__':
    with open('input.txt', 'r') as file:
        puzzle = [line[:-1] for line in file.readlines()]

    process_terminal_history(puzzle)
    print(get_total_usage_for_directories_smaller_than_100k())
    needed_space = get_needed_space()
    print(get_folder_size_to_be_deleted(get_deletion_candidates(needed_space), needed_space))


from google.appengine.ext import ndb

#Database
class Comment(ndb.Model):

    post_id = ndb.IntegerProperty(required = True)
    comment = ndb.TextProperty(required = True)
    poster = ndb.StringProperty(required = True)
    commented = ndb.DateProperty(auto_now_add = True)

    @classmethod
    def create_new_comment(cls, post_id, comment, poster):
        return Comment(post_id = post_id,
                    comment = comment,
                    poster = poster)


from typing import List, Optional, Union, cast

from librespot.audio.decoders import AudioQuality
from sanic.request import Request

from internals.spotify.shims import SpotifyAudioFormat

__all__ = (
    "get_spotify_audio_format",
    "get_spotify_audio_quality",
)

QueryParam = Optional[Union[str, List[str]]]

def select_first(single_or_multi: Union[str, List[str]]) -> str:
    if isinstance(single_or_multi, list):
        return single_or_multi[0]
    return single_or_multi

def get_spotify_audio_format(request: Request) -> Optional[SpotifyAudioFormat]:
    # Fallback from `format` to `fmt`
    query_param = cast(QueryParam, request.args.get("format") or request.args.get("fmt"))
    if query_param is None:
        return None
    query_param = select_first(query_param)

    query_param = query_param.lower()
    audio_mappings = {
        "mp3": SpotifyAudioFormat.MP3,
        "aac": SpotifyAudioFormat.AAC,
        "vorbis": SpotifyAudioFormat.VORBIS,
        "ogg": SpotifyAudioFormat.VORBIS,
        "m4a": SpotifyAudioFormat.AAC,
        "opus": SpotifyAudioFormat.VORBIS,
        "flac": SpotifyAudioFormat.FLAC,
        "hires": SpotifyAudioFormat.FLAC,
    }

    return audio_mappings.get(query_param)

def get_spotify_audio_quality(request: Request) -> Optional[AudioQuality]:
    # Fallback from `format` to `fmt`
    query_param = cast(QueryParam, request.args.get("q") or request.args.get("qual") or request.args.get("quality"))
    if query_param is None:
        return None

    query_param = query_param.lower()
    quality_mappings = {
        "lowest": AudioQuality.NORMAL,
        "low": AudioQuality.NORMAL,
        "lq": AudioQuality.NORMAL,
        "medium": AudioQuality.HIGH,
        "normal": AudioQuality.HIGH,
        "high": AudioQuality.VERY_HIGH,
        "hq": AudioQuality.VERY_HIGH,
        "highest": AudioQuality.VERY_HIGH,
    }

    return quality_mappings.get(query_param)


import argparse

from pypownet.environment import RunEnv
from runners.runner import CustomRunner
import agents.agent

parser = argparse.ArgumentParser(description='CLI tool to run experiments using PyPowNet.')
parser.add_argument('-a', '--agent', metavar='AGENT_CLASS', default='agent.QLearning', type=str,
                    help='class to use for the agent (must be within the \'pypownet/agent.py\' file); '
                         'default class Agent')
parser.add_argument('-n', '--niter', type=int, metavar='NUMBER_EPISODES', default='1000',
                    help='number of episodes to simulate (default 1000)')
parser.add_argument('-p', '--parameters', metavar='PARAMETERS_FOLDER', default='./parameters/default14/', type=str,
                    help='parent folder containing the parameters of the simulator to be used (folder should contain '
                         'configuration.json and reference_grid.m)')
parser.add_argument('-lv', '--level', metavar='GAME_LEVEL', type=str, default='level0',
                    help='game level of the timestep entries to be played (default \'level0\')')
parser.add_argument('-s', '--start-id', metavar='CHRONIC_START_ID', type=int, default=0,
                    help='id of the first chronic to be played (default 0)')
parser.add_argument('-lm', '--loop-mode', metavar='CHRONIC_LOOP_MODE', type=str, default='natural',
                    help='the way the game will loop through chronics of the specified game level: "natural" will'
                         ' play chronic in alphabetical order, "random" will load random chronics ids and "fixed"'
                         ' will always play the same chronic folder (default "natural")')
parser.add_argument('-m', '--game-over-mode', metavar='GAME_OVER_MODE', type=str, default='soft',
                    help='game over mode to be played: either "soft", and after each game over the simulator will load '
                         'the next timestep of the same chronic; or "hard", and after each game over the simulator '
                         'will load the first timestep of the next grid, depending on --loop-mode parameter (default '
                         '"soft")')
parser.add_argument('--no-overflow-cutoff', action='store_true',
                    help='disable the grid automatic cut-off of overflows lines (soft and hard) independently from the '
                         'parameters environment used')
parser.add_argument('-r', '--render', action='store_true',
                    help='render the power network observation at each timestep (not available if --batch is not 1)')
parser.add_argument('-la', '--latency', type=float, default=None,
                    help='time to sleep after each frame plot of the renderer (in seconds); note: there are multiple'
                         ' frame plots per timestep (at least 2, varies)')
parser.add_argument('-v', '--verbose', action='store_true',
                    help='display live info of the current experiment including reward, cumulative reward')
parser.add_argument('-vv', '--vverbose', action='store_true',
                    help='display live info + observations and actions played')

def main():
    args = parser.parse_args()
    env_class = RunEnv
    agent_class = eval('agents.{}'.format(args.agent))

    # Instantiate environment and agent
    env = env_class(parameters_folder=args.parameters, game_level=args.level,
                    chronic_looping_mode=args.loop_mode, start_id=args.start_id,
                    game_over_mode=args.game_over_mode, renderer_latency=args.latency,
                    without_overflow_cutoff=args.no_overflow_cutoff)
    agent = agent_class(env)
    # Instantiate game runner and loop
    runner = CustomRunner(env, agent, args.render, args.verbose, args.vverbose, args.parameters, args.level, args.niter)
    runner.loop(iterations=200, episodes=args.niter)

if __name__ == "__main__":
    main()


"""A threaded cv2 camera.

Largely from pyimagesearch.com
"""

import threading
import cv2

class CameraStream(object):
  def __init__(self, src=0):
    self.stream = cv2.VideoCapture(src)
    if not self.stream.isOpened():
      src = 1 - src
      self.stream = cv2.VideoCapture(src)
      if not self.stream.isOpened():
        sys.exit("Error: Camera didn't open for capture.")

    # Setup frame dims.
    self.stream.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, 320)
    self.stream.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, 240)

    self.grabbed, self.frame = self.stream.read()
    self.stopped = False

  def start(self):
    """Start the thread to read frames from the video stream."""
    t = threading.Thread(target=self.update, args=())
    t.daemon = True
    t.start()
    return self

  def update(self):
    """Grab frames until told to stop."""
    while not self.stopped:
      self.grabbed, self.frame = self.stream.read()

  def read(self):
    return self.frame

  def stop(self):
    self.stopped = True


import ouro_lib as ol
import json                             # for manipulating array data
import os                               # for basic OS functions
import pandas as pd                     # in-memory database capabilities
import argparse
from progress.bar import Bar
import datetime                         # used for stock timestamps
import alpaca_trade_api as tradeapi     # required for interaction with Alpaca
import csv
import logging
import time

# Get Quorum path from environment
quorumroot = os.environ.get("OURO_QUORUM", "C:\\TEMP")
actionpath = quorumroot + '\\broker-actions.json'
buyskippath = quorumroot + '\\broker-buyskip.json'
statuspath = quorumroot + '\\broker-status.csv'
logpath = quorumroot + '\\trader.log'
installpath = os.environ.get("OURO_INSTALL", "D:\\OneDrive\\Dev\\Python\\Oura")

# Setup Logging
logging.basicConfig(
    filename=logpath,
    filemode='a',
    format='%(asctime)s %(name)s %(levelname)s %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    level=os.environ.get("LOGLEVEL", "INFO"))

logging.info('OURO-TRADER logging enabled.')

# initialize files
try:
    logging.debug('Initializing trader files.')
    with open (statuspath, 'w', newline='\n', encoding='utf-8') as outfile:
        outfile.write('')
    with open (buyskippath, 'w', newline='\n', encoding='utf-8') as outfile:
        outfile.write('')
except Exception:
    logging.error('Could not initialize files', exc_info=True)
    quit()

# setup command line
parser = argparse.ArgumentParser(description="OURO-HISTORY:  Daily stock data ingestion.")
parser.add_argument("--test", action="store_true", default=False, help="Script runs in test mode.  FALSE (Default) = ignore if the market is closed; TRUE = only run while the market is open")
parser.add_argument("--marketopen", action="store_true", default=False, help="Force the market to be open for one execution.  FALSE (Default) = query the actual market; TRUE = set the market as open for one execution for testing purposes.")
cmdline = parser.parse_args()
logging.info('Command line arguement; test mode is ' + str(cmdline.test))

# Initialize the Alpaca API
alpaca = tradeapi.REST()

# Read the buy and sell strategies
strategies = pd.read_csv(installpath + '\\buy_strategies.csv')

# build simple index between family and average return percentage
familyreturns = {}
try:
    logging.debug('Building strategy families and average return percentages')
    for x in strategies['Family'].keys():
        familyreturns[strategies.at[x, 'Family']] = strategies.at[x, 'AvgPctRtn']
except Exception:
    logging.error('Could not build strategies', exc_info=True)

# Set maximum risk ratio to 0.5% of the account
# This ratio cannot be exceeded on a single trade
maxriskratio = .004

# Initialize the stock lists
boughtlist = []
skiplist = []
status = {}
closeprices = {}

# Get the closing prices for all the stocks from yesterday
query = "select ticker, c from stockdata..ohlcv_day o " \
        "where tradedate in (select dateadd(day, -1, max(tradedate)) from stockdata..ohlcv_day)"
crs = ol.sqldbcursor()
crs.execute(query)
for x in crs.fetchall():
    closeprices[x[0]] = x[1]

# Initialize MarketOpen
marketopen = ol.IsOpen()
eod = ol.IsEOD()

# Force the market open if configured to do so
if cmdline.marketopen:
    logging.info ('Forcing market to be open')
    marketopen = True
    eod = False

# Wait for the market to open unless it's a test
while not marketopen and not cmdline.test:
    logging.info('Market is closed; waiting for 1 minute.')
    marketopen = ol.IsOpen()
    ol.WaitForMinute()

# This is to work around an odd problem with Alpaca and the way it reports cash / buying power
account = ol.GetAccount()
cash = (float(account.buying_power) / (float(account.multiplier)))-25001 # minimum amount for day trading
tradecapital = cash / 10

while (marketopen and not eod) or cmdline.test is True:
    marketopen = ol.IsOpen()
    eod = ol.IsEOD()

    # Log info for heartbeat
    logging.info('Checking inbound stock actions.')

    # get ticker actions
    with open(actionpath, 'r', encoding='utf-8') as infile:
        inboundactions = json.load(infile)

    #setup a progress bar
    starttime = datetime.datetime.now().strftime('%H:%M:%S')
    logtime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    prgbar = Bar('  Stocks ' + starttime + ': ', max=len(inboundactions))

    # Bandwagonning happens where trader gets out of sync with pathfinder
    # and there is an abundance of orders (>10) that need to be bought.
    # This script will submit buy orders faster than they can be executed
    # so they're never seen in order count.  This helps limit the effect
    # of bandwagonning.
    inboundcount = 0
    for stock in inboundactions:
        if stock not in boughtlist and stock not in skiplist:
            inboundcount += 1

    # loop through the inbound stocks
    for stock in inboundactions:
        if inboundcount >= 10:
            # Give the order execution engine time to catch up
            time.sleep(2)
            # Reduce the risk if bandwaggoning is happening
            bandwagondiscount = .3
            logging.debug('Bandwagonning detected; reducing risk and delaying order placement.')
        else:
            # This is normal; risk is not modified
            bandwagondiscount = 1

        if stock not in boughtlist and stock not in skiplist:
            # how much is the stock
            stockprice = float(inboundactions[stock].get('price'))
            recenthigh = float(inboundactions[stock].get('recenthigh'))
            recentlow = float(inboundactions[stock].get('recentlow'))
            yesterdayclose = float(closeprices.get(stock))

            # set max trade risk
            maxriskamt = cash * maxriskratio * bandwagondiscount
            traderiskamt = cash * maxriskratio * bandwagondiscount

            # how much capital should I use on this trade?
            ordercount = ol.GetOrderCount()
            if ordercount < 10:
                # tradecapital = cash / float(10-ordercount)
                logging.debug('Orders are < 10; trade capital set to ' + str(tradecapital))
            else:
                # tradecapital = 0
                logging.debug('Orders count is > 10; trade capital set to 0')

            # how many shares should I buy
            ordershares = int(tradecapital/float(inboundactions[stock].get('price')))

            # reset pricing
            floorprice = 0
            ceilingprice = 0
            buylimit = 0
            traderiskpct = 0
            familyret = 0

            if ordercount < 10:
                # reset the skip reason
                skipreason = 'Unknown'

                # Get the strategy family and estimated return
                family = inboundactions[stock].get('strategyfamily')
                familyret = float(familyreturns[family]) * .8  # It's rare that the average is every filled

                # Set the baseline floor price and percent based on the return rate
                floorpct = familyret * .5
                floorprice = stockprice * (1-floorpct)

                # set the ceiling price for the bracket order
                ceilingprice = stockprice * (1 + float(familyreturns[family]))

                # Adjust prices to recent high/low if we're using oscilators
                if family != 'Candlestick':
                    # Pricing reality check -- are the prices achievable in the recent past?
                    if ceilingprice > recenthigh:
                        ceilingprice = recenthigh - 0.05  # $0.05 under the recent high
                    if floorprice > recentlow:
                        skipreason = 'Proposed stop-loss price already hit today'
                        ordershares = 0

                # Adjust the floor price if there is more risk than reward
                if (stockprice * ordershares * floorpct) > maxriskamt:
                    # Use 40% of the ceiling difference as the new floor amount
                    floorprice = stockprice - ((ceilingprice-stockprice) * .4) # I never want to break even on risk

                # Calculate the amount risked on this trade
                traderiskamt = (stockprice - floorprice) * ordershares
                traderiskpct = (stockprice - floorprice) / stockprice

                # set the buy limit to 5% of the potential profit
                buylimit = ((ceilingprice - stockprice) * .05) + stockprice

                # Calculate the trade return
                traderet = (ceilingprice - buylimit) / buylimit

                # Check if the price change between now and yesterday's close is more than
                # the average for this strategy family.
                if (stockprice - yesterdayclose) / yesterdayclose >= traderet:
                    ordershares = 0
                    skipreason = 'The potential return has already been met today.'

                # Are we planning on making more than we risk?
                if traderet-.005 <= traderiskpct:
                    # This is a bad trade
                    ordershares = 0
                    skipreason = 'Risk outweighs reward'

                # place the order
                if ordershares > 0:
                    try:
                        logging.debug('Placing a bracket order for' + stock)
                        alpaca.submit_order(
                            side='buy',
                            symbol=stock,
                            type='limit',
                            limit_price=buylimit,
                            qty=ordershares,
                            time_in_force='day', # bracket order must be 'day' or 'gtc'
                            order_class='bracket',
                            take_profit={
                                'limit_price': ceilingprice
                            },
                            stop_loss={
                                'stop_price': floorprice
                            }

                        )
                        # Add this to the stocks already bought
                        # Note:  Only add this to the bought list if the placing the order was successful
                        #        This allows the stock to be re-tried if the price falls below the stop
                        #        point before the buy order can be filled.
                        boughtlist.append(stock)
                        status[stock] = {
                            'DateTime': logtime,
                            'Ticker': stock,
                            'Cash': cash,
                            'TradeCapital': tradecapital,
                            'BuyPrice': stockprice,
                            'BuyLimit': buylimit,
                            'MaxRiskAmt': maxriskamt,
                            'TradeRiskAmt': traderiskamt,
                            'TradeRiskPct': traderiskpct,
                            'PortfolioRiskPct': traderiskamt/cash,
                            'FamilyReturnPct': familyret,
                            'TradeReturnPct' : traderet,
                            'OrderShares': ordershares,
                            'RecentHigh': recenthigh,
                            'RecentLow':  recentlow,
                            'FloorPrice': floorprice,
                            'CeilingPrice': ceilingprice,
                            'Decision': 'buy',
                            'Reason': family
                        }
                    except Exception as ex:
                        logging.error('Could not submit buy order', exc_info=True)
                        logging.info('Skipping ' + stock + ' because buy order failed.')
                        if stock not in skiplist:
                            # add this to the skip list -- the timing just wasn't right
                            # skiplist.append(stock) -- With buy limits, I don't need to do this.

                            # Annotate what happened
                            status[stock] = {
                                'DateTime': logtime,
                                'Ticker': stock,
                                'Cash': cash,
                                'TradeCapital': tradecapital,
                                'BuyPrice': stockprice,
                                'BuyLimit': buylimit,
                                'MaxRiskAmt': maxriskamt,
                                'TradeRiskAmt': traderiskamt,
                                'TradeRiskPct': traderiskpct,
                                'PortfolioRiskPct': traderiskamt / cash,
                                'FamilyReturnPct': familyret,
                                'TradeReturnPct': traderet,
                                'OrderShares': ordershares,
                                'RecentHigh': recenthigh,
                                'RecentLow': recentlow,
                                'FloorPrice': floorprice,
                                'CeilingPrice': ceilingprice,
                                'Decision': 'skip',
                                'Reason': skipreason + ' - buy order failed; eligible for retry.'
                            }
                else:
                    # define skipping reasons if not previously defined
                    if ordershares == 0 and skipreason == 'Unknown':
                        skipreason = 'Stock is too expensive or unable to buy shares.'
                    if stock in boughtlist and skipreason == 'Unknown':
                        skipreason = 'Stock in bought list.'
                    if ordercount >= 10 and skipreason == 'Unknown':
                        skipreason = 'Too many existing positions'

                    logging.info('Skipping ' + stock)
                    if stock not in skiplist:
                        # add this to the skip list -- the timing just wasn't right
                        skiplist.append(stock)
                        status[stock] = {
                            'DateTime': logtime,
                            'Ticker': stock,
                            'Cash': cash,
                            'TradeCapital': tradecapital,
                            'BuyPrice': stockprice,
                            'BuyLimit': buylimit,
                            'MaxRiskAmt': maxriskamt,
                            'TradeRiskAmt': traderiskamt,
                            'TradeRiskPct': traderiskpct,
                            'PortfolioRiskPct': traderiskamt/cash,
                            'FamilyReturnPct': familyret,
                            'TradeReturnPct' : traderet,
                            'OrderShares': ordershares,
                            'RecentHigh': recenthigh,
                            'RecentLow':  recentlow,
                            'FloorPrice': floorprice,
                            'CeilingPrice': ceilingprice,
                            'Decision': 'skip',
                            'Reason': skipreason + '; not eligible for retry.'
                        }
        # Update the order count after submitting the order
        ordercount = ol.GetOrderCount()

        #advance the progress bar
        prgbar.next()

    # finish the progress bar
    prgbar.finish()

    # write the bought and skip lists
    try:
        logging.debug('Writing bought and skip list.')
        with open (buyskippath, 'w', newline='\n', encoding='utf-8') as outfile:
            tmp = {
                'buy': boughtlist,
                'skip': skiplist
            }
            tmp = json.dumps(status, indent=4)
            outfile.write(tmp)
    except Exception:
        try:
            logging.error('Could not write buy and skip list', exc_info=True)
        except:
            print('Could not write to log file')

    # update broker status
    try:
        logging.debug('Writing broker status')
        with open (statuspath, 'w', newline='\n', encoding='utf-8') as outfile:
            fieldnames = ['DateTime', 'Ticker', 'Cash', 'TradeCapital', 'BuyPrice', 'BuyLimit', 'MaxRiskAmt',
                          'TradeRiskAmt', 'TradeRiskPct', 'PortfolioRiskPct', 'RiskPct', 'FamilyReturnPct', 'TradeReturnPct', 'OrderShares', 'RecentHigh',
                          'RecentLow','FloorPrice', 'CeilingPrice', 'Decision', 'Reason']
            writer = csv.DictWriter(outfile, fieldnames=fieldnames)
            # write the header
            writer.writeheader()
            #writer.writerow(['datetime', 'ticker', 'cash', 'TradeRiskAmt', 'TradeCapital', 'OrderShares', 'FloorPrice', 'CeilingPrice', 'Decision'])
            for x in status:
                writer.writerow(status[x])
    except Exception:
        try:
            logging.error('Could not write broker status', exc_info=True)
        except:
            print('Could not to log file.')

    # wait until the next minute before checking again
    ol.WaitForMinute()

# Log the transition to end of day processing
logging.info('Early end-of-day detected; checking for stocks that should be liquidated early.')

# Get stocks that should be sold early
try:
    crs = ol.sqldbcursor()
    query = "select ticker from stockdata..ticker_statistics where sellwhen = 'Early'"
    se = crs.execute(query)
    earlylist = []
    for x in se.fetchall():
        earlylist.append(x[0])
except Exception as ex:
    logging.error('Could not get list of early stocks.', exc_info=True)

logging.info('15-minute end-of-day check:  ' + str(ol.IsEOD(minutes=15)))

# If forcing the market open, simulate the end of day
eod = ol.IsEOD(minutes=15)
if cmdline.marketopen:
    eod = True

# Start wrapping up the day
while (not eod):
    # Check if a stock on an open order is in the early-sell list and cancel it
    for stock in ol.GetOrders():
        if stock.symbol in earlylist:
            try:
                alpaca.cancel_order(stock.id)
                logging.info('Cancelling open orders for ' + stock.symbol + ' early.')
            except Exception as ex:
                logging.error('Could not cancel order', exc_info=True)
    # If a held position is in the early sell list, close it
    for stock in ol.GetPositions():
        if stock.symbol in earlylist:
            try:
                alpaca.close_position(stock.symbol)
                logging.info('Closing open positions for ' + stock.symbol + ' early.')
            except Exception as ex:
                logging.error('Could not close position', exc_info=True)

    # Wait for a minute until we're 15 minutes before the end of the day
    time.sleep(60)

    # If forcing the market open, simulate the end of day
    eod = ol.IsEOD(minutes=15)
    if cmdline.marketopen:
        eod = True
    logging.info('15-minute end-of-day check:  ' + str(eod))

# It's the end of the day; cancel orders and quit
logging.info('End of day reached; liquidating all orders.')
try:
    alpaca.cancel_all_orders()
    alpaca.close_all_positions()
except Exception as ex:
    logging.error('Could not cancel orders and liquidate positions at the end of the day.', exc_info=True)


import asyncio
import logging
import pathlib
from lsst.dm.csc.base.archiver_csc import ArchiverCSC
from lsst.dm.CCArchiver.ccdirector import CCDirector
from lsst.ts import salobj

LOGGER = logging.getLogger(__name__)

class CCArchiverCSC(ArchiverCSC):
    """ CCArchiverCSC is a specialization of an Archiver CSC

    Parameters
    ----------
    index : `str`
    """

    def __init__(self):
        super().__init__("CCArchiver", initial_state=salobj.State.STANDBY)

        # receive events from CCCamera
        camera_events = {'endReadout', 'startIntegration'}
        self.camera_remote = salobj.Remote(self.domain, "CCCamera", readonly=True, include=camera_events,
                                           evt_max_history=0)
        self.camera_remote.evt_endReadout.callback = self.endReadoutCallback
        self.camera_remote.evt_startIntegration.callback = self.startIntegrationCallback

        # receive events from CCHeaderService
        cchs_events = {'largeFileObjectAvailable'}
        self.cchs_remote = salobj.Remote(self.domain, "CCHeaderService",
                                         readonly=True, include=cchs_events,
                                         evt_max_history=0)
        self.cchs_remote.evt_largeFileObjectAvailable.callback = self.largeFileObjectAvailableCallback

        # set up message director for ComCam
        self.director = CCDirector(self, "CCArchiver", "ccarchiver_config.yaml", "CCArchiverCSC.log")
        self.director.configure()

        # used to indicate that the CSC is in the process of transitioning to the FAULT state so
        # that it happens once, and not multiple times.
        self.transitioning_to_fault_evt = asyncio.Event()
        self.transitioning_to_fault_evt.clear()

        self.current_state = None
        LOGGER.info("************************ Starting CCArchiver ************************")


from flask import Flask
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import os
from dotenv import load_dotenv

load_dotenv()

app = Flask(__name__)

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']

# The ID of the target Google Drive folder where the new spreadsheet will be created
TARGET_FOLDER_ID = os.environ.get("TARGET_FOLDER_ID")

def create_spreadsheet():
    """Creates a new spreadsheet in Google Sheets and returns its ID"""
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    try:
        service = build('sheets', 'v4', credentials=creds)

        # Create a new spreadsheet with a specific name in the target folder
        spreadsheet_name = "New Spreadsheet"
        body = {
            "parents": [TARGET_FOLDER_ID],
            "properties": {"title": spreadsheet_name},
        }
        spreadsheet = service.spreadsheets().create(body=body).execute()
        spreadsheet_id = spreadsheet['spreadsheetId']
        return spreadsheet_id
    except HttpError as err:
        print(err)

@app.route('/')
def create_sheet():
    spreadsheet_id = create_spreadsheet()
    return f"New Spreadsheet created with ID: {spreadsheet_id}"

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


import dash
import plotly.express as px
import pandas as pd
from dash import html, dcc, dash_table
from dash.dependencies import Input, Output
from joblib import load

df = pd.read_csv('diamonds_cleared.csv')
y_pred_sfs = load('y_pred_sfs.joblib')
model_sfs = load('model_sfs.joblib')
X_test_sfs = pd.read_csv('X_test_sfs.csv')
y_test_sfs = pd.read_csv('y_test_sfs.csv')
X_train_sfs = pd.read_csv('X_train_sfs.csv')
continuous_columns = ['carat', 'x dimension', 'y dimension', 'z dimension', 'depth', 'table', 'price']
categorical_columns = ['clarity', 'color', 'cut']

app = dash.Dash(__name__)
def update_residuals_plot():
    y_pred_sfs = model_sfs.predict(X_test_sfs)
    residuals = y_test_sfs['price'] - y_pred_sfs
    fig = px.scatter(x=y_pred_sfs, y=residuals, labels={'x': 'Przewidywane wartości', 'y': 'Reszty'})
    fig.add_hline(y=0, line_dash="dash")
    fig.update_layout(
        bargap=0.2
    )
    return fig
def update_feature_importance_plot():
    feature_importance = pd.DataFrame(model_sfs.coef_, index=X_train_sfs.columns, columns=['importance'])
    feature_importance = feature_importance.sort_values('importance', ascending=False)

    fig = px.bar(feature_importance, x='importance', y=feature_importance.index, orientation='h')
    fig.update_layout(title='Wizualizacja ważności cech dla modelu selekcji postępującej',
                      xaxis_title='Ważność cechy',
                      yaxis_title='Nazwa cechy',
                      bargap=0.2
    )
    return fig
def update_predicted_vs_actual_plot():
    # Stwórz wykres
    fig = px.scatter(x=y_test_sfs['price'], y=y_pred_sfs)
    fig.add_scatter(x=[y_test_sfs['price'].min(), y_test_sfs['price'].max()],
                    y=[y_test_sfs['price'].min(), y_test_sfs['price'].max()],
                    mode='lines', line=dict(color='red', dash='dash'),
                    name='Linia Idealna')
    fig.update_layout(title='Porównanie rzeczywistych i przewidywanych wartości dla modelu selekcji postępującej',
                      xaxis_title='Rzeczywiste wartości',
                      yaxis_title='Przewidywane wartości',
                      bargap=0.2)

    return fig

# --------------------------------------------------------------------------------------
# Layout
# --------------------------------------------------------------------------------------
app.layout = html.Div([
    html.Div(className='header', children=[
        html.H1("Dashboard - s21415")
    ]),

    html.Div(className='dropdown', children=[
        html.H2("Rozkład zmiennych"),
        dcc.Dropdown(
            id='continuous-dropdown',
            options=[{'label': col, 'value': col} for col in continuous_columns],
            value=continuous_columns[0]
        )
    ]),

    dcc.Graph(id='continuous-histogram'),

    html.H2("Zależności ceny od innych zmiennych"),
    dcc.Dropdown(
        id='price-dependency-dropdown',
        options=[{'label': col, 'value': col} for col in continuous_columns if col != 'price'],
        value=continuous_columns[0]
    ),
    dcc.Graph(id='price-dependency-scatter'),

    html.H2("Liczebność kategorii"),
    dcc.Dropdown(
        id='category-dropdown',
        options=[{'label': col, 'value': col} for col in categorical_columns],
        value=categorical_columns[0]
    ),
    dcc.Graph(id='category-countplot'),
    html.H2("Podgląd Danych"),
    dash_table.DataTable(
        id='data-table',
        columns=[{"name": i, "id": i} for i in df.columns],
        data=df.to_dict('records'),
        page_size=20,  # Liczba wierszy na stronę
        style_cell={'textAlign': 'left'},
        style_header={
            'backgroundColor': 'white',
            'fontWeight': 'bold'
        },
        style_data_conditional=[
            {
                'if': {'row_index': 'odd'},
                'backgroundColor': 'lightgrey'
            }
        ],
        style_table={'height': '300px', 'overflowY': 'auto'}
    ),
    html.Div([
        dcc.Graph(figure=update_residuals_plot(), id='residuals-plot'),
        dcc.Graph(figure=update_feature_importance_plot(), id='feature-importance-plot'),
        dcc.Graph(figure=update_predicted_vs_actual_plot(), id='predicted-vs-actual-plot')

    ])
], style={'fontFamily': 'Arial, sans-serif'})

# --------------------------------------------------------------------------------------
# Callbacki
# --------------------------------------------------------------------------------------
@app.callback(
    Output('continuous-histogram', 'figure'),
    [Input('continuous-dropdown', 'value')]
)
def update_continuous_histogram(selected_column):
    fig = px.histogram(df, x=selected_column, marginal="box")
    fig.update_layout(bargap=0.2)

    return fig

@app.callback(
    Output('price-dependency-scatter', 'figure'),
    [Input('price-dependency-dropdown', 'value')]
)
def update_price_dependency_scatter(selected_column):
    fig = px.scatter(df, x=selected_column, y='price')
    return fig

@app.callback(
    Output('category-countplot', 'figure'),
    [Input('category-dropdown', 'value')]
)
def update_category_countplot(selected_column):
    fig = px.histogram(df, x=selected_column)
    fig.update_layout(bargap=0.2)
    return fig

def update_table(xaxis_column_name):
    table = html.Table([
        html.Thead(
            html.Tr([html.Th(col) for col in df.columns])
        ),
        html.Tbody([
            html.Tr([
                html.Td(df.iloc[i][col]) for col in df.columns
            ]) for i in range(min(len(df), 10))
        ])
    ])
    return table

if __name__ == '__main__':
    app.run_server(debug=True)


from typing import List

class Solution:
    def findDisappearedNumbers(self, nums: List[int]) -> List[int]:
        dic = dict()
        for i in range(1, len(nums) + 1):
            dic[i] = 0

        for num in nums:
            dic[num] += 1

        res = []
        for i, v in dic.items():
            if v == 0:
                res.append(i)

        return res

sol = Solution()
print(sol.findDisappearedNumbers([1, 2, 3, 5, 5]))


from django.shortcuts import render, redirect, reverse, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib import messages

from .models import Blog, Comment
from .forms import BlogForm, CommentForm

# Create your views here.
def blog(request):
    """ Return blog page """
    blogs = Blog.objects.all()

    context = {
        'blogs': blogs,
    }

    return render(request, 'blog/blog.html', context)

def blog_detail(request, blog_id):
    """ Return individual blog details """

    blog_detail = get_object_or_404(Blog, pk=blog_id)
    comments = blog_detail.comments.order_by("-created_on")
    liked = False
    if blog_detail.likes.filter(id=request.user.id).exists():
        liked = True

    context = {
        'blog_detail': blog_detail,
        'comments': comments,
        "liked": liked,
        'commentform': CommentForm(),
    }

    return render(request, 'blog/blog_detail.html', context)

@login_required
def like_blog(request, blog_id):
    """ Like a blog """

    blog = get_object_or_404(Blog, pk=blog_id)
    redirect_url = request.POST.get('redirect_url')

    if blog.likes.filter(id=request.user.id).exists():
        blog.likes.remove(request.user)
    else:
        blog.likes.add(request.user)

    return redirect(redirect_url)

@login_required
def comment(request, blog_id):
    """ Comment on a blog """

    blog = get_object_or_404(Blog, pk=blog_id)
    redirect_url = request.POST.get('redirect_url')

    if request.method == 'POST':
        commentform = CommentForm(request.POST, request.FILES)
        if commentform.is_valid():
            commentform.instance.name = request.user.username
            commentform.instance.blog = blog
            comment = commentform.save()
            messages.success(request, 'Successfully commented!')
            return redirect(reverse('blog_detail', args=[blog.id]))
        else:
            messages.error(request, (
                'Comment Failed. Please ensure the form is valid.'))
            form = CommentForm()

    return redirect(redirect_url)

@login_required
def edit_comment(request, comment_id):
    """ Edit a comment on a blog """

    comment = get_object_or_404(Comment, pk=comment_id)
    if request.method == 'POST':
        form = CommentForm(request.POST, request.FILES, instance=comment)
        success_url = request.POST.get('previous_page')
        if form.is_valid():
            form.save()
            messages.success(request, 'Successfully updated Comment!')
            return redirect(success_url)
        else:
            messages.error(request, (
                'Failed to update Comment. Please ensure the form is valid.'))
    else:
        form = CommentForm(instance=comment)
        messages.info(request, 'You are editing')

    template = 'blog/edit_comment.html'
    context = {
        'form': form,
        'comment': comment,
    }

    return render(request, template, context)

@login_required
def delete_comment(request, comment_id):
    """ Delete a comment from a blog """

    comment = get_object_or_404(Comment, pk=comment_id)
    query = request.GET.get('query')
    comment.delete()
    messages.success(request, 'comment deleted!')
    return redirect(reverse('blog_detail', args=[query]))

@login_required
def add_blog(request):
    """ Add a blog to the store """

    if not request.user.is_superuser:
        messages.error(request, 'Sorry, only an admin can access this page.')
        return redirect(reverse('home'))

    if request.method == 'POST':
        form = BlogForm(request.POST, request.FILES)
        if form.is_valid():
            blog = form.save()
            messages.success(request, 'Successfully added blog!')
            return redirect(reverse('blog_detail', args=[blog.id]))
        else:
            messages.error(request, (
                'Failed to add blog. Please ensure the form is valid.'))
    else:
        form = BlogForm()

    template = 'blog/add_blog.html'
    context = {
        'form': form,
    }

    return render(request, template, context)

@login_required
def edit_blog(request, blog_id):
    """ Edit a blog in the store """

    if not request.user.is_superuser:
        messages.error(request, 'Sorry, only an admin can access this page.')
        return redirect(reverse('home'))

    blog = get_object_or_404(Blog, pk=blog_id)
    if request.method == 'POST':
        form = BlogForm(request.POST, request.FILES, instance=blog)
        if form.is_valid():
            form.save()
            messages.success(request, 'Successfully updated Blog!')
            return redirect(reverse('blog_detail', args=[blog.id]))
        else:
            messages.error(request, (
                'Failed to update Blog. Please ensure the form is valid.'))
    else:
        form = BlogForm(instance=blog)
        messages.info(request, f'You are editing {blog.title}')

    template = 'blog/edit_blog.html'
    context = {
        'form': form,
        'blog': blog,
    }

    return render(request, template, context)

@login_required
def delete_blog(request, blog_id):
    """ Delete a blog from the store """

    if not request.user.is_superuser:
        messages.error(request, 'Sorry, only an admin can access this page.')
        return redirect(reverse('home'))
    blog = get_object_or_404(Blog, pk=blog_id)
    blog.delete()
    messages.success(request, 'Blog deleted!')
    return redirect(reverse('blog'))


#healthy programmer
"""
water reminder after every 26 min
exercise reminder after every 45 min
eyes relief reminder after every 30 min
"""
from pygame import mixer
from datetime import datetime
from time import time

def musiconloop(file,stopper):
    mixer.init()
    mixer.music.load(file)
    mixer.music.play()
    while(True):
        a = input()
        if a == stopper:
            mixer.music.stop()
            break
def log_now(msg):
    with open("mylogs.txt","a") as f:
        f.write(f"{msg} {datetime.now()}\n")
if __name__ == '__main__':
    init_water = time()
    init_exercise = time()
    init_eyes = time()
    watersecs = 1560
    exsecs = 2700
    eyessecs = 1800
    while True:
        if init_water>watersecs:
            print("time to drink water. Enter 'drank' to stop the alarm")
            musiconloop("water.mp3","drank")
            init_water = time()
            log_now("drank water at ")
        elif init_exercise>exsecs:
            print("time to exercise. Enter 'done' to stop the alarm")
            musiconloop("exercise.mp3","done")
            init_exercise = time()
            log_now("done exercise at ")
        elif init_eyes>eyessecs:
            print("time for eyes relief. Enter 'yes' to stop the alarm")
            musiconloop("eyes.mp3","yes")
            init_water = time()
            log_now("eyes relieved at ")


from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from dotenv import load_dotenv
import os

db = SQLAlchemy()
migrate = Migrate()
load_dotenv()

def create_app(test_config=None):
    app = Flask(__name__)
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

    if test_config is None:
        app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get(
            "SQLALCHEMY_DATABASE_URI")
    else:
        app.config["TESTING"] = True
        app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get(
            "SQLALCHEMY_TEST_DATABASE_URI")

    # Import models here for Alembic setup
    # Example:
    # from app.models.model import Model

    db.init_app(app)
    migrate.init_app(app, db)

    # Register Blueprints here
    # Example:
    # app.register_blueprint(task_page)

    return app


import gpiozero
from time import process_time

class driveBase():
    def __init__(self, port1: int, port2: int, port3: int, port4: int, defaultSpeed=100) -> None:
        """
        A class for all your robot driving needs. Use these functions for any movement.

        :param int port1:
        The GPIO pin to use for forward input in the left motor.

        :param int port2:
        The GPIO pin to use for forward input in the right motor.

        :param int port3:
        The GPIO pin to use for backward input in the left motor.

        :param int port4:
        The GPIO pin to use for backward input in the right motor.
        """

        self.lMotor = gpiozero.Motor(port1, port3, pwm=True)
        self.rMotor = gpiozero.Motor(port2, port4, pwm=True)

        self.defaultSpeed = max(0, min(defaultSpeed, 100))

    def drive(self, speed: int = None, turnAngle: int = 0) -> None:
        """
        Makes the robot drive. What did you think this did?

        :param int speed:
          Controls the speed at which to drive at. choose a number between -1000 and 1000.

        :param int turnAngle:
          A number that controls the speed at which to turn. negative is left, positive is right. Default value is zero.
        """

        if speed == None:
            speed = self.defaultSpeed

        turnAngle = max(-100, min(turnAngle, 100))

        lSpeed = 0
        rSpeed = 0

        if turnAngle < 0:
            rSpeed = -turnAngle * speed / 100
            lSpeed = (100 + turnAngle) * speed / 100
        else:
            rSpeed = (100 - turnAngle) * speed / 100
            lSpeed = turnAngle * speed / 100

        self.lMotor.forward(lSpeed)
        self.rMotor.forward(rSpeed)

    def stop(self) -> None:
        """
        Stops driving immediately.
        """

        self.lMotor.stop()
        self.rMotor.stop()

    def straight(self, distance: float, speed: int) -> None:
        """
        Drives straight for a period of time.

        :param float distance:
        The amount of time that the robot drives for.

        :param int speed:
        The speed at which to drive at.
        """

        self.stop()

        self.lMotor.forward(speed)
        self.rMotor.forward(speed)

        timeToStop = process_time + distance
        while process_time < timeToStop:
            pass

        self.stop()


import requests
from bs4 import BeautifulSoup
import spotipy
from spotipy.oauth2 import SpotifyOAuth
import os

BILLBOARD_URL = "https://www.billboard.com/charts/hot-100"

date = input("Which year do you want to travel to? Type the date in this format YYYY-MM-DD: ")
year = date.split('-')[0]

response = requests.get(f"{BILLBOARD_URL}/{date}/")
billboard_web = response.text
soup = BeautifulSoup(billboard_web, "html.parser")

songs = soup.select(selector="li #title-of-a-story")
songs_list = [song.getText().strip() for song in songs]

SPOTIPY_CLIENT_ID = os.environ.get("SPOTIPY_CLIENT_ID")
SPOTIPY_CLIENT_SECRET = os.environ.get("SPOTIPY_CLIENT_SECRET")
SPOTIPY_REDIRECT_URI = os.environ.get("SPOTIPY_REDIRECT_URI")

SCOPE = "playlist-modify-private"
sp = spotipy.Spotify(
    auth_manager=SpotifyOAuth(
        client_id=SPOTIPY_CLIENT_ID,
        client_secret=SPOTIPY_CLIENT_SECRET,
        redirect_uri=SPOTIPY_REDIRECT_URI,
        scope="playlist-modify-private",
        show_dialog=True,
        cache_path="token.txt"
    )
)

user_id = sp.current_user()["id"]

song_uri = []

for song in songs_list:
    try:
        result = sp.search(q=f"track: {song} year: {year}", type="track")
        uri = result["tracks"]["items"][0]["uri"]
    except IndexError:
        print(f"{song} doesn't exist in Spotify. Skipped.")
    else:
        song_uri.append(uri)

playlist = sp.user_playlist_create(
    user=user_id,
    name=f"{date} Billboard Hot 100",
    public=False,
    description=f"This is a playlist of the top 100 on Billboard in {date}",
)

sp.playlist_add_items(playlist_id=playlist["id"], items=song_uri)


import cv2
import numpy as np

'''
modified from solution on this page:
https://stackoverflow.com/questions/56905592/automatic-contrast-and-brightness-adjustment-of-a-color-photo-of-a-sheet-of-pape
'''

def adjust_gamma(image, gamma=1.2):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
                      for i in np.arange(0, 256)]).astype("uint8")

    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

BLOCK_SIZE = 40
DELTA = 25

def preprocess(image):
    image = cv2.GaussianBlur(image, (3, 3), 0)
    return 255 - image

def get_block_index(image_shape, yx, block_size):
    y = np.arange(max(0, yx[0]-block_size),
                  min(image_shape[0], yx[0]+block_size))
    x = np.arange(max(0, yx[1]-block_size),
                  min(image_shape[1], yx[1]+block_size))
    return np.meshgrid(y, x)

def adaptive_median_threshold(img_in):
    med = np.median(img_in)
    img_out = np.zeros_like(img_in)
    img_out[img_in - med < DELTA] = 255
    kernel = np.ones((3, 3), np.uint8)
    img_out = 255 - cv2.dilate(255 - img_out, kernel, iterations=2)
    return img_out

def block_image_process(image, block_size):
    out_image = np.zeros_like(image)
    for row in range(0, image.shape[0], block_size):
        for col in range(0, image.shape[1], block_size):
            idx = (row, col)
            block_idx = get_block_index(image.shape, idx, block_size)
            out_image[block_idx] = adaptive_median_threshold(image[block_idx])
    return out_image

def process_image(img):
    image_in = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    image_in = preprocess(image_in)
    image_out = block_image_process(image_in, BLOCK_SIZE)
    return image_out

def adjust_image(img):
    adjust = adjust_gamma(img)
    process = process_image(adjust)
    ret, thresh = cv2.threshold(process, 127, 255, cv2.THRESH_BINARY_INV)
    dilate = cv2.dilate(thresh, None)
    erode = cv2.erode(dilate, None)
    return erode


import pandas as pd
import numpy as np
import os
import sys
import matplotlib.pyplot as plt
import geopandas as gpd
import json
import glob
import datetime
from functools import reduce
from _1_calculate_revised_snow_drought_new_SWE import FormatData,CalcSnowDroughts
import snow_drought_definition_revision_new_SWE as sd
from snow_drought_definition_revision_new_SWE import DefineClusterCenters
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report
import seaborn as sns
from scipy.stats import pearsonr
import matplotlib.ticker as ticker
import pymannkendall as mk
from scipy import stats

def mk_test(input_data):
	"""Run a version of the Mann-Kendall trend test."""

	trend, h, p, z, Tau, s, var_s, slope, intercept = mk.original_test(input_data)

	return trend, h, p, z, Tau, s, var_s, slope, intercept

def plot_counts(df_list,output_dir,huc_col='huc8',**kwargs):
	print('Entered the plotting function: ')
	labels=['Snotel','UA SWE']

	nrow=3
	ncol=3
	fig,axs = plt.subplots(nrow,ncol,sharex=True,sharey=True,
				gridspec_kw={'wspace':0.01,'hspace':0},
                                    #'top':0.95, 'bottom':0.075, 'left':0.05, 'right':0.95},
                figsize=(8,6))
	cols=['dry','warm','warm_dry']
	xlabels=['Dry', 'Warm', 'Warm/dry']
	ylabels=['Early','Mid','Late']
	output_dict = {}
	mk_dict = {}
	count = 0
	for x in range(3):
		for y in range(3):

			#produce the count plots
			s_counts = df_list[x][f's_{cols[y]}'].value_counts().sort_index().astype('int')
			ua_counts = df_list[x][f'ua_{cols[y]}'].value_counts().sort_index().astype('int')
			# print(s_counts)
			# print(ua_counts)
			df = pd.DataFrame({"snotel":s_counts,"ua_swe":ua_counts})
			#reformat a few things in the df
			df.index=df.index.astype(int)
			df.replace(np.nan,0,inplace=True)

			#there are not droughts in all the years and timeframes but these gaps mess up plotting
			#so we want to infill them with zeros so all the timeperiods have all of the years.
			df=df.reindex(np.arange(1991,2021), fill_value=0)
			mk_dict.update({f's_{ylabels[x]}_{xlabels[y]}':mk_test(df.snotel)[0],
				f'ua_{ylabels[x]}_{xlabels[y]}':mk_test(df.ua_swe)[0]})
			#add the counts to a dict so we can output the actual counts and look at them
			output_dict.update({f's_{ylabels[x]}_{xlabels[y]}':df['snotel'],f'ua_{ylabels[x]}_{xlabels[y]}':df['ua_swe']})

			# calculate Pearson's correlation
			corr, _ = pearsonr(df.snotel, df.ua_swe)
			rho, pval = stats.spearmanr(df.snotel, df.ua_swe)
			print(f'Pearsons correlation: {corr}')

			df.plot.bar(ax=axs[x][y],color=['#D95F0E','#267eab'],width=0.9,legend=False)#,label=['Dry','Warm','Warm/dry']) #need to do something with the color scheme here and maybe error bars? This could be better as a box plot?
			axs[x][y].grid(axis='both',alpha=0.25)

			#set axis labels and annotate
			axs[x][y].annotate(f'\u03C1 = {round(rho,2)}',xy=(0.05,0.9),xycoords='axes fraction',fontsize=10)
			#add a subplot letter id
			axs[x][y].annotate(f'{chr(97+count)}',xy=(0.85,0.9),xycoords='axes fraction',fontsize=10,weight='bold')#f'{chr(97)}'
			axs[0][y].set_title(xlabels[y],fontdict={'fontsize': 10})
			axs[x][0].set_ylabel(ylabels[x],fontsize=10)
			# ax1.set_ylabel("Snow drought quantities")
			axs[2][2].legend(labels=labels,loc='center right',prop={'size': 10})
			axs[x][y].xaxis.set_major_locator(ticker.MultipleLocator(5))
			# for tick in axs[x][y].get_xticklabels():
			# 	tick.set_rotation(90)
			# 	print('tick is: ',tick)
			# 	print(type(tick))
			# 	#tick.label.set_fontsize(14)
			axs[x][y].tick_params(axis='x', labelsize=8)
			count += 1
	fig.text(0.025, 0.5, 'Snow drought count', va='center', rotation='vertical')

	print('mk dict is')
	print(mk_dict)
	stats_fn = os.path.join(output_dir,f'{huc_col}_ua_swe_snotel_snow_drought_counts_spearman_w_delta_swe_proj_final1.csv')
	output_df = pd.DataFrame(output_dict)
	if not os.path.exists(stats_fn):
		output_df.to_csv(stats_fn)
	fig_fn = os.path.join(kwargs.get('fig_dir'),f'ua_swe_counts_snotel_{huc_col}_spearman_w_delta_swe_proj_final_new_legend.jpg')
	if not os.path.exists(fig_fn):
		plt.savefig(fig_fn,
			dpi=500,
			bbox_inches = 'tight',
    		pad_inches = 0.1
    	)
	# plt.show()
	# plt.close('all')

def main(model_dir,pickles,start_date='1980-10-01',end_date='2020-09-30',huc_col = 'huc8', **kwargs):
	"""Testing improved definitions of snow drought. Original definitions based on Dierauer et al 2019 but trying to introduce some more nuance into the approach."""
	print(f'The huc col being processed is: {huc_col}')
	################################################################
	#first do the UA swe data - this is now (9/20/2021) in two different files, one from UA SWE and one from PRISM.
	#These are combined in _0_combine_ua_swe_w_prism.py
	early=FormatData(glob.glob(model_dir+f'*_12_months_data_output_formatted_combined.csv'),drop_cols=[]).read_in_csvs()
	mid=FormatData(glob.glob(model_dir+f'*_2_months_data_output_formatted_combined.csv'),drop_cols=[]).read_in_csvs()
	late=FormatData(glob.glob(model_dir+f'*_4_months_data_output_formatted_combined.csv'),drop_cols=[]).read_in_csvs()
	################################################################
	#next do the snotel data
	output=[]
	print('early')
	print(early)
	#read in some pickled objects, these look like a list of dfs with each being a station for the full time period
	for item in ['PREC','TAVG','WTEQ']:
		#get the pickled objects for each parameter
		files = glob.glob(pickles+f'*{item}_{start_date}_{end_date}_snotel_data_list') #hardcoded currently
		df=FormatData(files,drop_cols=['year','month','day']).read_in_pickles()
		output.append(df) #the df here is 365 days x ~30 yrs x 237 stations so these are pretty big dfs

	#join the three enviro params
	output_df = reduce(lambda left,right: pd.merge(left,right,how='inner',on=['date','id']), output)

	#convert the temp column from F to C
	output_df['TAVG'] = (output_df['TAVG']-32)*(5/9)
	#there are a couple of erroneous temp values, remove those
	output_df = output_df.loc[output_df['TAVG'] < 50]
	output_df = output_df.loc[output_df['TAVG'] > -40]

	#convert prec and swe cols from inches to mm
	output_df['PREC'] = output_df['PREC']*25.4
	output_df['WTEQ'] = output_df['WTEQ']*25.4

	#remove rows that have one of the data types missing- this might need to be amended because
	#it means that there are different numbers of records in some of the periods.
	output_df=output_df.dropna() #commented out 9/21/2021

	#cast the snotel id col to int to add the hucs
	output_df['id'] = output_df['id'].astype('int')

	#add the as yet nonexistant hucs data to the outputs
	hucs = kwargs.get('hucs')
	output_df[huc_col] = output_df['id'].map(hucs)
	#just doing this to get the snotel ids that we're using in later steps before we take the mean below
	id_df = output_df
	#there are multiple snotel stations in some of the basins,
	#combine those so there is just one number per basin like the
	#ua swe and RS data.

	output_df=output_df.groupby([huc_col,'date'])[['PREC','WTEQ','TAVG']].mean().reset_index()

	period_list = []
	for p1,p2 in zip(['early','mid','late'],[early,mid,late]):
		#get snotel first
		#make a temporal chunk of data- this is all seasonal windows irrespective of the year
		snotel_chunk=FormatData(None,time_period=p1).split_yearly_data(output_df)

		#####
		#####
		#new for UA SWE- there are some basins which extend into Canada but PRISM and UA SWE do not.
		#as of 9/22/2021 these basins are removed because there are no stats for the area north of the border.
		if huc_col == 'huc8':
			snotel_chunk = snotel_chunk.loc[~snotel_chunk[huc_col].isin(kwargs.get('remove_ids'))]
			p2 = p2.loc[~p2[huc_col].isin(kwargs.get('remove_ids'))]
		else:
			pass
		# print('Snotel chunk looks like: ')
		# pd.set_option("display.max_rows", None, "display.max_columns", None)
		# print(snotel_chunk.head(100))
		##########working below here
		############################
		#calculate the snow droughts for that chunk
		if (p1 == 'mid') | (p1 == 'late'):
			print('processing snotel')
			snotel_drought=CalcSnowDroughts(snotel_chunk,swe_c='WTEQ',precip='PREC',temp='TAVG',start_year=1991,sort_col=huc_col).prepare_df_cols()
		else:
			print('processing snotel')
			snotel_drought=CalcSnowDroughts(snotel_chunk,swe_c='WTEQ',precip='PREC',temp='TAVG',sort_col=huc_col).prepare_df_cols()

		#then do the same for ua SWE
		if (p1 == 'mid') | (p1 == 'late'):
			print('processing uaswe')
			ua_swe_drought=CalcSnowDroughts(p2,start_year=1991,sort_col=huc_col).prepare_df_cols()
		else:
			print('processing uaswe')
			ua_swe_drought=CalcSnowDroughts(p2,sort_col=huc_col).prepare_df_cols()

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

		#run the kmeans with drought types as intiilization conditions (centroids) for the clusters

		#these are all of the huc 4 basins in the study area
		huc4s = ['1708','1801','1710','1711','1709','1701','1702','1705','1703','1601','1707','1706','1712','1704']
		#use a subset to run a test for maritime snowpack
		#huc4s = ['1711','1709','1702','1703','1708','1707','1703','1702']
		#use a subset to run an alpine(ish) snowpack
		#huc4s = ['1704','1706','1601','1705']
		s_output = []
		ua_output = []
		for huc4 in huc4s:
			huc4_s = sd.prep_clusters(snotel_drought,huc4,p1,huc_col=huc_col) #get the subset of the snow drought data for a given huc4
			huc4_ua = sd.prep_clusters(ua_swe_drought,huc4,p1,huc_col=huc_col) #period added 9/21/2021 to make sure these get attributed to the correct water year
			#make the centroids that serve as the intialization for the kmeans clusters- these are like endmembers (ish)
			s_centroids = DefineClusterCenters(huc4_s,'WTEQ','PREC','TAVG').combine_centroids() #makes a numpy array with four centroids
			ua_centroids = DefineClusterCenters(huc4_ua,'swe','ppt','tmean').combine_centroids() #makes a numpy array with four centroids

			#clusters should be like: {0:dry, 1:warm, 2:warm_dry, 3:no_drought} 6/8/2021 DOUBLE CHECK
			#run kmeans for the snotel data
			s_clusters = sd.run_kmeans(huc4_s[['WTEQ','PREC','TAVG']].to_numpy(),huc4_s['label'],s_centroids)
			s_clusters = sd.add_drought_cols_to_kmeans_output(s_clusters, huc_col=huc_col) #add a few cols needed for plotting
			#run kmeans for the daymet data
			ua_clusters = sd.run_kmeans(huc4_ua[['swe','ppt','tmean']].to_numpy(),huc4_ua['label'],ua_centroids)
			ua_clusters = sd.add_drought_cols_to_kmeans_output(ua_clusters, huc_col=huc_col) #add a few cols needed for plotting

			s_output.append(s_clusters)
			ua_output.append(ua_clusters)
		s_plot = pd.concat(s_output)

		#select the cols of interest and rename so there's no confusion when dfs are merged
		s_plot=s_plot[[huc_col,'year','dry','warm','warm_dry']]
		s_plot.columns=[huc_col,'year']+['s_'+column for column in s_plot.columns if not (column == huc_col) | (column=='year')]

		ua_plot = pd.concat(ua_output)
		ua_plot=ua_plot[[huc_col,'year','dry','warm','warm_dry']]
		ua_plot.columns=[huc_col,'year']+['ua_'+column for column in ua_plot.columns if not (column == huc_col) | (column=='year')]

		#merge the two datasets into one df
		dfs = s_plot.merge(ua_plot,on=[huc_col,'year'],how='inner')
		# print('The final ds looks like: ')
		# print(dfs.head(50))
		#deal with the scenario that there are basins with less than 30 years of data, remove those here
		dfs = sd.remove_short_dataset_stations(dfs,huc_col)
		print()
		print(f'There are now {len(dfs[huc_col].unique())} unique stations in the seasonal window')
		hucs=list(dfs[huc_col].astype(int).unique())
		print(hucs)
		print(len(hucs))
		# test = id_df.loc[id_df['huc8'].isin(dfs['huc8'].astype(int).unique())]['id'].unique()
		# print(test)
		period_list.append(dfs)

	plot_counts(period_list,kwargs.get('stats_dir'),huc_col=huc_col,**kwargs)

if __name__ == '__main__':
	params = sys.argv[1]
	with open(str(params)) as f:
		variables = json.load(f)

		#construct variables from param file
		pickles=variables['pickles']
		stations=variables['stations']
		ua_swe_dir=variables['ua_swe_dir']
		stats_dir = variables['stats_dir']
		fig_dir = variables['fig_dir']

	hucs=pd.read_csv(stations)

	#get just the id cols
	hucs = hucs[['huc_08','id']]
	print('hucs shape is: ')
	print(hucs.shape)
	#rename the huc col
	hucs.rename({'huc_08':'huc8'},axis=1,inplace=True)

	hucs_dict=dict(zip(hucs.id,hucs.huc8))
	remove_ids = [17110004,
				17110001,
				17110005,
				17020006,
				17020002,
				17020001,
				17010216,
				17010215,
				17010104]

	# maritime_test = [17110012,
	# 			17110010,
	# 			17110009,
	# 			17110013,
	# 			17110014,
	# 			17110015,
	# 			17090011,
	# 			17070204,
	# 			17020009,
	# 			17030001,
	# 			17030002,
	# 			17080004,
	# 			17080005,
	# 			17080002,
	# 			17070106,
	# 			17030003,
	# 			17020010,
	# 			17020011,
	# 			17080001,
	# 			17070105,
	# 			17070305,
	# 			17070301,
	# 			17090004,
	# 			17070304,
	# 			17070306,
	# 			17090005,
	# 			17090006]
	# alpine_test = [
	# 			17040207,
	# 			17040205,
	# 			17040208,
	# 			17040218,
	# 			17040217,
	# 			17060201,
	# 			17040214,
	# 			17060204,
	# 			17060203,
	# 			17040204,
	# 			17040202,
	# 			17040209,
	# 			17050120,
	# 			17050111,
	# 			17040219,
	# 			17050113,
	# 			17040220,
	# 			17040221,
	# 			17040212,
	# 			17040213,
	# 			16010202,
	# 			16010204,
	# 			16010201,
	# 			]

	main(ua_swe_dir,pickles,
		huc_col='huc8',
		hucs=hucs_dict,
		stats_dir=stats_dir,
		fig_dir=fig_dir,
		remove_ids=remove_ids
		#test_ids = maritime_test
		)


#!/usr/bin/env python

import aoc
from collections import Counter

def solve(inp: str):
    ingredients = Counter()
    allergens = {}
    for line in inp.splitlines():
        ingredients_str, allergens_str = line[:-1].split(' (contains ')
        ingrs = set(ingredients_str.split(' '))
        ingredients.update(ingrs)
        for a in allergens_str.split(', '):
            if a not in allergens:
                allergens[a] = ingrs
            else:
                allergens[a] = allergens[a].intersection(ingrs)

    ingr_without_allergens = ingredients.keys() - set(
        [i for ingrs in allergens.values() for i in ingrs])
    print('Part 1:', sum([ingredients[i]
                          for i in ingr_without_allergens]))

    used = set([])
    while len(used) < len(allergens):
        for a, ingrs in allergens.items():
            if len(ingrs) > 1:
                allergens[a] -= used
            else:
                used.update(ingrs)

    print('Part 2:', ','.join([allergens[a].pop()
                               for a in sorted(allergens.keys())]))

# with open('test.txt', 'r') as f:
#     inp = f.read()
#     solve(inp)

with open('input.txt', 'r') as f:
    inp = f.read()
    solve(inp)