from collections import deque
import sys
input = sys.stdin.readline

# 1) bfs 돌려서 4번 이상 가면 (같은 색) 1연쇄가 시작.
# 2) 연쇄 후 아래로 떨어지게 된다.

def bfs(i, j):
    global flag
    queue = deque()
    queue.append([i, j])

    pang = [[i, j]]
    visited[i][j] = True
    # cnt = 1

    while queue:
        x, y = queue.popleft()
        for k in range(4):
            nx, ny = x + dx[k], y + dy[k]
            if 0 <= nx < 12 and 0 <= ny < 6 and game_map[nx][ny] == game_map[i][j] and not visited[nx][ny]:
                visited[nx][ny] = True
                # cnt += 1
                pang.append([nx,ny])
                queue.append([nx,ny])
    # 쓰읍.. 무조건 같을 때 'pang'으로 바꿔줬더니 4개 이상 아닐 때 다시 되돌리기 힘드네..?
    # 그러면 4이상 됐을 때 바꿔줘야하는데 어떻게 할까
    # cnt로 개수를 세지말고 값을 넣어두고 그거의 len을 비교?
    # if cnt >= 4:
    # return cnt
    if len(pang) >= 4:
        flag = True
        for i, j in pang:
            game_map[i][j] = '.'

# 뿌요는 위에서 아래로 떨어짐 (중력)
# def drop_puyos():
#     for i in range(12):
#         for j in range(6):
#             if game_map[i][j] != '.' and i != 11:
#                 if game_map[i+1][j] == '.':
#                     game_map[i+1][j] = game_map[i][j]
#                     game_map[i][j] = '.'

# def drop_puyos():
#     # 11번 째는 떨어질 곳이 없으니깐 10부터 시작
#     for i in range(10,-1,-1):
#         for j in range(6):
#             if game_map[i][j] != '.':
#                 if game_map[i+1][j] == '.':
#                     game_map[i+1][j] = game_map[i][j]
#                     game_map[i][j] = '.'

def drop_puyos():
    # 세로 방향으로 생각해서 6줄 중에서
    for i in range(6):
        # 밑에서부터아래로 떨어뜨릴 뿌요 검색
        # 근데 가장 바닥에 있는 뿌요는 확인안해도 되기 때문에
        for j in range(10, -1, -1):
            # 밑에서 부터 뿌요가 있는 곳까지
            # game_map[j][i] != "." 뿌요가 있는 위치가 '.'이 아닌
            for k in range(11, j, -1):
                if game_map[j][i] != "." and game_map[k][i] == ".":
                    game_map[k][i] = game_map[j][i]
                    game_map[j][i] = "."
                    break

game_map = [list(input().strip()) for i in range(12)]
dx, dy = (0,1,0,-1), (1,0,-1,0)
cnt = 0

# bfs() 하고 drop() 반복하다가 멈춰야함
while True:
    flag = False
    visited = [[False]*6 for _ in range(12)]

    for i in range(12):
        for j in range(6):
            if game_map[i][j] != '.' and not visited[i][j]:
                bfs(i,j)

    # 다 돌았는데 아직도 bfs 결과가 False면 끝~
    if not flag:
        break
    drop_puyos()
    cnt += 1

print(cnt)


# -*- coding=utf-8 -*-
r"""
"""
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QTextEdit, QLineEdit, QPushButton, QCheckBox, QGridLayout, \
    QVBoxLayout
from PyQt5.QtGui import QFont
from PyQt5.QtCore import Qt

class ToDoList(QWidget):
    def __init__(self):
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        self.setGeometry(100, 100, 500, 350)
        self.setWindowTitle('ToDo List GUI')
        self.setupWidgets()
        self.show()

    def setupWidgets(self):
        main_grid = QGridLayout()
        todo_title = QLabel('To Do List')
        todo_title.setStyleSheet('border: 1px solid #ABCEFF;')
        todo_title.setFont(QFont('Arial', 24))
        todo_title.setAlignment(Qt.AlignCenter)

        close_button = QPushButton('Close')
        close_button.clicked.connect(self.close)

        mustdo_label = QLabel('Must Dos')
        mustdo_label.setFont(QFont('Arial', 20))
        mustdo_label.setAlignment(Qt.AlignCenter)
        appts_label = QLabel('Appointments')
        appts_label.setFont(QFont('Arial', 20))
        appts_label.setAlignment(Qt.AlignCenter)

        mustdo_grid = QGridLayout()
        # print(mustdo_grid.setSpacing(0))
        mustdo_grid.setContentsMargins(5, 5, 5, 50)
        mustdo_grid.addWidget(mustdo_label, 0, 0, 1, 2)

        for position in range(1, 15):
            checkbox = QCheckBox()
            checkbox.setChecked(False)
            lineEdit = QLineEdit()
            lineEdit.setMinimumWidth(200)
            mustdo_grid.addWidget(checkbox, position, 0)
            mustdo_grid.addWidget(lineEdit, position, 1)

        morning_label = QLabel('Morning')
        morning_label.setFont(QFont('Arial', 16))
        morning_entry = QTextEdit()
        noon_label = QLabel('Noon')
        noon_label.setFont(QFont('Arial', 16))
        noon_entry = QTextEdit()
        evening_label = QLabel('Evening')
        evening_label.setFont(QFont('Arial', 16))
        evening_entry = QTextEdit()

        appt_v_box = QVBoxLayout()
        appt_v_box.setContentsMargins(5, 5, 5, 5)
        appt_v_box.addWidget(appts_label)
        appt_v_box.addWidget(morning_label)
        appt_v_box.addWidget(morning_entry)
        appt_v_box.addWidget(noon_label)
        appt_v_box.addWidget(noon_entry)
        appt_v_box.addWidget(evening_label)
        appt_v_box.addWidget(evening_entry)

        main_grid.addWidget(todo_title, 0, 0, 1, 2)
        main_grid.addLayout(mustdo_grid, 1, 0)
        main_grid.addLayout(appt_v_box, 1, 1)
        main_grid.addWidget(close_button, 2, 0, 1, 2)

        self.setLayout(main_grid)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = ToDoList()
    sys.exit(app.exec())


import player
import deck
import board
import random

