#!/bin/env python
import asyncio
import json
import gzip
import re
import chardet
from sunday.core import Logger, Fetch, getException, getParser
from sunday.utils import currentTimestamp, mergeObj, image
from os import path, makedirs, listdir, mknod
from mitmproxy import options, http
from mitmproxy.tools import dump
from urllib.parse import urlparse, unquote
from pydash import omit, get
from sunday.tools.proxy.params import CMDINFO
from datetime import datetime
from shutil import copyfile

SundayException = getException()

logger = Logger('TOOLS PROXY').getLogger()

imageTypeList = ['png', 'gif', 'jpg', 'ico']

class BytesEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, bytes):
            return obj.decode()
        elif hasattr(obj, '__dict__') and type(obj.__dict__) is dict:
            return obj.__dict__
        return json.JSONEncoder.default(self, obj)

def grenPath(urlInfo):
    url = urlInfo.netloc + urlInfo.path
    if url[-1] == '/': url += 'index.html'
    return url

class BaseClass:
    def __init__(self, dataPath, collectList, closeList, proxyList, setting):
        self.dataPath = dataPath
        self.collectList = collectList
        self.closeList = closeList
        self.proxyList = proxyList
        self.setting = setting

    def getSetting(self, url, key, defval=None):
        if url not in self.setting: return None
        return self.setting[url].get(key, defval)

    def getParams(self, flow):
        params = mergeObj(
                dict(flow.request.query),
                dict(flow.request.urlencoded_form),
                { 'header_method': flow.request.method })
        try:
            if flow.request.text: params.update(flow.request.json())
        except Exception as e:
            pass
        return params

    def checkUrlInclude(self, url, urlarr):
        for urlitem in urlarr:
            if urlitem == url: return True
            try:
                if re.search(urlitem, url):
                    return True
            except Exception as e:
                logger.error(f'匹配{url}失败，请检查{urlitem}是否为正则表达式')
        return False

class Collect(BaseClass):
    def __init__(self, *args, **kwargs):
        super(Collect, self).__init__(*args, **kwargs)
        logger.info(f'采集接口 => {self.dataPath}')

    def parseData(self, urlInfo, flow):
        url = grenPath(urlInfo)
        logger.warning('处理链接%s' % url)
        filecwd = path.join(self.dataPath, url)
        # info/main/format
        nowtime = datetime.today().isoformat()
        filecwdInfo = path.join(filecwd, 'info')
        filecwdFormat = path.join(filecwd, 'format')
        filecwdMain = path.join(filecwd, 'main')
        filecwdCurr = path.join(filecwd, nowtime)
        filecwdCurrInfo = f"{filecwdCurr}.info"
        if not path.exists(filecwd): makedirs(filecwd)
        content = flow.response.content
        try:
            if url.split('.').pop() in imageTypeList:
                with open(filecwdCurr, 'wb+') as currf, open(filecwdMain, 'wb+') as mainf:
                    currf.write(content)
                    mainf.write(content)
            else:
                encodeCfg = chardet.detect(content)
                if encodeCfg['confidence'] >= 0.8:
                    content = content.decode(encodeCfg['encoding'])
                else:
                    content = content.decode('utf-8')
                with open(filecwdCurr, 'w+') as currf, open(filecwdMain, 'w+') as mainf:
                    currf.write(content)
                    mainf.write(content)
        except Exception as e:
            logger.error(f'{url}返回内容解析失败')
            with open(filecwdCurr, 'wb+') as currf, open(filecwdMain, 'wb+') as mainf:
                currf.write(content)
                mainf.write(content)
        params = self.getParams(flow)
        skeys = self.getSetting(url, 'superkey', None)
        if skeys is not None:
            # 根据入参做文件映射
            superkeyCfg = path.join(filecwd, 'config')
            key = '@@'.join([params[skey] for skey in skeys if type(params.get(skey)) == str])
            obj = None
            if not path.exists(superkeyCfg): open(superkeyCfg, 'a').close()
            with open(superkeyCfg, 'r+') as superf:
                text = superf.read()
                if text:
                    obj = json.loads(text)
                    if key not in obj:
                        obj[key] = nowtime
                    else:
                        obj = None
                else:
                    obj = { key: nowtime }
            if obj:
                with open(superkeyCfg, 'w+') as superf:
                    superf.write(json.dumps(obj, indent=4))
        info = {
                'url': url,
                'url_full': unquote(flow.request.url),
                'params': params,
                'request': flow.request.data.__dict__,
                'response': omit(flow.response.data.__dict__, ['content']),
                }
        with open(filecwdCurrInfo, 'w+') as infof:
            infof.write(json.dumps(info, indent=4, cls=BytesEncoder))
        if self.getSetting(url, 'format', None):
            copyfile(filecwdCurr, filecwdFormat)
        if not path.exists(filecwdInfo):
            copyfile(filecwdCurrInfo, filecwdInfo)
        logger.info('文件写入成功!')

    def response(self, flow):
        urlInfo = urlparse(flow.request.url)
        if urlInfo.netloc:
            url = grenPath(urlInfo)
            if len(self.collectList) == 0 or url in self.collectList:
                try:
                    self.parseData(urlInfo, flow)
                except Exception as e:
                    __import__('ipdb').set_trace()

class Playback(BaseClass):
    def __init__(self, *args, **kwargs):
        super(Playback, self).__init__(*args, **kwargs)
        logger.info(f'回放接口 => {self.dataPath}')
        self.fetch = Fetch()
        self.headerList = [
                'Location', 'location',
                'Content-Type', 'content-type',
                'Content-Encoding', 'content-encoding',
                'Cache-Control', 'cache-control']
        self.responseHandle = {}

    def getCollectPath(self, url):
        if len(self.collectList) == 0 or url in self.collectList: return url
        for coll in self.collectList:
            if url.find(coll) > -1 and url.find(coll) + len(coll) == len(url):
                return coll
        return False

    def response(self, flow):
        urlInfo = urlparse(flow.request.url)
        url = grenPath(urlInfo)
        if url not in self.responseHandle: return
        filepath = self.responseHandle[url]
        logger.info('本地: ' + filepath)
        with open(filepath, 'r') as ff:
            # content = bytes(ff.read(), 'utf-8')
            content = ff.read()
            if content:
                jsonpKey = self.getSetting(url, 'jsonp')
                if jsonpKey is not None:
                    params = self.getParams(flow)
                    content = re.sub(r'\b(.*?)\(', f'{params.get(jsonpKey, jsonpKey)}(', content, 1)
                flow.response.headers.update({'sunday_flag': 'proxy'})
                flow.response.content = bytes(content, 'utf-8')

    def request(self, flow):
        urlInfo = urlparse(flow.request.url)
        url = grenPath(urlInfo)
        # if 'ac.dun.163.com/v2/config/js' == url: __import__('ipdb').set_trace()
        collectPath = self.getCollectPath(url)
        # logger.warning('链接: ' + url)
        # if url in self.closeList or url.split('.').pop() in ['png', 'gif']:
        if not collectPath:
            logger.debug('网络: ' + url)
            return
        if self.checkUrlInclude(url, self.closeList):
            logger.error('拦截: ' + url)
            flow.response = http.Response.make(400, str.encode(''))
        elif url.split('.').pop() in imageTypeList:
            logger.info('图片: ' + url)
            mode = url.split('.').pop().lower()
            if mode == 'jpg': mode = 'jpeg'
            img_byte = getattr(image, f'grenImage{mode.title()}')(150)
            flow.response = http.Response.make(200, img_byte, {
                'Content-Type': f'image/{mode}'
                })
        else:
            filepath = ''
            filepath_tmp = path.join(self.dataPath, collectPath)
            if path.isdir(filepath_tmp):
                filepath_format = path.join(filepath_tmp, 'format')
                filepath_main = path.join(filepath_tmp, 'main')
                filepath_info = path.join(filepath_tmp, 'info')
            else:
                collectPathSplit = collectPath.split('/')
                temp = collectPathSplit[-1].split('.')
                temp[-1] = 'format.' + temp[-1]
                collectPathSplit[-1] = '.'.join(temp)
                filepath_format = path.join(self.dataPath, *collectPathSplit)
                filepath_main = filepath_tmp
                filepath_info = filepath_tmp + '.info'
            superkeyCfg = path.join(filepath_tmp, 'config')
            skeys = self.getSetting(url, 'superkey', None)
            if skeys is not None and path.exists(superkeyCfg):
                # 根据入参做文件映射
                params = self.getParams(flow)
                key = '@@'.join([params[skey] for skey in skeys if type(params.get(skey)) == str])
                with open(superkeyCfg, 'r+') as superf:
                    text = superf.read()
                    if text:
                        obj = json.loads(text)
                        if key in obj:
                            filepath = path.join(filepath_tmp, obj[key])
            if filepath:
                pass
            elif path.exists(filepath_format) and path.isfile(filepath_format):
                filepath = filepath_format
            elif path.exists(filepath_main) and path.isfile(filepath_main):
                filepath = filepath_main
            elif path.exists(filepath_info) and path.isdir(filepath_tmp):
                for name in listdir(filepath_tmp):
                    try:
                        datetime.fromisoformat(name)
                        filepath = path.join(filepath_tmp, name)
                        copyfile(filepath, filepath_main)
                        break
                    except Exception as e:
                        pass
            if url in self.proxyList:
                logger.warning('代理: ' + url)
                data = flow.request.data.content
                headers = dict(flow.request.headers)
                targeturl = flow.request.url
                res = getattr(self.fetch, flow.request.method.lower())(targeturl, data=data, headers=headers)
                flow.response = http.Response.make(res.status_code, res.content, { **dict(res.headers), "sunday_flag": "proxy" })
            elif filepath:
                if self.getSetting(url, 'response', None):
                    self.responseHandle[url] = filepath
                    return
                logger.info('本地: ' + filepath)
                info = {}
                content = ''
                content_type = 'str'
                try:
                    with open(filepath, 'r') as ff: content = ff.read()
                except Exception as e:
                    content_type = 'bin'
                    with open(filepath, 'rb') as ff: content = ff.read()
                if content:
                    with open(filepath_info, 'r') as fi: info = json.load(fi)
                    jsonpKey = self.getSetting(url, 'jsonp')
                    if jsonpKey is not None:
                        params = self.getParams(flow)
                        content = re.sub(r'\b(.*?)\(', f'{params.get(jsonpKey, jsonpKey)}(', content, 1)
                    fields = {key.lower(): val for key, val in get(info, 'response.headers.fields') if key in self.headerList}
                    status_code = get(info, 'response.status_code')
                    if 'content-type' in fields:
                        fields['content-type'] = re.sub(r'charset=[A-Za-z0-9-_]*\b', 'charset=UTF8', fields['content-type'])
                    if type(content) != bytes: content = bytes(content, 'utf-8')
                    flow.response = http.Response.make(status_code, content, {
                        "sunday_flag": "proxy",
                        "Access-Control-Allow-Origin": "*",
                        **fields })
            else:
                logger.debug('网络: ' + url)

