import logging
import os
import os.path
import time

import numpy as np
from PyQt4 import QtCore, QtGui

import tulpenmanie.exchange

logger = logging.getLogger(__name__)

class DepthProxy(QtCore.QObject):

    refreshed_signal = QtCore.pyqtSignal(np.ndarray)

    def __init__(self, market_uuid, exchange_name,
                 precision=2, parent=None):
        super(DepthProxy, self).__init__(parent)
        self.storage_directory = str(QtGui.QDesktopServices.storageLocation(
            QtGui.QDesktopServices.DataLocation))

        self.precision = precision
        self.exchange = tulpenmanie.exchange.get_exchange_object(exchange_name,
                                                                 market_uuid)
        self.exchange.depth_signal.connect(self._process_depth)

    def get_array_filename(self):
        array_filename = os.path.join(
            self.storage_directory, '{}_{}_{}_depth.pickle'.format(market_uuid,
                                                                   exchange_name,
                                                                   int(time.time())))

        return array_filename

    def refresh(self):
        #if self.depth is not None and self.depth.any():
        #    self.refreshed_signal.emit(self.depth)
        #else:
        self.exchange.refresh_depth_data()

    def _process_depth(self, depth_data):
        "depth data should be (asks(prices, amounts), bids(prices, amounts))"
        times = list()
        price_steps = list()
        volume_sums = list()
        step_size = 1.0 / pow(10, self.precision)
        now = time.time()
        now = matplotlib.dates.epoch2num(now)

        #bids
        bids = np.array(depth_data[1], dtype=np.float).transpose()
        bid_prices = bids[0]
        bid_volumes = bids[1]
        floor = bid_prices.max().round(self.precision)
        bottom = bid_prices.min()

        while floor > bottom:
            floor -= step_size
            index = bid_prices > floor

            times.append(now)
            price_steps.append(floor)
            volume_sums.append(bid_volumes[index].sum())

        price_steps.reverse()
        volume_sums.reverse()

        # asks
        asks = np.array(depth_data[0], dtype=np.float).transpose()
        ask_prices = asks[0]
        ask_volumes = bids[1]
        ceiling = ask_prices.min().round(self.precision)
        top = ask_prices.max()

        while ceiling < top:
            ceiling += step_size
            index = ask_prices < ceiling

            times.append(now)
            price_steps.append(ceiling)
            volume_sums.append(ask_volumes[index].sum())

        self.depth = np.array((times, price_steps, volume_sums)).transpose()
        self.save()
        self.refreshed_signal.emit(self.depth)

    def save(self):
        array_filename = self.get_array_filename()
        directory = os.path.dirname(array_filename)
        if not os.path.exists(directory):
            os.makedir(directory)
        self.depth.dump(self.get_array_filename)
        logger.debug("saved depth data to %s", array_filename)


import requests, json
import re

def _GET_HEADERS_FROM_TOKEN(token):
    headers = {
            "Authorization": "Bearer " + token,
            "Content-Type": "application/json",
            "Notion-Version": "2021-05-13"
        }
    return headers

def _GET_FIRST_MATCH(pattern, string):
    pattern = re.compile(pattern)
    match = re.search(pattern,string)
    span = match.span()
    return string[span[0]+1 :span[1]-2]

def _DUMP_JSON_TO_FILE(data, name):
    file = f'./{name}'
    with open(file, 'w', encoding='utf8') as f:
        json.dump(data, f, ensure_ascii=False)
        print(f"Dumped JSON to {file}")

"""HIERARCHY
NotionUserObject(object)
|
NotionDataBase(object):
|
NotionPage(object):
|
NotionBlocks:
|
.....
"""

class NotionBase(object):
    """docstring for NotionAPI_Headers"""
    def __init__(self, token):
        super(NotionBase, self).__init__()
        self.token = token
        self.headers = headers = {
            "Authorization": "Bearer " + token,
            "Content-Type": "application/json",
            "Notion-Version": "2021-05-13"
        }

    def __repr__(self):
        return json.dumps(self.headers, indent=3)

class NotionDatabase(NotionBase):
    """DATABASE_OBJECT
    {
        object:
        results: [PAGE_OBJECT_1, PAGE_OBJECT_2]
        next_cursor: null
        has_more: false
    }
    """
    def __init__(self, databaseID, notionBase):
        super(NotionDatabase, self).__init__(notionBase.token)
        self.databaseID = databaseID
        self.data = None

    @classmethod
    def from_a_view_URL(cls, url, notionBase):
        """
        SAMPLE URL:
        https://www.notion.so/rysav/36ecfe52ed5e44cc98ab4f22a87eb4ea?v=23a032978ccc4cc78ff238163bb25bbc
        """
        dbPattern = r'/[^/]*\?v'
        databaseID = _GET_FIRST_MATCH(dbPattern, url)
        return cls(databaseID, notionBase)

    def readDatabase(self):
        readUrl = f"https://api.notion.com/v1/databases/{self.databaseID}/query"
        res = requests.request("POST", readUrl, headers=self.headers)
        statusCode = res.status_code
        # print(res.text)
        if statusCode == 200:
            print(f"-Reading Database Completed : Status {statusCode}")
            data = res.json()
            self.data = data
            return data
        else:
            print(f"-Reading Database Failed : Status {statusCode}")
            return None

    def createDatabase():
        _BLANK_DATABASE_TEMPLATE = {
            "object": "list",
            "results":
            [
                "PAGE_DATA_1",
                "PAGE_DATA_2",
                "..........."
            ],
            "next_cursor": null,
            "has_more": false
        }

    def updateDatabase():
        pass

    def getIDObject():
        info = {
            "type": "database_id",
            "database_id": self.databaseID
        }
        return info

    def __repr__(self):
        return json.dumps(self.data, indent=3)

class NotionPage(object):
    """PAGE OBJECT
    {
        object:
        id:
        created_time:
        last_edited_time:
        created_by:
        last_edited_by:
        cover:
        icon:
        parent:
    }
    """
    def __init__(self, pageID, token):
        super(NotionPage, self).__init__()
        self.pageID = pageID
        self.headers = _GET_HEADERS_FROM_TOKEN(token)
        self.data = None

    def createPage(self, newPageData, databaseID):
        #TODO - Update self.data after create page
        _BLANK_PAGE_TEMPLATE = {
            "object": "page",
            "id": "0e2475ec-cb6c-457d-ba50-09990f54fd4f",
            "created_time": "2022-04-12T10:21:00.000Z",
            "last_edited_time": "2022-04-12T10:21:00.000Z",
            "created_by":
            {
                "object": "user",
                "id": "20f3bc22-ba63-4f66-98b7-e665387b3138"
            },
            "last_edited_by":
            {
                "object": "user",
                "id": "20f3bc22-ba63-4f66-98b7-e665387b3138"
            },
            "cover": null,
            "icon": null,
            "parent":
            {
                "type": "database_id",
                "database_id": "6ee7657b-d396-47aa-991e-51edcc3167a3"
            },
            "archived": false,
            "properties":
            {
                "Name":
                {
                    "id": "title",
                    "type": "title",
                    "title":
                    []
                }
            },
            "url": "https://www.notion.so/0e2475eccb6c457dba5009990f54fd4f"
        }

        createUrl = 'https://api.notion.com/v1/pages'
        data = json.dumps(newPageData)
        res = requests.request("POST", createUrl, headers=self.headers, data=data)
        statusCode = res.status_code
        # print(res.text)
        if statusCode == 200:
            print(f"--Page Creation Completed : Status {statusCode}")
            self.data["results"].append(newPageData)
            return
        else:
            print(f"--Page Creation Failed : Status {statusCode}")
            return None

    def updatePage(self, updateData, pageId):
        updateUrl = f"https://api.notion.com/v1/pages/{pageId}"
        data = json.dumps(updateData)
        response = requests.request("PATCH", updateUrl, headers=self.headers, data=data)
        print(response.status_code)
        # print(response.text)

if __name__ == "__main__":
    notionBase = NotionBase('secret_wFBrBJ2HvixP9R8eZvo5WFzLqkiyQWzC46eFH9QWDp7')

    testURL = "https://www.notion.so/rysav/6ee7657bd39647aa991e51edcc3167a3?v=cf2aa57ea6234b01a0703797e4850ba3"
    notionDatabase = NotionDatabase.from_a_view_URL(testURL, notionBase)

    # print(notionBase)
    databaseData = notionDatabase.readDatabase()
    # print(notionDatabase)
    # newPageData =     {
    #     "object": "page",
    #     "id": "0e2475ec-cb6c-457d-ba50-09990f54fd4f",
    #     "created_time": "2022-04-12T10:21:00.000Z",
    #     "last_edited_time": "2022-04-12T10:21:00.000Z",
    #     "created_by":
    #     {
    #         "object": "user",
    #         "id": "20f3bc22-ba63-4f66-98b7-e665387b3138"
    #     },
    #     "last_edited_by":
    #     {
    #         "object": "user",
    #         "id": "20f3bc22-ba63-4f66-98b7-e665387b3138"
    #     },
    #     "parent":
    #     {
    #         "type": "database_id",
    #         "database_id": "6ee7657b-d396-47aa-991e-51edcc3167a3"
    #     },
    #     "archived": false,
    #     "properties":
    #     {
    #         "Name":
    #         {
    #             "id": "title",
    #             "type": "title",
    #             "title":
    #             []
    #         }
    #     },
    #     "url": "https://www.notion.so/0e2475eccb6c457dba5009990f54fd4f"
    # }

    # notionDB.createPage(newPageData)


# -*- coding: utf-8 -*-
import base64

SCRIPT_SETS = {
    "search_host_files": "config_query/job_scripts/search_host_files",
    "backup_host_files": "config_query/job_scripts/backup_host_files",
}

def get_script_base64(script_name, params=""):
    """
    获取对应脚本的base64编码
    """
    with open(SCRIPT_SETS[script_name], "r", encoding="utf-8") as f:
        script_content = f.read()

    return base64.b64encode(script_content.encode("utf8")).decode("utf-8"), base64.b64encode(
        params.encode("utf8")
    ).decode("utf-8")


from webcamsettings import WebCamSettings

import pyvirtualcam
import cv2 as cv2
import threading

class VirtualWebcam():
    def __init__(self, webCamSettings: WebCamSettings):
        self.__webCamSettings = webCamSettings

        self.__cam = None
        self.__stopAllThreads = False
        self.__webcamThread = threading.Thread(target=self.__StartVirtualWebcamThread)

    def ConnectToCamera(self, cameraIndex: int, resolution: tuple):
        self.Stop()

        self.__cam = cv2.VideoCapture(cameraIndex, cv2.CAP_DSHOW)
        if not self.__cam.isOpened():
            return False, f"Camera index {cameraIndex} is invalid."

        (width, height) = resolution
        self.__cam.set(cv2.CAP_PROP_FRAME_WIDTH, width)
        self.__cam.set(cv2.CAP_PROP_FRAME_HEIGHT, height)

        actualW = self.__cam.get(cv2.CAP_PROP_FRAME_WIDTH)
        actualH = self.__cam.get(cv2.CAP_PROP_FRAME_HEIGHT)

        if actualW == width and actualH == height:
            self.__resolutionWidth = width
            self.__resolutionHeight = height
            self.__stopAllThreads = False
            self.__webcamThread.start()
            return True, ""

        self.__cam.release()
        return False, f"The camera index {cameraIndex} does not support the selected resolution ({width} x {height})"

    def Stop(self):
        if self.__webcamThread.is_alive():
            self.__stopAllThreads = True
            self.__webcamThread.join()

        if self.__cam != None:
            self.__cam.release()

        cv2.destroyAllWindows()

    def __StartVirtualWebcamThread(self):
        with pyvirtualcam.Camera(width=self.__resolutionWidth, height=self.__resolutionHeight, fps=30) as virtualCam:
            self.__webCamSettings.SetVirtualCameraName(f'Using virtual camera: {virtualCam.device}')
            while not self.__stopAllThreads:
                # Capture frame-by-frame
                ret, frame = self.__cam.read()
                # if frame is read correctly ret is True
                if not ret:
                    print("Can't receive frame (stream end?). Exiting ...")
                    break

                frame = self.__ProcessFrame(frame=frame)

                virtualCam.send(frame)
                virtualCam.sleep_until_next_frame()

    def __ProcessFrame(self, frame):
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        # 1. Apply brightness & contrast
        alpha = self.__webCamSettings.GetContrast() # Contrast control
        beta = self.__webCamSettings.GetBrightness() # Brightness control
        frame = cv2.convertScaleAbs(frame, alpha=alpha, beta=beta)

        # 2. Apply image flip
        hFlip, vFlip = self.__webCamSettings.GetFlip()
        if hFlip:
            frame = cv2.flip(frame, 1)
        if vFlip:
            frame = cv2.flip(frame, 0)
        return frame


