from PyQt5.QAxContainer import *
from PyQt5.QtCore import *
from config.errCode import *
from config.kiwoomType import RealType
from config.slack import Slack
from PyQt5.QtTest import *
import os

class Kiwoom(QAxWidget):
    def __init__(self):
        super().__init__() # == QAxWidget.__init__()
        print('class: GetAccountInfo -- api[kiwoom] connected')
        self.slack = Slack()
        self.realType = RealType()

        #_____event loop______#
        self.login_event_loop = QEventLoop() # event loop start - for login
        self.detail_account_info_event_loop = QEventLoop()
        self.calculator_event_loop = QEventLoop()

        #_____account_rel_____#
        self.account_stock_dict = {}
        self.not_signed_stock_dict = {}
        self.portfolio_stock_dict = {}
        self.account_num = None
        self.deposit = 0 # 예수금
        self.use_money = 0
        self.use_money_percent = 0.5
        self.output_deposit = 0
        self.total_profit_loss_money = 0 # 총평가손익금액
        self.total_profit_loss_rate = 0.0 # 총수익률(%)

        #___for_calculate_stock__#
        self.calcul_data=[]

        #_____screen num______#
        self.screen_my_info="2000"
        self.screen_calculate_stock='4000'
        self.screen_real_stock='5000' # 종목별로 할당할 스크린 번호
        self.screen_order_stock='6000' # 종목별로 할당할 '주문용' 스크린 번호
        self.screen_start_stop_real = '1000'

        #_____initial setting___#
        self.get_ocx_instance() # 1. api를 컨트롤하겠다.
        self.event_slots() # 2. event slot들을 만들어주자.
        self.real_event_slots() # 2+. 실시간 event slot 추가
        self.signal_login_commConnect() # 3. login을 요청한다.
        self.get_account_info() # 4. 계좌번호를 출력한다.
        self.detail_account_info() # 5. 예수금 요청 시그널
        self.detail_account_mystock() # 6. 계좌평가잔고내역을 불러온다.
        self.not_concluded_account() # 7. 미체결 종목 불러오기.
        ##self.calculator_fnc() #종목분석
        self.read_code() # 8. 저장된 종목 조회
        self.screen_number_setting() # 9.스크린번호할당

        self.dynamicCall('SetRealReg(QString, QString, QString, QString)',
                    self.screen_start_stop_real,
                    '',
                    self.realType.REALTYPE['장시작시간']['장운영구분'],
                    '0') # 장시작 시간 받을때만 0으로(최초) 나머지 실시간 조회는 모두 '1'로 지정

        for code in self.portfolio_stock_dict.keys():
            screen_num = self.portfolio_stock_dict[code]['스크린번호']
            fids = self.realType.REALTYPE['주식체결']['체결시간']
            self.dynamicCall('SetRealReg(QString, QString, QString, QString)',
                    screen_num,
                    code,
                    fids,
                    '1') # 실시간 종목조회 - '1'로 지정
            print('CODE : {}, SCREEN : {}, FID : {}'.format(code, screen_num, fids))

    def get_code_list_by_market(self, market_code):
        '''
        전체 종목 코드 반환
        '''
        code_list = self.dynamicCall('GetCodeListByMarket(QString)', market_code)
        code_list = code_list.split(';')[:-1]
        return code_list

    def calculator_fnc(self):
        '''
        종목 분석
        '''
        code_list = self.get_code_list_by_market('10') #코스닥 전체 종목 조회
        code_list = code_list[100:]
        print('코스닥 종목 수 : {}'.format(len(code_list)))

        for idx, code in enumerate(code_list):
            self.dynamicCall('DisconnectRealData(QString)', self.screen_calculate_stock)
            print('{} / {} : KOSDAQ Stock Code : {} is updating.. '.format(idx+1, len(code_list), code))
            self.day_kiwoom_db(code=code)

    def day_kiwoom_db(self, code=None, date=None, sPrevNext='0'):

        QTest.qWait(3600) # 이벤트는 살려두고, 실행 지연만 시킴

        self.dynamicCall('SetInputValue(QString, QString)', '종목코드', code)
        self.dynamicCall('SetInputValue(QString, QString)', '수정주가구분', '1')

        if date != None:
            self.dynamicCall('SetInputValue(QString, QString)', '기준일자', date)

        self.dynamicCall('CommRqData(QString, QString, int, QString)',\
             '주식일봉차트조회', 'opt10081', sPrevNext, self.screen_calculate_stock)
        self.calculator_event_loop.exec_()

    ##___api controller____##
    def get_ocx_instance(self):
        self.setControl("KHOPENAPI.KHOpenAPICtrl.1") #.ocx확장자로 저장된 키움 api를 파이썬으로 컨트롤하겠다.

    ##___group of event slots__##
    def event_slots(self): # slot : 이벤트 발생시 slot으로 데이터 회수
        self.OnEventConnect.connect(self.login_slot) # 로그인 요청에 대한 응답이 왔을때 응답을 받도록 연결해둠.
        self.OnReceiveTrData.connect(self.trdata_slot) # 트랜젝션 요청에 대한 응답이 왔을때 응답을 받도록 연결해둠.

    ###___slots__###
    def login_slot(self, err_code):
        print(errors(err_code)[1]) # 로그인 요청에 대한 응답이 오면 에러 코드 출력
        self.login_event_loop.exit() # 에러 코드 출력하고 로그인 이벤트 루프 종료.

    def real_event_slots(self):
        self.OnReceiveRealData.connect(self.realdata_slot)

    def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext):
        if sRQName == '예수금상세현황요청':
            deposit = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                     sTrCode, sRQName, 0, '예수금')
            self.deposit = int(deposit)
            use_money = float(self.deposit)*self.use_money_percent
            self.use_money = int(use_money)
            self.use_money = self.use_money/4 # 4종목 이상 매수를 위함
            # 예수금
            output_deposit = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                            sTrCode, sRQName, 0, '예수금')
            self.output_deposit = int(output_deposit)
            print('예수금 : {}'.format(self.output_deposit))
            # 출금가능금액
            can_exit = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                            sTrCode, sRQName, 0, '출금가능금액')
            self.can_exit = int(can_exit)
            print('출금가능금액 : {}'.format(self.can_exit))
            self.detail_account_info_event_loop.exit()

        elif sRQName == '계좌평가잔고내역요청':
            total_buy_money = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                            sTrCode, sRQName, 0, '총매입금액')
            self.total_buy_money = int(total_buy_money)
            total_profit_loss_money = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                                        sTrCode, sRQName, 0, '총평가손익금액')
            self.total_profit_loss_money = int(total_profit_loss_money)
            total_profit_loss_rate = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                                        sTrCode, sRQName, 0, '총수익률(%)')
            self.total_profit_loss_rate = float(total_profit_loss_rate)
            print('[계좌평가잔고내역요청(싱글)]\n총매입액: {}\n총평가손익:{}\n총수익률(%):{}'.format(\
                self.total_buy_money, self.total_profit_loss_money, self.total_profit_loss_rate ))

            # 보유종목 수 가져오기
            rows = self.dynamicCall('GetRepeatCnt(QString, QString)',sTrCode, sRQName) # 최대 20개
            for i in range(rows):
                code = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                        sTrCode, sRQName, i, '종목번호') # 보유 종목의 종목코드를 순서대로 불러온다
                code = code.strip()[1:]

                code_name = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                            sTrCode, sRQName, i, '종목명')
                code_name = code_name.strip()

                count_stock = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                            sTrCode, sRQName, i, '보유수량')
                count_stock = int(count_stock)

                buy_price = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                            sTrCode, sRQName, i, '매입가')
                buy_price = int(buy_price)

                profit_rate = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                            sTrCode, sRQName, i, '수익률(%)')
                profit_rate = float(profit_rate)

                current_price = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                            sTrCode, sRQName, i, '현재가')
                current_price = int(current_price)

                total_buy_price = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                            sTrCode, sRQName, i, '매입금액')
                total_buy_price = int(total_buy_price)

                count_can_sell_stock = self.dynamicCall('GetCommData(QString, QString, int, QString)',
                                            sTrCode, sRQName, i, '매매가능수량')
                count_can_sell_stock = int(count_can_sell_stock)

                mystockMonit = '[보유종목정보(멀티)]\n종목번호: {} | 종목명: {} | 보유수량: {} | 매입가: {} | 수익률(%): {} | 현재가: {} | 매입금액: {} | 매매가능수량: {}'.\
                    format(code, code_name, count_stock, buy_price, profit_rate, current_price, total_buy_price, count_can_sell_stock)
                print(mystockMonit)
                # self.slack.notification(
                #     text=mystockMonit)

                self.account_stock_dict[code]={}
                self.account_stock_dict[code].update({
                                                    'name':code_name,
                                                    'count':count_stock,
                                                    'buy_price':buy_price,
                                                    'profit_rate':profit_rate,
                                                    'current_price':current_price,
                                                    'total_buy_price':total_buy_price,
                                                    'count_sell':count_can_sell_stock
                                                    })
                print('보유 종목 : {} - {}'.format(code_name,code))

            if sPrevNext == '2':
                print('현재 조회한 종목 수 : 20')
                print('다음 페이지를 조회합니다')
                self.detail_account_mystock(sPrevNext='2')
            else:
                print('현재 조회한 종목 수 : {}'.format(rows))
                print('최종페이지입니다.')
                self.detail_account_info_event_loop.exit()

        elif sRQName == '실시간미체결요청':
            rows = self.dynamicCall('GetRepeatCnt(QString, QString)', sTrCode, sRQName)

            for i in range(rows):
                code = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '종목코드')
                code_name = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '종목명')
                order_no = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '주문번호')
                order_status = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '주문상태')
                order_quantity = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '주문수량')
                order_price = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '주문가격')
                order_sector = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '주문구분')
                not_signed_quantity = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '미체결수량')
                ok_quantity = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '체결량')

                code = code.strip()
                code_name = code_name.strip()
                order_no = order_no.strip()
                order_status = order_status.strip()
                order_quantity = int(order_quantity.strip())
                order_price = int(order_price.strip())
                order_sector = order_sector.strip().lstrip('+').lstrip('-')
                not_signed_quantity = int(not_signed_quantity.strip())
                ok_quantity = int(ok_quantity.strip())

                if order_no in self.not_signed_stock_dict:
                    pass
                else:
                    self.not_signed_stock_dict[order_no]={}
                    self.not_signed_stock_dict[order_no].update({
                        'code':code,
                        'code_name':code_name,
                        'order_status':order_status,
                        'order_quantity':order_quantity,
                        'order_price':order_price,
                        'order_sector':order_sector,
                        'not_signed_quantity':not_signed_quantity,
                        'ok_quantity':ok_quantity
                    })
                    not_signed = '미체결 종목 : {}(주문번호:{})'.format(code_name, order_no)
                    print(not_signed)
                    # self.slack.notification(text=not_signed)

        elif '주식일봉차트조회' == sRQName:
            print('일봉 데이터 요청중..')
            code = self.dynamicCall('GetCommData(QString, QString, int, QString)',\
                sTrCode, sRQName, 0, '종목코드')
            code = code.strip()
            rows = self.dynamicCall('GetRepeatCnt(QString, QString)', sTrCode, sRQName)
            print('데이터 >> {} , {}개'.format(code, rows))

            # data = self.dynamicCall('GetCommDataEx(QString, QString)', sTrCode, sRQName)
            # [['', '현재가', '거래량', '거래대금', '날짜', '시가', '고가',' 저가],
            #  ['', '현재가', '거래량', '거래대금', '날짜', '시가', '고가',' 저가],
            #  ['', '현재가', '거래량', '거래대금', '날짜', '시가', '고가',' 저가],
            #  ...]
            # 이하 동일 코드(for-loop 사용)
            # self.slack.notification(text="['', '현재가', '거래량', '거래대금', '날짜', '시가', '고가',' 저가]")
            for i in range(rows):
                data = []
                current_price = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '현재가')
                trade_count = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '거래량')
                trade_amount = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '거래대금')
                date = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '일자')
                start_price = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '시가')
                high_price = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '고가')
                low_price = self.dynamicCall('GetCommData(QString, QString, int, QString)', sTrCode, sRQName, i, '저가')

                data.append("")
                data.append(current_price.strip())
                data.append(trade_count.strip())
                data.append(trade_amount.strip())
                data.append(date.strip())
                data.append(start_price.strip())
                data.append(high_price.strip())
                data.append(low_price.strip())
                data.append("")

                self.calcul_data.append(data.copy())

            if sPrevNext == '2':
                self.day_kiwoom_db(code=code, sPrevNext=sPrevNext)
            else:
                ## 120일 이평선 조건 | 예시
                print('상장 기간(총 일수) : {}'.format(len(self.calcul_data)))
                pass_success = False # 반복 조건

                # 이평선 그리기 위한 데이터가 충분한지 확인
                if self.calcul_data == None or len(self.calcul_data) < 120:
                    pass_success = False
                else:
                    # 데이터가 충분하다면(120일 이상)
                    total_price = 0
                    for value in self.calcul_data[:120]: # 리스트에는 최근일자부터 순서대로 들어가있음(최근 120일 순회)
                        total_price += int(value[1]) # 현재가(종가) 누적 더하기
                    moving_avg_price = total_price / 120

                    bottom_stock_price = False
                    check_price = None
                    if int(self.calcul_data[0][7]) <= moving_avg_price and moving_avg_price <= int(self.calcul_data[0][6]):  # 가장최근일(오늘) 저가
                        code_nm = self.dynamicCall('GetMasterCodeName(QString)', code)
                        msg = '[매수신호] 오늘 {} ({}) 주가 - 120 이평선에 걸쳐있음'.format(code_nm, code)
                        print(msg)
                        self.slack.notification(text=msg)
                        bottom_stock_price = True
                        check_price = int(self.calcul_data[0][6]) #고가

                    past_price = None
                    # 과거 일봉 조회 (120일 이평선보다 밑에 있는지 확인)
                    if bottom_stock_price == True:
                        moving_avg_price_past = 0
                        price_top_moving = False

                        idx = 1
                        while True:
                            if len(self.calcul_data[idx:]) < 120: # 데이터 충분한지(120일) 계속 확인
                                print('데이터 부족함(120일치 데이터 필요)')
                                break
                            else:
                                total_price = 0
                                for value in self.calcul_data[idx:idx+120]:
                                    total_price += int(value[1]) # 과거 종가 누적 더하기
                                moving_avg_price_past = total_price / 120

                                if moving_avg_price_past <= int(self.calcul_data[idx][6]) and idx <= 20:
                                    price_top_moving = False
                                    break

                                elif int(self.calcul_data[idx][7]) > moving_avg_price_past and idx > 20:
                                    print('120일 이평선 위에 있는 일봉 확인')
                                    price_top_moving = True
                                    past_price = int(self.calcul_data[idx][7])
                                    break
                                idx += 1

                            if price_top_moving == True:
                                if moving_avg_price > moving_avg_price_past and check_price > past_price:
                                    print('매수신호 포착')
                                    pass_success = true
                    if pass_success == True:
                        print('포착된 종목 저장..')
                        code_nm = self.dynamicCall('GetMasterCodeName(QString)', code)
                        msg = '{},{},{}\n'.format(code, code_nm, str(self.calcul_data[0][1]))
                        f = open('files/condition_stock.txt', 'a', encoding='utf8')
                        f.write('%s,%s,%s\n' % (code, code_nm, str(self.calcul_data[0][1])))
                        f.close()
                        self.slack.notification(text=msg)

                    elif pass_success == False:
                        code_nm = self.dynamicCall('GetMasterCodeName(QString)', code)
                        msg = '{} -{} | 조회 | 매수신호 포착되지 않음'.format(code, code_nm)
                        print(msg)
                        self.slack.notification(text=msg)
                    self.calcul_data.clear()
                    self.calculator_event_loop.exit()

                self.calculator_event_loop.exit()

        self.stop_screen_cancel(self.screen_my_info)
        self.detail_account_info_event_loop.exit()

    ##_____request_login_____##
    def signal_login_commConnect(self):
        self.dynamicCall("CommConnect()") # login request signal
        self.login_event_loop.exec() ## 요청에 대해 응답이 올때까지 대기

    ##_____request_account____##
    def get_account_info(self):
        account_list = self.dynamicCall("GetLoginInfo(QString)", "ACCNO") # request account number signal
        account_num = account_list.split(';')[1] # first account(모의투자 계좌)

        self.account_num = account_num
        print("account : {}".format(account_num))

    def detail_account_info(self, sPrevNext='0'): # 첫 조회 : sPrevNext='0'
        print('예수금 요청중..')
        self.dynamicCall('SetInputValue(QString, QString)','계좌번호', self.account_num)
        self.dynamicCall('SetInputValue(QString, QString)','비밀번호', '0000')
        self.dynamicCall('SetInputValue(QString, QString)','비밀번호입력매체구분','0000')
        self.dynamicCall('SetInputValue(QString, QString)','조회구분','1')
        self.dynamicCall('CommRqData(QString, QString, int, QString)',\
            '예수금상세현황요청','opw00001',sPrevNext, self.screen_my_info)
        self.detail_account_info_event_loop = QEventLoop()
        self.detail_account_info_event_loop.exec_()

    def stop_screen_cancel(self, sScrNo=None):
        self.dynamicCall('DisconnectRealData(QString)',sScrNo)

    def detail_account_mystock(self, sPrevNext='0'): #싱글데이터
        self.dynamicCall('SetInputValue(QString, QString)', '계좌번호', self.account_num)
        self.dynamicCall('SetInputValue(QString, QString)', '비밀번호', '0000') # 모의투자 공통 0000
        self.dynamicCall('SetInputValue(QString, QString)', '비밀번호입력매체구분', '00')
        self.dynamicCall('SetInputValue(QString, QString)', '조회구분', '1') # 1:합산, 2:개별
        self.dynamicCall('CommRqData(QString, QString, int, QString)', '계좌평가잔고내역요청', 'opw00018', sPrevNext, self.screen_my_info)
        self.detail_account_info_event_loop.exec_()

    def not_concluded_account(self, sPrevNext='0'):
        print('미체결 종목 요청중..')
        self.dynamicCall('SetInputValue(QString, QString)', '계좌번호', self.account_num)
        self.dynamicCall('SetInputValue(QString, QString)', '체결구분', '1')
        self.dynamicCall('SetInputValue(QString, QString)', '매매구분', '0')
        self.dynamicCall('CommRqData(QString, QString, int, QString)',
                        '실시간미체결요청','opt10075', sPrevNext, self.screen_my_info)
        self.detail_account_info_event_loop.exec_()

    def read_code(self):
        file_path = 'files/condition_stock.txt'
        if os.path.exists(file_path):
            f = open(file_path, 'r', encoding='utf8')

            lines = f.readlines()
            for line in lines:
                if line != '':
                    ls = line.split(',')
                    stock_code = ls[0]
                    stock_name = ls[1]
                    stock_price = abs(int(ls[2].split('\n')[0]))

                    self.portfolio_stock_dict.update({
                        stock_code: {'종목명':stock_name,'현재가':stock_price}
                    })
            f.close()

            print(self.portfolio_stock_dict)

    def screen_number_setting(self):
        screen_overwrite = []

        # 계좌평가잔고내역에 있는 종목들
        for code in self.account_stock_dict.keys():
            if code not in screen_overwrite:
                screen_overwrite.append(code)

        # 미체결에 있는 종목들
        for order_number in self.not_signed_stock_dict.keys():
            code = self.not_signed_stock_dict[order_number]['종목코드']

            if code not in screen_overwrite:
                screen_overwrite.append(code)

        # 포트폴리오에 담겨있는 종목들
        for code in self.portfolio_stock_dict.keys():
            if code not in screen_overwrite:
                screen_overwrite.append(code)

        # 스크린번호 할당
        cnt = 0 # 스크린번호 하나에 최대 100개 요청가능
        for code in screen_overwrite:
            real_screen = int(self.screen_real_stock)
            order_screen = int(self.screen_order_stock)

            if (cnt % 50) == 0: # 스크린번호 하나에 종목코드 최대 50개만 할당함
                real_screen += 1 # 5000 => 5001
                self.screen_real_stock = str(real_screen)

            if (cnt % 50) == 0:
                order_screen += 1 # 6000 -> 6001
                self.screen_order_stock = str(order_screen)

            if code in self.portfolio_stock_dict.keys():
                self.portfolio_stock_dict[code].update({
                    '스크린번호':str(self.screen_real_stock),
                    '주문용스크린번호':str(self.screen_order_stock)
                })
            elif code not in self.portfolio_stock_dict.keys():
                self.portfolio_stock_dict.update({
                    code: {'스크린번호': str(self.screen_real_stock),
                           '주문용스크린번호': str(self.screen_order_stock)}
                        })
            cnt += 1
        print(self.portfolio_stock_dict)

    def realdata_slot(self, sCode, sRealType, sRealData):

        if sRealType == '장시작시간':
            fid = self.realType.REALTYPE[sRealType]['장운영구분']
            chk = self.dynamicCall('GetCommRealData(QString, int)',
                            sCode, fid)

            if chk == '0':
                print('장 시작 전')
            elif chk == '3':
                print('장 시작')
            elif chk == '2':
                print('장 종료, 동시호가 전환')
            elif chk == '4':
                print('장 종료 (3:30)')

        elif sRealType == '주식체결':
            currtime = self.dynamicCall('GetCommRealData(QString,int)',
                            sCode, self.realType.REALTYPE[sRealType]['체결시간'])
            currprice = self.dynamicCall('GetCommRealData(QString,int)',
                            sCode, self.realType.REALTYPE[sRealType]['현재가'])
            currprice = abs(int(currprice))

            addprice = self.dynamicCall('GetCommRealData(QString,int)',
                            sCode, self.realType.REALTYPE[sRealType]['전일대비'])
            addprice = abs(int(addprice))

            perprice = self.dynamicCall('GetCommRealData(QString,int)',
                            sCode, self.realType.REALTYPE[sRealType]['등락율'])
            perprice = float(perprice)

            bestsellprice = self.dynamicCall('GetCommRealData(QString,int)',
                            sCode, self.realType.REALTYPE[sRealType]['(최우선)매도호가'])
            bestsellprice = abs(int(bestsellprice))

            bestbuyprice = self.dynamicCall('GetCommRealData(QString,int)',
                            sCode, self.realType.REALTYPE[sRealType]['(최우선)매수호가'])
            bestbuyprice = abs(int(bestbuyprice))

            amount = self.dynamicCall('GetCommRealData(QString,int)',
                            sCode, self.realType.REALTYPE[sRealType]['거래량'])
            amount = abs(int(amount))

            if sCode not in self.portfolio_stock_dict:
                self.portfolio_stock_dict.update({sCode:{}})

            self.portfolio_stock_dict[sCode].update({
                '체결시간':currtime,
                '현재가':currprice,
                '전일대비':addprice,
                '등락율':perprice,
                '(최우선)매도호가':bestsellprice,
                '(최우선)매수호가':bestbuyprice,
                '거래량':amount
            })
            print(self.portfolio_stock_dict[sCode])
            self.slack.notification(text = self.portfolio_stock_dict[sCode])