class Proxy():
    def __init__(self, name='playback', host='0.0.0.0', port=7758, collectList=None, closeList=None, proxyList=None, dataPath=None, setting=None, isLog=False, **kwargs):
        self.name = name
        self.host = host
        self.port = int(port)
        self.collectList = collectList or []
        self.closeList = closeList or []
        self.proxyList = proxyList or []
        self.setting = setting or {}
        self.configFile = None
        self.dataPath = dataPath
        self.runpath = path.realpath(path.curdir)
        self.isLog = isLog

    def addCloseUrl(self, url):
        if type(url) == str: url = [url]
        if type(url) != list: return
        logger.debug('add close url %s' % url)
        self.closeList.extend(list(filter(lambda item: item not in self.closeList, url)))

    def addProxyUrl(self, url):
        if type(url) == str: url = [url]
        if type(url) != list: return
        logger.debug('add proxy url %s' % url)
        self.proxyList.extend(list(filter(lambda item: item not in self.proxyList, url)))

    def addCollectUrl(self, url):
        if type(url) == str: url = [url]
        if type(url) != list: return
        logger.debug('add collect url %s' % url)
        self.collectList.extend(list(filter(lambda item: item not in self.collectList, url)))

    def init(self):
        if self.configFile:
            try:
                configStr = self.configFile[0].read()
                configObj = json.loads(configStr)
                self.collectList = configObj.get('collectList', [])
                self.proxyList = configObj.get('proxyList', [])
                self.closeList = configObj.get('closeList', [])
                self.setting = configObj.get('setting', {})
            except Exception as e:
                raise SundayException(-1, '配置文件解析失败，请检查文件%s内容是否为JSON格式' % self.configFile.name)

    async def run(self):
        self.init()
        logger.info('捕获处理的链接有: %s' % self.collectList)
        logger.info('拦截处理的链接有: %s' % self.closeList)
        logger.info('代理处理的链接有: %s' % self.proxyList)
        logger.info('特定链接强化配置: %s' % self.setting)
        opts = options.Options(listen_host=self.host, listen_port=self.port)
        master = dump.DumpMaster(
            opts,
            with_termlog=self.isLog,
            with_dumper=False,
        )
        if self.name not in ['collect', 'playback']:
            raise SundayException(-1, '传入name值不正确，请检查')
        Addon = Collect if self.name == 'collect' else Playback
        master.addons.add(
            Addon(path.join(self.runpath, self.dataPath), self.collectList, self.closeList, self.proxyList, self.setting),
            )
        await master.run()

def runcmd():
    parser = getParser(**CMDINFO)
    handle = parser.parse_args(namespace=Proxy())
    asyncio.run(handle.run())

if __name__ == '__main__':
    runcmd()


from setuptools import setup, find_packages

with open('README.rst') as f:
    readme = f.read()

with open('LICENSE') as f:
    license = f.read()

setup(
    name='crispor_cli',
    version='0.1.0',
    description='Command line tool for crispr offtarget finding extracted from crispor website',
    long_description=readme,
    author='Kailash Yadav',
    author_email='kailash.yadav@elucidata.io',
    url='https://github.com/ElucidataInc/crispor-cli',
    license=license,
    packages=find_packages(exclude=('tests', 'docs'))
)


import os
import uuid
import json
import logging
import numpy as np
import pandas as pd
from datetime import datetime
from argparse import ArgumentParser
from sklearn.metrics import precision_recall_fscore_support
from sklearn.model_selection import KFold
from sklearn.model_selection import train_test_split
from toxicitydetector.preprocessing.csv_reader import DataLoader
from toxicitydetector.models.factory import get_model

class ClassificationTask:
    def __init__(self, args):
        self.args = args
        self.args.run_id = datetime.now().strftime("%Y%m%d%H%M%S")
        self.args.initial_timestamp = datetime.now().timestamp()
        self.dataset = DataLoader(self.args)
        self.output_path = args.output_file
        self.write_header = not self.args.no_output_headers
        # set random state
        np.random.seed(args.random_state)
        print("PARAMS: {}".format(self.args))

    def split_dataset(self):

        X = self.dataset.X_labeled.values
        y = self.dataset.y_labeled.values

        if self.args.predict:
            X_train, y_train = X, y
            X_test, y_test = self.dataset.X_test.values, None
        else:
            X_train, X_test, y_train, y_test = train_test_split(
                X, y, test_size=0.2,random_state=self.args.random_state)

        return X_train, X_test, y_train, y_test

    def run(self):

        self.dataset.load()

        X_train, X_test,  y_train, y_test = self.split_dataset()

        logging.info("Train data: {}".format(X_train.shape))
        logging.info("Test data: {}".format(X_test.shape))

        labels = self.dataset.y_cols
        results = None
        k_folds = self.args.kfolds
        scores = []
        best_model = None
        best_score = 0
        cv = KFold(k_folds, random_state=self.args.random_state)

        for k, fold in enumerate(cv.split(X_train, y_train)):
            logging.info('MODEL: {}'.format(self.args.model))
            logging.info('training fold {}'.format(k))
            train, valid = fold
            X_kfold, X_valid = X_train[train], X_train[valid]
            y_kfold, y_valid = y_train[train], y_train[valid]

            model = get_model(self)
            model.train(X_kfold, y_kfold)
            y_pred = model.predict(X_valid)

            preds = (y_pred > 0.5).astype(int) if self.args.predict_probs else y_pred
            score = precision_recall_fscore_support(y_valid, preds, average='weighted')
            score = score[2] #F1
            scores.append(score)
            print(f"CV {k} F1: {score}")

            if score > best_score:
                best_score = score
                best_model = model

            y_pred = pd.DataFrame(y_pred, columns=labels)
            y_pred = self.dataset.decode_features(y_pred, labels)
            y_valid = pd.DataFrame(y_valid, columns=labels)
            y_valid = self.dataset.decode_features(y_valid, labels)

            results_df = y_valid.merge(y_pred, left_index=True,right_index=True, suffixes=('', '_pred'))
            results_df['run_id'] = self.args.run_id
            results_df['timestamp'] = datetime.now().timestamp()
            results_df['model'] = model.args.model
            results_df['set'] = 'cv'
            results_df['kfold'] = k
            results_df['id'] = X_valid[:,0]
            results = results_df if results is None else results.append(results_df, ignore_index=True)

        # predict on tests set
        y_pred = best_model.predict(X_test)

        if self.args.predict:

            if len(self.dataset.y_cols) == 1:
                y_pred = np.expand_dims(y_pred, axis=1)

            for ix, col in enumerate(self.dataset.y_cols):
                self.dataset.X_test.loc[:,col] = y_pred[:, ix]

            cols = ['id']
            cols.extend(self.dataset.y_cols)
            results = self.dataset.X_test[cols]
            results = self.dataset.decode_features(results, labels)
            results.to_csv(self.output_path, index=False, header=self.write_header)

        else:
            preds = (y_pred > 0.5).astype(int) if self.args.predict_probs else y_pred
            score = precision_recall_fscore_support(y_test, preds, average='weighted')
            score = score[2] # f1
            scores = np.array(scores)
            print(f"CV F1: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))
            print(f"Test F1: %0.2f" % (score))

            y_pred = pd.DataFrame(y_pred, columns=labels)
            y_pred = self.dataset.decode_features(y_pred, labels)
            y_test = pd.DataFrame(y_test, columns=labels)
            y_test = self.dataset.decode_features(y_test, labels)

            results_df = y_test.merge(y_pred, left_index=True,right_index=True, suffixes=('', '_pred'))
            results_df['run_id'] = self.args.run_id
            results_df['timestamp'] = datetime.now().timestamp()
            results_df['model'] = model.args.model
            results_df['set'] = 'test'
            results_df['kfold'] = 0
            results_df['id'] = X_test[:, 0]
            results = results.append(results_df, ignore_index=True)
            write_header = not os.path.exists(self.output_path)

            # save results
            with open(self.output_path, 'a') as f:
                results.to_csv(path_or_buf=f, index=False, header= write_header)

        # save hyperparams
        self.args.final_timestamp = datetime.now().timestamp()
        filepath = os.path.splitext(self.output_path)[0] + '.json'
        with open(filepath, 'a') as f:
            config = json.dumps(self.args.__dict__)
            f.write(config +'\r')

if __name__ == '__main__':
    logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG)
    logging.info('initializing task...')
    parser = ArgumentParser()
    parser.add_argument('--train-path', type=lambda x:os.path.expanduser(x))
    parser.add_argument('--unlabeled-path', type=lambda x: os.path.expanduser(x))
    parser.add_argument('--test-path', type=lambda x: os.path.expanduser(x))
    parser.add_argument('--labels', type=lambda x: x.split(','))
    parser.add_argument('--field-sep', type=str, default=',')
    parser.add_argument('--text-field', type=str, default='text')
    parser.add_argument('--use-allfeats', action='store_true')
    parser.add_argument('--num-unlabeled', type=int, default=0)
    parser.add_argument('--kfolds', type=int, default=2)
    parser.add_argument('--epochs', type=int, default=2)
    parser.add_argument('--ngrams', type=int, default=1)
    parser.add_argument('--embeddings-size', type=int, default=300)
    parser.add_argument('--embeddings-path', type=lambda x: os.path.expanduser(x))
    parser.add_argument('--embeddings-trainable', action='store_true')
    parser.add_argument('--random-state', type=int, default=1)
    parser.add_argument('--predict', action='store_true')
    parser.add_argument('--predict-probs', action='store_true')
    parser.add_argument('--no-output-headers', action='store_true')
    parser.add_argument('--output-file', type=lambda x:os.path.expanduser(x))
    parser.add_argument('--models')
    parser.add_argument('--append-results', action='store_true')
    args = parser.parse_args()

    # clean previous results
    if not args.append_results:
        if os.path.exists(args.output_file):
            os.remove(args.output_file)

    for model in args.models.split(','):
        logging.info(f'running {model} model...')
        args.model = model
        task = ClassificationTask(args)
        task.run()
        logging.info(f'running {model} model...[OK]')

    logging.info('task finished...[ok]')


"""DDP inference script."""
import os
import time
import numpy as np
import hydra
import torch
import GPUtil
from pytorch_lightning import Trainer
from omegaconf import DictConfig, OmegaConf
from experiments import utils as eu
from models.flow_module import FlowModule

torch.set_float32_matmul_precision('high')
log = eu.get_pylogger(__name__)

