#!/usr/bin/python3
import sys
import pygame
import random

pygame.init()

def main():
    setupGame()
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONUP:
                x, y = pygame.mouse.get_pos()
                dealWithMouseClick(x, y)
        displayScreen()

def setupGame():
    global turn
    global screen
    global player1Name
    global player2Name
    global diceScore
    global subGo
    global redLeftPos
    global redRightPos
    global blackLeftPos
    global blackRightPos
    global mover
    global winner
    diceScore = 0
    player1Name = "Player 1"
    player2Name = "Player 2"
    screen = "Main Menu"
    turn = "Player 1"
    subGo = "A"
    mover = False
    createObjects()
    redLeftPos = 1
    redRightPos = 1
    blackLeftPos = 1
    blackRightPos = 1
    winner = ""
    setCounterPos()

def displayScreen():
    DISPLAYSURF.blit(background, backgroundRect)
    if screen == "Main Menu":
        displayMainMenu()
    elif screen == "Enter Names":
        displayEnterNames()
    elif screen == "Play Game":
        setCounterPos()
        displayPlayGame()
    pygame.display.flip()

def setCounterPos():
    global redCounterLeftRect
    global redCounterRightRect
    global blackCounterLeftRect
    global blackCounterRightRect
    redCounterLeftRect.x = 200
    redCounterLeftRect.y = 650 - (50 * redLeftPos)
    redCounterRightRect.x = 250
    redCounterRightRect.y = 650 - (50 * redRightPos)
    blackCounterLeftRect.x = 300
    blackCounterLeftRect.y = 650 - (50 * blackLeftPos)
    blackCounterRightRect.x = 350
    blackCounterRightRect.y = 650 - (50 * blackRightPos)

def displayMainMenu():
    line1 = myFont.render(player1Name, 0, (255, 255, 255))
    line1Rect = line1.get_rect()
    line1Rect.x = 20
    line1Rect.y = 20
    line2 = myFont.render(player2Name, 0, (255, 255, 255))
    line2Rect = line2.get_rect()
    line2Rect.x = 20
    line2Rect.y = 50
    DISPLAYSURF.blit(line1, line1Rect)
    DISPLAYSURF.blit(line2, line2Rect)
    DISPLAYSURF.blit(btnPlayGame, btnPlayGameRect)
    DISPLAYSURF.blit(btnEnterNames, btnEnterNamesRect)
    DISPLAYSURF.blit(btnQuitGame, btnQuitGameRect)

def displayEnterNames():
    line1 = myFont.render("Please go to the Python Shell to", 0, (255, 255, 255))
    line1Rect = line1.get_rect()
    line1Rect.centerx = backgroundRect.centerx
    line1Rect.y = 100
    DISPLAYSURF.blit(line1, line1Rect)
    line2 = myFont.render("enter player names.", 0, (255, 255, 255))
    line2Rect = line1.get_rect()
    line2Rect.centerx = backgroundRect.centerx
    line2Rect.y = 150
    DISPLAYSURF.blit(line2, line2Rect)
    pygame.display.flip()
    enterPlayerNames()

def enterPlayerNames():
    global player1Name
    global player2Name
    global screen
    player1Name = input("Please enter a name for Player 1:")
    player2Name = input("Please enter a name for Player 2:")
    screen = "Main Menu"

def displayPlayGame():
    if subGo == "Z":
        pass
    else:
        line1 = myFont.render(player1Name, 0, (255, 255, 255))
        line1Rect = line1.get_rect()
        line1Rect.x = 20
        line1Rect.y = 20
        line2 = myFont.render(player2Name, 0, (255, 255, 255))
        line2Rect = line2.get_rect()
        line2Rect.x = 20
        line2Rect.y = 50
        if subGo == "A":
            goA()
        if subGo == "B":
            goB()
        DISPLAYSURF.blit(line1, line1Rect)
        DISPLAYSURF.blit(line2, line2Rect)
        DISPLAYSURF.blit(board, boardRect)
        DISPLAYSURF.blit(redCounterLeft, redCounterLeftRect)
        DISPLAYSURF.blit(redCounterRight, redCounterRightRect)
        DISPLAYSURF.blit(blackCounterLeft, blackCounterLeftRect)
        DISPLAYSURF.blit(blackCounterRight, blackCounterRightRect)

def goA():
    if turn == "Player 1":
        whosGo = myFont.render(player1Name + " please roll", 0, (255, 255, 255))
    else:
        whosGo = myFont.render(player2Name + " please roll", 0, (255, 255, 255))
    whosGoRect = whosGo.get_rect()
    whosGoRect.x = 300
    whosGoRect.y = 20
    whosGo2 = myFont.render("the dice", 0, (255, 255, 255))
    whosGo2Rect = whosGo2.get_rect()
    whosGo2Rect.x = 300
    whosGo2Rect.y = 50
    DISPLAYSURF.blit(whosGo, whosGoRect)
    DISPLAYSURF.blit(whosGo2, whosGo2Rect)
    DISPLAYSURF.blit(btnRollDice, btnRollDiceRect)

def goB():
    global mover
    if turn == "Player 1":
        whosGo = myFont.render(player1Name + " you scored:", 0, (255, 255, 255))
    else:
        whosGo = myFont.render(player2Name + " you scored:", 0, (255, 255, 255))
    whosGoRect = whosGo.get_rect()
    whosGoRect.x = 300
    whosGoRect.y = 20
    whosGo2 = diceFont.render(str(diceScore), 0, (0, 255, 255))
    whosGo2Rect = whosGo2.get_rect()
    whosGo2Rect.x = 500
    whosGo2Rect.y = 70
    DISPLAYSURF.blit(whosGo, whosGoRect)
    DISPLAYSURF.blit(whosGo2, whosGo2Rect)
    firstLine = messageFont.render("You can move a counter:", 0, (0, 255, 255))
    firstLineRect = firstLine.get_rect()
    firstLineRect.x = 420
    firstLineRect.y = 150
    message = messageFont.render(diceMessage(), 0, (0, 255, 255))
    messageRect = message.get_rect()
    messageRect.x = 420
    messageRect.y = 180
    DISPLAYSURF.blit(firstLine, firstLineRect)
    DISPLAYSURF.blit(message, messageRect)
    if canThePlayerMove():
        mover = True
        chooseACounter = messageFont.render("Please choose a counter to move:", 0, (0, 255, 255))
        chooseACounterRect = chooseACounter.get_rect()
        chooseACounterRect.x = 410
        chooseACounterRect.y = 250
        DISPLAYSURF.blit(chooseACounter, chooseACounterRect)
        if turn == "Player 1":
            if canRedLeftMove():
                DISPLAYSURF.blit(btnLeft, btnLeftRect)
            else:
                DISPLAYSURF.blit(btnLeftNo, btnLeftRect)
            if canRedRightMove():
                DISPLAYSURF.blit(btnRight, btnRightRect)
            else:
                DISPLAYSURF.blit(btnRightNo, btnRightRect)
        else:
            if canBlackLeftMove():
                DISPLAYSURF.blit(btnLeft, btnLeftRect)
            else:
                DISPLAYSURF.blit(btnLeftNo, btnLeftRect)
            if canBlackRightMove():
                DISPLAYSURF.blit(btnRight, btnRightRect)
            else:
                DISPLAYSURF.blit(btnRightNo, btnRightRect)
    else:
        mover = False
        noMoveAvailable = messageFont.render("No valid move is possible.", 0, (255, 0, 0))
        noMoveAvailableRect = noMoveAvailable.get_rect()
        noMoveAvailableRect.x = 410
        noMoveAvailableRect.y = 250
        DISPLAYSURF.blit(noMoveAvailable, noMoveAvailableRect)
        DISPLAYSURF.blit(btnEndGo, btnEndGoRect)

def canThePlayerMove():
    if turn == "Player 1":
        if canRedLeftMove() or canRedRightMove():
            return True
    else:
        if canBlackLeftMove() or canBlackRightMove():
            return True
    return False

