import os
from datetime import datetime
from collections import deque
from binance.client import Client
import argparse

import alpha_collection
from utils import *
from decimal import Decimal
import time
import csv
from const import *

def get_current_futures_position(symbols):
    account_info = client.futures_account()
    positions = account_info['positions']
    df_futures_position = pd.DataFrame([position for position in positions if position['symbol'] in symbols]).set_index("symbol")[['entryPrice', 'positionAmt', 'leverage']].astype(float)
    max_withdraw_amount = float(account_info['maxWithdrawAmount'])
    return df_futures_position, max_withdraw_amount

def create_order(symbol, price, quantity, leverage, side=None, is_dryrun=False):
    if side is None:
        side = "BUY" if quantity > 0 else "SELL"
    quantity = str(abs(Decimal(str(quantity))))
    if not is_dryrun and quantity != '0':
        try:
            order = client.futures_create_order(
                symbol=symbol,
                side=side,
                price=price,
                quantity=quantity,
                timeInForce='GTC',
                type="LIMIT",
                reduceOnly=False
            )
        except Exception as e:
            print(f'Failed to create order for {symbol} {side} {quantity} at price {price}', "Exception:", type(e).__name__)
            time.sleep(0.0001)
            return False, None
    data = [symbol, side, quantity, price, leverage]
    return True, data

def log_order(order_data_list, is_dryrun=True):
    #current timestamp in date time format
    print(datetime.now())
    msg_list = [f'{data[1]} {data[2]} {data[0]} at price {data[3]}, usd {round(float(data[2]) * float(data[3]), 2)}, leverage={data[4]}' for data in order_data_list]
    if is_dryrun:
        for msg in msg_list:
            print(msg)
    else:
        csv_file = './logs/buy_log.csv'
        file_exists = os.path.isfile(csv_file)
        with open(csv_file, 'a', newline='') as file:
            writer = csv.writer(file, delimiter=',')
            if not file_exists:
                writer.writerow(['time', 'symbol', 'side', 'quantity', 'price', 'leverage'])

            for data in order_data_list:
                writer.writerow([str(datetime.now())] + [str(e) for e in data])
                msg = f'{data[1]} {data[2]} {data[0]} at price {data[3]}, usd {round(float(data[2]) * float(data[3]), 2)}, leverage={data[4]}'
                print(msg)

def slack_order(order_data_list, is_dryrun=False, slack_token=None):
    if slack_token:
        columns = ['symbol', 'side', 'quantity', 'price', 'leverage']
        rows = [columns] + [[str(element) for element in data] for data in order_data_list]
        width = max([max(len(str(cell)) for cell in column) for column in zip(*rows)])
        message = ""
        for row in rows:
            message += " | ".join(cell.ljust(width) for cell in row)
            message += "\n"
        channel = SLACK_DRYRUN_ORDER_LOG_CHANNEL if is_dryrun else SLACK_ORDER_LOG_CHANNEL
        send_slack_message(message, slack_token, channel)

def log_total_quantity(quantity):
    csv_file = './logs/total_quantity.csv'
    file_exists = os.path.isfile(csv_file)
    with open(csv_file, 'a', newline='') as file:
        writer = csv.writer(file, delimiter=',')
        if not file_exists:
            writer.writerow(['time', 'quantity'])
        writer.writerow([str(datetime.now()), str(quantity)])

def slack_total_quantity(quantity, is_dryrun=False, slack_token=None):
    if slack_token:
        msg = f'Total quantity: {quantity}'
        channel = SLACK_DRYRUN_TOTAL_QUANTITY_CHANNEL if is_dryrun else SLACK_TOTAL_QUANTITY_CHANNEL
        send_slack_message(msg, slack_token, channel)

def cancle_order_and_close_all_positions(symbols, is_dryrun=False):
    if is_dryrun:
        return
    cancel_all_orders(symbols)
    for symbol in symbols:
        df_current_futures_position, _ = get_current_futures_position(symbols)
        side = Client.SIDE_BUY if df_current_futures_position.loc[symbol]['positionAmt'] < 0 else Client.SIDE_SELL # close position
        quantity = str(abs(df_current_futures_position.loc[symbol]['positionAmt']))
        try:
            order_response = client.futures_create_order(
                symbol=symbol,
                side=side,
                type=Client.ORDER_TYPE_MARKET,
                quantity=quantity
            )
            position = 'LONG' if side == Client.SIDE_BUY else 'SHORT'
            msg = f"Force-closed position for {position} {symbol} {quantity}"
            send_slack_message(msg, slack_token, SLACK_SOMETHING_IRREGULAR_CHANNEL)
            print(msg)
        except Exception as e:
            print(f"Error placing order: {e}")

def get_remaining_orders(symbols):
    open_orders = {}
    for symbol in symbols:
        open_orders_symbol = client.futures_get_open_orders(symbol=symbol)
        if len(open_orders_symbol) > 0:
            open_orders[symbol] = open_orders_symbol[0] #length is always 1
    return open_orders

def renew_order_if_not_meet(symbols, leverage):
    open_orders = get_remaining_orders(symbols)
    if len(open_orders) == 0:
        return True
    current_price = {symbol: float(client.futures_ticker(symbol=symbol)['lastPrice']) for symbol in open_orders.keys()}
    for symbol, order in open_orders.items():
        canceled = cancel_order(order, symbol)
        if canceled:
            usdt_amount = float(order['origQty']) * float(order['price'])
            adjusted_quantity_trimmed = trim_quantity(symbol, usdt_amount, current_price[symbol])
            create_order(symbol=symbol, price=current_price[symbol], quantity=adjusted_quantity_trimmed, leverage=leverage, is_dryrun=is_dryrun, side=order['side'])
            msg = f"Renewed order into {order['side']} {symbol} {adjusted_quantity_trimmed} at price {current_price[symbol]}"
            print(msg)
            send_slack_message(msg, slack_token, SLACK_SOMETHING_IRREGULAR_CHANNEL)
    return False

def order_with_quantity(df, quantity_column_name, price_column_name, is_dryrun=False, leverage=1):
    unfilled_symbols = deque(df.index)
    order_data_list = []
    tried, try_max_cnt = 0, 100
    while unfilled_symbols:
        symbol = unfilled_symbols.popleft()
        is_success, data = create_order(symbol=symbol, price=df.loc[symbol, price_column_name], quantity=df.loc[symbol, quantity_column_name], leverage=leverage, is_dryrun=is_dryrun)
        if not is_success:
            unfilled_symbols.append(symbol)
        else:
            tried += 1
            order_data_list.append(data)
        if tried >= try_max_cnt:
            cancle_order_and_close_all_positions(symbols, is_dryrun=is_dryrun)
            break
    return order_data_list

def cancel_order(order, symbol):
    order_id = order['orderId']
    cancel_response = client.futures_cancel_order(symbol=symbol, orderId=order_id)
    if cancel_response['status'] == 'CANCELED':
        msg = f"Order {order_id} ({order['side']} {order['origQty']} {symbol} at price {order['price']}) canceled successfully."
        print(msg)
        send_slack_message(msg, slack_token, SLACK_SOMETHING_IRREGULAR_CHANNEL)
        return True
    else:
        msg = f"Failed to cancel order {order_id}. Error: {cancel_response['msg']}"
        print(msg)
        send_slack_message(msg, slack_token, SLACK_SOMETHING_IRREGULAR_CHANNEL)
        return False

def cancel_all_orders(symbols):
    cancel_any = False
    for symbol in symbols:
        open_orders = client.futures_get_open_orders(symbol=symbol)
        for order in open_orders:
            cancel_order(order, symbol)
            cancel_any = True
    if cancel_any:
        send_slack_message("Canceling all orders", slack_token, SLACK_SOMETHING_IRREGULAR_CHANNEL)

def log_position(df, past_quantity_column_name, change_quantity_column_name, entry_price_column_name, current_price_column_name):
    csv_file = './logs/position.csv'
    file_exists = os.path.isfile(csv_file)
    time_str = str(datetime.now())
    with open(csv_file, 'a', newline='') as file:
        writer = csv.writer(file, delimiter=',')
        if not file_exists:
            writer.writerow(['time', 'symbol', 'past_quantity', 'new_quantity', 'entry_price', 'current_price'])
        for symbol in df.index:
            past_quantity = df.loc[symbol, past_quantity_column_name]
            new_quantity = df.loc[symbol, change_quantity_column_name] + past_quantity
            entry_price = df.loc[symbol, entry_price_column_name]
            current_price = df.loc[symbol, current_price_column_name]
            writer.writerow([time_str, symbol, past_quantity, new_quantity, entry_price, current_price])

def slack_position(df, past_quantity_column_name, change_quantity_column_name, entry_price_column_name, current_price_column_name, is_dryrun=False, slack_token=None):
    if slack_token:
        msgs = []
        rows = [['symbol', 'past_quantity', 'new_quantity', 'entry_price', 'current_price']]
        for symbol in df.index:
            past_quantity = str(df.loc[symbol, past_quantity_column_name])
            new_quantity = str(df.loc[symbol, change_quantity_column_name] + df.loc[symbol, past_quantity_column_name])
            entry_price = str(round(df.loc[symbol, entry_price_column_name], 4))
            current_price = str(df.loc[symbol, current_price_column_name])
            rows.append([symbol, past_quantity, new_quantity, entry_price, current_price])
        column_widths = [max(len(str(cell)) for cell in column) for column in zip(*rows)]
        message = ""
        for row in rows:
            message += " | ".join(cell.ljust(width) for cell, width in zip(row, column_widths))
            message += "\n"
        channel = SLACK_DRYRUN_POSITION_CHANNEL if is_dryrun else SLACK_POSITION_CHANNEL
        send_slack_message(message, slack_token, channel)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Receive input')
    parser.add_argument('--dryrun', default=True, help='dryrun', type=lambda x: x.lower() != 'false')
    parser.add_argument('--leverage', default=7, help='leverage', type=int)
    parser.add_argument('--budget_allocation', default=0.64, help='budget_allocation', type=float)
    parser.add_argument('--budget_keep', default=0, help='budget_keep', type=float)
    parser.add_argument('--api_key', help='api_key')
    parser.add_argument('--api_secret', help='api_secret')
    parser.add_argument('--slack_token', help='slack_token')
    args = parser.parse_args()
    is_dryrun, leverage, budget_allocation, budget_keep = bool(args.dryrun), int(args.leverage), float(args.budget_allocation), float(args.budget_keep)
    api_key, api_secret, slack_token = args.api_key, args.api_secret, args.slack_token
    if api_key is None or api_secret is None:
        api_key = os.getenv('BINANCE_API_KEY')
        api_secret = os.getenv('BINANCE_SECRET_API_KEY')
    if slack_token is None:
        slack_token = os.getenv('PERSONAL_SLACK_TOKEN')
    pd.set_option('display.max_columns', 500)
    pd.set_option('display.width', 1000)
    client = Client(api_key, api_secret)
    print(f'is_dryrun={is_dryrun}, leverage={leverage}, budget_allocation={budget_allocation}')
    symbols = ['BTCUSDT', 'ETHUSDT', 'XRPUSDT', 'DOGEUSDT', 'LTCUSDT', 'MATICUSDT', 'TRXUSDT', 'ADAUSDT', 'SOLUSDT', 'DOTUSDT']
    dict_df_klines = {}
    df_current_futures_position, max_withdraw_amount = get_current_futures_position(symbols)
    old_leverage = df_current_futures_position['leverage'].iloc[0] # we assume leverage are all the same
    if not is_dryrun:
        cancel_all_orders(symbols)
        for symbol in symbols:
            client.futures_change_leverage(symbol=symbol, leverage=str(leverage))
    alphas = alpha_collection.Alphas()
    past_price = {symbol: [float(kline[4]) for kline in client.futures_historical_klines(symbol, '1h', '127 hours ago UTC')[:-1]] for symbol in symbols}
    current_price = {symbol: float(client.futures_ticker(symbol=symbol)['lastPrice']) for symbol in symbols}
    dict_df_close = {symbol: pd.DataFrame({'close': past_price[symbol] + [current_price[symbol]]}) for symbol in symbols}
    df_weight = pd.DataFrame(alphas.close_position_in_nday_bollinger_band_ewm(dict_df_close, n=125, shift=0)[0].iloc[-1].T.rename('next_position_usdt'))
    df_current_price_and_amount = pd.DataFrame.from_dict(current_price, orient='index', columns=['price']).join(df_current_futures_position)
    total_quantity_usdt = ((df_current_price_and_amount['positionAmt'].abs() * df_current_price_and_amount['price']).sum() / old_leverage + max_withdraw_amount)
    trading_quantity_usdt = (total_quantity_usdt - budget_keep) * budget_allocation
    df_quantity = df_weight * trading_quantity_usdt * leverage
    df_quantity_and_price = df_quantity.join(df_current_price_and_amount)\
        .assign(current_position_usdt=lambda x: x.positionAmt * x.price)\
        .assign(changing_position_usdt=lambda x: x.next_position_usdt - x.current_position_usdt)\
        .assign(margin_increase=lambda x: x.next_position_usdt.abs() - x.current_position_usdt.abs())
    df_quantity_and_price_trimmed = trim_quantity_df(df_quantity_and_price, usdt_column_name='changing_position_usdt', price_column_name='price').sort_values('margin_increase')
    order_data_list = order_with_quantity(df_quantity_and_price_trimmed, quantity_column_name='quantity_trimmed', price_column_name='price', leverage=leverage, is_dryrun=is_dryrun)
    if not is_dryrun:
        log_total_quantity(total_quantity_usdt)
        log_position(df_quantity_and_price_trimmed, past_quantity_column_name='positionAmt',
                     change_quantity_column_name='quantity_trimmed', entry_price_column_name='entryPrice',
                     current_price_column_name='price')
        log_order(order_data_list, is_dryrun=is_dryrun)
    slack_order(order_data_list, is_dryrun=is_dryrun, slack_token=slack_token)
    slack_total_quantity(total_quantity_usdt, is_dryrun=is_dryrun, slack_token=slack_token)
    slack_position(df_quantity_and_price_trimmed, past_quantity_column_name='positionAmt',
                   change_quantity_column_name='quantity_trimmed', entry_price_column_name='entryPrice',
                   current_price_column_name='price', is_dryrun=is_dryrun, slack_token=slack_token)
    while not is_dryrun and len(get_remaining_orders(symbols)) > 0:
        time.sleep(900)
        is_all_filled = renew_order_if_not_meet(symbols, leverage)
        if is_all_filled:
            break
    print()