#!/usr/bin/env python3
"""
    Session Authentication Module
"""
from api.v1.auth.auth import Auth
from api.v1.views.users import User
import uuid
from typing import TypeVar

class SessionAuth(Auth):
    """
        Responsible for session Authentication
        Inherits From auth class
    """
    user_id_by_session_id = {}

    def create_session(self, user_id: str = None) -> str:
        """
            creates a session ID for a user_id
            args:
                user_id: str - id of user
            return:
                Session id
        """
        if user_id is None or type(user_id) is not str:
            return None
        else:
            session_id: str = str(uuid.uuid4())
            self.user_id_by_session_id[session_id] = user_id
            return session_id

    def user_id_for_session_id(self, session_id: str = None) -> str:
        """
            Return User id based on the session id
            Args:
                session_id: str : session id
            Return:
                user_id: str : user id
        """
        if session_id is None or type(session_id) is not str:
            pass
        else:
            user_id: str = self.user_id_by_session_id.get(session_id)
            return user_id

    def current_user(self, request=None):
        """
            Returns the user Id
            Args:
                request
            Return:
                user_id
        """
        session_cookie = self.session_cookie(request)
        user_id = self.user_id_for_session_id(session_cookie)
        return User.get(user_id)

    def destroy_session(self, request=None):
        """
            deletes the user session / logout:
        """
        if request is None:
            return False
        else:
            session_token = self.session_cookie(request)
            if session_token:
                user_id = self.user_id_for_session_id(session_token)
                if user_id:
                    del self.user_id_by_session_id[session_token]
                    return True
                else:
                    return False
            else:
                return False