def canRedLeftMove():
    if diceScore < 4:
        if redLeftPos == 11:
            return False
        trialPos = redLeftPos + diceScore
        if trialPos == redRightPos:
            if trialPos == 5 or trialPos >= 11:
                return True
            else:
                return False
        else:
            return True
    else:
        if redLeftPos == 1:
            return False
        trialPos = redLeftPos - 1
        if trialPos == redRightPos:
            if trialPos == 5 or trialPos <= 1:
                return True
            else:
                return False
        else:
            return True

def canRedRightMove():
    if diceScore < 4:
        if redRightPos == 11:
            return False
        trialPos = redRightPos + diceScore
        if trialPos == redLeftPos:
            if trialPos == 5 or trialPos >= 11:
                return True
            else:
                return False
        else:
            return True
    else:
        if redRightPos == 1:
            return False
        trialPos = redRightPos - 1
        if trialPos == redLeftPos:
            if trialPos == 5 or trialPos <= 1:
                return True
            else:
                return False
        else:
            return True

def canBlackLeftMove():
    if diceScore < 4:
        if blackLeftPos == 11:
            return False
        trialPos = blackLeftPos + diceScore
        if trialPos == blackRightPos:
            if trialPos == 5 or trialPos >= 11:
                return True
            else:
                return False
        else:
            return True
    else:
        if blackLeftPos == 1:
            return False
        trialPos = blackLeftPos - 1
        if trialPos == blackRightPos:
            if trialPos == 5 or trialPos <= 1:
                return True
            else:
                return False
        else:
            return True
    return False

def canBlackRightMove():
    if diceScore < 4:
        if blackRightPos == 11:
            return False
        trialPos = blackRightPos + diceScore
        if trialPos == blackLeftPos:
            if trialPos == 5 or trialPos >= 11:
                return True
            else:
                return False
        else:
            return True
    else:
        if blackRightPos == 1:
            return False
        trialPos = blackRightPos - 1
        if trialPos == blackLeftPos:
            if trialPos == 5 or trialPos <= 1:
                return True
            else:
                return False
        else:
            return True

def diceMessage():
    theMessage = ""
    if diceScore == 1:
        theMessage = "1 space closer to the FINISH"
    elif diceScore == 2:
        theMessage = "2 spaces closer to the FINISH"
    elif diceScore == 3:
        theMessage = "3 spaces closer to the FINISH"
    elif diceScore == 4:
        theMessage = "1 space closer to the START"
    return theMessage

def dealWithMouseClick(theX, theY):
    global screen
    global subGo
    if screen == "Main Menu":
        if btnPlayGameRect.collidepoint(theX, theY):
            screen = "Play Game"
        elif btnEnterNamesRect.collidepoint(theX, theY):
            screen = "Enter Names"
        elif btnQuitGameRect.collidepoint(theX, theY):
            pygame.quit()
            sys.exit()
    if screen == "Play Game":
        if subGo == "A":
            if btnRollDiceRect.collidepoint(theX, theY):
                rollTheDice()
        if mover:
            if turn == "Player 1":
                if canRedLeftMove():
                    if btnLeftRect.collidepoint(theX, theY):
                        moveRedLeft()
                if canRedRightMove():
                    if btnRightRect.collidepoint(theX, theY):
                        moveRedRight()
            else:
                if canBlackLeftMove():
                    if btnLeftRect.collidepoint(theX, theY):
                        moveBlackLeft()
                if canBlackRightMove():
                    if btnRightRect.collidepoint(theX, theY):
                        moveBlackRight()
                pass
        else:
            if btnEndGoRect.collidepoint(theX, theY):
                changeTurn()

def moveRedLeft():
    global redLeftPos
    global blackLeftPos
    global blackRightPos
    if diceScore < 4:
        trialPos = redLeftPos + diceScore
        if trialPos > 11:
            redLeftPos = 11
        else:
            redLeftPos = trialPos
    else:
        redLeftPos = redLeftPos - 1
    if redLeftPos == 1 or redLeftPos == 5 or redLeftPos == 11:
        pass
    else:
        if blackLeftPos == redLeftPos:
            blackLeftPos = 1
        if blackRightPos == redLeftPos:
            blackRightPos = 1
    hasRedWon()
    changeTurn()

def moveRedRight():
    global redRightPos
    global blackLeftPos
    global blackRightPos
    if diceScore < 4:
        trialPos = redRightPos + diceScore
        if trialPos > 11:
            redRightPos = 11
        else:
            redRightPos = trialPos
    else:
        redRightPos = redRightPos - 1
    if redRightPos == 1 or redRightPos == 5 or redRightPos == 11:
        pass
    else:
        if blackLeftPos == redRightPos:
            blackLeftPos = 1
        if blackRightPos == redRightPos:
            blackRightPos = 1
    hasRedWon()
    changeTurn()

def moveBlackLeft():
    global blackLeftPos
    global redLeftPos
    global redRightPos
    if diceScore < 4:
        trialPos = blackLeftPos + diceScore
        if trialPos > 11:
            blackLeftPos = 11
        else:
            blackLeftPos = trialPos
    else:
        blackLeftPos = blackLeftPos - 1
    if blackLeftPos == 1 or blackLeftPos == 5 or blackLeftPos == 11:
        pass
    else:
        if redLeftPos == blackLeftPos:
            redLeftPos = 1
        if redRightPos == blackLeftPos:
            redRightPos = 1
    hasBlackWon()
    changeTurn()

def moveBlackRight():
    global blackRightPos
    global redLeftPos
    global redRightPos
    if diceScore < 4:
        trialPos = blackRightPos + diceScore
        if trialPos > 11:
            blackRightPos = 11
        else:
            blackRightPos = trialPos
    else:
        blackRightPos = blackRightPos - 1
    if blackRightPos == 1 or blackRightPos == 5 or blackRightPos == 11:
        pass
    else:
        if redLeftPos == blackRightPos:
            redLeftPos = 1
        if redRightPos == blackRightPos:
            redRightPos = 1
    hasBlackWon()
    changeTurn()

def hasRedWon():
    global winner
    global subGo
    global mover
    if redLeftPos == 11 and redRightPos == 11:
        mover = False
        winner = "Red"
        subGo = "Z"

def hasBlackWon():
    global winner
    global subGo
    global mover
    if blackLeftPos == 11 and blackRightPos == 11:
        mover = False
        winner = "Black"
        subGo = "Z"

def changeTurn():
    global turn
    global subGo
    if turn == "Player 1":
        turn = "Player 2"
    else:
        turn = "Player 1"
    subGo = "A"

def rollTheDice():
    global subGo
    global diceScore
    subGo = "B"
    diceScore = random.randint(1, 4)

def createObjects():
    global background
    global backgroundRect
    global board
    global boardRect
    global btnPlayGame
    global btnPlayGameRect
    global btnEnterNames
    global btnEnterNamesRect
    global btnQuitGame
    global btnQuitGameRect
    global DISPLAYSURF
    global myFont
    global diceFont
    global messageFont
    global redCounterLeft
    global redCounterLeftRect
    global redCounterRight
    global redCounterRightRect
    global blackCounterLeft
    global blackCounterLeftRect
    global blackCounterRight
    global blackCounterRightRect
    global btnRollDice
    global btnRollDiceRect
    global btnLeft
    global btnLeftRect
    global btnLeftNo
    global btnRight
    global btnRightNo
    global btnRightRect
    global btnEndGo
    global btnEndGoRect

    background = pygame.image.load("background.png")
    backgroundRect = background.get_rect()

    board = pygame.image.load("board.png")
    boardRect = board.get_rect()
    boardRect.x = 100
    boardRect.y = 100

    redCounterLeft = pygame.image.load("red-counter.png")
    redCounterLeftRect = redCounterLeft.get_rect()

    redCounterRight = pygame.image.load("red-counter.png")
    redCounterRightRect = redCounterRight.get_rect()

    blackCounterLeft = pygame.image.load("black-counter.png")
    blackCounterLeftRect = blackCounterLeft.get_rect()

    blackCounterRight = pygame.image.load("black-counter.png")
    blackCounterRightRect = blackCounterRight.get_rect()

    btnPlayGame = pygame.image.load("play-game-button.png")
    btnPlayGameRect = btnPlayGame.get_rect()
    btnPlayGameRect.x = 200
    btnPlayGameRect.y = 150

    btnEnterNames = pygame.image.load("enter-names-button.png")
    btnEnterNamesRect = btnEnterNames.get_rect()
    btnEnterNamesRect.x = 200
    btnEnterNamesRect.y = 250

    btnQuitGame = pygame.image.load("quit-game-button.png")
    btnQuitGameRect = btnQuitGame.get_rect()
    btnQuitGameRect.x = 200
    btnQuitGameRect.y = 350

    btnRollDice = pygame.image.load("roll-dice.png")
    btnRollDiceRect = btnRollDice.get_rect()
    btnRollDiceRect.x = 450
    btnRollDiceRect.y = 70

    btnRight = pygame.image.load("right.png")
    btnRightNo = pygame.image.load("right-no.png")
    btnRightRect = btnRight.get_rect()
    btnRightRect.x = 520
    btnRightRect.y = 300

    btnLeft = pygame.image.load("left.png")
    btnLeftNo = pygame.image.load("left-no.png")
    btnLeftRect = btnLeft.get_rect()
    btnLeftRect.x = 450
    btnLeftRect.y = 300

    btnEndGo = pygame.image.load("end-turn.png")
    btnEndGoRect = btnEndGo.get_rect()
    btnEndGoRect.x = 450
    btnEndGoRect.y = 300

    DISPLAYSURF = pygame.display.set_mode(background.get_size())
    pygame.display.set_caption("LuBiDaDo")

    messageFont = pygame.font.SysFont("Arial", 20)
    myFont = pygame.font.SysFont("Arial", 30)
    diceFont = pygame.font.SysFont("Arial", 50)