# -*- coding: utf-8 -*-
import datetime
import logging
from turtle import color
import streamlit as st
import streamlit.components.v1 as components
from src.utils.dataio import get_data, create_transaction
from src.utils.minter import *
from src.utils.pinata import pin_image
from web3 import Web3
from dotenv import load_dotenv

# Load the required variables from .env file
load_dotenv()

contract_address = os.getenv("SMART_CONTRACT_ADDRESS")
contract_abi = os.getenv("ABI_PATH")
ipfs_uri = os.getenv("IPFS_URI")
recipient_df = get_data("SELECT Organization, City, Address from ORGANIZATIONS")
categories_df = get_data("SELECT DISTINCT Category from DONATIONS")
resources_df = get_data("SELECT Category, Item, QtySize, USD, Tags from DONATIONS")
donor_account = os.getenv("PUBLIC_KEY")
# Instantiate a web3 object inline
w3 = Web3(Web3.HTTPProvider(os.getenv("WEB3_PROVIDER_URI")))

# Begin Streamlit calls
st.set_page_config(layout="wide")

@st.cache(allow_output_mutation=True)
def load_contract():
    # Load the contract address into an object using the ABI code and smart contract address
    with open(contract_abi) as f:
        this_abi = json.load(f)
    contract_address = os.getenv("SMART_CONTRACT_ADDRESS")
    contract = w3.eth.contract(
        address=contract_address,
        abi=this_abi
    )
    return contract

contract = load_contract()

col1, col2 = st.columns([3, 1])

def main(df):

    with col1:
        # Header information
        st.title("Make a Donation", anchor=None)
        st.write("WIP page for testing minting process with local image files instead of streamlit uploaded file.")

        # Selectbox for recipient Org-City-Address (JOIN & SPLIT columns to create data relationships)
        recipient_df["org"] = recipient_df[["Organization", "City", "Address"]].agg(" - ".join, axis=1)
        orgs = recipient_df.org.unique()
        recipient = st.selectbox("Donation Recipient", options=orgs)
        recipient_name = recipient.split(" - ")[0]
        recipient_city = recipient.split(" - ")[1]
        recipient_account = recipient.split(" - ")[2]

        # Selectbox for Category
        category = st.selectbox("Donation Category", options=categories_df)

        # Selectbox for Resources - (JOIN & SPLIT columns to create data relationships)
        resources_df["USD"] = resources_df["USD"].astype(str)
        resources_df["item"] = resources_df[["Item", "QtySize", "USD"]].agg(" - ".join, axis=1)
        this_cat = resources_df[resources_df['Category'].str.contains(category)]
        items = this_cat.item.unique()
        resource = st.selectbox("Resource", options=items)

        # Value retrieved from resource selectbox and SPLIT to get the last value column `USD`
        resource_name = resource.split("-")[0]
        initial_appraisal_value = int(float(resource.split("-")[2]))

        # Value retrieved from resource selectbox
        city = st.text_input("City", recipient_city, type="default", help=None, disabled=True)

        # READ ALL THE BYTES of new image file template to upload to ipfs!
        image_file = open(Path(f"src/images/tokens/{category}.png"),"rb")

        if st.button("Donate"):
            # Timestamp when button is clicked (can't hurt right?)
            now = datetime.datetime.now()
            date_time = now.strftime("%Y/%m/%d %H:%M:%S")
            # Use function to call Pinata API to pin the resource to the public IPFS
            resource_ipfs_hash, resource_cid = pin_image(resource_name, image_file)

            # Set up the transaction and make the function call to the deployed contract
            resource_uri = f"ipfs://{resource_ipfs_hash}"
            tx_hash = contract.functions.safeMintResource(
                recipient_account,
                resource_uri,
                donor_account,
                category,
                city,
                resource_name,
                int(initial_appraisal_value)
            ).transact({'from': donor_account, 'gas': 1000000})
            # get the reciept, then display transaction data to user.
            receipt = w3.eth.waitForTransactionReceipt(tx_hash)
            st.markdown(f"#### Transaction has been successfully mined.")
            st.write(f"Timestamp: {date_time}")
            st.write(f"TX Hash: {tx_hash}")
            st.write(f"Pinata Links: [IPFS Metadata]({ipfs_uri}{resource_ipfs_hash}) [IPFS Image]({ipfs_uri}{resource_cid})")
            st.write(f"Resource CID: {resource_cid}")
            st.write(f"Recipient Account: {recipient_account}")
            st.write(f"Category: {category}")
            st.write(f"City: {city}")
            st.write(f"Resource: {resource_name}")
            st.write(f"Appraisal Value: {initial_appraisal_value}")
            st.image(f"{ipfs_uri}{resource_cid}")
            st.write("---")
            st.write(f"Transaction Recipt: ")
            st.write(dict(receipt))
            st.write("---")
            # TODO: sync with local database for reporting etc
            # create_transaction(recipient_name, tx_hashHex, date_time, recipient_account, ipfs_link, donor_account, category, city, resource_name, initial_appraisal_value)

    with col2:
        # Populate the top right column with selected organization's logo
        if recipient_name == "Action Against Hunger":
            logo = "src/images/logos/Action_Against_Hunger_logo.png"
        elif recipient_name == "Oxfam":
            logo = "src/images/logos/Oxfam_logo.png"
        elif recipient_name == "Care International":
            logo = "src/images/logos/care_international_logo.png"
        elif recipient_name == "World Food Program":
            logo = "src/images/logos/world_food_program_logo.png"
        elif recipient_name == "International Rescue Committee":
            logo = "src/images/logos/International_Rescue_Committee_Logo.png"
        elif recipient_name == "World Vision":
            logo = "src/images/logos/World_Vision_logo.png"
        elif recipient_name == "Unicef":
            logo = "src/images/logos/UNICEF_logo.png"
        elif recipient_name == "Direct Relief":
            logo = "src/images/logos/Direct_Relief_logo.webp"
        elif recipient_name == "Transaprent Hands":
            logo = "src/images/logos/transparent_hands_logo.webp"

        else:
            logo = "src/images/content/_na.png"

        st.image(logo, use_column_width=True)
        st.write("---")

        # Populate the right bottom column with an image of the item to be minted
        if category =="Water":
            cat = "src/images/tokens/water.png"
        elif category =="Food":
            cat = "src/images/tokens/food.png"
        elif category =="Clothing":
            cat = "src/images/tokens/clothing.png"
        elif category =="Shelter":
            cat = "src/images/tokens/shelter.png"
        elif category =="Education":
            cat = "src/images/tokens/education.png"
        elif category =="Health":
            cat = "src/images/tokens/health.png"
        else:
            cat = "src/images/content/_na.png"

        st.image(cat, use_column_width=True)

def load_data():
    # Populate a dataframe from SQL table to use on this page.
    query_str = "SELECT * FROM DONATIONS;"
    df = get_data(query_str)
    return df

if __name__ == '__main__':
    logging.basicConfig(level=logging.CRITICAL)
    df = load_data()
    main(df)


from flask import Flask
from flask import render_template, abort
from flask.ext.sqlalchemy import SQLAlchemy
from pymongo import MongoClient
from datetime import *
app=Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"]='mysql://root@localhost/shiyanlou'
db=SQLAlchemy(app)
mongo=MongoClient('127.0.0.1',27017).shiyanlou

class File(db.Model):
    id=db.Column(db.Integer,primary_key=True)
    title=db.Column(db.String(80))
    created_time=db.Column(db.DateTime())
    category_id=db.Column(db.Integer,db.ForeignKey('category.id'))
    content=db.Column(db.Text)
    category=db.relationship('Category',backref=db.backref('posts',lazy='dynamic'))
    def __init__(self,title,created_time,category,content):
        self.title=title
        self.created_time=created_time
        self.content=content
        self.category=category
    def __repr__(self):
        return '<title:%r>' % self.title
    def add_tag(self,tag_name):
        file_item=mongo.files.find_one({'file_id':self.id})
        if file_item:
            tags=file_item['tags']
            if tag_name not in tags:
                tags.append(tag_name)
            mongo.files.update_one({'file_id':self.id},{'$set':{'tags':tags}})
        else:
            tags=[tag_name]
            mongo.files.insert_one({'file_id':self.id,'tags':tags})
        return tags
    def remove_tag(self,tag_name):
        file_item=mongo.files.find_one({'file_id':self.id})
        if file_item:
            tags=file_item['tags']
            try:
                tags.remove(tag_name)
                new_tags=tags
            except ValueError:
                return tags
            mongo.files.update_one({'file_id':self.id},{'$set':{'tags':new_tags}})
            return new_tags
        return []
    @property
    def tags(self):
        file_item=mongo.files.find_one({'file_id':self.id})
        if file_item:
            print(file_item)
            return file_item['tags']
        else:
            return []
class Category(db.Model):
    id=db.Column(db.Integer,primary_key=True)
    name=db.Column(db.String(80))
    def __init__(self,category):
        self.name=category
        def __repr__(self):
            return '<name:%r>' % self.name
@app.route('/')
def index():
    files = File.query.all()
    return render_template('index.html', files=files)
@app.route('/files/<int:file_id>')
def file(file_id):
    f = File.query.filter_by(id=file_id).first_or_404()
    return render_template('file.html', f=f)
@app.errorhandler(404)
def not_found(error):
    return render_template('404.html'),404