class Sampler:

    def __init__(self, cfg: DictConfig):
        """Initialize sampler.

        Args:
            cfg: inference config.
        """
        ckpt_path = cfg.inference.ckpt_path
        ckpt_dir = os.path.dirname(ckpt_path)
        ckpt_cfg = OmegaConf.load(os.path.join(ckpt_dir, 'config.yaml'))

        # Set-up config.
        OmegaConf.set_struct(cfg, False)
        OmegaConf.set_struct(ckpt_cfg, False)
        cfg = OmegaConf.merge(cfg, ckpt_cfg)
        cfg.experiment.checkpointer.dirpath = './'

        self._cfg = cfg
        self._infer_cfg = cfg.inference
        self._samples_cfg = self._infer_cfg.samples
        self._rng = np.random.default_rng(self._infer_cfg.seed)

        # Set-up directories to write results to
        self._ckpt_name = '/'.join(ckpt_path.replace('.ckpt', '').split('/')[-3:])
        self._output_dir = os.path.join(
            self._infer_cfg.output_dir,
            self._ckpt_name,
            self._infer_cfg.name,
        )
        os.makedirs(self._output_dir, exist_ok=True)
        log.info(f'Saving results to {self._output_dir}')
        config_path = os.path.join(self._output_dir, 'config.yaml')
        with open(config_path, 'w') as f:
            OmegaConf.save(config=self._cfg, f=f)
        log.info(f'Saving inference config to {config_path}')

        # Read checkpoint and initialize module.
        self._flow_module = FlowModule.load_from_checkpoint(
            checkpoint_path=ckpt_path,
        )
        self._flow_module.eval()
        self._flow_module._infer_cfg = self._infer_cfg
        self._flow_module._samples_cfg = self._samples_cfg
        self._flow_module._output_dir = self._output_dir

    def run_sampling(self):
        devices = GPUtil.getAvailable(
            order='memory', limit = 8)[:self._infer_cfg.num_gpus]
        log.info(f"Using devices: {devices}")
        eval_dataset = eu.LengthDataset(self._samples_cfg)
        dataloader = torch.utils.data.DataLoader(
            eval_dataset, batch_size=1, shuffle=False, drop_last=False)
        trainer = Trainer(
            accelerator="gpu",
            strategy="ddp",
            devices=devices,
        )
        trainer.predict(self._flow_module, dataloaders=dataloader)

@hydra.main(version_base=None, config_path="../configs", config_name="inference")
def run(cfg: DictConfig) -> None:

    # Read model checkpoint.
    log.info(f'Starting inference with {cfg.inference.num_gpus} GPUs')
    start_time = time.time()
    sampler = Sampler(cfg)
    sampler.run_sampling()
    elapsed_time = time.time() - start_time
    log.info(f'Finished in {elapsed_time:.2f}s')

if __name__ == '__main__':
    run()


# -*- coding: utf-8 -*-
import scrapy
from time import sleep
from selenium import webdriver
from scrapy.selector import Selector
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.options import Options
import csv

class MinimalSpider(scrapy.Spider):
    name = 'minimal'
    allowed_domains = ['tokopedia.com']

    def start_requests(self):
        # open csv file
        with open('./csvfiles/produri.csv', newline='') as csvfile:
            record = csv.reader(csvfile, delimiter=',')
            for i in record:
                # [id, uri, helpfulreviewerscnt]
                yield scrapy.Request(i[0], callback=self.parse)

    def parse(self, response):
        user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
        options = webdriver.ChromeOptions()
        options.add_argument(f'user-agent={user_agent}')
        options.add_argument('--headless')
        self.driver = webdriver.Chrome(chrome_options=options,
                executable_path='/usr/bin/chromedriver')
        self.driver.get(response.request.url)

        # sleep for 10 seconds
        sleep(10)
        self.logger.info('Sleeping for 10 seconds')

        # extract source page
        selProdPage = Selector(text=self.driver.page_source)

        # Minimal beli
        minpurchase = selProdPage.xpath(
                '//div[contains(@class, "product-content-container")]/descendant::dd[contains(@class, "pull-left m-0 border-none")]/text()'
                ).extract()[1]
        minpurchase = minpurchase.strip()

        yield {
                'uri':response.request.url,
                'minpurchase':minpurchase
                }

        self.driver.quit()


# From Python
# It requires OpenCV installed for Python
import sys
import cv2
import os
from sys import platform
import argparse
import json

def create_pose_json(op, opWrapper, image):
    try:
        # Process Image
        # Flags
        parser = argparse.ArgumentParser()
        parser.add_argument("--image_path", default=image)
        # parser.add_argument("--image_path", default="../../../examples/media/COCO_val2014_000000000192.jpg")
        # parser.add_argument("--image_path", default="../../../examples/media/Danya.png", help="Process an image. Read all standard formats (jpg, png, bmp, etc.).")
        args = parser.parse_known_args()
        datum = op.Datum()
        imageToProcess = image  # cv2.imread(args[0].image_path) if using imagepath
        datum.cvInputData = imageToProcess
        opWrapper.emplaceAndPop([datum])

        poseModel = op.PoseModel.BODY_25
        #print(op.getPoseBodyPartMapping(poseModel))

        poseModel = {0: 'Nose', 1: 'Neck', 2: 'RShoulder', 3: 'RElbow', 4: 'RWrist', 5: 'LShoulder', 6: 'LElbow', 7: 'LWrist', 8: 'MidHip',
                     9: 'RHip', 10: 'RKnee', 11: 'RAnkle', 12: 'LHip', 13: 'LKnee', 14: 'LAnkle', 15: 'REye', 16: 'LEye', 17: 'REar',
                     18: 'LEar', 19: 'LBigToe', 20: 'LSmallToe', 21: 'LHeel', 22: 'RBigToe', 23: 'RSmallToe', 24: 'RHeel', 25: 'Background'}
        merged = {}
        for person in range(len(datum.poseKeypoints)):
            anchor_point_X = datum.poseKeypoints[person][1][0] #Neck
            anchor_point_Y = datum.poseKeypoints[person][1][1]
            persnum = "Person{}".format(person)
            parts = [{'bodypart': poseModel[bodypart], 'X': str(datum.poseKeypoints[person][bodypart][0] - anchor_point_X), 'Y': str(datum.poseKeypoints[person][bodypart][1] - anchor_point_Y),
                    'Confidence': str(datum.poseKeypoints[person][bodypart][2])} for bodypart in range(len(datum.poseKeypoints[person]))]
            '''lefthand = []
            for part in range(int((datum.handKeypoints[0].size)/3)):
                lefthand.append({'X' : str(datum.handKeypoints[0][part][0]), 'Y': str(datum.handKeypoints[0][part][1])})
            leftHands = ([{'LeftHandParts': {'X' : str(datum.handKeypoints[person][0][part][0]), 'Y': str(datum.handKeypoints[person][0][part][1])} for part in range(datum.handKeypoints[0].size)}])
            parts.append(leftHands)'''
           # parts.append({'RightHand': str(datum.handKeypoints[1])})
            merged[persnum] = parts
        res = json.dumps(merged,               sort_keys=False, indent=4, separators=(',', ': '))
        # Display Image
        #print("Body keypoints: \n" + str(datum.poseKeypoints))
        #cv2.imshow("OpenPose 1.5.1 - Tutorial Python API", datum.cvOutputData)
        #cv2.waitKey(0)
        return res
    except Exception as e:
        print(e)
        return -1


from selenium import webdriver
from time import sleep

driver = webdriver.Chrome(executable_path='F:\chromedriver.exe')
driver.maximize_window()

while True:
    list = []
    driver.get('https://www.tiktok.com/')
    scorll = driver.execute_script("window.scrollBy(0,document.body.scrollHeight)")
    get_id_link = driver.find_elements("xpath","//a[@class='tiktok-1lqhxf7-StyledAuthorAnchor emt6k1z1']")
    for id in get_id_link:
        id_link = id.get_attribute('href')
        if id_link not in list:
            list.append(id_link)
        print(id_link)
        #sleep(5)

    for i in list:
        print(i)
    print('__________________________')


#!/usr/bin/env python
# coding: utf-8

# In[1]:

import pandas as pd
import csv
import json
import time
import os
from pymongo import MongoClient
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt

# In[2]:

pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)

# In[3]:

spotify_csv = pd.read_csv('Spotify 2010 - 2019 Top 100.csv', encoding = 'utf-8')
print('Last modification date:', time.ctime(os.path.getctime('Spotify 2010 - 2019 Top 100.csv')))
spotify_csv.info()

# In[4]:

display(spotify_csv.iloc[1:11])

# In[5]:

display(spotify_csv[['title','duration']])

# In[6]:

spotify_csv.duration.describe()

# In[7]:

spotify_csv.sort_values(['beats per minute'], ascending = 0)

# In[8]:

spotify_csv.loc[(spotify_csv['top year'] == 2019)]

# In[9]:

spotify_csv.loc[(spotify_csv['popularity'] < 50)]

# In[10]:

songs_to_dance = spotify_csv.title.loc[spotify_csv['danceability rate'] >= 70]
songs_to_dance.count()

# In[11]:

spotify_csv.loc[(spotify_csv['acoustic rate'] == spotify_csv['acoustic rate'].max())]

# In[12]:

spotify_csv.loc[(spotify_csv['acoustic rate'] == spotify_csv['acoustic rate'].min())]

# In[13]:

spotify_csv[(spotify_csv['genre'].str.contains('hip hop') | (spotify_csv['genre'].str.contains('pop'))
    & spotify_csv['artist type'].str.contains('Solo'))]

# In[14]:

spotify_csv.groupby(['artist type']).mean()

# In[15]:

spotify_csv.sort_values(by = ['date added to list'], ascending = 0)

# In[16]:

spotify_csv.groupby(['genre']).sum()

# In[17]:

spotify_csv.groupby(['top year']).count()

# In[18]:

spotify_csv['beats per minute'].hist()

# In[19]:

def search_songs_by_duration_range(min_duration, max_duration):
    searched_songs = spotify_csv.loc[(spotify_csv.duration >= min_duration) & (spotify_csv.duration <= max_duration)]
    sorted_songs = searched_songs.sort_values(by = ['duration'], ascending = 0)
    display(sorted_songs)

search_songs_by_duration_range(100, 220)

# In[20]:

def search_songs_by_genre(genre_to_find):
    display(spotify_csv.loc[spotify_csv['genre'].str.contains(genre_to_find)])

search_songs_by_genre('dance pop')

# In[21]:

def search_songs_by_title_keyword(keyword):
    display(spotify_csv.loc[(spotify_csv['title'].str.contains(keyword))])

search_songs_by_title_keyword('You')

# In[22]:

def convert_csv_to_json(csv_file_path, json_file_path):
    json_array = []
    with open(csv_file_path, encoding = 'utf-8') as csv_file:
        csv_dict_reader = csv.DictReader(csv_file)
        for row in csv_dict_reader:
            json_array.append(row)

    with open(json_file_path, 'w', encoding = 'utf-8') as json_file:
        json_text = json.dumps(json_array, indent = 4)
        json_file.write(json_text)

csv_file_path = r'Spotify 2010 - 2019 Top 100.csv'
json_file_path = r'SpotifyTop100Songs.json'

convert_csv_to_json(csv_file_path, json_file_path)

# In[23]:

spotify_json = pd.read_json('SpotifyTop100Songs.json', encoding = 'utf-8')

# In[24]:

mongo_client = MongoClient('mongodb://localhost:27017')
spotify_database = mongo_client['SpotifyTop100Songs']

# In[25]:

songs_collection = spotify_database.Top100SpotifySongs
songs_dict = spotify_json.to_dict('records')

# In[26]:

songs_collection.insert_many(songs_dict)

# In[27]:

all_docs_number = songs_collection.count_documents({})
print('The total number of documents in Top100SpotifySongs collection:', all_docs_number)