# Game Class
class Game:

    # Init
    def __init__(self, playerList):
        # Take player list input and order it so team members are spaced every-other
        sortedPlayers = sorted(playerList, key=lambda player: player.team) # Sort by team e.g. 1,1,1,2,2,2
        numPlayers = len(playerList)
        everyOtherSlices = [slice(i,None,numPlayers//2) for i in range(numPlayers//2)] # Each slice has a player from both teams
        self.playerList = [player for pairSlice in everyOtherSlices
                                  for player in sortedPlayers[pairSlice]] # Combine all slices to make ordered list
        self.turn = 0
        self.deck = deck.Deck()
        random.shuffle(self.deck)
        self.board = board.Board(self.playerList)
        # self.board.printBoard()

    # Setters
    def nextTurn(self):
        self.turn = self.turn+1 if self.turn<len(self.playerList)-1 else 0

    # Getters
    def getAllPlayerNames(self):
        nameList = []
        for player in self.playerList:
            nameList.append(player.getName())
        return nameList
    def getPlayers(self):
        return self.playerList
    def getCurrentPlayer(self):
        return self.playerList[self.turn]
    def getDeck(self):
        return self.deck
    def getBoard(self):
        return self.board

    # Printers
    def printCurrentPlayer(self):
        print ("Current player is: "+self.getCurrentPlayer().getName())

    # Card Methods
    def dealHands(self):
        for player in self.playerList:
            for i in range(5):
                player.addCard(self.deck.popCard())
    def printHand(self,player):
        print(player.getName()+"'s hand is:")
        player.printHand()

    # Gameplay functions
    def playGame(self):
        while (True):
            self.dealHands()
            # while (True):
            for i in range(len(self.playerList)*self.getCurrentPlayer().getHandLen()):
                self.printCurrentPlayer()
                currentPlayer = self.getCurrentPlayer()
                self.printHand(currentPlayer)
                # Prompt for card to play
                canPlay = True if (input("Can you play? (y/n) ")=="y") else False
                if (canPlay):
                    cardIdx = int(input("Enter card index: "))
                    marbIdx = int(input("Enter marb index: "))
                    # Play card
                    self.board.playCard(currentPlayer.getName(),marbIdx,currentPlayer.getCard(cardIdx).getValue())
                else:
                    currentPlayer.clearHand()
                # Show board
                self.board.printBoard()
                # Next player
                self.nextTurn()


import eventlet
import socketio

from pymongo import MongoClient

sio = socketio.Server()
app = socketio.WSGIApp(sio, static_files={
    '/': {'content_type': 'text/html', 'filename': 'index.html'}
})
client = MongoClient('localhost', 27017)
db = client["database"]
col = db["storage"]

def init():
    for i in range(3):
        n_dest = str(i+1)
        cur = list(col.find({'dest': n_dest}))
        if len(cur) == 0:
            _init = {'dest':n_dest, 'red':0, 'green':0, 'blue':0}
            col.insert_one(_init)
            print(f'inserted initial {n_dest} dict')

    eventlet.wsgi.server(eventlet.listen(('0.0.0.0', 8080)), app)

@sio.event
def connect(sid, environ):
    print('connected!! ', sid)
    #my_message(sid, {'Test': 'Message'})

@sio.event
def initialize_database(sid, environ):
    x = col.delete_many({})
    print('database initialized', sid)

@sio.event
def my_message(sid, data):
    #sio.send(data)
    print(f'received: {data}')

    dest = data['dest']
    color = data['color']
    _dict = list(col.find({'dest': str(dest)}))[0]

    print('before update: ')
    print(_dict)

    col.delete_one({'dest': str(dest)})
    _dict[color] += 1
    col.insert_one(_dict)

    _dict = list(col.find({'dest': str(dest)}))[0]
    print(f'updated: {_dict}')

@sio.event
def disconnect(sid):
    print('disconnect ', sid)

'''
@sio.event
def on_my_message(self, data):
    print('receivced event')
    print(data)
'''

if __name__ == '__main__':
    init()


import random
words='Play'
score=0
print("Guess the anime title!!!")
names=['tokyo ghoul', 'your lie in april','guilty crown', 'pokemon','grand blue', 'my hero academia',
'sword art online', 'attack on titan', 'death note', 'vinland saga']
while len(names)!=0:
    play=input(f"{words}?(Y/N)")
    if play.lower()=='y':
        num2,num1=1,0
        orig_word=[]
        num1=random.randint(0,len(names)-1)
        orig_word=list(names[num1])
        words=names[num1]
        names.remove(words)
        chr='_'*len(orig_word)
        words="Continue"
        num3=0
        while num1==num2 or num2==num3 or num1==num3: #3 unique random character
            num1=random.randint(1,len(orig_word)-1)
            num2=random.randint(1,len(orig_word)-1)
            num3=random.randint(1,len(orig_word)-1)
        in_game_word=list(chr)
        for i in range(0,len(orig_word)):#loop for blanks
            if i==num1 or i==num2 or i==num3 or orig_word[i]==' ':
                in_game_word[i]=orig_word[i]
            if len(orig_word)>=10 and i>=7: #additional random characters if word has more than 8 characters
                num2=random.randint(0,len(orig_word)-1)
                in_game_word[num2]=orig_word[num2]
        num2=0
        chr=""
        print(f"Your word is: {chr.join(in_game_word)}")
        while in_game_word!=orig_word:
            player_input=input(">>> ")
            num1,num4,num3=0,0,0
            if list(player_input)==orig_word:
                print("You guessed correct!, You win")
                score+=1
                break
            for i in range(0,len(orig_word)):#loop for comparing
                if player_input.lower()==in_game_word[i]:
                    num4+=1
                elif player_input.lower()==orig_word[i]:
                    in_game_word[i]=orig_word[i]
                    num1=-1
                    num3+=1
            print(chr.join(in_game_word))
            if num3==0 and num4>=1:
                print("This letter already exists!")
            elif num2==3:
                print(f"Correct word was: {chr.join(orig_word)}")
                print("All guesses used, You lose!")
                break
            elif num1!=-1 and num4==0:
                print(f"Wrong Guess!! {3-num2} chance(s) remaining")
                num2+=1
            elif in_game_word==orig_word:
                print("You win!")
                score+=1
    elif play.lower()=='n':
        print(f"Final score: {score}")
        print("Bye!")
        break
    else:
        print("select a correct option")
if len(names)==0:
    print("You finished all levels!")
    print(f"Final score: {score}")


import random

def yes_no(question):
    valid = False
    while not valid:
        response = input(question).lower()

        if response == "yes" or response == "y":
            response = "yes"
            return response

        elif response == "no" or response == "n":
            response = "no"
            return response

        else:
            print("Please answer yes / no")

def instructions():
    print("**** How to Play ****")
    print()
    print("The rules of the game go here")
    print()
    return ""

def num_check(question, low, high):

    error = "Please enter an whole number between 1 and 10"

    vaild = False
    while not vaild:
        try:
            response = int(input(question))

            if low < response <= high:
                return response

            else:
                print(error)

        except ValueError:
            print(error)

played_before = yes_no("Have you played the game before? ")

if played_before == "no":
    instructions()

how_much = num_check("How much would you like to play with? ", 0, 10)

print("You will be spending ${}".format(how_much))

balance = how_much

rounds_played = 0

print()
play_again = input("Press <Enter> to play...").lower()

while play_again == "":

    rounds_played += 1

    print()
    print("*** Round #{} ***".format(rounds_played))

    chosen_num = random.randint(1, 100)

    if 1 <= chosen_num <= 5:
        chosen = "unicorn"
        balance += 4

    elif 6 <= chosen_num <= 36:
        chosen = "donkey"
        balance -= 1

    else:
        if chosen_num % 2 == 0:
            chosen = "horse"

        else:
            chosen = "zebra"
        balance -= 0.5

    if balance < 1:
        play_again = "xxx"
        print("Sorry you have run out of money")

    else:
        print("You got a {}. Your balance: ${:.2f}".format(chosen, balance))
        play_again = input("Press Enter to play again or 'xxx' to quit ")

print()
print("Final balance ${}".format(balance))


from math_operator_operation import operation as op

print("20-05-2019")

while (True):

    num1 = input("Enter The First Number: ")
    num2 = input("Enter The Second Number: ")

    num1 = float(num1)
    num2 = float(num2)

    obj = op(num1, num2)

    re = obj.alloperation()
    for i in range(0, len(re)):
        if (i == 0):
            print("Addition is :", re[i])
        elif(i == 1):
            print("Subtraction is :", re[i])
        elif(i == 2):
            print("Multiplication is :", re[i])

    per = input("Do you want to run again?\nEnter Yes or No.")
    per = per.lower()
    if (per == "yes"):
        continue
    elif (per == 'no'):
        break


class PythonListQueue(object):
    """
    A queue based on the built in Python list type.
    """
    def __init__(self):
        self._items = []

    def enqueue(self, item):
        self._items.append(item)

    def dequeue(self):
        return self._items.pop(0)

    def size(self):
        return len(self._items)

    def is_empty(self):
        return len(self._items) == 0

class LinkedListNode(object):
    """
    A doubly linked list node, support for the LinkedListQueue. You should not need
    to change this code, but you will want to use it in the LinkedListQueue
    """
    def __init__(self, value, prevNode, nextNode):
        self.value = value
        self.prev = prevNode
        self.next = nextNode

class LinkedListQueue(object):
    """
    Finish the functions below to create a queue based on a linked list. Because
    a queue must either:

        * enqueue to the head and dequeue from the tail; or
        * enqueue to the tail and dequeue from the head.

    You should use a doubly linked list to ensure O(1) time enqueue and dequeue.
    """
    def __init__(self):
        self.head = None
        self.tail = None
        self.num_items = 0

    def enqueue(self, item):
        node = LinkedListNode(item, None, None)

        # Link the old head and the new node (which becomes the head)
        if self.head is None:
            self.tail = node
        else:
            self.head.prev = node
            node.next = self.head

        self.head = node
        self.num_items += 1

    def dequeue(self):
        # Update the tail
        ret_node = self.tail
        self.tail = self.tail.prev

        # Unlink things
        ret_node.prev = None

        if self.tail == None:
            self.head = None
        else:
            self.tail.next = None

        self.num_items -= 1

        return ret_node.value

    def size(self):
        return self.num_items

    def is_empty(self):
        return self.num_items == 0

class RingBufferQueue(object):
    """
    Finish the functions below such that this queue is backed by a Ring Buffer.
    Recall that a ring buffer uses an array and two pointers to keep track of
    where to read, and where to write.

    Be careful! If the read pointer were to overtake the write pointer, it
    would return incorrect data! If the write pointer were to overtake the read
    pointer, it would overwrite data that hasn't been read yet!

    In many contexts, you would avoid this issue by stalling when one pointer
    would overwrite the other. Since doing so only makes sense in a multithreaded
    environment, you may prefer to just resize the underlying ring buffer at
    these times, instead.
    """
    def __init__(self):
        self._capacity = 200
        self._items = [None] * self._capacity
        self._write_idx = 0
        self._read_idx = 0
        self._item_count = 0

    def enqueue(self, item):
        if self._item_count == self._capacity:
            # If the buffer is full, rotate items so that the next items to be
            # read are at the beginning, then double the capacity. To rotate,
            # we reverse the whole list in place, then reverse both components.
            # See Programming Pearls for an explanation.
            items = self._items
            items.reverse()
            n = self._capacity - self._read_idx
            for i in range(n):
                items[i], items[n-i-1] = items[n-i-1], items[i]
            for i in range(self._read_idx//2):
                items[n+i], items[-i-1] = items[-i-1], items[n+i]
            items.extend(None for _ in range(self._capacity))

            self._items = items
            self._write_idx = self._capacity
            self._read_idx = 0
            self._capacity *= 2

        self._items[self._write_idx] = item
        self._write_idx = (self._write_idx + 1) % self._capacity
        self._item_count += 1

    def dequeue(self):
        ret_itm = self._items[self._read_idx]
        self._read_idx = (self._read_idx + 1) % self._capacity
        self._item_count -= 1

        return ret_itm

    def size(self):
        return self._item_count

    def is_empty(self):
        return self._item_count == 0

QUEUE_CLASSES = (
    PythonListQueue,
    LinkedListQueue,
    RingBufferQueue
)


import json
from transformers import AutoTokenizer

from query_dict import preprocessques, get_meta

tokenizer = AutoTokenizer.from_pretrained("./FinBERT_L-12_H-768_A-12_pytorch")
cnt_er = 0

class SQLExample(object):

    def __init__(self,
                 qid,
                 question,
                 table_id,
                 column_meta,
                 select=None,
                 conditions=None,
                 tokens=None,
                 value_start_end=None,
                 valid=True):
        self.qid = qid
        self.question = question
        self.table_id = table_id
        self.column_meta = column_meta
        self.select = select
        self.conditions = conditions
        self.valid = valid
        if tokens is None:
            self.tokens = tokenizer.tokenize(question)
            self.value_start_end = {}
            if conditions is not None and len(conditions) > 0:
                cur_start = None
                for cond in conditions:
                    value = cond[-1]
                    value_tokens = tokenizer.tokenize(value)
                    val_len = len(value_tokens)
                    for i in range(len(self.tokens)):
                        if " ".join(self.tokens[i:i+val_len]).lower() != " ".join(value_tokens).lower():
                            continue
                        s = i
                        e = len(value) + s
                        recovered_answer_text = question[s:e].strip()
                        if value.lower() == recovered_answer_text.lower():
                            cur_start = i
                            break

                    if cur_start is None:
                        global cnt_er
                        cnt_er += 1
                        self.valid = False
                    else:
                        self.value_start_end[value] = (cur_start, cur_start + val_len)
        else:
            self.tokens=tokens
            self.value_start_end=value_start_end

    @staticmethod
    def load_from_json(s):
        d = json.loads(s)
        keys = ["qid", "question", "table_id", "column_meta", "select", "conditions", "tokens", "value_start_end", "valid"]

        return SQLExample(*[d[k] for k in keys])

    @staticmethod
    def load_from_json_test(s):
        d = json.loads(s)
        keys = ["id", "question", "table_id"]

        return SQLExample(qid=d['id'], question=preprocessques(d['question'], False), table_id=d['table_id'], column_meta=get_meta())

    def dump_to_json(self):
        d = {}
        d["qid"] = self.qid
        d["question"] = self.question
        d["table_id"] = self.table_id
        d["column_meta"] = self.column_meta
        d["select"] = self.select
        d["conditions"] = self.conditions
        d["tokens"] = self.tokens
        d["value_start_end"] = self.value_start_end
        d["valid"] = self.valid

        return json.dumps(d, ensure_ascii=False)

    def output_SQ(self, return_str=True):
        agg_ops = ['none', 'avg', 'max', 'min', 'count', 'sum']
        cond_ops = ['>', '<', '==', '!=', 'like', '>=', '<=']

        select_text = self.column_meta[self.select][0]
        cond_texts = []
        for wc, op, value_text in self.conditions:
            column_text = self.column_meta[wc][0]
            op_text = cond_ops[op]
            cond_texts.append(column_text + op_text + value_text)

        if return_str:
            sq =  select_text + ", " + " AND ".join(cond_texts)
        else:
            sq = (select_text, set(cond_texts))
        return sq


from odoo import models, fields, api

class AutoServiceTimeTableMechanic(models.Model):
    _name = 'auto_service.timetable_mechanic'
    _description = 'Auto service mechanics time table'

    active = fields.Boolean(
        default=True, )
    name = fields.Char(translate=True)
    mechanic_id = fields.Many2one('auto_service.mechanic')
    date = fields.Date(string='Date')
    # for calculations
    start_time_int = fields.Integer(string='Hours from')
    end_time_int = fields.Integer(string='Hours to')
    # for timetable store
    start_time = fields.Datetime(string='From')
    end_time = fields.Datetime(string='To')

    @api.onchange('mechanic_id', 'start_time', 'end_time')
    def _compute_name(self):
        """Determine field name to display in the calendar
                Changes on the fields
                :param 'mechanic_id', 'start_time', 'end_time'
                :return None:
                """
        for trace in self:
            trace.name = '%s: %s - %s' % (trace.mechanic_id.name, trace.start_time_int, trace.end_time_int)


import os

from paramiko.config import SSHConfig
from pygerrit.rest import GerritReview, GerritRestAPI
from pygerrit.rest.auth import HTTPBasicAuthFromNetrc

class GerritServer:

   def __init__(self, gerrit_host_alias):

      ssh_config = SSHConfig()
      user_ssh_config_file = os.path.expanduser("~/.ssh/config")
      if os.path.exists(user_ssh_config_file):
         with open(user_ssh_config_file) as f:
            ssh_config.parse(f)

      gerrit_host_name = ssh_config.lookup(gerrit_host_alias).get("hostname")

      auth = HTTPBasicAuthFromNetrc("https://{}/".format(gerrit_host_alias))

      self.gerrit_api_client = GerritRestAPI("https://{}/".format(gerrit_host_name), auth)

   def set_score_labels(self, change_id, code_review_score, verified_score):
      labels = {}
      labels['Code-Review'] = code_review_score
      labels['Verified']    = verified_score

      review = GerritReview()
      review.add_labels(labels)
      self.gerrit_api_client.review(change_id, "current", review)


from easier.minimodel import MiniModelSqlite, MiniModelPG
from unittest import TestCase
import os

# # RUN TESTS WITH
# # pytest -sv ./test_duck.py
# coverage erase && pytest -sv --cov=easier ./tests/test_minimodel.py  | grep minimodel
# coverage erase && pytest -sv --cov=easier.minimodel ./tests/test_minimodel.py::TestMiniModelSqlite::test_saving

# This will run tests and raise error on warnings
# python -W error -munittest test_minimodel.TestMiniModel.test_saving

class TestMiniModelSqlite(TestCase):
    TEST_DB_FILE = "/tmp/test_minimodel.ddb"
    MODEL_CLASS = MiniModelSqlite

    def setUp(self):
        import pandas as pd

        # Creat dataframe to store
        self.df_one = pd.DataFrame(
            [
                {"a": 1, "b": pd.Timestamp("1/1/2022")},
                {"a": 2, "b": pd.Timestamp("1/2/2022")},
            ]
        )

        # Create second dataframe to store
        self.df_two = self.df_one.copy()
        self.df_two.loc[0, "a"] = 7
        self.df_two.loc[0, "b"] = pd.Timestamp("11/18/2022")
        self._cleanup()

    def _cleanup(self):
        for file_name in [self.TEST_DB_FILE]:  # pragma: no cover
            if os.path.isfile(file_name):
                os.unlink(file_name)

    def tearDown(self):  # pragma: no cover
        self._cleanup()

    def get_model(self, overwrite, read_only):
        return self.MODEL_CLASS(
            self.TEST_DB_FILE, overwrite=overwrite, read_only=read_only
        )

    def test_saving(self):
        mm = self.get_model(overwrite=True, read_only=False)
        mm.create("one", self.df_one)
        # import pdb; pdb.pdb.set_trace()
        df1 = mm.tables.one.df
        self.assertListEqual(list(self.df_one.b), list(df1.b))

    def test_dropping(self):
        mm = self.get_model(overwrite=True, read_only=False)
        mm.create("one", self.df_one)
        # import pdb; pdb.pdb.set_trace()
        df1 = mm.tables.one.df
        self.assertListEqual(list(self.df_one.b), list(df1.b))

        self.assertTrue("one" in mm.table_names)
        mm.drop("one")
        self.assertFalse("one" in mm.table_names)

        mm = self.get_model(overwrite=True, read_only=False)
        mm.create("one", self.df_one)
        mm.create("two", self.df_two)

        self.assertEqual(set(mm.table_names), {"one", "two"})
        mm.drop_all_tables()
        self.assertEqual(len(mm.table_names), 0)

        mm = self.get_model(overwrite=True, read_only=False)
        mm.create("one", self.df_one)
        with self.assertRaises(ValueError):
            mm.drop("table_that_doesnt exist")

        mm = self.get_model(overwrite=False, read_only=True)
        with self.assertRaises(ValueError):
            mm.drop("one")

    def test_inserting(self):
        import pandas as pd

        # Create a table
        mm = self.get_model(overwrite=True, read_only=False)
        mm.create("one", self.df_one)

        # Make sure the table was created
        df1 = mm.tables.one.df
        self.assertListEqual(list(self.df_one.b), list(df1.b))
        del mm

        # Recreate the table with an overwrite
        mm2 = self.get_model(overwrite=True, read_only=False)
        mm2.insert("one", self.df_one)

        # Make sure the table was created
        df1 = mm2.tables.one.df
        self.assertListEqual(list(self.df_one.b), list(df1.b))
        del mm2

        # Reopen the file for additional insert
        mm3 = self.get_model(overwrite=False, read_only=False)
        mm3.insert("one", self.df_two)

        # Make sure inserts happened
        df_expected = pd.concat([self.df_one, self.df_two])
        df = mm3.tables.one.df
        self.assertListEqual(list(df_expected.b), list(df.b))

    def test_read_only(self):
        import pandas as pd

        df = pd.DataFrame(
            [
                {"a": 1, "b": pd.Timestamp("1/1/2022")},
                {"a": 2, "b": pd.Timestamp("1/2/2022")},
            ]
        )

        mm = self.get_model(overwrite=True, read_only=False)
        mm.create("one", df)

        with self.assertRaises(ValueError):
            self.get_model(overwrite=True, read_only=True)

        mm = self.get_model(overwrite=False, read_only=True)

        with self.assertRaises(ValueError):
            mm.create("one", df)

        with self.assertRaises(ValueError):
            mm.insert("one", df)

        with self.assertRaises(ValueError):
            mm.upsert("one", ["a"], df)

    def test_upserting(self):
        import pandas as pd

        df_base = pd.DataFrame(
            [
                {"a": 1, "b": pd.Timestamp("1/1/2022")},
                {"a": 2, "b": pd.Timestamp("1/2/2022")},
            ]
        )

        df_upsert = pd.DataFrame(
            [
                {"a": 2, "b": pd.Timestamp("1/2/2050")},
                {"a": 3, "b": pd.Timestamp("1/3/2050")},
            ]
        )

        df_expected = pd.DataFrame(
            [
                {"a": 1, "b": pd.Timestamp("1/1/2022")},
                {"a": 2, "b": pd.Timestamp("1/2/2050")},
                {"a": 3, "b": pd.Timestamp("1/3/2050")},
            ]
        )

        mm = self.get_model(overwrite=True, read_only=False)
        mm.create("one", df_base)
        mm.upsert("one", ["a"], df_upsert)

        df = mm.tables.one.df
        self.assertListEqual(list(df_expected.b), list(df.b))

    def test_record_upsert(self):
        import pandas as pd

        df_base = pd.DataFrame(
            [
                {"a": 1, "b": pd.Timestamp("1/1/2022")},
                {"a": 2, "b": pd.Timestamp("1/2/2022")},
            ]
        )
        df_expected = pd.DataFrame(
            [
                {"a": 1, "b": pd.Timestamp("1/1/2022")},
                {"a": 2, "b": pd.Timestamp("1/2/2050")},
                {"a": 3, "b": pd.Timestamp("11/18/2050")},
            ]
        )

        mm = self.get_model(overwrite=True, read_only=False)
        # Create a table twice to ensure creating actually drops
        mm.create("one", df_base)
        mm.create("one", df_base)
        mm.upsert("one", ["a"], {"a": 2, "b": pd.Timestamp("1/2/2050")})
        mm.upsert("one", ["a"], pd.Series({"a": 3, "b": pd.Timestamp("11/18/2050")}))

        with self.assertRaises(ValueError):
            mm.upsert("one", ["a"], [1, 2, 3])

        df = mm.tables.one.df
        self.assertListEqual(list(df_expected.b), list(df.b))

    def test_sql(self):
        import pandas as pd
        import numpy as np

        df_base = pd.DataFrame(
            [
                {"a": 1, "b": pd.Timestamp("1/1/2022")},
                {"a": 2, "b": pd.Timestamp("1/2/2022")},
            ]
        )
        mm = self.get_model(overwrite=True, read_only=False)
        mm.create("one", df_base)
        df = mm.query("select a, b from one order by b")
        df.loc[:, "b"] = df.b.astype(np.datetime64)
        self.assertListEqual(list(df_base.b), list(df.b))

class TestMiniModelPG(TestMiniModelSqlite):
    MODEL_CLASS = MiniModelPG

    def _cleanup(self):
        mm = self.get_model(overwrite=False, read_only=False)
        mm.drop_all_tables()

    def get_model(self, overwrite, read_only):
        return self.MODEL_CLASS(overwrite=overwrite, read_only=read_only)


from torch.nn import parameter
from tqdm import tqdm
import matplotlib.pyplot as plt

import os
import cv2
import numpy as np
import utils.visualize as vis

from utils.cs_dataset import cs_data
from cfg.settings import get_cfg_defaults
from typing import List

import json

from utils.visualize import visualize_2d, visualize_3d, draw_bev
from utils.evaluation import mkdir, path_leaf
from utils.cs_annotation import CsBbox3d
from utils.box3dImageTransform import (Camera,
                                  Box3dImageTransform,
                                  CRS_V,
                                  CRS_C,
                                  CRS_S
                                )

def get_camera(json_data):
    camera = Camera(fx=json_data["sensor"]["fx"],
            fy=json_data["sensor"]["fy"],
            u0=json_data["sensor"]["u0"],
            v0=json_data["sensor"]["v0"],
            sensor_T_ISO_8855=json_data["sensor"]["sensor_T_ISO_8855"])
    return camera

def get_cs_targets_and_objects(target_class:List[str], camera, json_data):
    target_objects = []
    cs_data = json_data.get('objects', {})
    for cs_object in cs_data:
        if cs_object['label'] in target_class:
            target_objects.append(cs_object)
    # Sort objects based on the depth location
    sorted_targets = sorted(target_objects, key=lambda item: item['3d']['center'][0], reverse=True)
    sorted_objects = [] # saved in citiscape object format
    for sorting in sorted_targets:
        obj = CsBbox3d()
        obj.fromJsonText(sorting)
        box3d_annotation = Box3dImageTransform(camera=camera)
        box3d_annotation.initialize_box_from_annotation(obj, coordinate_system=CRS_V)
        sorted_objects.append(box3d_annotation)
    return sorted_targets, sorted_objects

def vis_all(cfg, bev=False):
    pred_dir = cfg.EVAL.SAVE_FOLDER
    cs_dir = cfg.DATASETS.ROOT

    top_dir = 'saves/vis/' + pred_dir.split('/')[-1]
    cs_eval_data = cs_data(cs_dir, cfg=cfg, split='val')
    img_list = cs_eval_data.images
    label_list = cs_eval_data.labels_json

    for i in tqdm(range(len(img_list))):

        img = cv2.imread(img_list[i]).astype(np.uint8)
        img = img[...,::-1]

        full_path = os.path.normpath(label_list[i])
        camera_label = open(label_list[i])
        camera_data = camera_label.read()
        camera_data = json.loads(camera_data)
        camera = get_camera(camera_data)

        full_path = full_path.split(os.sep)
        city = full_path[-2]
        label_name = full_path[-1]

        pred_label = os.path.join(pred_dir, city, label_name)
        label = open(pred_label)
        json_data = label.read()
        data = json.loads(json_data)
        if len(data['objects']) == 0:
            continue

        sorted_targets, sorted_objects = get_cs_targets_and_objects(['car'], camera, data)

        input_data = zip(sorted_targets, sorted_objects)

        city_dir = os.path.join(top_dir, city)
        mkdir(city_dir)

        fname = full_path[-1].split('.')[0]
        fname3d = os.path.join(city_dir, fname) + '_3D.png'
        fname2d = os.path.join(city_dir, fname) + '_2D.png'
        plt.imsave(fname3d, visualize_3d(img.copy(), input_data))
        plt.imsave(fname2d, visualize_2d(img.copy(), sorted_targets))

        if bev:
            _, gt = get_cs_targets_and_objects(['car'], camera, camera_data)
            bev_image =  draw_bev(sorted_objects, gt)
            fname_bev = os.path.join(city_dir, fname) + '_BEV.png'
            plt.imsave(fname_bev, bev_image)

if __name__ == '__main__':
    cfg = get_cfg_defaults()
    vis_all(cfg, bev=True)


"""This module handles retweeting tweets"""
import tweepy
from time import sleep

def retweet_tweet(api):
    """Reteet tweets with guidelines for freshers every 20 seconds

    This pauses for 30 seconds before pulling any more data from
    the twitter api to prevent spam

    Args:
        api: The tweepy api object

    Returns:
        None

    """
    # Initialize key variables
    query = '#FacultyOfGreatness AND #FreshersGuide20 OR #FreshersGuide2020 OR #freshersguide2020'
    me = api.me()
    no_tweets = 20
    cursor_obj = tweepy.Cursor(api.search, q=(query),lang='en').items(no_tweets)
    for tweet in cursor_obj:
        # Skip entries from current user
        if tweet.user.id == me.id:
            continue
        print('\nTweet by: @' + tweet.user.screen_name)
        # Try exccept block to catch retweeted tweets
        try:
            # Retweet tweet as its found
            tweet.retweet()
        except tweepy.TweepError as e:
            print(e.reason)
            sleep(10)
        except StopIteration:
            break
        else:
            print('Retweeted the tweet')
            sleep(20)
    sleep(30)


#### imports:

# system & general:
# from os import listdir, mkdir, makedirs
# from os.path import isfile, join, isdir, exists
# import cPickle as pickle
# import os
# import re
import time

# data analysis and statistics:
# import pandas as pd
# import numpy as np
# from scipy import stats
# import random
# from scipy.stats import pearsonr, fisher_exact
# import math
# from scipy.spatial.distance import braycurtis, pdist, euclidean

# figures:
import matplotlib as mpl
mpl.use('Agg')

# import matplotlib.pyplot as plt
# from matplotlib.backends.backend_pdf import PdfPages
# import seaborn as sns
# from matplotlib.ticker import FormatStrFormatter
# from matplotlib import gridspec
# from PNPChip.ForPaper.Figures.nature_guidline_utils import m2inch
# import matplotlib.cm as cm
# from mpl_toolkits.axes_grid1 import make_axes_locatable

# my functions:
# from ShaniBA.myplots import roundup, rounddown, find_decimal_fold, percentile_cut_off, rarefaction_calc, rarefaction_plot, adjusted_roundup
# from ShaniBA.MyFunctionsShani import *
# from ShaniBA.GeneralFeaturePhenotypeInteractions.Feature_phenotype_functions import *
# from ShaniBA.TCR_microbiome_interactions.TCR_microbiome_interactions_functions import *
# from ShaniBA.TCR_microbiome_interactions.TCR_microbiome_interactions_functions2 import *
# from ShaniBA.SampleLists.SampleFileFunctions import *
# from ShaniBA.PhenotypicData.PhenotypeGenerationFunctions import *
# from ShaniBA.CardioProject.CardioFunctions import *
from ShaniBA.PredictionPipeline.PredictionFunctions import *
from ShaniBA.TCR_feature_generation.SubsamplingFunctions import *

if __name__ == "__main__":
    #####path definitions:
    MyPath = '/net/mraid08/export/genie/Lab/Personal/ShaniBAF'

    with open('/net/mraid08/export/genie/Lab/Personal/ShaniBAF/Sample files/BD lists/PNP530', 'rb') as fp:
        PNP530 = pickle.load(fp)
    with open('/net/mraid08/export/genie/Lab/Personal/ShaniBAF/Sample files/BD lists/Cardio126', 'rb') as fp:
        Cardio126 = pickle.load(fp)
    PNP530Cardio126 = PNP530 + Cardio126

    FIG1_DIR = '/net/mraid08/export/genie/Lab/Personal/ShaniBAF/Presentations and Manuscripts/CardioTCR paper/FigureDraft_Jan19/\
    Fig1_AgeGenderPrediction/'
    PRED_RESULTS_DIR = '/net/mraid08/export/jafar/Microbiome/Analyses/ShaniBAF/predictions2/'

    ##### general definitions:
    pd.set_option('display.expand_frame_repr', False)
    pd.set_option('display.width', 1000)
    np.set_printoptions(precision=4, linewidth=200)

    cdate = str(time.strftime("%d%m%Y"))
    cdate

def add_subfigure_letter(ax, letter, fontsize=18, x_frac_offset=0,y_frac_offset=1.15,
                          **text_kw):
    ax.annotate(letter, xy=(x_frac_offset, y_frac_offset), xycoords='axes fraction', fontsize=fontsize,
                xytext=(0, 0), textcoords='offset points',
                ha='right', va='top', **text_kw)
    return ax

def plot_many_roc(ax,sample_list,color_map,prediction_subdir_list=None):
    Y_file='/net/mraid08/export/jafar/Microbiome/Analyses/ShaniBAF/predictions2/TargetDFs/isCardio.dat'
    Y=pd.read_pickle(Y_file).loc[sample_list,:]
    # print Y.head()

    #plot best prediction:
    d1='/net/mraid08/export/jafar/Microbiome/Analyses/ShaniBAF/predictions2/isCardio/'
    prediction_subdir_list=['XGB_randomSearch_25_byPredictedGender/', 'XGB_randomSearch_25_byPredictedAge/',
               'XGB_randomSearch_25_byPredictedAgeGender/','XGB_randomSearch_25_byRepFeatPCA10percVDJ0999PredictedAgeGender/']
    cmap=plt.get_cmap(color_map, 5)
    color_list=[cmap(1),cmap(2),cmap(3),cmap(4)]
    # print colorlist
    dataset_name_list=['Pred. Gender','Pred. Age','Pred. Age+Gender','TCR features + Pred. Age+Gender']
    for n in range(len(prediction_subdir_list)):
        d=prediction_subdir_list[n]
        color=color_list[n]
    #     print ("color=",color)

        pred=pd.read_pickle(d1+d+'predictions_df.pkl')
    #     print pred.head()
        y_true=Y.isCardio
        y_pred=pred.isCardio.loc[sample_list]
        pos_label=1
        dataset_name=dataset_name_list[n]

        ax, roc_auc=plot_roc_curve(ax,y_true,y_pred,pos_label,dataset_name=dataset_name,color=color)
        if n==2: auc_AgeGender=roc_auc
        elif n==3: auc_TCR=roc_auc
    AUC_diff=round(auc_TCR-auc_AgeGender,3)
    handles, labels = ax.get_legend_handles_labels()
    labels=[l.replace('area = ','') for l in labels]
    ax.legend(handles, labels,loc='3',fontsize='small')
    # ax.legend(loc='best',bbox_to_anchor=(1.05, 1))

    return ax,AUC_diff

def edit_feature_names(feature_list):
    # get readable feature names
    replace_tuple = (
        ('_1', '') , ('_0', '(non-prod)') , ('clonal', '') , ('normSeqNums_per2000', 'Norm seq #') , ('_NT', ' nt') , ('_aa', ' aa'),
        ('_rel_seq_count', ' seq #'), ('_mean', ' mean'), ('_std', ' std'), ('cdr3Length', 'CDR3 length'), ('Multiplesclerosis', 'MS '), ('Colorectalcancer', 'Colorectal cancer'),
        ('_rel_cum_freq(perc)', ' seq freq.'), ('Deletion', ' deletion'), ('Insertion', ' insertion'), ('top', 'Top'), ('mean_nt_per', 'Mean nt per'),
        ('totalAnnotatefreqs', 'Total annotated Seqs'), ('shannon', 'shannon '),('(perc)',''),('Influenza','Influenza-related'),
        ('cum','cumul.'),
        ('_', '-'), ('-', ' ')
        )
    feature_list_new = feature_list
    for r in replace_tuple:
        feature_list_new = [feature.replace(*r) for feature in feature_list_new]
    feature_list_new = [feature.capitalize() for feature in feature_list_new]
    feature_list_new = [' '.join(x.split(' ')[:2]) +'\n' + ' '.join(x.split(' ')[2:])
                        if len(x) > 2 else x for x in feature_list_new]

    return feature_list_new

def remove_spines(ax=None,removeFigBorders=False,removeTicks=True,removeTicklabels=True):
    if ax is None:
        ax = plt.gca()
    if removeTicks:
        ax.tick_params(axis='both', which='both', bottom=False, top=False,
                        left=False, right=False)
    if removeTicklabels:
        ax.tick_params(labelbottom=False, labelleft=False)
    if removeFigBorders:
        for spine in ax.spines.values():
                spine.set_edgecolor('white')

    return ax

def make_custome_legend(color_list, marker_list, label_list, ax, loc=None, bbox_to_anchor=None, **kwargs):
    '''
    color list = list of colors for markers
    marker_list = list of marker shapes such as 'o','*' etc.
    label_list = list of labels (strings)
    loc = legend location (string) such as 'upper right'
    bbox_to_anchor = 2-tuple indicating x,y coords for legend. see
    https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.legend.html
    for more explanations
    **kwargs  - such as fontsize, title, title_fontsize...

    '''
    import matplotlib.pyplot as plt
    from matplotlib.legend_handler import HandlerBase

    class MarkerHandler(HandlerBase):
        def create_artists(self, legend, tup, xdescent, ydescent,
                           width, height, fontsize, trans):
            return [plt.Line2D([width / 2], [height / 2.], ls="",
                               marker=tup[1], color=tup[0], transform=trans)]

    ax.legend(list(zip(color_list,marker_list)), label_list,
              handler_map={tuple: MarkerHandler()}, loc=loc, bbox_to_anchor=bbox_to_anchor, **kwargs)

    return ax

def edit_species_names(species_name_list):
    species = species_name_list
    replace_list = ['f__','g__','s__','__']
    for word in replace_list:
        species = [item.replace(word,'') for item in species]
    # species.remove('cluster')
    new_species = ['_'.join(item.split('|')[-2:]) if 'unknown' in item else item.split('|')[-2] for item in species]
    new_species = [('_'.join(item.split('_')[:-2]) + '\n' + \
      '_'.join(item.split('_')[-2:])) \
         if len(item.split('_')) > 2 else item \
     for item in new_species]
    new_species = [item.replace('_',' ').replace(' unclassified','') for item in new_species]

    # new_species = [(item.split('|')[-2].split('_')[0] + '/' + item.split('|')[-1].split('_')[1]) for item in
    #                new_species]
    # new_species = [item.split('/')[0] if item.split('/')[0] == item.split('/')[1] else item for item in new_species]
    return new_species


# import numpy
# from numpy import random
# from numpy import int64
import random

def create_hashboard(hashtable, board, width, height):
    a = 0
    for i in range(width):
        for j in range(height):
            b = board[i][j]
            if b != 0:
                a = a ^ hashtable.table()[b-1][i][j]
    return a

class hash():
    def __init__(self, Width, Height):
        self.Zobrist1 = [[random.randint(0,9223372036854775807) for _ in range(20)] for _ in range(20)]
        self.Zobrist2 = [[random.randint(0,9223372036854775807) for _ in range(20)] for _ in range(20)]

    def table(self):
        return [self.Zobrist1, self.Zobrist2]

if __name__ == '__main__':
    print(hash(3,3).table())


from ConfigFile import ConfigFile

class ConfigFileCollection:
  def __init__(self, configDirectoryCsvPath, repoName):
    self.configFiles = []

    with open(configDirectoryCsvPath) as configDirectoryCsvFile:
      for configDirectoryCsvLine in configDirectoryCsvFile:
        self.configFiles.append(ConfigFile(configDirectoryCsvLine, repoName))

  def forEach(self, function):
    for configFile in self.configFiles:
      function(configFile)


from flask import Flask, jsonify, request
from processing import headlines, get_sources, get_everything

application = Flask(__name__)

@application.route('/')
def hello_world():
    return application.send_static_file("index.html")

@application.route('/headlines')
@application.route('/headline')
def send_headlines():
    return jsonify(headlines)

@application.route('/search')
def search():
    keyword = request.args.get('keyword')
    from_date = request.args.get('from')
    to_date = request.args.get('to')
    source = request.args.get('source')
    return jsonify(get_everything(q=keyword, from_param=from_date, to=to_date, sources=source))

@application.route('/sources')
@application.route('/source')
def send_source():
    category = request.args.get('category')
    news_sources = get_sources(category=category)
    return jsonify({'sources': news_sources[:10]})

# run the app.
if __name__ == "__main__":
    # Setting debug to True enables debug output. This line should be
    # removed before deploying a production app.
    application.debug = True
    application.run()


import calculator
import pytest
import math
import cmath
import sympy

from test_calc_helpers import *

def test_negation():
	doit("9", 9)
	doit("-9", -9)
	# doit("--9", 9)
	doit("(9)", 9)
	doit("(-9)", -9)
	# doit("(--9)", 9)
	dort("-E", -sympy.E)
	doit('3-2', 1)
	doit('3 - 2', 1)
	doit('-2^2', -4)
	doit('(-2)^2', 4)
	doit('2^-1', 1/2)

def test_4func():
	doit("9 + 3 + 6", 9 + 3 + 6)
	doit("9 + 3 / 11", 9 + 3.0 / 11)
	doit("(9 + 3)", (9 + 3))
	doit("(9+3) / 11", (9+3.0) / 11)
	doit("9 - 12 - 6", 9 - 12 - 6)
	doit("9 - (12 - 6)", 9 - (12 - 6))
	doit("3 * -5", 3 * -5)
	doit("3 * (-5)", 3 * (-5))
	doit("2*3.14159", 2*3.14159)
	doit("3.1415926535*3.1415926535 / 10", 3.1415926535*3.1415926535 / 10)
	doit("6.02E23 * 8.048", 6.02E23 * 8.048)
	# doit("6.02E23 x 8.048", 6.02E23 * 8.048)

def test_modulo():
	doit('5 ~mod 2', 1)
	doit('10 ~mod 4', 2)
	throws('10 ~mod 0')

def test_constants():
	dort("PI * PI / 10", sympy.pi * sympy.pi / 10)
	dort("PI*PI/10", sympy.pi*sympy.pi/10)
	dort("PI^2", sympy.pi**2)
	dort("e / 3", sympy.E / 3)
	doit('0.0', 0)
	doit('.0', 0)
	doit('01', 1)
	doit('00', 0)
	doit('0.1', sympy.Number(1) / sympy.Number(10))

def test_math_functions():
	dort('sin(37)', sympy.sin(37))
	dort('cos(38)', sympy.cos(38))
	dort('tan(38)', sympy.tan(38))
	dort('sec(39)', sympy.sec(39))
	dort('csc(40)', sympy.csc(40))
	dort('cot(41)', sympy.cot(41))
	dort('asin(42)', sympy.asin(42))
	dort('acos(43)', sympy.acos(43))
	dort('atan(44)', sympy.atan(44))
	dort('asec(45)', sympy.asec(45))
	dort('acsc(46)', sympy.acsc(46))
	dort('acot(47)', sympy.acot(47))
	dort('sind(37)', sympy.sin(37 * sympy.pi / sympy.Number(180)))
	dort('cosd(38)', sympy.cos(38 * sympy.pi / sympy.Number(180)))
	dort('tand(38)', sympy.tan(38 * sympy.pi / sympy.Number(180)))
	dort('secd(39)', sympy.sec(39 * sympy.pi / sympy.Number(180)))
	dort('cscd(40)', sympy.csc(40 * sympy.pi / sympy.Number(180)))
	dort('cotd(41)', sympy.cot(41 * sympy.pi / sympy.Number(180)))
	dort('asind(42)', sympy.asin(42) * sympy.Number(180) / sympy.pi)
	dort('acosd(43)', sympy.acos(43) * sympy.Number(180) / sympy.pi)
	dort('atand(44)', sympy.atan(44) * sympy.Number(180) / sympy.pi)
	dort('asecd(45)', sympy.asec(45) * sympy.Number(180) / sympy.pi)
	dort('acscd(46)', sympy.acsc(46) * sympy.Number(180) / sympy.pi)
	dort('acotd(47)', sympy.acot(47) * sympy.Number(180) / sympy.pi)
	dort('sinh(4)', sympy.sinh(4))
	dort('cosh(5)', sympy.cosh(5))
	dort('tanh(6)', sympy.tanh(6))
	dort('asinh(4)', sympy.asinh(4))
	dort('acosh(5)', sympy.acosh(5))
	dort('atanh(6)', sympy.atanh(6))
	dort('int(E)', int(sympy.E))
	dort('int(-E)', int(-sympy.E))

def test_power():
	doit("2^3^2", 2**3**2)
	doit("2^3+2", 2**3+2)
	doit("2^9", 2**9)
	dort("E^PI", sympy.E**sympy.pi)

# def test_mixed():
# 	doit('round(sin(20))!', sympy.factorial(round(sympy.sin(20))))
# 	doit('2 * 3!', 2 * sympy.factorial(3))
# 	doit('(2 * 3)!', sympy.factorial(2 * 3))

def test_logarithms():
	dort('log(5)', sympy.log(5, 10))
	dort('ln(5)', sympy.log(5))
	dort('ln(e)', 1)
	dort('ln(-3)', sympy.log(-3))
	dort('log(-3)', sympy.log(-3, 10))

def test_unicode():
	doit('3×2', 6)
	doit('6÷2', 3)
	dort('π', sympy.pi)
	dort('τ', 2 * sympy.pi)
	doit('5*0', 0)

# def test_dice_rolling():
# 	repeat('d6', 1, 6)
# 	repeat('2d6', 2, 12)
# 	repeat('8d9', 9, 8 * 9)
# 	repeat('d4 * d4', 1, 16)
# 	repeat('sin(d1000)', -1, 1)
# 	throws('d0')
# 	throws('10000d10000')

def test_factorial():
	for i in range(0, 10):
		doit('{}!'.format(i), sympy.factorial(i))
	for i in range(1, 10):
		dort('gamma({})'.format(i), sympy.gamma(i))
	doit('4.5!', sympy.gamma(sympy.Rational(9, 2) + 1))
	dort('gamma(5) - 5!', -96)
	throws('(-1)!')
	doit('300!', sympy.factorial(300))
	# throws('301!')

def test_problems():
	throws('nothing')

def test_equality():
	doit('1 < 2', True)
	doit('1 < 2 < 3', True)
	doit('1 < 2 > 1', True)
	doit('1 < 2 > 3', False)
	doit('1 < 2 > 3 < 4', False)
	doit('1 == 1', True)
	doit('1 != 1', False)
	doit('1 == 2', False)
	doit('1 != 2', True)
	doit('1 < 2 < 3 < 4 <= 4 >= 2 == 2 < 5', True)
	doit('1 < 2 && 3 < 4', True)
	doit('1 < 0 || 3 < 4', True)
	doit('3 == 3 && 2 == 2', True)

def test_assignment():
	doit('x = 2', None)
	doit('x = 2, y = 3', None)
	doit('a = 2, a', 2)
	doit('A = 2, a', 2)
	doit('a = 2, A', 2)
	doit('A = 2, A', 2)
	doit('x = 2, y = 3, x * y', 6)
	doit('f = (() -> f)', None)

def test_functions():
	doit('double = (x) -> x * 2, double(3)', 6)
	doit('multiply = (x, y) -> x * y, multiply(4, 5)', 20)
	doit('double (x) = x * 2, double(3)', 6)
	doit('multiply (x, y) = x * y, multiply(4, 5)', 20)
	doit('f = (n) -> if (n < 2, 1, f(n - 1) + f(n - 2)), f(5)', 8)
	doit('f = (n) -> if (n < 2, 1, f(n - 1) + f(n - 2)), f(50)', 20365011074)
	doit('if(0, 0, 0)', 0)
	compile_fail('if(0, 0)')
	compile_fail('if(0, 0, 0, 0)')
	doit('f = (x) -> x, t = f(5), 1 + f(5)', 6)
	doit('(x -> x * 2)(8)', 16)
	doit('f = x -> x * 3, f(3)', 9)

def test_function_creation():
	doit('f = x -> x * 2, f(3)', 6)
	doit('f(x) = x * 2, f(3)', 6)
	doit('f = (x y) -> x + y, f(1, 2)', 3)
	doit('f(x y) = x + y, f(1, 2)', 3)

def test_macros():
	doit('((x) ~> x())(5)', 5)
	doit('(x ~> x())(5 + 6)', 11)

def test_logic():
	dort('true  && true',  True)
	dort('true  && false', False)
	dort('false && true',  False)
	dort('false && false', False)
	dort('true  || true',  True)
	dort('true  || false', True)
	dort('false || true',  True)
	dort('false || false', False)
	doit('1 && 1 || 1 && 0', True)
	doit('0 || 1 && 1 || 0', True)
	doit('0 || 1 && 0 || 0', False)
	doit('!0', 1)
	doit('!1', 0)
	doit('!!0', 0)
	doit('!!1', 1)
	doit('!!3!!', 1)

def test_short_circuit():
	doit('1 || x', 1)
	doit('1 || x || x || x', 1)
	doit('0 && x', 0)
	doit('0 && x && x', 0)
	throws('0 || x')
	throws('1 && x')

def test_gcd():
	dort('gcd(8, 6)', 2)
	dort('lcm(3, 2)', 6)

def test_type_checking():
# 	doit('is_real(1)', True)
# 	doit('is_real(2.5)', True)
# 	doit('is_real(3i)', False)
# 	doit('is_real(sin)', False)
# 	doit('is_real((x) -> x)', False)
# 	doit('is_real((x) ~> x)', False)

# 	doit('is_complex(1)', False)
# 	doit('is_complex(2.5)', False)
# 	doit('is_complex(3i)', True)
# 	doit('is_complex(sin)', False)
# 	doit('is_complex((x) -> x)', False)
# 	doit('is_complex((x) ~> x)', False)

	dort('is_function(1)', False)
	dort('is_function(2.5)', False)
	dort('is_function(3i)', False)
	dort('is_function(sin)', True)
	dort('is_function((x) -> x)', True)
	dort('is_function((x) ~> x)', True)
	dort('is_function(((x) ~> x)(1))', True)
	dort('is_function(((x) ~> x)(1)())', False)

def test_large_numbers():
	doit('200! / 3', sympy.factorial(200) / sympy.Number(3))
	# throws('200! / 3.2')

def test_variadic_function():
	doit('((n, a.) -> a(n))(0, 7, 8, 9)', 7)
	doit('((n, a.) -> a(n))(1, 7, 8, 9)', 8)
	doit('((a.) -> a(4) + 2)(0, 1, 2, 3, 4, 5, 7, 8, 9)', 6)
	doit('list = (x.) -> x, list(9, 8, 7, 6, 5)', Ignore)
	dort('''
		_min2 = (x, y) -> if (x < y, x, y),
		_minV = (l, i) -> if (i == length(l) - 1, l(i), _min2(l(i), _minV(l, i + 1))),
		_min = (x.) -> _minV(x, 0),
		_min(7, 3, 6, 9)
	''', 3)

def test_argument_expansion():
	dort('sum(expand(array(1, 2)))', 3)
	throws('msum = (x, y) ~> x() + y(), msum(expand(array(1, 2)))')

def test_superscript():
	doit('2²', 4)
	doit('2²²', 4194304)
	doit('2² ²', 16)
	doit('3³ ⁴', (3 ** 3) ** 4)
	doit('(3³)⁴', (3 ** 3) ** 4)

def test_if_statement():
	doit('if (0, 3, 4)', 4)
	doit('if (1, 3, 4)', 3)
	doit('if (2, 3, 4)', 3)
	dort('x = if, x(0, 3, 4)', 4)
	dort('x = if, x(1, 3, 4)', 3)
	dort('x = if, x(2, 3, 4)', 3)

def test_map():
	dort("' \\ map((x) -> x * 2, list(0, 1, 2, 3, 4, 5))", 2)
	dort("' \\ \\ \\ \\ map((x) -> x * 2, list(0, 1, 2, 3, 4, 5))", 8)
	dort("' \\ map((x) ~> x() * 2, list(0, 1, 2, 3, 4, 5))", 2)
	dort("' \\ \\ \\ map(sin, list(0, 1, 2, 3, 4))", sympy.sin(3))
	dort("' \\ map((x) -> x * 2, range(0, 6))", 2)
	dort("' \\ \\ \\ \\ map((x) -> x * 2, range(0, 6))", 8)
	throws("' \\ \\ \\ \\ map((a, b) -> a + b, list(0, 1, 2, 3, 4, 5))")
	dort("length(list(1, 2, 3))", 3)
	dort("f = (x) -> x * 2, length(map(f, list()))", 0)

def test_foldl():
	dort('foldl((a, b) -> a + b, 0, list(0, 1, 2, 3, 4))', 10)
	dort('foldl(sum, 0, range(0, 5))', 10)
	throws('foldl((a, b) -> a + b, list())')
	throws('foldl(3, 4)')
	throws('foldl(() -> f, list(1, 2))')
	dort('msum = (x, y) ~> x() + y(), foldl(msum, 0, list(1, 2, 3, 4))', 10)

def test_filter():
	dort('''
		is_even = (x) -> (x ~mod 2 == 0),
		length(filter(is_even, range(0, 100)))
	''', 50)
	dort('''
		is_small = (x) ~> x() < 5,
		length(filter(is_small, range(0, 100)))
	''', 5)

def test_range():
	# for i in range(0, 5):
	# 	dort('range(0, 5)({})'.format(i), i)
	# 	dort('range(10, 20)({})'.format(i), i + 10)
	dort('length(range(0, 5))', 5)
	dort('length(range(8, 10))', 2)
	dort('length(range(7, 7))', 0)
	# throws('range(5, 4)')

def test_invalid_syntax():
	parse_fail('= == =')
	parse_fail('== = ==')
	parse_fail('= = =')
	parse_fail('== == ==')
	parse_fail('3 -> 3')
	parse_fail('[] -> 3')
	parse_fail('-> -> x')
	parse_fail('f(x) -> x')

def test_compile_failures():
	compile_fail('(if) -> 0')
	compile_fail('(map) -> 0')
	compile_fail('(reduce) -> 0')
	compile_fail('(filter) -> 0')
	compile_fail('if = 0')
	compile_fail('map = 0')
	compile_fail('reduce = 0')
	compile_fail('filter = 0')

def test_errors():
	# throws('e^900')
	throws('sqrt(() -> 0)')
	# throws('10*2^6643')
	compile_fail('if (true, 8)')
	throws('low(1, 1)')
	throws('cos(true)')
	throws('sin(false)')

def test_trig():
	dort('sin(0)', 0)
	dort('cos(pi)', -1)
	dort('sin(8)', sympy.sin(8))
	dort('sin(8i+3)', sympy.sin(3+sympy.Number(8) * sympy.I))
	dort('atan(0.1)', sympy.atan(sympy.Rational(1, 10)))

def test_commaless():
	dort('sum(1 2)', 3)
	dort('sum(1 (1 + 1))', 3)

def test_strings():
	doit(';a', 'a')
	doit(';\\;', ';')
	doit(';\\\\', '\\')
	doit('"Hello"', "Hello")
	doit('\'"Hello"', 'H')
	doit('\\"Hello"', 'ello')
	doit(';a:; :"string"', "a string")

	tokenization_fail('"a')

	doit('“Hello”', "Hello")
	tokenization_fail('“a“b”c”')
	tokenization_fail('“a“')
	tokenization_fail('”a”')

def test_lists():
	doit("'[1 2 3]", 1)
	doit("'\\[1 2 3]", 2)
	doit("'\\\\[1 2 3]", 3)
	dort("length([1 2 3])", 3)
	# dort("length(.)", 0)
	dort("length([])", 0)
	dort("'\\\\\\\\join([1 2 3] [4 5 6])", 5)

def test_percentage():
	doit('100%', 1)
	doit('1%', 0.01)
	doit('1 + 1%', 1.01)

def test_try_catch():
	doit('try(1, x)', 1)
	doit('try(x, 2)', 2)
	doit('try(x, 2, 3, 4, 5)', 2)
	doit('try(x, x, 3, 4, 5)', 3)
	doit('try(x, 8, x)', 8)

def test_unicode():
	tokens = calculator.parser.tokenizer(';🐱', calculator.parser.TOKEN_SPEC)
	strings = list(map(lambda x: x['string'], tokens))
	assert strings == ['', ';🐱', '']

	result = calculator.calculate(';🐱')
	assert isinstance(result, calculator.functions.Glyph)
	assert result.value == '🐱'
	assert calculator.formatter.format(result) == '🐱'

	doformatted(';🐱', '🐱')
	doformatted(';🐶 : ;🦊 :[]', '"🐶🦊"')
	doformatted(';🐶 : ;🦊 :[]', '"🐶🦊"')
	doformatted('"🐶🦊"', '"🐶🦊"')
	doformatted('ord(;🐱)', '128\u201A049')
	doformatted('chr(ord(;🐱))', '🐱')

def test_small_floats():
	doformatted('0.2', '1/5')
	doformatted('0.1 + 0.2 - 0.3', '0')
	doformatted('3.14', '157/50')

def test_operator_fuctions():
	dort('sum(1, 2)', 3)
	dort('sum(5783, 3857)', 5783 + 3857)
	dort('dif(5, 2)', 3)
	dort('dif(4853, 246745)', 4853 - 246745)
	dort('mul(4, 7)', 4 * 7)
	dort('mul(37563, -35728)', 37563 * -35728)
	dort('div(8, 4)', 2)
	dort('div(5, 1)', 5)
	dort('mod(7, 3)', 1)

def test_object_equality():
	doit('[] == []', True)
	dort('[1, 2, 3] == \\range(0 4)', True)
	dort('[1, 2, 3] == range(0 4)', False)
	doit('["foo"] != [1 2 3]', True)
	doit('2^100 == 2^101/2', True)
	doit('"dx is the best xd" == "dx is the best xd"', True)
	doit('\'"DXSmiley" == \'"Discord"', True)
	doit('"" == ""', True)
	doit('"d" == \\"d"', False)
	doit('[1] == [1]', True)
	doit('[100] == [1000/10]', True)
	doit('[1 2 3] == [1 2 3]', True)
	doit('[0 0 0] == [1 1 1]', False)
	doit('[[1 2] 3 [4 5]] == [[1 2] 3 [4 5]]', True)
	throws('1 == []')
	throws('[] == 1')
	throws('[[]] == [1]')
	throws('[1] == [[]]')

def test_object_ordering():
	doit('[0] < [1]', True)
	doit('[0] < [1] < [2]', True)
	doit('[6, 0] < [3, 2]', False)
	doit('[0] <= [0]', True)
	doit('"a" < "b"', True)
	doit('"a" <= "b"', True)
	doit('"a" > "b"', False)
	doit('"a" >= "b"', False)
	doit('"text" <= "text that is longer"', True)
	doit('"text" <  "text that is longer"', True)
	doit('"text" >= "text that is longer"', False)
	doit('"text" >  "text that is longer"', False)
	throws('[0] <  [[]]')
	throws('[0] <= [[]]')
	throws('[0] >  [[]]')
	throws('[0] >= [[]]')
	throws('[[]] <  [0]')
	throws('[[]] <= [0]')
	throws('[[]] >  [0]')
	throws('[[]] >= [0]')

def test_floats():
	doit('0.1', sympy.Rational(1, 10))
	doit('0.01', sympy.Rational(1, 100))
	doit('1e-1', sympy.Rational(1, 10))
	doit('1e-2', sympy.Rational(1, 100))
	doit('1e1', 10)
	doit('1e2', 100)
	doit('1e+1', 10)
	doit('1e+2', 100)

def test_unicode_operators():
	doit('1 ≤ 1', True)
	doit('1 ≤ 2', True)
	doit('2 ≤ 1', False)
	doit('1 ≯ 1', True)
	doit('1 ≯ 2', True)
	doit('2 ≯ 1', False)
	doit('1 ≥ 1', True)
	doit('2 ≥ 1', True)
	doit('1 ≥ 2', False)
	doit('1 ≮ 1', True)
	doit('1 ≮ 2', False)
	doit('2 ≮ 1', True)
	doit('1 ≠ 1', False)
	doit('1 ≠ 2', True)
	doit('1 ≤ 2 ≤ 3', True)
	doit('4 ≤ 2 ≤ 3', False)
	doit('1 ≤ 2 ≤ 1', False)


import os

from pynashapi import create_app

basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))

def test_development_config():
    app = create_app('development')
    assert app.config['DEBUG']
    assert app.config['SQLALCHEMY_DATABASE_URI'] == 'sqlite:///' + \
        os.path.join(basedir, 'data-dev.sqlite')

def test_testing_config():
    app = create_app('testing')
    assert app.config['TESTING']
    assert app.config['SQLALCHEMY_DATABASE_URI'] == 'sqlite:///' + \
        os.path.join(basedir, 'data-test.sqlite')


"""
Exercise No. 243

Note: This exercise require basic knowledge of SQL.

sqlite3 documentation: https://docs.python.org/3/library/sqlite3.html

csv documentation: https://docs.python.org/3/library/csv.html

The file Product.csv (utf-8 encoding) containing data about products in a creation warehouse is attached to the exercise.
In this exercise, you will create a SQLite database (named store.db) with a table named Product and the data contained
in the Product.csv file.

Extract the names of the Product table columns from the first line of the Product.csv file:

    "Id",
    "ProductName",
    "SupplierId",
    "CategoryId",
    "QuantityPerUnit",
    "UnitPrice",
    "UnitsInStock",
    "UnitsOnOrder",
    "ReorderLevel",
    "Discontinued",

Product table constraints are included in the product_constraints list:

    product_constraints = [
        'INTEGER PRIMARY KEY',
        'TEXT NOT NULL',
        'INTEGER NOT NULL',
        'INTEGER NOT NULL',
        'TEXT NOT NULL',
        'REAL NOT NULL',
        'INTEGER NOT NULL',
        'INTEGER NOT NULL',
        'INTEGER NOT NULL',
        'INTEGER NOT NULL',
    ]

Use the generate_sql() function from the previous exercise to generate the SQL that creates the Product table:

    def generate_sql(table_name, col_names, constraints):
        cols = [
            " ".join((col, constraint)).strip()
            for col, constraint in zip(col_names, constraints)
        ]
        return f'CREATE TABLE {table_name} (' + ', '.join(cols) + ')'

Then create the Product table and insert data from Product.csv. In response, create a query to store.db that extracts
the number of records in the Product table and print it to the console.

In the solution, use the built-in sqlite3 package. The built-in csv module may be helpful to work with the csv file.

Expected result:

    77
"""
# Solution I
import csv
import sqlite3

def generate_sql(table_name, col_names, constraints):
    cols = [
        " ".join((col, constraint)).strip()
        for col, constraint in zip(col_names, constraints)
    ]
    return f'CREATE TABLE {table_name} (' + ', '.join(cols) + ')'

with open('../Data/Product.csv', encoding='utf-8') as f:
    reader = csv.reader(f)
    col_names = next(reader)
    product_constraints = [
        'INTEGER PRIMARY KEY',
        'TEXT NOT NULL',
        'INTEGER NOT NULL',
        'INTEGER NOT NULL',
        'TEXT NOT NULL',
        'REAL NOT NULL',
        'INTEGER NOT NULL',
        'INTEGER NOT NULL',
        'INTEGER NOT NULL',
        'INTEGER NOT NULL',
    ]
    sql = generate_sql('Product', col_names, product_constraints)

    conn = sqlite3.connect('../Data/store.db')
    cur = conn.cursor()

    cur.execute('''DROP TABLE IF EXISTS Product''')
    conn.commit()

    cur.execute(sql)

    for row in reader:
        cur.execute(
            '''INSERT INTO Product VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', row
        )

    conn.commit()

    cur.execute('''SELECT COUNT(*) FROM Product''')
    print(cur.fetchone()[0])

    conn.close()

# Solution II
product_constraints = [
    'INTEGER PRIMARY KEY',
    'TEXT NOT NULL',
    'INTEGER NOT NULL',
    'INTEGER NOT NULL',
    'TEXT NOT NULL',
    'REAL NOT NULL',
    'INTEGER NOT NULL',
    'INTEGER NOT NULL',
    'INTEGER NOT NULL',
    'INTEGER NOT NULL',
]

def generate_sql(table_name, col_names, constraints):
    cols = [
        " ".join((col, constraint)).strip()
        for col, constraint in zip(col_names, constraints)
    ]
    return f'CREATE TABLE {table_name} (' + ', '.join(cols) + ')'

# Read csv file
with open('Product.csv', 'r', encoding='utf-8') as file:
    reader = csv.reader(file, delimiter=',')
    columns = next(reader)
    rows = tuple(reader)

# Create SQL code
sql_create_table = generate_sql(
    'Product', columns, product_constraints
)

# Create a DB connection
conn = sqlite3.connect('store.db')
cur = conn.cursor()

# Create Product table
cur.execute(sql_create_table)
cur.executemany(
    '''INSERT INTO Product VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
    rows,
)
conn.commit()

# Select number of rows
cur.execute('''SELECT COUNT(*) FROM Product''')
total_rows = cur.fetchall()[0][0]
print(total_rows)

conn.close()


#!/usr/bin/env python
"""
This script makes the manifest files for each study.

It includes only samples we're interested in (i.e. no robot samples,
no 10 uM samples, etc) and outputs manifest files formatted for QIIME 2.
"""

import pandas as pd

def write_manifest(fout, df, fastqpath, file_prefix):
    """
    Write the QIIME 2 manifest file.

    Parameters
    ----------
    fout : str
        File path to write manifest file to
    df : pandas DataFrame
        DataFrame with 'BMC ID' and 'Sample ID' columns
    fastqpath : str
        path that raw data is in, locally
    file_prefix : str
        the prefix to add to each file (before whatever is in
        the 'BMC ID' column in the dataframe)
    """

    with open(fout, 'w') as f:
        f.write("sample-id,absolute-filepath,direction\n")
        for _, row in df.iterrows():
            sid = row['Sample ID']
            fid = row['BMC ID']
            stem = fastqpath + '/' + file_prefix + fid
            # Forward read
            f.write(','.join([
                sid,
                stem + '_1_sequence.fastq',
                'forward'
            ]) + '\n')
            # Reverse read
            f.write(','.join([
                sid,
                stem + '_2_sequence.fastq',
                'reverse'
            ]) + '\n')

################
# 24-hour study
################

# input metadata file that has BMC IDs <--> sample IDs
fin = "data/raw/16s/24hr/24hr EXP - Metadata April 8,9 2015.xlsx"
# You can also change the fout path to point to something in the
# processing folder if that's easier
fout = "data/raw/16s/24hr/24hr.manifest.csv"
# Note: may need to change this path depending on where the
# qiime2 scripts get called from. fastqpath gives the absolute
# path that tells qiime2 where to find the raw fastq files.
fastqpath = 'data/raw/16s/24hr/fastq'

sheetname = "Labels of samples 16S sequenced"

df = pd.read_excel(fin, sheet_name=sheetname, skiprows=1)
df = df[['BMC ID', 'Sample ID']]

# Keep only the 02 um samples
df = df[df['Sample ID'].str.contains('UW_02um')]

# Write the output manifest file
write_manifest(fout, df, fastqpath, '150702Alm_')

############################
# Upstream/downstream Boston
############################

fin = "data/raw/16s/boston-upstream-downstream/24hr EXP - Metadata April 8,9 2015.xlsx"
fout = "data/raw/16s/boston-upstream-downstream/boston-upstream-downstream.manifest.csv"
fastqpath = 'data/raw/16s/boston-upstream-downstream/fastq'

# Actual sheet name is "Labels of samples sent to 16S seq (batch 2)",
# but downloading from google drive truncates file names and turned this
# one into the same as another sheet, so it got renamed
sheetname = 'Sheet16'

df = pd.read_excel(fin, sheet_name=sheetname, skiprows=1)
df = df[['BMC ID', 'Sample ID']]

# Keep only the 11/04 samples (bc they have paired upstream/downstream sampling)
# and .2 uM filter data
df = df[df['Sample ID'].str.contains('uw_110415_02um')]

# Write the output manifest file
write_manifest(fout, df, fastqpath, '160202Alm_')

################################################
# Boston multi-loc and MIT semester longitudinal
################################################

fin = "data/raw/16s/boston-multi-loc-MIT-long/Metadata - 10 locations.xlsx"
fout = "data/raw/16s/boston-multi-loc-MIT-long/boston-multi-loc-MIT-long.manifest.csv"
fastqpath = 'data/raw/16s/boston-multi-loc-MIT-long/fastq'

sheetname = 'BMC IDs 16S BATCH 1'

# This one doesn't have the data nicely in columns, will need to parse
df = pd.read_excel(fin, sheet_name=sheetname, skiprows=1,
    names=['ix', 'bmc_sample_map', 'xx'])

# Keep just the multi-loc and longitudinal samples
# Note: any samples in this metadata that are labeled with 'B' are blanks,
# we exclude these here.
# So we'll just keep the first 41 rows
df = df.query('ix < 42')

# Now split up the column with all the info into two columns
df = df['bmc_sample_map'].str.split(' : ', expand=True)
df.columns = ['BMC ID', 'Sample ID']
df['Sample ID'] = df['Sample ID'].str.split("(").str[0].str.strip()

# Write the output manifest file
write_manifest(fout, df, fastqpath, '170120AlmA_')

##################
# Kuwait multi-loc
##################

fin = "data/raw/16s/kuwait-multi-loc/Metadata - 10 locations.xlsx"
fout = "data/raw/16s/kuwait-multi-loc/kuwait-multi-loc.manifest.csv"
fastqpath = 'data/raw/16s/kuwait-multi-loc/fastq'

sheetname = 'BMC IDs 16S BATCH 2'

# This one doesn't have the data nicely in columns, will need to parse
df = pd.read_excel(fin, sheet_name=sheetname,
    names=['bmc_sample_map'])

# Here again we'll exclude the blanks. Also I don't know what the
# NDC samples are, so exclude those as well.
df = df.iloc[:14]

# Now split up the column with all the info into two columns
df = df['bmc_sample_map'].str.split(' : ', expand=True)
df.columns = ['BMC ID', 'Sample ID']
df['Sample ID'] = df['Sample ID'].str.split("(").str[0].str.strip()

# Write the output manifest file
write_manifest(fout, df, fastqpath, '170201AlmA_')

#################
# Seoul multi-loc
#################

fin = "data/raw/16s/seoul-multi-loc/Metadata - 10 locations.xlsx"
fout = "data/raw/16s/seoul-multi-loc/seoul-multi-loc.manifest.csv"
fastqpath = 'data/raw/16s/seoul-multi-loc/fastq'

sheetname = 'BMC IDs 16S BATCH 3'

# This one doesn't have the data nicely in columns, will need to parse
df = pd.read_excel(fin, sheet_name=sheetname,
    names=['bmc_sample_map'])

# Here again we'll exclude the blanks. Also I don't know what the
# NDC samples are, so exclude those as well.
df = df.iloc[:9]

# Now split up the column with all the info into two columns
df = df['bmc_sample_map'].str.split(' : ', expand=True)
df.columns = ['BMC ID', 'Sample ID']
df['Sample ID'] = df['Sample ID'].str.split("(").str[0].str.strip()

# Write the output manifest file
write_manifest(fout, df, fastqpath, '170613AlmA_')


import cfscrape, csv, argparse, json, datetime
from bs4 import BeautifulSoup

#Alterando

class Spotify:
    def __init__(self) -> None:
        pass

    def spotify_top_charts(self, country='global', date='latest', frequency='daily', quantity=200):
        scraper = cfscrape.create_scraper()
        url = f'https://spotifycharts.com/regional/{country}/{frequency}/{date}'
        html = scraper.get(url).content
        soup = BeautifulSoup(html, 'html.parser')
        table = soup.find('table', class_='chart-table')
        top_charts = table.find_all('tr')
        for chart in top_charts[1:quantity+1]:
            top_chart = {
                "chart_position":chart.find('td', class_='chart-table-position').text,
                "chart_music_name":chart.select('td > strong')[0].text,
                "chart_author_name":chart.select('td > span')[0].text.strip('by '),
                "total_streams":chart.find('td', class_='chart-table-streams').text
            }
            yield top_chart

    def save_to_csv(self, data, output):
        with open(f'{output}.csv', 'w',newline='', encoding='utf-8') as file:
            fieldnames = ['chart_position', 'chart_author_name', 'chart_music_name', 'total_streams']
            writer = csv.DictWriter(file, fieldnames=fieldnames)
            writer.writeheader()
            for item in data:
                writer.writerow(item)
            print('Saved to csv file!')
            file.close()

    def save_to_json(self, data, output):
        list_to_json = []
        for item in data:
            list_to_json.append(item)
        json_save = {"top_charts":list_to_json}
        with open(f'{output}.json', 'w', encoding='utf-8') as file:
            json.dump(json_save, file)
            file.close()
        print(f'Saved to "{output}.json"')

    def using_argparse(self):
        parser = argparse.ArgumentParser()
        parser.add_argument('-c', required=False, action='store', dest='country', default='global', type=str, help='Insert one country to get the Spotify top charts.')
        parser.add_argument('-d', required=False, action='store', dest='date', type=str, default='latest', help='Date to get the Spotify top charts.')
        parser.add_argument('-f', required=False, action='store', dest='frequency', type=str, default='daily', help='"daily" or "weekly" needed.')
        parser.add_argument('-q', required=False, action='store', dest='quantity', default=200, type=int, help='Quantity of musics to get.')
        parser.add_argument('-o', required=True, action='store', dest='output', type=str, help='File name to save.')
        args = parser.parse_args()
        output = self.spotify_top_charts(country=args.country, date=args.date, frequency=args.frequency, quantity=args.quantity)
        self.save_to_csv(output, args.output)

if __name__ == '__main__':
    spotify_trends = Spotify()
    spotify_trends.using_argparse()


from textwrap import dedent
from scy.scy_task_tree import TaskTree
import pytest

def first_tree_from_string(input_str: str) -> "TaskTree | str":
    return TaskTree.from_string(input_str)[0]

def get_tree_list(func, tree: TaskTree):
    return list(map(func, tree.traverse()))

def test_empty_tree():
    task_tree = TaskTree.from_string("")
    assert not task_tree

@pytest.fixture(params=["from_string", "constructed"])
def mintree(request) -> "TaskTree | str":
    if request.param == "from_string":
        return first_tree_from_string(dedent("""\
            cover a:
                cover b:
                    cover c:
                cover d
        """))
    elif request.param == "constructed":
        a = TaskTree("a", "cover", 1)
        b = TaskTree("b", "cover", 2)
        c = TaskTree("c", "cover", 3)
        d = TaskTree("d", "cover", 4)
        a.add_children([b.add_child(c), d])
        return a
    else:
        return ""

def test_mintree_exists(mintree):
    assert mintree

@pytest.mark.parametrize("xfunc,expected", [
        ("x.stmt", ["cover"]*4),
        ("x.name", ["a", "b", "c", "d"]),
        ("x.depth", [0, 1, 2, 1]),
        ("x.line", [1, 2, 3, 4]),
        ("x.is_root", [True, False, False, False]),
        ("x.is_leaf", [False, False, True, True]),
        ("len(x)", [4, 2, 1, 1]),
        ("len(x.children)", [2, 1, 0, 0]),
        ("len(list(x.traverse()))", [4, 2, 1, 1]),
])
def test_mintree_vals(mintree: TaskTree, xfunc, expected: list):
    assert get_tree_list(lambda x: eval(xfunc), mintree) == expected

@pytest.mark.parametrize("amount,expected", [(1, [0, 0, 1, 0]),
                                             (-1, [1, 2, 3, 2])])
def test_mintree_reduce_depth(mintree: TaskTree, amount: int, expected: list):
    mintree.reduce_depth(amount)
    assert get_tree_list(lambda x: x.depth, mintree) == expected

@pytest.mark.parametrize("input_str,stmt,name,asgmt,body", [
        ("cover", None, None, None, None),
        ("cover a", "cover", "a", None, ""),
        ("cover a:\n", "cover", "a", None, ""),
        ("cover b:\n body", "cover", "b", None, " body"),
        ("cover c\n", "cover", "c", None, ""),
        ("enable cell d e f:\n body\n", "enable", "cell", "d e f", " body\n"),
        ("cover g:\n body\n cover h", "cover", "g", None, " body"),
        ("trace this\n", "trace", "this", None, ""),
        ("trace\n", None, None, None, None),
        #("add assume\n", None, None, None, None),
        ("add assume a b c\n", "add", "assume", "a b c", ""),
        ("enable no body:\n", None, None, None, None),
        ("enable with body:\n ", "enable", "with", "body", " "),
        ("disable that:\n ", "disable", "that", None, " "),
])
def test_task_from_string(input_str, stmt, name, asgmt, body):
    task_tree = first_tree_from_string(input_str)
    if stmt:
        assert isinstance(task_tree, TaskTree)
        assert task_tree.stmt == stmt
        assert task_tree.name == name
        assert task_tree.asgmt == asgmt
        assert task_tree.body == body
    else:
        assert isinstance(task_tree, str)

def test_enable_stmt():
    task_tree = first_tree_from_string(dedent("""\
        cover a:
            enable cell b:
                cover c
    """))

    assert len(task_tree) == 3

    stmts = get_tree_list(lambda x: x.stmt, task_tree)
    assert stmts == ["cover", "enable", "cover"]

    enable_task = task_tree.children[0]
    assert enable_task.stmt == "enable"
    assert enable_task.asgmt == "b"
    assert enable_task.name == "cell"

def test_enable_body():
    task_tree = first_tree_from_string(dedent("""\
        cover a:
            enable cell b
            cover c
    """))
    print(task_tree)
    assert len(task_tree) == 2
    assert task_tree.body.strip() == "enable cell b"
    assert task_tree.has_local_enable_cells

@pytest.fixture
def tree_with_blank():
    return first_tree_from_string(dedent("""\

        cover a
    """))

def test_tree_with_blank_len(tree_with_blank: TaskTree):
    assert len(tree_with_blank) == 1

def test_tree_with_blank_stmt(tree_with_blank: TaskTree):
    assert tree_with_blank.stmt == "cover"

def test_tree_with_blank_line(tree_with_blank: TaskTree):
    assert tree_with_blank.line == 2

def test_bad_stmt():
    task_tree = first_tree_from_string(dedent("""\
        help
    """))

    assert isinstance(task_tree, str)

@pytest.fixture
def no_colon():
    return TaskTree.from_string(dedent("""\
        cover a
            cover b
    """))

def test_no_colon_len(no_colon):
    assert len(no_colon) == 1

def test_no_colon_tree_len(no_colon):
    task_tree = no_colon[0]
    assert len(task_tree) == 1

def test_no_colon_name(no_colon):
    task_tree = no_colon[0]
    assert task_tree.name == "a"

@pytest.fixture(params=[
    {"input_str": "cover a:\n cover b:\n\tcover c:",
     "expected_lens": [3, 1, 1]},
    {"input_str": "cover a:\n cover b:\n\t cover c:",
     "expected_lens": [3, 1, 1]},
    {"input_str": "cover a:\n cover b:\n\t trace c",
     "expected_lens": [3, 1, 1]},
])
def mixed_spacing_input(request):
    return request.param

@pytest.fixture
def mixed_spacing_tree(mixed_spacing_input):
    return TaskTree.from_string(mixed_spacing_input["input_str"])

def test_mixed_spacing(mixed_spacing_input, mixed_spacing_tree):
    expected = mixed_spacing_input["expected_lens"]
    actual = get_tree_list(len, mixed_spacing_tree[0])
    assert actual == expected

@pytest.fixture
def enable_tree():
    a = TaskTree("a", "cover", 0)
    b = TaskTree("cell", "enable", 1, asgmt="b")
    c = TaskTree("c", "cover", 2, enable_cells={"b": {"lhs": "0"}})
    d = TaskTree("d", "cover", 3, body="enable e\n")
    a.add_child(b.add_child(c)).add_child(d)
    return a

def test_enable_tree_len(enable_tree):
    tree_lens = get_tree_list(lambda x: len(x.enable_cells), enable_tree)
    assert tree_lens == [0, 0, 1, 0]

@pytest.fixture(params=[("test", {"val": "zero"}),
                        ("b", {"rhs": "test"})])
def enable_tree_with_cell(request, enable_tree: TaskTree):
    name, cell = request.param
    enable_tree.add_or_update_enable_cell(name, cell)
    return (name, cell, enable_tree)

def test_enable_tree_with_cell(enable_tree_with_cell):
    name, enable_cell, enable_tree = enable_tree_with_cell
    assert enable_tree.enable_cells.get(name) == enable_cell

def test_enable_tree_with_cell_len(enable_tree_with_cell):
    _, _, enable_tree = enable_tree_with_cell
    tree_lens = get_tree_list(lambda x: len(x.enable_cells), enable_tree)
    assert tree_lens == [1, 0, 1, 0]

@pytest.mark.parametrize("recurse", [True, False])
def test_update_children_enable_cells_len(enable_tree_with_cell, recurse):
    name, _, enable_tree = enable_tree_with_cell
    enable_tree.update_children_enable_cells(recurse)
    tree_lens = get_tree_list(lambda x: len(x.enable_cells), enable_tree)
    if name == "b" or not recurse:
        assert tree_lens == [1, 1, 1, 1]
    else:
        assert tree_lens == [1, 1, 2, 1]

@pytest.fixture(params=[
        {"input_str": dedent("""\
                                cover a:
                                    cover b
                                cover c:
                                    cover d
                            """),
         "len": 2, "trees": 2},
        {"input_str": "cover a\ncover b\ncover c",
         "len": 3, "trees": 3},
        {"input_str": "\ncover a\n cover b",
         "len": 1, "trees": 1},
        {"input_str": "cover a:\n cover b\n\ncover c",
         "len": 2, "trees": 2},
        {"input_str": "cover a\nempty\ncover b",
         "len": 3, "trees": 2},
        {"input_str": "\n\n\n",
         "len": 0, "trees": 0},
        {"input_str": "\n \n  \n",
         "len": 1, "trees": 0}, # this one could (should?) be 0 instead
])
def multi_root_input(request):
    return request.param

@pytest.fixture
def multi_root_tree(multi_root_input: "dict[str,str|int]"):
    return TaskTree.from_string(multi_root_input["input_str"])

def test_multi_root_len(multi_root_input: "dict[str,str|int]",
                        multi_root_tree: "list[TaskTree|str]"):
    expected_len = multi_root_input["len"]
    actual_len = len(multi_root_tree)
    assert actual_len == expected_len

def test_multi_root_trees(multi_root_input: "dict[str,str|int]",
                          multi_root_tree: "list[TaskTree|str]"):
    expected_trees = multi_root_input["trees"]
    actual_trees = len([x for x in multi_root_tree if isinstance(x, TaskTree)])
    assert actual_trees == expected_trees

@pytest.mark.parametrize("input_a,input_b,count", [
    ("cover a:\n\tcover b", "cover c:\n\tcover d", 4),
    ("cover a\ncover b", "cover c:\n\tcover d", 3),
    ("cover a:\n\tcover b", "cover c\ncover d", 4),
    ("cover a", "cover b\nstring\ncover c", 3),
])
def test_add_children(input_a: str, input_b: str, count: int):
    tree_a = first_tree_from_string(input_a)
    tree_a.add_children(TaskTree.from_string(input_b))
    assert len(tree_a) == count

@pytest.mark.parametrize([
     "input_str",           "prop",                     "expected",    "child"
    ], [
    ("cover a",             "is_root",                  True,           False),
    ("cover a:\n cover b",  "is_root",                  False,          True),
    ("cover a",             "is_leaf",                  True,           False),
    ("cover a:\n cover b",  "is_leaf",                  False,          False),
    ("cover a:\n cover b",  "is_leaf",                  True,           True),
    ("cover a",             "is_common",                False,          False),
    ("cover a",             "uses_sby",                 True,           False),
    ("trace a",             "uses_sby",                 False,          False),
    ("cover a",             "makes_dir",                True,           False),
    ("trace a",             "makes_dir",                False,          False),
    ("cover a",             "is_runnable",              True,           False),
    ("trace a",             "is_runnable",              True,           False),
    ("append a",            "is_runnable",              False,          False),
    ("cover a",             "has_local_enable_cells",   False,          False),
    ("cover a:\n enable a", "has_local_enable_cells",   True,           False),
    ("cover a:\n disable a","has_local_enable_cells",   True,           False),
    ("cover a",             "tracestr",                 "trace001",     False),
    ("cover a:\n cover b",  "tracestr",                 "trace002",     True),
    ("cover a:\n append 1", "tracestr",                 "trace001",     True),
    ("cover a:\n\n cover b","tracestr",                 "trace003",     True),
    ("cover a",             "linestr",                  "L001_000",     False),
    ("cover a:\n cover b",  "linestr",                  "L002_001",     True),
    ("cover a",             "dir",                      "L001_000_a",   False),
    ("cover a:\n cover b",  "dir",                      "L002_001_b",   True),
    ("cover a",             "children",                  [],            False),
    ("cover a",             "parent",                    None,          False),
    ("cover a:\n #comment", "body",                      " #comment",   False),
])
def test_statement_properties(input_str, prop, expected, child):
    task_tree = first_tree_from_string(input_str)
    if child:
        task_tree = task_tree.children[0]
    actual = getattr(task_tree, prop)
    assert actual == expected

@pytest.mark.parametrize([
     "input_str",           "func",         "expected",     "child"
    ], [
    ("cover a:\n trace b",  "get_dir",    "L001_000_a",   False),
    ("cover a:\n trace b",  "get_dir",    "L001_000_a",   True),
    ("cover a",             "get_asgmt",  None,           False),
    ("enable cell d e f:\n body\n",
                            "get_asgmt",  {"lhs": "d e f"},False),
])
def test_statement_callable(input_str, func, expected, child):
    task_tree = first_tree_from_string(input_str)
    if child:
        task_tree = task_tree.children[0]
    actual = getattr(task_tree, func)()
    assert actual == expected

@pytest.mark.parametrize([
     "func_or_prop",    "expected"
    ], [
    ("tracestr",        "common"),
    ("dir",             "common"),
    ("get_dir()",       "common"),
    ("as_str()",       "L000_000 => common "), # Should this be like this?
    ("uses_sby",        True),
    ("is_common",       True),
])
def test_common_tree(func_or_prop: str, expected):
    common_tree = TaskTree.make_common()
    if func_or_prop.endswith(")"):
        # function call
        actual = eval(f"common_tree.{func_or_prop}")
    else:
        # property
        actual = getattr(common_tree, func_or_prop)
    assert actual == expected

@pytest.fixture(params=[
    {"input_str": "cover a",
     "tree_lines": [1],
     "print_lines": (1, 1)},
    {"input_str": "\ncover a",
     "tree_lines": [2],
     "print_lines": (1, 1)},
    {"input_str": "cover a:\n cover b",
     "tree_lines": [1, 2],
     "print_lines": (1, 2)},
    {"input_str": "cover a:\n\n cover b",
     "tree_lines": [1, 3],
     "print_lines": (1, 2)},
    {"input_str": "cover a:\n \n cover b",
     "tree_lines": [1, 3],
     "print_lines": (1, 2)},
    {"input_str": "cover a:\n text\n cover b",
     "tree_lines": [1, 3],
     "print_lines": (2, 3)},
    {"input_str": "cover a:\n #comment\n cover b",
     "tree_lines": [1, 3],
     "print_lines": (2, 3)},
    {"input_str": "cover a:\n #comment1\n #comment2\n cover b",
     "tree_lines": [1, 4],
     "print_lines": (3, 4)},
    {"input_str": "enable cell d e f:\n body\n",
     "tree_lines": [1],
     "print_lines": (2, 2)}
])
def line_counts_input(request):
    return request.param

@pytest.fixture
def line_counts_tree(line_counts_input):
    return first_tree_from_string(line_counts_input["input_str"])

def test_tree_lines(line_counts_input: "dict[str, list[int]]", line_counts_tree: TaskTree):
    expected = line_counts_input["tree_lines"]
    actual = get_tree_list(lambda x: x.line, line_counts_tree)
    assert actual == expected

@pytest.mark.parametrize("recurse", [True, False])
def test_tree_print_lines(recurse: bool, line_counts_input: "dict[str, tuple[int,int]]", line_counts_tree: TaskTree):
    expected = line_counts_input["print_lines"][1 if recurse else 0]
    actual = line_counts_tree.as_str(recurse)
    print(line_counts_tree.body)
    assert len(actual.splitlines()) == expected

#TODO: get_all_linestr(), start_cycle and stop_cycle


import serial
import re
import matplotlib.pyplot as plt
from collections import deque

# Establish a serial connection to Arduino
ser = serial.Serial('/dev/ttyACM0', 9600)  # Change '/dev/ttyACM0' to match your Arduino's port and 9600 to match your Arduino's baud rate

# Initialize lists to store data
MAX_LENGTH = 50  # Maximum number of data points to display on the graph
timestamps = deque(maxlen=MAX_LENGTH)
temperature = deque(maxlen=MAX_LENGTH)
humidity = deque(maxlen=MAX_LENGTH)
soil_temperature = deque(maxlen=MAX_LENGTH)
soil_moisture = deque(maxlen=MAX_LENGTH)
wind_speed = deque(maxlen=MAX_LENGTH)

# Function to update the live plot
def update_plot():
    plt.clf()  # Clear the previous plot
    plt.subplot(2, 1, 1)
    plt.title('Temperature and Humidity')
    plt.grid(True)
    plt.ylabel('Temperature (°F)')
    plt.plot(timestamps, temperature, 'r-', label='Temperature')
    plt.plot(timestamps, humidity, 'b-', label='Humidity')
    plt.legend(loc='upper left')

    plt.subplot(2, 1, 2)
    plt.title('Soil Temperature, Soil Moisture, and Wind Speed')
    plt.grid(True)
    plt.xlabel('Time')
    plt.ylabel('Value')
    plt.plot(timestamps, soil_temperature, 'r-', label='Soil Temperature')
    plt.plot(timestamps, soil_moisture, 'b-', label='Soil Moisture')
    plt.plot(timestamps, wind_speed, 'g-', label='Wind Speed')
    plt.legend(loc='upper left')

    plt.tight_layout()
    plt.pause(0.01)  # Pause to allow time for the plot to update

# Read data from Arduino and update lists
while True:
    arduino_data = ser.readline().decode().strip()
    if arduino_data:
        try:
            # Extract numerical values using regular expressions
            values = re.findall(r'[0-9.]+', arduino_data)
            if len(values) >= 5:
                air_temp = float(values[0])
                humidity_val = float(values[1])
                soil_temp = float(values[2])
                soil_moisture_val = float(values[3])
                wind_speed_val = float(values[4])

                # Append data to lists
                timestamps.append(timestamps[-1] + 1 if timestamps else 1)  # Incrementing timestamp for each data point
                temperature.append(air_temp)
                humidity.append(humidity_val)
                soil_temperature.append(soil_temp)
                soil_moisture.append(soil_moisture_val)
                wind_speed.append(wind_speed_val)

                # Update the live plot
                update_plot()

        except (ValueError, IndexError) as e:
            print(f"Error parsing data: {e}")


import numpy as np
from pyspark.ml import Estimator, Model
from pyspark.ml.util import DefaultParamsReadable, DefaultParamsWritable
from pyspark import keyword_only
from pyspark.sql.types import ArrayType, FloatType, StructType, StructField
from pyspark.sql.functions import udf
from pyspark.sql import functions as SF

from linreg_params import LinRegModelParams, LinRegEstimatorParams
from linreg_core import NumpyLinReg

def compute_grad_udf(x, y, weights, bias, lr=0.1):
    x = np.array([x])
    y = np.array(y)
    weights = np.array(weights)
    grad_w, grad_b = NumpyLinReg.compute_grad(x, y, weights, bias, lr)
    grad_w = grad_w.tolist()
    grad_b = grad_b.tolist()
    return [grad_w, grad_b]

compute_grad_udf = udf(compute_grad_udf, StructType([
    StructField('weights', ArrayType(FloatType())),
    StructField('bias', FloatType())
]))

class LinRegEstimator(Estimator, LinRegEstimatorParams, DefaultParamsReadable, DefaultParamsWritable):
    @keyword_only
    def __init__(self, lr=0.1, step=100):
        super(LinRegEstimator, self).__init__()
        kwargs = self._input_kwargs
        self.setParams(**kwargs)

    @keyword_only
    def setParams(self, lr=0.1, step=100):
        kwargs = self._input_kwargs
        return self._set(**kwargs)

    def _fit(self, dataset):
        x = self.getInputCol()
        y = self.getTargetCol()
        data_shape = dataset.count()
        x_example = dataset.select(x).limit(1).toPandas().values[0][0]

        weights_bias = NumpyLinReg.init_weights(np.array(x_example))
        for s in range(self.getStep()):
            grad_w_b = self.compute_grad_from_dataset(dataset, x, y, *weights_bias)
            weights_bias = NumpyLinReg.sgd_step(*grad_w_b, *weights_bias, data_shape)

        lr_model = self.init_model(*weights_bias)
        return lr_model

    def compute_grad_from_dataset(self, dataset, x, y, weights, bias):
        grad = dataset.select(self.compute_grad_expr(x, y, weights, bias).alias('grad'))
        grad = grad.select(
            *[SF.col('grad.weights').getItem(i).alias(f'w_{i}') for i, _ in enumerate(weights)],
            'grad.bias'
        )
        grad = grad.select(*[SF.sum(col) for col in grad.columns]).collect()[0]
        grad_w, grad_b = grad[:weights.shape[0]], grad[-1]
        grad_w = np.array(grad_w)[:, None]
        return grad_w, grad_b

    def compute_grad_expr(self, x, y, weights, bias):
        grad_expr = compute_grad_udf(
            SF.col(x), SF.col(y),
            SF.array(*[SF.lit(w.tolist()[0]) for w in weights]),
            SF.lit(bias),
            SF.lit(self.getLearningRate())
        )
        return grad_expr

    @staticmethod
    def init_model(weights, bias):
        weights = weights.squeeze().tolist()
        bias = bias
        lr_model = LinRegModel(
            weights=weights,
            bias=bias
        )
        return lr_model

class LinRegModel(Model, LinRegModelParams, DefaultParamsReadable, DefaultParamsWritable):
    @keyword_only
    def __init__(self, weights, bias):
        super(LinRegModel, self).__init__()
        kwargs = self._input_kwargs
        self.setParams(**kwargs)
        self.predict_udf = udf(self._predict, FloatType())

    @keyword_only
    def setParams(self, weights, bias):
        kwargs = self._input_kwargs
        return self._set(**kwargs)

    def _transform(self, dataset):
        x = self.getInputCol()
        y = self.getOutputCol()
        return dataset.withColumn(y, self.predict_udf(x))

    def _predict(self, x):
        weights = self.getWeights()
        bias = self.getBias()
        weights = np.array(weights)
        x = np.array(x)
        prediction = weights @ x + bias
        return prediction.tolist()

def to_udf(spark_type):
    def udf_wrapper(func):
        return udf(func, spark_type)
    return udf_wrapper


import utils

one_hot = True
balance = False

X_tr, X_te, y_tr, y_te = utils.preprocess_and_split(balance, one_hot)

th = None
if not balance:
    th = 0
    if one_hot:
        th = 0.002
    else:
        th = 0.007

utils.create_datasets(X_tr, X_te, y_tr, y_te, balance=balance, one_hot=one_hot, th=th)


import datetime as dt
import pandas as pd
# async
import asyncio
# Pyppeteer
from pyppeteer import launch

class Run:
    """
    WARNING:

    it's a test no the final implementation

    """

    def __init__(self):
        self.url = 'https://co.talent.com/salary?job='

    async def get_page(self, job_title):
        browser = await launch()
        # launch the browser
        # context = await browser.createIncognitoBrowserContext()
        page = await browser.newPage()
        job_to_search = job_title.replace(' ', '+').lower()
        await page.goto(f'{self.url}{job_to_search}')
        avg_salary = await page.evaluate(
            pageFunction='document.getElementsByClassName("c-card__stats-mainNumber")[0].innerText',
            force_expr=True)

        # second way
        #     hadle = await page.querySelector('.l-card__mainNumber')
        #     content = await hadle.Jeval('div', 'node => node.innerText')

        max_salary = await page.evaluate(
            pageFunction='document.getElementsByClassName("c-card--stats-graph-text")[5].innerText',
            force_expr=True)

        min_salary = await page.evaluate(
            pageFunction='document.getElementsByClassName("c-card--stats-graph-text")[3].innerText',
            force_expr=True)

        amount_salaries = await page.evaluate(
            pageFunction='document.getElementsByClassName("c-card__stats-based")[0].innerText',
            force_expr=True)

        await browser.close()
        return {
            'job_title': job_title,
            'avg_salary': avg_salary,
            'max_salary': max_salary,
            'min_salary': min_salary,
            'amount_salaries': amount_salaries
        }

if __name__ == '__main__':
    jobs = ['back end', 'front end', 'analista de datos', 'analista de sistemas']
    run = Run()
    results = []
    for job in jobs:
        results.append(asyncio.get_event_loop().run_until_complete(run.get_page(job)))
    df = pd.DataFrame(results)
    df.to_csv(path_or_buf='salary.csv', index=False)


# Return subsets sum to K
# Send Feedback
# Given an array A of size n and an integer K, return all subsets of A which sum to K.
# Subsets are of length varying from 0 to n, that contain elements of the array. But the order of elements should remain same as in the input array.
# Note : The order of subsets are not important.
# Input format :
# Line 1 : Integer n, Size of input array
# Line 2 : Array elements separated by space
# Line 3 : K
# Constraints :
# 1 <= n <= 20
# Sample Input :
# 9
# 5 12 3 17 1 18 15 3 17
# 6
# Sample Output :
# 3 3
# 5 1

def printAllSubsetsRec(arr, n, v, sum) :

    # If remaining sum is 0, then print all
    # elements of current subset.
    #x=arr
    if (sum == 0) :
#         if len(v)>1:
#
#             #print(arr)
#             for value in arr:
#                     if value in v:
#                         x.append(value)
#

#         else
        x=[]
        l=len(v)
        x1=l-1
        while(x1>=0):
            x.append(v[x1])
            #print(v[x1],end=" ")
            x1-=1
        print(*x,sep=" ")
        #print()
        return

    # If no remaining elements,
    if (n == 0):
        return

    printAllSubsetsRec(arr, n - 1, v, sum)
    v1 = [] + v
    v1.append(arr[n - 1])
    printAllSubsetsRec(arr, n - 1, v1, sum - arr[n - 1])

# Wrapper over printAllSubsetsRec()
def printAllSubsets(arr, n, sum):

    v = []
    printAllSubsetsRec(arr, n, v, sum)

# Driver code
n = int(input())
arr=list(int(i) for i in input().strip().split(" "))
sum=int(input())
printAllSubsets(arr, n, sum)