def insert_datas():
    db.create_all()
    java=Category('Java')
    python=Category("Python")
    file1=File('Hello Java',datetime.utcnow(),java,'File Content - Java is cool!')
    file2=File('Hello Python',datetime.utcnow(),python,'File content - Pyhton is cool')
    db.session.add(java)
    db.session.add(python)
    db.session.add(file1)
    db.session.add(file2)
    db.session.commit()
    file1.add_tag('tech')
    file1.add_tag('java')
    file1.add_tag('linux')
    file2.add_tag('python')
    file2.add_tag('tech')
if __name__=="__main__":
    app.run()


from unittest import mock

import pytest

from paasng.engine.controller.cluster import RegionClusterService

pytestmark = pytest.mark.django_db

@pytest.fixture(autouse=True)
def helper(bk_app):
    # Make a mocked controller client
    mocked_client = mock.Mock()
    mocked_client.list_region_clusters.return_value = [
        {
            "name": "default",
            "is_default": True,
            "bcs_cluster_id": "BCS-K8S-10000",
            "support_bcs_metrics": False,
            "ingress_config": {
                "app_root_domains": [{"name": "local-bkapps-t.example.com"}],
            },
        },
        {
            "name": "extra-1",
            "is_default": False,
            "bcs_cluster_id": "BCS-K8S-10001",
            "support_bcs_metrics": False,
            "ingress_config": {
                "app_root_domains": [{"name": "local-bkapps-extra.example.com"}],
            },
        },
    ]
    return RegionClusterService(bk_app, client=mocked_client)

class TestGetEngineAppCluster:
    def test_empty_cluster_field(self, bk_stag_env, helper):
        helper.client.retrieve_app_config.return_value = {'cluster': ''}

        engine_app = bk_stag_env.engine_app
        assert helper.get_engine_app_cluster(engine_app.name).name == 'default'

    def test_valid_cluster_field(self, bk_stag_env, helper):
        helper.client.retrieve_app_config.return_value = {'cluster': 'extra-1'}

        engine_app = bk_stag_env.engine_app
        assert helper.get_engine_app_cluster(engine_app.name).name == 'extra-1'

    def test_invalid_cluster_field(self, bk_stag_env, helper):
        helper.client.retrieve_app_config.return_value = {'cluster': 'invalid-cluster-name'}

        engine_app = bk_stag_env.engine_app
        with pytest.raises(ValueError):
            helper.get_engine_app_cluster(engine_app.name)

def test_get_cluster(helper):
    assert helper.get_cluster('extra-1').name == 'extra-1'


# coding: utf-8
# Author: wanhui0729@gmail.com

from functools import lru_cache

'''
lru_cache 用于函数缓存，在连续用相同参数调用一个函数时，函数使用存储值作为返回值
接受maxsize和typed两个参数
maxsize为缓存最多maxsize个此函数的结果
typed为是否对参数类型敏感，例如设置为True时，f(3)和f(3.0)会被分别存储
'''

@lru_cache(maxsize=2)
def add(x, y):
    print(f"calculating: {x} + {y}")
    return x+y

if __name__ == '__main__':
    # 存储第一个
    add(1, 2)
    add(1, 2)
    add(1, 2)
    # 存储第二个
    add(2, 3)
    add(2, 3)
    # 存储第三个，maxsize为２,覆盖掉最先存储的
    add(3, 4)
    # 已经被覆盖掉，重新调用函数计算
    add(1, 2)


from enum import Enum

# noinspection PyArgumentList
TYPE = Enum('TYPE', 'stimulus measurement scan_config analysis emka', module=__name__)

FILE_TYPES = {
    TYPE.stimulus: ('.mat', [('matlab', '.mat'), ('json', '.json'), ('python', '.pkl')]),
    TYPE.measurement: ('.csv', [('table', '.csv'), ('matlab', '.mat'), ('python', '.pkl')]),
    TYPE.scan_config: ('.cfg', [('scanImage', '.cfg')]),
    TYPE.analysis: ('.csv', [('data frame', '.pandas'), ('table', '.csv'), ('python', '.pkl')]),
    TYPE.emka: ('.raw', [('raw file', '.raw'), ('raw file txt', '.txt')])}


import tornado.ioloop
import tornado.web
from tornado import gen
from time import sleep
from datetime import datetime
from tornado.ioloop import IOLoop, PeriodicCallback

loop = IOLoop.current()

class MainHandler(tornado.web.RequestHandler):
    async def get(self):
        await gen.sleep(1)
        self.write('Hello, world')

def background_task():
    print(datetime.now())

if __name__ == '__main__':
    application = tornado.web.Application(
        [
            (r'/', MainHandler),
        ]
    )
    application.listen(8888)
    task = PeriodicCallback(background_task, 1000)
    task.start()
    loop.start()


# This Python 3 environment comes with many helpful analytics libraries installed

# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python

# For example, here's several helpful packages to load

import numpy as np # linear algebra

import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

# Input data files are available in the read-only "../input/" directory

# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory

import os

for dirname, _, filenames in os.walk('/kaggle/input'):

    for filename in filenames:

        print(os.path.join(dirname, filename))

# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using "Save & Run All"

# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session
import numpy as np

import pandas as pd

import json

import string

import sys

import re

from collections import Counter

from wordcloud import WordCloud

from sklearn.feature_extraction.text import CountVectorizer

train_df = pd.read_csv('/kaggle/input/tweet-sentiment-extraction/train.csv')

test_df = pd.read_csv('/kaggle/input/tweet-sentiment-extraction/test.csv')

sub_df = pd.read_csv('/kaggle/input/tweet-sentiment-extraction/sample_submission.csv')

train = np.array(train_df)

test = np.array(test_df)

use_cuda = True # whether to use GPU or not

import cufflinks as cf

cf.go_offline()

cf.set_config_file(offline=False, world_readable=True)
# First few rows of the training dataset

train_df.head()
#Missing values in training set

train_df.isnull().sum()
# Dropping missing values

train_df.dropna(axis = 0, how ='any',inplace=True) ;
#Missing values in test set

test_df.isnull().sum()
train_df['sentiment'].value_counts()
pos = train_df[train_df['sentiment']=='positive']

neg = train_df[train_df['sentiment']=='negative']

neutral = train_df[train_df['sentiment']=='neutral']
pos.head()
def get_top_n_words(corpus, n=None):

    """

    List the top n words in a vocabulary according to occurrence in a text corpus.

    """

    vec = CountVectorizer(stop_words = 'english').fit(corpus)

    bag_of_words = vec.transform(corpus)

    sum_words = bag_of_words.sum(axis=0)

    words_freq = [(word, sum_words[0, idx]) for word, idx in vec.vocabulary_.items()]

    words_freq =sorted(words_freq, key = lambda x: x[1], reverse=True)

    return words_freq[:n]
pos_unigrams = get_top_n_words(pos['text'],20)

neg_unigrams = get_top_n_words(neg['text'],20)

neutral_unigrams = get_top_n_words(neutral['text'],20)

#for word, freq in top_unigrams:

    #print(word, freq)

df1 = pd.DataFrame(pos_unigrams, columns = ['Text' , 'count'])

df1.groupby('Text').sum()['count'].sort_values(ascending=True).iplot(

    kind='bar', yTitle='Count', linecolor='black',color='red', title='Top 20 Unigrams in positve text',orientation='h')

df2 = pd.DataFrame(neg_unigrams, columns = ['Text' , 'count'])

df2.groupby('Text').sum()['count'].sort_values(ascending=True).iplot(

    kind='bar', yTitle='Count', linecolor='black', color='green',title='Top 20 Unigrams in negative text',orientation='h')

df3 = pd.DataFrame(neutral_unigrams, columns = ['Text' , 'count'])

df3.groupby('Text').sum()['count'].sort_values(ascending=True).iplot(

    kind='bar', yTitle='Count', linecolor='black', title='Top 20 Unigrams in neutral text',orientation='h')
train_data = [

    {

        'context': "This tweet sentiment extraction challenge is great",

        'qas': [

            {

                'id': "00001",

                'question': "positive",

                'answers': [

                    {

                        'text': "is great",

                        'answer_start': 43

                    }

                ]

            }

        ]

    }

    ]

"""

Prepare training data in QA-compatible format

"""

# Adpated from https://www.kaggle.com/cheongwoongkang/roberta-baseline-starter-simple-postprocessing

def find_all(input_str, search_str):

    l1 = []

    length = len(input_str)

    index = 0

    while index < length:

        i = input_str.find(search_str, index)

        if i == -1:

            return l1

        l1.append(i)

        index = i + 1

    return l1

def do_qa_train(train):

    output = []

    for line in train:

        context = line[1]

        qas = []

        question = line[-1]

        qid = line[0]

        answers = []

        answer = line[2]

        if type(answer) != str or type(context) != str or type(question) != str:

            print(context, type(context))

            print(answer, type(answer))

            print(question, type(question))

            continue

        answer_starts = find_all(context, answer)

        for answer_start in answer_starts:

            answers.append({'answer_start': answer_start, 'text': answer.lower()})

            break

        qas.append({'question': question, 'id': qid, 'is_impossible': False, 'answers': answers})

        output.append({'context': context.lower(), 'qas': qas})

    return output

qa_train = do_qa_train(train)

with open('data/train.json', 'w') as outfile:

    json.dump(qa_train, outfile)

"""

Prepare testing data in QA-compatible format

"""

def do_qa_test(test):

    output = []

    for line in test:

        context = line[1]

        qas = []

        question = line[-1]

        qid = line[0]

        if type(context) != str or type(question) != str:

            print(context, type(context))

            print(answer, type(answer))

            print(question, type(question))

            continue

        answers = []

        answers.append({'answer_start': 1000000, 'text': '__None__'})

        qas.append({'question': question, 'id': qid, 'is_impossible': False, 'answers': answers})

        output.append({'context': context.lower(), 'qas': qas})

    return output

qa_test = do_qa_test(test)

with open('data/test.json', 'w') as outfile:

    json.dump(qa_test, outfile)

from simpletransformers.question_answering import QuestionAnsweringModel

MODEL_PATH = '/kaggle/input/transformers-pretrained-distilbert/distilbert-base-uncased-distilled-squad/'

# Create the QuestionAnsweringModel

model = QuestionAnsweringModel('distilbert',

                               MODEL_PATH,

                               args={'reprocess_input_data': True,

                                     'overwrite_output_dir': True,

                                     'learning_rate': 5e-5,

                                     'num_train_epochs': 1,

                                     'max_seq_length': 192,

                                     'doc_stride': 64,

                                     'fp16': False,

                                    },

                              use_cuda=use_cuda)

model.train_model('data/train.json')

predictions = model.predict(qa_test)

predictions_df = pd.DataFrame.from_dict(predictions)

sub_df['selected_text'] = predictions_df['answer']

sub_df.to_csv('/kaggle/working/outputs/submission.csv', index=False)


import typing
import weakref
from collections import defaultdict

class BaseClass:

    __refs = defaultdict(list)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__refs[self.__class__].append(self)

    @classmethod
    def instances(cls) -> typing.List:
        for instance in cls.__refs.get(cls, []):
            yield instance

class BaseClassWeakRef:

    __refs = defaultdict(list)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__refs[self.__class__].append(weakref.ref(self))

    @classmethod
    def instances(cls) -> typing.List:
        for instance_ref in cls.__refs.get(cls, []):
            instance = instance_ref()
            if instance is not None:
                yield instance


import os
import glob
import polars as pl
import pandas as pd

import config
from utils import set_display_options, describe_numeric
from etl import load_data

set_display_options()

asofdate = '2022-12-01'
asofdate_fcst = '2023-01-01'