if __name__ == "__main__":
    main()


import sys
input=sys.stdin.readline
# 1h 52m
def solve(a,b):
    if a<b: a,b=b,a
    while b>0:
        a,b=b,a%b
    return a

a,b=map(int,input().split())
cnt=int(b**0.5)-int(a**0.5)
mo=solve(cnt,b-a)
print(0 if cnt==0 else str(cnt//mo)+'/'+str((b-a)//mo))


import requests    #this is for getting the webpage
from bs4 import BeautifulSoup    #html parser or whatever
import re
import string
import numpy as np

'''
This is our job description scraping file
It goes through every id in 'id_list.txt' and save the text description as a numpy array of strings

Input: .txt File
Output: .txt Files
'''

headers = requests.utils.default_headers()    #need to provide a user-agent code to access the website
headers.update({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36',})

with open('id_list.txt', 'r')as f:
    job_list = f.readlines()

job_list = list(set(job_list))

# Map the languages with punctuations to letters only
punctuatedLanguages = {"asp.net" : "aspdotnet",
    "f#" : "fsharp",
    "objective-c" : "objectivec",
    "objective-c++" : "objectivecplusplus",
    "c#": "csharp",
    "c++": "cplusplus",
    }

start = 0
end = 12285
# for i in range(end, start, -1): ## this one runs backward
for i in range(start, end):  #this one runs forward
    job_id = job_list[i].replace('\n', '')
    jobPage0 = 'https://www.glassdoor.com/Job/json/details.htm?jobListingId=' + job_id
    jobPage0 = requests.get(jobPage0,headers = headers)
    jobsoup  = BeautifulSoup(jobPage0.text,'html.parser')
    jobsoup = str(jobsoup).lower()
    for element in punctuatedLanguages:
        jobsoup = jobsoup.replace(element, punctuatedLanguages[element])
    jobsoup = re.sub('[%s]'%string.punctuation, " ", jobsoup)
    jobsoup = jobsoup.split()
    np.save('job_description' + str(i) + '.npy', jobsoup)   # Save each job description as a numpy file
    print(i)


##############################################################
#### Written By: ANKHI PAUL                               ####
#### Written On: 03-MAR-2020                              ####
#### Modified On 03-MAR-2020                              ####
#### Objective: AWS Lambda script written in Python       ####
####                 to read csv file from S3             ####
##############################################################

import boto3
s3 =  boto3.client('s3') #boto3 is Python SDK for AWS
URL = "https://maps.googleapis.com/maps/api/geocode/json"
key = config.api_key
bucket = 'pythonusecase'

def lambda_handler(event, context):
    # Reading file into dictionary - https://stackoverflow.com/questions/42312196/how-do-i-read-a-csv-stored-in-s3-with-csv-dictreader
    csvfile=s3.get_object(Bucket=bucket, Key='employee_demo.txt')
    csvfile = csv.DictReader(codecs.getreader('utf-8')(csvfile[u'Body']))

    # In memory file writing
    csvio = io.StringIO()
    writer = csv.DictWriter(csvio, fieldnames=["Name", "Address_line_1", "Postal_Code"])
    writer.writeheader()

    for row in csvfile:
        print(row)
        # defining a params dict for the parameters to be sent to the API
        PARAMS = {'address': row['Address_line_1'],'key': key}
        # sending get request and saving the response as response object
        r = requests.get(url=URL, params=PARAMS)

        # extracting data in json format
        output = r.json()
        correct_postal_code = output['results'][0]['address_components'][7]['long_name']
        print('Correct postal code:'+correct_postal_code)
        row['Postal_Code'] = correct_postal_code
        writer.writerow(row)
    print('============Put output file into s3 =========')
    #s3 - https://stackoverflow.com/questions/57768041/how-do-i-use-aws-lambda-to-create-csv-file-from-json-data
    s3.put_object(Body=csvio.getvalue(), ContentType='text/csv', Bucket=bucket, Key='employee_demo_out.txt')
    csvio.close()

    return {
        'statusCode': 200,
        'message': 'Success'
    }


#u
####   Python: 3.6.4
#
####   Author: Brandon Lyon
#
####   Purpose:
#

####def start():
####    print("Hello {}".format(get_name()))
##
##
##
####def get_name():
####    name = input("What is your name?")
####    return name

def start():
    f_name = "Brandon"
    l_name = "Lyon"
    age = 22
    gender = "Male"
    get_info(f_name,l_name,age,gender)

def get_info(f_name,l_name,age,gender):
    print("My name is {} {}. I am {} yearold {}.".format(f_name,l_name,age,gender))

if __name__ == "__main__":
    start()


class MyZeroDivisionError(Exception):
    def __init__(self, text):
        self.text = text

i = int(input('Divide 100 by: '))

try:
    if i == 0:
        raise MyZeroDivisionError('Can not divide by 0')
except MyZeroDivisionError as err:
    print(err)
else:
    print(f"Ответ: {100 / i}")


import speech_recognition as sr
from gtts import gTTS
from playsound import playsound
import os
import sys
from docx import Document
import geocoder
import requests
import json
from json.decoder import JSONDecodeError

talking = True

r = sr.Recognizer()
desktop = os.path.expanduser("~/Desktop")
if '\\' in desktop:
    desktop = desktop.replace('\\','/')

mic = sr.Microphone(device_index=2)

def speck(text):
    spech = gTTS(text, lang = 'en')
    spech.save('spech.mp3')
    playsound('spech.mp3')
    os.remove('spech.mp3')

def recognize():
    with mic as sourse:
        audio = r.listen(sourse)
    text = r.recognize_google(audio)
    return text

def documents():
    print('How do want to call your file?')
    speck('How do want to call your file? (please say it).')

    name_of_file = recognize()
    print('start talking')
    speck('start talking, ')
    doc = Document()

    data = recognize()
    with open(f'{desktop}/{name_of_file}.txt', 'w') as myfile:
        myfile.write(data)
    with open(f'{desktop}/{name_of_file}.txt','r',encoding='utf-8') as file:
        doc.add_paragraph(file.read())
        doc.save(f'{desktop}/{name_of_file}.docx')
    os.remove(f'{desktop}/{name_of_file}.txt')

    print('The file saved on your desktop')
    speck('the file saved on your desktop. thank you!')

def wether():
    me = geocoder.ip('me')
    cords = me.latlng
    lat = cords[0]
    lang = cords[1]
    weather = requests.get(f'http://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lang}&units=metric&appid=b7830cb6712606dd3a60ce03794cf408')
    weather_json = json.loads(weather.text)
    speck(f'the weather is {weather_json["main"]["temp"]} celsius degrees')

username = sys.argv[1]


"""
NEM12 module, everything related to NEM12 parsing, handling of NEM12 blob events
and NEM12 calculations.
"""

import csv
import os
from datetime import datetime
from pathlib import Path

import pandas as pd
from google.cloud.storage import Blob

from app import NEM12_STORAGE_PATH_IN, NEM12_STORAGE_PATH_MERGED
from app.common import merge_df_to_db

def handle_nem12_blob_in(data, context, storage_client, bucket, blob_name, logger):
    """
    Handle blob events in path NEM12_STORAGE_PATH_IN, merges all NEM12 files in this path
    together and places in NEM12_STORAGE_PATH_MERGED path, one NMI per file.
    """

    logger.info(f"handle_nem12_blob_in(blob_name={blob_name})")
    nem12_blobs = [blob for blob in (storage_client.list_blobs(
        bucket_or_name=bucket, prefix=NEM12_STORAGE_PATH_IN)) if blob.name.endswith('.csv')]

    Path(
        f"/tmp/{NEM12_STORAGE_PATH_IN}").mkdir(parents=True, exist_ok=True)
    Path(
        f"/tmp/{NEM12_STORAGE_PATH_MERGED}").mkdir(parents=True, exist_ok=True)

    logger.info(
        f"Merging blobs [{str.join(',', [n12.name for n12 in nem12_blobs])}]")
    nem12_files = []
    for n12 in nem12_blobs:
        file_name = f"/tmp/{n12.name}"
        with open(file_name, 'wb') as file_obj:
            n12.download_to_file(file_obj)
            nem12_files.append(file_name)

    merger = Nem12Merger(nem12_files)
    nmi_meter_registers = merger.nmi_meter_registers

    if len(nmi_meter_registers) > 0:
        nmis = set([nmr.nmi for nmr in nmi_meter_registers])

        for nmi in nmis:
            tmp_file_name = f"/tmp/{NEM12_STORAGE_PATH_MERGED}/nem12_{nmi}.csv"
            logger.info(f"Writing to file_name={tmp_file_name}")

            with open(tmp_file_name, mode="w") as csv_file:
                csv_writer = csv.writer(csv_file, delimiter=',')
                nmrs = [nmr for nmr in nmi_meter_registers if nmr.nmi == nmi]
                for nmr in nmrs:
                    csv_writer.writerow(nmr.line_items)
                    for iday in nmr.interval_days:
                        csv_writer.writerow(iday.line_items)
                        for var_q in iday.variable_qualities:
                            csv_writer.writerow(var_q.line_items)

            new_blob_name = f"{NEM12_STORAGE_PATH_MERGED}/nem12_{nmi}.csv"
            logger.info(f"Writing to new_blob_name={new_blob_name}")
            new_blob = bucket.blob(new_blob_name)
            with open(tmp_file_name, mode="rb") as tmp_file_obj:
                new_blob.upload_from_file(
                    file_obj=tmp_file_obj, content_type='text/csv')

            os.remove(tmp_file_name)

def handle_nem12_blob_merged(data, context, storage_client, bucket, blob_name, root_collection_name, logger):
    """
    Handle blob events in path NEM12_STORAGE_PATH_MERGED, parses the NEM12 blob (from the blob event),
    groups consumption and generation data into dates and loads into Firestore.
    This function only handles one NMI per NEM12 file, pre-processed by handle_nem12_blob_in()
    """

    logger.info(f"handle_nem12_blob_merged(blob_name={blob_name})")

    Path(
        f"/tmp/{NEM12_STORAGE_PATH_MERGED}").mkdir(parents=True, exist_ok=True)

    blob = Blob(blob_name, bucket)

    nem12_files = []
    with open(f"/tmp/{blob_name}", 'wb') as file_obj:
        blob.download_to_file(file_obj)
        nem12_files.append(f"/tmp/{blob_name}")

    nem12_parser = Nem12Merger(nem12_files)
    nmi_meter_registers = nem12_parser.nmi_meter_registers

    if len(nmi_meter_registers) > 0:
        nmis = set([nmr.nmi for nmr in nmi_meter_registers])
        assert len(nmis) == 1, f"Expected only one NMI but found [{nmis}]"

        nmi = list(nmis)[0]

        flattened = nem12_parser.flatten_data()
        df_nem12 = pd.DataFrame(flattened)

        df_interval = df_nem12.groupby(['interval_date', 'interval']).agg(
            consumption_kwh=pd.NamedAgg(column='consumption', aggfunc='sum'),
            generation_kwh=pd.NamedAgg(column='generation', aggfunc='sum'),
            quality=pd.NamedAgg(column='quality', aggfunc='first'),
            interval_length=pd.NamedAgg(
                column='interval_length', aggfunc='first'),
            uom=pd.NamedAgg(column='uom', aggfunc='first'),
        )
        df_interval['generation_kwh'] = df_interval['generation_kwh'].abs()
        df_agged_to_day = df_interval.groupby(['interval_date']).agg(
            meter_consumptions_kwh=pd.NamedAgg(
                column='consumption_kwh', aggfunc=list),
            meter_generations_kwh=pd.NamedAgg(
                column='generation_kwh', aggfunc=list),
            meter_data_qualities=pd.NamedAgg(column='quality', aggfunc=list),
        )

        merge_df_to_db(nmi, df_agged_to_day, root_collection_name, logger)

    for tmp_n12_file in nem12_files:
        os.remove(tmp_n12_file)

class Nem12Merger():
    """Naive implementation, only handles record 200, 300 and 400.
    For record 400 (VariableDayQuality), only the whole CSV line is parsed.
    All other record types are skipped.
    NEM12 file spec can be found here:
    https://www.aemo.com.au/consultations/current-and-closed-consultations/meter-data-file-format-specification-nem12-and-nem13/
    """

    def __init__(self, nem12_files):
        self.nem12_files = nem12_files
        self.nmi_meter_registers = []
        self.current_nmr = None
        self.current_iday = None
        self._parse()

    def _parse(self):
        for nem12_file in self.nem12_files:
            with open(nem12_file) as csv_file:
                csv_reader = csv.reader(csv_file, delimiter=',')
                for row in csv_reader:
                    if row[0] == '200':
                        nmi = row[1]
                        register = row[3]
                        meter = row[6]
                        register_config = row[2]
                        uom = row[7]
                        interval_length = int(row[8])
                        row_nmr = NmiMeterRegister(
                            nmi, meter, register, register_config, uom, interval_length, row)
                        existing_nmr = next(
                            (nmr for nmr in self.nmi_meter_registers if nmr == row_nmr), None)
                        if existing_nmr is None:
                            existing_nmr = row_nmr
                            self.nmi_meter_registers.append(existing_nmr)
                        self.current_nmr = existing_nmr

                    elif row[0] == '300':
                        interval_count = 1440 / self.current_nmr.interval_length
                        interval_date = datetime.strptime(
                            row[1], '%Y%m%d')
                        quality = row[int(interval_count + 2)]
                        row_iday = IntervalDay(
                            self.current_nmr, interval_date, quality, row)
                        existing_iday = next(
                            (iday for iday in self.current_nmr.interval_days if iday == row_iday), None)
                        if existing_iday is None:
                            existing_iday = row_iday
                            existing_iday.interval_values = [
                                float(iv) for iv in row[2:int(interval_count + 2)]]
                            self.current_nmr.interval_days.append(
                                existing_iday)
                        self.current_iday = existing_iday

                    elif row[0] == '400':
                        row_var_quality = VariableDayQuality(
                            self.current_iday, "".join(row), row)
                        existing_var_quality = next(
                            (vq for vq in self.current_iday.variable_qualities if vq == row_var_quality), None)
                        if existing_var_quality is None:
                            existing_var_quality = row_var_quality
                            self.current_iday.variable_qualities.append(
                                existing_var_quality)

                    else:
                        print(f"skipping record type {row[0]}")

    def flatten_data(self):
        """
        This implementation assumes the following:
        * input and output interval_length = 30
        * input and output UOM is KWH
        * input registers starts with either E or B to represent consumption or generation respectively, all other streams (e.g. K, Q) result in 0.0 value

        Returns:
        * Flattenned representation of interval values with parent keys (e.g. nmi, meter, register, interval_date) associated.
        * This representation is intended for convenient Pandas DataFrame creation.
        """
        result = []

        for nmr in self.nmi_meter_registers:
            uom = nmr.uom
            interval_length = nmr.interval_length
            assert uom == 'KWH', f"Current implementation only supports KWH but got uom={uom}"
            assert interval_length == 30, f"Current implementation only supports interval length of 30 minutes but got interval_length={interval_length}"

            for iday in nmr.interval_days:

                for i, value in enumerate(iday.interval_values):

                    result.append({
                        'nmi': nmr.nmi,
                        'meter': nmr.meter,
                        'register': nmr.register,
                        'interval_date': iday.interval_date,
                        'quality': iday.quality,
                        'interval_length': nmr.interval_length,
                        'uom': nmr.uom,
                        'interval': i+1,
                        'consumption': value if nmr.register.startswith('E') else 0.0,
                        'generation': value if nmr.register.startswith('B') else 0.0,
                    })

        return result

class NmiMeterRegister():
    def __init__(self, nmi, meter, register, register_config, uom, interval_length, line_items):
        self.nmi = nmi
        self.meter = meter
        self.register = register
        self.register_config = register_config
        self.uom = uom
        self.interval_length = interval_length
        self.interval_days = []
        self.line_items = line_items

    def __eq__(self, other):
        if not isinstance(other, NmiMeterRegister):
            return False
        else:
            return self.nmi == other.nmi and self.meter == other.meter and self.register == other.register and self.register_config == other.register_config

    def __repr__(self):
        return f"nmi={self.nmi},meter={self.meter},register={self.register},register_config={self.register_config},uom={self.uom},len(interval_days)={len(self.interval_days)}"

    def __str__(self):
        return self.__repr__()

class IntervalDay():
    def __init__(self, nmi_meter_register, interval_date, quality, line_items):
        self.nmi_meter_register = nmi_meter_register
        self.interval_date = interval_date
        self.quality = quality
        self.interval_values = []
        self.variable_qualities = []
        self.line_items = line_items

    def get_interval_length(self):
        return self.nmi_meter_register.interval_length

    def __eq__(self, other):
        if not isinstance(other, IntervalDay):
            return False
        else:
            return self.nmi_meter_register == other.nmi_meter_register and self.interval_date == other.interval_date

    def __repr__(self):
        return f"nmi_meter_register={self.nmi_meter_register},interval_date={self.interval_date},len(interval_values)={len(self.interval_values)},len(variable_qualities)={len(self.variable_qualities)}"

    def __str__(self):
        return self.__repr__()

class VariableDayQuality():
    def __init__(self, interval_day, line_str, line_items):
        self.interval_day = interval_day
        self.line_str = line_str
        self.line_items = line_items

    def __eq__(self, other):
        if not isinstance(other, VariableDayQuality):
            return False
        else:
            return self.interval_day == other.interval_day and self.line_str == other.line_str

    def __repr__(self):
        return f"interval_day={self.interval_day},line_str={self.line_str}"

    def __str__(self):
        return self.__repr__()


# coding: utf-8

"""
    DocuSign REST API

    The DocuSign REST API provides you with a powerful, convenient, and simple Web services API for interacting with DocuSign.  # noqa: E501

    OpenAPI spec version: v2.1
    Contact: devcenter@docusign.com
    Generated by: https://github.com/swagger-api/swagger-codegen.git
"""

import pprint
import re  # noqa: F401

import six

from docusign_esign.client.configuration import Configuration

class WorkflowStep(object):
    """NOTE: This class is auto generated by the swagger code generator program.

    Do not edit the class manually.
    """

    """
    Attributes:
      swagger_types (dict): The key is attribute name
                            and the value is attribute type.
      attribute_map (dict): The key is attribute name
                            and the value is json key in definition.
    """
    swagger_types = {
        'action': 'str',
        'completed_date': 'str',
        'delayed_routing': 'DelayedRouting',
        'item_id': 'str',
        'recipient_routing': 'RecipientRouting',
        'status': 'str',
        'triggered_date': 'str',
        'trigger_on_item': 'str',
        'workflow_step_id': 'str'
    }

    attribute_map = {
        'action': 'action',
        'completed_date': 'completedDate',
        'delayed_routing': 'delayedRouting',
        'item_id': 'itemId',
        'recipient_routing': 'recipientRouting',
        'status': 'status',
        'triggered_date': 'triggeredDate',
        'trigger_on_item': 'triggerOnItem',
        'workflow_step_id': 'workflowStepId'
    }

    def __init__(self, _configuration=None, **kwargs):  # noqa: E501
        """WorkflowStep - a model defined in Swagger"""  # noqa: E501
        if _configuration is None:
            _configuration = Configuration()
        self._configuration = _configuration

        self._action = None
        self._completed_date = None
        self._delayed_routing = None
        self._item_id = None
        self._recipient_routing = None
        self._status = None
        self._triggered_date = None
        self._trigger_on_item = None
        self._workflow_step_id = None
        self.discriminator = None

        setattr(self, "_{}".format('action'), kwargs.get('action', None))
        setattr(self, "_{}".format('completed_date'), kwargs.get('completed_date', None))
        setattr(self, "_{}".format('delayed_routing'), kwargs.get('delayed_routing', None))
        setattr(self, "_{}".format('item_id'), kwargs.get('item_id', None))
        setattr(self, "_{}".format('recipient_routing'), kwargs.get('recipient_routing', None))
        setattr(self, "_{}".format('status'), kwargs.get('status', None))
        setattr(self, "_{}".format('triggered_date'), kwargs.get('triggered_date', None))
        setattr(self, "_{}".format('trigger_on_item'), kwargs.get('trigger_on_item', None))
        setattr(self, "_{}".format('workflow_step_id'), kwargs.get('workflow_step_id', None))

    @property
    def action(self):
        """Gets the action of this WorkflowStep.  # noqa: E501

          # noqa: E501

        :return: The action of this WorkflowStep.  # noqa: E501
        :rtype: str
        """
        return self._action

    @action.setter
    def action(self, action):
        """Sets the action of this WorkflowStep.

          # noqa: E501

        :param action: The action of this WorkflowStep.  # noqa: E501
        :type: str
        """

        self._action = action

    @property
    def completed_date(self):
        """Gets the completed_date of this WorkflowStep.  # noqa: E501

          # noqa: E501

        :return: The completed_date of this WorkflowStep.  # noqa: E501
        :rtype: str
        """
        return self._completed_date

    @completed_date.setter
    def completed_date(self, completed_date):
        """Sets the completed_date of this WorkflowStep.

          # noqa: E501

        :param completed_date: The completed_date of this WorkflowStep.  # noqa: E501
        :type: str
        """

        self._completed_date = completed_date

    @property
    def delayed_routing(self):
        """Gets the delayed_routing of this WorkflowStep.  # noqa: E501

        A complex element that specifies the delayed routing settings for the workflow step.  # noqa: E501

        :return: The delayed_routing of this WorkflowStep.  # noqa: E501
        :rtype: DelayedRouting
        """
        return self._delayed_routing

    @delayed_routing.setter
    def delayed_routing(self, delayed_routing):
        """Sets the delayed_routing of this WorkflowStep.

        A complex element that specifies the delayed routing settings for the workflow step.  # noqa: E501

        :param delayed_routing: The delayed_routing of this WorkflowStep.  # noqa: E501
        :type: DelayedRouting
        """

        self._delayed_routing = delayed_routing

    @property
    def item_id(self):
        """Gets the item_id of this WorkflowStep.  # noqa: E501

          # noqa: E501

        :return: The item_id of this WorkflowStep.  # noqa: E501
        :rtype: str
        """
        return self._item_id

    @item_id.setter
    def item_id(self, item_id):
        """Sets the item_id of this WorkflowStep.

          # noqa: E501

        :param item_id: The item_id of this WorkflowStep.  # noqa: E501
        :type: str
        """

        self._item_id = item_id

    @property
    def recipient_routing(self):
        """Gets the recipient_routing of this WorkflowStep.  # noqa: E501

        The rules for recipient routing.  # noqa: E501

        :return: The recipient_routing of this WorkflowStep.  # noqa: E501
        :rtype: RecipientRouting
        """
        return self._recipient_routing

    @recipient_routing.setter
    def recipient_routing(self, recipient_routing):
        """Sets the recipient_routing of this WorkflowStep.

        The rules for recipient routing.  # noqa: E501

        :param recipient_routing: The recipient_routing of this WorkflowStep.  # noqa: E501
        :type: RecipientRouting
        """

        self._recipient_routing = recipient_routing

    @property
    def status(self):
        """Gets the status of this WorkflowStep.  # noqa: E501

        Indicates the envelope status. Valid values are:  * sent - The envelope is sent to the recipients.  * created - The envelope is saved as a draft and can be modified and sent later.  # noqa: E501

        :return: The status of this WorkflowStep.  # noqa: E501
        :rtype: str
        """
        return self._status

    @status.setter
    def status(self, status):
        """Sets the status of this WorkflowStep.

        Indicates the envelope status. Valid values are:  * sent - The envelope is sent to the recipients.  * created - The envelope is saved as a draft and can be modified and sent later.  # noqa: E501

        :param status: The status of this WorkflowStep.  # noqa: E501
        :type: str
        """

        self._status = status

    @property
    def triggered_date(self):
        """Gets the triggered_date of this WorkflowStep.  # noqa: E501

          # noqa: E501

        :return: The triggered_date of this WorkflowStep.  # noqa: E501
        :rtype: str
        """
        return self._triggered_date

    @triggered_date.setter
    def triggered_date(self, triggered_date):
        """Sets the triggered_date of this WorkflowStep.

          # noqa: E501

        :param triggered_date: The triggered_date of this WorkflowStep.  # noqa: E501
        :type: str
        """

        self._triggered_date = triggered_date

    @property
    def trigger_on_item(self):
        """Gets the trigger_on_item of this WorkflowStep.  # noqa: E501

          # noqa: E501

        :return: The trigger_on_item of this WorkflowStep.  # noqa: E501
        :rtype: str
        """
        return self._trigger_on_item

    @trigger_on_item.setter
    def trigger_on_item(self, trigger_on_item):
        """Sets the trigger_on_item of this WorkflowStep.

          # noqa: E501

        :param trigger_on_item: The trigger_on_item of this WorkflowStep.  # noqa: E501
        :type: str
        """

        self._trigger_on_item = trigger_on_item

    @property
    def workflow_step_id(self):
        """Gets the workflow_step_id of this WorkflowStep.  # noqa: E501

          # noqa: E501

        :return: The workflow_step_id of this WorkflowStep.  # noqa: E501
        :rtype: str
        """
        return self._workflow_step_id

    @workflow_step_id.setter
    def workflow_step_id(self, workflow_step_id):
        """Sets the workflow_step_id of this WorkflowStep.

          # noqa: E501

        :param workflow_step_id: The workflow_step_id of this WorkflowStep.  # noqa: E501
        :type: str
        """

        self._workflow_step_id = workflow_step_id

    def to_dict(self):
        """Returns the model properties as a dict"""
        result = {}

        for attr, _ in six.iteritems(self.swagger_types):
            value = getattr(self, attr)
            if isinstance(value, list):
                result[attr] = list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[attr] = value.to_dict()
            elif isinstance(value, dict):
                result[attr] = dict(map(
                    lambda item: (item[0], item[1].to_dict())
                    if hasattr(item[1], "to_dict") else item,
                    value.items()
                ))
            else:
                result[attr] = value
        if issubclass(WorkflowStep, dict):
            for key, value in self.items():
                result[key] = value

        return result

    def to_str(self):
        """Returns the string representation of the model"""
        return pprint.pformat(self.to_dict())

    def __repr__(self):
        """For `print` and `pprint`"""
        return self.to_str()

    def __eq__(self, other):
        """Returns true if both objects are equal"""
        if not isinstance(other, WorkflowStep):
            return False

        return self.to_dict() == other.to_dict()

    def __ne__(self, other):
        """Returns true if both objects are not equal"""
        if not isinstance(other, WorkflowStep):
            return True

        return self.to_dict() != other.to_dict()


import numpy as np

class NaiveBayes(object):
	def __init__(self,num_class,feature_dim,num_value):
		"""Initialize a naive bayes model.

		This function will initialize prior and likelihood, where
		prior is P(class) with a dimension of (# of class,)
			that estimates the empirical frequencies of different classes in the training set.
		likelihood is P(F_i = f | class) with a dimension of
			(# of features/pixels per image, # of possible values per pixel, # of class),
			that computes the probability of every pixel location i being value f for every class label.

		Args:
		    num_class(int): number of classes to classify
		    feature_dim(int): feature dimension for each example
		    num_value(int): number of possible values for each pixel
		"""

		self.num_value = num_value
		self.num_class = num_class
		self.feature_dim = feature_dim

		self.prior = np.zeros((num_class))
		self.likelihood = np.zeros((feature_dim,num_value,num_class))

	def train(self,train_set,train_label):
		""" Train naive bayes model (self.prior and self.likelihood) with training dataset.
			self.prior(numpy.ndarray): training set class prior (in log) with a dimension of (# of class,),
			self.likelihood(numpy.ndarray): traing set likelihood (in log) with a dimension of
				(# of features/pixels per image, # of possible values per pixel, # of class).
			You should apply Laplace smoothing to compute the likelihood.

		Args:
		    train_set(numpy.ndarray): training examples with a dimension of (# of examples, feature_dim)
		    train_label(numpy.ndarray): training labels with a dimension of (# of examples, )
		"""

		# YOUR CODE HERE

		# Calculate likelihood
		for label in range(len(train_label)):
			# Calculate priors
			self.prior[train_label[label]] += 1
			for pixel in range(len(train_set[label])):
				# print("Training")
				# Calculate likelihood
				self.likelihood[pixel, int(train_set[label][pixel]), train_label[label]] += 1

		# Laplace smoothing
		# for k in range (0.1, 10, 0.1):
		k = 1
		for i in range(self.num_class):
			# print("Smoothing")
			self.likelihood[:,:,i] = (self.likelihood[:,:,i]+k)/(self.prior[i]+self.num_value*k)

		# Take the log to avoid underflow during testing
		self.likelihood = np.log(self.likelihood)
		self.prior = np.log(self.prior/len(train_label))
		print("End of training")
		pass

	def test(self,test_set,test_label):
		""" Test the trained naive bayes model (self.prior and self.likelihood) on testing dataset,
			by performing maximum a posteriori (MAP) classification.
			The accuracy is computed as the average of correctness
			by comparing between predicted label and true label.

		Args:
		    test_set(numpy.ndarray): testing examples with a dimension of (# of examples, feature_dim)
		    test_label(numpy.ndarray): testing labels with a dimension of (# of examples, )

		Returns:
			accuracy(float): average accuracy value
			pred_label(numpy.ndarray): predicted labels with a dimension of (# of examples, )
		"""

		# YOUR CODE HERE

		accuracy = 0
		pred_label = np.zeros((len(test_set)))

		'''
		posterior_prob_matrix = np.ndarray((len(test_set), self.num_class))

		for i in range(len(test_set)):
			for j in range(self.num_class):
				print("Testing")
				posterior_prob_matrix[i][j] = self.prior[j]
				posterior_prob_matrix[i][j] += np.sum(self.likelihood[np.arange(self.feature_dim),int(test_set[i][j]),j])
			pred_label[i] = np.argmax(posterior_prob_matrix[i])

		accuracy = (len(test_set) - np.count_nonzero(pred_label - test_label))/len(test_set)
		'''

		for i in range(len(test_label)):
 			evaluation = np.zeros(self.num_class)
 			for j in range(self.num_class):
 				evaluation[j] = self.prior[j]
 				for k in range(self.feature_dim):
 					evaluation[j] += self.likelihood[k, int(test_set[i][k]), j]
 			pred_label[i] = np.argmax(evaluation)
 			if (pred_label[i] == test_label[i]): accuracy += 1

		accuracy /= len(test_set)
		print("Accuracy:", accuracy)
		print("End of testing")
		return accuracy, pred_label

	def save_model(self, prior, likelihood):
		""" Save the trained model parameters
		"""

		np.save(prior, self.prior)
		np.save(likelihood, self.likelihood)

	def load_model(self, prior, likelihood):
		""" Load the trained model parameters
		"""

		self.prior = np.load(prior)
		self.likelihood = np.load(likelihood)

	def intensity_feature_likelihoods(self, likelihood):
	    """
	    Get the feature likelihoods for high intensity pixels for each of the classes,
	        by sum the probabilities of the top 128 intensities at each pixel location,
	        sum k<-128:255 P(F_i = k | c).
	        This helps generate visualization of trained likelihood images.

	    Args:
	        likelihood(numpy.ndarray): likelihood (in log) with a dimension of
	            (# of features/pixels per image, # of possible values per pixel, # of class)
	    Returns:
	        feature_likelihoods(numpy.ndarray): feature likelihoods for each class with a dimension of
	            (# of features/pixels per image, # of class)
	    """
	    # YOUR CODE HERE
	    print("Get the feature likelihoods for high intensity pixels")
	    return np.sum(np.exp(likelihood[:,128:,:]), axis = 1)


import peewee as pw
from pytest import mark

from database.db import Database
from database.models import (
    Asset,
    Category,
    Project,
)

class TestAssets:
    def setup(self):
        self.test_db = Database()
        self.category_data = {
            "name": "FX",
            "description": "Effects",
        }
        self.project_data = {
            "name": "Super Good",
            "short_name": "SG",
            "description": "Sequel to Good",
        }
        self.category = Category.create(**self.category_data)
        self.project = Project.create(**self.project_data)

    def test_create_asset(self):
        asset_name = "Explosion"
        asset_desc = "Fire Magic"
        asset_short_name = "EXP"
        asset_data = {
            "category": self.category.id,
            "description": asset_desc,
            "name": asset_name,
            "short_name": asset_short_name,
            "project": self.project.id,
        }

        Asset.create(**asset_data)
        a = Asset.get(**asset_data)
        assert a.name == asset_name
        assert a.description == asset_desc
        assert a.short_name == asset_short_name
        assert a.category.name == "FX"
        assert a.project.name == "Super Good"
        assert str(a) == "fEXP"


import os
import shutil

import cv2
import cv2.face
import numpy

class FaceRecognizer:
    def __init__(self, settings):
        self.training_file_name = 'training.xml'
        self.cascade_file_name = 'haarcascade_frontalface_alt.xml'
        self.training_image_directory = 'training_images'
        self.training_user = None
        self.training_user_iteration = None
        self.settings = settings

        self.model = None
        if os.path.isfile(self.training_file_name):
            self.model = cv2.face.LBPHFaceRecognizer_create(threshold=self.settings.recognition_threshold)
            self.model.load(self.training_file_name)

        self.cascade_classifier = cv2.CascadeClassifier(self.cascade_file_name)

    def detect_faces(self, image):
        image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

        faces = self.cascade_classifier.detectMultiScale(image, scaleFactor=1.2, minNeighbors=3, minSize=(200, 200),
                                                        flags=cv2.CASCADE_SCALE_IMAGE)

        detected_faces = []
        for face in faces:
            x, y, w, h = face
            image_face = numpy.copy(image)
            image_face = image_face[y:y + h, x:x + w]

            label = -1
            if self.model is not None:
                try:
                    label, confidence = self.model.predict(image_face)
                except:
                    label = -1

            detected_faces.append(type('obj', (object,), {'user': str(label), 'x': x, 'y': y, 'w': w, 'h': h}))

        return detected_faces

    def init_new_face(self):
        if not os.path.exists(self.training_image_directory):
            os.makedirs(self.training_image_directory)

        i = 0
        while True:
            i += 1
            potential_directory = os.path.join(self.training_image_directory, '%03d' % i)
            if not os.path.exists(potential_directory):
                os.makedirs(potential_directory)
                self.training_user = i
                self.training_user_iteration = 0
                break

    def add_new_face(self, image):
        if self.training_user is None or self.training_user_iteration is None:
            return False, "Face training was not initiated."

        faces = self.detect_faces(image)
        if len(faces) == 0:
            return False, "No face detected."
        elif len(faces) > 1:
            return False, "More than one face detected."

        face = faces[0]
        cropped = image[face.y:face.y + face.h, face.x:face.x + face.w]
        filename = os.path.join(self.training_image_directory, '%03d' % self.training_user,
                                '%03d.pgm' % self.training_user_iteration)
        cv2.imwrite(filename, cropped)
        self.training_user_iteration += 1
        return True, ""

    def train_faces(self):
        self.training_user = None
        self.training_user_iteration = None

        training_model = cv2.face.LBPHFaceRecognizer_create()
        images = []
        labels = []
        for directory in os.listdir(self.training_image_directory):
            joined_directory = os.path.join(self.training_image_directory, directory)
            if os.path.isdir(joined_directory):
                for image_file in os.listdir(joined_directory):
                    joined_file = os.path.join(joined_directory, image_file)
                    image = cv2.imread(joined_file, cv2.IMREAD_GRAYSCALE)
                    images.append(image)
                    labels.append(int(directory))
        training_model.train(numpy.asarray(images), numpy.asarray(labels))
        training_model.save(self.training_file_name)
        self.model = training_model

    def delete_training(self):
        if os.path.isdir(self.training_image_directory):
            shutil.rmtree(self.training_image_directory)
        if os.path.isfile(self.training_file_name):
            os.remove(self.training_file_name)
        self.model = None


from typing import Callable, Any
import functools

def how_are_you(func: Callable) -> Callable:
    # top = True  # если переменная в коде не используется, стоит её удалить =)

    @functools.wraps(func)
    def wrapped_func(*args, **kwargs) -> Any:
        input('Как дела? ')
        print('А у меня не очень! Ладно, держи свою функцию.')
        result = func(*args, **kwargs)
        return result

    return wrapped_func

@how_are_you
def test():
    print('<Тут что-то происходит...>')

@how_are_you
def print_number(num):
    if num == 0:
        return
    for i_num in range(num):
        print(i_num)

test()

print_number(3)

# зачёт!


def read4():
    return None

"""
Given a file and assume that you can only read the file using
a given method read4, implement a method to read n characters.

The read4 API is already defined for you.

    @param buf4, a list of characters
    @return an integer
    def read4(buf4):

# Below is an example of how the read4 API can be called.
file = File("abcdefghijk") # File is "abcdefghijk", initially file pointer (fp) points to 'a'
buf4 = [' '] * 4 # Create buffer with enough space to store characters
read4(buf4) # read4 returns 4. Now buf = ['a','b','c','d'], fp points to 'e'
read4(buf4) # read4 returns 4. Now buf = ['e','f','g','h'], fp points to 'i'
read4(buf4) # read4 returns 3. Now buf = ['i','j','k',...], fp points to end of file
"""

class Solution:
    def read(self, buf, n):
        """
        :type buf: Destination buffer (List[str])
        :type n: Number of characters to read (int)
        :rtype: The number of actual characters read (int)

        1. dont get confused with question description, our final buf will have min( n, all the characters that are in file)
        2. At any point buf4, will maximum of 4 characters or count returned from the read4.
        3. As I can read utmost 4 chars at a time, I create an array of size 4 and pass it to the function read4(buf4).
        That read4 function will fill my buf4 and returns the count how many characters it filled.
        4. I take those buf4 chars filled and append it to my final buf.
        """

        buf4 = [''] * 4
        read = 0
        while read < n:
            count = read4(buf4)             # Read file into buf4 && count -> num of chars in buf4
            if not count: break             # no of chars to read, EOF
            count = min(count, n - read)    # if n = 5 and file size is 8, in second read you have to take only n-read i.e 5-4 = 1
            buf[read:] = buf4[:count]       # Copy from buf4 to buf.
            read += count
        return read                         # we have return total num of characters read

0157 - (1) - Read N Characters Given Read4.py


import random

from cosmpy.aerial.client import LedgerClient
from cosmpy.aerial.config import NetworkConfig
from cosmpy.aerial.faucet import FaucetApi
from cosmpy.aerial.tx_helpers import SubmittedTx
from cosmpy.aerial.wallet import LocalWallet

def _wait_for_tx(operation: str, tx: SubmittedTx):
    print(f"Waiting for {operation} to complete... (tx: {tx.tx_hash})")
    tx.wait_to_complete()
    print(f"Waiting for {operation} to complete... done")

def main():
    """Run main."""
    alice = LocalWallet.generate()

    ledger = LedgerClient(NetworkConfig.fetchai_stable_testnet())
    faucet_api = FaucetApi(NetworkConfig.fetchai_stable_testnet())

    alice_balance = ledger.query_bank_balance(alice.address())

    while alice_balance < (10**18):
        print("Providing wealth to alice...")
        faucet_api.get_wealth(alice.address())
        alice_balance = ledger.query_bank_balance(alice.address())

    # get all the active validators on the network
    validators = ledger.query_validators()

    # randomly choose one to stake to (this is a BAD idea generally, but fine for this example)
    first_validator = random.choice(validators)  # nosec

    # delegate some tokens to this validator
    tx = ledger.delegate_tokens(first_validator.address, 20, alice)
    _wait_for_tx("delegate", tx)

    # select another validator to redelegate to (again, not a good idea in general)
    second_validator = random.choice(  # nosec
        list(
            filter(
                lambda v: v.address != first_validator.address,
                validators,
            )
        )
    )

    # redelegate the tokens
    tx = ledger.redelegate_tokens(
        first_validator.address, second_validator.address, 10, alice
    )
    _wait_for_tx("redelegate", tx)

    # undelegate the tokens
    tx = ledger.undelegate_tokens(first_validator.address, 5, alice)
    _wait_for_tx("undelegate", tx)

    summary = ledger.query_staking_summary(alice.address())
    print(
        f"Summary: Staked: {summary.total_staked} Unbonding: {summary.total_unbonding} Rewards: {summary.total_rewards}"
    )

    # finally, lets collect up all the rewards we have earned so far
    claimed = False
    for position in summary.current_positions:
        if position.reward > 0:
            claimed = True

            tx = ledger.claim_rewards(position.validator, alice)
            _wait_for_tx(f"claim from {str(position.validator)}", tx)

    if claimed:
        summary = ledger.query_staking_summary(alice.address())
        print(
            f"Summary: Staked: {summary.total_staked} Unbonding: {summary.total_unbonding} Rewards: {summary.total_rewards}"
        )

if __name__ == "__main__":
    main()


## Basic Python libraries
import argparse
import sys
import os
sys.path.append(os.getcwd() + '/')

## Deep learning and array processing libraries
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
import torchvision.datasets as datasets

## Inner-Project Imports
from base_classifiers.architectures import small_cnn, resnet18
from utils.transforms import *
from davis_utils.estimation import estimation
from davis_utils.inference import inference

def arguments():
    parser = argparse.ArgumentParser(description='Training baseline classifier')
    parser.add_argument('--image_dir', '-I',
                        default='', type=str,
                        metavar='ID', help='location of image data')
    parser.add_argument('--network_path', '-NP',
                        default='', type=str,
                        metavar='NET', help='path to network pth file')
    parser.add_argument('--tree_path', '-TP',
                        default='', type=str,
                        metavar='NET', help='path to tree txt file')
    parser.add_argument('--results_dir', '-R',
                        default='', type=str,
                        metavar='RD', help='location to save results')
    parser.add_argument('--dataset', '--data', '-d',
                        default='tomato', type=str,
                        metavar='DATA', help='name of data set')
    parser.add_argument('--name',
                        default='', type=str,
                        metavar='NAME', help='name of experiment')
    parser.add_argument('--network', '-n',
                        default='small_cnn', type=str,
                        metavar='N', choices=['small_cnn', 'resnet18'],
                        help='network architecture')
    parser.add_argument('--num_bins', '--nbins',
                        default=10, type=int,
                        metavar='NB', help='number of histogram bins')
    parser.add_argument('--priors', '-p',
                        default='equal', type=str,
                        metavar='P', choices=['equal', 'data', 'manual'],
                        help='what type of priors are we using')
    parser.add_argument('--confidence', '--conf',
                        default=0.5, type=float,
                        metavar='CONF', help='confidence threshold for inference procedure')
    parser.add_argument('--device', '--dev',
                        default='cuda:0', type=str,
                        metavar='DEV', choices=['cpu', 'cuda:0'],
                        help='device id (e.g. \'cpu\', \'cuda:0\'')
    parser.add_argument('--seed',
                        default=None, type=str,
                        metavar='S', help='set a seed for reproducability')
    args = vars(parser.parse_args())

    # Ensure necessary paths have been provided
    assert args['image_dir'] != '', f'Must provide a path to an image directory for {args["dataset"]}'
    assert os.path.exists(args['network_path']), f'Must provide a path to a network pth file for {args["dataset"]}'
    assert os.path.exists(args['tree_path']), f'Must provide a path to a tree txt file for {args["dataset"]}'
    assert args['results_dir'] != '', f'Must provide a path to a results directory for {args["dataset"]}'

    # Create the experiment name
    args['name'] = f'{args["dataset"]}_test' if args['name'] == '' else args['name']

    # Ensure we don't accidentally overwrite anything by checking how many previous experiments share the same name
    directories = [name for name in os.listdir(os.path.abspath(args['results_dir'])) if os.path.isdir(f'{args["results_dir"]}{name}') and args['name'] in name]
    num = len(directories)
    args['name'] = f'{args["name"]}_{num}'

    assert args['num_bins'] > 1, 'Number of histograms should be more than 1'
    assert 0 <= args['confidence'] <= 1, 'Confidence threshold must be between 0 and 1 (inclusive)'

    # Set the device
    if 'cuda' in args['device']:
        assert torch.cuda.is_available(), 'Device set to GPU but CUDA not available'
    args['device'] = torch.device(args['device'])

    # Set a seed if provided
    if args['seed'] is not None:
        args['seed'] = int(args['seed'])
        torch.manual_seed(args['seed'])
        torch.backends.cudnn.deterministic = True
        torch.backends.cudnn.benchmark = False
        np.random.seed(args['seed'])

    return args

if __name__ == '__main__':
    # Get arguments
    args = arguments()

    # Create the data transforms for each respective set
    if args['dataset'] == 'tomato':
        transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])
    elif args['dataset'] == 'corn' or args['dataset'] == 'soybean':
        transform = transforms.Compose([AdaptiveCenterCrop(), Resize(size=345),
                                        transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])
    else:
        raise Exception('Dataset not yet supported')

    # Create the data sets
    train_dataset = datasets.ImageFolder(root=f'{args["image_dir"]}train/', transform=None)
    test_dataset = datasets.ImageFolder(root=f'{args["image_dir"]}test/', transform=transform)
    val_dataset = datasets.ImageFolder(root=f'{args["image_dir"]}val/', transform=transform)

    # Create the DataLoaders from the data sets
    train_dataloader = DataLoader(train_dataset, batch_size=1, shuffle=False)
    test_dataloader = DataLoader(test_dataset, batch_size=1, shuffle=False)
    val_dataloader = DataLoader(val_dataset, batch_size=1, shuffle=False)

    # Create the network and load network state dictionary
    num_classes = len(val_dataset.classes)
    if args['network'] == 'small_cnn':
        network = small_cnn.SmallCNN(num_classes)
    elif args['network'] == 'resnet18':
        network = resnet18.ResNet18(num_classes)
    network.load_state_dict(torch.load(args['network_path'], map_location='cpu'))
    network.eval()

    # Send to device (preferably GPU)
    network = network.to(args['device'])

    # Do the estimation on the validation data
    tree = estimation(tree_path=args['tree_path'], network=network, compute_device=args['device'], train_dataloader=train_dataloader,
                        val_dataloader=val_dataloader, nbins=args['num_bins'], priors=args['priors'])

    # Perform inference on the test data
    inference(confidence_threshold=args['confidence'], experiment=args['name'], tree=tree, network=network, compute_device=args['device'],
                dataloader=test_dataloader, nbins=args['num_bins'], results_directory=args['results_dir'], save_results=True)