# In[28]:

first_100_songs = songs_collection.find({}).limit(100)
for song in first_100_songs:
    print(song)

# In[29]:

edm_songs = songs_collection.find({'genre':'edm'})
for edm_song in edm_songs:
    display(edm_song)

# In[30]:

loud_songs = songs_collection.find({'decibel':{'$lt':-5}, 'beats per minute':{'$gt': 100}}).sort('beats per minute', -1)
for loud_song in loud_songs:
    display(loud_song)

# In[31]:

year2016_or_more_songs = songs_collection.find({'year released':{'$gte':2016}}).sort('year released')
for year2016_or_more_song in year2016_or_more_songs:
    display(year2016_or_more_song)

# In[32]:

group_songs = songs_collection.find({'artist type':{'$ne':'Solo'}})
for group_song in group_songs:
    display(group_song)

# In[33]:

rihanna_songs = songs_collection.find({'artist':{'$in':['Rihanna']}})
for rihanna_song in rihanna_songs:
    display(rihanna_song)

# In[34]:

no_pop_songs = songs_collection.find({'genre':{'$nin':['dance pop', 'pop soul','pop rap', 'art pop', 'pop', 'barbadian pop',
    'acoustic pop', 'belgian pop', 'baroque pop', 'indie pop', 'australian pop','canadian pop', 'folk-pop', 'austrian pop',
    'irish pop', 'chill pop', 'indie pop rap', 'electropop']}})
for no_pop_song in no_pop_songs:
    print(no_pop_song)

# In[35]:

solo_and_duo_songs = songs_collection.find({'$nor':[{'artist type': 'Band/Group'}, {'artist type': 'Trio'}]})
for solo_and_duo_song in solo_and_duo_songs:
    print(solo_and_duo_song)

# In[36]:

year_2018_and_2019_songs = songs_collection.find({'$or':[{'top year': 2018}, {'top year': 2019}]})
for year_2018_and_2019_song in year_2018_and_2019_songs:
    print(year_2018_and_2019_song)

# In[37]:

query = {
    'decibel': { '$gte': -5 },
    'popularity': { '$gt': 60 },
    'duration': { '$lt': 200 },
}

query_list = list(songs_collection.find(query))
decibel = [x['decibel'] for x in query_list]
popularity = [x['popularity'] for x in query_list]
duration = [x['duration'] for x in query_list]

plt.clf()
fig = plt.figure()

ax = fig.add_subplot(111, projection = '3d')
ax.scatter(decibel, popularity, duration)

ax.set_xlabel('Decibel')
ax.set_ylabel('Popularity')
ax.set_zlabel('Duration')

plt.show()


import pygame
import sys
import time
import random
from pygame.locals import *

redColour = pygame.Color(255, 0, 0)
blackColour = pygame.Color(0, 0, 0)
whiteColour = pygame.Color(255, 255, 255)
greyColour = pygame.Color(150, 150, 150)

def gameOver(playSurface, score):
    gameOverFont = pygame.font.SysFont("arial.ttf", 54)
    gameOverSurf = gameOverFont.render("Game Over!", True, greyColour)
    gameOverRect = gameOverSurf.get_rect()
    gameOverRect.midtop = (300, 10)
    playSurface.blit(gameOverSurf, gameOverRect)
    scoreFont = pygame.font.SysFont("arial.ttf", 54)
    scoreSurf = scoreFont.render("Score:" + str(score), True, greyColour)
    scoreRect = scoreSurf.get_rect()
    scoreRect.midtop = (300, 50)
    playSurface.blit(scoreSurf, scoreRect)
    pygame.display.flip()
    time.sleep(5)
    pygame.quit()
    sys.exit()

def main():
    pygame.init()
    fpsClock = pygame.time.Clock()
    playSurface = pygame.display.set_mode((600, 460))
    pygame.display.set_caption("Snake Game")
    snakePosition = [100, 100]
    snakeSegments = [[100, 100]]
    raspberryPosition = [300, 300]
    raspberrySpawned = 1
    direction = "right"
    changeDirection = direction
    score = 0
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == KEYDOWN:
                if event.key == K_RIGHT or event.key == ord("d"):
                    changeDirection = "right"
                if event.key == K_LEFT or event.key == ord("a"):
                    changeDirection = "left"
                if event.key == K_UP or event.key == ord("w"):
                    changeDirection = "up"
                if event.key == K_DOWN or event.key == ord("s"):
                    changeDirection = "down"
                if event.key == K_ESCAPE:
                    pygame.event.post(pygame.event.Event(QUIT))

        if changeDirection == "right" and not direction == "left":
            direction = changeDirection
        if changeDirection == "left" and not direction == "right":
            direction = changeDirection
        if changeDirection == "up" and not direction == "down":
            direction = changeDirection
        if changeDirection == "down" and not direction == "up":
            direction = changeDirection

        if direction == "right":
            snakePosition[0] += 20
        if direction == "left":
            snakePosition[0] -= 20
        if direction == "up":
            snakePosition[1] -= 20
        if direction == "down":
            snakePosition[1] += 20

        snakeSegments.insert(0, list(snakePosition))

        if (
            snakePosition[0] == raspberryPosition[0]
            and snakePosition[1] == raspberryPosition[1]
        ):
            raspberrySpawned = 0
        else:
            snakeSegments.pop()

        if raspberrySpawned == 0:
            x = random.randrange(1, 30)
            y = random.randrange(1, 23)
            raspberryPosition = [int(x * 20), int(y * 20)]
            raspberrySpawned = 1
            score += 1

        playSurface.fill(blackColour)
        for position in snakeSegments:
            pygame.draw.rect(
                playSurface, whiteColour, Rect(position[0], position[1], 20, 20)
            )
            pygame.draw.rect(
                playSurface,
                redColour,
                Rect(raspberryPosition[0], raspberryPosition[1], 20, 20),
            )

        pygame.display.flip()

        if snakePosition[0] > 600 or snakePosition[0] < 0:
            gameOver(playSurface, score)
            if snakePosition[1] > 460 or snakePosition[1] < 0:
                gameOver(playSurface, score)
        for snakeBody in snakeSegments[1:]:
            if snakePosition[0] == snakeBody[0] and snakePosition[1] == snakeBody[1]:
                gameOver(playSurface, score)

        fpsClock.tick(5)

if __name__ == "__main__":
    main()


#Importing libraries
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns

#Importing the dataset
dataset = pd.ExcelFile('C:/Users/USER/Hash-Analytic-Python-Analytics-Problem-case-study-1 (1).xlsx')
existing_employees = dataset.parse('Existing employees')

# To get the correlation betweem attributes
corr_matrix = existing_employees.corr()
plt.figure(figsize=(10,10))
sns.heatmap(corr_matrix,annot=True)
plt.savefig('Existing Employees Correlation.png')
plt.show()

#Visualising some features
features=['number_project','time_spend_company','Work_accident','promotion_last_5years','dept','salary']
subplot = plt.subplots(figsize=(20,15))
for i,j in enumerate(features):
    plt.subplot(4,2,i+1)
    plt.subplots_adjust(hspace=0.5)
    sns.countplot(x=j, data=existing_employees)
    plt.xticks(rotation=90)
    plt.title('Existing Employees')
    plt.savefig('Existing Employees')


import random
import time
from datetime import datetime

import numpy as np
import torchvision
import torchvision.transforms as transforms
from functions.algorithms.manifool import manifool
from models import *

#Parameter
num_trials = 5
maxIt = 100
mode = 'affine'
step_sizes = np.logspace(-2,np.log10(1),20)
rng_seed = 13
gamma = 0
torch.set_num_threads(8)

mean = (0.4914, 0.4822, 0.4465)
std = (0.2023, 0.1994, 0.2010)
transform = transforms.Compose([transforms.ToTensor(),
                                transforms.Normalize(mean = mean,
                                                     std = std)
                                ])

#Getting the network and the dataset
pretrained = torch.load('./models/cifar_net.t7')
net = pretrained['net']
net.train(mode=False)

dataset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True,
            transform = transform)
random.seed(rng_seed)
im_ind = random.sample(range(len(dataset)),num_trials)

num_of_fail = 0
total_mf = 0
successful_dur_manifool = 0
t = time.time()
geo_scores = []
for i,k in enumerate(im_ind):

    im = dataset.__getitem__(k)[0]

    t0 = time.time()
    out = manifool(im, net, mode,
                   maxIter=maxIt,
                   cuda_on=True,
                   step_sizes = step_sizes,
                   gamma = gamma,
                   numerical=True,
                   verbose = False)

    geo_sc = out['geo_dist']
    tar = out['target']
    k_org = out['org_label']

    t1 = time.time()

    if (k_org != tar):
        geo_scores.append(geo_sc)
        total_mf += geo_sc
        successful_dur_manifool += t1 - t0

    num_of_fail += (k_org == tar)

    print('Iteration {}, Image {}.'
    ' Current Avg. score: {}'.format(i,k,total_mf/(i-num_of_fail+1)))

elapsed = time.time()-t

fail_percent = num_of_fail/num_trials*100
avg_mf = total_mf/(num_trials - num_of_fail)
avg_succ_dur = successful_dur_manifool/(num_trials-num_of_fail)

file_name = 'CIFAR10_geo_scores_var_'+mode
np.save(file_name, geo_scores)

info_str = ("\n"+"-"*13+"Manifool CIFAR10 Demo"+"-"*13+"\nTransformation: {}\n"
            "Number of images: {}\nGamma: {}\nMaximum number of iterations: {}".format(
            mode, num_trials, gamma, maxIt))

log_str = ("\n"+"-"*20+"Results"+"-"*21+"\nNet not fooled for {}%  of images\nTime elapsed for whole "
          "loop: {:.2f} seconds\nAverage duration for an image: {:.4f} seconds\n"
          "Average duration for successul computations: {:.4f} seconds\n"
          "Average Score(Calculated Directly): {}\n\n".format(
          fail_percent, elapsed, elapsed/num_trials, avg_succ_dur, avg_mf))

print(info_str)
print(log_str)

text_file = open('CIFAR10_wholeDemo_var_log.txt','a')
text_file.write(str(datetime.now()))
text_file.write(info_str)
text_file.write(log_str)


import pytest
from pathlib import Path
import numpy as np
from numpy.testing import assert_allclose
from blendtorch import btt

BLENDDIR = Path(__file__).parent / "blender"

@pytest.mark.background
def test_projection():
    launch_args = dict(
        scene=BLENDDIR / "cam.blend",
        script=BLENDDIR / "cam.blend.py",
        num_instances=1,
        named_sockets=["DATA"],
        background=True,
    )

    ortho_xy_expected = np.array(
        [
            [480.0, 80],
            [480.0, 80],
            [480.0, 400],
            [480.0, 400],
            [160.0, 80],
            [160.0, 80],
            [160.0, 400],
            [160.0, 400],
        ]
    )

    proj_xy_expected = np.array(
        [
            [468.148, 91.851],
            [431.111, 128.888],
            [468.148, 388.148],
            [431.111, 351.111],
            [171.851, 91.851],
            [208.888, 128.888],
            [171.851, 388.148],
            [208.888, 351.111],
        ]
    )

    z_expected = np.array([6.0, 8, 6, 8, 6, 8, 6, 8])

    with btt.BlenderLauncher(**launch_args) as bl:
        addr = bl.launch_info.addresses["DATA"]
        ds = btt.RemoteIterableDataset(addr, max_items=2)
        item = next(iter(ds))
        assert_allclose(item["ortho_xy"], ortho_xy_expected, atol=1e-2)
        assert_allclose(item["ortho_z"], z_expected, atol=1e-2)
        assert_allclose(item["proj_xy"], proj_xy_expected, atol=1e-2)
        assert_allclose(item["proj_z"], z_expected, atol=1e-2)