id_fcst = 'best_public'
# id_fcst = 'ens-naive_ema_theta-20220701-active-wavg-test-weight-folds_5-active-20220701-active-target-naive_ema_theta-corner-20221201-20220801-manual_fix'
# id_fcst = 'ens-naive_ema_theta-20221201-active-wavg-full-weight-folds_1-active-20221201-active-target-naive_ema_theta-corner-20221201-20220801-manual_fix'
# id_fcst = 'combined'
dir_fcsts = f'{config.DIR_ARTIFACTS}/forecast_ensemble/{id_fcst}'

df_train, df_test, df_census, df_pop = load_data()
df_actual_last = df_train \
    .with_columns(pl.lit(asofdate).str.strptime(pl.Date, fmt='%Y-%m-%d').alias('asofdate')) \
    .filter(pl.col('first_day_of_month') == pl.lit(asofdate).str.strptime(pl.Date, fmt='%Y-%m-%d')) \
    .select(['cfips', 'asofdate', 'active'])

try:
    file_fcst = sorted(glob.glob(f'{dir_fcsts}/sub*.csv'))[-1]
    df_fcst = pl.read_csv(file_fcst)
    df_fcst = df_fcst \
        .with_columns(pl.col('row_id').str.split('_').alias('row_id')) \
        .with_columns(pl.col('row_id').arr.get(0).cast(pl.Int64).alias('cfips')) \
        .with_columns(pl.col('row_id').arr.get(1).str.strptime(pl.Date, fmt='%Y-%m-%d').alias('date'))\
        .filter(pl.col('date') >= pl.lit(asofdate_fcst).str.strptime(pl.Date, fmt='%Y-%m-%d'))
except:
    file_fcst = f'{dir_fcsts}/fcsts_all_models.csv'
    df_fcst = pl.read_csv(file_fcst)
    df_fcst = df_fcst \
        .select(['date', 'cfips', 'ensemble']) \
        .with_columns(pl.col('date').str.strptime(pl.Date, fmt='%Y-%m-%d').alias('date')) \
        .rename({'ensemble': 'microbusiness_density'}) \
        .filter(pl.col('date') >= pl.lit(asofdate_fcst).str.strptime(pl.Date, fmt='%Y-%m-%d'))

# convert to active
df_fcst = df_fcst \
    .join(df_pop.rename({'first_day_of_month': 'date'}), on=['cfips', 'date']) \
    .with_columns((pl.col('microbusiness_density') * pl.col('population') / 100).alias('forecast')) \
    .select(['cfips', 'date', 'forecast'])

df_rates = df_actual_last \
    .join(df_fcst, on='cfips') \
    .with_columns((pl.col('forecast') / pl.col('active') - 1).alias('rate_county')) \
    .select(['cfips', 'asofdate', 'date', 'rate_county'])

print(describe_numeric(
    df=df_rates.select(['rate_county']).to_pandas(),
    percentiles=[0.01, 0.05, 0.10, 0.25, 0.50, 0.75, 0.95, 0.98, 0.99],
    stats_nans=False))

# rates by horizon/date
list_stats = []
for d in df_rates['date'].unique():
    stats = describe_numeric(df_rates.filter(pl.col('date') == d).select(['rate_county']).to_pandas(), stats_nans=False)
    stats['date'] = d
    list_stats.append(stats)
stats = pd.concat(list_stats)
print(stats)

print((stats[['date', 'mean']]))

print(pl.from_pandas(stats[['date', 'mean']]))

# ┌────────────┬──────────┐
# │ date       ┆ mean     │
# ╞════════════╪══════════╡
# │ 2023-01-01 ┆ 0.003256 │
# │ 2023-02-01 ┆ 0.005212 │
# │ 2023-03-01 ┆ 0.006449 │
# │ 2023-04-01 ┆ 0.007289 │
# │ 2023-05-01 ┆ 0.00794  │
# │ 2023-06-01 ┆ 0.008466 │
# └────────────┴──────────┘

# ┌────────────┬──────────┐
# │ date       ┆ mean     │
# ╞════════════╪══════════╡
# │ 2023-01-01 ┆ 0.003256 │
# │ 2023-02-01 ┆ 0.003946 │
# │ 2023-03-01 ┆ 0.004767 │
# │ 2023-04-01 ┆ 0.00554  │
# │ 2023-05-01 ┆ 0.006318 │
# │ 2023-06-01 ┆ 0.007104 │
# └────────────┴──────────┘

# stats for the best public submission:
#                count  mean   std    min     1%    5%   10%   25%   50%   75%   95%   98%   99%   max
# rate_county 3135.000 0.003 0.002 -0.000 -0.000 0.000 0.000 0.000 0.004 0.005 0.006 0.006 0.007 0.007

# ens-naive_ema_theta-20221201-active-wavg-full-weight-folds_1-active-20221201-active-target-naive_ema_theta-corner-20221201-20220801-manual_fix
#                count  mean   std    min     1%     5%    10%    25%   50%   75%   95%   98%   99%   max
# rate_county 3135.000 0.001 0.003 -0.016 -0.006 -0.002 -0.000 -0.000 0.000 0.001 0.004 0.007 0.009 0.048

# ens-naive_theta-20221201-active-max-no:
#                count  mean   std    min     1%     5%    10%   25%   50%   75%   95%   98%   99%   max
# rate_county 3135.000 0.002 0.016 -0.000 -0.000 -0.000 -0.000 0.000 0.000 0.002 0.008 0.012 0.017 0.654

# ens-naive_ema_theta-20220701-active-wavg-test-weight-folds_5-active-20220701-active-target-naive_ema_theta-corner-20221201-20220801-manual_fix
#                count   mean   std    min     1%     5%    10%    25%   50%   75%   95%   98%   99%   max
# rate_county 3134.000 -0.000 0.004 -0.059 -0.012 -0.006 -0.003 -0.000 0.000 0.001 0.004 0.006 0.009 0.045

dir_out = f'{config.DIR_ARTIFACTS}/get_rates_submission'
os.makedirs(dir_out, exist_ok=True)
file_out = f'{dir_out}/{id_fcst}.csv'
df_rates.write_csv(file_out, float_precision=6)

print(f'rates saved to: {file_out}')


from flask import jsonify, request, g
from app import app, db, auth
from app.group import group
from app.group.model import Group
from app.group import mapper as group_mapper
from app import views as common_views
import constants

@group.route("/", methods = ["POST"])
@auth.login_required
def add_group():
    if not request.json:
        return common_views.bad_request(constants.view_constants.REQUEST_PARAMETERS_NOT_SUFFICIENT)
    data = request.json
    try:
        print("\n\n\n",g.customer)
        gp = group_mapper.get_obj_from_request(data, g.customer)
    except Exception as e:
        print("Jasdeep exception : " + str(e))
        return common_views.internal_error(constants.view_constants.MAPPING_ERROR)
    try:
        db.session.add(gp)
        db.session.commit()
    except:
        return common_views.internal_error(constants.view_constants.DB_TRANSACTION_FAULT)
    response_object = jsonify({
        "group": gp.full_serialize(),
        "status" : 'success',
        "message": 'Group Created'
        })
    return response_object,200

@group.route("/", methods = ["PUT"])
@auth.login_required
def edit_group():
    if not request.json:
        return common_views.bad_request(constants.view_constants.REQUEST_PARAMETERS_NOT_SUFFICIENT)
    exists_group = Group.query.get(request.json['id'])
    if exists_group:
        try:
            data = request.json
            gp = group_mapper.update_obj_from_request(data)
        except Exception as e:
            return common_views.internal_error(constants.view_constants.MAPPING_ERROR)
        try:
            exists_group._name = data['groupName']
            db.session.commit()
        except:
            return common_views.internal_error(constants.view_constants.DB_TRANSACTION_FAULT)
        # return common_views.as_success(constants.view_constants.SUCCESS)
        response_object = jsonify({
            "data": gp.full_serialize(),
            "status" : 'success',
            "message": 'Successfully Updated'
        })
        return response_object,200
    else:
        response_object = jsonify({
                "status" : 'fail',
                "message": 'record not exists'
        })
        return response_object,200

@group.route("/", methods = ["GET"])
@auth.login_required
def list_groups():
    groups = Group.query.filter(Group._customer_id == g.customer.id)
    list_resp = []
    for group in groups:
        list_resp.append(group.half_serialize())
    return jsonify({"groups": list_resp})

@group.route("/<string:groupId>", methods = ["DELETE"])
@auth.login_required
def delete_group(groupId):
    if not groupId:
        return common_views.bad_request(constants.view_constants.REQUEST_PARAMETERS_NOT_SUFFICIENT)
    gp = Group.query.get(int(groupId))
    if gp:
        try:
            db.session.delete(gp)
            db.session.commit()
        except:
            return common_views.internal_error(constants.view_constants.DB_TRANSACTION_FAULT)
        response_object = jsonify({
            "status" : 'success',
            "message": 'Group deleted',
            "id": groupId
        })
        return response_object,200
    else:
        response_object = jsonify({
            "status" : 'fail',
            "message": 'Group not exists'
        })
        return response_object,200

@group.route("/groupRental", methods = ["POST"])
@auth.login_required
def add_rental_to_group():
    if not request.json:
        return common_views.bad_request(constants.view_constants.REQUEST_PARAMETERS_NOT_SUFFICIENT)
    data = request.json
    group = Group.query.get(data["groupId"])
    rental = Rental.query.get(data["rentalId"])
    group.rentals.append(rental)
    try:
        db.session.add(group)
        db.session.commit()
    except:
        return common_views.internal_error(constants.view_constants.DB_TRANSACTION_FAULT)
    return common_views.as_success(constants.view_constants.SUCCESS)


from __future__ import annotations

from typing import Callable, List, Dict

from ndspy.rom import NintendoDSRom
from range_typed_integers import u16_checked, u32_checked

from skytemple_files.common.i18n_util import _, f
from skytemple_files.common.ppmdu_config.data import (
    GAME_REGION_EU,
    GAME_REGION_JP,
    GAME_REGION_US,
    GAME_VERSION_EOS,
    Pmd2Data,
)
from skytemple_files.common.util import (
    create_file_in_rom,
    write_u32,
    read_u16,
    write_u16,
    read_u32,
)
from skytemple_files.data.md.handler import MdHandler
from skytemple_files.data.md.protocol import (
    AdditionalRequirement,
    EvolutionMethod,
    Gender,
)
from skytemple_files.patch.category import PatchCategory
from skytemple_files.patch.handler.abstract import AbstractPatchHandler

PATCH_CHECK_ADDR_APPLIED_US = 0x59B24
PATCH_CHECK_ADDR_APPLIED_EU = 0x59EA0
PATCH_CHECK_ADDR_APPLIED_JP = 0x59E20
PATCH_CHECK_INSTR_APPLIED = 0xE1D960F4

MEVO_PATH = "BALANCE/md_evo.bin"
MEVO_ENTRY_LENGTH = 0x20
MEVO_STATS_LENGTH = 0xA

EVO_HP_BONUS_US = 0xA18C4
EVO_HP_BONUS_EU = 0xA1E48
EVO_HP_BONUS_JP = 0xA2C98
EVO_PHYS_BONUS_US = 0xA18D0
EVO_PHYS_BONUS_EU = 0xA1E54
EVO_PHYS_BONUS_JP = 0xA2CA4
EVO_SPEC_BONUS_US = 0xA18E4
EVO_SPEC_BONUS_EU = 0xA1E68
EVO_SPEC_BONUS_JP = 0xA2CB8

MAX_TRY = 1000

SPECIAL_EVOS: Dict[int, List[int]] = {
    462: [464],
    463: [465],
    1062: [1064],
    1063: [1065],
    1047: [450],
    1048: [451],
    1049: [452],
    447: [453],
    448: [453],
    449: [453],
    393: [394],
    993: [994],
    993: [520],
    454: [],
    1054: [455],
}
SPECIAL_EGGS: Dict[int, List[int]] = {
    379: [379],
    380: [379],
    381: [379],
    382: [379],
    979: [979],
    980: [979],
    981: [979],
    982: [979],
    460: [460],
    461: [460],
    1060: [1060],
    1061: [1060],
    455: [1054],
    464: [462],
    465: [463],
    1064: [1062],
    1065: [1063],
    450: [1047],
    451: [1048],
    452: [1049],
    453: [447, 448, 449],
}