from Algorithms.Usefull_elements import Step, intersection, addition, get_edges, invert_Graph, vertex_list_to_str, hsv_to_hex, replace_color
import copy
from collections import defaultdict

def algorithm_depth_first_search(matrix):
    mass = list() # массив смежных вершин
    vertex_mark = dict() # объявление пустого словаря (соотв. вершин меткам)
    vertex = list() # объявление пустого списка (вершины без меток)
    stack = list() # объявление пустого списка (стек)
    all_vertex = [] # список вершин
    steps = [] # список шагов
    alg_result = [] # шаг-результат
    edges = [] # список рёбер
    route = [] # маршрут
    loop = False # нет контура

    # вложенная функция, реализующая алгоритм
    def dfs(prev_ver, cur_ver):
        print(f' Текущая вершина: {cur_ver}')
        #h_step.node_options[cur_ver] = replace_color(h_step.node_options[cur_ver], "#DC143C") # изменение цвета по маршруту
        h_step.node_options[cur_ver] += ', borderWidth: 3, color: {border: "#DC143C", background: "#1E90FF", highlight: { border: "#DC143C" }}'; # изменение цвета границы по маршруту
        vertex_mark[cur_ver] = False # вершина просмотрена
        while mass[cur_ver]: # пока есть смежные вершины
            # h_step.edge_options[(cur_ver, mass[cur_ver][0])] += replace_color(h_step.edge_options[(cur_ver, mass[cur_ver][0])], "#DC143C")  # подкрашиваем ребро
            if vertex_mark[mass[cur_ver][0]] == None: # МОЖЕТ БЫТЬ ПЕТЛЯ or vertex_mark[mass[cur_ver][0]] == False
                h_step.edge_options[(cur_ver, mass[cur_ver][0])] += ', "color": "#DC143C", width: 3'  # подкрашиваем ребро
            if vertex_mark[mass[cur_ver][0]] == None:
                print(f' Переходим к смежной вершине: {mass[cur_ver][0]}')
                route.append(cur_ver) # добавляем вершину в маршрут
                # переходим к первой смежной вершине
                if not dfs(cur_ver, mass[cur_ver][0]): # обнаружен контур
                    return False
                print(f' Возвращаемся к вершине {cur_ver}')
                h_step.text = f'
Возвращаемся к вершине {cur_ver}
' + h_step.text
                print(f' Текущая вершина: {cur_ver}')
                mass[cur_ver].pop(0) # удаляем просмотренную смежную вершину
            elif vertex_mark[mass[cur_ver][0]]:
                mass[cur_ver].pop(0) # удаляем просмотренную смежную вершину
            else:
                return False # обнаружен контур
        print(f'Смежных непомеченных вершин нет, помещаем в стек вершину {cur_ver}')
        vertex_mark[cur_ver] = True # определён порядок вершины
        stack.append(cur_ver) # помещаем вершину в стек
        vertex.remove(cur_ver) # исключаем вершину для повторного просмотра

        for ver in route:
            h_step.text += f'{ver}->'
        if route:
            route.pop()
            h_step.text += f'{cur_ver}

Вершина {cur_ver} не имеет смежных вершин, добавляем её в стек {stack}
' # последний текст шага
        else:
            h_step.text = f'
Возвращаемся к вершине {cur_ver}

Некуда шагать!

Вершина {cur_ver} не имеет смежных вершин, добавляем её в стек {stack}
' # последний текст шага
        h_step.step_label = f'Добавление вершины x{cur_ver} в стек' # название шага
        h_step.node_options[cur_ver] += ', borderWidth: 1, "color": "#00FA9A"' # изменение цвета

        new_step = copy.deepcopy(h_step)
        h_step.text = '
Маршрут обхода: ' # текст шага
        if prev_ver != cur_ver and (prev_ver, cur_ver) in edges:
            h_step.edge_options[(prev_ver, cur_ver)] += ', "color": "#1E90FF", width: 1'  # возвращаем цвет ребру
        # print(new_step.edge_options)
        steps.append(new_step) # добавляем шаг в список
        new_step = Step(True, True) # создаём новый шаг

        return True

    # инициализация
    size_of_matrix = len(matrix) # получаем размер матрицы
    for i in range(size_of_matrix):
        # словарь соответствия исходных вершин меткам
        vertex_mark.update({i: None})
        # формирование множеста непомеченных вершин
        vertex.append(i)
        # формирование массива смежных вершин
        neighbor = list() # смежные вершины
        for j in range(size_of_matrix):
            if matrix[i][j] == 1:
                neighbor.append(j)
        mass.append(neighbor)
    edges = get_edges(matrix) # список рёбер
    all_vertex = vertex.copy()
    print(f'Вершины: {all_vertex}')

    # исходный граф
    first_step = Step(True, True) # создаём первый шаг (исходный граф)
    first_step.text = '
Это граф по введённой матрице
' # текст шага
    first_step.nodes = all_vertex # список вершин
    first_step.edges = edges # список ребер

    # общие опции для рёбер
    for edge in edges.keys():
        first_step.edge_options[edge] = 'label: "1"'
        first_step.edge_options[edge] += ', "color": "#1E90FF"'
    print(f'рёбра: {first_step.edge_options}')

    for i in all_vertex: # метки для вершин
        first_step.node_options[i] = f'label: "x{i}"'
        first_step.node_options[i] += ', shape: "circle"'
        first_step.node_options[i] += ', "color": "#1E90FF"'

    # выбор начальной вершины обхода
    h_step = copy.deepcopy(first_step) # создаём вспомогательный объект (шаг)
    print(vertex)
    while vertex:
        new_step = copy.deepcopy(first_step) # создаём первый шаг
        h_step.text = '
Маршрут обхода: ' # текст шага
        if not dfs(0, vertex[0]): # запуск алгоритма
            loop = True
            print('Выполнение алгоритма прервано из-за наличия контура')
            break
    print(f'Вершины в стеке:', list(map(lambda el: el, stack)))
    if not loop:
        print('Алгоритм успешно завершен')

        result_step = copy.deepcopy(first_step)
        result_step.text = f'
Стек - {stack} ({stack[-1]} - вершина стека)
'
        result_step.text += '
Это граф, разбитый на уровни
' # текст шага
        stack.reverse() # переворачиваем список для следования вершин по уровням
        for ver in stack: # установка уровней для вершин
            result_step.node_options[ver] = f'label: "x{ver}"'
            result_step.node_options[ver] += ', shape: "circle"'
            result_step.node_options[ver] += ', "color": "#1E90FF"'
            result_step.node_options[ver] += f', level: {stack.index(ver)}'

        neighbor_ver = [] # пары вершин соседних уровней
        for i in range(len(stack)-1):
            neighbor_ver.append(tuple([stack[i], stack[i+1]]))

        print(f'Пары смежных вершин: {neighbor_ver}')

        result_step.general_options += ', layout: { hierarchical: { direction: "LR", levelSeparation: 100} }'
        flag = True
        for edge in edges.keys():
            # result_step.edge_options[edge] = 'smooth: { "enabled": true, "type": "curvedCCW", "forceDirection": "none" }, width: 1'
            if edge in neighbor_ver:
                result_step.edge_options[edge] = 'smooth: { "enabled": true, "type": "dynamic", roundness: 0 }, width: 1'
            elif flag:
                result_step.edge_options[edge] = 'smooth: { "enabled": true, "type": "curvedCW", roundness: 0.5 }, width: 1'
                flag = False
            else:
                result_step.edge_options[edge] = 'smooth: { "enabled": true, "type": "curvedCCW", roundness: 0.5 }, width: 1'
                flag = True

        alg_result.append(result_step)
    else:
        print('ОШИБКА')
        result_step = Step(True, True)
        result_step.text = '
АЛГОРИТМ ПРЕРВАН ИЗ-ЗА НАЛИЧИЯ КОНТУРА В ГРАФЕ!
' # текст шага
        alg_result.append(result_step)

    # добавление таблицы в исходные данные
    alg_input = Step(True, True, True)
    alg_input.text = copy.deepcopy(first_step.text)
    alg_input.nodes = copy.deepcopy(first_step.nodes)
    alg_input.edges = copy.deepcopy(first_step.edges)
    alg_input.edge_options = copy.deepcopy(first_step.edge_options)
    alg_input.node_options = copy.deepcopy(first_step.node_options)
    first_line = []
    first_line.append('')
    for i in range(size_of_matrix):
        first_line.append(f'x{i}')
    alg_input.matrix.append(list(first_line))
    for i in range(size_of_matrix):
        next_line = []
        next_line.append(f'x{i}')
        next_line += (list(matrix[i]))
        alg_input.matrix.append(list(next_line))
    for i in range(1, size_of_matrix+1):
        alg_input.matrix[i][i] = -1

    return [ alg_input, steps, alg_result ]

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

# топологическая соритровка, алгоритм Демукрона