import click
from lirc.exceptions import LircdCommandFailureError

from stb.remote import Remote
from stb.utils import get_config_file

@click.command(short_help="Send IR signals")
@click.argument("key", required=True)
@click.option("-r", "--remote", default=None, help="The remote to press keys on.")
def press(key, remote):
    """
    Simulate a button press by sending an IR signal
    """
    if not remote:
        remote = get_config_file().get("lirc.remote")

    try:
        Remote(remote).press(key)
        click.secho(f"Emitted {key} successfully", fg="green")
    except LircdCommandFailureError as error:
        click.secho(f"Error while trying to transmit {key}: ", fg="red")
        print(error)


"""Useful mixins for models."""
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import get_language

from hvad.models import NoTranslation, TranslationManager

class HvadPublishedManager(TranslationManager):
    """
    Returns all objects, which are published and in the currently
    active language if check_language is True (default).

    :param request: A Request instance.
    :param check_language: Option to disable language filtering.

    """
    def published(self, request, check_language=True):
        kwargs = {'translations__is_published': True}
        if check_language:
            language = getattr(request, 'LANGUAGE_CODE', get_language())
            if not language:
                self.model.objects.none()
            kwargs.update({'translations__language_code': language})
        return self.get_queryset().filter(**kwargs)

@python_2_unicode_compatible
class TranslationModelMixin(object):
    """Mixin to provide custom django-hvad overrides."""
    def __str__(self):
        return self.translation_getter('title')

    def check_for_result(self, language, translation, result, name):
        if not result:
            try:
                translation = self.translations.get(language_code=language)
            except ObjectDoesNotExist:
                pass
            else:  # pragma: nocover
                result = getattr(translation, name, '')
        return translation, result

    def translation_getter(self, name):
        """
        Custom translation getter.

        1. Try the current language
        2. Try base language (e.g. 'en' instead of 'en-gb')
        3. Try default sys language
        4. Use any translation

        """
        stuff = self.safe_translation_getter(name, NoTranslation)
        if stuff is not NoTranslation:
            return stuff

        translation = None
        result = None

        # Check for the current language
        translation, result = self.check_for_result(
            get_language(), translation, result, name)

        # Check for the current main language
        translation, result = self.check_for_result(
            get_language()[:2], translation, result, name)

        # Check for the default language
        translation, result = self.check_for_result(
            settings.LANGUAGE_CODE, translation, result, name)

        if not result:
            # Check for any available language
            for trans in self.translations.all():  # pragma: nocover
                translation = trans
                result = getattr(translation, name, '')
                if result:
                    break

        setattr(self, self._meta.translations_cache, translation)
        return result


"""
Originally: https://github.com/bobloy/Fox-V3/blob/master/hangman/hangman.py (Thanks mate!)
Heavily altered to fit my needs
"""

import discord
from discord.ext import commands

import asyncio
from collections import defaultdict
from random import randint
from typing import Union

class Hangman(commands.Cog):
    """Lets anyone play a game of hangman with custom phrases"""

    navigate = "🔼🔽"
    letters = "🇦🇧🇨🇩🇪🇫🇬🇭🇮🇯🇰🇱🇲🇳🇴🇵🇶🇷🇸🇹🇺🇻🇼🇽🇾🇿"

    def __init__(self, bot):
        super().__init__()
        self.bot = bot

        self.the_data = defaultdict(
            lambda: {
                "running": False,
                "hangman": 0,
                "guesses": [],
                "trackmessage": False,
                "answer": "",
            }
        )
        self.answer_path = "/app/bot/cogs/hangman/hanganswers.txt"

        self.winbool = defaultdict(lambda: False)

        self.hanglist = {}

    async def red_delete_data_for_user(self, **kwargs):
        """Nothing to delete"""
        return

    async def _update_hanglist(self):
        for guild in self.bot.guilds:
            self.hanglist[guild] = (
                """>
                   \\_________
                    |/
                    |
                    |
                    |
                    |
                    |
                    |\\___
                    """,
                """>
                   \\_________
                    |/   |
                    |
                    |
                    |
                    |
                    |
                    |\\___
                    H""",
                """>
                   \\_________
                    |/   |
                    |   """
                + "😁"
                + """
                    |
                    |
                    |
                    |
                    |\\___
                    HA""",
                """>
                   \\________
                    |/   |
                    |   """
                + "🙄"
                + """
                    |    |
                    |    |
                    |
                    |
                    |\\___
                    HAN""",
                """>
                   \\_________
                    |/   |
                    |   """
                + "😬"
                + """
                    |   /|
                    |     |
                    |
                    |
                    |\\___
                    HANG""",
                """>
                   \\_________
                    |/   |
                    |   """
                + "😔"
                + """
                    |   /|\\
                    |     |
                    |
                    |
                    |\\___
                    HANGM""",
                """>
                   \\________
                    |/   |
                    |   """
                + "😣"
                + """
                    |   /|\\
                    |     |
                    |   /
                    |
                    |\\___
                    HANGMA""",
                """>
                   \\________
                    |/   |
                    |   """
                + "💀"
                + """
                    |   /|\\
                    |     |
                    |   / \\
                    |
                    |\\___
                    HANGMAN""",
            )

    @commands.command(aliases=["hang"])
    async def hangman(self, ctx, guess: str = None):
        """Play a game of hangman against the bot!"""
        if guess is None:
            if self.the_data[ctx.guild]["running"]:
                await ctx.send(
                    "Game of hangman is already running!\nEnter your guess!"
                )
                await self._printgame(ctx.channel)
            else:
                await ctx.send("Starting a game of hangman!")
                self._startgame(ctx.guild)
                await self._printgame(ctx.channel)
        elif not self.the_data[ctx.guild]["running"]:
            await ctx.send(
                "Game of hangman is not yet running!\nStarting a game of hangman!"
            )
            self._startgame(ctx.guild)
            await self._printgame(ctx.channel)
        else:
            await ctx.send("Guess by reacting to the message")

    def _startgame(self, guild):
        """Starts a new game of hangman"""
        self.the_data[guild]["answer"] = self._getphrase().upper()
        self.the_data[guild]["hangman"] = 0
        self.the_data[guild]["guesses"] = []
        self.winbool[guild] = False
        self.the_data[guild]["running"] = True
        self.the_data[guild]["trackmessage"] = False

    def _stopgame(self, guild):
        """Stops the game in current state"""
        self.the_data[guild]["running"] = False
        self.the_data[guild]["trackmessage"] = False

    async def _checkdone(self, channel):
        if self.winbool[channel.guild]:
            await channel.send("You Win!")
            self._stopgame(channel.guild)
        elif self.the_data[channel.guild]["hangman"] >= 7:
            await channel.send(
                "You Lose!\nThe Answer was: **" + self.the_data[channel.guild]["answer"] + "**"
            )

            self._stopgame(channel.guild)

    def _getphrase(self):
        """Get a new phrase for the game and returns it"""

        with open(self.answer_path, "r") as phrasefile:
            phrases = phrasefile.readlines()

        outphrase = ""
        while outphrase == "":
            outphrase = phrases[randint(0, len(phrases) - 1)].partition(" (")[0]
        return outphrase

    def _hideanswer(self, guild):
        """Returns the obscured answer"""
        out_str = ""

        self.winbool[guild] = True
        for i in self.the_data[guild]["answer"]:
            if i in [" ", "-"]:
                out_str += i * 2
            elif i in self.the_data[guild]["guesses"] or i not in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
                out_str += "__" + i + "__ "
            else:
                out_str += "**\\_** "
                self.winbool[guild] = False

        return out_str

    def _guesslist(self, guild):
        """Returns the current letter list"""
        out_str = "".join(str(i) + "," for i in self.the_data[guild]["guesses"])
        out_str = out_str[:-1]

        return out_str

    async def _guessletter(self, guess, message):
        """Checks the guess on a letter and prints game if acceptable guess"""
        channel = message.channel
        if guess.upper() not in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" or len(guess) != 1:
            await channel.send("Invalid guess. Only A-Z is accepted")
            return

        if guess.upper() in self.the_data[channel.guild]["guesses"]:
            await channel.send("Already guessed that! Try again")
            return
        if guess.upper() not in self.the_data[channel.guild]["answer"]:
            self.the_data[channel.guild]["hangman"] += 1

        self.the_data[channel.guild]["guesses"].append(guess.upper())

        await self._reprintgame(message)

    @commands.Cog.listener("on_reaction_add")
    async def on_react(self, reaction, user: Union[discord.User, discord.Member]):
        """Thanks to flapjack reactpoll for guidelines
        https://github.com/flapjax/FlapJack-Cogs/blob/master/reactpoll/reactpoll.py"""
        guild: discord.Guild = getattr(user, "guild", None)
        if guild is None:
            return

        if reaction.message.id != self.the_data[guild]["trackmessage"]:
            return

        if user.bot:
            return  # Don't react to bot reactions

        message = reaction.message
        emoji = reaction.emoji

        if str(emoji) in self.letters:
            letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[self.letters.index(str(emoji))]
            await self._guessletter(letter, message)
            await message.remove_reaction(emoji, user)
            await asyncio.sleep(1)
            await message.remove_reaction(emoji, self.bot.user)

        if str(emoji) in self.navigate:
            if str(emoji) == self.navigate[0]:
                await self._reactmessage_am(message)

            if str(emoji) == self.navigate[-1]:
                await self._reactmessage_nz(message)

    async def _try_clear_reactions(self, message):
        try:
            await message.clear_reactions()
        except discord.Forbidden:
            pass

    async def _reactmessage_menu(self, message):
        """React with menu options"""
        await self._try_clear_reactions(message)

        await message.add_reaction(self.navigate[0])
        await message.add_reaction(self.navigate[-1])

    async def _reactmessage_am(self, message):
        await self._try_clear_reactions(message)

        for x in range(len(self.letters)):
            if x in [
                i for i, b in enumerate("ABCDEFGHIJKLM") if b not in self._guesslist(message.guild)
            ]:
                await message.add_reaction(self.letters[x])

        await message.add_reaction(self.navigate[-1])

    async def _reactmessage_nz(self, message):
        await self._try_clear_reactions(message)

        for x in range(len(self.letters)):
            if x in [
                i for i, b in enumerate("NOPQRSTUVWXYZ") if b not in self._guesslist(message.guild)
            ]:
                await message.add_reaction(self.letters[x + 13])

        await message.add_reaction(self.navigate[0])

    async def _make_say(self, guild):
        c_say = "Guess this: " + str(self._hideanswer(guild)) + "\n"
        c_say += "Used Letters: " + str(self._guesslist(guild)) + "\n"
        c_say += self.hanglist[guild][self.the_data[guild]["hangman"]] + "\n"
        c_say += "React with {} - {} to guess".format(self.letters[0], self.letters[-1])

        return c_say

    async def _reprintgame(self, message):
        if message.guild not in self.hanglist:
            await self._update_hanglist()

        c_say = await self._make_say(message.guild)

        await message.edit(content=c_say)
        self.the_data[message.guild]["trackmessage"] = message.id

        await self._checkdone(message.channel)

    async def _printgame(self, channel):
        """Print the current state of game"""
        if channel.guild not in self.hanglist:
            await self._update_hanglist()

        c_say = await self._make_say(channel.guild)

        message = await channel.send(c_say)

        self.the_data[channel.guild]["trackmessage"] = message.id

        await self._reactmessage_menu(message)
        await self._checkdone(channel)