import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import argparse
import os
import joblib

parser = argparse.ArgumentParser()
parser.add_argument("--imgst_dir",default='mimgst',type=str)
parser.add_argument("--dataset",default='voc',choices=['voc','coco','kitti'],type=str,help='dataset name')
parser.add_argument("--mode",default='clip',choices=['mask','clip'],type=str,help='type of secure PatchGuard aggregation; robust masking or clipping')
parser.add_argument("--w",default=8,type=int)
parser.add_argument("--m",default=-1,type=int)
parser.add_argument("--t",default=32,type=float)
parser.add_argument("--eps",default=3,type=int,help='DBSCAN eps')
parser.add_argument("--ms",default=24,type=int,help='DBSCAN min number of samples')

args = parser.parse_args()

DATASET = args.dataset
font = {'family' : 'serif',
        #'weight' : 'bold',
        'size'   : 12}

matplotlib.rc('font', **font)

########################################GT################################
SETTING = '{}_{}_w{}m{}t{:.1f}_{}_{}'.format('gt',args.mode,args.w,args.m,args.t,args.eps,args.ms)
IMGST_DIR = os.path.join(args.imgst_dir,DATASET,SETTING)

prec = np.mean(joblib.load(os.path.join(IMGST_DIR,'prec.z')))
rec = np.mean(joblib.load(os.path.join(IMGST_DIR,'rec.z')))
gt_fa_list = joblib.load(os.path.join(IMGST_DIR,'fa_list.z'))

plt.plot([100],[100],'o',label='Precision-PCD-vanilla',markersize=6)

plt.plot([rec*100],[prec*100],'x',label='Precision-PCD-defended',markersize=6)
gt_rec = rec
###############################################################################

def process(prec,rec,fa_list,conf_cut):
	thres_list=np.linspace(0,0.999,1000)[::-1]
	tmp = thres_list <  conf_cut
	thres_list = thres_list[tmp]
	prec = prec[tmp]
	rec = rec[tmp]
	#prec = np.nanmean(np.where(prec!=0,prec,np.nan),1)
	#rec = np.nanmean(np.where(rec!=0,rec,np.nan),1)
	prec = np.mean(prec,1)
	rec = np.mean(rec,1)
	fa_list = fa_list[tmp]
	tmp = np.argsort(rec)
	rec= rec[tmp]
	prec= prec[tmp]
	fa_list= fa_list[tmp]
	return prec,rec,fa_list
lw = 2

if DATASET == 'voc':
	yolo_cut = 0.945
	frcnn_cut = 0.999
elif DATASET =='coco':
	yolo_cut = 0.9
	frcnn_cut = 0.997
elif DATASET == 'kitti':
	yolo_cut = 0.925
	frcnn_cut =  0.9999
######################YOLO########################################################
prec = joblib.load(os.path.join(args.imgst_dir,args.dataset,'prec_vanilla_{}.z'.format('yolo')))
rec = joblib.load(os.path.join(args.imgst_dir,args.dataset,'rec_vanilla_{}.z'.format('yolo')))
fa_list = joblib.load(os.path.join(args.imgst_dir,args.dataset,'fa_list_vanilla_{}.z'.format('yolo')))

prec,rec,fa_list = process(prec,rec,fa_list,yolo_cut)
plt.plot(rec*100,prec*100,label='Precision-YOLO-vanilla',linestyle='-',linewidth=lw)

#####################YOLO_DPG########################################################
SETTING = '{}_{}_w{}m{}t{:.1f}_{}_{}'.format('yolo',args.mode,args.w,args.m,args.t,args.eps,args.ms)
IMGST_DIR = os.path.join(args.imgst_dir,DATASET,SETTING)

prec = joblib.load(os.path.join(IMGST_DIR,'prec.z'))
rec = joblib.load(os.path.join(IMGST_DIR,'rec.z'))
fa_list = joblib.load(os.path.join(IMGST_DIR,'fa_list.z'))

prec,rec,fa_list = process(prec,rec,fa_list,yolo_cut)
plt.plot(rec*100,prec*100,label='Precision-YOLO-defended',linestyle='-.',linewidth=lw)

yolo_fa_list= fa_list.copy()
yolo_rec = rec.copy()

######################FRCNN########################################################
prec = joblib.load(os.path.join(args.imgst_dir,args.dataset,'prec_vanilla_{}.z'.format('frcnn')))
rec = joblib.load(os.path.join(args.imgst_dir,args.dataset,'rec_vanilla_{}.z'.format('frcnn')))
fa_list = joblib.load(os.path.join(args.imgst_dir,args.dataset,'fa_list_vanilla_{}.z'.format('frcnn')))

prec,rec,fa_list = process(prec,rec,fa_list,frcnn_cut)
plt.plot(rec*100,prec*100,label='Precision-FRCNN-vanilla',linestyle='--',linewidth=lw)

############FRCNN_DPG###############################################

SETTING = '{}_{}_w{}m{}t{:.1f}_{}_{}'.format('frcnn',args.mode,args.w,args.m,args.t,args.eps,args.ms)
IMGST_DIR = os.path.join(args.imgst_dir,DATASET,SETTING)

prec = joblib.load(os.path.join(IMGST_DIR,'prec.z'))
rec = joblib.load(os.path.join(IMGST_DIR,'rec.z'))
fa_list = joblib.load(os.path.join(IMGST_DIR,'fa_list.z'))

prec,rec,fa_list = process(prec,rec,fa_list,frcnn_cut)
plt.plot(rec*100,prec*100,label='Precision-FRCNN-defended',linestyle='-.',linewidth=lw)

frcnn_fa_list= fa_list.copy()
frcnn_rec = rec.copy()

############FAR##########################################################

plt.plot([gt_rec*100],[gt_fa_list*100],'D',label='FAR-PCD-defended',markersize=6)

plt.plot(yolo_rec*100,yolo_fa_list*100,label='FAR-YOLO-defended',linestyle='-',linewidth=lw)
plt.plot(frcnn_rec*100,frcnn_fa_list*100,label='FAR-FRCNN-defended',linestyle='-.',linewidth=lw)

plt.legend(loc='center left')
plt.grid()
plt.xlabel('Recall (%)')
plt.ylabel('Precision / FAR (%)')

plt.xticks(np.arange(10,110,10))
plt.yticks(np.arange(0,110,10))

#plt.xlim([0,1])
#plt.ylim([0,1])
plt.tight_layout()
plt.savefig('clean_{}_{}.png'.format(DATASET,args.mode))
plt.savefig('clean_{}_{}.pdf'.format(DATASET,args.mode))
plt.close()


from tfc import utfc
from tfc.utils import TFCDictRobust, egrad, NllsClass, MakePlot

import numpy as onp
import jax.numpy as np
from jax import vmap, jacfwd, jit, lax

import tqdm
import pickle

from scipy.optimize import fsolve
from time import process_time as timer

## TEST PARAMETERS: ***************************************************
tol = np.finfo(float).eps
maxIter = 50

## CONSTANTS: *********************************************************
# Number of points to use
N = 100

# Number of basis functions to use
ms = 30
mc = 1

# Number of constraints
nCx = 0
nCy = 0

## GET CHEBYSHEV VALUES **********************************************
stfc = utfc(N,nCx,ms,basis='CP',x0 = -1, xf = 1.)
ctfc = utfc(N,nCy,mc,basis='CP',x0 = -1, xf = 1.)

Hs  = stfc.H
Hc  = ctfc.H

## DEFINE THE ASSUMED SOLUTION **************************************
z = stfc.z
z0 = z[0]
zf = z[-1]

## DEFINE CONSTRAINED EXPRESSION *************************************
r = lambda z, xi, IC: np.dot(Hs(z),xi['xis'])
v = egrad(r,0)
a = egrad(v,0)

lam = lambda z, xi: np.dot(Hc(z),xi['xic'])
lamr = egrad(lam,0)

## FORM LOSS AND JACOBIAN ***********************************************************************************
L0  = lambda xi,IC: r(z,xi,IC)[0,:] - IC['R0']
Ld0 = lambda xi,IC: xi['b']**2 * v(z,xi,IC)[0,:] - IC['V0']
Lf  = lambda xi,IC: r(z,xi,IC)[-1,:]
Ldf = lambda xi,IC: xi['b']**2 * v(z,xi,IC)[-1,:]

Ls  = lambda xi,IC: xi['b']**4 * a(z,xi,IC) - IC['ag'] + lam(z,xi)

# Htf = lambda xi,IC: np.dot(lam(z,xi)[-1,:],(-1./2.*lam(z,xi)[-1,:] + IC['ag']))
# Updated because need to at lam_r * v term for spectral method
Htf = lambda xi,IC: np.dot(lam(z,xi)[-1,:],(-1./2.*lam(z,xi)[-1,:] + IC['ag'])) \
                  + np.dot(-xi['b']**2 *lamr(z,xi)[-1,:], xi['b']**2 * v(z,xi,IC)[-1,:])

L = jit(lambda xi,IC: np.hstack([Ls(xi,IC)[1:-1,:].flatten(), \
                                 L0(xi,IC).flatten(), \
                                 Ld0(xi,IC).flatten(), \
                                 Lf(xi,IC).flatten(), \
                                 Ldf(xi,IC).flatten(), \
                                 Htf(xi,IC)] ))

## INITIALIZE VARIABLES *************************************************************************************
xis   = onp.zeros((Hs(z).shape[1],3))
xic  = onp.zeros((Hc(z).shape[1],3))
b    = np.sqrt(2)*onp.ones(1)

xi = TFCDictRobust({'xis':xis,\
                    'xic':xic,\
                    'b':b})

IC = {'R0': np.zeros((3,)), 'V0': np.zeros((3,)), 'ag': np.zeros((3,))}

## NONLINEAR LEAST-SQUARES CLASS *****************************************************************************
nlls = NllsClass(xi,L,IC,tol=tol,maxIter=maxIter,timer=True)

data = pickle.load(open('data/EOL_IC.pickle','rb'))
sol = {'loss': onp.zeros((data['R0'].shape[0])), 'it': onp.zeros((data['R0'].shape[0])), 'time': onp.zeros((data['R0'].shape[0]))}
## RUN TEST *************************************************************************************************
for i in tqdm.trange(data['R0'].shape[0]):
    R0 = data['R0'][i,:]
    V0 = data['V0'][i,:]

    ## scale initial conditons
    pscale = np.max(np.abs(R0))
    tscale = pscale/np.max(np.abs(V0))

    xi = TFCDictRobust({'xis':onp.zeros((Hs(z).shape[1],3)),\
                        'xic':onp.array([0.5 * (V0 - R0), -0.5*(V0 + R0)]),\
                        'b':np.sqrt(10.)*onp.ones(1)})

    IC['R0']    = R0 / pscale
    IC['V0']    = V0 * tscale/pscale
    IC['ag']    = np.array([0., 0., -1.62]) * tscale**2/pscale

    xi,it,time = nlls.run(xi,IC)

    sol['loss'][i] = np.max(np.abs(L(xi,IC)))
    sol['it'][i]   = it
    sol['time'][i] = time

## END: **************************************************************
# with open('data/EOL_Spec.pickle', 'wb') as handle:
#     pickle.dump(sol, handle)