class ChangeEvoSystemPatchHandler(AbstractPatchHandler):
    @property
    def name(self) -> str:
        return "ChangeEvoSystem"

    @property
    def description(self) -> str:
        return _(
            """Change the evolution system.
After applying this, every single Pokémon will have two lists for their evolution and children, and different stat bonuses when a Pokémon evolves into them.
This supposedly removes most of the particular cases the game handles for evolutions. """
        )

    @property
    def author(self) -> str:
        return "Anonymous"

    @property
    def version(self) -> str:
        return "0.0.2"

    @property
    def category(self) -> PatchCategory:
        return PatchCategory.UTILITY

    def is_applied(self, rom: NintendoDSRom, config: Pmd2Data) -> bool:
        if config.game_version == GAME_VERSION_EOS:
            if config.game_region == GAME_REGION_US:
                return (
                    read_u32(rom.arm9, PATCH_CHECK_ADDR_APPLIED_US)
                    != PATCH_CHECK_INSTR_APPLIED
                )
            if config.game_region == GAME_REGION_EU:
                return (
                    read_u32(rom.arm9, PATCH_CHECK_ADDR_APPLIED_EU)
                    != PATCH_CHECK_INSTR_APPLIED
                )
            if config.game_region == GAME_REGION_JP:
                return (
                    read_u32(rom.arm9, PATCH_CHECK_ADDR_APPLIED_JP)
                    != PATCH_CHECK_INSTR_APPLIED
                )
        raise NotImplementedError()

    def apply(
        self, apply: Callable[[], None], rom: NintendoDSRom, config: Pmd2Data
    ) -> None:
        if not self.is_applied(rom, config):
            if config.game_version == GAME_VERSION_EOS:
                if config.game_region == GAME_REGION_US:
                    evo_hp_bonus = EVO_HP_BONUS_US
                    evo_ph_bonus = EVO_PHYS_BONUS_US
                    evo_sp_bonus = EVO_SPEC_BONUS_US
                if config.game_region == GAME_REGION_EU:
                    evo_hp_bonus = EVO_HP_BONUS_EU
                    evo_ph_bonus = EVO_PHYS_BONUS_EU
                    evo_sp_bonus = EVO_SPEC_BONUS_EU
                if config.game_region == GAME_REGION_JP:
                    evo_hp_bonus = EVO_HP_BONUS_JP
                    evo_ph_bonus = EVO_PHYS_BONUS_JP
                    evo_sp_bonus = EVO_SPEC_BONUS_JP
            # Create Evo Table
            md_bin = rom.getFileByName("BALANCE/monster.md")
            md_model = MdHandler.deserialize(md_bin)

            mevo_data = bytearray(len(md_model) * MEVO_ENTRY_LENGTH + 4)
            write_u32(mevo_data, u32_checked(len(mevo_data)), 0)
            next_stage: List[int]
            for i in range(len(md_model)):
                if i in SPECIAL_EVOS:
                    next_stage = SPECIAL_EVOS[i]
                else:
                    next_stage = []
                    for j, x in enumerate(md_model):
                        if (i < 600 and 1 <= j < 555) or (i >= 600 and 601 <= j < 1155):
                            if (
                                x.pre_evo_index == i
                                and x.evo_method != EvolutionMethod.NONE.value
                                and (
                                    x.evo_param2 != AdditionalRequirement.MALE.value
                                    or i < 600
                                )
                                and (
                                    x.evo_param2 != AdditionalRequirement.FEMALE.value
                                    or i >= 600
                                )
                            ):
                                next_stage.append(j)
                write_u16(
                    mevo_data, u16_checked(len(next_stage)), i * MEVO_ENTRY_LENGTH + 4
                )
                for j, x in enumerate(next_stage):
                    write_u16(
                        mevo_data, u16_checked(x), i * MEVO_ENTRY_LENGTH + j * 2 + 6
                    )
                if i in SPECIAL_EGGS:
                    next_stage = SPECIAL_EGGS[i]
                else:
                    next_stage = []
                    pre_evo = i
                    tries = 0
                    try:
                        while md_model[pre_evo].pre_evo_index != 0:
                            current = md_model[pre_evo]
                            pre_evo = current.pre_evo_index
                            if (
                                current.evo_param2 == AdditionalRequirement.MALE.value
                                and md_model[pre_evo % 600].gender == Gender.MALE.value
                                and md_model[pre_evo % 600 + 600].gender
                                == Gender.FEMALE.value
                            ):
                                pre_evo = pre_evo % 600
                            elif (
                                current.evo_param2 == AdditionalRequirement.FEMALE.value
                                and md_model[pre_evo % 600].gender == Gender.MALE.value
                                and md_model[pre_evo % 600 + 600].gender
                                == Gender.FEMALE.value
                            ):
                                pre_evo = pre_evo % 600 + 600
                            tries += 1
                            if tries >= MAX_TRY:
                                raise Exception(
                                    f(
                                        _(
                                            "Infinite recursion detected in pre evolutions for md entry {i}. "
                                        )
                                    )
                                )
                        next_stage.append(pre_evo)
                    except IndexError as e:
                        raise Exception(
                            f(
                                _(
                                    "One of the monsters in the pre-evolution chain of monster ${i:04} has an invalid pre "
                                    "evolution configured: ${pre_evo:04}. Can not apply patch."
                                )
                            )
                        ) from e
                if next_stage != [i]:
                    write_u16(
                        mevo_data,
                        u16_checked(len(next_stage)),
                        i * MEVO_ENTRY_LENGTH + 0x16,
                    )
                    for j, x in enumerate(next_stage):
                        write_u16(
                            mevo_data,
                            u16_checked(x),
                            i * MEVO_ENTRY_LENGTH + j * 2 + 0x18,
                        )

            hp_bonus = read_u32(rom.arm9, evo_hp_bonus)
            atk_bonus = read_u16(rom.arm9, evo_ph_bonus)
            def_bonus = read_u16(rom.arm9, evo_ph_bonus + 2)
            spatk_bonus = read_u16(rom.arm9, evo_sp_bonus)
            spdef_bonus = read_u16(rom.arm9, evo_sp_bonus + 2)
            evo_add_stats = bytearray(MEVO_STATS_LENGTH)
            write_u16(evo_add_stats, u16_checked(hp_bonus), 0)
            write_u16(evo_add_stats, atk_bonus, 2)
            write_u16(evo_add_stats, spatk_bonus, 4)
            write_u16(evo_add_stats, def_bonus, 6)
            write_u16(evo_add_stats, spdef_bonus, 8)
            mevo_data += evo_add_stats * len(md_model)
            if MEVO_PATH not in rom.filenames:
                create_file_in_rom(rom, MEVO_PATH, mevo_data)
            else:
                rom.setFileByName(MEVO_PATH, mevo_data)
        try:
            apply()
        except RuntimeError as ex:
            raise ex

    def unapply(
        self, unapply: Callable[[], None], rom: NintendoDSRom, config: Pmd2Data
    ) -> None:
        raise NotImplementedError()


"""
Python script to scrape books from `Project Gutenberg` eBook library
website: https://www.gutenberg.org/
"""

# =====================================================================
# Import
# =====================================================================

# import internal modules
import re
import requests
import time
import random

# import 3rd-party modules
from bs4 import BeautifulSoup as bs
import pandas as pd

# import local modules

# =====================================================================
# Functions
# =====================================================================

def download_page(url):
    """
    Function to
    - download page
    - and parse it with BeautifulSoup
    """
    # download page
    response = requests.get(url)
    print(url, response.status_code)

    # parse page
    soup = bs(response.content, features="lxml")

    return soup

def get_book_links(soup) -> pd.DataFrame:
    """
    Function to get links of the first 25 books
    from search page
    """
    # create empty dataframe
    cols = ["title", "author", "link", "book_id"]
    books_df = pd.DataFrame(columns=cols)

    # define base url for links
    base_url = "https://www.gutenberg.org"

    # scrape info
    for rank, element in enumerate(soup.find_all("li", attrs={"class": "booklink"}), start=1):
        title = element.find("span", attrs={"class": "title"}).text
        author = element.find("span", attrs={"class": "subtitle"}).text
        link = base_url + element.find("a", attrs={"class": "link"}).get("href")
        # cover_img_link = base_url + element.find("img", attrs={"class": "cover-thumb"}).get("src")
        book_id = re.findall(r"\d+", link)[0]
        # utf_8_txt_link = f"{base_url}/files/{book_id}/{book_id}-0.txt"
        books_df.loc[rank] = [title, author, link, book_id]

    return books_df

def get_book_text(link):
    """
    Function to get book text in html
    """
    # download book page
    soup = download_page(link)

    # define base url for links
    base_url = "https://www.gutenberg.org"

    # scrape book html link
    book_html_link = base_url + soup.find("a", attrs={"class": "link"}, href=re.compile(r".htm")).get("href")

    # slow down requests frequency to avoid IP ban
    time.sleep(random.uniform(2.0, 3.0))

    # download book page
    response = requests.get(book_html_link)
    print(book_html_link, response.status_code)

    # scrape
    soup = bs(response.text, 'html.parser')
    tags = soup.find_all(['h4', 'p'])
    text = [tag.text for tag in tags]
    book = ' '.join(text)

    # return book text
    return book

def search_books(search) -> pd.DataFrame:
    """
    Function to search for books
    """

    # prepare search query url in required format
    search_book_url = "https://www.gutenberg.org/ebooks/search/?query="
    search_book_url += "+".join(search.split(" "))

    # download page
    soup = download_page(search_book_url)

    return get_book_links(soup)

def get_most_popular_books() -> pd.DataFrame:
    """
    Function to get links of the 25 most popular books
    (most downloaded from `Project Gutenberg`)
    """
    # download page of most popular books
    url='https://www.gutenberg.org/ebooks/search/?sort_order=downloads'
    soup = download_page(url)

    return get_book_links(soup)

# ============================================================
# Main Function
# ============================================================

def main():
    """
    Main function
    """
    # input search query
    # search = input("search for books, authors, genre, ...")

    popular_books = get_most_popular_books()
    print(popular_books)
    book_link = popular_books.loc[1, "link"]
    print(book_link)
    book_text = get_book_text(book_link)
    # book_text = get_book_text("https://www.gutenberg.org/ebooks/31547")

    # find index position where metadata from website ends
    # metadata_end_idx = book_text.rfind("***",0,1000)
    # print(book_text[metadata_end_idx: 1000])

# =====================================================================
# Run
# =====================================================================

# execute main() if you directly run this program
if __name__ == '__main__':
    main()


"""
840. Magic Squares In Grid
A 3 x 3 magic square is a 3 x 3 grid filled with distinct numbers from 1 to 9 such that each row, and both diagonals all have the same sum.

Given a row x col grid of integers, how many 3 x 3 "magic square" subgrids are there? (Each subgrid is contiguous).

Example1:
Input: grid = [
    [4,3,8,4],
    [9,5,1,9],
    [2,7,6,2]
]
Output: 1

Example2:
Input: grid = [[8]]
Output: 0

Constraints:
row == grid.length
col == grid[i].length
1 <= row, col <= 10
0 <= grid[i][j] <= 15
"""

"""
Note:
1. Brute Force: O(nm) time | O(1) space
2. Magic Order: O(nm) time | O(1) space
ref: https://leetcode.com/problems/magic-squares-in-grid/discuss/133874/Python-5-and-43816729
(1) The center of magic square must be 5.
(2) The even must be in the corner, and the odd must be on the edge.
(3) it must be in a order like "43816729" （clockwise or anticlockwise)
"""

