#!/usr/bin/env python3
import subprocess
import tempfile
import os
import os.path
import collections
import json
import sys
import multiprocessing
import struct

ProcessedTrack = collections.namedtuple("ProcessedTrack", ["dfpwm_file", "metadata"])

def convert_wav_dfpwm(infile, outfile):
    subprocess.run(["java", "-jar", "LionRay.jar", infile, outfile])

def convert_any_wav(infile, outfile):
    subprocess.run(["ffmpeg", "-hide_banner", "-i", infile, "-ar", "48000", "-ac", "1", outfile], stderr=subprocess.PIPE)

def read_meta(path):
    proc = subprocess.run(["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", path], stdout=subprocess.PIPE)
    data = json.loads(proc.stdout)
    meta = {}
    # These are the two locations I've found tags in in my not very thorough testing
    try:
        meta.update(data["format"]["tags"])
    except KeyError: pass
    try:
        meta.update(data["streams"][0]["tags"])
    except KeyError: pass
    # lowercase all keys because in Opus files these seem to be uppercase sometimes
    return { k.lower(): v for k, v in meta.items() }

def process_file(filename):
    meta = read_meta(filename)
    wav_dest = tempfile.mktemp(".wav")
    convert_any_wav(filename, wav_dest)
    dfpwm_dest = tempfile.mktemp(".dfpwm")
    convert_wav_dfpwm(wav_dest, dfpwm_dest)
    os.remove(wav_dest)
    print(filename)
    return ProcessedTrack(dfpwm_dest, {
        "title": meta["title"],
        "artist": meta.get("artist", None) or meta.get("artists", None),
        "album": meta.get("album", None)
    })

def read_binary(filename):
    with open(filename, "rb") as f:
        return f.read()

def process_dir(dirname):
    files = list(map(lambda file: os.path.join(dirname, file), os.listdir(dirname)))
    with multiprocessing.Pool(8) as p:
        tracks = p.map(process_file, files)
    tape_image = b""
    tracks_meta = []
    for track in tracks:
        track.metadata["start"] = len(tape_image)
        data = read_binary(track.dfpwm_file)
        os.remove(track.dfpwm_file)
        track.metadata["end"] = track.metadata["start"] + len(data)
        tape_image += data
        tracks_meta.append(track.metadata)
    # dump in a compact format to save space
    meta = json.dumps({ "tracks": tracks_meta }, separators=(',', ':')).encode("utf-8")
    assert(len(meta) < 65536)
    # new format - 0x54 marker byte, then metadata length as 2-byte big endian integer, then metadata, then concatenated DFPWM files
    # start is now not an absolute position but just how far after the metadata it is
    tape_image = b"\x54" + struct.pack(">H", len(meta)) + meta + tape_image
    with open("tape.bin", "wb") as f:
        f.write(tape_image)
    # Tape lengths are measured in minutes. 6000 bytes are played per second because they use a 48000Hz sample rate and DFPWM is somehow 1 bit per sample.
    length_minutes = len(tape_image) / (6000*60)
    print(length_minutes, "minute tape required")

process_dir(sys.argv[1])


import networkx as nx

def transport(cost, supply, demand):
    N = len(cost)
    G = nx.DiGraph()
    G.add_node('s', demand=-sum(supply))
    G.add_node('t', demand=sum(demand))
    # G.add_edge('t', 's', weight=0, capacity=sum(r))
    for i in range(N):
        G.add_edge('s', 's_' + str(i), weight=0, capacity=supply[i])
        G.add_edge('t_' + str(i), 't', weight=0, capacity=demand[i])
        for j in range(N):
            if cost[i][j] < float("inf"):
                G.add_edge('s_' + str(i), 't_' + str(j), weight=cost[i][j], capacity=float('inf'))
    flowCost, flowDict = nx.capacity_scaling(G)
    flowXprime = {}
    for u in flowDict:
        for v in flowDict[u]:
            if "_" in u and "_" in v and flowDict[u][v] > 0:
                i, j = int(u[2:]), int(v[2:])
                flowXprime[(i, j)] = flowDict[u][v]
    return flowCost, flowXprime


#coding:utf-8
from django.conf.urls import url
from jiahuaApp import jsonViews,callbackViews
urlpatterns = [

    #url(r'^/$', views.get),#地址：www.*/oneApp/get?id=*
    url(r'^order/create/$', jsonViews.orderCreate),#订单创建
    url(r'^order/query/$', jsonViews.orderQuery),#订单查询
    url(r'^order/update/$', jsonViews.orderUpdate),#订单修改
    url(r'^order/batchUpdate/$', jsonViews.orderBatchUpdate),#订单批量修改
    url(r'^order/delete/$', jsonViews.orderDelete),#订单删除,发送id键
    url(r'^order/delbydate/$',jsonViews.deleteOrder),#按日期删除订单
    url(r'^order/count/$', jsonViews.orderCount),#订单统计，发送createTime键

    url(r'^order/batch/insert/$', jsonViews.batchCreate),#批处理导入订单
    url(r'^order/batch/query/$', jsonViews.batchQuery),#查询历史导入订单

    #url(r'^cat/query/$', jsonViews.queryCat),#车辆查询
    url(r'^cat/department/$', jsonViews.departmentList),#部门列表
    url(r'^cat/query/$', jsonViews.getDriver),#车辆查询
    url(r'^cat/create/$', jsonViews.createCat),#车辆创建
    url(r'^cat/update/$', jsonViews.updateCat),#车辆修改
    url(r'^cat/delete/$', jsonViews.deleteCat),#车辆删除

    url(r'^client/query/$', jsonViews.queryClient),#客户查询
    url(r'^client/create/$', jsonViews.createClient),#客户创建
    url(r'^client/update/$', jsonViews.updateClient),#客户修改
    url(r'^client/delete/$', jsonViews.deleteClient),#客户删除

    url(r"^postCat/$", jsonViews.postCat),#指派车辆功能
    url(r"^batchPostCat/$", jsonViews.batchPostCat),#指派车辆功能#批量指派
    url(r"^getCat/$", jsonViews.getCat),#查询所有车牌号
    url(r"^postCat/$", jsonViews.postCat),#订单按车次派送,{"userid":1,"plateNum:"鄂A12312","orderList":[..... ]}

    url(r'^operateHistory/$', jsonViews.operateHistory),#查询操作历史
    url(r'^activeTimeout/$', jsonViews.activeTimeout),#查询取卸超时
    url(r'^deleteActiveTimeout/$', jsonViews.deleteActiveTimeout),#删除取卸超时

    url(r'^location/$', jsonViews.location),#获取位置

]


from modelgenerators.RectangularDenseModelGenerator import RectangularDenseModelGenerator
from endtoendfactories.EndToEndFactoryV2 import EndToEndFactoryV2
from dataprocessors.DataProcessorGaussAndCosine import DataProcessorGaussAndCosine
import unittest

class EndToEndFactoryV2Test (unittest.TestCase):
    """Tests the EndToEndFactoryV2 class"""
    def testGetPreProcessData(self) -> None:
        """Makes sure this end to end factory gives back a
        DataProcessorGaussAndCosine"""
        data = [
            [1,2,3,4],
            [5,6,7,False]
        ]
        preProcessData = EndToEndFactoryV2.getInstance().getPreProcessData(data, True)
        self.assertTrue(issubclass(type(preProcessData), DataProcessorGaussAndCosine))

    def testGetModelGenerator(self) -> None:
        """Makes sure this end to end factory gives back a RectangularDenseModelGenerator"""
        modelGenerator = EndToEndFactoryV2.getInstance().getModelGenerator()
        self.assertTrue(issubclass(type(modelGenerator), RectangularDenseModelGenerator))


from flask import Flask ,render_template, request ,redirect, session
from datetime import datetime
import pdfkit

app=Flask(__name__)
@app.route("/")
def index():
    return render_template("index.html")

muz=(' ','Onze', 'Douze', 'Treize',
          'Quatorze', 'Quinze', 'Seize', 'Dix-Sept', 'Dix-Huit', 'Dix-Neuf' )

to_19_fr = ( 'Zéro',  'Un',   'Deux',  'Trois', 'Quatre',   'Cinq',   'Six',
          'Sept', 'Huit', 'Neuf', 'Dix',   'Onze', 'Douze', 'Treize',
          'Quatorze', 'Quinze', 'Seize', 'Dix-Sept', 'Dix-Huit', 'Dix-Neuf' )
tens_fr  = ( 'Vingt', 'Trente', 'Quarante', 'Cinquante', 'Soixante', 'Soixante-Dix', 'Quatre-Vingt', 'Quatre-Vingt Dix')
denom_fr = ( '',
          'Mille',     'Million(s)',         'Milliards',       'Billions',       'Quadrillions',
          'Quintillion',  'Sextillion',      'Septillion',    'Octillion',      'Nonillion',
          'Décillion',    'Undecillion',     'Duodecillion',  'Tredecillion',   'Quattuordecillion',
          'Sexdecillion', 'Septendecillion', 'Octodecillion', 'Icosillion', 'Vigintillion' )

def _convert_nn_fr(val):
    """ convertion des valeurs < 100 en Français
    """
    if val < 20:
        return to_19_fr[val]
    for (dcap, dval) in ((k, 20 + (10 * v)) for (v, k) in enumerate(tens_fr)):
          if dval + 10 > val:
                if val % 10:
                      if(val>70 and val <= 79):
                           dcap='Soixante'
                           return dcap + '-' +muz[val % 10]

                      if(val>90 and val <=99 ):
                            dcap='Quatre-vingt'
                            return dcap + '-' +muz[val % 10]
                      else:
                              return dcap + '-' +to_19_fr[val % 10]

                return dcap