import PyPDF2
import sys
pdf = 'Lecture_Schedule2.pdf'
sys.stdout = open('output.txt','wt')
pFObject = open(pdf, 'rb')
pdfR = PyPDF2.PdfFileReader(pFObject)
c = pdfR.numPages
for i in range(c):
    page = pdfR.getPage(i)
    print(page.extractText())


import argparse
import os
from tqdm import tqdm
import pickle
import time
from utils import build_graph, Data, split_validation
from model import *

def seed_everything(seed):
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False
    np.random.seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)

def main(opt):

    if not os.path.exists(os.path.join(os.getcwd(),"long_seq")):
        os.makedirs("long_seq")
    if not os.path.exists(os.path.join(os.getcwd(),"short_seq")):
        os.makedirs("short_seq")

    if opt.sequence_type=="all":
        train_path_data=os.path.join(opt.dataset,"train.txt")
        test_path_data=os.path.join(opt.dataset,"test.txt")
    elif opt.sequence_type=="long":
        data_dir=os.path.join(opt.dataset,"long_short_seq")
        train_path_data=os.path.join(data_dir,"long_train.txt")
        test_path_data=os.path.join(data_dir,"long_test.txt")
    elif opt.sequence_type=="short":
        data_dir=os.path.join(opt.dataset,"long_short_seq")
        train_path_data=os.path.join(data_dir,"short_train.txt")
        test_path_data=os.path.join(data_dir,"short_test.txt")
    else:
        raise ValueError("unknown sequence type")

    with open(train_path_data, 'rb') as f1:
        train_data = pickle.load(f1)

    if opt.validation:
        train_data, valid_data = split_validation(train_data, opt.valid_portion)
        test_data = valid_data
    else:
        with open(test_path_data, 'rb') as f2:
            test_data = pickle.load(f2)

    # all_train_seq = pickle.load(open('../datasets/' + opt.dataset + '/all_train_seq.txt', 'rb'))
    # g = build_graph(all_train_seq)
    train_data = Data(train_data, shuffle=True)
    test_data = Data(test_data, shuffle=False)
    # del all_train_seq, g
    if opt.dataset.split("/")[-2] == 'diginetica_data':
        n_node = 43098
    elif opt.dataset.split("/")[-2] == 'yoochoose1_64' or opt.dataset.split("/")[-2] == 'yoochoose1_4':
        n_node = 37484
    else:
        n_node = 556

    model = trans_to_cuda(SessionGraph(opt, n_node))

    start = time.time()
    best_result = [0, 0]
    best_epoch = [0, 0]
    bad_counter = 0

    # best_metric = float('inf') ## if cross-entropy loss is selected
    best_mrr = float(0)
    best_recall = float(0)

    for epoch in tqdm(range(opt.epoch)):
        print('-------------------------------------------------------')
        print('epoch: ', epoch)
        hit, mrr = train_test(model, train_data, test_data)

        if opt.sequence_type=="all":
            root_dir=os.path.join(os.getcwd(),"output_metrics")
            if not os.path.exists(root_dir):
                os.makedirs(root_dir)
        elif opt.sequence_type=="long":
            root_dir=os.path.join(os.getcwd(),"long_seq","output_metrics")
            if not os.path.exists(root_dir):
                os.makedirs(root_dir)
        elif opt.sequence_type=="short":
            root_dir=os.path.join(os.getcwd(),"short_seq","output_metrics")
            if not os.path.exists(root_dir):
                os.makedirs(root_dir)
        else:
            raise ValueError("unknown sequence type")

        if opt.sequence_type=="all":
            root_dir=os.path.join(os.getcwd(),"output_metrics")
            with open(os.path.join(root_dir,"test_"+opt.output_name),'a') as f:
                f.write(f'{epoch+1},{hit},{mrr}\n')

        elif opt.sequence_type=="long":
            root_dir=os.path.join(os.getcwd(),"long_seq","output_metrics")
            with open(os.path.join(root_dir,"test_"+opt.output_name),'a') as f:
                f.write(f'{epoch+1},{hit},{mrr}\n')

        elif opt.sequence_type=="short":
            root_dir=os.path.join(os.getcwd(),"short_seq","output_metrics")
            with open(os.path.join(root_dir,"test_"+opt.output_name),'a') as f:
                f.write(f'{epoch+1},{hit},{mrr}\n')
        else:
            raise ValueError("unknown sequence type")

        # store best loss and save a model checkpoint
        ckpt_dict = {
            'epoch': epoch + 1,
            'state_dict': model.state_dict(),
            'optimizer': model.optimizer.state_dict()
        }

        if hit>best_recall or mrr>best_mrr:
            best_recall=hit
            best_mrr=mrr
            if opt.sequence_type=="all":
                torch.save(ckpt_dict, opt.model_checkpoint)
            elif opt.sequence_type=="long":
                save_dir=os.path.join(os.getcwd(),"long_seq")
                torch.save(ckpt_dict, os.path.join(save_dir,opt.model_checkpoint))
            elif opt.sequence_type=="short":
                save_dir=os.path.join(os.getcwd(),"short_seq")
                torch.save(ckpt_dict, os.path.join(save_dir,opt.model_checkpoint))
            else:
                raise ValueError("unknown sequence type")

        flag = 0
        if round(hit,2) > round(best_result[0],2):
            best_result[0] = hit
            best_epoch[0] = epoch
            flag = 1
        if round(mrr,2) > round(best_result[1],2):
            best_result[1] = mrr
            best_epoch[1] = epoch
            flag = 1
        print('Best Result:')
        print('\tRecall@20:\t%.4f\tMMR@20:\t%.4f\tEpoch:\t%d,\t%d'% (best_result[0], best_result[1], best_epoch[0], best_epoch[1]))
        bad_counter += 1 - flag
        if bad_counter >= opt.patience:
            break
    print('-------------------------------------------------------')
    end = time.time()
    print("Run time: %f s" % (end - start))

if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('--dataset', default='../YOOCHOOSE_data/yoochoose1_64/', help='the dataset directory')
    parser.add_argument('--batchSize', type=int, default=100, help='input batch size')
    parser.add_argument('--hiddenSize', type=int, default=100, help='hidden state size')
    parser.add_argument('--epoch', type=int, default=30, help='the number of epochs to train for')
    parser.add_argument('--lr', type=float, default=0.001, help='learning rate')  # [0.001, 0.0005, 0.0001]
    parser.add_argument('--lr_dc', type=float, default=0.1, help='learning rate decay rate')
    parser.add_argument('--lr_dc_step', type=int, default=3, help='the number of steps after which the learning rate decay')
    parser.add_argument('--l2', type=float, default=1e-5, help='l2 penalty')  # [0.001, 0.0005, 0.0001, 0.00005, 0.00001]
    parser.add_argument("--gradient_accumulation",action='store_true', help='gradient accumulation or not')
    parser.add_argument("--accumulation_steps",type=int,default=2,
                               help="Number of updates steps to accumulate before performing a backward/update pass.")
    parser.add_argument('--step', type=int, default=1, help='gnn propogation steps')
    parser.add_argument('--patience', type=int, default=10, help='the number of epoch to wait before early stop ')
    parser.add_argument('--nonhybrid', action='store_true', help='only use the global preference to predict')
    parser.add_argument('--validation', action='store_true', help='validation')
    parser.add_argument('--valid_portion', type=float, default=0.1, help='split the portion of training set as validation set')
    parser.add_argument("--output_name", type=str, default="amex_metrics.txt")
    parser.add_argument("--model_checkpoint", type=str, default="amex_checkpoint.pth")
    parser.add_argument('--sequence_type',type=str,default="all",help='all sequence or longer only sequence(>5) or short only sequence(<=5)')
    opt = parser.parse_args()
    print(opt)

    seed_everything(101)

    main(opt)


import re
import sys
import time
from Bio import SeqIO

import os
import argparse

#This script takes a bed file with cds information and creates a bed file with only cds regions
# Use this to get CDS sequence using bedtools getfasta

ap = argparse.ArgumentParser(description='This script takes a bed file with cds information and creates a bed file with only cds regions')

ap.add_argument('-b', type=str, nargs=1, help='Bed file (required)')
ap.add_argument('-s', type=str, nargs=1, help='Stop codon include flag (required)')
ap.add_argument('-o', type=str, nargs=1, help='Output file name (required)')

opts = ap.parse_args()

#check for missing args
missing_arg_flag = 0

if not opts.b:
    print("Annotation bed file missing")
    missing_arg_flag = 1
if not opts.s:
    print("Stop codon include flag missing")
    missing_arg_flag = 1
if not opts.o:
    print("output name missing")
    missing_arg_flag = 1

if missing_arg_flag == 1:
    print("Please try again with complete arguments")

bed_file = opts.b[0]
stop_codon_flag = opts.s[0]
outfile_name = opts.o[0]

print("opening bed file")
#bed_file = sys.argv[1]
bed_file_contents = open(bed_file).read().rstrip("\n").split("\n")

#stop_codon_flag = sys.argv[2] # either include_stop or exclude_stop

#outfile_name = sys.argv[3]
outfile = open(outfile_name,"w")

gene_source = "tama"
trans_source = "tama"

def calc_end(start,block_size):
    end = int(start) + int(block_size) - 1 # adjust for bed 0 base and gtf 1 base coords
    #end = int(start) + int(block_size)  #
    return str(end)

def calc_exon_start(t_start,e_start):
    coordinate_start = int(e_start) + int(t_start)
    return str(coordinate_start)

def convert_str_list_to_int(str_list):
    int_list = []
    for string in str_list:
        int_list.append(int(string))
    return int_list

def convert_int_list_to_str(int_list):
    str_list = []
    for integer in int_list:
        str_list.append(str(integer))
    return str_list

class Transcript:
    def __init__(self, bed_line):
        line_split = bed_line.split("\t")
        chrom = line_split[0]
        t_start = int(line_split[1])
        t_end = int(line_split[2])
        id_line = line_split[3]
        strand = line_split[5]
        num_exons = int(line_split[9])
        blocks = line_split[10]
        starts = line_split[11]

        cds_start = int(line_split[6])
        cds_end = int(line_split[7])

        id_split = id_line.split(";")
        gene_id = id_split[0]
        trans_id = id_split[1]
        prot_id = id_split[2]
        degrade_flag = id_split[3]
        match_flag = id_split[4]
        nmd_flag = id_split[5]

        self.id_list = id_split
        self.prot_id = prot_id
        self.degrade_flag = degrade_flag
        self.match_flag = match_flag
        self.nmd_flag = nmd_flag

        self.trans_id = trans_id
        self.gene_id = gene_id
        self.chrom = chrom
        self.t_start = str(t_start)
        self.t_end = str(t_end)
        self.strand = strand

        t_start_list = [int(t_start)] * int(num_exons)
        start_list = starts.split(",")
        start_list = filter(None, start_list)
        block_list = blocks.split(",")
        block_list = filter(None, block_list)

        self.bed_starts = starts
        self.bed_blocks = blocks

        # coordinate starts and ends
        self.start_list = map(calc_exon_start, t_start_list, start_list)
        self.end_list = map(calc_end, self.start_list, block_list)
        self.num_exons = num_exons

        self.cds_start = cds_start  #################################################
        self.cds_end = cds_end  #################################################

        # make position list

        self.trans_coord_list = []
        self.trans_coord_dict = {} # trans_coord_dict[coord] = index
        for i in xrange(int(self.num_exons)):

            e_index = i
            e_num = e_index + 1

            e_start = int(self.start_list[e_index])
            e_end = int(self.end_list[e_index])

            e_length = e_end - e_start

            for j in xrange(e_length + 1):
                pos_coord = e_start + j
                self.trans_coord_list.append(pos_coord)
                self.trans_coord_dict[pos_coord] = len(self.trans_coord_list) - 1

        # adjust cds end because of bed format 0 1 number method
        # correct for neg strand when cds goes to end
        if self.strand == "-" and self.cds_end == self.trans_coord_list[-1] + 1:
                self.cds_end_adj = self.trans_coord_list[-1]

        else: # this is the normal condition for CDS
            try:
                cds_end_index = self.trans_coord_dict[self.cds_end]
            except:
                print(self.trans_coord_list)
                print(len(self.trans_coord_list))
                print(self.cds_end)
                print(self.trans_id)
                print("error with self.cds_end")
                sys.exit()

            self.cds_end_adj = self.trans_coord_list[cds_end_index - 1]

        # this is deprecated because I do this check before calling this function
        # just keep it here for sanity
        no_cds_flag = "cds_exists"
        if self.cds_start == 0 and self.cds_end == 0:
            no_cds_flag = "no_cds"

        if no_cds_flag == "cds_exists":
            if self.strand == "+":
                if stop_codon_flag == "include_stop":

                    try:
                        cds_end_index = self.trans_coord_dict[self.cds_end_adj]
                    except:
                        print(self.trans_coord_list)
                        print(self.cds_end_adj)
                        print(self.trans_id)
                        print("error with self.cds_end_adj")
                        sys.exit()

                    stop_codon_index = cds_end_index + 3

                    #if stop_codon_index >= len(self.trans_coord_list):
                    #    stop_codon_index = len(self.trans_coord_list) - 1

                        #print(self.trans_coord_list)
                        #print(stop_codon_index)
                        #print(len(self.trans_coord_list))
                        #print(self.trans_id)
                        #sys.exit()

                    self.cds_end_adj = self.trans_coord_list[stop_codon_index]

            if self.strand == "-":
                if stop_codon_flag == "include_stop":
                    cds_start_index = self.trans_coord_dict[self.cds_start]
                    stop_codon_index = cds_start_index - 3
                    self.cds_start = self.trans_coord_list[stop_codon_index]