# диалог с пользователем
def demukron(matrix):
    vertex_level = dict() # объявление пустого словаря (соотв. вершин уровням)
    vertex = set() # объявление пустого множества (вершины без уровня)
    all_vertex = [] # список вершин
    edges = [] # список рёбер
    steps = [] # список шагов
    alg_result = [] # шаг-результат

    # реализация алгоритма
    def dm(vertex):

        step = Step(False, True, True) # создание первого шага
        # формирование исходной матрицы
        first_line = []
        first_line.append('')
        for i in range(size_of_matrix):
            first_line.append(f'x{i}')
        step.matrix.append(list(first_line))
        for i in range(size_of_matrix):
            next_line = []
            next_line.append(f'x{i}')
            next_line += (list(matrix[i]))
            step.matrix.append(list(next_line))
        for i in range(1, size_of_matrix+1):
            step.matrix[i][i] = -1

        # формирование уровня
        level = 0
        while vertex:

            step = copy.deepcopy(step)
            step.text = '
'

            flag = False # уровень отсутствует
            level_v = set()  # вершины формируемого уровня
            for i in vertex: # просмотр столбца матрицы
                sum = 0
                # просмотр входящих вершин
                for j in range(len(matrix)):
                    sum += matrix[j][i]
                if sum == 0:
                    level_v.add(i) # добавление вершины в уровень
                    vertex_level[i] = level # обновление уровня вершины
                    flag = True # уровень найден
            if flag:
                print(f'Вершины {level} уровня: ', set(map(lambda el: el, level_v)))
            else:
                return False # уровень не сформирован
            for i in level_v:
                matrix[i] = list(map(lambda el: 0, matrix[i]))  # удаление(зануление) строки

            # удаление строки
            for ver in level_v:
                for i in range(1, size_of_matrix+1):
                    step.matrix[ver+1][i] = -1
                step.text += f'Вершина x{ver} не имеет входящих рёбер
'
            step.text += f'Формируем уровень N{level}  = ' + '{&nbsp'
            for ver in level_v:
                step.text += f'x{ver}&nbsp'
            step.text += '}
'
            for ver in level_v:
                step.text += f'Порядковая функция O(x{ver}) = {level}
'
            step.text += '
'
            step.step_label = f'Формирование уровня N {level}'

            steps.append(step)

            print(f'матрица {matrix}')
            vertex -= level_v # исключение вершин с определённым уровнем
            level += 1
        return True

    # инициализация
    for i in range(len(matrix)):
        # словарь соответствия исходных вершин уровням
        vertex_level.update({i: None})
        # формирование множеста вершин без уровня
        vertex.add(i)
    edges = get_edges(matrix) # список рёбер
    all_vertex = vertex.copy() # список вершин

    # исходный граф
    alg_input = Step(True, True, True) # создаём первый шаг (исходный граф)
    alg_input.text = '
Это граф по введённой матрице
' # текст шага
    alg_input.nodes = all_vertex # список вершин
    alg_input.edges = edges # список ребер

    # общие опции для рёбер
    for edge in edges.keys():
        alg_input.edge_options[edge] = 'label: "1"'
        alg_input.edge_options[edge] += ', "color": "#1E90FF"'
    print(f'рёбра: {alg_input.edge_options}')

    for i in all_vertex: # метки для вершин
        alg_input.node_options[i] = f'label: "x{i}"'
        alg_input.node_options[i] += ', shape: "circle"'
        alg_input.node_options[i] += ', "color": "#1E90FF"'

    # добавление таблицы в исходные данные
    size_of_matrix = len(matrix)
    first_line = []
    first_line.append('')
    for i in range(size_of_matrix):
        first_line.append(f'x{i}')
    alg_input.matrix.append(list(first_line))
    for i in range(size_of_matrix):
        next_line = []
        next_line.append(f'x{i}')
        next_line += (list(matrix[i]))
        alg_input.matrix.append(list(next_line))
    for i in range(1, size_of_matrix+1):
        alg_input.matrix[i][i] = -1

    res = dm(vertex) # запуск алгоритма
    if res:
        print('Алгоритм успешно завершен')
        print(f'Вершины по уровням: {vertex_level}')
        result_step = copy.deepcopy(alg_input)
        result_step.matrix = []
        result_step.text = f'
Разделение вершин по уровням - {vertex_level})
'
        result_step.text += '
Это граф, разбитый на уровни
' # текст шага
        for ver, level in vertex_level.items(): # установка уровней для вершин
            result_step.node_options[ver] = f'label: "x{ver}"'
            result_step.node_options[ver] += ', shape: "circle"'
            result_step.node_options[ver] += ', "color": "#1E90FF"'
            result_step.node_options[ver] += f', level: {level}'

        neighbor_ver = [] # пары вершин соседних уровней
        sorted_levels = sorted(set(vertex_level.values()))  # Получение уникальных значений уровней и их сортировка
        for level in sorted_levels[:-1]:  # Проход по уровням, исключая последний
            current_level_vertices = [vertex for vertex, vertex_level in vertex_level.items() if vertex_level == level]  # Вершины текущего уровня
            next_level_vertices = [vertex for vertex, vertex_level in vertex_level.items() if vertex_level == level + 1]  # Вершины следующего уровня
            neighbor_pairs = [(v1, v2) for v1 in current_level_vertices for v2 in next_level_vertices]  # Пары соседних вершин
            neighbor_ver.extend(neighbor_pairs)  # Добавление пар в список

        result_step.general_options += ', layout: { hierarchical: { direction: "LR", levelSeparation: 100, nodeSpacing: 150} }'

        print(edges)
        print(neighbor_ver)
        flag = True
        for edge in edges.keys():
            # result_step.edge_options[edge] = 'smooth: { "enabled": true, "type": "curvedCCW", "forceDirection": "none" }, width: 1'
            if edge in neighbor_ver:
                result_step.edge_options[edge] = 'smooth: { "enabled": true, "type": "dynamic", roundness: 0 }, width: 1'
            elif flag:
                result_step.edge_options[edge] = 'smooth: { "enabled": true, "type": "curvedCW", roundness: 0.5 }, width: 1'
                flag = False
            else:
                result_step.edge_options[edge] = 'smooth: { "enabled": true, "type": "curvedCCW", roundness: 0.5 }, width: 1'
                flag = True

        sorted_dict = defaultdict(list)
        for vertex, level in vertex_level.items():
            sorted_dict[level].append(vertex)
        sorted_dict = dict(sorted(sorted_dict.items()))

        result_step.text = '
'
        for level, ver in sorted_dict.items():
            result_step.text += f'Уровень N{level}  = ' + '{&nbsp'
            for x in (ver):
                result_step.text += f'x{x}&nbsp'
            result_step.text += '}
'
        result_step.text += '
'
        alg_result.append(result_step)
    else:
        print('Выполнение алгоритма прервано из-за наличия контура')
        result_step = Step()
        result_step.text = '
АЛГОРИТМ ПРЕРВАН ИЗ-ЗА НАЛИЧИЯ КОНТУРА В ГРАФЕ!
' # текст шага
        alg_result.append(result_step)

    return [ alg_input, steps, alg_result ]


"""
Filename:     plot_zonal_mean.py
Author:       Damien Irving, irving.damien@gmail.com
Description:

"""

# Import general Python modules

import sys, os, pdb
import argparse
import numpy
import matplotlib.pyplot as plt
from matplotlib import gridspec
import iris
import iris.plot as iplt
from iris.experimental.equalise_cubes import equalise_attributes
import seaborn

# Import my modules

cwd = os.getcwd()
repo_dir = '/'
for directory in cwd.split('/')[1:]:
    repo_dir = os.path.join(repo_dir, directory)
    if directory == 'ocean-analysis':
        break

modules_dir = os.path.join(repo_dir, 'modules')
sys.path.append(modules_dir)

try:
    import general_io as gio
    import timeseries
    import grids
    import convenient_universal as uconv
except ImportError:
    raise ImportError('Must run this script from anywhere within the ocean-analysis git repo')

# Define functions

experiment_colors = {}
experiment_colors['historical'] = 'green'
experiment_colors['piControl'] = 'black'
experiment_colors['historicalAA'] = 'blue'
experiment_colors['historicalGHG'] = 'red'
experiment_colors['historicalnoAA'] = 'orange'

basins = {'atlantic': 2,
          'pacific': 3,
          'indian': 5}

def scale_data(cube, var, reverse_sign=False):
    """Scale data"""

    if var == 'precipitation_minus_evaporation_flux':
        cube.data = cube.data * 86400
        units = 'mm/day'
    else:
        units = cube.units

    if reverse_sign:
        cube.data = cube.data * -1

    return cube, units

def set_plot_grid(tas_trend=False):
    """Set the grid of plots.

    Args:
      tas_trend (bool): Include a panel for the tas trend?

    """

    if tas_trend:
        nrows = 4
        heights = [2, 1, 1, 1]
    else:
        nrows = 3
        heights = [2, 1, 1]

    gs = gridspec.GridSpec(nrows, 1, height_ratios=heights)

    return gs

def calculate_climatology(cube, time_bounds, experiment):
    """Calculate annual mean climatology"""

    if not experiment == 'piControl':
        time_constraint = gio.get_time_constraint(time_bounds)
        cube = cube.extract(time_constraint)

    cube = cube.collapsed('time', iris.analysis.MEAN)
    cube.remove_coord('time')

    return cube

def calc_linear_trend(data, xaxis):
    """Calculate the linear trend.
    polyfit returns [a, b] corresponding to y = a + bx
    """

    if data.mask[0]:
        return data.fill_value
    else:
        return numpy.polynomial.polynomial.polyfit(xaxis, data, 1)[-1]

def get_trend_cube(cube, xaxis='time'):
    """Get the trend data.
    Args:
      cube (iris.cube.Cube)
      xaxis (iris.cube.Cube)
    """

    coord_names = [coord.name() for coord in cube.dim_coords]
    assert coord_names[0] == 'time'

    if xaxis == 'time':
        trend_data = timeseries.calc_trend(cube, per_yr=True)
        trend_unit = ' yr-1'
    else:
        trend_data = numpy.ma.apply_along_axis(calc_linear_trend, 0, cube.data, xaxis.data)
        trend_data = numpy.ma.masked_values(trend_data, cube.data.fill_value)
        trend_unit = ' '+str(xaxis.units)+'-1'

    trend_cube = cube[0, ::].copy()
    trend_cube.data = trend_data
    trend_cube.remove_coord('time')
    trend_cube.units = str(cube.units) + trend_unit

    return trend_cube

def get_scale_factor(tas_cube):
    """Calculate scale factor (linear warming).

    Multiplies the linear trend (K / yr) by the number of years

    """

    linear_trend = get_trend_cube(tas_cube)
    scale_factor = linear_trend.data * tas_cube.shape[0]

    return scale_factor

def plot_climatology(climatology_dict, var, units, legloc, aggregation='Zonal mean'):
    """Plot the zonal mean climatology"""

    for experiment in ['historical', 'historicalGHG', 'historicalAA', 'historicalnoAA', 'piControl']:
        if climatology_dict[experiment]:
            color = experiment_colors[experiment]
            iplt.plot(climatology_dict[experiment], color=color, alpha=0.8, label=experiment)

    plt.legend(loc=legloc)
    plt.ylabel('%s %s (%s)' %(aggregation, var.replace('_', ' '), units) )