import tkinter as tk
from tkinter import ttk
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from tkinter import scrolledtext
import pandas as pd
from src.main import diagnose
import time

def processData(event=None):
    if finished:
        return
    beforeStart.after(0, beforeStart.destroy())
    userInput = e1.get()
    chat.insert(END, '(You):\n', '(You)')
    chat.insert(END, userInput, 'yourword')
    chat.insert(END, '\n')
    chat.see(tk.END)
    checkingSymptoms()
    e1.delete(0, END)

def AISolution():
    global finished
    finished = True
    result = diagnose(record)
    chat.insert(END, 'Doc:\n', 'Doc')
    chat.insert(END, "Ok. It seems you've got " + str(result), 'Docword')
    chat.insert(END, '\n')
    chat.see(tk.END)
    return

def checkingSymptoms():
    if finished:
        return
    global loc
    for i in range(len(record)):
        if record[i] == -1:
            chat.insert(END, 'Doc:\n', 'Doc')
            chat.insert(END, "Got it, did you feel " + symptoms[i] + " recently?", 'Docword')
            chat.insert(END, '\n')
            chat.see(tk.END)
            YesButton = ttk.Button(gui, text="Yes I have that feeling", bootstyle=SUCCESS, command=makeTrue)
            YesButton.place(x=100, y=415)
            NoButton = ttk.Button(gui, text="No, I don't have that feeling", bootstyle=FLAT, command=makeFalse)
            NoButton.place(x=250, y=415)
            loc = i
            return
    AISolution()

def makeTrue():
    if finished:
        return
    chat.insert(END, '(You):\n', '(You)')
    chat.insert(END, "Yes I have that feeling", 'yourword')
    chat.insert(END, '\n')
    chat.see(tk.END)
    record[loc] = 1
    checkingSymptoms()
def makeFalse():
    if finished:
        return
    chat.insert(END, '(You):\n', '(You)')
    chat.insert(END, "No, I don't have that feeling", 'yourword')
    chat.insert(END, '\n')
    chat.see(tk.END)
    record[loc] = 0
    checkingSymptoms()

symptoms = ['arm pain', 'back pain', 'leg pain', 'ankle pain', 'inner thigh pain', 'back thigh pain', 'shoulder pain', 'tendon pain', 'swelling','headache', 'weakness', 'stiffness', 'difficulty moving/straightening ','nausea', 'bruising ', 'tenderness', 'numbness','difficulty putting weight on', 'dizziness or blurry vision', 'spasms','elbow pain', 'difficulty balancing ', 'light and sound irritation',' Trouble controlling bowels or bladder', 'injury']
record = []
cur = 0
loc = 0
finished = False
for _ in symptoms:
    record.append(-1)
print(symptoms)
print(record)
print(len(symptoms))
print(len(record))
gui = tk.Tk()
gui.title('HealAI')
gui.geometry("500x500")
style = ttk.Style("minty")

e1 = tk.Entry(gui, width=50)
e1.insert(0, "")

e1.grid(row=0, column=1)
e1.place(x=115, y=455)

quitButton = ttk.Button(gui, text="End Chat", bootstyle=(INFO, OUTLINE), command=gui.quit)
quitButton.place(x=25, y=450)

sentButton = ttk.Button(gui, text="|>", bootstyle=(SUCCESS, OUTLINE), command=processData)
sentButton.place(x=440, y=450)

chat = scrolledtext.ScrolledText(gui, height=24, width=70)
chat.place(x=0, y=0)
chat.tag_config('(You)', foreground='blue')
chat.tag_config('yourword', foreground='grey')
chat.tag_config('Doc', foreground='green')
chat.tag_config('Docword', foreground='black')

beforeStart = tk.Label(gui, text="Please describe your symptom below:")
beforeStart.place(x=120, y=425)

gui.bind('<Return>', processData)

gui.mainloop()


from matplotlib import pyplot as plt
from skimage.io import imread
import numpy as np

def line_curve():
    H = np.hstack((x ** 2, x, ones))
    return H

image = imread(r"image8.png",as_gray=True)

mean = image.mean()
print(mean)

filter_image = image > mean

x = []
y = []

j = 0

#print(filter_image)
for row in filter_image:
    i = 0
    j += 1
    for colomn in row:
        i += 1
        if not(colomn):
            x.append(i)
            y.append(j) # len(row)-i)

x = np.array(x).reshape((len(x),1))
y = np.array(y).reshape((len(y), 1))

ones = np.ones(len(x)).reshape((len(x), 1))

H = line_curve()

abc1 = np.linalg.inv(np.dot(H.T,H))
abc2 = np.dot(H.T,y)

abc = np.dot(abc1,abc2)
print(abc)
yhat = np.dot(H,abc)
#print(x)
#print(len(yhat))
for i in range(0,len(yhat),500):
    #print(i)
    plt.plot(x,yhat,'w.')

plt.imshow(filter_image)
plt.show()


import numpy as np
import itertools
import matplotlib.pyplot as plt
import random

from matplotlib.patches import Circle, Arc
from matplotlib.animation import FuncAnimation

class Interval():
    def __init__(self, a, b, mat, letters, color):
        self.a = a
        self.b = b
        self.mat = mat
        self.color = color
        self.letters = letters

    # Draw image of the interval
    def draw(self, ax):
        theta2, theta1 = get_arc_params(rp1_interval(self.a, self.b))
        ax.add_patch(Arc((0,0), 2., 2., theta1=theta1, theta2=theta2, color=self.color, linewidth=10))

    # Draw image of the interval under all letters except inv(self.mat)
    # Check containment of the images within the interval
    def draw_image(self, ax):
        I = rp1_interval(self.a, self.b)
        for mat in letters:
            if not np.allclose(mat, np.linalg.inv(self.mat)):
                theta2, theta1 = get_arc_params(mat @ I)
                ax.add_patch(Arc((0,0), 2., 2., theta1=theta1, theta2=theta2, color='orange', linewidth=7))

def rp1_to_s1(v):
    """map a point in R^2 - {0} to S1 via the homeo RP1 -> S1"""
    x, y = v[0], v[1]

    return np.row_stack([
        2*x*y / (x*x + y*y),
        (x*x - y*y) / (x*x + y*y)
    ])

# TODO Make this
def s1_to_rp1(v):
    pass

def get_arc_params(interval):
    """map a pair of points in R^2 - {0} to a pair of circle angles"""
    x, y = rp1_to_s1(interval)
    return np.arctan2(y,x) * 180 / np.pi

def rp1_interval(theta1, theta2):
    """get a pair of points in RP1 representing the pair of angles theta1, theta2

    note: theta1, theta2 parameterize the double cover of RP^1"""
    return np.array([
        [np.cos(theta1), np.cos(theta2)],
        [np.sin(theta1), np.sin(theta2)]
    ])

def contains(a, b, c, d):
    # Check if (a,b) is contained in (c,d)
    return a < c and b > d

def non_triv_intersect(a, b, c, d):
    # Check if (a,b) intersects (c,d) nontrivially
    return a < c < b or a < d < b

def rand_matrix(n):
    # n determines how large you want the entries to be. Pick n in (0, 5).
    # random matrix generation
    a = float(np.random.rand(1) * n)
    c = float(np.random.rand(1) * n) #* np.random.choice(-1, 1) * 5)
    d = float(np.random.rand(1) * n)
    b = (a * d - 1) / c

    return np.array([[a, b], [c, d]])

def pair_of_free_group_generators(n):
    # Create a random pair of matrices that are guaranteed to generate a free group in SL(2,R)
    # n determines how large you want the entries to be. Pick n in (0, 5).

    # file:///C:/Users/abhay/Downloads/1028999969.pdf PDF pg 2 / pg 162
    # Title: Pairs of Real 2-by-2 Matrices that Generate Free Products by R.C. Lyndon & J.L. Ullman

    a, c, e, g = float(np.random.rand(1) * n) , float(np.random.rand(1) * n) , float(np.random.rand(1) * n) , float(np.random.rand(1) * n)
    d, h = float(np.random.rand(1) * n) + a + 2 , float(np.random.rand(1) * n) + e + 2
    b, f = (a * d + 1) / c , (e * h + 1) / g

    R = rand_matrix(1)

    return R @ np.array([[-a , b] , [-c , d]]) @ np.linalg.inv(R) , R @ np.array([[ -e , -f] , [ g , h]]) @ np.linalg.inv(R)

def generators_up_to_conjugacy(eig,n):
    # Classifies generators of a free group up to conjugacy by specifying eigenvalue

    a = float(np.random.rand(1) * n)
    c = float(np.random.rand(1) * n)# * np.random.choice(-1, 1) * 5)
    d = (eig**2 + 1) / eig - a
    b = (a * d - 1) / c

    return np.array([ [a, b], [c, d] ])

def create_intervals(generators, epsilon):
    # Find theta for eigenvectors on S1 via RP1 -> S1
    # Create interval objects with initial values around eigenvectors
    colors = [np.array([0,0,1]), np.array([1,0,0])]
    intervals = []
    iter = 0

    for mat in generators:

        e1 = np.arctan2(np.linalg.eig(mat)[1][1][0], np.linalg.eig(mat)[1][0][0])
        e2 = np.arctan2(np.linalg.eig(mat)[1][1][1], np.linalg.eig(mat)[1][0][1])

        if np.linalg.eig(mat)[0][0] > 1:
            intervals.append(Interval(e1 - epsilon, e1 + epsilon, mat, letters, colors[iter]))
            intervals.append(Interval(e2 - epsilon, e2 + epsilon, np.linalg.inv(mat), letters, colors[iter]))
        else:
            intervals.append(Interval(e1 - epsilon, e1 + epsilon, np.linalg.inv(mat), letters, colors[iter]))
            intervals.append(Interval(e2 - epsilon, e2 + epsilon, mat, letters, colors[iter]))

        iter += 1
    return intervals