#        if self.trans_id == "G1594.5":
#            print(self.trans_coord_list)
#            print(stop_codon_index)
#            print(len(self.trans_coord_list))
#            print(self.trans_id)
#            print(self.cds_end_adj)
#            print(self.cds_end)
#            sys.exit()

    def cds_extract(self):

        if int(self.num_exons) != len(self.start_list):
            print("Error with number of exons")
            sys.exit()

        cds_e_start_list = []
        cds_e_end_list = []

        for i in xrange(int(self.num_exons)):

            e_index = i
            e_num = e_index + 1

            e_start = int(self.start_list[e_index])
            e_end = int(self.end_list[e_index])

            cds_e_start = e_start
            cds_e_end = e_end

            if self.cds_start >= e_start and self.cds_start <= e_end:
                cds_e_start = self.cds_start
                #######################

            if self.cds_end_adj >= e_start and self.cds_end_adj <= e_end:
                cds_e_end = self.cds_end_adj
                ######################

            #if self.cds_end_adj == e_start:
            #    continue

            if self.cds_start > e_end: # cds start is after this exon
                continue

            if self.cds_end_adj < e_start: # cds end is before this exon
                continue

            cds_e_start_list.append(cds_e_start)
            cds_e_end_list.append(cds_e_end)

        self.cds_start = cds_e_start_list[0]
        self.cds_end_adj = cds_e_end_list[-1]

        # convert to new bed line
        new_block_list = []
        new_starts_list = []
        for i in xrange(len(cds_e_start_list)):
            cds_e_start = cds_e_start_list[i]
            cds_e_end = cds_e_end_list[i]

            new_start = str(cds_e_start - self.cds_start)
            new_block = str(1 + cds_e_end - cds_e_start)

            new_starts_list.append(new_start)
            new_block_list.append(new_block)

        new_starts_line = ",".join(new_starts_list)
        new_blocks_line = ",".join(new_block_list)

        new_bed_list = line_split
        new_bed_list[10] = new_blocks_line
        new_bed_list[11] = new_starts_line

        new_bed_list[1] = str(self.cds_start)
        new_bed_list[2] = str(self.cds_end_adj + 1)

        new_bed_list[6] = str(self.cds_start)
        new_bed_list[7] = str(self.cds_end_adj + 1)

        new_num_exons = str(len(new_starts_list))

        new_bed_list[9] = new_num_exons

        new_id_list = ["cds"]
        new_id_list.extend(self.id_list)

        new_id_line = ";".join(new_id_list)

        new_bed_list[3] = new_id_line

        new_bed_line = "\t".join(new_bed_list)

        return new_bed_line

count = 0

print("Going through bed file")
for line in bed_file_contents:

    count += 1
    if count % 10000 == 0 :
        print(count)

    line_split = line.split("\t")

    chrom = line_split[0]
    t_start = line_split[1]
    t_end = line_split[2]
    id_line = line_split[3]
    strand = line_split[5]
    num_exons = line_split[9]
    block_sizes = line_split[10]
    block_starts = line_split[11]

    cds_start = line_split[6]
    cds_end = line_split[7]

    id_split = id_line.split(";")
    gene_id = id_split[0]
    trans_id = id_split[1]

    if cds_start != "0" and cds_end != "0":
        trans_obj = Transcript(line)

        new_bed_line = trans_obj.cds_extract()

        outfile.write(new_bed_line)
        outfile.write("\n")


import uvicorn
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware

import config
from routes import auth, student, attendance

app = FastAPI()

origins = ['http://localhost:3000', 'http://192.168.178.23:3000']  # add your front-end ip:port here

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(auth.router)
app.include_router(student.router)
app.include_router(attendance.router)

if __name__ == '__main__':
    uvicorn.run(
        app,
        host=config.get("application", "application.host"),
        port=int(config.get("application", "application.port"))
    )


import numpy as np
from scipy.signal import savgol_filter
if __name__ == '__main__':
    import sys
    from os import path
    sys.path.append( path.dirname(path.dirname( path.abspath(__file__) ) ))

from lib.OpenChromFile import FileOpenClass
from lib.Smoother import Moving_average, data_Bunching
from lib import AirPLS
from lib.peakDetectionAlgorithm import adjustPeaksBoundary, peakSearchAlgorithm
from lib.thresholdCalc import threshold

from lib.ChromAlgorithm import SmoothData, Detrand, data_Bunching
from lib.Peak import Peak
from lib.PeakSymmetry import calcPeakSymmetry

'''
class Peak:
    # ------------ Property ------------
    # Peak 邊界 (front x, front y, back x, back y)
    boundary = (0,0,0,0)
    boundary_index = (-1,-1) # ( front index, back index)
    # Peak 峰值位置 (x,y)
    Apex = (0,0)
    Apex_index = -1
    # Peak 基本參數
    height,tr, width ,area = 0,0,0,0
    # peak 的非對稱資訊
    w05,w01,w005,tf,As,N, sigma= 0,0,0,1,1,0,0
    # implied Peak 資訊 ( 三次微分所找的peak )
    co_peak = []
    #-----------------------------------
    def __init__(self):
        pass
'''
class Chromatograph:
    # ------------ Property ------------
    time=[]
    signal=[]
    baseline=[]
    # 微分圖譜, 分別為一次微分, 二次微分, 三次微分
    dydx=[]
    dydx2=[]
    dydx3=[]
    # 儲存 Peaks 的容器 , 為 list(Class Peak)
    peak_list=[]
    # -----------------------------------

    def __init__(self, time=[], signal=[]):
        self.time = time
        self.signal = signal

    def DataBunch(self, bunching_point=3):
        self.time, self.signal = data_Bunching( self.time, self.signal, bunching_point )

    def CalcBaseline(self, method="AirPLS", *args, **kwargs):
        lambda_ = kwargs.get('lambda_') if 'lambda_' in kwargs else 10000
        self.baseline = Detrand( method, self.signal, lambda_= lambda_ )

    def Smooth( self, method='Savitzky_Golay_Smooth', window_size=13 , *args, **kwargs ):
        order = kwargs.get('order') if 'order' in kwargs else 3
        mode = kwargs.get('mode') if 'mode' in kwargs else 'nearest'
        sigma = kwargs.get('sigma') if 'sigma' in kwargs else 7

        self.time, self.signal = SmoothData(
            method,
            self.time,
            self.signal,
            window_size,
            order=order,
            mode= mode,
            sigma=sigma
        )

    def SmoothDerivative( self, window_size=21, alpha=1.5):
        # ------ 把 window size 處理為奇數 ------
        window_size = window_size+1 if window_size%2 == 0 else window_size
        # ------ ------ ------ ------ ----- -----
        dx = self.time[1] - self.time[0]

        self.dydx = savgol_filter(
            self.signal, window_length=window_size, polyorder=2, deriv=1, delta=dx
          )  # 一次微分
        self.dydx2 = savgol_filter(
            self.signal, window_length=int(window_size*alpha), polyorder=2, deriv=2, delta=dx
            ) # 二次微分
        self.dydx3 = savgol_filter(
            self.signal, window_length=int(window_size*alpha*alpha), polyorder=3, deriv=3, delta=dx
            ) # 三次微分

    def PeakDetection(self, k = 10, tail_factor = 0.3, MIN_PEAK_INTERVAL=0.5 ):
        dydx_threshold = threshold(self.dydx.copy(), k)
        dydx2_threshold = threshold(self.dydx2.copy(), k)
        #///////////////////////////////////////////////////////////////////////
        peak_index_list = peakSearchAlgorithm(
            [self.time,self.signal],
            [self.dydx,self.dydx2,self.dydx3],
            dydx_threshold[1],
            dydx_threshold[0] * tail_factor,
            dydx2_threshold[0],
            offset=10,
            MAX_TIME_WIDTH=0.5
            )

        # peak_index_list : list  , 2D-array
        # array( [ start index, highest index, end index, apex index ] )
        # index 為 time array 或 signal array的編號
        # start index : peak 起始點的 index
        # highest index : peak 最高點的 index
        # end index : peak 終點的 index
        # apex index : 峰值位置的 index, 為 list, 為利用三次微分圖譜所找到的 peak
        #   為單一peak時, len(apex index)=1且應為 apex index[0] == highest index
        #   若有高度共析狀況發生, 圖譜與一次微分無發區分該共析peaks,
        #   此時 len(apex index) > 1, 其 list內容則是共析peak的apex位置
        #///////////////////////////////////////////////////////////////////////

        boundary_table = adjustPeaksBoundary(
            self.time, self.signal, peak_index_list, self.baseline,
            MIN_PEAK_INTERVAL
            )
        self.__build_peak_list( peak_index_list, boundary_table )

        #-----------------------

        temp = []
        for p in self.peak_list:
            temp.append(
                calcPeakSymmetry(self.time, self.signal, p)
                )
        self.peak_list = temp.copy()

        #------------------------

    def __build_peak_list(self, peak_index_list, boundary_table):
        self.peak_list = []
        for i in range( len(peak_index_list) ):
            peak = Peak()
            peak.boundary_index = (
                peak_index_list[i][0], peak_index_list[i][2]
                )
            peak.boundary= ( boundary_table[i] )
            peak.Apex = (
                self.time[ peak_index_list[i][1]], self.signal[ peak_index_list[i][1] ]
                )
            peak.Apex_index = peak_index_list[i][1]

            peak.height = peak.Apex[1]
            peak.tr = peak.Apex[0]
            peak.width = peak.boundary[2] - peak.boundary[0]
            # ----- 計算積分 -----
            area = np.trapz(
                self.signal[ peak.boundary_index[0]: peak.boundary_index[1] ],
                self.time[ peak.boundary_index[0]: peak.boundary_index[1] ]
                )

            # ----- 計算基線 -----
            # 因為計算出來的 baseline可能會大於原始訊號, 這會造成積分值會比預期低
            # 因此多一到工序  min( signal, baseline ), 保證積分時的基線必 <= signal
            base = []
            for i in range( peak.boundary_index[0], peak.boundary_index[1], 1 ):
                base.append( min( self.signal[i], self.baseline[i] ) )

            base_area = np.trapz(
                base ,
                self.time[ peak.boundary_index[0]: peak.boundary_index[1] ]
                )
            peak.area = area - base_area

            # ------ ------ ------ ------
            peak.co_peak = peak_index_list[ 3 ]

            # ----- 寫入資料 -----
            self.peak_list.append( peak )
            # ------ ------ ------ ------

    def peakHeightFilter( self, SN_rate=3.0 ):
        # 利用 peak height 過濾"已找尋到"的 peaks
        new_peak_list = []
        for peak in self.peak_list:
            if (peak.height / self.baseline[ peak.Apex_index ] ) >= SN_rate :
                new_peak_list.append( peak )
        self.peak_list = new_peak_list