def check_lats(climatology_dict, experiment):
    """Sometimes the latitude axes are not exactly equal after regridding."""

    experiment_lats = climatology_dict[experiment].coord('latitude')
    control_lats = climatology_dict['piControl'].coord('latitude')
    if not control_lats == experiment_lats:
        diffs = experiment_lats.points - control_lats.points
        assert numpy.abs(diffs).max() < 0.0001, "%s and control have very different latitude axes" %(experiment)
        climatology_dict[experiment].coord('latitude').points = control_lats.points
        climatology_dict[experiment].coord('latitude').bounds = control_lats.bounds
        assert climatology_dict[experiment].coord('latitude') == climatology_dict['piControl'].coord('latitude'), \
        "Problem with %s latitude axis" %(experiment)

    return climatology_dict[experiment]

def plot_difference(climatology_dict):
    """Plot the difference between experiment and control climatology"""

    assert climatology_dict['piControl'], 'must have control data for difference plot'

    for experiment in ['historical', 'historicalGHG', 'historicalAA', 'historicalnoAA']:
        if climatology_dict[experiment]:
            climatology_dict[experiment] = check_lats(climatology_dict, experiment)
            diff_cube = climatology_dict[experiment] - climatology_dict['piControl']
            iplt.plot(diff_cube, color=experiment_colors[experiment], alpha=0.8)

    plt.ylabel('Experiment - piControl')

def plot_trend(trend_dict, units, scaled=False):
    """Plot the trend"""

    for experiment in ['historical', 'historicalGHG', 'historicalAA', 'historicalnoAA', 'piControl']:
        if trend_dict[experiment]:
            iplt.plot(trend_dict[experiment], color=experiment_colors[experiment], alpha=0.8)

    if not scaled:
        plt.ylabel('Trend ($%s \enspace yr^{-1}$)' %(units) )
    else:
        plt.ylabel('Trend ($%s \enspace yr^{-1}$) scaled by warming' %(units) )

def read_data(inargs):
    """Read input data into appropriate dictionaries."""

    file_dict = {'historical': inargs.historical_files,
                 'historicalGHG': inargs.historicalghg_files,
                 'historicalAA': inargs.historicalaa_files,
                 'historicalnoAA': inargs.historicalnoaa_files,
                 'piControl': inargs.picontrol_files}

    tas_dict = {'historical': inargs.historical_tas_file,
                'historicalGHG': inargs.historicalghg_tas_file,
                'historicalAA': inargs.historicalaa_tas_file,
                'historicalnoAA': inargs.historicalnoaa_tas_file,
                'piControl': None}

    area_dict = {'historical': inargs.historical_area_file,
                 'historicalGHG': inargs.historicalghg_area_file,
                 'historicalAA': inargs.historicalaa_area_file,
                 'historicalnoAA': inargs.historicalnoaa_area_file,
                 'piControl': inargs.picontrol_area_file}

    basin_dict = {'historical': inargs.historical_basin_file,
                  'historicalGHG': inargs.historicalghg_basin_file,
                  'historicalAA': inargs.historicalaa_basin_file,
                  'historicalnoAA': inargs.historicalnoaa_basin_file,
                  'piControl': inargs.picontrol_basin_file}

    return file_dict, tas_dict, area_dict, basin_dict

def get_areacello_data(cube):
    """Generate an area data array."""

    dim_coord_names = [coord.name() for coord in cube.dim_coords]
    assert 'latitude' in dim_coord_names
    assert 'longitude' in dim_coord_names

    if not cube.coord('latitude').has_bounds():
        cube.coord('latitude').guess_bounds()

    if not cube.coord('longitude').has_bounds():
        cube.coord('longitude').guess_bounds()

    area_data = iris.analysis.cartography.area_weights(cube)
    area_data = numpy.ma.masked_where(numpy.ma.getmask(cube.data), area_data)

    return area_data

def area_ajustment(data_cube, area_file, metadata_dict):
    """Multipy a data cube by its cell area."""

    if area_file:
        area_cube = iris.load_cube(area_file[0])
        area_data = uconv.broadcast_array(area_cube.data, [1, 2], data_cube.shape)
        metadata_dict[area_file[0]] = area_cube.attributes['history']
    else:
        area_data = get_areacello_data(data_cube)

    data_cube.data = data_cube.data * area_data
    if 'm-2' in str(data_cube.units):
        units = str(data_cube.units).replace('m-2', "")
    else:
        units = str(data_cube.units) + ' m2'

    return data_cube, units, metadata_dict

def main(inargs):
    """Run the program."""

    file_dict, tas_dict, area_dict, basin_dict = read_data(inargs)

    metadata_dict = {}
    climatology_dict = {}
    time_trend_dict = {}
    tas_scaled_trend_dict = {}
    branch_dict = {}
    for experiment in ['historical', 'historicalGHG', 'historicalAA', 'historicalnoAA', 'piControl']:
        filenames = file_dict[experiment]
        if not filenames:
            climatology_dict[experiment] = None
            time_trend_dict[experiment] = None
            tas_scaled_trend_dict[experiment] = None
        else:
            print(experiment)
            try:
                time_constraint = gio.get_time_constraint(inargs.total_time)
            except (AttributeError, TypeError):
                time_constraint = iris.Constraint()

            with iris.FUTURE.context(cell_datetime_objects=True):
                cube = iris.load(filenames, gio.check_iris_var(inargs.var))

                # Merge cubes
                metadata_dict[filenames[0]] = cube[0].attributes['history']
                equalise_attributes(cube)
                iris.util.unify_time_units(cube)
                cube = cube.concatenate_cube()
                cube = gio.check_time_units(cube)

                # Time extraction and branch time info
                coord_names = [coord.name() for coord in cube.dim_coords]
                assert coord_names[0] == 'time'

                if 'historical' in experiment:
                    original_time_length = cube.shape[0]
                    cube = cube.extract(time_constraint)
                    new_time_length = cube.shape[0]
                    branch_time_index_offset = original_time_length - new_time_length

                    branch_time = cube.attributes['branch_time']
                    time_length = cube.shape[0]
                    branch_dict[experiment] = (branch_time, time_length, branch_time_index_offset)

                elif experiment == 'piControl':
                    branch_time, time_length, branch_time_index_offset = branch_dict['historical']
                    start_index, error = uconv.find_nearest(cube.coord('time').points, float(branch_time) + 15.5, index=True)
                    if abs(error) > 15:
                        print("WARNING: Large error of %f in locating branch time"  %(error))
                        start_index = 0
                    start_index = start_index + branch_time_index_offset
                    cube = cube[start_index:start_index+time_length, ::]

                # Temporal smoothing
                cube = timeseries.convert_to_annual(cube, full_months=True)

                # Mask marginal seas
                if basin_dict[experiment]:
                    basin_cube = iris.load_cube(basin_dict[experiment])
                    cube = uconv.mask_marginal_seas(cube, basin_cube)

                # Regrid and select basin
                cube, coord_names, regrid_status = grids.curvilinear_to_rectilinear(cube)
                if not inargs.basin == 'globe':
                    if basin_dict[experiment] and not regrid_status:
                        ndim = cube.ndim
                        basin_array = uconv.broadcast_array(basin_cube.data, [ndim - 2, ndim - 1], cube.shape)
                    else:
                        basin_array = uconv.create_basin_array(cube)
                    cube.data.mask = numpy.where((cube.data.mask == False) & (basin_array == basins[inargs.basin]), False, True)

                # Scale
                cube, units = scale_data(cube, inargs.var, reverse_sign=inargs.reverse_sign)

                # Zonal statistic
                if inargs.area_adjust:
                    if regrid_status:
                        area_dict[experiment] = None
                    cube, units, metadata_dict = area_ajustment(cube, area_dict[experiment], metadata_dict)
                    zonal_cube = cube.collapsed('longitude', iris.analysis.SUM)
                    aggregation = 'Zonally integrated'
                else:
                    zonal_cube = cube.collapsed('longitude', iris.analysis.MEAN)
                    aggregation = 'Zonal mean'
                zonal_cube.remove_coord('longitude')

                # Climatology and trends
                climatology_dict[experiment] = calculate_climatology(zonal_cube, inargs.climatology_time, experiment)
                time_trend_dict[experiment] = get_trend_cube(zonal_cube)
                if tas_dict[experiment]:
                    tas_cube = iris.load_cube(tas_dict[experiment], 'air_temperature' & time_constraint)
                    scale_factor = get_scale_factor(tas_cube)
                    print(experiment, 'warming:', scale_factor)
                    tas_scaled_trend_dict[experiment] = time_trend_dict[experiment] * (1. / abs(scale_factor))
                    metadata_dict[tas_dict[experiment][0]] = tas_cube.attributes['history']
                else:
                    tas_scaled_trend_dict[experiment] = None

    # Create the plots

    tas_scaled_trend_flag = tas_scaled_trend_dict['historicalGHG'] and tas_scaled_trend_dict['historicalAA']

    fig = plt.figure(figsize=[15, 20])
    gs = set_plot_grid(tas_trend=tas_scaled_trend_flag)

    ax_main = plt.subplot(gs[0])
    plt.sca(ax_main)
    plot_climatology(climatology_dict, inargs.var, units, inargs.legloc, aggregation)
    plt.title('%s (%s), %s' %(inargs.model, inargs.run, inargs.basin) )

    ax_diff = plt.subplot(gs[1])
    plt.sca(ax_diff)
    plot_difference(climatology_dict)

    ax_time_trend = plt.subplot(gs[2])
    plt.sca(ax_time_trend)
    plot_trend(time_trend_dict, units)

    if tas_scaled_trend_flag:
        ax_tas_trend = plt.subplot(gs[3])
        plt.sca(ax_tas_trend)
        plot_trend(tas_scaled_trend_dict, units, scaled=True)

    plt.xlabel('latitude')

    plt.savefig(inargs.outfile, bbox_inches='tight')
    gio.write_metadata(inargs.outfile, file_info=metadata_dict)