def _convert_nnn_fr(val):
    """ convert a value < 1000 to french

        special cased because it is the level that kicks
        off the < 100 special case.  The rest are more general.  This also allows you to
        get strings in the form of 'forty-five hundred' if called directly.
    """
    word = ''
    (mod, rem) = (val % 100, val // 100)
    b = val // 100
    if rem > 0:
         if b == 1 :
               word= 'Cent'
         else:
               word = to_19_fr[rem] + ' Cent'
    if mod > 0:
            word += ' '
    if mod > 0:
        word += _convert_nn_fr(mod)
    return word

def french_number(val):
    if val < 100:
        return _convert_nn_fr(val)
    if val < 1000:
         return _convert_nnn_fr(val)
    for (didx, dval) in ((v - 1, 1000 ** v) for v in range(len(denom_fr))):
        if dval > val:
            mod = 1000 ** didx
            l = val // mod
            r = val - (l * mod)
            if (l ==1 ) and (denom_fr[didx] == 'Mille'):
                ret = denom_fr[didx]
            else:
                  ret = _convert_nnn_fr(l) + ' ' + denom_fr[didx]
            if r > 0:
                ret = ret + ' ' + french_number(r)
            return ret

def amount_to_text_fr(number):
    import math
    number = '%.2f' % number
    units_name = ' '
    list = str(number).split('.')
    muzamil=(french_number(abs(int(list[0]))))
    start_word = muzamil
    end_word =''
    #french_number(int(list[1]))
    cents_number = int(list[1])
    cents_name = (cents_number > 1) and ' dirhams' or ' dirhams'
    final_result = start_word +' '+units_name+' '+ end_word +' '+cents_name
    return final_result
@app.route("/data",methods=['POST','GET'])
def data():
    if request.method=="POST":
        if request.form["nom"] and request.form["ice"] and request.form["qte"] and request.form["puht"] and request.form["adress"] and request.form["desi"] and request.form["dtf"]:
            total=int(request.form["qte"])*int(request.form["puht"])
            ttc=total*1.2
            return render_template("data.html",nom=request.form["nom"],ice=request.form["ice"],qte=request.form["qte"],puht=request.form["puht"],total=total,tva=(total*20)/100,ttc=ttc,adress=request.form["adress"],desi=request.form["desi"],date=str(datetime.now().strftime('%Y-%m-%d')),dtf=request.form["dtf"],nbch=amount_to_text_fr(ttc))

@app.route("/pdf")
def pdf():
    pdfkit.from_file(data(), 'out.pdf')
    return res

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


class Solution:
    def PredictTheWinner(self, nums: List[int]) -> bool:

        @lru_cache
        def solve(i,j):
            if i>j: return 0
            first = nums[i] + min(solve(i+1,j-1), solve(i+2,j))
            last = nums[j] + min(solve(i,j-2), solve(i+1,j-1))

            return max(first,last)

        p1_score = solve(0,len(nums)-1)
        return p1_score>= (sum(nums)-p1_score)

486 (Predict the Winner)/python/Solution.py


from Genocchi import genocchi
from fractions import Fraction as frac

"""Bernoulli numbers A164555/A027642
"""

# #@

def Bernoulli(n: int) -> frac:
    if n < 2: return frac(1, n + 1)
    if n % 2 == 1: return frac(0, 1)
    g = genocchi(n // 2 - 1)[-1]
    f = frac(g, 2 ** (n + 1) - 2)
    return -f if n % 4 == 0 else f

if __name__ == "__main__":

    print([Bernoulli(n) for n in range(10)])

    from timeit import default_timer as timer
    start = timer()
    [Bernoulli(n) for n in range(1000)]
    end = timer()
    print(end - start)


import pickle

def model_prediction(features):

    pickled_model = pickle.load(open('C:/Users/Sakshi Rohida/Desktop/deepak sir ML projects/Social_Media_Ads_Classification/model/Social_Media _Ads_prediction_RandomForest.pkl', 'rb'))
    Purchased = str(list(pickled_model.predict(features)))

    return str(f'He/She purcased = {Purchased}')

Age = int(input("Enter the age"))
EstimatedSalary = int(input("Enter Salary"))

print(model_prediction([[Age,EstimatedSalary]]))


def loop_steps(rem, subject_number):
    return (rem * subject_number) % 20201227

def apply_secret_loop(loop, subject_number):
    i = 0
    remainder = 1
    while i != loop:
        remainder = loop_steps(remainder, subject_number)
        i += 1
    return remainder

def find_secret_loop(target, subject_number):
    i = 0
    remainder = 1
    while remainder != target:
        remainder = loop_steps(remainder, subject_number)
        i += 1
    return i

def solution1(target1, target2):
    loop1 = find_secret_loop(target1, 7)
    loop2 = find_secret_loop(target2, 7)
    print(f"loop1:{loop1} | loop2:{loop2}")
    enc_key1 = apply_secret_loop(loop2, target1)
    enc_key2 = apply_secret_loop(loop1, target2)
    print(f"{enc_key1 == enc_key2} | {enc_key1} - {enc_key2}")

# solution1(5764801, 17807724)
solution1(9717666, 20089533)


import numpy.random as random
import numpy as np
import matplotlib
matplotlib.use('pdf') # required to compile on MCS over SSH
import matplotlib.pyplot as plt
import time

s = np.pi / 8

def integrand(input):
    return np.sin(np.sum(input)) * 10 ** 6

def estimate_average_f(N):
    # Uses Monte-Carlo routine to randomly sample f
    # Initiate pythonic list to store sampled values of the integrand, more efficient than np array here.
    f_list = []
    for i in range(N):
        # initiate 1D array of random values in range [0,s]
        inputs = random.rand(8) * s
        f = integrand(inputs)
        f_list.append(f)

    # Convert f_list to numpy array f_array for vectorisation
    f_array = np.array(f_list)
    f_squared_array = f_array ** 2
    average_f = (1 / N) * np.sum(f_array)
    average_f_squared = (1 / N) * np.sum(f_squared_array)
    return average_f, average_f_squared

def plot_errors(results_list):
    # Plot a graph of sampled error against N
    Ns = [dic.get("N") for dic in results_list]
    errors = [dic.get("sampled_error") for dic in results_list]
    fig, ax1 = plt.subplots()
    ax1.set_yscale("log")
    ax1.set_xscale("log")
    ax1.set_ylabel("log(Sampled Error /No Units)")
    ax1.set_xlabel("log(N /No Units)")
    ax1.set_title("Plot of sampled error against N")
    ax1.plot(Ns, errors, label="Sampled error")

    # Calculate normalisation value to match expected relationship to results
    normalisation_k = errors[0] / Ns[0] ** -0.5
    ax1.plot(Ns, normalisation_k * np.power(Ns, -1 / 2), label="Theoretical relationship", linestyle="dashed")
    ax1.legend()
    plt.savefig("core_one_error_plot.pdf")

def plot_theoretical_error(results_list):
    Ns = [dic.get("N") for dic in results_list]
    errors = [dic.get("sampled_error") for dic in results_list]
    theoretical_errors = [dic.get("theoretical_error") for dic in results_list]
    fig, ax1 = plt.subplots()
    ax1.set_ylabel("Error /No Units")
    ax1.set_xlabel("N /No Units")
    ax1.plot(Ns, theoretical_errors, label="Theoretical error")
    ax1.plot(Ns, errors, label="Sampled error")
    ax1.set_title("Plot of theoretical and sampled error against N")
    ax1.legend()
    plt.savefig("supplementary_one_plot.pdf")

def main_loop(N_list, N_t=25):
    # Estimates the integral using Monte-Carlo techniques, by taking N samples, and repeating this process n_t times. This process is applied to each value N in N_list
    results_list = []
    volume = s ** 8

    for N in N_list:
        estimates_list = []
        theoretical_error_list = []
        for i in range(N_t):
            average_f, average_f_squared = estimate_average_f(N)
            estimate = average_f * volume
            theoretical_error = volume * ((average_f_squared - average_f ** 2) / N) ** (1 / 2)
            theoretical_error_list.append(theoretical_error)
            estimates_list.append(estimate)
        estimates_array = np.array(estimates_list)
        mean = np.mean(estimates_array)
        theoretical_error_mean = np.mean(theoretical_error_list)

        # RMS error in mean, from estimates
        sampled_error = np.std(estimates_array)
        results_list.append(
            {"N": N, "mean": mean, "sampled_error": sampled_error, "theoretical_error": theoretical_error_mean})
    return results_list

if __name__ == "__main__":
    N_list = np.arange(10, 400, 4, dtype=int).tolist()

    # Prove N^(-1/2) relationship
    print("Beginning error calculation.")
    results_list = main_loop(N_list, N_t=25)
    plot_errors(results_list)

    # Supplementary task one
    plot_theoretical_error(results_list)
    print("Finished error calculation.")

    # Estimate integral for N=20000, n_t=25
    N = 20000
    print(f"Estimating integral for N={N}.")
    t_start = time.time()
    results_list = main_loop([N], N_t=25)
    estimated_value = results_list[0].get("mean")
    sampled_error = results_list[0].get("sampled_error")
    print(
        f"Integral estimated to be {estimated_value} +/- {sampled_error} for N={N} in {round(time.time()-t_start, 3)}s.")


"""main URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.9/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin

from django.contrib.auth import views as auth_views
import app.views as app_views

from channels.routing import route

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', app_views.index),
    url(r'^login/$', auth_views.login, {'template_name': 'login.html'}),
    url(r'^logout/$', auth_views.logout, {'template_name': 'logout.html'}),
    url(r'^home/$', app_views.home),
    url(r'^uploads/$', app_views.uploads),
    url(r'^downloads/$', app_views.downloads),
]

channel_routing = [
    route("websocket.connect", app_views.ws_connect),
    route("websocket.receive", app_views.ws_receive),
    route("websocket.disconnect", app_views.ws_disconnect),
]


import torch
import cv2
import numpy as np
import time
import audio

def yolo():
    # Model
    model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True)

    start_time = time.time()

    audio.say('I CAN SEE A...')

    lst = []
    cap = cv2.VideoCapture(0)
    while time.time() - start_time < 25:
        ret, frame = cap.read()

        # Make detections
        results = model(frame)
        cv2.imshow('YOLO', np.squeeze(results.render()))

        df = results.pandas().xyxy[0]

        for i in df['name']:
            if i not in lst:
                lst.append(i)
                new_label = i
                time.sleep(2)
                confidence = df[df['name'] == new_label]['confidence'].max().item()

                print(new_label)

                if confidence >= 0.35:
                    # Determine direction based on object's bounding box center
                    bbox_center_x = (df[df['name'] == new_label]['xmax'].iloc[0] + df[df['name'] == new_label]['xmin'].iloc[0]) / 2
                    bbox_center_y = (df[df['name'] == new_label]['ymax'].iloc[0] + df[df['name'] == new_label]['ymin'].iloc[0]) / 2
                    frame_center_x = frame.shape[1] / 2
                    frame_center_y = frame.shape[0] / 2

                    if bbox_center_x > frame_center_x:
                        direction_x = "to your right"
                    else:
                        direction_x = "to your left"

                    if bbox_center_y < frame_center_y: # Flip the comparison for vertical direction
                        direction_y = "above you" # Flip the direction description
                    else:
                        direction_y = "below you" # Flip the direction description

                    words = f'{new_label} {direction_x} {direction_y}'

                    print(words)
                    audio.say(words)

    cap.release()

    cv2.destroyAllWindows()


from typing import List

from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session

from . import crud, models, schemas
from .database import SessionLocal, engine

models.Base.metadata.create_all(bind=engine)

app = FastAPI()

# Dependency
def get_db():
    try:
        db = SessionLocal()
        yield db
    finally:
        db.close()

users_micro = [
{
"referral_link": "test1",
"credits": 10,
"administrator": 1,
"referraled_id": None,
"id": 1
},
{
"referral_link": "test2",
"credits": 20,
"administrator": 0,
"referraled_id": 1,
"id": 2
},
{
"referral_link": "test3",
"credits": 0,
"administrator": 0,
"referraled_id": None,
"id": 42
},
{
"referral_link": "test4",
"credits": 20,
"administrator": 0,
"referraled_id": None,
"id": 43
},
{
"referral_link": "test5",
"credits": 20,
"administrator": 0,
"referraled_id": None,
"id": 44
}
]

def get_user(user_id, db):
    db_user = crud.get_user(db=db, user_id=user_id)
    if db_user is None:
        db_user = [x for x in users_micro if x['id'] == user_id][0]
        print(db_user)
        if db_user is None:
            raise HTTPException(status_code=404, detail="User not found")
        crud.create_user(db=db, user_id=db_user['id'], administrator=db_user['administrator'],
                         referraled_id=db_user['referraled_id'])
    db_user = crud.get_user(db=db, user_id=user_id)
    return db_user

@app.get("/plans")
def read_plans(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    plans = crud.get_plans(db, skip=skip, limit=limit)
    return plans

@app.post("/plans", response_model=schemas.Plan)
def create_plan(plan: schemas.PlanBase, db: Session = Depends(get_db)):
    db_plan = crud.get_plan_by_name(db, plan_name=plan.name)
    if db_plan:
        raise HTTPException(status_code=400, detail="Plan already exists")
    return crud.create_plan(db=db, plan=plan)

@app.get("/plans/name/{plan_name}", response_model=schemas.Plan)
def get_plan_by_name(plan_name: str, db: Session = Depends(get_db)):
    db_plan = crud.get_plan_by_name(db, plan_name=plan_name)
    if db_plan is None:
        raise HTTPException(status_code=400, detail="Plan doesn't exists")
    return db_plan

@app.get("/plans/id/{plan_id}", response_model=schemas.Plan)
def get_plan_by_name(plan_id: int, db: Session = Depends(get_db)):
    db_plan = crud.get_plan_by_id(db, plan_id=plan_id)
    if db_plan is None:
        raise HTTPException(status_code=400, detail="Plan doesn't exists")
    return db_plan

@app.get("/users/", response_model=List[schemas.User])
def get_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    users = crud.get_users(db, skip=skip, limit=limit)
    return users

@app.get("/users/{user_id}", response_model=schemas.User)
def get_user(user_id: int, db: Session = Depends(get_db)):
    db_user = crud.get_user(db, user_id=user_id)
    if db_user is None:
        raise HTTPException(status_code=404, detail="User not found")
    return db_user

@app.get("/vouchers", response_model=List[schemas.Voucher])
def get_vouchers(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    vouchers = crud.get_vouchers(db, skip=skip, limit=limit)
    return vouchers

@app.post("/vouchers", response_model=schemas.Voucher)
def create_voucher(voucher: schemas.VoucherBase, db: Session = Depends(get_db)):
    return crud.create_voucher(db=db, voucher=voucher)

@app.post("/vouchers/{num_codes}", response_model=List[schemas.Voucher])
def create_vouchers(num_codes: int, voucher: schemas.VoucherBase, db: Session = Depends(get_db)):
    vouchers = []
    for i in range(num_codes):
        vouchers.append(crud.create_voucher(db=db, voucher=voucher))
    return vouchers

@app.post("/{user_id}/{voucher_code}")
def add_credits_to_user(user_id: int, voucher_code: str, db: Session = Depends(get_db)):
    db_voucher = crud.verify_voucher(db=db, voucher_code=voucher_code)
    if db_voucher is None:
        raise HTTPException(status_code=404, detail="Voucher not found")
    if db_voucher.is_used == 1:
        raise HTTPException(status_code=404, detail="Voucher is already used")
    db_user = get_user(user_id, db)
    crud.add_credits_to_user(db=db, user_id=user_id, credits=db_voucher.amount)
    crud.used_voucher(db=db, voucher_code=voucher_code, user_id=user_id)
    return {"name": "successful"}

@app.get("/referral_link/{user_id}")
def get_referral(user_id: int, db: Session = Depends(get_db)):
    db_user = get_user(user_id, db)
    return db_user.referral_link

@app.post("/promo_codes", response_model=schemas.PromoCode)
def create_promo_code(promo_code: schemas.PromoCodeBase, db: Session = Depends(get_db)):
    return crud.create_promo_code(db=db, promo_code=promo_code)

@app.post("/promo_codes/{nums}", response_model=List[schemas.PromoCode])
def create_promo_codes(nums: int, promo_code: schemas.PromoCodeBase, db: Session = Depends(get_db)):
    promo_codes = []
    print(nums)
    print(10)
    for i in range(nums):
        promo_codes.append(crud.create_promo_code(db=db, promo_code=promo_code))
    return promo_codes

@app.post("/promo_codes10", response_model=List[schemas.PromoCode])
def create_promo_codes(promo_code: schemas.PromoCodeBase, db: Session = Depends(get_db)):
    promo_codes = []
    # print(num)
    for i in range(10):
        promo_codes.append(crud.create_promo_code(db=db, promo_code=promo_code))
    return promo_codes

@app.get("/promo_codes", response_model=List[schemas.PromoCode])
def get_promo_codes(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    return crud.get_promo_codes(db=db, skip=skip, limit=limit)

@app.get("/promo_codes/id/{promo_code_id}", response_model=schemas.PromoCode)
def get_promo_code_by_id(promo_code_id: int, db: Session = Depends(get_db)):
    db_promo_code = crud.get_promo_code_by_id(db=db, promo_code_id=promo_code_id)
    if db_promo_code is None:
        raise HTTPException(status_code=400, detail="Promocode doesn't exists")
    return db_promo_code

@app.get("/promo_codes/name/{promo_code_code}", response_model=schemas.PromoCode)
def get_promo_code_by_code(promo_code_code: str, db: Session = Depends(get_db)):
    db_promo_code = crud.get_promo_code_by_code(db=db, promo_code_code=promo_code_code)
    if db_promo_code is None:
        raise HTTPException(status_code=400, detail="Promocode doesn't exists")
    return db_promo_code

@app.post("/successfulpayment")
def successful_payment(successful: schemas.SuccessfulPayment, db: Session = Depends(get_db)):
    db_user = get_user(successful.user_id, db)
    if(db_user.referraled_id != None):
        db_referraled_user = crud.get_user(db, db_user.referraled_id)
        crud.add_credits_to_user(db, db_referraled_user.id, successful.amount * 0.1)
    crud.add_credits_to_user(db, db_user.id, successful.credits * (-1))
    db_promo_code = crud.get_promo_code_by_code(db, successful.promo_code)
    if(db_promo_code != None):
        crud.used_promo_code(db, db_promo_code.code, db_user.id)
    return {"successful": "payment"}


"""Exceptions raised by the qdvc."""

class QdvcException(Exception):
    """Base class for all dvc exceptions."""

    def __init__(self, msg, *args):
        assert msg
        self.msg = msg
        super().__init__(msg, *args)

class NotQdvcRepoError(QdvcException):
    """Thrown if a directory is not a QDVC repo"""


import streamlit as st
from PIL import Image
import ultralytics
from ultralytics import YOLO

st.title('Aloe Vera Plant Disease Analyser')

col1,col2=st.columns(2)
upload_stat=0
with col1:

    input_image=st.file_uploader('Upload The Image File Here',type=['jpg','png'])

    confirmation=st.button('Submit')
    if confirmation==True:
        st.image(input_image)
        upload_stat=1

with col2:
    st.subheader('Detection:')
    if upload_stat==1:
        image_new=Image.open(input_image)
        model=YOLO('best_new_v2.pt')
        results= model(image_new)

        for r in results:
            im_array = r.plot()  # plot a BGR numpy array of predictions
            im = Image.fromarray(im_array[..., ::-1])  # RGB PIL image
            st.image(im)  # show image


"""Metadata scraper for AV files."""
from __future__ import unicode_literals

import re
import six

from file_scraper.base import BaseMeta
from file_scraper.defaults import UNAP, UNAV
from file_scraper.exceptions import SkipElementException
import file_scraper.mediainfo
from file_scraper.utils import iso8601_duration, strip_zeros, metadata

class BaseMediainfoMeta(BaseMeta):
    # pylint: disable=too-many-public-methods
    """Metadata models for streams scraped using MediainfoScraper."""

    def __init__(self, tracks, index):
        """
        Initialize the metadata model.

        :tracks: list of all tracks in the file
        :index: index of the track represented by this metadata model
        """
        self._stream = tracks[index]
        self._tracks = tracks
        self._track_index = index

        # Find out if file is a video container
        if len(self._tracks) > 2 or tracks[0].format != tracks[1].format:
            self._container = tracks[0]
        else:
            self._container = None

    @metadata()
    def mimetype(self):
        """Return mimetype for stream."""
        return file_scraper.mediainfo.track_mimetype(self._stream) or UNAV

    @metadata()
    def version(self):
        """Return version of stream."""
        if self._stream.format_version is not None:
            return self._stream.format_version.replace("Version ", "")
        return UNAV

    @metadata()
    def stream_type(self):
        """Return stream type."""
        if self._container and self._stream == self._container:
            return "videocontainer"

        if self._stream.track_type == "Audio":
            return 'audio'

        if self._stream.track_type == "Video":
            return 'video'

        # For example "General" tracks are not streams, unless they are
        # videocontainers
        return None

    @metadata()
    def index(self):
        """Return stream index."""
        if self._container:
            return self._track_index

        # Since file is not a container, the first track is not a
        # stream. It is just general information that is skipped.
        return self._track_index - 1

    @metadata()
    def color(self):
        """
        Return color information.

        Only values from fixed list are allowed. Must be resolved, if
        returns None.
        """
        if self.stream_type() not in ["video"]:
            raise SkipElementException()
        if self._stream.color_space is not None:
            if self._stream.color_space in ["RGB", "YUV"]:
                return "Color"
            if self._stream.color_space in ["Y"]:
                return "Grayscale"
        if self._stream.chroma_subsampling is not None:
            return "Color"
        return UNAV

    @metadata()
    def signal_format(self):
        """Return signal format."""
        if self.stream_type() not in ["video"]:
            raise SkipElementException()
        if self._stream.standard is not None:
            return self._stream.standard

        return UNAV

    @metadata()
    def width(self):
        """Return frame width."""
        if self.stream_type() not in ["video"]:
            raise SkipElementException()
        if self._stream.width is not None:
            return six.text_type(self._stream.width)
        return UNAV

    @metadata()
    def height(self):
        """Return frame height."""
        if self.stream_type() not in ["video"]:
            raise SkipElementException()
        if self._stream.height is not None:
            return six.text_type(self._stream.height)
        return UNAV

    @metadata()
    def par(self):
        """Return pixel aspect ratio."""
        if self.stream_type() not in ["video"]:
            raise SkipElementException()
        if self._stream.pixel_aspect_ratio is not None:
            return strip_zeros(six.text_type(self._stream.pixel_aspect_ratio))
        return UNAV

    @metadata()
    def dar(self):
        """Return display aspect ratio."""
        if self.stream_type() not in ["video"]:
            raise SkipElementException()
        if self._stream.display_aspect_ratio is not None:
            return strip_zeros(six.text_type(
                self._stream.display_aspect_ratio))
        return UNAV

    @metadata()
    def data_rate(self):
        """Return data rate (bit rate)."""
        if self.stream_type() not in ["video", "audio"]:
            raise SkipElementException()
        if self._stream.bit_rate is not None:
            if self._stream.track_type == "Video":
                return strip_zeros(six.text_type(float(
                    self._stream.bit_rate) / 1000000))
            return strip_zeros(six.text_type(float(
                self._stream.bit_rate)/1000))
        return UNAV

    @metadata()
    def frame_rate(self):
        """Return frame rate."""
        if self.stream_type() not in ["video"]:
            raise SkipElementException()
        if self._stream.frame_rate is not None:
            return strip_zeros(six.text_type(self._stream.frame_rate))
        return UNAV

    @metadata()
    def sampling(self):
        """Return chroma subsampling method."""
        if self.stream_type() not in ["video"]:
            raise SkipElementException()
        if self._stream.chroma_subsampling is not None:
            return self._stream.chroma_subsampling
        return UNAV

    @metadata()
    def sound(self):
        """Return "Yes" if sound channels are present, otherwise "No"."""
        if self.stream_type() not in ["video"]:
            raise SkipElementException()
        if (self._tracks[0].count_of_audio_streams is not None and
                int(self._tracks[0].count_of_audio_streams) > 0):
            return "Yes"
        if (self._tracks[0].audio_count is not None and
                int(self._tracks[0].audio_count) > 0):
            return "Yes"
        return "No"

    @metadata()
    def codec_quality(self):
        """
        Return codec quality.

        Must be resolved, if returns None. Only values "lossy" or
        "lossless" are allowed.
        """
        if self.stream_type() not in ["video", "audio"]:
            raise SkipElementException()
        if self._stream.compression_mode is not None:
            return self._stream.compression_mode.lower()
        return UNAV

    @metadata()
    def data_rate_mode(self):
        """
        Return data rate mode.

        Must be resolved, if returns None. The allowed values are
        "Fixed" and "Variable".
        """
        if self.stream_type() not in ["video", "audio"]:
            raise SkipElementException()
        if self._stream.bit_rate_mode == "CBR":
            return "Fixed"
        if self._stream.bit_rate_mode is not None:
            return "Variable"
        return UNAV

    @metadata()
    def audio_data_encoding(self):
        """Return audio data encoding."""
        if self.stream_type() not in ["audio"]:
            raise SkipElementException()
        if self._stream.format is not None:
            return six.text_type(self._stream.format)
        return UNAV

    @metadata()
    def sampling_frequency(self):
        """Return sampling frequency."""
        if self.stream_type() not in ["audio"]:
            raise SkipElementException()
        if self._stream.sampling_rate is not None:
            return strip_zeros(six.text_type(float(
                self._stream.sampling_rate)/1000))
        return UNAV

    @metadata()
    def num_channels(self):
        """Return number of channels."""
        if self.stream_type() not in ["audio"]:
            raise SkipElementException()
        if self._stream.channel_s is not None:
            return six.text_type(self._stream.channel_s)
        return UNAV

    @metadata()
    def codec_creator_app(self):
        """Return creator application."""
        if self.stream_type() not in ["video", "audio", "videocontainer"]:
            raise SkipElementException()
        if self._tracks[0].writing_application is not None:
            return self._tracks[0].writing_application
        return UNAV

    @metadata()
    def codec_creator_app_version(self):
        """Return creator application version."""
        if self.stream_type() not in ["video", "audio", "videocontainer"]:
            raise SkipElementException()
        if self._tracks[0].writing_application is not None:
            reg = re.search(r"([\d.]+)$",
                            self._tracks[0].writing_application)
            if reg is not None:
                return reg.group(1)
        return UNAV

    @metadata()
    def codec_name(self):
        """Return codec name."""
        if self.stream_type() not in ["video", "audio", "videocontainer"]:
            raise SkipElementException()
        if self._stream.format is not None:
            return self._stream.format
        return UNAV

    @metadata()
    def duration(self):
        """Return duration."""
        if self.stream_type() not in ["video", "audio"]:
            raise SkipElementException()
        if self._stream.duration is not None:
            return iso8601_duration(float(
                self._stream.duration) / 1000)
        return UNAV

    @metadata()
    def bits_per_sample(self):
        """Return bits per sample."""
        if self.stream_type() not in ["video", "audio"]:
            raise SkipElementException()
        if self._stream.bit_depth is not None:
            return six.text_type(self._stream.bit_depth)
        return UNAV

class ContainerMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for container streams."""

    _supported = {"video/quicktime": [""],
                  "video/MP1S": [""],
                  "video/MP2P": [""],
                  "video/MP2T": [""],
                  "video/avi": [""],
                  "video/x-ms-asf": [""]}
    _allow_versions = True  # Allow any version

    @metadata()
    def version(self):
        """Return version of stream.

        Container streams do not have version, and therefore the result
        is unapplicable (:unap).
        """
        return UNAP

class MkvMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for Matroska AV container."""

    _supported = {"video/x-matroska": ["4"]}
    _allow_versions = True  # Allow any version

    @metadata()
    def version(self):
        """Return version of stream."""
        version = super(MkvMediainfoMeta, self).version()
        if isinstance(version, six.text_type):
            version = version.split(".")[0]
        return version

class FfvMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for FF Video Codec 1."""

    _supported = {"video/x-ffv": [""]}
    _allow_versions = True  # Allow any version

    @metadata()
    def signal_format(self):
        """Return signal format."""
        return UNAP

    @metadata()
    def version(self):
        """Return version of stream."""
        version = super(FfvMediainfoMeta, self).version()
        if isinstance(version, six.text_type):
            version = version.split(".")[0]
        return version

class DvMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for Digital Video."""

    _supported = {"video/dv": [""]}
    _allow_versions = True  # Allow any version

    @metadata()
    def version(self):
        """Return version of stream.

        DV streams do not have version, and therefore the result is
        unapplicable (:unap).
        """
        return UNAP

class LpcmMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for Linear Pulse-Code Modulation audio."""

    _supported = {"audio/L8": [""],
                  "audio/L16": [""],
                  "audio/L20": [""],
                  "audio/L24": [""]}
    _allow_versions = True  # Allow any version

    @metadata()
    def version(self):
        """Return version of stream.

        PCM audio streams (i.e. audio/L*) do not have version, and
        therefore the result is unapplicable (:unap).
        """
        return UNAP

    @metadata()
    def codec_quality(self):
        """Return codec quality."""
        if self._stream.compression_mode is not None:
            return self._stream.compression_mode.lower()

        return "lossless"

class AiffMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for AIFF audio."""

    _supported = {"audio/x-aiff": ["", "1.3"]}
    _allow_versions = True  # Allow any version

    def __init__(self, tracks, index):
        """Initialize the metadata model.

        AIFF is a special container format. For AIFF files, no
        distinction between container and soundtrack needs to be made,
        as both are treated as one in the DPS.
        """
        super(AiffMediainfoMeta, self).__init__(tracks, index)
        self._container = None

    @metadata()
    def mimetype(self):
        """Return mimetype."""
        return 'audio/x-aiff'

    @metadata()
    def codec_name(self):
        """Return codec name.

        The codec name for AIFF-C files is ready from the codec_id
        key. AIFF files should have PCM in the format key.
        """
        if self._stream.codec_id is not None:
            return self._stream.codec_id.lower()

        if self._stream.format is not None:
            return self._stream.format

        return UNAV

    @metadata()
    def codec_quality(self):
        """Return codec quality.

        AIFF-C can contain lossless or lossy compression. We'll set the
        codec quality based on the codec ID.
        """
        if self._stream.compression_mode is not None:
            return self._stream.compression_mode.lower()

        if self._stream.codec_id is not None:
            if self._stream.codec_id not in [
                    "raw", "twos", "swot", "fl32", "fl64", "in24", "in32"]:
                return "lossy"

        return "lossless"

class WmaMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for WMA audio."""

    _supported = {"audio/x-ms-wma": ["9"]}
    _allow_versions = True  # Allow any version

    @metadata()
    def mimetype(self):
        """Return mimetype."""
        return 'audio/x-ms-wma'

    @metadata()
    def version(self):
        """Return version of stream."""
        if any((self._stream.description_of_the_codec is not None and
                self._stream.description_of_the_codec == 'wmav1',
                self._stream.format_version is not None and
                self._stream.format_version == 'Version 1')):
            return "7"
        if any((self._stream.description_of_the_codec is not None and
                self._stream.description_of_the_codec == 'wmav2',
                self._stream.format_version is not None and
                self._stream.format_version == 'Version 2')):
            return "8"
        if any((self._stream.description_of_the_codec is not None and
                self._stream.description_of_the_codec in ['wmav3', 'wmapro'],
                self._stream.format_profile is not None and
                self._stream.format_profile in ['Pro', 'Lossless'])):
            return "9"
        return UNAV

    @metadata()
    def codec_quality(self):
        """Return codec quality.

        Most common WMA codecs are lossy, but some WMA files can use
        the Windows Media Audio Lossless codec.
        """
        if any((self._stream.codec_id_info is not None
                and "Lossless" in self._stream.codec_id_info,
                self._stream.format_profile is not None
                and "Lossless" in self._stream.format_profile)):
            return "lossless"
        return "lossy"

    @metadata()
    def data_rate_mode(self):
        """Return data rate mode.

        WMA supports both fixed and variable bit rates. Variable
        bit rate mode was officially introduced in WMA9.
        """
        mode = super(WmaMediainfoMeta, self).data_rate_mode()
        if mode not in [UNAV, None]:
            return mode

        # Overall data rate mode is reported in the container stream.
        # It can be used if the file contains max. two tracks (General
        # + Audio)
        if len(self._tracks) <= 2:
            if self._tracks[0].overall_bit_rate_mode == "CBR":
                return "Fixed"
            if self._tracks[0].overall_bit_rate_mode is not None:
                return "Variable"
        return UNAV

class WmvMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for WMV video."""

    _supported = {"video/x-ms-wmv": ["9"]}
    _allow_versions = True  # Allow any version

    @metadata()
    def mimetype(self):
        """Return mimetype."""
        return 'video/x-ms-wmv'

    @metadata()
    def version(self):
        """Return version of stream."""
        if self._stream.codec_id is not None and \
                self._stream.codec_id == 'WMV1':
            return "7"
        if self._stream.codec_id is not None and \
                self._stream.codec_id == 'WMV2':
            return "8"
        if self._stream.codec_id is not None and \
                self._stream.codec_id in ['WVC1', 'WMV3', 'WMVA', 'WMVP']:
            return "9"
        return UNAV

    @metadata()
    def codec_quality(self):
        """Return codec quality.

        WMV codecs are lossy codecs.
        """
        return "lossy"

    @metadata()
    def signal_format(self):
        """Return signal format."""
        return UNAP

    @metadata()
    def data_rate_mode(self):
        """Return data rate mode.

        WMV supports both fixed and variable bit rates.
        """
        mode = super(WmvMediainfoMeta, self).data_rate_mode()
        if mode not in [UNAV, None]:
            return mode

        # Overall bit rate mode is reported in the container stream
        # It can be used if the file contains max. two tracks (General
        # + Video)
        if len(self._tracks) <= 2:
            if self._tracks[0].overall_bit_rate_mode == "CBR":
                return "Fixed"
            if self._tracks[0].overall_bit_rate_mode is not None:
                return "Variable"
        return UNAV

    @metadata()
    def color(self):
        """Return color information.

        WMV files are by default based on the YUV 4:2:0 color
        sampling.

        NOTE: FFMpeg can detect the color in the "pix_fmt" metadata.
        However, combining MediaInfo and FFMpeg is difficult and since
        WMV files are by default in color, we can just use it as a
        default value if no other value is found.
        """
        mode = super(WmvMediainfoMeta, self).color()
        if mode not in [UNAV, None]:
            return mode

        return "Color"

class FlacMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for FLAC audio."""

    _supported = {"audio/flac": ["1.2.1"]}
    _allow_versions = True  # Allow any version

    @metadata()
    def version(self):
        """Return version of stream.

        The version number 1.2.1 of FLAC comes from PRONOM registry.
        This is actually the version number of FLAC tools containing
        FLAC format specification. Although the latest FLAC tools
        version is 1.3.3, version 1.2.1 still includes the latest format
        change and was released in 2007. There is no separate version
        numbering in FLAC format itself, and therefore, there is no
        proper way to extract it.
        """
        return "1.2.1"

class WavMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for WAV audio."""

    _supported = {"audio/x-wav": ["2", ""]}
    _allow_versions = True  # Allow any version

    def __init__(self, tracks, index):
        """Initialize the metadata model.

        WAV is a special container format. For WAV files, no
        distinction between container and soundtrack needs to be made,
        as both are treated as one in the DPS.
        """
        super(WavMediainfoMeta, self).__init__(tracks, index)
        self._container = None

    @metadata()
    def mimetype(self):
        """Return mimetype."""
        return 'audio/x-wav'

    @metadata()
    def version(self):
        """Return version."""
        if self._tracks[0].bext_present is not None \
                and self._tracks[0].bext_present == "Yes":
            return "2"
        return UNAP

    @metadata()
    def codec_quality(self):
        """Return codec quality."""
        return "lossless"

class MpegMediainfoMeta(BaseMediainfoMeta):
    """Metadata model for MPEG audio."""

    # Supported mimetypes
    _supported = {"audio/mpeg": ["1", "2"],
                  "audio/mp4": [""],
                  "video/mpeg": ["1", "2"],
                  "video/mp4": [""]}
    _allow_versions = True  # Allow any version

    @metadata()
    def signal_format(self):
        """Return signal format."""
        if self.stream_type() not in ["video"]:
            raise SkipElementException()
        if self._stream.standard is not None:
            return self._stream.standard
        return UNAP

    @metadata()
    def codec_quality(self):
        """Return codec quality."""
        if self._stream.compression_mode is not None:
            return self._stream.compression_mode.lower()
        return "lossy"

    @metadata()
    def data_rate_mode(self):
        """Return data rate mode.

        MP4 is assumed to always have variable bit rate, based on e.g.
        https://slhck.info/video/2017/03/01/rate-control.html claiming
        that MP4 does not support NAL stuffing and thus it cannot be
        forced to have constant bit rate.
        """
        mode = super(MpegMediainfoMeta, self).data_rate_mode()
        if mode not in [UNAV, None]:
            return mode
        if self._stream.bit_rate_mode == "CBR":
            return "Fixed"
        return "Variable"

    @metadata()
    def version(self):
        """Return version of stream.

        MP4 streams do not have version, and and therefore the result is
        unapplicable (:unap).

        MP3 "container" does not know the version, so it has to be
        checked from the first stream.
        """
        if self.mimetype() in ["audio/mp4", "video/mp4"]:
            return UNAP

        if (self.mimetype() == "audio/mpeg" and
                self._stream.track_type == "General" and
                len(self._tracks) >= 2):
            return six.text_type(self._tracks[1].format_version)[-1]

        if self._stream.format_version is not None:
            return six.text_type(self._stream.format_version)[-1]
        return UNAV

class VersionlessFormatMeta(BaseMediainfoMeta):
    """Generic metadata model for stream formats, which do not have a version.
    """

    _supported = {"video/x.fi-dpres.prores": [""]}
    _allow_versions = True  # Allow any version

    @metadata()
    def version(self):
        """Return version of stream.

        Result is always unapplicable (:unap), because these formats do not
        have a version.
        """
        return UNAP

class UnknownStreamFormatMeta(BaseMediainfoMeta):
    """Metadata model for streams that were not detected."""

    _supported = {None: [""]}
    _allow_versions = True  # Allow any version


# 이항분류는 뭐야? 시그모이드
# diabetes 데이터로 이항분류(sigmoid)와 다항분류(softmax)처리

from keras.models import Sequential
from keras.layers import Dense
import numpy as np

dataset=np.loadtxt("../testdata/diabetes.csv", delimiter=',')
# print(dataset[:1])
# print(dataset.shape) #(759, 9)
# print(dataset[:,-1])  #label 값 확인해보니, 0,1로 되어있다. 손을 댈 필요가 읎어요

from sklearn.model_selection import train_test_split
# 0~8열, 9열
x_train, x_test, y_train, y_test=train_test_split(dataset[:,0:8], dataset[:,-1], test_size=0.3, random_state=123)
print(x_train.shape, x_test.shape, y_train.shape, y_test.shape) #(531, 8) (228, 8) (531,) (228,)

#===============================================================================
# # 이항분류 sigmoid / binary_crossentropy / 이항분류는 label을 0~1 사이의 값
#===============================================================================
model=Sequential()
model.add(Dense(units=64, input_dim=8, activation='relu'))
model.add(Dense(units=32, activation='relu'))
model.add(Dense(units=1, activation='sigmoid'))

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) # 이항분류일 때 loss는 binary_crossentropy를 쓴다.
model.fit(x_train, y_train, epochs=100, batch_size=32, validation_split=0.2, verbose=0)
scores=model.evaluate(x_test, y_test) #마지막값만 볼까?
print('%s : %.2f'%(model.metrics_names[0], scores[0]))
print('%s : %.2f'%(model.metrics_names[1], scores[1]))

# 예측값 구하기
# print(x_train[0])
new_data=[[-0.0588235,0.20603,0.,0.,0.,-0.105812,-0.910333,-0.433333]]
pred=model.predict(new_data, batch_size=32, verbose=0)
print('sigmoid 예측결과: ',pred)
print('sigmoid 예측결과: ',np.where(pred>0.5,1,0))
# [[0.4277862]] 0.5를 기준으로 0과1을 분류

#===============================================================================
# # 다항분류 #softmax /categorical_crossentropy'
# 레이블의 개수만큼 확률값으로 나온다.
# 다항분류일떄는 반드시 레이블에 대해 onehot처리를 해줘야한다.
#===============================================================================
# 다항분류 softmax
print(y_train[:3]) # onehot처리가 필요
from keras.utils import to_categorical #sklearn 에 onehot 사용가능

y_train=to_categorical(y_train)
y_test=to_categorical(y_test)
print(y_train[:3])

model2=Sequential()
model2.add(Dense(units=64, input_dim=8, activation='relu'))
model2.add(Dense(units=32, activation='relu'))
model2.add(Dense(units=2, activation='softmax'))
# label의 category 수 만큼 결과는 확률 값으로 출력된다

model2.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # 이항분류일 때 loss는 binary_crossentropy를 쓴다.
model2.fit(x_train, y_train, epochs=100, batch_size=32, validation_split=0.2, verbose=0)
scores2=model2.evaluate(x_test, y_test) #마지막값만 볼까?
print('%s : %.2f'%(model2.metrics_names[0], scores2[0]))
print('%s : %.2f'%(model2.metrics_names[1], scores2[1]))

new_data2=[[-0.0588235,0.20603,0.,0.,0.,-0.105812,-0.910333,-0.433333]]
pred2=model2.predict(new_data2, batch_size=32, verbose=0)
print('softmax 예측결과: ',pred2)
#softmax 예측결과:  [[0.6369634  0.36303654]]
# 확률값이 가장 큰 지점의 index를 분류 결과로 취한다.
print('softmax 예측결과: ',np.argmax(pred2))


"""
Given a sorted array of distinct integers and a target value, return the index if the
target is found. If not, return the index where it would be if it were inserted in order.

You must write an algorithm with O(log n) runtime complexity.

Example 1:

Input: nums = [1,3,5,6], target = 5
Output: 2
Example 2:

Input: nums = [1,3,5,6], target = 2
Output: 1
Example 3:

Input: nums = [1,3,5,6], target = 7
Output: 4

Constraints:

1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums contains distinct values sorted in ascending order.
-104 <= target <= 104
"""
from typing import List

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        nums.sort()
        i = 0
        for n in nums:
            if n == target:
                return i
            elif n > target:
                return i
            i += 1
        return i

def main():
    nums = [1, 3, 5, 6]
    target = 5
    print(Solution().searchInsert(nums, target))
    nums = [1, 3, 5, 6]
    target = 2
    print(Solution().searchInsert(nums, target))
    nums = [1, 3, 5, 6]
    target = 7
    print(Solution().searchInsert(nums, target))
    nums = [1, 3, 5, 6]
    target = 0
    print(Solution().searchInsert(nums, target))
    nums = [-1, -3, -5, -6]
    target = -4
    print(Solution().searchInsert(nums, target))

if __name__ == '__main__':
    main()


# Задача 107 Создайте программу для игры в ""Крестики-нолики"" (Добавьте игру против бота)
# Инициализация карты
from random import randint
pole = [7, 8, 9,
        4, 5, 6,
        1, 2, 3]

# Инициализация победных линий
victories = [[0, 1, 2],
             [3, 4, 5],
             [6, 7, 8],
             [0, 3, 6],
             [1, 4, 7],
             [2, 5, 8],
             [0, 4, 8],
             [2, 4, 6]]

# Вывод карты на экран
def print_pole():
    print(f'╔═══╦═══╦═══╗')
    print(f'║ {pole[0]}', end=" ")
    print(f'║ {pole[1]} ║', end=" ")
    print(f'{pole[2]} ║')
    print(f'╠═══╬═══╬═══╣')
    print(f'║ {pole[3]}', end=" ")
    print(f'║ {pole[4]} ║', end=" ")
    print(f'{pole[5]} ║')
    print(f'╠═══╬═══╬═══╣')
    print(f'║ {pole[6]}', end=" ")
    print(f'║ {pole[7]} ║', end=" ")
    print(f'{pole[8]} ║')
    print(f'╚═══╩═══╩═══╝\n')

# Сделать ход в ячейку
def step_pole(step, symbol):
    ind = pole.index(step)
    pole[ind] = symbol

# Получить текущий результат игры
def get_result():
    win = ""
    for i in victories:
        if pole[i[0]] == "X" and pole[i[1]] == "X" and pole[i[2]] == "X":
            win = "X"
        if pole[i[0]] == "O" and pole[i[1]] == "O" and pole[i[2]] == "O":
            win = "O"

    return win

# Поиск линии с нужным количеством X и O на победных линиях
def check_line(sum_O, sum_X):

    step = ""
    for line in victories:
        o = 0
        x = 0

        for j in range(0, 3):
            if pole[line[j]] == "O":
                o = o + 1
            if pole[line[j]] == "X":
                x = x + 1

        if o == sum_O and x == sum_X:
            for j in range(0, 3):
                if pole[line[j]] != "O" and pole[line[j]] != "X":
                    step = pole[line[j]]
    return step

# Искусственный интеллект: выбор хода
def AI(side_0):
    # сжалится компьютер или нет зависит от удачи
    luck = randint(0, 2)
    step = ""
    if side_0 == 1:
        step = check_line(0, 2)
        # если на какой либо из победных линий 2 чужие фигуры и 0 своих - ставим
        if step == "" and luck != 1:
            step = check_line(2, 0)
        # если 1 фигура своя и 0 чужих - ставим
        if step == "":
            step = check_line(0, 1)
        # центр пуст, то занимаем центр
        if step == "":
            if pole[4] != "X" and pole[4] != "O" and luck != 1:
                step = 5
        # если центр занят, то занимаем ячейку
        if step == "":
            for i in range(10):
                if pole[i] != "X" and pole[i] != "O":
                    step = i+1
                    break
    else:
        step = check_line(2, 0)
        # если на какой либо из победных линий 2 чужие фигуры и 0 своих - ставим
        if step == "" and luck != 1:
            step = check_line(0, 2)
        # если 1 фигура своя и 0 чужих - ставим
        if step == "":
            step = check_line(1, 0)
        # центр пуст, то занимаем центр
        if step == "":
            if pole[4] != "X" and pole[4] != "O"  and luck != 1:
                step = 5
        # если центр занят, то занимаем ячейку
        if step == "":
            for i in range(9):
                if pole[i] != "X" and pole[i] != "O":
                    step = i+1
                    break

    return step

# Основная программа
game_over = False
side = input(f"За кого играете введите х или 0??\n").lower()
if side == 0 or side == '0' or side == 'o' or side == 'о':
    side_0 = 1
    human = False
else:
    side_0 = 0
    human = True

shag = 0
while game_over == False:
    print_pole()

    if human == True:
        if side_0 == 1:
            symbol = "O"
        else:
            symbol = "X"
        step = int(input("Человек, ваш ход: "))
    else:
        print("Компьютер делает ход: ")
        if side_0 == 1:
            symbol = "X"
        else:
            symbol = "O"
        step = AI(side_0)
    shag +=1
    # Если компьютер нашел куда сделать ход, то играем. Если нет, то ничья.
    print(shag)
    if shag != 9:
        if step != "":
            step_pole(step, symbol)  # делаем ход в указанную ячейку
            win = get_result()  # определим победителя
            if win != "":
                game_over = True
            else:
                game_over = False

    else:
        print("Ничья!")
        game_over = True
        win = "дружба"

    human = not (human)

# Игра окончена. Покажем карту. Объявим победителя.
print_pole()
print("Победил", win)


import socket
import threading
import struct
import json
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
IS_ALL_GROUPS = True
MULTICAST_TTL = 2
name = input("Ingresa tu nombre: ")
def sendMessage(sock,message,action):
    message = json.dumps({"user":name,"text":message,"action":action}).encode()
    sock.sendto(message, (MCAST_GRP, MCAST_PORT))
def sender():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
    sendMessage(sock,"","join")
    while True:
        texto = input(">")
        sendMessage(sock,texto,"message")

def processAction(message):
    if message["action"] == "message":
        print("%s:%s\n>"%(message["user"],message["text"]),end="")
    elif message["action"] == "join":
        print("El usuario %s se ha unido!\n>"%(message["user"]),end="")
def listener():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    if IS_ALL_GROUPS:
        # on this port, receives ALL multicast groups
        sock.bind(('', MCAST_PORT))
    else:
        # on this port, listen ONLY to MCAST_GRP
        sock.bind((MCAST_GRP, MCAST_PORT))
    mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)

    sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

    while True:
        data = sock.recv(10240)
        data = json.loads(data.decode())
        if data["user"] == name:
            pass
        else:
            processAction(data)

threadlist = []
threadlist.append(threading.Thread(target=listener))
threadlist.append(threading.Thread(target=sender))
for t in threadlist:
    t.start()


import torch
import json

def tokensByDevice(device, token, isBase, debug=False, showTokens=False):
    if debug and showTokens:
        print(
            f'{"Tokenising prompt" if isBase else "Inferencing"} using ({device})... Tokens:',
            token,
        )
    elif debug:
        print(f'{"Tokenising prompt" if isBase else "Inferencing"} using ({device})...')
    if device == "cuda":
        if isBase:
            result = torch.as_tensor([token]).cuda()
        else:
            result = torch.as_tensor([[token]], device="cuda")
    elif device == "cpu-gptq":
        if isBase:
            result = token
        else:
            result = torch.as_tensor([[token]])
    elif device == "cpu":
        if isBase:
            result = torch.as_tensor([token])
        else:
            result = torch.as_tensor([[token]])
    if debug:
        print("tokenised result", result)
    return result

class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKCYAN = '\033[96m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

bc = bcolors.OKGREEN
tc = bcolors.WARNING
th = bcolors.OKBLUE
vs = "│"

def printDictAsTable(dict, title="Table output:", headers = ["Key", "Value"]):
    table = ""
    maxKeyWidth = max(len(str(key)) for key in dict.keys())
    maxValueWidth = max(len(str(value)) for value in dict.values())
    if maxValueWidth < 8:
        maxValueWidth = 8
    tableHeaders = bc + vs + " " + th +  "   ".join(cell.ljust(maxKeyWidth if cell == headers[0] else maxValueWidth) for cell in headers) + bc + vs + "\n"
    for key, value in dict.items():
        table += bc + vs + " " + tc + f" {vs} ".join(str(cell).ljust(maxKeyWidth if cell == key else maxValueWidth) for cell in [key, value]) + bc + vs + "\n"
    tableWidth = maxKeyWidth + maxValueWidth + 4
    border = ""
    spacer = ""
    for i in range(tableWidth):
        spacer += " "
        border += "─"
    table = bc + "┌" + border + "┐\n" + vs + tc + (" " + title).ljust(tableWidth) + bc + vs + "\n" + vs + spacer + vs + "\n" + tableHeaders + table + "└" + border + "┘" + bcolors.ENDC
    print(table)

def processConvo(convo, humanRole, aiRole):
    try:
        convHistoryList = json.loads(convo)
    except json.JSONDecodeError:
        return "Invalid conversationHistory JSON"

    if not isinstance(convHistoryList, list):
        return 'conversationHistory JSON structure must be an array of arrays, eg. [["Human","How do magnets work?"],["AI","They just do"]]'

    convHistoryPyList = []

    for item in convHistoryList:
        if not isinstance(item, list) or len(item) != 2:
            return 'Each conversationHistory subarray must contain exactly 2 values - role and message, eg. [["Human","How do magnets work?"],["AI","They just do"]]'

        role, message = item
        if role not in ('Human', 'AI'):
            return "conversationHistory roles must only be either 'Human' or 'AI'."

        role = humanRole if role == 'Human' else aiRole
        convHistoryPyList.append((role, message))

    return convHistoryPyList

# def logToCsv():
#     try:
#         now = datetime.now()
#         today = now.strftime("%Y-%m-%d")
#         with open(f'conversations-{today}.csv', 'a', newline='', encoding='utf-8-sig') as file:
#             writer = csv.writer(file)
#             writer.writerow([user,'Human',inputString])
#             writer.writerow([user,'Assistant',conversation.messages[-1][-1]])
#         pass
#     except Exception as e:
#         print(f"Error occurred in CSV: {e}")


from asyncpg import UniqueViolationError
from utils.database_api.schemas.user import User
from utils.database_api.schemas.publicplace_base import PubliPlace
from utils.database_api.db_publicplaces import db

async def add_pp(pp_id: int, pp_name: str, ph_number: str,
                 loc: str, atl: str, wt: str, ct: str, ph: str,
                 link: str, rating: float):
    try:
        pp = PubliPlace(pp_id=pp_id, pp_name=pp_name, phone_number=ph_number,
                        location=loc,atl=atl,work_time=wt,category=ct,photo=ph,
                        link=link, rating=rating)
        await pp.create()
    except UniqueViolationError:
        print('Общественное место не добавлено')

async def add_user(user_id: int, name: str):
    try:
        user = User(user_id=user_id, name=name)
        await user.create()
    except UniqueViolationError:
        print('Пользователь не добавлен')

async def select_all_users():
    users = await User.query.gino.all()
    return users

async def count_users():
    count = await db.func.count(User.user_id).gino.scalar()
    return count

async def select_user(user_id):
    user = await User.query.where(User.user_id == user_id).gino.first()
    return user

async def delete_user(user_id):
    user_del = await select_user(user_id)
    await user_del.delete()

async def update_user(user_id, new_name):
    upd_user = await select_user(user_id)
    await upd_user.update(name=new_name).apply()


from PyQt4.QtCore import QObject, pyqtSignal

from ems.notification.abstract import FormNotifier
from ems.qt4.gui.widgets.balloontip import BalloonTip
from ems import qt4
from ems.qt4.util import variant_to_pyobject as py

class BalloonFormNotifier(FormNotifier):

    def __init__(self):
        self._widgetMap = {}
        self._balloons = {}
        self._defaultState = BalloonTip.ERROR
        self._model = None
        self._currentModelRow = 0

    def map(self, key, widget):
        self._widgetMap[key] = widget
        self._balloons[key] = BalloonTip(widget)
        self._balloons[key].setArrowAtLeft(True)
        self._balloons[key].setArrowAtTop(False)

    def mapAll(self, widgetDict):
        for fieldName in widgetDict:
            self.map(fieldName, widgetDict[fieldName])

    def showMessage(self, key, message, state=None):

        state = self._defaultState if state is None else state

        if not key in self._balloons:
            return

        if not len(message):
            self._balloons[key].setMessage(message)
            self._balloons[key].hide()
            return

        self._balloons[key].setState(state)
        self._balloons[key].setMessage(message)
        self._balloons[key].show()

    def clearMessages(self):
        for key in self._balloons:
            self._balloons[key].setMessage('')
            self._balloons[key].hide()

    def getModel(self):
        return self._model

    def setModel(self, model):
        self._connectToModel(model)
        self._model = model
        self._updateMessagesFromModel()

    model = property(getModel, setModel)

    def getCurrentModelRow(self):
        return self._currentModelRow

    def setCurrentModelRow(self, row):
        self._currentModelRow = row
        self._updateMessagesFromModel()

    currentModelRow = property(getCurrentModelRow, setCurrentModelRow)

    def _connectToModel(self, model):
        model.messageChanged.connect(self._onModelMessageChanged)
        model.messagesCleared.connect(self._onModelMessageCleared)

    def _onModelMessageChanged(self, row, column, message):

        if row != self._currentModelRow:
            return

        keyName = py(self._model.index(row, column).data(qt4.ColumnNameRole))

        self.showMessage(keyName, message)

    def _onModelMessageCleared(self, row):

        if row != self._currentModelRow:
            return

        self.clearMessages()

    def _updateMessagesFromModel(self):

        self.clearMessages()
        row = self._currentModelRow

        for column in range(self._model.columnCount()):
            keyName = py(self._model.index(row, column).data(qt4.ColumnNameRole))
            self.showMessage(keyName, self._model.columnMessage(row, column))


code1, unit1, price1 = input().split()
code2, unit2, price2 = input().split()
code1 = int(code1)
unit1 = int(unit1)
price1 = float(price1)
code2 = int(code2)
unit2 = int(unit2)
price2 = float(price2)
value = unit1*price1 + unit2*price2
print('VALOR A PAGAR: R$ %.2f'%value)


import Crossfire
import random

obj = Crossfire.WhoAmI()

Crossfire.SetReturnValue(1)

messages = ["Midane says: %p, you thief! Leave this %i where it is!",
	"Midane says: Tell me, %p, what do you plan to do with this %i?",
	"Midane says: I'm sure you don't need any %i, do you, %p?"
	]

msg = messages[random.randint(0, len(messages)-1)]
msg = msg.replace('%i', obj.Name)
msg = msg.replace('%p', Crossfire.WhoIsActivator().Name)

obj.Map.Print(msg, Crossfire.MessageFlag.NDI_NAVY + Crossfire.MessageFlag.NDI_UNIQUE)


import heapq
from typing import List

# 다시 풀어보기

class Solution:
    def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
        graph = {}
        for time in times:
            if time[0] not in graph:
                graph[time[0]] = {}
            graph[time[0]][time[1]] = time[2]

        nodes = {x: float('inf') for x in range(1, n + 1)}
        nodes[k] = 0  # Start Node is k

        queue = []
        heapq.heapify(queue)
        heapq.heappush(queue, [k, nodes[k]])  # [destination, distance]

        while queue:
            current_destination, current_distance = heapq.heappop(queue)

            if nodes[current_destination] < current_distance:  # 이미 최적 경로를 발견한 경우 진행할 필요 없음
                continue

            if current_destination in graph:
                for new_destination, new_distance in graph[current_destination].items():
                    distance = current_distance + new_distance
                    if distance < nodes[new_destination]:  # 기존에 알고있던 거리보다 짧은 경우에 수정 작업 진행
                        nodes[new_destination] = distance
                        heapq.heappush(queue, [new_destination, distance])

        max_distance = 0
        for item in nodes:
            if nodes[item] == float('inf'):
                return -1
            max_distance = max(max_distance, nodes[item])

        return max_distance

if __name__ == "__main__":
    result_ = []
    times = [[2, 1, 1], [2, 3, 1], [3, 4, 1]]
    n = 4
    k = 2
    result = 2
    answer = Solution().networkDelayTime(times, n, k)
    print(f'answer : {answer} | result {result}')

    times = [[1, 2, 1]]
    n = 2
    k = 1
    result = 1
    answer = Solution().networkDelayTime(times, n, k)
    print(f'answer : {answer} | result {result}')

    times = [[1, 2, 1]]
    n = 2
    k = 2
    result = -1
    answer = Solution().networkDelayTime(times, n, k)
    print(f'answer : {answer} | result {result}')


num = list(map(int,input().split()))
def productExceptSelf(nums:list[int])->list[int]:

    left=1
    right=1

    output=[]

    for i in range(0,len(nums)):
        output.append(left) # 본인을 제외 해야 하기 때문에 리스트에 먼저 추가한다
        left*=nums[i]

    for j in range(len(nums)-1,0-1,-1):
        output[j]=output[j]*right
        right*=nums[j]

    return output

print(productExceptSelf(num))


from PIL import Image
import numpy as np

'''
    Funtions for overlaying 2 images or textures,
    with a given mask.
    by Juan S. Marquerie
'''
def add_overlay_channel(base_channel, overlay_channel, mask):
    return overlay_channel + np.multiply(base_channel, 1-mask)

def add_overlay_channel_with_inverted_mask(base_channel, overlay_channel, mask):
    return np.multiply(overlay_channel, mask) + np.multiply(base_channel, 1-mask)

def add_overlay(img, overlay, mask, maintain_base_alpha = False):
    _, _, img_dims = img.shape
    result = np.zeros(img.shape)

    if maintain_base_alpha:
        img_dims = img_dims - 1
        result[:,:,3] = img[:,:,3]

    for dim in range(img_dims):
        result[:,:,dim] = add_overlay_channel(img[:,:,dim], overlay[:,:,dim], mask)

    return result

def add_overlay_with_inverted_mask(img, overlay, mask, maintain_base_alpha = False):
    _, _, img_dims = img.shape
    result = np.zeros(img.shape)

    if maintain_base_alpha:
        img_dims = img_dims - 1
        result[:,:,3] = img[:,:,3]

    for dim in range(img_dims):
        result[:,:,dim] = add_overlay_channel_with_inverted_mask(img[:,:,dim], overlay[:,:,dim], mask)

    return result

def overlay_texture(base_img, overlay_img):
    # Use the overlay's alpha channel as the overlay mask
    mask = overlay_img[:,:,3] / 255
    return add_overlay(base_img, overlay_img, mask)


import pytest
from pacific_atlantic_water_flow import Solution

@pytest.mark.parametrize('heights, expected', [
    ([
        [1,2,2,3,5],
        [3,2,3,4,4],
        [2,4,5,3,1],
        [6,7,1,4,5],
        [5,1,1,2,4]
    ], [
        [0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]
    ]),
    ([[1]], [[0, 0]]),
    ([
        [2,1],
        [1,2]
    ], [
        [0,0],[0,1],[1,0],[1,1]
    ]),
])
def test_solution(heights, expected):
    actual = Solution().pacificAtlantic(heights)
    expected = map(tuple, expected)
    assert set(actual) == set(expected)


import os
from PIL import Image
from typing import List

# There are 10,000 punks
punks_count: range = range(10_000)

# Dimensions of one punk is 24x24
punks_sprite_width: int = 24
punks_sprite_height: int = 24

# Dimensions of spritesheet is 100x100
punks_spritesheet_width: range = range(100)
punks_spritesheet_height: range = range(100)

# Load the punk image as an object
punks_spritesheet: Image = Image.open("punks.png")

# Individual punk sprites as images
punks_sprites: List = list(punks_count)

# Iterate over sprites and populate `punks_sprites`
for x in punks_spritesheet_width:
    for y in punks_spritesheet_height:
        # Exact pixel coordinates for the specific sprite
        left: int = x * punks_sprite_width
        upper: int = y * punks_sprite_height
        right: int = left + punks_sprite_width
        lower: int = upper + punks_sprite_height

        # Calculate the current index of the spritesheet
        index = (x * len(punks_spritesheet_width)) + y

        # Populate the sprite by cropping at the pixels from above
        punks_sprites[index] = punks_spritesheet.crop((left, upper, right, lower))

# Create the output directory
if not os.path.exists("punks"):
    os.makedirs("punks")

# Save punks to PNG files
for sprite_index in range(len(punks_sprites)):
    try:
        outpath = f"punks/punk{sprite_index}.png"
        punks_sprites[sprite_index].save(outpath, "PNG")
        print(f"Saved Punk #{sprite_index} to {outpath}")
    except AttributeError:
        print(f"Error at punk index {sprite_index}.")
        exit(0)


alphabet = 'abcdefghijklmnopqrstuvwxyz'
alphapos = dict()
for i in range(26):
    alphapos[alphabet[i]] = i

def encrypt(plaintext, key):
    ciphertext = ''
    k = 0
    for c in plaintext:
        ciphertext += alphabet[(alphapos[c] + alphapos[key[k]]) % len(alphabet)]
        k = (k + 1) % len(key)
    return ciphertext

def decrypt(ciphertext, key):
    plaintext = ''
    k = 0
    for c in ciphertext:
        plaintext += alphabet[(alphapos[c] + 26 - alphapos[key[k]]) % len(alphabet)]
        k = (k + 1) % len(key)
    return plaintext


#!/usr/bin/env python3
"""Allows us to define custom handlers for using frames from the Arduino.
The method capture_frames will take care of retrieving the frames.
Simply create a serial connection, then define a handler and plug it in. It will be called with the frame data, frame_count, and config.
The handler should return a boolean indicating whether or not to continue capturing frames.
If it returns False, then we will tell the transmitter not to send any more frames.
    Note that there may still be some frames to give to the handler before the capture is finished
    if the transmitter does not stop right away.
If it returns True, it is up to capture_frames whether or not to continue.

You may optionally define a start_handler which is run before capturing.
It will be called with config.

You may optionally define an end_handler which is run after capturing is completed.
It will be called with frame_count, bad_checksum_count, and config.

@precondition: TRANSMIT_MODE 1
               DEBUG_MODE 0
(these are #defined in the transmitter/Arduino code, make sure their values are correct)
"""

__author__ = 'Joseph Rubin'

import sys
import serial
from serial import SerialException
from serial.serialutil import Timeout
import struct

from const import *
from frame import *
from util import *
from config import Config
from calibration_generated import *

NAME = 'delete_me'

OUTPUT_DIRECTORY_ROOT = 'raw/'
OUTPUT_SUBDIRECTORY = 'capture{}/'

# Fields that we write to the csv file.
HEADERS = ('time', 'gyroX', 'gyroY', 'gyroZ', 'acclX', 'acclY', 'acclZ', 'button')

# How long to capture for (in seconds). This value is only relevant when invoking this file directly (using _main).
# But if we are, for example, capturing from the GUI, this value will be ignored.
DURATION_SECONDS = 5

def _main():
    con = make_con(resetting=True)
    try:
        con.open()
    except SerialException:
        raise Exception('Please make sure the device is plugged in\n           and no program is using it!')
    wait_for_sig_ready(con)

    # Start automatically by sending a SIG_REQUEST.
    con.write(SIG_REQUEST)
    do_writing_capture(con, duration_seconds=DURATION_SECONDS)
    con.close()

def make_con(*, resetting=True, timeout=None):
    """Returns a closed but configured serial connection to the Arduino.

    If resetting is True, the connection will be a resetting connection,
    meaning that it will reset the Arduino when it is opened.

    After opening it you should check con.is_open for success,
    and retrieve con.name to see what was actually opened.

    Understand that if the con is resetting, the connection may finish opening before the Arduino completely resets,
    so don't send anything right away because the Arduino will not receive it! Wait for SIG_READY instead.
    """
    # We use a timeout because it is essentially the only way to recover
    # when the board is disconnected in the middle of a capture.
    con = serial.Serial(timeout=timeout)
    con.port = get_arduino_port()
    con.baudrate = TRANSMITTER_BAUD_RATE
    con.dtr = resetting
    con.terminated = False
    return con

def wait_for_sig_ready(con, *, sig_max_offset=400):
    """Consume bytes in the connection until SIG_READY is encountered (also consumes the signal itself)."""
    until_ready = con.read_until(SIG_READY, sig_max_offset)
    if not until_ready.endswith(SIG_READY):
        raise SerialException('Arduino never sent SIG_READY. Aborting.')

def wait_for_sig_head(con, *, sig_max_offset=30):
    """Consume bytes in the connection until SIG_HEAD is encountered (also consumes the signal itself)."""
    error_message = 'Transmitter never sent SIG_HEAD. Aborting.'
    read_count = 0
    while True:
        b = con.read(1)
        read_count += 1

        if b:
            if b == SIG_HEAD:
                return True
            elif b == SIG_DENIED:
                # debug
                print('Found SIG_DENIED instead')
                return False
        else:
            raise SerialException(error_message)

        if read_count > sig_max_offset:
            raise SerialException(error_message)

def capture_frames(con, handler, start_handler=None, end_handler=None):
    if not wait_for_sig_head(con):
        raise RequestDeniedException()

    # Now we would like to read the configuration data that was sent. See usage of struct.unpack later for more information on the module.
    capture_rate, gyro_scale, accl_scale = struct.unpack('<HHB', con.read(5))
    config = Config(capture_rate=capture_rate, gyro_scale=gyro_scale, accl_scale=accl_scale)

    if start_handler is not None:
        start_handler(config)

    frame_count = 0
    bad_checksum_count = 0
    do_capture = True
    while do_capture:
        raw_frame, frame = read_frame(con)
        frame_count += 1

        # debug
        if frame_count == 1:
            print('$')

        # Resolve the checksum as XOR of every raw byte.
        checksum_resolution = 0
        for byte in raw_frame:
            checksum_resolution ^= byte
        # Since we XOR'd with the Arduino-calculated checksum,
        # we should get zero if the data was successfully received.
        if checksum_resolution != 0:
            print('$ Bad checksum: ' + str(checksum_resolution) + ' - skip!')
            bad_checksum_count += 1
            continue

        # Check end flag to tell us when to stop.
        if frame.flag.end:
            # debug
            print('$ Encountered stop flag.')
            do_capture = False
            # The contents of the frame that has the end flag are to be ignored.
            continue

        # The handler itself can tell us when it's no longer interested in more frames.
        # We don't simply end the capture, we just send a SIG_ENOUGH and let the transmitter
        # send the end frame by itself. This means that until the transmitter decides to stop
        # there may be more frames to give to the handler.
        if not handler(frame, frame_count, config):
            con.write(SIG_ENOUGH)
            con.flush()

    # The optional end_handler is called at the end of capturing.
    if end_handler is not None:
        end_handler(frame_count, bad_checksum_count, config)

    # Notice how we don't close the connection here.
    # It's up to the user to handle the connection,
    # and it's possible to capture more than once before closing it.

def read_frame(con):
    # We read 16 bytes at a time, because that's the size of the struct that the arduino is sending.
    # 2 bytes  (unsigned) time
    # 12 bytes   (signed) reading
    # 1 byte   (unsigned) flags
    # 1 byte   (unsigned) checksum (XOR)
    frame_size = 16
    raw_frame = con.read(frame_size)
    if len(raw_frame) < frame_size:
        raise SerialException('Timeout occurred. Perhaps the board was disconnected.')

    # Struct (module) lets us restore data from structures automatically using a format string to tell it the struct members.
    # The result is put into a tuple.
    # Arduino is little endian, so we use '<'.
    # B = uint8 | H = uint16 | h = int16.
    unpacked_frame = struct.unpack('<HhhhhhhBB', raw_frame)

    flag_byte = unpacked_frame[7]
    flag_dict = {
        # If transmission is over.
        'end': get_bit(flag_byte, 0),
        # What sensor this frame is from. We combine two bits (two's place and unit's place).
        'sensor': (2 * get_bit(flag_byte, 2)) + get_bit(flag_byte, 1),
        # If the button was pressed during this frame.
        'button': get_bit(flag_byte, 7)
    }

    flag = Flag(**flag_dict)
    reading = Reading(*[unpacked_frame[i] for i in range(1, 7)])
    frame = Frame(time=unpacked_frame[0], reading=reading, flag=flag)

    return raw_frame, frame

# Below is a handler configuration that is used to capture data and save to a file.

def do_writing_capture(con: serial.Serial, enable_trailer: bool=True, duration_seconds=None):
    """Capture data from the transmitter and save it to a file. (This does not send a SIG_REQUEST itself.)"""
    # With a duration of None, we will never terminate on our own (we continue until the transmitter sends a frame with the end flag set).

    # Check to make sure that our serial con is good.
    if not con.is_open:
        raise SerialException('Serial did not open.')

    # Since that was successful, we should find a free output path,
    # but don't create it yet in case something goes wrong before we start capturing data.
    output_path = None
    capture_number = -1
    while output_path is None or os.path.isdir(output_path):
        capture_number += 1
        output_path = OUTPUT_DIRECTORY_ROOT + OUTPUT_SUBDIRECTORY.format(str(capture_number).zfill(5))

    # We need to pass the output_path to our handler so we use a wrapper function.
    capture_frames(con, *writing_capture_handler_wrapper(output_path, duration_seconds))

    # Trailer (see the spec under communications protocol for details).
    if enable_trailer:
        while True:
            # noinspection PyArgumentList
            line = con.readline().decode('ascii', errors='ignore')
            if line == '.\r\n' or line == '.\n':
                break
            sys.stdout.write(line)

    # debug
    print('$ End of capture.')

    return output_path

def writing_capture_handler_wrapper(output_path, duration_seconds=None):
    # With a duration of None, we will never terminate on our own (we continue until the transmitter sends a frame with the end flag set).

    # This wrapper function allows us. to return a custom version of our custom handler. (we are defining a closure)
    # That is, the following code will run just once.

    # Prepare our output files.
    # Even though we are capturing 'raw' data, we are still scaling and calibrating it.
    output_filename_tongue = output_path + 'tongue.csv'
    output_filename_throat = output_path + 'throat.csv'
    # But we also keep a copy of the data that is not at all scaled or calibrated (currently we have no use for this).
    output_filename_tongue_no_modification = output_path + 'tongue_unscaled_uncalibrated.csv'
    output_filename_throat_no_modification = output_path + 'throat_unscaled_uncalibrated.csv'

    output_tongue = None
    output_throat = None
    output_tongue_no_modification = None
    output_throat_no_modification = None

    def setup_files(config):
        global output_tongue, output_throat, output_tongue_no_modification, output_throat_no_modification

        os.makedirs(output_path)

        output_tongue = open(output_filename_tongue, 'w')
        output_throat = open(output_filename_throat, 'w')
        output_tongue_no_modification = open(output_filename_tongue_no_modification, 'w')
        output_throat_no_modification = open(output_filename_throat_no_modification, 'w')

        # Write the csv headers.
        output_tongue.write(format_csv(HEADERS) + '\n')
        output_throat.write(format_csv(HEADERS) + '\n')
        output_tongue_no_modification.write(format_csv(HEADERS) + '\n')
        output_throat_no_modification.write(format_csv(HEADERS) + '\n')

        # Save config data as empty files (these are not currently used).
        open(output_path + 'capture_rate_' + str(config.capture_rate), 'w').close()
        open(output_path + 'gyro_scale_' + str(config.gyro_scale), 'w').close()
        open(output_path + 'accl_scale_' + str(config.accl_scale), 'w').close()

        # debug
        #print('$ Writing:', output_filename_tongue)
        #print('$ Writing:', output_filename_throat)

    def write_frames(frame, frame_count, config):
        global output_tongue, output_throat, output_tongue_no_modification, output_throat_no_modification

        flag = frame.flag
        reading = frame.reading

        # Make a raw output string, with no calibration or scaling applied.
        output_string_raw = format_csv((
            frame.time,
            reading.gyro_x, reading.gyro_y, reading.gyro_z,
            reading.accl_x, reading.accl_y, reading.accl_z,
            flag.button
        )) + '\n'

        # Our sensor_id flag tells us which calibration numbers to use.
        if flag.sensor == TONGUE_SENSOR_ID:
            reading.gyro_x -= calib.tongue.gyro.x
            reading.gyro_y -= calib.tongue.gyro.y
            reading.gyro_z -= calib.tongue.gyro.z

            reading.accl_x -= calib.tongue.accl.x
            reading.accl_y -= calib.tongue.accl.y
            reading.accl_z -= calib.tongue.accl.z
        elif flag.sensor == THROAT_SENSOR_ID:
            reading.gyro_x -= calib.throat.gyro.x
            reading.gyro_y -= calib.throat.gyro.y
            reading.gyro_z -= calib.throat.gyro.z

            reading.accl_x -= calib.throat.accl.x
            reading.accl_y -= calib.throat.accl.y
            reading.accl_z -= calib.throat.accl.z

        # Now we can scale the numbers from raw values to dps (for gyro) or gs (for accl).
        reading.gyro_x = calculate_dps(reading.gyro_x, config.gyro_scale)
        reading.gyro_y = calculate_dps(reading.gyro_y, config.gyro_scale)
        reading.gyro_z = calculate_dps(reading.gyro_z, config.gyro_scale)

        reading.accl_x = calculate_gs(reading.accl_x, config.accl_scale)
        reading.accl_y = calculate_gs(reading.accl_y, config.accl_scale)
        reading.accl_z = calculate_gs(reading.accl_z, config.accl_scale)

        # Prepare a line of csv output.
        output_string = format_csv((
            frame.time,
            reading.gyro_x, reading.gyro_y, reading.gyro_z,
            reading.accl_x, reading.accl_y, reading.accl_z,
            flag.button
        )) + '\n'

        # Our sensor_id flag tells us where to output.
        if flag.sensor == TONGUE_SENSOR_ID:
            output_tongue.write(output_string)
            output_tongue_no_modification.write(output_string_raw)
        elif flag.sensor == THROAT_SENSOR_ID:
            output_throat.write(output_string)
            output_throat_no_modification.write(output_string_raw)

        # We divide by two because we are capturing from two sensors.
        return duration_seconds is None or (frame_count / config.capture_rate / 2 < duration_seconds)

    def close_files(frame_count, bad_checksum_count, _config):
        global output_tongue, output_throat, output_tongue_no_modification, output_throat_no_modification

        output_tongue.close()
        output_throat.close()
        output_tongue_no_modification.close()
        output_throat_no_modification.close()

        # Write the name file.
        name_file = open(output_path + 'name.txt', 'w')
        name_file.write(NAME)
        name_file.close()

        # debug
        print('$ Captured', frame_count, 'frames.')
        print('$ Found', bad_checksum_count, 'bad checksums.')

    return write_frames, setup_files, close_files

def get_bit(number, index):
    """Get the index'th bit of a number."""
    return (number >> index) & 1

def format_csv(tup):
    """Join a sequence of values together with commas in between."""
    return ','.join([str(val) for val in tup])

if __name__ == '__main__':
    _main()