import requests
import json
from flask import Flask, render_template, session, request, redirect, url_for, flash
import forms
from flask_session import Session
from flask_bootstrap import Bootstrap4
import msal
import app_config
import lorem
from werkzeug.middleware.proxy_fix import ProxyFix
from datetime import datetime

# initialization
app = Flask(__name__)
app.config.from_object(app_config)
app.config['SECRET_KEY'] = app_config.SECRET_KEY
Session(app)
bootstrap = Bootstrap4(app)
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)

@app.route("/")
def index():
    if not session.get("user"):
        return redirect(url_for("login"))
    return render_template('index.html', user=session["user"], version=msal.__version__)

@app.route("/login")
def login():
    # Technically we could use empty list [] as scopes to do just sign in,
    # here we choose to also collect end user consent upfront
    session["flow"] = _build_auth_code_flow(scopes=app_config.SCOPE)
    return render_template("login.html", auth_url=session["flow"]["auth_uri"], version=msal.__version__)

@app.route(app_config.REDIRECT_PATH)  # Its absolute URL must match your app's redirect_uri set in AAD
def authorized():
    try:
        cache = _load_cache()
        result = _build_msal_app(cache=cache).acquire_token_by_auth_code_flow(
            session.get("flow", {}), request.args)
        if "error" in result:
            return render_template("auth_error.html", result=result)
        session["user"] = result.get("id_token_claims")
        _save_cache(cache)
    except ValueError:  # Usually caused by CSRF
        pass  # Simply ignore them
    return redirect(url_for("index"))

@app.route("/logout")
def logout():
    session.clear()  # Wipe out user and its token cache from session
    return redirect(  # Also logout from your tenant's web session
        app_config.AUTHORITY + "/oauth2/v2.0/logout?post_logout_redirect_uri=" + url_for("index", _external=True))

@app.route("/graphcall")
def graphcall():
    token = _get_token_from_cache(app_config.SCOPE)
    if not token:
        return redirect(url_for("login"))
    graph_data = requests.get(  # Use token to call downstream service
        app_config.ENDPOINT,
        headers={'Authorization': 'Bearer ' + token['access_token']},
    ).json()
    return render_template('display.html', result=graph_data, version=msal.__version__)

@app.route("/get-access-token")
def get_access_token():
    token = _get_token_from_cache(app_config.SCOPE)
    if not token:
        return redirect(url_for("login"))
    token_type = token['token_type']
    access_token = token['access_token']
    expires_in = token['expires_in']
    return render_template('get_access_token.html', raw_access_token=token, token_type=token_type,
                           access_token=access_token, expires_in=expires_in, version=msal.__version__)

@app.route("/send-mail", methods=['GET', 'POST'])
def send_mail():
    if not session.get("user"):
        return redirect(url_for("login"))

    form = forms.SendMailForm()

    # get from email address (userPrincipalName)
    from_email = _get_user_profile_json()['userPrincipalName']

    if form.validate_on_submit():
        recipient = form.recipient.data
        subject = form.subject.data
        content = form.content.data
        save_to_sent_items = form.save_to_sent_items.data

        # get 'access_token'
        token = _get_token_from_cache(app_config.SCOPE)
        if not token:
            return redirect(url_for("login"))
        access_token = token['access_token']

        # send email
        flag = _send_mail(recipient=recipient, subject=subject, content=content, access_token=access_token,
                          save_to_sent_items=save_to_sent_items)
        if flag:
            flash('Your message has been successfully submitted to the corresponding API.')
        else:
            flash('There is an error that occurred. Please refer to the debug log for more information.')

    # define form default values
    form.subject.data = 'TEST MESSAGE [' + str(datetime.now().strftime("%d/%m/%Y %H:%M:%S")) + ']'
    form.content.data = lorem.paragraph()

    return render_template('send_mail.html', form=form, from_email=from_email, version=msal.__version__)

def _send_mail(recipient, subject, content, access_token, save_to_sent_items=False):
    if recipient is not None and subject is not None and content is not None and access_token is not None:
        user_ms_id = _get_user_profile_json()['id']
        url = 'https://graph.microsoft.com/v1.0/users/' + str(user_ms_id) + '/sendMail'
        print(url)
        payload = json.dumps({
            "message": {
                "subject": str(subject),
                "body": {
                    "contentType": "HTML",
                    "content": str(content)
                },
                "toRecipients": [
                    {
                        "emailAddress": {
                            "address": str(recipient)
                        }
                    }
                ]
            },
            "saveToSentItems": str(save_to_sent_items).lower()
        })

        headers = {
            'Authorization': 'Bearer ' + str(access_token),
            'Content-Type': 'application/json'
        }

        # send request
        response = requests.request("POST", url, headers=headers, data=payload)

        # capture response and return to the caller
        print(f"Status Code: {response.status_code}, Response: {response.text}")
        if str(response.status_code) != '202':
            return False
        return True

@app.route('/get-user-profile')
def get_user_profile():
    url = "https://graph.microsoft.com/v1.0/me/"
    payload = {}
    token = _get_token_from_cache(app_config.SCOPE)
    if not token:
        return redirect(url_for("login"))
    access_token = token['access_token']
    headers = {
        'Authorization': 'Bearer ' + str(access_token)
    }
    response = requests.request("GET", url, headers=headers, data=payload).json()
    return render_template('get_user_profile.html', user_profile=response)

def _get_user_profile_json():
    url = "https://graph.microsoft.com/v1.0/me/"
    token = _get_token_from_cache(app_config.SCOPE)
    if not token:
        return redirect(url_for("login"))
    access_token = token['access_token']
    response = requests.request("GET", url, headers={'Authorization': 'Bearer ' + str(access_token)}).json()
    return response

def _load_cache():
    cache = msal.SerializableTokenCache()
    if session.get("token_cache"):
        cache.deserialize(session["token_cache"])
    return cache

def _save_cache(cache):
    if cache.has_state_changed:
        session["token_cache"] = cache.serialize()

def _build_msal_app(cache=None, authority=None):
    return msal.ConfidentialClientApplication(
        app_config.CLIENT_ID, authority=authority or app_config.AUTHORITY,
        client_credential=app_config.CLIENT_SECRET, token_cache=cache)

def _build_auth_code_flow(authority=None, scopes=None):
    return _build_msal_app(authority=authority).initiate_auth_code_flow(
        scopes or [],
        redirect_uri=url_for("authorized", _external=True))

def _get_token_from_cache(scope=None):
    cache = _load_cache()  # This web app maintains one cache per session
    cca = _build_msal_app(cache=cache)
    accounts = cca.get_accounts()
    if accounts:  # So all account(s) belong to the current signed-in user
        result = cca.acquire_token_silent(scope, account=accounts[0])
        _save_cache(cache)
        return result

app.jinja_env.globals.update(_build_auth_code_flow=_build_auth_code_flow)  # Used in template

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


# coding:utf-8
"""
Filename: utils.py
Author: @DvdNss

Created on 11/15/2021
"""

import json
import os

def dict_to_json(args_dict: dict, filename: str) -> str:
    """
    Saves a dictionnary as a json file.

    :param args_dict: model dictionnary
    :param filename: json file name
    """

    assert filename[-5:] == '.json', \
        "filename must be a .json file. "

    # Create intermediate folders
    os.makedirs(os.path.dirname(filename), exist_ok=True)

    # Saving the config as json file
    with open(filename, 'w') as config:
        json.dump(args_dict, config, indent=2)

    return filename


from transformers import AutoModel, AutoTokenizer
import torch
import torch.nn.functional as F
from sklearn.metrics import mean_squared_error
from tqdm import tqdm
import numpy as np
import pandas as pd
import os,gc,re,warnings
import sys

from cuml.svm import SVR
import cuml

#Fetching data from folds
dftr = pd.read_csv('C:/Users/lionh/OneDrive/Desktop/roberta-train/data/train_folds.csv')
dfts = pd.read_csv('C:/Users/lionh/OneDrive/Desktop/roberta-train/data/test.csv')

#for ease I have defined the models here, but youb need to take it from config in actual process
tokenizer = None
MAX_LEN = 640
BATCH_SIZE = 4
model = {
    'MODEL_LM_debertabase' : 'microsoft/deberta-base',
    'MODEL_LM_debertalargev3' : 'microsoft/deberta-v3-large',
    'MODEL_LM_debertalarge' : 'microsoft/deberta-large',
    'MODEL_LM_debertalargemnli' : 'microsoft/deberta-large-mnli',
    'MODEL_LM_debertaxlarge' : 'microsoft/deberta-xlarge'
}

#Code for mean pooling
def mean_pooling(model_output, attention_mask):
    token_embeddings = model_output.last_hidden_state.detach().cpu()
    input_mask_expanded = (
        attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
    )
    return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(
        input_mask_expanded.sum(1), min=1e-9
    )

class EmbedDataset(torch.utils.data.Dataset):
    def __init__(self,df):
        self.df = df.reset_index(drop=True)
    def __len__(self):
        return len(self.df)
    def __getitem__(self,idx):
        text = self.df.loc[idx,"full_text"]
        tokens = tokenizer(
                text,
                None,
                add_special_tokens=True,
                padding='max_length',
                truncation=True,
                max_length=MAX_LEN,return_tensors="pt")
        tokens = {k:v.squeeze(0) for k,v in tokens.items()}
        return tokens

ds_tr = EmbedDataset(dftr)
embed_dataloader_tr = torch.utils.data.DataLoader(ds_tr,\
                        batch_size=BATCH_SIZE,\
                        shuffle=False)
ds_te = EmbedDataset(dfts)
embed_dataloader_te = torch.utils.data.DataLoader(ds_te,\
                        batch_size=BATCH_SIZE,\
                        shuffle=False)

#Extracting Embeddings from various deberta models

def get_embeddings(MODEL_NM='', MAX=640, BATCH_SIZE=4, verbose=True):
    global tokenizer, MAX_LEN
    DEVICE="cuda"
    model = AutoModel.from_pretrained( MODEL_NM )
    tokenizer = AutoTokenizer.from_pretrained( MODEL_NM )
    MAX_LEN = MAX

    model = model.to(DEVICE)
    model.eval()
    all_train_text_feats = []
    for batch in tqdm(embed_dataloader_tr,total=len(embed_dataloader_tr)):
        input_ids = batch["input_ids"].to(DEVICE)
        attention_mask = batch["attention_mask"].to(DEVICE)
        with torch.no_grad():
            model_output = model(input_ids=input_ids,attention_mask=attention_mask)
        sentence_embeddings = mean_pooling(model_output, attention_mask.detach().cpu())
        # Normalize the embeddings
        sentence_embeddings = F.normalize(sentence_embeddings, p=2, dim=1)
        sentence_embeddings =  sentence_embeddings.squeeze(0).detach().cpu().numpy()
        all_train_text_feats.extend(sentence_embeddings)
    all_train_text_feats = np.array(all_train_text_feats)
    if verbose:
        print('Train embeddings shape',all_train_text_feats.shape)

    te_text_feats = []
    for batch in tqdm(embed_dataloader_te,total=len(embed_dataloader_te)):
        input_ids = batch["input_ids"].to(DEVICE)
        attention_mask = batch["attention_mask"].to(DEVICE)
        with torch.no_grad():
            model_output = model(input_ids=input_ids,attention_mask=attention_mask)
        sentence_embeddings = mean_pooling(model_output, attention_mask.detach().cpu())
        # Normalize the embeddings
        sentence_embeddings = F.normalize(sentence_embeddings, p=2, dim=1)
        sentence_embeddings =  sentence_embeddings.squeeze(0).detach().cpu().numpy()
        te_text_feats.extend(sentence_embeddings)
    te_text_feats = np.array(te_text_feats)
    if verbose:
        print('Test embeddings shape',te_text_feats.shape)

    return all_train_text_feats, te_text_feats

#taking deberta variants one by one
MODEL_NM = model['MODEL_LM_debertabase']
all_train_text_feats, te_text_feats = get_embeddings(MODEL_NM)
print('Got debertabase embeddings')