if __name__ == '__main__':

    extra_info ="""
author:
  Damien Irving, irving.damien@gmail.com

note:

"""

    description=''
    parser = argparse.ArgumentParser(description=description,
                                     epilog=extra_info,
                                     argument_default=argparse.SUPPRESS,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument("outfile", type=str, help="Output file name")
    parser.add_argument("var", type=str, help="Variable standard_name")
    parser.add_argument("model", type=str, help="Model name")
    parser.add_argument("run", type=str, help="Run (e.g. r1)")
    parser.add_argument("basin", type=str, choices=('atlantic', 'pacific', 'indian', 'globe'), help="Ocean basin")

    parser.add_argument("--historical_files", type=str, default=None, nargs='*',
                        help="Input files for the historical experiment")
    parser.add_argument("--historicalghg_files", type=str, default=None, nargs='*',
                        help="Input files for the historicalGHG experiment")
    parser.add_argument("--historicalaa_files", type=str, default=None, nargs='*',
                        help="Input files for the historicalAA experiment")
    parser.add_argument("--historicalnoaa_files", type=str, default=None, nargs='*',
                        help="Input files for the historicalnoAA experiment")
    parser.add_argument("--picontrol_files", type=str, default=None, nargs='*',
                        help="Input files for the piControl experiment")

    parser.add_argument("--historical_tas_file", type=str, default=None, nargs='*',
                        help="Global mean surface temperature file for historical experiment")
    parser.add_argument("--historicalghg_tas_file", type=str, default=None, nargs='*',
                        help="Global mean surface temperature file for historicalGHG experiment")
    parser.add_argument("--historicalaa_tas_file", type=str, default=None, nargs='*',
                        help="Global mean surface temperature file for historicalAA experiment")
    parser.add_argument("--historicalnoaa_tas_file", type=str, default=None, nargs='*',
                        help="Global mean surface temperature file for historicalnoAA experiment")

    parser.add_argument("--historical_area_file", type=str, default=None, nargs='*',
                        help="Cell area file for historical experiment")
    parser.add_argument("--historicalghg_area_file", type=str, default=None, nargs='*',
                        help="Cell area file for historicalGHG experiment")
    parser.add_argument("--historicalaa_area_file", type=str, default=None, nargs='*',
                        help="Cell area file for historicalAA experiment")
    parser.add_argument("--historicalnoaa_area_file", type=str, default=None, nargs='*',
                        help="Cell area file for historicalnoAA experiment")
    parser.add_argument("--picontrol_area_file", type=str, default=None, nargs='*',
                        help="Cell area file for piControl experiment")

    parser.add_argument("--historical_basin_file", type=str, default=None, nargs='*',
                        help="Cell basin file for historical experiment")
    parser.add_argument("--historicalghg_basin_file", type=str, default=None, nargs='*',
                        help="Cell basin file for historicalGHG experiment")
    parser.add_argument("--historicalaa_basin_file", type=str, default=None, nargs='*',
                        help="Cell basin file for historicalAA experiment")
    parser.add_argument("--historicalnoaa_basin_file", type=str, default=None, nargs='*',
                        help="Cell basin file for historicalnoAA experiment")
    parser.add_argument("--picontrol_basin_file", type=str, default=None, nargs='*',
                        help="Cell basin file for piControl experiment")

    parser.add_argument("--area_adjust", action="store_true", default=False,
                        help="Adjust plots for area [default=False]")
    parser.add_argument("--reverse_sign", action="store_true", default=False,
                        help="Multiple the data by -1 (CCSM4 has wrong sign for wind stress) [default=False]")

    parser.add_argument("--climatology_time", type=str, nargs=2, metavar=('START_DATE', 'END_DATE'),
                        default=('1986-01-01', '2005-12-31'), help="Time period for climatology [default = entire]")
    parser.add_argument("--total_time", type=str, nargs=2, metavar=('START_DATE', 'END_DATE'),
                        default=None, help="Time period for entire analysis. Must go right to end of experiment for control overlap period to be calculated correctly. [default = entire]")

    parser.add_argument("--legloc", type=int, default=8,
                        help="Legend location")

    args = parser.parse_args()
    main(args)


import unittest
from selenium import webdriver
from data.constants import Constants
from helpers.keywords import Helpers
from pom.pages.login import Login
from pom.pages.project import Project
from pom.locators.base_loc import BaseLoc
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from pom.pages.home import Home
from pom.locators.sidebar_loc import SideBarLoc

class ProjectTest(unittest.TestCase):

    def setUp(self):
        options = Options()
        options.headless = True
        print("\n========== PROJECTS TESTS ==========")
        self.driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)
        self.driver.maximize_window()
        self.driver.get(Constants.url["prod"])
        self.driver.find_element(*BaseLoc.sign_in_lnk).click()
        Login.login_form(self, Constants.credentials["users"]["real"]["user"], Constants.credentials["users"]["real"]["pass"])
        Helpers.click_visible_element(self, SideBarLoc.inbox_li_btn)

    def test_create_project(self):
        Project.create_projects(self, 1, Constants.project_data["name"], False, Constants.project_data["view"]["panel"])
        Home.validate_project(self)

    def test_create_project_fav(self):
        Project.create_projects(self, 1, Constants.project_data["name"], True, Constants.project_data["view"]["list"])
        Home.validate_project(self)

    def test_create_projects(self):
        Project.create_projects(self, 3, Constants.project_data["name"], True, Constants.project_data["view"]["list"])
        Home.validate_project(self)

    def test_delete_all_projects(self):
        Project.delete_all_projects(self)

    def tearDown(self):
        Helpers.wait_seconds(self, 3)
        self.driver.quit()

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


import imaplib
import email
from time import sleep
from random import randint
import importlib
from src.Analyser import mark_email
from src.Email import Email
import numpy as np
from goto import with_goto
from src.save import save

ai = importlib.import_module("Neural_Network", package=None)

"""
Fonction qui efface tous les fichiers emailX.txt
De nouveaux fichiers seront créés, avec X commençant à 1
"""
def efface_old_mail():
    import os

    arret = False
    x = 1
    while not arret:
        if os.path.exists("email" + str(x) + ".txt"):
            os.remove("email" + str(x) + ".txt")
            x += 1
        else:
            print("Fichiers supprimés")
            arret = True

old_mes_nb = -1
x = 1

efface_old_mail()

@with_goto
def run():
    print('start')

    label.connexion

    ### Récupération de l'adresse mail à tester, et du mot de passe ###
    connexion_pos = False
    while not connexion_pos:
        adresse = input("Adresse mail: ")
        mdp = input("Mot de passe: ")

        if("@gmail.com" in adresse):
            connexion_pos = True
        else:
            print("Adresse mail non valide\n")
            continue

    label.start
    try:
        old_mes_nb = -1
        x = 1

        ### Connexion à la boite mail ###
        try :
            mail = imaplib.IMAP4_SSL('imap.gmail.com')

            #mail.login('yncrea.test.projet.M1@gmail.com', 'ujikolpm')
            mail.login(adresse, mdp)

        except Exception:
            ### Cas où la connexion échoue ###
            print("Echec connexion\n")
            goto.connexion

        while True:

            mail.list()
            mail.select('inbox')

            result, data = mail.uid('search', None, "ALL")

            i = len(data[0].split())
            new_mes_nb = i

            if (old_mes_nb == -1):
                old_mes_nb = new_mes_nb

            ### Un nouveau message arrive dans la boite mail ###
            if (new_mes_nb > old_mes_nb):
                print("\n---NOUVEAU MESSAGE : %i---" % x)
                latest_email_uid = data[0].split()[new_mes_nb - 1]
                result, email_data = mail.uid('fetch', latest_email_uid, '(RFC822)')

                raw_email = email_data[0][1]

                raw_email_string = raw_email.decode('utf-8')
                email_message = email.message_from_string(raw_email_string)

                ### Création d'un fichier texte contenant le message                ###
                ### Création d'un objet Email récupérant les infos du fichier texte ###
                for part in email_message.walk():
                    save_string = r"email" + str(x) + ".txt"
                    myfile = open(save_string, 'a')
                    myfile.write(str(part))
                    mailo = Email(save_string)
                    myfile.close()

                ### L'email est déplacé dans le dossier traitement ###
                cible_dossier = 'traitement'

                result_move, err_mes = mail.uid('move', latest_email_uid, cible_dossier)
                if (result_move == 'OK'):
                    print("Mail déplacé avec succès")
                else:
                    print(err_mes)

                mail.select(cible_dossier)

                result, data = mail.uid('search', None, "ALL")
                latest_email_uid = data[0].split()[- 1]

                ### Analyse du message et attribution de son niveau de dangerosit ###
                mark = mark_email(mailo)
                marks = np.array([mark])
                sortie_traitement = ai.analyse_mail(marks)[0][0]
                save(mailo, marks=mark, grade=sortie_traitement.item())

                print("Résultat traitement :", sortie_traitement)

                if (sortie_traitement >= 0.6): ### Cas d'un message sur ###
                    result_move, err_mes = mail.uid('move', latest_email_uid, "sur")
                    if (result_move == 'OK'):
                        print("Mail déplacé dans sur")
                    else:
                        print(err_mes)

                elif (sortie_traitement >= 0.4 and sortie_traitement < 0.6): ### Cas d'un message pour lequel l'IA a un doute ###
                    result_move, err_mes = mail.uid('move', latest_email_uid, "moyen")
                    if (result_move == 'OK'):
                        print("Mail déplacé dans moyen")
                    else:
                        print(err_mes)

                else: ### Cas d'un message dangereux ###
                    result_move, err_mes = mail.uid('move', latest_email_uid, "danger")
                    if (result_move == 'OK'):
                        print("Mail déplacé dans danger")
                    else:
                        print(err_mes)

                x += 1
                old_mes_nb = new_mes_nb
                print("Analyse effectuée")

            elif (new_mes_nb < old_mes_nb):### Cas où des messages ont été supprimés ###
                old_mes_nb = new_mes_nb
    except TimeoutError:### Timeout de la connexion avec la boite mail atteint, retour au label start pour rafraichir la connexion ###
        goto.start
    except KeyboardInterrupt:
        goto.end

    label.end
    mail.logout()
    print("Good bye")

run()


from flask import Blueprint, jsonify, g, request
from wrappers.auth_required import auth_required, rate_limited
from models.jobs import TOPJob
from utils.json_helper import jsonify_payload

bp = Blueprint("management", __name__, url_prefix="/management")

@bp.route("/jobs", methods=["GET"])
@auth_required
def get_jobs():
    print('user info: ', g.user_id)

    jobs = TOPJob.find_by_user_id(g.user_id)

    print('jobs: ', [job.serialize() for job in jobs])

    return jsonify_payload({'jobs': [job.serialize() for job in jobs]})

@bp.route("/jobs", methods=["POST"])

@auth_required
@rate_limited
def create_job():
    payload = request.get_json()

    print('payload: ', payload)
    print('subscription data: ', g.subscription)

    job_name = payload.get('job_name')
    job_description = payload.get('job_description')
    job_id = payload.get('job_id')

    if not job_id:
        print('creating job')
        job = TOPJob(job_name, job_description, g.user_id)
        job.save()

    else:
        print('updating job ', job_id)
        job = TOPJob.find_by_id(job_id)
        job.update(job_name, job_description)

    return jsonify_payload({'job': job.serialize()})


#!/usr/bin/python3
def list_division(my_list_1, my_list_2, list_length):
    result = []

    for i in range(list_length):
        try:
            if i >= len(my_list_1) or i >= len(my_list_2):
                raise IndexError("out of range")

            numerator = my_list_1[i]
            denominator = my_list_2[i]

            if not (
                    isinstance(numerator, (int, float)) and
                    isinstance(denominator, (int, float))
            ):
                raise TypeError("wrong type")

            if denominator == 0:
                raise ZeroDivisionError("division by zero")

            division_result = numerator / denominator
            result.append(division_result)

        except IndexError:
            print("out of range")
            result.append(0)

        except TypeError:
            print("wrong type")
            result.append(0)

        except ZeroDivisionError:
            print("division by zero")
            result.append(0)

        finally:
            pass
    return (result)


#!/bin/python3

import math
import os
import random
import re
import sys

def setVisit(M, pos):
  x,y = pos
  M[y][x] = 2

def fillRegion(M, pos, size):
  x,y = pos
  n,m = size

  if(x < 0 or y < 0 or x >= m or y >= n):
    return 0
  if(M[y][x] != 1):
    return 0

  ret = 1
  setVisit(M, pos)

  for i in range(-1, 2):
    for j in range(-1, 2):
      ret += fillRegion(M, (x+j, y+i), size)
  return ret

# Complete the connectedCell function below.
def connectedCell(matrix):
  l = []
  n = len(matrix)
  m = len(matrix[0])
  for mat in matrix:
    l.append(list(mat))

  ret = 0
  for i in range(n):
    for j in range(m):
      ret = max(ret, fillRegion(l, (j, i), (n, m)))

  return ret

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    n = int(input())

    m = int(input())

    matrix = []

    for _ in range(n):
        matrix.append(list(map(int, input().rstrip().split())))

    result = connectedCell(matrix)

    fptr.write(str(result) + '\n')

    fptr.close()