from typing import List
class Solution:
    def numMagicSquaresInside(self, grid: List[List[int]]) -> int:
        rows, cols = len(grid), len(grid[0])
        total = 0
        for row in range(rows-2):
            for col in range(cols-2):
                if self.isMagicSquare(row, col, grid):
                    total += 1
        return total

    def isMagicSquare(self, row, col, grid) -> bool:
        squareSet = set()
        for r in range(row, row+3):
            for c in range(col, col+3):
                squareSet.add(grid[r][c])
        if squareSet != {i for i in range(1, 9+1)}:
            return False

        for i in range(row, row+3):
            if sum(grid[i][col:col+3]) != 15:
                return False

        for j in range(col, col+3):
            colSum = 0
            for i in range(row, row+3):
                colSum += grid[i][j]
            if colSum != 15:
                return False

        if sum([grid[row][col], grid[row+1][col+1], grid[row+2][col+2]]) != 15:
            return False
        if sum([grid[row][col+2], grid[row+1][col+1], grid[row+2][col]]) != 15:
            return False
        return True

    def numMagicSquaresInside2(self, grid: List[List[int]]) -> int:
        def isMagicSquare(row, col):
            s = "".join(str(grid[row+x//3][col+x%3]) for x in [0, 1, 2, 5, 8, 7, 6, 3])
            return grid[row][col] % 2 == 0 and (s in "43816729" * 2 or s in "43816729"[::-1] * 2)

        rows, cols = len(grid), len(grid[0])
        total = 0
        for row in range(rows-2):
            for col in range(cols-2):
                if isMagicSquare(row, col) and grid[row+1][col+1] == 5:
                    total += 1
        return total

# Unit Tests
import unittest
funcs = [Solution().numMagicSquaresInside, Solution().numMagicSquaresInside2]

class TestNumMagicSquaresInside(unittest.TestCase):
    def testNumMagicSquaresInside1(self):
        for func in funcs:
            grid = [[4,3,8,4],[9,5,1,9],[2,7,6,2]]
            self.assertEqual(func(grid=grid), 1)

    def testNumMagicSquaresInside2(self):
        for func in funcs:
            grid = [[8]]
            self.assertEqual(func(grid=grid), 0)

    def testNumMagicSquaresInside3(self):
        for func in funcs:
            grid = [[5,5,5],[5,5,5],[5,5,5]]
            self.assertEqual(func(grid=grid), 0)

if __name__ == "__main__":
    unittest.main()


import imgaug as ia
from imgaug import augmenters as iaa

def get():
    def sometimes(aug): return iaa.Sometimes(0.5, aug)

    return iaa.Sequential(
        [
            # apply the following augmenters to most images
            iaa.Fliplr(0.5),  # horizontally flip 50% of all images
            iaa.Flipud(0.2),  # vertically flip 20% of all images
            # crop images by -5% to 10% of their height/width
            sometimes(iaa.CropAndPad(
                percent=(-0.05, 0.1),
                pad_mode=ia.ALL,
                pad_cval=(0, 255)
            )),
            sometimes(iaa.Affine(
                # scale images to 80-120% of their size, individually per axis
                scale={'x': (0.8, 1.2), 'y': (0.8, 1.2)},
                # translate by -20 to +20 percent (per axis)
                translate_percent={'x': (-0.2, 0.2), 'y': (-0.2, 0.2)},
                rotate=(-45, 45),  # rotate by -45 to +45 degrees
                shear=(-16, 16),  # shear by -16 to +16 degrees
                # use nearest neighbour or bilinear interpolation (fast)
                order=[0, 1],
                # if mode is constant, use a cval between 0 and 255
                cval=(0, 255),
                # use any of scikit-image's warping modes (see 2nd image from the top for examples)
                mode=ia.ALL
            )),
            # execute 0 to 5 of the following (less important) augmenters per image
            # don't execute all of them, as that would often be way too strong
            iaa.SomeOf((0, 5),
                       [
                # convert images into their superpixel representation
                sometimes(iaa.Superpixels(
                    p_replace=(0, 1.0), n_segments=(20, 200))),
                iaa.OneOf([
                    # blur images with a sigma between 0 and 3.0
                    iaa.GaussianBlur((0, 3.0)),
                    # blur image using local means with kernel sizes between 2 and 7
                    iaa.AverageBlur(k=(2, 7)),
                    # blur image using local medians with kernel sizes between 2 and 7
                    iaa.MedianBlur(k=(3, 11)),
                ]),
                iaa.Sharpen(alpha=(0, 1.0), lightness=(
                    0.75, 1.5)),  # sharpen images
                iaa.Emboss(alpha=(0, 1.0), strength=(
                    0, 2.0)),  # emboss images
                # search either for all edges or for directed edges,
                # blend the result with the original image using a blobby mask
                iaa.SimplexNoiseAlpha(iaa.OneOf([
                    iaa.EdgeDetect(alpha=(0.5, 1.0)),
                    iaa.DirectedEdgeDetect(
                        alpha=(0.5, 1.0), direction=(0.0, 1.0)),
                ])),
                # add gaussian noise to images
                iaa.AdditiveGaussianNoise(loc=0, scale=(
                    0.0, 0.05*255), per_channel=0.5),
                iaa.OneOf([
                    # randomly remove up to 10% of the pixels
                    iaa.Dropout((0.01, 0.1), per_channel=0.5),
                    iaa.CoarseDropout((0.03, 0.15), size_percent=(
                        0.02, 0.05), per_channel=0.2),
                ]),
                # invert color channels
                iaa.Invert(0.05, per_channel=True),
                # change brightness of images (by -10 to 10 of original value)
                iaa.Add((-10, 10), per_channel=0.5),
                # change hue and saturation
                iaa.AddToHueAndSaturation((-20, 20)),
                # either change the brightness of the whole image (sometimes
                # per channel) or change the brightness of subareas
                iaa.OneOf([
                    iaa.Multiply((0.5, 1.5), per_channel=0.5),
                    iaa.FrequencyNoiseAlpha(
                        exponent=(-4, 0),
                        first=iaa.Multiply((0.5, 1.5), per_channel=True),
                        second=iaa.ContrastNormalization((0.5, 2.0))
                    )
                ]),
                # improve or worsen the contrast
                iaa.ContrastNormalization((0.5, 2.0), per_channel=0.5),
                iaa.Grayscale(alpha=(0.0, 1.0)),
                # move pixels locally around (with random strengths)
                sometimes(iaa.ElasticTransformation(
                    alpha=(0.5, 3.5), sigma=0.25)),
                # sometimes move parts of the image around
                sometimes(iaa.PiecewiseAffine(scale=(0.01, 0.05))),
                sometimes(iaa.PerspectiveTransform(scale=(0.01, 0.1)))
            ],
                random_order=True
            )
        ],
        random_order=True
    )


import sys
import unittest

import soundfile

from porcupine import Porcupine
from util import *

class PorcupineTestCase(unittest.TestCase):
    @staticmethod
    def __append_language(s, language):
        if language == 'en':
            return s
        return f'{s}_{language}'

    @classmethod
    def __pv_model_path_by_language(cls, relative, language):
        model_path_subdir = cls.__append_language('lib/common/porcupine_params', language)
        return os.path.join(os.path.dirname(__file__), relative, f'{model_path_subdir}.pv')

    @classmethod
    def __pv_keyword_paths_by_language(cls, relative, language):
        keyword_files_root = cls.__append_language('resources/keyword_files', language)
        keyword_files_dir = \
            os.path.join(os.path.dirname(__file__), relative, keyword_files_root, pv_keyword_files_subdir())

        res = dict()
        for x in os.listdir(keyword_files_dir):
            res[x.rsplit('_')[0]] = os.path.join(keyword_files_dir, x)

        return res

    def run_porcupine(self, language, keywords, ground_truth, audio_file_name=None):
        if audio_file_name is None:
            _audio_file_name_prefix = self.__append_language('multiple_keywords', language)
            audio_file_name = f'{_audio_file_name_prefix}.wav'
        keyword_paths = list()
        for x in keywords:
            keyword_paths.append(self.__pv_keyword_paths_by_language('../..', language)[x])

        porcupine = Porcupine(
            access_key=sys.argv[1],
            library_path=pv_library_path('../..'),
            model_path=self.__pv_model_path_by_language('../..', language),
            keyword_paths=keyword_paths,
            sensitivities=[0.5] * len(keyword_paths))

        audio, sample_rate = soundfile.read(
            os.path.join(os.path.dirname(__file__), '../../resources/audio_samples/', audio_file_name),
            dtype='int16')
        assert sample_rate == porcupine.sample_rate

        num_frames = len(audio) // porcupine.frame_length
        results = []
        for i in range(num_frames):
            frame = audio[i * porcupine.frame_length:(i + 1) * porcupine.frame_length]
            result = porcupine.process(frame)
            if result >= 0:
                results.append(result)

        porcupine.delete()

        self.assertEqual(results, ground_truth)

    def test_single_keyword(self):
        self.run_porcupine(
            language='en',
            keywords=['porcupine'],
            ground_truth=[0],
            audio_file_name='porcupine.wav')

    def test_multiple_keywords(self):
        keywords = [
            'americano', 'blueberry', 'bumblebee', 'grapefruit',
            'grasshopper', 'picovoice', 'porcupine', 'terminator'
        ]
        self.run_porcupine(
            language='en',
            keywords=keywords,
            ground_truth=[6, 0, 1, 2, 3, 4, 5, 6, 7])

    def test_single_keyword_es(self):
        self.run_porcupine(
            language='es',
            keywords=['manzana'],
            ground_truth=[0],
            audio_file_name='manzana.wav')

    def test_multiple_keywords_es(self):
        self.run_porcupine(
            language='es',
            keywords=['emparedado', 'leopardo', 'manzana'],
            ground_truth=[0, 1, 2])

    def test_single_keyword_de(self):
        self.run_porcupine(
            language='de',
            keywords=['heuschrecke'],
            ground_truth=[0],
            audio_file_name='heuschrecke.wav')

    def test_multiple_keywords_de(self):
        self.run_porcupine(
            language='de',
            keywords=['ananas', 'heuschrecke', 'leguan', 'stachelschwein'],
            ground_truth=[0, 1, 2, 3])

    def test_single_keyword_fr(self):
        self.run_porcupine(
            language='fr',
            keywords=['mon chouchou'],
            ground_truth=[0],
            audio_file_name='mon_chouchou.wav')

    def test_multiple_keywords_fr(self):
        self.run_porcupine(
            language='fr',
            keywords=['framboise', 'mon chouchou', 'parapluie'],
            ground_truth=[0, 1, 0, 2])

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print("usage: test_porcupine.py ${AccessKey}")
        exit(1)

    unittest.main(argv=sys.argv[:1])


# Section12-1
# 파이썬 데이터베이스 연동(SQLite)
# 테이블 생성 및 삽입

import sqlite3
import datetime

# 삽입 날짜 생성
now = datetime.datetime.now()
print('now : ', now)

nowDatetime = now.strftime('%Y-%m-%d %H:%M:%S')
print('nowDatetime : ',nowDatetime)

# sqlite3
print('sqlite3.version : ', sqlite3.version)
print('sqlite3.sqlite_version : ',sqlite3.sqlite_version)

# DB 생성 & Auto Commit(Rollback)
conn = sqlite3.connect('D:\Study\IT_Skill\패스트캠퍼스\Python\python_basic/resource/database.db', isolation_level=None)

# Cursor
c = conn.cursor()
print('Cursor Type ', type(c))

# 테이블 생성(Data Type : TEXT, NUMERIC INTEGER REAL BLOB)
c.execute("CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, username text, email text \
,phone text, website text, regdata text)") # 테이블이 없으면 만들겠다

# 테이블 삽입
#c.execute("INSERT INTO users VALUES(1, 'Kim', 'Kim@naver.com', '010-1234-5678', \
    #'Kim.com', ?)", (nowDatetime,)) # nowDatetime 이 ? 에 매칭돼 들어감
#c.execute("INSERT INTO users(id, username, email, phone, website, regdata) VALUES(?,?,?,?,?,?)",(2, 'Lee', 'Lee@naver.com', '010-1234-5678', 'Lee.com', nowDatetime))

# Many 삽입(튜플, 리스트)
userList = (
    (3, 'Park', 'Park@naver.com', '010-0000-0003', 'Park.com', nowDatetime),
    (4, 'Choi', 'Choi@naver.com', '010-0000-0004', 'Choi.com', nowDatetime),
    (5, 'Jung', 'Jung@naver.com', '010-0000-0005', 'Jung.com', nowDatetime)
)

# c.executemany("INSERT INTO users(id, username, email, phone, website, regdata) VALUES(?,?,?,?,?,?)", userList)

# 테이블 데이터 삭제
# conn.execute("DELETE FROM users")
# print("users db deleted : ", conn.execute("DELETE FROM users").rowcount) # 데이터를 지운 후 몇개를 지웠는지 알려준다

# 커밋 : isolation_level = None 일 경우 자동 반영(오토 커밋)

# 롤백
# conn.rollback()

# 접속 해제
# conn.close()


#!/usr/bin/env python

import asyncio
import websockets
import json
import time
import sys
from mrc88_interface import Interface
from channel import Channel

class WebSocketServer:

    def __init__(self, amp):
        self.nextStateUpdate = time.time()
        self.connections = set()
        self.amp = amp

    def start(self):
        start_server = websockets.serve(self.handleWebSocket, "0.0.0.0", 8765)
        print("Awaiting websocket connections")
        asyncio.get_event_loop().run_until_complete(start_server)
        self.pollTask = asyncio.get_event_loop().create_task(self.checkAmpPeriodically())
        asyncio.get_event_loop().run_forever()
        try:
            self.pollTask.cancel()
        except asyncio.CancelledError:
            print("Stopped polling amp")

    async def registerClient(self, websocket):
        self.connections.add(websocket)

    async def removeClient(self, websocket):
        self.connections.remove(websocket)

    async def handleWebSocket(self, websocket, path):
        await self.registerClient(websocket)
        try:
            async for message in websocket:
                jsn = json.loads(message)
                operation = jsn["operation"]
                if operation == "command":
                    await self.handleCommand(websocket, jsn)
                elif operation == "getState":
                    await self.updateState(websocket, jsn["id"])
        except websockets.exceptions.ConnectionClosedError:
            print("Connection closed for one client")
        finally:
            await self.removeClient(websocket)

    async def handleCommand(self, websocket, jsn):
        t = jsn['type']
        channel = jsn['id']
        value = jsn['value']
        if t == 'volume':
            self.amp.setVolume(channel, value)
        elif t == 'input':
            self.amp.selectSource(channel, value)
        elif t == 'power':
            self.amp.togglePower(channel)
        elif t == 'treble':
            self.amp.setTreble(channel, value)
        elif t == 'bass':
            self.amp.setBass(channel, value)
        elif t == 'balance':
            self.amp.setBalance(channel, value)

        for ws in self.connections:
            if ws is not websocket:
                await self.updateState(ws, channel)

    def getCurrentState(self, channel):
        data = []
        if channel == -1:
            for channel in self.amp.channels:
                data.append(channel)
        else:
            data.append(self.amp.channels[channel])
        return data

    async def updateState(self, websocket, channel):
        await self.sendStateData(websocket, self.getCurrentState(channel))

    async def sendStateData(self, websocket, stateData):
        jsn = {"responseType": "state"}
        data = []
        for channel in stateData:
            data.append(channel.toDict())
        jsn["data"] = data
        await websocket.send(json.dumps(jsn))

    async def checkAmpPeriodically(self):
        while True:
            await asyncio.sleep(60)
            changedAmpData = self.amp.checkIfAmpChanged()
            if len(changedAmpData):
                for websocket in self.connections:
                    await self.sendStateData(websocket, changedAmpData)

serialPort = sys.argv[1]
amp = Interface()
try:
    amp.connect(serialPort)
    server = WebSocketServer(amp)
    server.start()
finally:
    print("Disconnecting from serial")
    amp.disconnect()


import sys
sys.path.append('C:\\Users\\Ruedi\\OneDrive\\Learning\\Learning\\World Bank')
import GUI_Plots_Pannel
import GUI_ListPannel
import WorldBank

from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout

class WIN( QWidget ):

    def __init__(self, parent = None):
        super(WIN, self).__init__(parent)
        self.worldBank = WorldBank.WorldBank()
        self.showFullScreen()
        self.setWindowTitle( "World Bank GUI" )

        layout = QHBoxLayout()
        self.setLayout(layout)

        self.plots_Pannel = GUI_Plots_Pannel.GUI_Plots_Pannel( self.worldBank )
        self.listPannel = GUI_ListPannel.GUI_List_Pannel( self.worldBank, self.plots_Pannel )

        layout.addLayout( self.listPannel, 1 )
        layout.addLayout( self.plots_Pannel, 5 )

        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = WIN()
    sys.exit(app.exec_())


# -*- coding: utf-8 -*-

import pandas as pd
import os

df = pd.read_pickle(os.path.join('..', 'data_frame.pickle'))

# Smaller object for easier vis
small_df = df.iloc[49980:50019, :].copy()

# Basic Excel
small_df.to_excel("basic.xlsx")
small_df.to_excel("no_index.xlsx", index=False)
small_df.to_excel("columns.xlsx", columns=["artist", "title", "year"])

# Multiple worksheets
writer = pd.ExcelWriter('multiple_sheets.xlsx', engine='xlsxwriter')
small_df.to_excel(writer, sheet_name="Preview", index=False)
df.to_excel(writer, sheet_name="Complete", index=False)
writer.save()

# Conditional formatting
artist_counts = df['artist'].value_counts()
artist_counts.head()
writer = pd.ExcelWriter('colors.xlsx', engine='xlsxwriter')
artist_counts.to_excel(writer, sheet_name="Artist Counts")
sheet = writer.sheets['Artist Counts']
cells_range = 'B2:B{}'.format(len(artist_counts.index))
sheet.conditional_format(cells_range, {'type': '2_color_scale',
                              'min_value': '10',
                              'min_type': 'percentile',
                              'max_value': '99',
                              'max_type': 'percentile'})
writer.save()

# SQL
import sqlite3

with sqlite3.connect('my_database.db') as conn:
    small_df.to_sql('Tate', conn)

# import sqlalchemy as sa
# with sa.create_engine('postgresql://localhost/my_data') as conn:
#     small_df.to_sql('Tate', conn)

# JSON
small_df.to_json('default.json')
small_df.to_json('table.json', orient='table')


from dataclasses import dataclass

def bin8(value: int):
    """
    Convert 8-bit register value to binary representation.
    """
    return ("0"*8 + bin(value)[2:])[-8:]

def metronome_pattern(bar_length):
    return [3, 0] + [1, 0] * (bar_length - 1)

def timing_grade(time, target, margin):
    error = abs(target-time)
    if error <= margin:
        return 1.0
    else:
        return 0

@dataclass
class RegRecording:
    data: int
    time: int
    tainted: bool = False

    def timing_grade(self, target, margin):
        return timing_grade(self.time, target, margin)

def bitmask_history(history, bitmask: int):
    first = history[0]
    newhist = [RegRecording(first.data & bitmask, first.time, first.data & bitmask != first.data)]
    for n in history[1:]:
        if n.data & bitmask == newhist[-1].data:
            newhist[-1].time += n.time
            if n.data & bitmask != n.data:
                newhist[-1].tainted = True
        else:
            newhist.append(RegRecording(n.data & bitmask, n.time, n.data & bitmask != n.data))
    return newhist

def prefix_match(sequence, target):
    out = []
    for i, expected in enumerate(target):
        if i >= len(sequence):
            break
        if sequence[i].data != expected:
            break
        out.append(sequence[i])
    return out

def get_longest_match(sequence, target):
    prefixes = [prefix_match(sequence[i:], target) for i in range(len(sequence))]
    if not prefixes:
        return -1, []
    # Reversed because we want to prefer the latest longest match.
    # For example, if we don't use the latest match in 2X speed test, we might incorrectly
    # detect a timing error.
    maxi = max(reversed(range(len(prefixes))), key=lambda i: len(prefixes[i]))
    return maxi, prefixes[maxi]

class ReportSection:
    def __init__(self, name: float, max_grade: float):
        self.name = name
        self.max_grade = max_grade
        self.grade = 0.0

    def grade_str(self) -> str:
        if self.max_grade > 0:
            return "%.1f / %.1f" % (self.grade, self.max_grade)
        else:
            return "%.1f" % self.grade

class Report:
    def __init__(self):
        self.grade_log = []

    def add_section(self, name, grade):
        new_section = ReportSection(name, grade)
        self.grade_log.append(new_section)
        return new_section

    def report_str(self):
        if len(self.grade_log) == 0:
            self.add_section("Failed to execute tests", 0.0)
        grade_items = [g.grade_str() for g in self.grade_log]
        f = "{0:>" + str(max([len(s) for s in grade_items])) + "}  {1}"
        grade_report = "\n".join([f.format(g, r.name) for g, r in zip(grade_items, self.grade_log)])

        total_grade = sum([g.grade for g in self.grade_log])
        max_grade = sum([g.max_grade for g in self.grade_log])
        return f"GRADE\n{grade_report}\nFINAL GRADE: {total_grade:.1f}/{max_grade:.1f}"

def record_porta(m, max_history: int, max_cycles: int, max_flicker: int = 1000):
    flickers = []
    # Watch writes to this register
    m.watch("PORTA W")
    m.watch("LATA W")
    history = []
    # Since PORTA is output, we need to read from LATCH
    value = m.get("LATA")
    current = RegRecording(value, 0)
    cycles = 0
    while len(history) < max_history:
        m.run()
        value = m.get("LATA")
        time = m.stopwatch()
        current.time += time
        cycles += time
        if value != current.data:
            print("PORTA changed to", str(value) + " (" + bin8(value) + ") after", str(time/1e6) + "s", end = " ")
            if current.time > max_flicker:  # Don't record if too short
                history.append(current)
            elif len(history) > 1:  # Ignore flickers at the start
                flickers.append(current)
                print("(FLICKER)", end="")
            print()
            current = RegRecording(value, 0)
        if cycles > max_cycles:
            if current.time > max_flicker:  # Don't record if too short
                history.append(current)
            break
    m.clear_breakpoints()
    return history

def click_button(m, pin):
    """
    Press the button, wait 10ms, release the button
    """
    print("Pressing & releasing "+ pin.upper() + "...")
    m.exec("write pin " + pin + " high")
    m.stepi(50_000)
    m.exec("write pin " + pin + " low")
    m.stepi(50_000)

def hold_button(m, pin):
    """
    Press the button
    """
    print("Holding "+ pin.upper() + "...")
    m.exec("write pin " + pin + " high")

def release_button(m, pin):
    """
    Release the button
    """
    print("Releasing "+ pin.upper() + "...")
    m.exec("write pin " + pin + " low")


import cv2

# Aquí coloca la ruta de la imagen con la cara a detectar
imagenRuta = 'imagen.jpeg'

# Cargar el modelo pre-entrenado para detección facial
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

# Cargar la imagen en la que deseas realizar el reconocimiento facial
image = cv2.imread( imagenRuta )

# Convertir la imagen a escala de grises
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Detectar caras en la imagen
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

# Dibujar un rectángulo alrededor de cada cara detectada
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)

# Mostrar la imagen con las caras marcadas
cv2.imshow("Reconocimiento Facial", image)

# Esperar a que el usuario presione una tecla y luego cerrar la ventana
cv2.waitKey(0)
cv2.destroyAllWindows()


import os
import json

from collections import namedtuple
from tile2net.tileseg.config import cfg
from runx.logx import logx
from tile2net.tileseg.datasets.base_loader import BaseLoader
from tile2net.tileseg.datasets.utils import make_dataset_folder
from tile2net.tileseg.datasets import uniform

Label = namedtuple( 'Label' , [

    'name'        , # The identifier of this label, e.g. 'car', 'person', ... .
    # We use them to uniquely name a class

    'id'          , # An integer ID that is associated with this label.
    # The IDs are used to represent the label in ground truth images
    # An ID of -1 means that this label does not have an ID and thus
    # is ignored when creating ground truth images (e.g. license plate).
    # Do not modify these IDs, since exactly these IDs are expected by the
    # evaluation server.

    'trainId'     , # Feel free to modify these IDs as suitable for your method. Then create
# ground truth images with train IDs, using the tools provided in the
# 'preparation' folder. However, make sure to validate or submit results
# to our evaluation server using the regular IDs above!
# For trainIds, multiple labels might have the same ID. Then, these labels
# are mapped to the same class in the ground truth images. For the inverse
# mapping, we use the label that is defined first in the list below.
# For example, mapping all void-type classes to the same ID in training,
# might make sense for some approaches.
# Max value is 255!
    'color'       , # The color of this label
] )

labels = [
    #       name                     id    trainId     color
    Label(  'Sidewalk'             ,  1 ,        0 ,  (0, 0, 255)),
    Label(  'Road'                 ,  2 ,        1 ,  (0, 128, 0)),
    Label(  'Crosswalk'            ,  3 ,        2 ,  (255, 0, 0)),
    Label(  'Background'           ,  4 ,        3 ,  (0, 0, 0)),
    ]

name2label      = { label.name    : label for label in labels           }
# id to label object
id2label        = { label.id      : label for label in labels           }
# trainId to label object
trainId2label   = { label.trainId : label for label in reversed(labels) }
# label2trainid
label2trainid   = { label.id      : label.trainId for label in labels   }
# trainId to label object
trainId2name   = { label.trainId : label.name for label in labels   }
trainId2color  = { label.trainId : label.color for label in labels      }

class Loader(BaseLoader):
    num_classes = 4
    ignore_label = -1
    trainid_to_name = {}
    color_mapping = []

    def __init__(self, mode, quality='semantic', joint_transform_list=None,
                 img_transform=None, label_transform=None, eval_folder=None):

        super(Loader, self).__init__(quality=quality,
                                     mode=mode,
                                     joint_transform_list=joint_transform_list,
                                     img_transform=img_transform,
                                     label_transform=label_transform)

        root = cfg.DATASET.SATELLITE_DIR
        # config_fn = os.path.join(root, 'config.json')
        # self.fill_colormap_and_names(config_fn)
        self.id_to_trainid = label2trainid
        self.trainid_to_name = trainId2name
        self.fill_colormap()

        ######################################################################
        # Assemble image lists
        ######################################################################
        if mode == 'folder':
            self.all_imgs = make_dataset_folder(eval_folder)
        elif mode =='test':
            self.all_imgs = make_dataset_folder(eval_folder, testing=True)
        else:
            splits = {'train': 'train',
                      'val': 'val',
                      'test': 'tests'}
            split_name = splits[mode]
            # img_ext = 'png'
            # mask_ext = 'png'
            img_ext = '*'
            mask_ext = '*'
            img_root = os.path.join(root, split_name, 'images')
#            print(img_root)
            mask_root = os.path.join(root, split_name, 'annotations')
            self.all_imgs = self.find_images(img_root, mask_root, img_ext,
                                             mask_ext)
        logx.msg('all imgs {}'.format(len(self.all_imgs)))
        self.fine_centroids = uniform.build_centroids(self.all_imgs,
                                                      self.num_classes,
                                                      self.train,
                                                      cv=cfg.DATASET.CV,
                                                      id2trainid=self.id_to_trainid)
        self.centroids = self.fine_centroids
#        print('centroids', self.centroids)
        self.build_epoch()

    def fill_colormap(self):
        palette = [0, 0, 255,
                   0, 128, 0,
                   255, 0, 0,
                   0, 0, 0]

        zero_pad = 256 * 3 - len(palette)
        for i in range(zero_pad):
            palette.append(0)
        self.color_mapping = palette


import requests
import yaml

with open('config.yaml', encoding='utf-8') as f:
    data = yaml.safe_load(f)

S = requests.Session()

def test_step1(user_login, post_title):
    result = S.get(url=data['address'], headers={'X-Auth-Token': user_login}, params={'owner': 'notMe'}).json()['data']
    result_title = [i['title'] for i in result]
    assert post_title in result_title, 'test_step1 FAIL'

# Новый тест для создания и проверки нового поста
def test_create_and_check_new_post(user_login, new_post_data):
    # Создаем новый пост
    response = S.post(
        url=data['address'],
        headers={'X-Auth-Token': user_login},
        data=new_post_data
    )
    assert response.status_code == 200, 'Failed to create a new post'

    # Получаем описание нового поста
    new_post_description = new_post_data['description']

    # Проверяем, есть ли созданный пост на сервере по полю "описание"
    result = S.get(url=data['address'], headers={'X-Auth-Token': user_login}).json()['data']
    result_descriptions = [i['description'] for i in result]
    assert new_post_description in result_descriptions, 'New post not found'


import pygame
from tiles import Tile, AnimatedTile
from support import import_folder
from settings import screen_ratio

class Enemy(Tile):

	def __init__(self, width, height, x, y, direction, speed, surface):
		super().__init__(width, height, x, y)
		self.direction = direction
		self.speed = int(screen_ratio * speed)
		self.image = surface

	# Move enemy. If direction is 0 (horizontal), move along x axis.
	# If direction is 1 (vertical), move along y axis
	def move(self):
		if self.direction == 0:
			self.rect.x += self.speed
		elif self.direction == 1:
			self.rect.y += self.speed

	# Reverse enemy direction when they collide with constraints.
	# If enemy direction is horizontal, flip image
	def reverse_direction(self):
		self.speed *= -1
		if self.direction == 0:
			self.image = pygame.transform.flip(self.image, True, False)

	def update(self, shift):
		self.rect.x += shift
		self.move()

class AnimatedEnemy(Enemy):

	def __init__(self, width, height, x, y, direction, speed, surface, path_index):
		super().__init__(width, height, x, y, direction, speed, surface)
		self.path = '../graphics/enemies/' + str(path_index)
		self.frames = import_folder(self.path)
		self.frame_index = 0
		self.image = self.frames[self.frame_index]
		self.width = width
		self.height = height

	def animate(self):

		self.frame_index += 0.15
		if self.frame_index >= len(self.frames):
			self.frame_index = 0
		self.image = self.frames[int(self.frame_index)]
		self.image = pygame.transform.scale(self.image, (self.width, self.height))
		print(self.direction)
		if self.speed > 0:
			self.image = pygame.transform.flip(self.image, True, False)

	def update(self, shift):
		self.rect.x += shift
		self.animate()
		self.move()


import sys
import os

from flask import Flask, request, jsonify, redirect, url_for

app = Flask(__name__)

#@app.route("/", methods=['GET','POST', 'PUT', 'DELETE', 'PATCH','OPTIONS'])
@app.route("/", methods=['GET','POST', 'PUT', 'DELETE', 'PATCH','OPTIONS'])
def home():
   return printAndReturnRequest(request)

@app.route("/<string:query>", methods=['GET','POST', 'PUT', 'DELETE', 'PATCH','OPTIONS'])
def homeQuery(query):
    print("Query: %s" % query)
    return printAndReturnRequest(request)

def printAndReturnRequest(request):
    headers = ""
    for i in request.headers.keys():
      headers+= "\t%s: %s \n" % (i, request.headers[i])
    print("Headers: \n%s" % (headers))
    print(request.json)
    return jsonify(headers=headers, body=request.json)

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True, port=os.environ.get("LISTEN_PORT","80"))


from flask import Blueprint, request, jsonify
from flask_cors import cross_origin
from utilities.query_signup import SignUp
from database_functions.db_connection.connection import connection
from database_functions.groups.querying_functions import get_status_for_group, get_group_pending_state_machine

checkUserAPI = Blueprint('checkUserAPI', __name__)

# API to check a username is available for signup
@checkUserAPI.route('/auth/checkUser', methods=['POST'])
@cross_origin()
def check_user():
    signup = SignUp(request.json['username'])
    username = request.json['username']
    try:
        group_id = request.json['group_id']
        if get_status_for_group(connection(), group_id, username, "rejected") and \
                get_group_pending_state_machine(connection(), username, group_id) >= 4:
            message = 'User has rejected the group too many times'
        else:
            message = 'Request successfully sent to user'
        x = jsonify(
            {'username': username, 'available': signup.check_user(), 'message': message
             })
    except KeyError:
        x = jsonify(
            {'username': username, 'available': signup.check_user()
             })
    return x


import cv2, time, pandas
from datetime import datetime

first_frame = None
status_list = [None, None]
times = []
df = pandas.DataFrame(columns=["Start", "End"])

video = cv2.VideoCapture(0)  # creates the video object
time.sleep(2)  # allows webcam to initialize properly

while True:
    check, frame = video.read()
    status = 0
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # convert to grayscale
    gray = cv2.GaussianBlur(gray, (21, 21), 0)  # apply blur to increase accuracy

    if first_frame is None:  # fires on first loop
        first_frame = gray
        continue  # skips rest of the code on the first loop

    # compares differences between frames
    delta_frame = cv2.absdiff(first_frame, gray)

    # anything beyond a threshold of 30 difference is assigned to white
    # returns a tuple, but only need second item of tuple so [1]
    thresh_frame = cv2.threshold(delta_frame, 30, 255, cv2.THRESH_BINARY)[1]

    # smooth out the thresh_frame
    thresh_frame = cv2.dilate(thresh_frame, None, iterations=3)

    # find the contours and check the area of the contours
    # make copy of threshframe, retrieve external, approximate contours
    (_, cnts, _) = cv2.findContours(thresh_frame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # filter out the conturs and keep the ones with area larger than 10000 pixels
    # Create rectangle around large contours
    for contour in cnts:
        if cv2.contourArea(contour) < 10000:
            continue
        status = 1
        (x, y, w, h) = cv2.boundingRect(contour)
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)

    # append status to status_list to track start and end
    status_list.append(status)

    status_list = status_list[-2:]

    # check whether last two items of list are changing; if so append datetime to times list
    if status_list[-1] == 1 and status_list[-2] == 0:
        times.append(datetime.now())
    if status_list[-1] == 0 and status_list[-2] == 1:
        times.append(datetime.now())

    # create frames
    cv2.imshow("Gray Frame", gray)
    cv2.imshow("Delta Frame", delta_frame)
    cv2.imshow("Threshold Frame", thresh_frame)
    cv2.imshow("Color Frame", frame)

    # time the program waits on each frame display. TWEAK THIS TO ADJUST FPS
    key = cv2.waitKey(100)

    if key == ord('q'):  # sets q to break out of the loop
        if status == 1:
            times.append(datetime.now())
        break

print(status_list)
print(times)

for i in range(0, len(times), 2):
    df = df.append({"Start": times[i], "End": times[i + 1]}, ignore_index=True)

df.to_csv("Times.csv")

video.release()
cv2.destroyAllWindows()


import cv2
from base_camera import BaseCamera

class Camera(BaseCamera):
    video_source = 0
    width = 1024
    height= 768

    @staticmethod
    def set_video_source(source):
        Camera.video_source = source
    @staticmethod
    def set_video_height(height):
        Camera.height = height
        return Camera

    @staticmethod
    def set_video_width(width):
        Camera.width = width
        width=width
        print(Camera.width)
        return Camera

    @staticmethod
    def frames():
        camera = cv2.VideoCapture(Camera.video_source)
        camera.set(3,Camera.width)

        camera.set(4,Camera.height)

        if not camera.isOpened():
            raise RuntimeError('Could not start camera.')

        while True:
            # read current frame
            _, img = camera.read()
            height, width = img.shape[:2]
            #print(str(height) + 'x' + str(width))
            # encode as a jpeg image and return it
            yield img