MODEL_NM = model['MODEL_LM_debertalargev3']
all_train_text_feats2, te_text_feats2 = get_embeddings(MODEL_NM)

MODEL_NM = model['MODEL_LM_debertalarge']
all_train_text_feats2, te_text_feats2 = get_embeddings(MODEL_NM)

MODEL_NM = model['MODEL_LM_debertalargemnli']
all_train_text_feats2, te_text_feats2 = get_embeddings(MODEL_NM)

MODEL_NM = model['MODEL_LM_debertaxlarge']
all_train_text_feats2, te_text_feats2 = get_embeddings(MODEL_NM)

#combinig all the embeddings
all_train_text_feats = np.concatenate([all_train_text_feats,all_train_text_feats2,
                                       all_train_text_feats3,all_train_text_feats4,
                                       all_train_text_feats5],axis=1)

te_text_feats = np.concatenate([te_text_feats,te_text_feats2,
                                te_text_feats3,te_text_feats4,
                                te_text_feats5],axis=1)

#deleting all the variables to free up memory
del all_train_text_feats2, te_text_feats2
del all_train_text_feats3, te_text_feats3
del all_train_text_feats4, te_text_feats4
del all_train_text_feats5, te_text_feats5
gc.collect()

print('concatenated embeddings have shape', all_train_text_feats.shape)

#Now defining a Rapid SVR model to predict the target variable
preds = []
scores = []
def comp_score(y_true,y_pred):
    rmse_scores = []
    for i in range(len(target_cols)):
        rmse_scores.append(np.sqrt(mean_squared_error(y_true[:,i],y_pred[:,i])))
    return np.mean(rmse_scores)

#for fold in tqdm(range(FOLDS),total=FOLDS):
for fold in range(FOLDS):
    print('#'*25)
    print('### Fold',fold+1)
    print('#'*25)

    dftr_ = dftr[dftr["FOLD"]!=fold]
    dfev_ = dftr[dftr["FOLD"]==fold]

    tr_text_feats = all_train_text_feats[list(dftr_.index),:]
    ev_text_feats = all_train_text_feats[list(dfev_.index),:]

    ev_preds = np.zeros((len(ev_text_feats),6))
    test_preds = np.zeros((len(te_text_feats),6))
    for i,t in enumerate(target_cols):
        print(t,', ',end='')
        clf = SVR(C=1)
        clf.fit(tr_text_feats, dftr_[t].values)
        ev_preds[:,i] = clf.predict(ev_text_feats)
        test_preds[:,i] = clf.predict(te_text_feats)
    print()
    score = comp_score(dfev_[target_cols].values,ev_preds)
    scores.append(score)
    print("Fold : {} RSME score: {}".format(fold,score))
    preds.append(test_preds)

print('#'*25)
print('Overall CV RSME =',np.mean(scores))

#preds: output of the model
#  array([[2.94900918, 2.80713797, 3.1332984 , 2.95393324, 2.66409802,
#          2.67784142],
#         [2.72251678, 2.46881819, 2.70102072, 2.32998419, 2.05252576,
#          2.68055749],
#         [3.63700128, 3.44540453, 3.56421232, 3.65185833, 3.40497899,
#          3.35660815]])]
# np.array(preds)
# [[2.91515398 2.82003951 3.16167831 2.97052073 2.67681551 2.68956351]
#   [2.70253325 2.45898795 2.71900558 2.3118124  2.01470613 2.63774276]
#   [3.6399312  3.4656961  3.58689547 3.64418197 3.41387224 3.35341716]]

#taking average of the predictions
sub = dfte.copy()
sub.loc[:,target_cols] = np.average(np.array(preds),axis=0)
sub_columns = pd.read_csv("C:/Users/lionh/OneDrive/Desktop/roberta-train/data/sample_submission.csv").columns
sub = sub[sub_columns]


import os
import requests
import logging
import time
from datetime import datetime

import json
from bs4 import BeautifulSoup
import re
import pandas as pd
from tqdm import tqdm

# Player Goalkeeping
player_keepers = [
    "nationality", "squad", "age", "birth_year",
    "games_gk", "games_starts_gk", "minutes_gk", "goals_against_gk",
    "goals_against_per90_gk", "shots_on_target_against", "saves", "save_pct",
    "wins_gk", "draws_gk", "losses_gk", "clean_sheets", "clean_sheets_pct",
    "pens_att_gk", "pens_allowed", "pens_saved", "pens_missed_gk"]

# Squad Advanced Goalkeeping
keepersadv = [
    "goals_against_gk", "pens_allowed", "free_kick_goals_against_gk",
    "corner_kick_goals_against_gk", "own_goals_against_gk", "psxg_gk",
    "psnpxg_per_shot_on_target_against", "psxg_net_gk", "psxg_net_per90_gk",
    "passes_completed_launched_gk", "passes_launched_gk",
    "passes_pct_launched_gk", "passes_gk", "passes_throws_gk",
    "pct_passes_launched_gk", "passes_length_avg_gk", "goal_kicks",
    "pct_goal_kicks_launched", "goal_kick_length_avg", "crosses_gk",
    "crosses_stopped_gk", "crosses_stopped_pct_gk",
    "def_actions_outside_pen_area_gk", "def_actions_outside_pen_area_per90_gk",
    "avg_distance_def_actions_gk"]

# Player Standard Stats
player_stats = [
    "nationality", "position", "squad", "age", "birth_year", "games",
    "games_starts", "minutes", "goals", "assists", "goals_pens", "pens_made",
    "pens_att", "cards_yellow", "cards_red", "goals_per90", "assists_per90",
    "goals_assists_per90", "goals_pens_per90", "goals_assists_pens_per90",
    "xg", "npxg", "xa", "xg_per90", "xa_per90", "xg_xa_per90", "npxg_per90",
    "npxg_xa_per90"]

# Player Shooting
player_shooting = [
    "shots_total", "shots_on_target", "shots_on_target_pct",
    "shots_total_per90", "shots_on_target_per90", "goals_per_shot",
    "goals_per_shot_on_target", "average_shot_distance", "shots_free_kicks",
    "pens_made", "pens_att", "xg", "npxg", "npxg_per_shot", "xg_net",
    "npxg_net"]

# Squad Passing
passing = [
    "passes_completed", "passes", "passes_pct", "passes_total_distance",
    "passes_progressive_distance", "passes_completed_short", "passes_short",
    "passes_pct_short", "passes_completed_medium", "passes_medium",
    "passes_pct_medium", "passes_completed_long", "passes_long",
    "passes_pct_long", "assists", "xa_net", "assisted_shots",
    "passes_into_final_third", "passes_into_penalty_area",
    "crosses_into_penalty_area", "progressive_passes"]

# Squad Pass Types
passing_types = [
    "passes", "passes_live", "passes_dead", "passes_free_kicks",
    "through_balls", "passes_pressure", "passes_switches", "crosses",
    "corner_kicks", "corner_kicks_in", "corner_kicks_out",
    "corner_kicks_straight", "passes_ground", "passes_low", "passes_high",
    "passes_left_foot", "passes_right_foot", "passes_head", "throw_ins",
    "passes_other_body", "passes_completed", "passes_offsides", "passes_oob",
    "passes_intercepted", "passes_blocked"]

# Squad Goal and Shot Creation
gca = [
    "sca", "sca_per90", "sca_passes_live", "sca_passes_dead", "sca_dribbles",
    "sca_shots", "sca_fouled", "sca_defense", "gca", "gca_per90",
    "gca_passes_live", "gca_passes_dead", "gca_dribbles", "gca_shots",
    "gca_fouled", "gca_defense"]

# Squad Defensive Actions
defense = [
    "tackles", "tackles_won", "tackles_def_3rd", "tackles_mid_3rd",
    "tackles_att_3rd", "dribble_tackles", "dribbles_vs", "dribble_tackles_pct",
    "dribbled_past", "pressures", "pressure_regains", "pressure_regain_pct",
    "pressures_def_3rd", "pressures_mid_3rd", "pressures_att_3rd", "blocks",
    "blocked_shots", "blocked_shots_saves", "blocked_passes", "interceptions",
    "tackles_interceptions", "clearances", "errors"]

# Squad Possession
possession = [
    "touches", "touches_def_pen_area", "touches_def_3rd", "touches_mid_3rd",
    "touches_att_3rd", "touches_att_pen_area", "touches_live_ball",
    "dribbles_completed", "dribbles", "dribbles_completed_pct",
    "players_dribbled_past", "nutmegs", "carries", "carry_distance",
    "carry_progressive_distance", "progressive_carries",
    "carries_into_final_third", "carries_into_penalty_area", "miscontrols",
    "dispossessed", "pass_targets", "passes_received", "passes_received_pct",
    "progressive_passes_received"]

# Squad Miscellaneous Stats
misc = [
    "cards_yellow", "cards_red", "cards_yellow_red", "fouls", "fouled",
    "offsides", "crosses", "interceptions", "tackles_won", "pens_won",
    "pens_conceded", "own_goals", "ball_recoveries", "aerials_won",
    "aerials_lost", "aerials_won_pct"]