import json
import os
import subprocess
import sys
from pathlib import Path
import youtube_dl

ydl_opts_download = {
    "format": "bestaudio/best",
    "cachedir": False,
    "outtmpl": "%(id)s%(ext)s",
    "postprocessors": [
        {
            "key": "FFmpegExtractAudio",
            "preferredcodec": "mp3",
            "preferredquality": "192",
        }
    ],
}

def download_single_yt(url_list):
    skipped = []
    for i in range(len(url_list)):
        try:
            with youtube_dl.YoutubeDL(ydl_opts_download) as ydl:
                ydl.download([url_list[i]])
        except:
            skipped.append(url_list[i])
    if skipped == []:
        return 0
    else:
        download_single_yt(skipped)

def ytdownload(link):
    with youtube_dl.YoutubeDL(
        {
            "outtmpl": "%(id)s%(ext)s",
            "quiet": True,
        }
    ) as ydl:
        result = ydl.extract_info(link, download=False)
        if "entries" in result:
            # Can be a playlist or a list of videos
            video = result["entries"]
        playlist_urls = [
            result["entries"][i]["webpage_url"] for i, item in enumerate(video)
        ]

    download_single_yt(playlist_urls)
    print("-" * 15)

def download(title, link, out_folder, i):
    print("downloading ", title, " OTS")
    os.chdir("./" + out_folder)
    fname = ""
    if i < 10:
        fname = "0" + str(i) + " - " + title
    else:
        fname = str(i) + " - " + title
    os.mkdir(fname)
    os.chdir("./" + fname)
    if "spotify" in link.lower():
        subprocess.check_call(["spotdl", link, "--output-format wav"])
    elif "youtube" in link.lower():
        ytdownload(link)
    os.chdir("..")
    os.chdir("..")

def download_all(json_source, out_folder):
    print("open file...")
    file = open(json_source)
    movies = json.load(file)

    print("creating main folder...")
    ost = Path(out_folder)
    if not ost.exists():
        ost.mkdir()

    for i, movie in enumerate(movies):
        link = movie["link"].replace(" ", "_")
        title = movie["title"].replace(" ", "_")
        download(title, link, out_folder, i + 1)

    print("--- DONE ---")

# download_all("ESC.json", "ESC")


#!/usr/bin/env python3

with open('input.txt', 'r') as f:
    adjustments = [int(n) for n in f]
    print("Part 1:", sum(adjustments))

    seen = set()
    current = 0
    i = 0
    while current not in seen:
        seen.add(current)
        current += adjustments[i]
        i = (i+1) % len(adjustments)

    print("Part 2:", current)


# coding: utf-8

"""
    Yapily API

    To access endpoints that require authentication, use your application key and secret created in the Dashboard (https://dashboard.yapily.com)  # noqa: E501

    The version of the OpenAPI document: 0.0.358
    Generated by: https://openapi-generator.tech
"""

from __future__ import absolute_import

import unittest
import datetime

import yapily
from yapily.models.bulk_user_delete_details import BulkUserDeleteDetails  # noqa: E501
from yapily.rest import ApiException

class TestBulkUserDeleteDetails(unittest.TestCase):
    """BulkUserDeleteDetails unit test stubs"""

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def make_instance(self, include_optional):
        """Test BulkUserDeleteDetails
            include_option is a boolean, when False only required
            params are included, when True both required and
            optional params are included """
        # model = yapily.models.bulk_user_delete_details.BulkUserDeleteDetails()  # noqa: E501
        if include_optional :
            return BulkUserDeleteDetails(
                id = '0',
                invalid_application_user_ids = [
                    '0'
                    ],
                invalid_user_uuids = [
                    '0'
                    ],
                status = 'IN_PROGRESS',
                started_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'),
                users = [
                    yapily.models.user_delete_response.UserDeleteResponse(
                        id = '0',
                        delete_status = 'SUCCESS',
                        creation_date = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'),
                        user_consents = [
                            yapily.models.consent_delete_response.ConsentDeleteResponse(
                                id = '0',
                                delete_status = 'SUCCESS',
                                institution_id = '0',
                                institution_consent_id = '0',
                                creation_date = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), )
                            ], )
                    ],
                links = {
                    'key' : '0'
                    }
            )
        else :
            return BulkUserDeleteDetails(
        )

    def testBulkUserDeleteDetails(self):
        """Test BulkUserDeleteDetails"""
        inst_req_only = self.make_instance(include_optional=False)
        inst_req_and_optional = self.make_instance(include_optional=True)

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


from utils import connector

async def declare_queue(queue_name, durable=False):
    conct = connector.Connector()
    channel = await conct.get_channel()
    await channel.queue_declare(
        queue=queue_name,
        durable=durable,
    )

async def bind_queue(queue_name, exchange_name, routing_key):
    conct = connector.Connector()
    channel = await conct.get_channel()
    await channel.queue_bind(
        queue=queue_name,
        exchange=exchange_name,
        routing_key=routing_key,
    )

async def declare_exchange(
        exchange_name,
        exchange_type="direct",
        durable=False,
):
    conct = connector.Connector()
    channel = await conct.get_channel()
    await channel.exchange_declare(
        exchange=exchange_name,
        exchange_type=exchange_type,
        durable=durable,

        passive=False,
        # if passive is True - it will raise exception if exchange
        # doesn't exist

        internal=False,
        # If set, the exchange may not be used directly by publishers,
        # but only when bound to other exchanges. Internal exchanges are
        # used to construct wiring that is not visible to applications.
        # Hint: could be used as "dead-letter-exchange" for queues
    )


import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
from .. import default_config
import numpy

class CustomViewBox(pg.ViewBox):
    def __init__(self, *args, **kwds):
        pg.ViewBox.__init__(self, *args, **kwds)
        self.StromDisplay=None
        self.ChannelNum=0
        self.ScaleBar = []
        self.ScaleSize = 0
        self.ScaleText = ''
        self.Window = []
        self.FreehandRoi = []
        self.DrawnRoi = []
        self.StormRegistrationChannel = -1
        self.ConfRegistrationChannel = -1
        self.DrawnRoi = []
        self.ConfocalOffset = [0, 0]
        self.StormMarkerRois = []
        self.ConfMarkerRois = []
        self.PanMode = default_config.viewer_input_mode
        self.ClickMode ='Norm'
        self.AffineTransform = []

    ## reimplement right-click to zoom out
    def mouseClickEvent(self, ev):
        if self.ClickMode == 'Reg':
            Current = self.mapToView(ev.pos())
            Marker= pg.ROI([0, 0])
            if len(self.StormMarkerRois)<3:
                self.StormMarkerRois.append(Marker)
                Marker.addFreeHandle([Current.x(),Current.y()])
                Handle=Marker.getHandles()[0]
                Handle.sides=4
                Handle.startAng=0
                Handle.buildPath()
                Handle.generateShape()
                self.StormDisplay.plot_widget.addItem(Marker)
            else:
                if len(self.ConfMarkerRois)<3:
                    self.ConfMarkerRois.append(Marker)
                    Marker.addFreeHandle([Current.x(),Current.y()])
                    self.StormDisplay.plot_widget.addItem(Marker)
                else:
                    self.ClickMode='Norm'

        else:
            pg.ViewBox.mouseClickEvent(self, ev)

    def SetRegistrationChannelStorm(self,StormChannelNum):
        self.StormRegistrationChannel=StormChannelNum

    def SetRegistrationChannelConf(self,ConfChannelNum):
        self.ConfRegistrationChannel=ConfChannelNum

    def mouseDragEvent(self, ev):
        if self.PanMode == 'Pan':
            pg.ViewBox.mouseDragEvent(self, ev)
        elif self.PanMode == 'Conf':
            cursorOffset = ev.screenPos() - ev.lastScreenPos()
            # scale to pixel coordinates
            XTrans = cursorOffset[0] * self.viewPixelSize()[0] / 8
            YTrans = cursorOffset[1] * self.viewPixelSize()[1] / 8
            self.ConfocalOffset = [self.ConfocalOffset[0] + YTrans, self.ConfocalOffset[1] + XTrans]

            for CN in range(4):
                if self.StormDisplay.DisplayedConfocalChannel[CN] != 0:
                    self.StormDisplay.DisplayedConfocalChannel[CN].translate(YTrans, XTrans)
            #move the registration markers if there are any:
            Scale=1000.0/self.StormDisplay.ConfocalSizeMultiplier
            for RoiInd in range(len(self.main_window.viewer.display.Viewbox.ConfMarkerRois)):
                Marker= pg.ROI([0, 0])
                OldPoints=self.ConfMarkerRois[RoiInd].getLocalHandlePositions()[0][1]
                self.StormDisplay.plot_widget.removeItem(self.ConfMarkerRois[RoiInd])
                self.ConfMarkerRois[RoiInd]=Marker
                Marker.addFreeHandle([OldPoints.x()+XTrans*Scale * self.StormDisplay.ConfocalMetaData['SizeX'],OldPoints.y()+YTrans*Scale * self.StormDisplay.ConfocalMetaData['SizeY']])
                self.StormDisplay.plot_widget.addItem(Marker)
            #calcualte correlation between confocal and storm channel

            #if event is finished display registration correlation
            if ev.isFinish():
                #if the displayed channels exist:
                if self.ConfRegistrationChannel!=-1 and self.StormRegistrationChannel!=-1:
                    #if the channels are displayed:
                    if self.StormDisplay.DisplayedConfocalChannel[self.ConfRegistrationChannel]!=0 and self.StormDisplay.DisplayedStormChannel[self.StormRegistrationChannel]!=0:
                        #maybe rescale the images if really slow;Or precalculate an image and just index from it
                        Im1=self.StormDisplay.DisplayedConfocalChannel[self.ConfRegistrationChannel]
                        Im2=self.StormDisplay.DisplayedStormChannel[self.StormRegistrationChannel]

                        Scale=1000.0/self.StormDisplay.ConfocalSizeMultiplier
                        Correlation=0
                        for ind in range(len(Im2.getData()[0])):
                            IndX=(int(Im2.getData()[0][ind])/(Scale * self.StormDisplay.ConfocalMetaData['SizeX']))-self.ConfocalOffset[1]
                            IndY=(int(Im2.getData()[1][ind])/(Scale * self.StormDisplay.ConfocalMetaData['SizeY']))-self.ConfocalOffset[0]
                            if IndX>-1 and IndX<Im1.image.shape[1] and IndY>-1 and IndY<Im1.image.shape[0]:
                                Correlation+=Im1.image[IndY,IndX]
                        Msg=self.main_window.status_bar.currentMessage()
                        Msg=str.split(str(Msg),' Correlation:')[0]
                        #find a possible norm of correlation
                        #mean might be a more representative value for normalization:numpy.mean(Im1.image)
                        MaxCorr=len(Im2.getData()[0])*Im1.image.max()
                        self.main_window.status_bar.showMessage(Msg+' Correlation: '+ str(float(Correlation)/float(MaxCorr)) )
                else:
                    Msg=self.main_window.status_bar.currentMessage()
                    Msg=str.split(str(Msg),' Correlation:')[0]
                    self.main_window.status_bar.showMessage(Msg+' Correlation: The selected channels are not displayed' )
            #print signal.correlate2d(Im1,Im2)
            if self.main_window.viewer.display.ConfocalSizeMultiplier==1:
                Scale=1000*self.main_window.viewer.display.ConfocalSizeMultiplier
            else:
                Scale=10*self.main_window.viewer.display.ConfocalSizeMultiplier
            self.main_window.doubleSpinBox_confocal_display_offset_x.setValue(
                int(self.ConfocalOffset[1] * Scale * self.main_window.viewer.display.ConfocalMetaData['SizeX']))
            self.main_window.doubleSpinBox_confocal_display_offset_y.setValue(
                int(self.ConfocalOffset[0] * Scale * self.main_window.viewer.display.ConfocalMetaData['SizeX']))
            ev.accept()
            pos = ev.pos()

            modifiers = QtGui.QApplication.keyboardModifiers()
            if modifiers == QtCore.Qt.ControlModifier and ev.button() == QtCore.Qt.LeftButton:
                if ev.isFinish():
                    # self.traj_widget.update_selection_infos()
                    self.rbScaleBox.hide()
                else:
                    rect_box = QtCore.QRectF(pg.Point(ev.buttonDownPos(ev.button())), pg.Point(pos))
                    rect_box = self.childGroup.mapRectFromParent(rect_box)
                    self.update_selection(rect_box)
                    self.traj_widget.update_selection_infos()
                    self.updateScaleBox(ev.buttonDownPos(), ev.pos())
        elif self.PanMode == 'Roi':
            Current = self.mapToView(ev.pos())
            Prev = self.mapToView(ev.lastPos())
            r1 = pg.QtGui.QGraphicsLineItem(Prev.x(), Prev.y(), Current.x(), Current.y())
            r1.setPen(pg.mkPen('w'))
            self.DrawnRoi.append(r1)
            self.addItem(r1)
            self.FreehandRoi.append(Current)
            # closing curve on finish
            if ev.isFinish():
                Current = self.mapToView(ev.buttonDownPos())
                Prev = self.mapToView(ev.pos())
                r1 = pg.QtGui.QGraphicsLineItem(Prev.x(), Prev.y(), Current.x(), Current.y())
                r1.setPen(pg.mkPen('w'))
                self.DrawnRoi.append(r1)
                self.addItem(r1)
                self.FreehandRoi.append(Current)

            ev.accept()
            pos = ev.pos()
            modifiers = QtGui.QApplication.keyboardModifiers()
            if modifiers == QtCore.Qt.ControlModifier and ev.button() == QtCore.Qt.LeftButton:
                if ev.isFinish():
                    # self.traj_widget.update_selection_infos()
                    self.rbScaleBox.hide()
                else:
                    rect_box = QtCore.QRectF(pg.Point(ev.buttonDownPos(ev.button())), pg.Point(pos))
                    rect_box = self.childGroup.mapRectFromParent(rect_box)
                    self.update_selection(rect_box)
                    self.traj_widget.update_selection_infos()
                    self.updateScaleBox(ev.buttonDownPos(), ev.pos())

    def deleteFreehandROI(self, roi):
        for r in self.DrawnRoi:
            self.removeItem(r)
        self.FreehandRoi = []
        self.DrawnRoi = []
        roi = None

    def deleteActiveContourROI(self, DrawnElements):
        for r in DrawnElements:
            self.removeItem(r)

    def deleteActiveContourROI3d(self, DrawnElements):
        for r in DrawnElements:
            self.removeItem(r)

    def deleteEllipseROI(self, roi):
        self.removeItem(roi)

    def updateMatrix(self, changed=None):
        # keep scale bar at same position
        if self.ScaleBar != []:
            ViewRange = self.viewRange()
            XLength = (ViewRange[0][1] - ViewRange[0][0]) * 0.05
            YLength = (ViewRange[1][1] - ViewRange[1][0]) * 0.05
            Xpos = ViewRange[0][0] + XLength
            Ypos = ViewRange[1][0] + YLength
            self.ScaleBar.clear()
            self.Window.removeItem(self.ScaleText)
            self.ScaleBar = self.Window.plot(x=[Xpos, Xpos + self.ScaleSize], y=[Ypos, Ypos], symbol='o')
            PosX = Xpos
            PosY = Ypos + YLength * 0.1
            self.ScaleText = pg.TextItem(text=str(self.ScaleSize) + ' nm', color=(200, 200, 200))
            self.Window.addItem(self.ScaleText)
            self.ScaleText.setPos(PosX, PosY)
        pg.ViewBox.updateMatrix(self, changed=None)

    def setScaleBar(self, ScaleBar, Window, Size, Text):
        self.ScaleBar = ScaleBar
        self.Window = Window
        self.ScaleSize = Size
        self.ScaleText = Text

    def deleteScaleBar(self):
        if self.ScaleBar != []:
            self.ScaleBar.clear()
            self.Window.removeItem(self.ScaleText)
            self.ScaleBar = []
            self.ScaleSize = 0
            self.ScaleText = ''

    def setWindow(self, Window):
        self.Window = Window

    def deleteConfocalImage(self):
        self.StromDisplay = None

    def setConfocalImage(self, StormDisplay, ChannelNum):
        self.StormDisplay = StormDisplay
        self.ChannelNum = ChannelNum