if __name__ == '__main__':

    # Check out 0.2 or 0.25!
    epsilon = 0.25

    print()
    print()
    print("How would you like to generate 2 matrices in SL(2,R) to test if Ping-Pong intervals exist?" )
    print()
    print("1. Keep generating 2 random matrices in SL(2,R) as potential generators of a Free group until a successful Ping-Pong interval is found.")
    print()
    print("2. Generate a pair of matrices in SL(2,R) that already generate a free group.")
    print()
    print("3. Specify two eigenvalues to create two corresponding matrices in SL(2,R).")
    print("   Matrices with the specified eigenvalues will continue to be generated until a successful Ping-Pong interval is found.")
    print("   This will classify generators of a free group in conjugacy classes.")
    print()
    print("4. Enter manual inputs for 2 potential generators in SL(2,R).")
    print()

    val = int(input("Enter choice 1, 2, 3, or 4 and press Enter: "))
    print("-"*145)

    if val == 3:

        print()
        print("Please enter eigenvalues in (0 , ∞) / {1}.")

        repeat = True
        while repeat:

            print()
            eA = float(input("Enter an eigenvalue to genenerate the first matrix in SL(2,R) and press Enter: "))
            eB = float(input("Enter an eigenvalue to genenerate the second matrix in SL(2,R) and press Enter: "))

            if eA == 1 or eB == 1:
                print()
                print("Please do not enter 1 as an eigenvalue. Enter eigenvalues in (0 , ∞) / {1}. Try again!")
            else:
                print("-"*145)
                repeat = False

    if val == 4:

        print()
        print( np.array( [["a", "b"],
                          ["c", "d"]] )  )
        print()
        print( np.array( [["e", "f"],
                          ["g", "h"]] )  )
        print()
        print("Please fill in the letters above for the two matrices:")
        a, b, c, d = input("Enter the values of a, b, c, d. Seperate the values by a space and then press Enter: ").split()
        e, f, g, h = input("Enter the values of e, f, g, h. Seperate the values by a space and then press Enter: ").split()
        a, b, c, d, e, f, g, h = float(a), float(b), float(c), float(d), float(e), float(f), float(g), float(h)
        print("-"*145)

    print()

    done = False
    while not done:

        i = 1

        if val == 1:
            # random matrix generation
            print('checking')

            A, B = rand_matrix(7), rand_matrix(7)
            eA, eB = np.linalg.eig(A)[0][0], np.linalg.eig(B)[0][0]

        elif val == 2:
            # Create a random pair of matrices that are
            # guaranteed to generate a free group in SL(2,R)

            A, B = pair_of_free_group_generators(5)
            eA, eB = np.linalg.eig(A)[0][0], np.linalg.eig(B)[0][0]

        elif val == 3:
            # generate a pair of matrices by their eigenvalues (classifying them in conjugacy classes)
            print('checking')

            A = generators_up_to_conjugacy(eA,3)
            B = generators_up_to_conjugacy(eB,3)

        elif val == 4:

            A = np.array([[a, b],
                          [c, d]])
            B = np.array([[e, f],
                          [g, h]])
            eA, eB = np.linalg.eig(A)[0][0], np.linalg.eig(B)[0][0]

        if np.iscomplex(eA) == True or np.iscomplex(eB) == True:
            continue
        elif np.abs(eA - float(1)) < 0.0001 or np.abs(eB - float(1)) < 0.0001:
            continue
        else:
            pass

        # Get all letters (this includes generators and their inverses)
        generators = [A, B]
        letters = []
        for g in generators:
            letters += [g]
            letters += [np.linalg.inv(g)]

        ##########################################################################################################
        # TODO Make sure intervals don't overlap
        for epsilon in np.arange(0.01, 0.4, 0.01):
            intervals = create_intervals(generators, epsilon)
            all_fully_contained = True
            for interval in intervals:
                fully_contained = True
                for other_interval in intervals:
                    I = rp1_interval(other_interval.a, other_interval.b)
                    if not np.allclose(other_interval.mat, np.linalg.inv(interval.mat)):
                        theta2, theta1 = get_arc_params(interval.mat @ I)
                        b, a = get_arc_params(rp1_interval(interval.a, interval.b))
                        # print(a, b, theta1, theta2)
                        if a > b:
                            # Interval crosses the break point
                            if theta1 > theta2:
                                # Inner interval crosses the break point
                                fully_contained = fully_contained and contains(theta2, theta1, b, a)
                            else:
                                if theta1 > 0:
                                    # Inner interval completely above break point
                                    fully_contained = fully_contained and contains(theta2-360, theta1, b, a)
                                else:
                                    # Inner interval completely below break point
                                    fully_contained = fully_contained and contains(theta2, theta1+360, b, a)
                        else:
                            fully_contained = fully_contained and contains(a, b, theta1, theta2)
                all_fully_contained = all_fully_contained and fully_contained

            for pair in itertools.combinations(intervals, 2):
                if non_triv_intersect(pair[0].a, pair[0].b, pair[1].a, pair[1].b):
                    if i == 1:
                        print('Intervals are intersecting!')
                        print()
                        i += 1
                    intervals = create_intervals(generators, epsilon - 0.01)
                    done = False

            if all_fully_contained and not done:
                intervals = create_intervals(generators, epsilon + 0.01)
                done = True

            if done:
                break
    ##########################################################################################################
    print('A = ')
    print(A)
    print('Determinant = ', np.linalg.det(A))
    print()
    print('Eigenvalues = ', np.linalg.eig(A)[0][0],' , ', np.linalg.eig(A)[0][1], ";")
    print('Eigenvectors = [', np.linalg.eig(A)[1][0][0] , ',' , np.linalg.eig(A)[1][1][0], '] ,', '[', np.linalg.eig(A)[1][0][1] , ',', np.linalg.eig(A)[1][1][1], '].')
    print()
    print('B = ')
    print(B)
    print('Determinant = ', np.linalg.det(B))
    print()
    print('Eigenvalues = ', np.linalg.eig(B)[0][0],' , ', np.linalg.eig(B)[0][1], ";")
    print('Eigenvectors = [', np.linalg.eig(B)[1][0][0] , ',' , np.linalg.eig(B)[1][1][0], '] ,', '[', np.linalg.eig(B)[1][0][1] , ',', np.linalg.eig(B)[1][1][1], '].')
    print()
    print('epsilon = ', epsilon)

    if not all_fully_contained:
        print('Ping Pong Intervals Not Found.')

    print("-"*145)
    print()

    # verify acrtan2 gives correct angles

    '''# A coordinates
    x1, y1, x2, y2 = np.linalg.eig(A)[1][0][0], np.linalg.eig(A)[1][1][0], np.linalg.eig(A)[1][0][1], np.linalg.eig(A)[1][1][1]
    v1, v2 = [x1, y1] , [x2, y2]
    # B coordinates
    x3, y3, x4, y4 = np.linalg.eig(B)[1][0][0], np.linalg.eig(B)[1][1][0], np.linalg.eig(B)[1][0][1], np.linalg.eig(B)[1][1][1]
    v3, v4 = [x3, y3] , [x4, y4]

    print(rp1_to_s1(v1), np.arctan2(y1,x1) * 180 / np.pi)
    print(rp1_to_s1(v2), np.arctan2(y2,x2) * 180 / np.pi)
    print(rp1_to_s1(v3), np.arctan2(y3,x3) * 180 / np.pi)
    print(rp1_to_s1(v4), np.arctan2(y4,x4) * 180 / np.pi)'''

    fig, ax = plt.subplots(figsize=(5, 5))

    # Plot data
    ax.set_xlim((-1.2, 1.2))
    ax.set_ylim((-1.2, 1.2))
    ax.axis("off")
    ax.set_aspect("equal")

    # RP1
    rp1 = Circle((0,0), 1.0, fill=False)
    ax.add_patch(rp1)

    # Draw intervals
    # Draw images of intervals under the respective transforms

    for interval in intervals:
        interval.draw(ax)
    for interval in intervals:
        interval.draw_image(ax)
    plt.show()


import numpy as np
import pygame
from consts import WindowConsts, ScreenConsts, PlayerConsts, BackgroundsConsts, EnemyConsts
from kg_logger import KGLogger, log_function
from objects.bullet import Bullet
from objects.enemy import Enemy
from objects.explosion import Explosion
from objects.player import Player
from objects.star import Star
from utils.timer import Timer