class FBRef:
    """Scrape FBRef website"""

    def __init__(self, logger, season_data):
        """
        Args:
            logger (logging.logger): Logging package
            season_data (int): Season
        """
        self.root = 'data/fbref'
        if not os.path.exists(self.root):
            os.makedirs(self.root)

        self.logger = logger

        self.season = season_data['season']

    def get_competition_urls(self, url):
        """ Get all the links of previous EPL seasons

        Returns:
            (list): past url seasons
        """
        res = requests.get(url)
        parsed_html = BeautifulSoup(res.text, 'html.parser')
        past_seasons = []

        for table in parsed_html.findAll('table'):
            for a in table.findAll('a'):
                if 'comps' in a['href'] and a['href'] not in past_seasons:
                    past_seasons.append(a['href'])

        return past_seasons

    def get_fixtures(self):
        """ Scrape data fixture data """

        for index, comp in zip(
                ["9", "690", "514", "8", "19"],
                [
                    'Premier-League', 'EFL-Cup', "FA-Cup",
                    "Champions-League", "Europa-League"]):

            # Get links of historical competitions
            seasons = self.get_competition_urls(
                f'https://fbref.com/en/comps/{index}/history/{comp}-Seasons')

            self.logger.info(f"Downloading {comp} Fixtures Data")
            for season in seasons:
                if season.split('/')[-2] == index:
                    url = (
                        f'https://fbref.com/en/comps/{index}/schedule' +
                        f'/{comp}-Scores-and-Fixtures')
                    year = self.season

                else:
                    url = (
                        f'https://fbref.com/en/comps/{index}/' +
                        season.split('/')[-2] +
                        '/schedule/' +
                        season.split('/')[-1][:-6] +
                        '-Scores-and-Fixtures')
                    year = season.split('/')[-1][:4]

                # Skip years with no underlying stats
                if int(year) > 2016:
                    self.logger.info(f"Season: {season}")

                    df = pd.read_html(url)[0]
                    time_start = time.time()
                    # Remove empty row
                    df = df[~(df.Date.isna())]
                    # Add Competition label
                    df["Competition"] = comp

                    if "Wk" in df.columns:
                        if (
                                comp == "Champions-League" or
                                comp == "Europa-League"):
                            df = df.drop(["Wk"], axis=1)
                        else:
                            df = df.rename(columns={'Wk': "Round"})

                    df = df.loc[:, [
                        "Round", "Day", "Date", "Time", "Home", "Score",
                        "Away", "Attendance", "Venue", "Referee",
                        "Notes", "Competition"]]

                    if os.path.isfile(os.path.join(self.root, 'fixtures.csv')):
                        df.to_csv(
                            os.path.join(self.root, 'fixtures.csv'),
                            index=False, mode='a', header=False)
                    else:
                        df.to_csv(
                            os.path.join(self.root, 'fixtures.csv'),
                            index=False)

                    # Wait to comply with scraping rules
                    time.sleep(3 - (time.time() - time_start))

        # Drop dupplicates in case I run the latest season scraper to update it.
        (
            pd.read_csv(os.path.join(self.root, 'fixtures.csv'))
            .drop_duplicates()
            .to_csv(os.path.join(self.root, 'fixtures.csv'), index=False))

    def get_team_data(self, url):
        """ Scrape each table of team data

        Args:
            url (string): Base link to the team stats

        Returns:
            (pd.DataFrame): Final data
        """
        df, df_opp = [], []
        # URL Request
        tables = pd.read_html(url.format(table=""))
        for i, table in enumerate(tables):
            if i > 1 or i == 0 :
                if i != 0 :
                    table.columns = [' '.join(col).strip() if "Unnamed" not in col[0] else col[1] for i, col in enumerate(table.columns.values)]
                else:
                    table = table.sort_values(by=['Squad']).reset_index().drop(['Rk', 'index'], 1)

                if not i % 2:
                    df.append(table)
                else:
                    df_opp.append(table)

        df = pd.concat(df, axis=1)
        df_opp = pd.concat(df_opp, axis=1)
        return df.loc[:, ~df.columns.duplicated()], df_opp.loc[:, ~df_opp.columns.duplicated()]

    def get_url(self, url):
        """ Request the url

        Args:
            url (string): link

        Returns:
            [type]: Parsed html
        """
        attempts = 3
        while attempts:
            try:
                res = requests.get(url)

                if res.status_code != 200:
                    raise Exception('Bad request response.')

                # Handle hidden table.
                comm = re.compile("<!--|-->")
                soup = BeautifulSoup(comm.sub("", res.text), 'lxml')
                return soup.findAll("tbody")

            except:
                attempts -= 1
                if not attempts:
                    self.logger.warning(
                        f"URL Request to {url} failed after 3 attempts.")
                    return None

                self.logger.warning(
                    f'URL Request failed, retrying in 30 seconds! URL: {url}')
                time.sleep(30)

        time.sleep(3)

    def get_player_table(self, url, columns):
        """ Parse the table of outfield or keeper player data

        Args:
            url (string): Link
            columns (list): Column names to select

        Returns:
            pd.DataFrame: Data
        """
        tables = self.get_url(url)
        player_rows = tables[2].find_all('tr')
        player_dict = dict()

        for row in player_rows:
            if row.find('th', {"scope": "row"}) is not None:
                player_name = (
                    row.find('td', {"data-stat": "player"})
                    .text.strip().encode().decode("utf-8"))

                # Add player name
                if 'player' in player_dict:
                    player_dict['player'].append(player_name)
                else:
                    player_dict['player'] = [player_name]

                # Parse the table
                for col in columns:
                    # Get the statistic
                    cell = row.find("td", {"data-stat": col})
                    if cell is None:
                        # Fill na
                        text = 'None'
                    else:
                        a = cell.text.strip().encode()
                        text = a.decode("utf-8")
                        # Fill na
                        if(text == ''):
                            text = '0'

                        if (
                                (col != 'player') & (col != 'nationality') &
                                (col != 'position') & (col != 'squad') &
                                (col != 'age') & (col != 'birth_year')):
                            text = float(text.replace(',', ''))

                    if col in player_dict:
                        player_dict[col].append(text)
                    else:
                        player_dict[col] = [text]

        return pd.DataFrame.from_dict(player_dict)

    def get_keeper_data(self, url):
        """ Scrape each table of Goalkeeper data

        Args:
            url (string): Base link to the team stats

        Returns:
            (pd.DataFrame): Final data
        """
        categories_name = ['keepers', 'keepersadv']
        categories_cols = [player_keepers, keepersadv]
        df = []
        for name, cols in zip(categories_name, categories_cols):
            df.append(self.get_player_table(url.format(table=name + "/"), cols))

        df = pd.concat(df, axis=1)
        return df.loc[:, ~df.columns.duplicated()]

    def get_player_data(self, url):
        """ Scrape each table of Outfield player data

        Args:
            url (string): Base link to the team stats

        Returns:
            (pd.DataFrame): Final data
        """
        categories_name = [
            'stats', 'shooting', 'passing', 'passing_types',
            'gca', 'defense', 'possession', 'misc'
            ]
        categories_cols = [
            player_stats, player_shooting, passing, passing_types,
            gca, defense, possession, misc
            ]
        df = []
        for name, cols in zip(categories_name, categories_cols):
            df.append(self.get_player_table(url.format(table=name + "/"), cols))

        df = pd.concat(df, axis=1)
        return df.loc[:, ~df.columns.duplicated()]

    def get_pl_season(self, history=False):
        """ Scrape data from seasons

        Args:
            history (bool, optional): Scrape current. Defaults to False.
        """
        seasons = self.get_competition_urls(
            'https://fbref.com/en/comps/9/history/Premier-League-Seasons')

        if not history:
            seasons = [seasons[0]]

        self.logger.info("Downloading Season Data")

        for season in seasons:
            if season.split('/')[-2] == '9':
                url = (
                    'http://fbref.com/en/comps/9/{table}' +
                    season.split('/')[-1])
                year = self.season

            else:
                url = (
                    'https://fbref.com/en/comps/9/' +
                    season.split('/')[-2] +  '/{table}' +
                    season.split('/')[-1])
                year = season.split('/')[-1][:4]

            if int(year) > 2016:
                self.logger.info(f"Season: {season}")

                df, df_opp = self.get_team_data(url)
                time_start = time.time()

                df.loc[:, "season"] = year
                df_opp.loc[:, "season"] = year
                if os.path.isfile(os.path.join(self.root, 'team.csv')):
                    df.to_csv(
                        os.path.join(self.root, 'team.csv'),
                        index=False, mode='a', header=False)
                else:
                    df.to_csv(
                        os.path.join(self.root, 'team.csv'),
                        index=False)
                if os.path.isfile(os.path.join(self.root, 'team_opp.csv')):
                    df_opp.to_csv(
                        os.path.join(self.root, 'team_opp.csv'),
                        index=False, mode='a', header=False)
                else:
                    df_opp.to_csv(
                        os.path.join(self.root, 'team_opp.csv'),
                        index=False)

                # Wait to comply with scraping rules
                time.sleep(3 - (time.time() - time_start))

                df = self.get_keeper_data(url)
                time_start = time.time()
                df.loc[:, "season"] = year
                if os.path.isfile(os.path.join(self.root, 'keeper.csv')):
                    df.to_csv(
                        os.path.join(self.root, 'keeper.csv'),
                        index=False, mode='a', header=False)
                else:
                    df.to_csv(
                        os.path.join(self.root, 'keeper.csv'),
                        index=False)

                # Wait to comply with scraping rules
                time.sleep(3 - (time.time() - time_start))

                df = self.get_player_data(url)
                time_start = time.time()
                df.loc[:, "season"] = year
                if os.path.isfile(os.path.join(self.root, 'outfield.csv')):
                    df.to_csv(
                        os.path.join(self.root, 'outfield.csv'),
                        index=False, mode='a', header=False)
                else:
                    df.to_csv(
                        os.path.join(self.root, 'outfield.csv'),
                        index=False)

                # Wait to comply with scraping rules
                time.sleep(3 - (time.time() - time_start))

        # Drop dupplicates in case I run the latest season scraper to update it.
        (
            pd.read_csv(os.path.join(self.root, 'outfield.csv'))
            .drop_duplicates()
            .to_csv(os.path.join(self.root, 'outfield.csv'), index=False))
        (
            pd.read_csv(os.path.join(self.root, 'keeper.csv'))
            .drop_duplicates()
            .to_csv(os.path.join(self.root, 'keeper.csv'), index=False))
        (
            pd.read_csv(os.path.join(self.root, 'team.csv'))
            .drop_duplicates()
            .to_csv(os.path.join(self.root, 'team.csv'), index=False))
        (
            pd.read_csv(os.path.join(self.root, 'team_opp.csv'))
            .drop_duplicates()
            .to_csv(os.path.join(self.root, 'team_opp.csv'), index=False))

    def get_games_players(self, tables):
        """ Get data about the outfielders who played

        Args:
            tables (list): DataFrames extracted from the url of fixture

        Returns:
            pd.DataFrames: Data of the fixture
        """
        df_h = []
        df_a = []

        # Home player
        for i in range(3, 9):
            table = tables[i].copy()
            table.columns = [' '.join(col).strip() if i > 5 else col[1] for i, col in enumerate(table.columns.values)]
            table = table.dropna(subset=["Nation"])
            table.loc[:, 'home'] = 1
            df_h.append(table)

        # Away player
        for i in range(10, 16):
            table = tables[i].copy()
            table.columns = [' '.join(col).strip() if i > 5 else col[1] for i, col in enumerate(table.columns.values)]
            table = table.dropna(subset=["Nation"])
            table.loc[:, 'home'] = 0
            df_a.append(table)

        df = pd.concat(
            [pd.concat(df_h, axis=1),
            pd.concat(df_a, axis=1)])
        return df.loc[:, ~df.columns.duplicated()]

    def get_games_keepers(self, tables):
        """ Get data about the keepers who played

        Args:
            tables (list): DataFrames extracted from the url of fixture

        Returns:
            pd.DataFrames: Data of the fixture
        """
        # Home keeper
        table_h = tables[9].copy()
        table_h.columns = [' '.join(col).strip() if i > 5 else col[1] for i, col in enumerate(table_h.columns.values)]
        table_h = table_h.dropna(subset=["Nation"])
        table_h.loc[:, 'home'] = 1

        # Away keeper
        table_a = tables[16].copy()
        table_a.columns = [' '.join(col).strip() if i > 5 else col[1] for i, col in enumerate(table_a.columns.values)]
        table_a = table_a.dropna(subset=["Nation"])
        table_a.loc[:, 'home'] = 0

        df = pd.concat([table_h, table_a])
        return df.loc[:, ~df.columns.duplicated()]

    def get_games_lineups(self, tables):
        """ Get data about the players who played and got subsituted

        Args:
            tables (list): DataFrames extracted from the url of fixture

        Returns:
            pd.DataFrames: Data of the fixture
        """
        df_h = []
        df_a = []

        # Home roster
        starting_lineup_h = tables[0][[tables[0].columns[1]]]
        starting_lineup_h['Lineup'] = 1

        starting_lineup_h.loc[:11, 'Starter'] = 1
        starting_lineup_h.loc[11:, 'Benched'] = 1

        starting_lineup_h = starting_lineup_h.drop(11)
        starting_lineup_h = starting_lineup_h.rename(columns={tables[0].columns[1]: 'Player'})
        starting_lineup_h.loc[:, 'home'] = 1

        # Away roster
        starting_lineup_a = tables[1][[tables[1].columns[1]]]
        starting_lineup_a['Lineup'] = 1

        starting_lineup_a.loc[:11, 'Starter'] = 1
        starting_lineup_a.loc[11:, 'Benched'] = 1

        starting_lineup_a = starting_lineup_a.drop(11)
        starting_lineup_a = starting_lineup_a.rename(columns={tables[1].columns[1]: 'Player'})
        starting_lineup_a.loc[:, 'home'] = 0

        # Home minutes played & substitutions
        minutes_h = tables[3][[('Unnamed: 0_level_0', 'Player'), ('Unnamed: 5_level_0', 'Min')]]
        minutes_h.columns = minutes_h.columns.map(lambda x: x[1])
        minutes_h = minutes_h.iloc[:-1]

        # Away minutes played & substitutions
        minutes_a = tables[10][[('Unnamed: 0_level_0', 'Player'), ('Unnamed: 5_level_0', 'Min')]]
        minutes_a.columns = minutes_a.columns.map(lambda x: x[1])
        minutes_a = minutes_a.iloc[:-1]

        df_h = pd.merge(
            starting_lineup_h,
            minutes_h,
            how='outer',
            left_on='Player',
            right_on='Player'
        )

        df_a = pd.merge(
            starting_lineup_a,
            minutes_a,
            how='outer',
            left_on='Player',
            right_on='Player'
        )
        df = pd.concat([df_h, df_a])

        return df.fillna(0)

    def get_pl_games(self, history=False):
        """ Get every PL fixture data

        Args:
            history (boolean): Collect historical data
        """
        seasons = self.get_competition_urls(
            'https://fbref.com/en/comps/9/history/Premier-League-Seasons')

        if not history:
            seasons = [seasons[0]]

        self.logger.info("Downloading Match Data")

        for season in seasons:
            if season.split('/')[-2] == '9':
                url = (
                    'https://fbref.com/en/comps/9/schedule/Premier-League-Scores-and-Fixtures')
                year = self.season

            else:
                url = (
                    'https://fbref.com/en/comps/9/' +
                    season.split('/')[-2] +
                    '/schedule/' +
                    season.split('/')[-1][:-6] +
                    '-Scores-and-Fixtures')
                year = season.split('/')[-1][:4]

            # Skip years with no underlying stats
            if int(year) > 2016:
                self.logger.info(f"Season: {season}")

                # URL Request
                df = (
                    pd.read_html(url)[0]
                    .loc[:, [
                        'Wk', 'Day', 'Date', 'Time', 'Home', 'Away',
                        'Attendance', 'Venue', 'Referee', 'Notes']]
                        )
                time.sleep(3)

                # Remove empty row
                df = df[~df.Wk.isna()]
                # Remove upcoming games
                df = df[df.Date < datetime.now().strftime("%Y-%m-%d")]
                # Save
                if os.path.isfile(os.path.join(self.root, f'games.csv')):
                    df.to_csv(
                        os.path.join(self.root, 'games.csv'),
                        index=False, mode='a', header=False)
                else:
                    df.to_csv(
                        os.path.join(self.root, f'games.csv'),
                        index=False)

                # Get urls to games
                table_rows = self.get_url(url)[0].find_all('tr')

                for row in tqdm(table_rows):
                    # Skip blank rows, and postponed games
                    if (
                            row.find('th', {"scope": "row"}) is not None
                            and row.find('td', {"data-stat": "match_report"}).text != ""
                            ):

                        # Skip upcoming games
                        if 'stathead' in row.find('td', {"data-stat": "match_report"}).find('a')['href']:
                            continue

                        date = row.find('td', {"data-stat": "date"}).text
                        squad_h = row.find('td', {"data-stat": "squad_a"}).text
                        squad_a = row.find('td', {"data-stat": "squad_b"}).text

                        tables = pd.read_html(
                            "https://fbref.com" +
                            row.find('td', {"data-stat": "match_report"}).find('a')['href'])
                        time_start = time.time()

                        df = self.get_games_players(tables)
                        df.loc[:, 'date'] = date
                        df.loc[:, 'squad_h'] = squad_h
                        df.loc[:, 'squad_a'] = squad_a

                        if os.path.isfile(os.path.join(self.root, f'games_players.csv')):
                            df.to_csv(
                                os.path.join(self.root, 'games_players.csv'),
                                index=False, mode='a', header=False)
                        else:
                            df.to_csv(
                                os.path.join(self.root, f'games_players.csv'),
                                index=False)

                        df = self.get_games_keepers(tables)
                        df.loc[:, 'date'] = date
                        df.loc[:, 'squad_h'] = squad_h
                        df.loc[:, 'squad_a'] = squad_a

                        if os.path.isfile(os.path.join(self.root, f'games_keepers.csv')):
                            df.to_csv(
                                os.path.join(self.root, 'games_keepers.csv'),
                                index=False, mode='a', header=False)
                        else:
                            df.to_csv(
                                os.path.join(self.root, f'games_keepers.csv'),
                                index=False)

                        df = tables[17].copy()
                        df.columns = [' '.join(col).strip() if i > 6 else col[1] for i, col in enumerate(df.columns.values)]
                        df = df[~df.Player.isna()]
                        df.loc[:, 'date'] = date

                        if os.path.isfile(os.path.join(self.root, f'games_shots.csv')):
                            df.to_csv(
                                os.path.join(self.root, 'games_shots.csv'),
                                index=False, mode='a', header=False)
                        else:
                            df.to_csv(
                                os.path.join(self.root, f'games_shots.csv'),
                                index=False)

                        df = self.get_games_lineups(tables)
                        df.loc[:, 'date'] = date
                        df.loc[:, 'squad_h'] = squad_h
                        df.loc[:, 'squad_a'] = squad_a

                        if os.path.isfile(os.path.join(self.root, f'games_lineup.csv')):
                            df.to_csv(
                                os.path.join(self.root, 'games_lineup.csv'),
                                index=False, mode='a', header=False)
                        else:
                            df.to_csv(
                                os.path.join(self.root, f'games_lineup.csv'),
                                index=False)

                        # Wait to comply with scraping rules
                        time.sleep(3 - (time.time() - time_start))

        # Drop dupplicates in case I run the latest season scraper to update it.
        (
            pd.read_csv(os.path.join(self.root, 'games.csv'))
            .drop_duplicates()
            .to_csv(os.path.join(self.root, 'games.csv'), index=False))

        (
            pd.read_csv(os.path.join(self.root, 'games_players.csv'))
            .drop_duplicates()
            .to_csv(os.path.join(self.root, 'games_players.csv'), index=False))

        (
            pd.read_csv(os.path.join(self.root, 'games_keepers.csv'))
            .drop_duplicates()
            .to_csv(os.path.join(self.root, 'games_keepers.csv'), index=False))

        (
            pd.read_csv(os.path.join(self.root, 'games_shots.csv'))
            .drop_duplicates()
            .to_csv(os.path.join(self.root, 'games_shots.csv'), index=False))

        (
            pd.read_csv(os.path.join(self.root, 'games_lineup.csv'))
            .drop_duplicates()
            .to_csv(os.path.join(self.root, 'games_lineup.csv'), index=False))

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(message)s")
    logger: logging.Logger = logging.getLogger(__name__)

    with open('info.json') as stat:
        season_data = json.load(stat)

    fbref = FBRef(logger, season_data)
    # fbref.get_fixtures()

    # fbref.get_pl_season(True)

    fbref.get_pl_games()