from argparse import ArgumentParser

from gitrello import Gitrello
import github
import trello
import settings

if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument('--pr_id', required=True)
    parser.add_argument('--repo', required=True)
    args = parser.parse_args()

    g = github.Github(settings.GITHUB_TOKEN).get_user()
    client = trello.TrelloClient(api_key=settings.API_KEY, token=settings.API_TOKEN)
    board = client.get_board(settings.BOARD_ID)
    repo = [x for x in g.get_repos() if x.name == args.repo][0]
    pull = repo.get_pull(int(args.pr_id))
    gitrello = Gitrello(pull, board)
    card = gitrello.create_card()


import os, argparse, traceback, glob, random, itertools, time, torch, threading, queue
import numpy as np
import torch.optim as optim
from models.tacotron import post_CBHG
from torch.nn import L1Loss
from torch.utils.data import Dataset, DataLoader
from torch.nn.utils.rnn import pad_sequence
from util.hparams import *

data_dir = './data'
mel_list = sorted(glob.glob(os.path.join(data_dir + '/mel', '*.npy')))
spec_list = sorted(glob.glob(os.path.join(data_dir + '/spec', '*.npy')))
mel_len = np.load(os.path.join(data_dir + '/mel_len.npy'))

def DataGenerator():
    while True:
        idx_list = np.random.choice(len(mel_list), batch_group, replace=False)
        idx_list = sorted(idx_list)
        idx_list = [idx_list[i : i + batch_size] for i in range(0, len(idx_list), batch_size)]
        random.shuffle(idx_list)

        for idx in idx_list:
            random.shuffle(idx)

            mel = [torch.from_numpy(np.load(mel_list[mel_len[i][1]])) for i in idx]
            spec = [torch.from_numpy(np.load(spec_list[mel_len[i][1]])) for i in idx]

            mel = pad_sequence(mel, batch_first=True)
            spec = pad_sequence(spec, batch_first=True)

            yield [mel, spec]

class Generator(threading.Thread):
    def __init__(self, generator):
        threading.Thread.__init__(self)
        self.queue = queue.Queue(8)
        self.generator = generator
        self.start()

    def run(self):
        for item in self.generator:
            self.queue.put(item)
        self.queue.put(None)

    def next(self):
        next_item = self.queue.get()
        if next_item is None:
             raise StopIteration
        return next_item

def train(args):
    train_loader = Generator(DataGenerator())

    model = post_CBHG(K=8, conv_dim=[256, mel_dim]).cuda()

    optimizer = optim.Adam(model.parameters())

    step, epochs = 0, 0
    if args.checkpoint is not None:
        ckpt = torch.load(args.checkpoint)
        model.load_state_dict(ckpt['model'])
        optimizer.load_state_dict(ckpt['optimizer'])
        step = ckpt['step'],
        step = step[0]
        epoch = ckpt['epoch']
        print('Load Status: Epoch %d, Step %d' % (epoch, step))

    torch.backends.cudnn.benchmark = True

    try:
        for epoch in itertools.count(epochs):
            for _ in range(batch_group):
                start = time.time()
                mel, target = train_loader.next()
                mel = mel.float().cuda()
                target = target.float().cuda()

                pred = model(mel)
                loss = L1Loss()(pred, target)

                model.zero_grad()
                loss.backward()
                optimizer.step()

                step += 1
                print('step: {}, loss: {:.5f}, {:.3f} sec/step'.format(step, loss, time.time() - start))

                if step % checkpoint_step == 0:
                    save_dir = './ckpt/' + args.name + '/2'
                    torch.save({
                        'model': model.state_dict(),
                        'optimizer': optimizer.state_dict(),
                        'step': step,
                        'epoch': epoch
                    }, os.path.join(save_dir, 'ckpt-{}.pt'.format(step)))

    except Exception as e:
        traceback.print_exc()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--checkpoint', '-c', default=None)
    parser.add_argument('--name', '-n', required=True)
    args = parser.parse_args()
    save_dir = os.path.join('./ckpt/' + args.name, '2')
    os.makedirs(save_dir, exist_ok=True)
    train(args)


import copy
from node import Node

import heapq

class Search():
    def __init__(self, unsorted_stack, search_type):
        self.unsorted_stack = unsorted_stack
        self.frontier = [] # tuples to make total cost priority
        self.visited = []
        self.order_added = 0
        self.root = Node(unsorted_stack, None, self.order_added, search_type)
        self.frontier.append((self.root.total_cost, 0, self.root))
        self.order_added += 1

    def find_duplicate(self, state):
        # check if duplicate state is already in frontier
        for tuple in self.frontier:
            if tuple[2].state == state:
                return tuple
        return None

    def expand_frontier(self, node):
        # create children for each possible flip level
        for level in range(2, len(self.unsorted_stack)):
            child = copy.deepcopy(node)
            child.flip(level)
            child.parent = node
            child.order_added = self.order_added
            dup = self.find_duplicate(child.state)

            # if the state is unique, push to frontier
            if (child.state not in self.visited):
                if (dup == None):
                    heapq.heappush(self.frontier, (child.total_cost(), child.order_added, child))
                    self.order_added += 1
            # use faster route to state if one is found
            elif dup != None:
                if dup[0] > child.total_cost():
                    self.frontier[self.frontier.index(dup)] = child

    def find_solution(self):
        while not len(self.frontier) == 0:
            # explore cheapest node in frontier
            node = heapq.heappop(self.frontier)[2]
            self.visited.append(node.state) # record as visited
            if node.get_heuristic() == 0: # if sorted, return sorted stack
                return node
            self.expand_frontier(node)


from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from devup.views import UpList, UpDetail, UpCreate, UpUpdate

app_name = 'devup'

urlpatterns = [
    url(r'^up_list$', UpList.as_view(), name='up_list'),
    url(r'^up_create$', UpCreate.as_view(), name='up_create'),
    url(r'^up_detail/(?P<pk>[-\w]+)/$', UpDetail.as_view(), name='up_detail'),
    url(r'^(?P<pk>[-\w]+)/$', UpDetail.as_view(), name='detail'),
    url(r'^(?P<pk>\d+)/update$', UpUpdate.as_view(), name='update'),

]