class Game:
    def __init__(self):
        self.logger = KGLogger()
        pygame.init()
        self.screen = pygame.display.set_mode(size=WindowConsts.WINDOW_SIZE)
        self.delta_axis = PlayerConsts.PLAYER_INIT_DELTA_AXIS
        pygame.display.set_caption(WindowConsts.WINDOW_TITLE)
        icon = pygame.image.load(WindowConsts.WINDOW_ICON_PATH)
        pygame.display.set_icon(icon)
        self._load_images()
        self._load_objects()
        self.running = True
        self._player_score = 0
        self._timer = Timer()

    @log_function
    def _load_images(self):
        self._bullet_img = pygame.image.load(BackgroundsConsts.BULLET_IMAGE_PATH)
        self._star_img = pygame.image.load(BackgroundsConsts.STAR_IMAGE_PATH)
        self.small_explosion_img = pygame.image.load(BackgroundsConsts.SMALL_EXPLOSION_IMAGE_PATH)
        self.medium_explosion_img = pygame.image.load(BackgroundsConsts.MEDIUM_EXPLOSION_IMAGE_PATH)
        self.large_explosion_img = pygame.image.load(BackgroundsConsts.LARGE_EXPLOSION_IMAGE_PATH)
        self.player_img = pygame.image.load(PlayerConsts.PLAYER_IMAGE_PATH)

    @log_function
    def _load_objects(self):
        self._stars = []
        self._enemies = []
        self.add_enemy_each_seconds = 3
        self._player = Player()
        self._bullets = []
        self._explosions = []

    @log_function
    def _quit_running(self):
        self.running = False

    def show_score(self):
        font = pygame.font.Font(ScreenConsts.MAIN_FONT_FAMILY, ScreenConsts.MAIN_FONT_SIZE)
        score = font.render(f"Score: {str(self._player_score)}", True, ScreenConsts.WHITE)
        self.screen.blit(score, ScreenConsts.SCORE_AXIS)

    def _set_player(self):
        self.screen.blit(self.player_img, self._player.get_axis())
        self._player.set_speed(speed=PlayerConsts.PLAYER_SPEED + self._speed_depends_time())

    @log_function
    def _create_new_enemies(self):
        new_enemy = Enemy(speed=EnemyConsts.ENEMY_SPEED + self._speed_depends_time())
        self._enemies.append(new_enemy)
        self.logger.info(f"Created enemy")

    def _set_enemy(self):
        if self._timer.time_pass_in_seconds() > self.add_enemy_each_seconds:
            self.add_enemy_each_seconds += EnemyConsts.SET_ENEMY_EVERY_SECONDS + np.random.randint(0, 3)
            if len(self._enemies) < EnemyConsts.MAX_ENEMY_ON_SCREEN:
                self._create_new_enemies()
            self.logger.debug(f"Next enemy will appears at {self.add_enemy_each_seconds} sec")
        for enemy in self._enemies:
            if enemy.is_done():
                self._player_score += 3
                self._enemies.remove(enemy)
            enemy.random_move()
            enemy.handle_out_of_board()
            self.screen.blit(enemy.img, enemy.get_axis())

    def _create_new_star(self):
        if len(self._stars) < BackgroundsConsts.NUM_OF_STARS:
            new_star = Star()
            self._stars.append(new_star)

    def _set_starts(self):
        self._create_new_star()
        for star in self._stars:
            if star.is_done():
                self._stars.remove(star)
            star.move()
            self.screen.blit(self._star_img, star.get_axis())

    def _shoot_bullet(self):
        bullet_axis = self._player.get_middle_axis()
        bullet = Bullet(axis=bullet_axis)
        self._bullets.append(bullet)

    def _add_explosion(self, axis: np.array, explosion_type: str):
        explosion = Explosion(axis=axis, explosion_type=explosion_type)
        self._explosions.append(explosion)

    def _get_explosion_image(self, explosion_type):
        if explosion_type == BackgroundsConsts.S_EXPLOSION:
            return self.small_explosion_img
        elif explosion_type == BackgroundsConsts.M_EXPLOSION:
            return self.medium_explosion_img
        elif explosion_type == BackgroundsConsts.L_EXPLOSION:
            return self.large_explosion_img

    def _set_explosion(self):
        for explosion in self._explosions:
            if explosion.is_done():
                self._explosions.remove(explosion)
            explosion.move()
            self.screen.blit(self._get_explosion_image(explosion.explosion_type), explosion.get_axis())

    def _bullet_hit_enemy(self, bullet: Bullet):
        for enemy in self._enemies:
            if enemy.is_axis_in_enemy(other_axis=bullet.get_axis()):
                self.logger.error(f"hit enemy")
                bullet.set_done()
                enemy.hit()
                enemy_axis = enemy.get_middle_axis()
                explosion_type = BackgroundsConsts.S_EXPLOSION
                if enemy.damage == 2:
                    explosion_type = BackgroundsConsts.S_EXPLOSION
                elif enemy.damage == 1:
                    explosion_type = BackgroundsConsts.M_EXPLOSION
                elif enemy.damage == 0:
                    explosion_type = BackgroundsConsts.L_EXPLOSION
                self._add_explosion(axis=enemy_axis, explosion_type=explosion_type)
                self._player_score += 1

    def _set_bullets(self):
        for bullet in self._bullets:
            if bullet.is_done():
                self._bullets.remove(bullet)
            if not bullet.is_done():
                self._bullet_hit_enemy(bullet=bullet)
            bullet.move()
            self.screen.blit(self._bullet_img, bullet.get_axis())

    def _speed_depends_time(self) -> float:
        return self._timer.time_pass_in_seconds() / 500

    def _handle_key_events(self, event):
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                self.delta_axis[0] = 0.
            if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
                self.delta_axis[1] = 0.

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                self.delta_axis[0] -= self._player.speed
            if event.key == pygame.K_RIGHT:
                self.delta_axis[0] += self._player.speed
            if event.key == pygame.K_UP:
                self.delta_axis[1] -= self._player.speed
            if event.key == pygame.K_DOWN:
                self.delta_axis[1] += self._player.speed
            if event.key == pygame.K_SPACE:
                self._shoot_bullet()

    def run(self):
        while self.running:
            self.screen.fill(ScreenConsts.SCREEN_INIT_RGB)
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self._quit_running()
                self._handle_key_events(event)

            self._player.add_axis(self.delta_axis)
            self._player.handle_out_of_board()
            self._set_player()
            self._set_enemy()
            self._set_starts()
            self._set_bullets()
            self._set_explosion()
            self.show_score()
            self._timer.print_seconds()
            pygame.display.update()
        self.logger.info(f"Time played in total seconds: {self._timer.time_pass_in_seconds()}")


from tkinter import *
import pandas as pd
import tkinter as tk
from tkinter import filedialog
import pandas as pd
#import numpy as np
from pandas import DataFrame
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
#importing filters
import csv
import numpy
df= pd.read_csv('oct_2019 MELT.csv')

#desk filter
def desk_filter(day,desk):
    global df2
    desk_new=[]
    for i in desk:
        desk_new.append(str(i))
    df1= df[df.Day.isin(day)]
    df2=df1[df1.Desk.isin(desk_new)]  #needs to be a string
    return (df2)

desk_filter([1],[3])
#print(df2)

class VerticalScrolledFrame(Frame):
    """A pure Tkinter scrollable frame that actually works!
    * Use the 'interior' attribute to place widgets inside the scrollable frame
    * Construct and pack/place/grid normally
    * This frame only allows vertical scrolling

    """
    def __init__(self, parent, *args, **kw):
        Frame.__init__(self, parent, *args, **kw)

        # create a vertical scrollbar for scrolling it
        vscrollbar = Scrollbar(self, orient=VERTICAL)
        vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)

        # create a horizontal scrollbar and the canvas
        hscrollbar = Scrollbar(self, orient=HORIZONTAL)
        hscrollbar.pack(fill=X, side=BOTTOM, expand=FALSE)
        canvas = Canvas(self, bd=0, highlightthickness=0,
                        yscrollcommand=vscrollbar.set, xscrollcommand=hscrollbar.set)
        canvas.pack(side=LEFT, fill=BOTH, expand=TRUE, anchor=W)
        vscrollbar.config(command=canvas.yview)
        hscrollbar.config(command=canvas.xview)

        # reset the view
        canvas.xview_moveto(0)
        canvas.yview_moveto(0)

        # create a frame inside the canvas which will be scrolled with it
        self.interior = interior = Frame(canvas)
        interior_id = canvas.create_window(0, 0, window=interior,
                                           anchor=NW)

        # track changes to the canvas and frame width and sync them,
        # also updating the scrollbar
        def _configure_interior(event):
            # update the scrollbars to match the size of the inner frame
            size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
            canvas.config(scrollregion="0 0 %s %s" % size)
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the canvas's width to fit the inner frame
                canvas.config(width=interior.winfo_reqwidth())
        interior.bind('<Configure>', _configure_interior)

        def _configure_canvas(event):
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the inner frame's width to fill the canvas
                canvas.itemconfigure(interior_id, width=canvas.winfo_width())
        canvas.bind('<Configure>', _configure_canvas)

if __name__ == "__main__":

    class SampleApp(Tk):

        def __init__(self, *args, **kwargs):
            root = Tk.__init__(self, *args, **kwargs)

            self.frame = VerticalScrolledFrame(root)
            self.frame.grid(row=0, column=0)
            #self.label = Label(text="Shrink the window to activate the scrollbar.")
            #self.label.grid(row=1, column=0)
            def graphdesk(desk):
            #print('you are printing imaginary graphs!')

                #placeholder dataframes

                Data1 = {'Country': ['US','CA','GER','UK','FR'],
                        'GDP_Per_Capita': [45000,42000,52000,49000,47000]
                       }

                df1 = DataFrame(Data1, columns= ['Country', 'GDP_Per_Capita'])
                df1 = df1[['Country', 'GDP_Per_Capita']].groupby('Country').sum()

                Data2 = {'Year': [1920,1930,1940,1950,1960,1970,1980,1990,2000,2010],
                        'Unemployment_Rate': [9.8,12,8,7.2,6.9,7,6.5,6.2,5.5,6.3]
                       }

                df2 = DataFrame(Data2,columns=['Year','Unemployment_Rate'])
                df2 = df2[['Year', 'Unemployment_Rate']].groupby('Year').sum()

                Data3 = {'Interest_Rate': [5,5.5,6,5.5,5.25,6.5,7,8,7.5,8.5],
                        'Stock_Index_Price': [1500,1520,1525,1523,1515,1540,1545,1560,1555,1565]
                       }

                df3 = DataFrame(Data3,columns=['Interest_Rate','Stock_Index_Price'])

                #placeholder dataframes

                newWindow = tk.Toplevel()

                print(desk)
                figure1 = plt.Figure(figsize=(6,5), dpi=100)
                ax1 = figure1.add_subplot(111)
                bar1 = FigureCanvasTkAgg(figure1, newWindow)
                bar1.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH)
                df1.plot(kind='bar', legend=True, ax=ax1)
                ax1.set_title('Country Vs. GDP Per Capita')

                figure2 = plt.Figure(figsize=(5,4), dpi=100)
                ax2 = figure2.add_subplot(111)
                line2 = FigureCanvasTkAgg(figure2, newWindow)
                line2.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH)
                df2.plot(kind='line', legend=True, ax=ax2, color='r',marker='o', fontsize=10)
                ax2.set_title('Year Vs. Unemployment Rate')

                figure3 = plt.Figure(figsize=(5,4), dpi=100)
                ax3 = figure3.add_subplot(111)
                ax3.scatter(df3['Interest_Rate'],df3['Stock_Index_Price'], color = 'g')
                scatter3 = FigureCanvasTkAgg(figure3, newWindow)
                scatter3.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH)
                ax3.legend()
                ax3.set_xlabel('Interest Rate')
                ax3.set_title('Interest Rate Vs. Stock Index Price')

            deskNum=tk.StringVar()
            entry_deskNum = tk.Entry(self.frame.interior, textvariable=deskNum, width=6).grid(row=0, column=0)
            button_graphdesk = tk.Button(self.frame.interior, text = 'Graph the desk!', command=lambda:graphdesk(deskNum.get())).grid(row=0, column=1, sticky='w'+'e')
            headers = []
            for col in df2.columns:
                #print(col)
                headers.append(col)
            headers[0] = 'Desk#'
            headerindex = 0
            for i in headers:
                tk.Label(self.frame.interior,text=i,font=("Helvetica", 8),bg = 'cyan',anchor= 'e',relief = 'solid').grid(row = 1, column = headerindex, sticky = 'w'+'e')
                headerindex +=1
            df2.to_csv('headless.csv', header=False, index=False)
            listedDF = df2.values.tolist()
            i_index = 2
            j_index = 0
            for i in listedDF:
                for j in i:
                    if i[0] < 101:
                        tk.Label(self.frame.interior, text=j,font=("Helvetica", 8),bg = 'lightgreen',anchor= 'e',relief = 'solid').grid(row = i_index, column = j_index, sticky = 'w'+'e')
                    else:
                        tk.Label(self.frame.interior,text=j,font=("Helvetica", 8),bg = 'orange', anchor = 'e', relief = 'solid').grid(row = i_index, column = j_index, sticky = 'w'+'e')
                    j_index +=1
                i_index +=1
                j_index = 0

    app = SampleApp()
    app.mainloop()


#!/usr/bin/env python

#  2018 JHU CLSP (Aswin Shanmugam Subramanian)
#  Apache 2.0  (http://www.apache.org/licenses/LICENSE-2.0)

from load_data import save_list
import argparse

parser = argparse.ArgumentParser(description='Create REVERB list')
parser.add_argument('--data_dir', default='wav/REVERB_WSJCAM0_tr/data/mc_train',
                    help='Base directory of the REVERB challenge parallel simulation data.')
parser.add_argument('--dest_dir', default='data',
                    help='Base directory to store the list.')
args = parser.parse_args()

save_list(args.data_dir, args.dest_dir)