from collections import defaultdict
import sys
input = sys.stdin.readline
from bisect import bisect

n, x = map(int, input().split())
arr = list(map(int, input().split()))

arr = [[v, i] for i, v in enumerate(arr)]
arr.sort()
arr_v = [arr[i][0] for i in range(n)]

def solve(arr, arr_v, n, x):
    d = defaultdict(list)
    for i in range(n):
        d[arr_v[i]].append(i)
    for i in range(n):
        for j in range(i+1, n):
            v = arr[i][0]+arr[j][0]
            if x-v in d:
                for k in d[x-v]:
                    if i < k < j:
                        print(arr[i][1]+1, arr[j][1]+1, arr[k][1]+1)
                        return
    print("IMPOSSIBLE")

solve(arr, arr_v, n, x)


import cv2
import os

class FaceExtractor:
    def __init__(self):
        # Load the input image
        self.input_image_path = 'ClassUpload/SwimTeam.jpeg'
        self.input_image = cv2.imread(self.input_image_path)
        if self.input_image is None:
            print('Error: could not load image')
            exit()

        # Load the face detection classifier
        self.face_cascade = cv2.CascadeClassifier('env/lib/python3.8/site-packages/cv2/data/haarcascade_frontalface_default.xml')

    def extract(self):
        # Detect faces in the image
        self.faces = self.face_cascade.detectMultiScale(self.input_image, scaleFactor=1.1, minNeighbors=5)

        # Create a directory to store the cropped face images
        self.output_dir = 'Classes'
        if not os.path.exists(self.output_dir):
            os.makedirs(self.output_dir)

        # Crop and save each face as a separate image
        for i, (x, y, w, h) in enumerate(self.faces):
            self.face_image = self.input_image[y:y+h, x:x+w]
            self.output_image_path = os.path.join(self.output_dir, f'face_{i}.jpg')
            cv2.imwrite(self.output_image_path, self.face_image)


from datetime import datetime
from pathlib import Path

from pandas import DataFrame

from src.repository import BarsRepo
from src.utils.candlestick_chart import save_chart

def save_snapshot_for_gap(gap, bars_df: DataFrame, bars_before: int, bars_after: int, path: str):
    gap_index = bars_df[bars_df['datetime_at'] == gap['datetime_at']].index.tolist()[0]
    df_snapshot = bars_df.iloc[max(gap_index - bars_before, 0):(gap_index + bars_after + 1)]
    save_chart(df_snapshot, path)

def save_chart_images_with_gaps(bars_repo: BarsRepo, bars_before: int, bars_after: int, min_gap_size: float):
    gaps_per_symbol = bars_repo.get_gaps_per_symbol(min_gap_size)
    for symbol, gaps in gaps_per_symbol.items():
        print(f'processing: {symbol}')
        folder_path = f'{bars_repo.chart_images_base_path}/{bars_repo.timeframe}/{symbol}'
        Path(folder_path).mkdir(parents=True, exist_ok=True)
        bars_df = bars_repo.get_market_hours_bars(symbol)
        for gap in gaps:
            path = f'{folder_path}/{int(datetime.fromisoformat(gap["datetime_at"]).timestamp())}_{bars_before}_{bars_after}'
            save_snapshot_for_gap(gap, bars_df, bars_before, bars_after, path)


import os
import numpy as np
import tensorflow as tf
from skimage.io import imread
from skimage.transform import resize
import math
import cv2

class Batch_Create(tf.keras.utils.Sequence):

    def __init__(self, x_set, y_set, batch_size):
        self.x, self.y = x_set, y_set
        self.batch_size = batch_size

    def __len__(self):
        return math.ceil(len(self.x) / self.batch_size)

    def __getitem__(self, idx):
        print(idx)

        batch_x = self.x[idx * self.batch_size:(idx + 1) *
                                               self.batch_size]
        batch_y = self.y[idx * self.batch_size:(idx + 1) *
                                               self.batch_size]

        return batch_x, batch_y

def data_load(input_path, mask_path):
    # npy array load 후 patch function에 넣기
    image_list = os.listdir(input_path)
    image_list = [file for file in image_list if file.startswith('input_')]
    label_list = os.listdir(mask_path)
    label_list = [file for file in label_list if file.startswith('mask_')]

    iteration_num = len(image_list)

    return image_list, label_list, iteration_num

def read_image_normal(data_list, path):
    data_Num = len(data_list)
    total_image_list = []

    for i in range(data_Num):
        image_array = cv2.imread(os.path.join(path, data_list[i]), cv2.IMREAD_COLOR)
        # image_array = image_array / 255.0 -> 일단 하지말자 fcn_model에서는 전이 학습할때 이걸 normalization 해주는거 같음.
        total_image_list.append(image_array)

    return total_image_list

def read_mask_normal(data_list, path):
    data_Num = len(data_list)
    total_mask_list = []

    for i in range(data_Num):
        image_array = cv2.imread(os.path.join(path, data_list[i]), cv2.IMREAD_GRAYSCALE)
        # image_array = image_array / 255.0  -> mask image는 preprocess할때 normalization 완료.
        total_mask_list.append(image_array)

    return total_mask_list

def create_patch(npy_image, npy_mask, patch_size, overlay):
    # input : (batch_size, h, w, 3), mask : (batch_size, h, w, 1)

    step = patch_size - overlay
    for row in range(0, npy_image.shape[1] - overlay, step):
        for col in range(0, npy_image.shape[2] - overlay, step):
            patch_image_height = patch_size if npy_image.shape[1] - row > patch_size else npy_image.shape[1] - row
            patch_image_width = patch_size if npy_image.shape[2] - col > patch_size else npy_image.shape[1] - col

            patch_image = npy_image[:, row : row + patch_image_height, col : col + patch_image_width]
            patch_mask = npy_mask[:, row : row + patch_image_height, col : col + patch_image_width]

            # zero padding
            if patch_image_height < patch_size or patch_image_width < patch_size:
                pad_height = patch_size - patch_image_height
                pad_width = patch_size - patch_image_width
                patch_image = np.pad(patch_image, ((0, 0), (0, pad_height), (0, pad_width), (0, 0)), 'constant')
                patch_mask = np.pad(patch_mask, ((0, 0), (0, pad_height), (0, pad_width), (0, 0)), 'constant')

            yield patch_image, patch_mask, row, col