import re
import os
import sys
import json
import random
import torch
import pytorch_lightning as pl

from tqdm import tqdm
from pprint import pprint
from dataclasses import dataclass
from collections import Counter
from transformers import BertTokenizerFast, RobertaTokenizerFast
from q_snippets.object import Config, print_config, print_string
from q_snippets.data import BaseData, sequence_padding, save_json
from torch.utils.data import Dataset, DataLoader, random_split
from data.causal_relation.pdtb2.pdtb2 import CorpusReader

FILE_DIR = os.path.dirname(os.path.abspath(__file__))
PROJ_DIR = FILE_DIR[:FILE_DIR.index('src')]
sys.path.append(PROJ_DIR)
os.environ["TOKENIZERS_PARALLELISM"] = "true"

@dataclass
class InputSample:  # 原始数据
    arg1: str
    arg2: str
    connective: str
    sense: str

@dataclass
class InputFeature:  # 处理后的特征数据
    input_ids: list
    attention_mask: list
    # token_type_ids: list
    mask_token_id: int
    label: int

@dataclass
class InputBatch(BaseData):  # 对特征数据进行batch处理
    input_ids: torch.Tensor
    attention_mask: torch.Tensor
    # token_type_ids: torch.Tensor
    mask_token_ids: torch.Tensor
    labels: torch.Tensor

    def __len__(self):
        return self.input_ids.size(0)

    def info(self):
        size = {k: v.size() if type(v) is torch.Tensor else len(v)
                for k, v in self.__dict__.items()}
        print(size)

class LabelMapping(object):
    def __init__(self, mapping_path):
        with open(mapping_path, "r") as f:
            self.label2words:dict = json.load(f)
        self.words2label = self.get_words2label(self.label2words)
        labels = sorted(list(set(self.words2label.values())))
        self.label2id = self.get_label2id(labels)
        self.id2label = {id: label for label, id in self.label2id.items()}

    def get_words2label(self, label2words):
        words2label = {}
        for label, words in label2words.items():
            # if label.startswith("Contingency"):  # causality
            #     for word in words:
            #         words2label[word] = label
            # else:
            for word in words:
                words2label[word] = label.split(".")[0]  # pdtb2 top-level
                # words2label[word] = ".".join(label.split(".")[:2])  # pdtb2 second-level
                # words2label[word] = label  # cross-level
        return words2label

    def get_label2id(self, labels):
        label2id = {"Other": 0}
        for idx, label in enumerate(labels):
            label2id[label] = idx+1  # 1~n
        return label2id

class CoNll16Dataset(Dataset):
    def __init__(self, config, tokenizer, dataset_mode) -> None:
        super().__init__()
        self.tokenizer = tokenizer
        self.config = config
        self.mode = dataset_mode
        self.label_mapping = LabelMapping(config.mapping_path)
        self.label2words = self.label_mapping.label2words
        self.words2label = self.label_mapping.words2label
        self.samples, self.features = self._handle_cache()

    def _handle_cache(self):
        """
            核心是 self.load_data 加载并处理数据，返回原始数据和处理后的特征数据
            需要注意缓存文件与 self.config.cache_dir  self.mode 有关
        Returns:
            samples, features
        """
        os.makedirs(self.config.cache_dir, exist_ok=True)               # 确保缓存文件夹存在
        file = os.path.join(self.config.cache_dir, f"{self.mode}.pt")   # 获得缓存文件的路径
        # 如果已经存在，且没有强制重新生成，则从缓存读取
        if os.path.exists(file) and not self.config.force_reload:
            samples, features = torch.load(file)
            print(f"{len(samples), len(features)} samples, features loaded from {file}")
            return samples, features
        else:
            samples, features = self.load_data()                        # 读取并处理数据
            torch.save((samples, features), file)                       # 生成缓存文件
            return samples, features

    def load_data(self):
        samples, features = [], []
        if self.mode == 'train':
            path = self.config.train_path
        elif self.mode == 'val':
            path = self.config.val_path
        elif self.mode == 'test':
            path = self.config.test_path
        with open(path, 'r', encoding='utf-8') as f:
            all_data = json.load(f)

        sense_list = []
        for dic in tqdm(all_data):
            arg1 = dic["Arg1"]
            arg2 = dic["Arg2"]

            sense = dic["Sense"]
            if sense not in self.label2words.keys():
                continue

            connective = dic["Connective"]
            if connective in self.label2words[sense]:
                mask_word = connective
            else:  # 对于其他连接词用频率最高的连接词进行替换
                mask_word = self.label2words[sense][0]
            label = self.tokenizer.convert_tokens_to_ids(mask_word)

            # prompt = "[CLS] " + arg1 + " [MASK] " + arg2 + ". [SEP]"  # bert prompt
            # prompt = "<s> " + arg1.capitalize() + " <mask> " + arg2.lower() + ". </s>"  # roberta prompt1
            # prompt = "<s> " + arg1.capitalize() + ". That's <mask> " + arg2.lower() + ". </s>"  # roberta prompt2
            prompt3 = "Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + ". The conjunction between Arg1 and Arg2 is <mask>."  # roberta prompt3
            prompt4 = "<s>Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + ". The conjunction between Arg1 and Arg2 is <mask>.</s>"  # roberta prompt4
            inputs = self.tokenizer(
                prompt4,
                max_length=512,
                truncation=True,
                return_offsets_mapping=True
            )

            if self.tokenizer.mask_token_id not in inputs.input_ids: # 如果arg1超过512限制则舍弃
                continue
            mask_token_id = inputs.input_ids.index(self.tokenizer.mask_token_id)

            if self.mode in ["train", "val", "test"]:
                sense_list.append(sense)
                samples.append(InputSample(
                    arg1=arg1, arg2=arg2,
                    connective=connective,
                    sense=sense
                ))
                features.append(InputFeature(
                    input_ids=inputs.input_ids,
                    attention_mask=inputs.attention_mask,
                    # token_type_ids=inputs.token_type_ids,
                    mask_token_id=mask_token_id,
                    label=label
                ))
            else:
                pass

        print(dict(Counter(sense_list)))
        print(f"{str(len(samples))} samples, {str(len(features))} features in total for {self.mode}")

        return samples, features

    def __len__(self):
        return len(self.features)

    def __getitem__(self, index):
        return self.features[index]

    @staticmethod
    def collate_fn(batch):
        test = batch[0].label is None
        max_len = min(max([len(x.input_ids) for x in batch]), 512)

        # 将batch_size条feature转换成Tensor
        input_ids = torch.tensor(sequence_padding([x.input_ids for x in batch], length=max_len))
        attention_mask = torch.tensor(sequence_padding([x.attention_mask for x in batch], length=max_len))
        # token_type_ids = torch.tensor(sequence_padding([x.token_type_ids for x in batch], length=max_len))
        mask_token_ids = torch.tensor([x.mask_token_id for x in batch])
        labels = torch.tensor([x.label for x in batch]) if not test else None
        batch = InputBatch(
            input_ids=input_ids,
            attention_mask=attention_mask,
            # token_type_ids=token_type_ids,
            mask_token_ids=mask_token_ids,
            labels=labels
        )
        return batch

class PDTB2Dataset(Dataset):
    def __init__(self, config, tokenizer, dataset_mode) -> None:
        super().__init__()
        self.tokenizer = tokenizer
        self.config = config
        self.mode = dataset_mode
        self.label_mapping = LabelMapping(config.mapping_path)
        self.label2words = self.label_mapping.label2words
        self.words2label = self.label_mapping.words2label
        self.samples, self.features = self._handle_cache()

    def _handle_cache(self):
        """
            核心是 self.load_data 加载并处理数据，返回原始数据和处理后的特征数据
            需要注意缓存文件与 self.config.cache_dir  self.mode 有关
        Returns:
            samples, features
        """
        os.makedirs(self.config.cache_dir, exist_ok=True)               # 确保缓存文件夹存在
        file = os.path.join(self.config.cache_dir, f"{self.mode}.pt")   # 获得缓存文件的路径
        # 如果已经存在，且没有强制重新生成，则从缓存读取
        if os.path.exists(file) and not self.config.force_reload:
            samples, features = torch.load(file)
            print(f"{len(samples), len(features)} samples, features loaded from {file}")
            return samples, features
        else:
            samples, features = self.load_data()                        # 读取并处理数据
            torch.save((samples, features), file)                       # 生成缓存文件
            return samples, features

    def load_data(self):
        samples, features = [], []
        if self.mode == 'train':
            path = self.config.train_path
        elif self.mode == 'val':
            path = self.config.val_path
        elif self.mode == 'test':
            path = self.config.test_path

        pdtb = CorpusReader(path)
        sense_list = []
        for datum in pdtb.iter_data(display_progress=True):
            if datum.Relation == "Implicit":
                # continue
                arg1:str = datum.Arg1_RawText.strip()
                arg2:str = datum.Arg2_RawText.strip()
                sense = datum.ConnHeadSemClass1
                connective = datum.Conn1.strip()

                if sense not in self.label2words.keys():
                    continue
                if "Ġ"+connective in self.label2words[sense]:
                    mask_word = "Ġ"+connective  # roberta
                    # mask_word = connective  # bert
                else:  # 对于其他连接词用频率最高的连接词进行替换
                    mask_word = self.label2words[sense][0]  # roberta
                    # mask_word = self.label2words[sense][0][1:]  # bert
                label = self.tokenizer.convert_tokens_to_ids(mask_word)

                # prompt = "[CLS] " + arg1.strip().capitalize() + " [MASK] " + arg1.strip().lower() + ". [SEP]"  # bert prompt1
                # prompt = "[CLS] Arg1: " + arg1.strip().capitalize() + ". Arg2: " + arg2.strip().capitalize() + ". [SEP] The conjunction between Arg1 and Arg2 is [MASK]. [SEP]"  # bert prompt2

                roberta_prompt1 = arg1.capitalize() + " <mask> " + arg2.lower() + "."  # roberta prompt1
                roberta_prompt2 = arg1.capitalize() + ". That's <mask> " + arg2.lower() + "."  # roberta prompt2
                roberta_prompt3 = "Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + ".</s></s>The conjunction between Arg1 and Arg2 is <mask>."  # roberta prompt3
                roberta_prompt4 = "Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + ".</s></s>The connective between Arg1 and Arg2 is <mask>."  # roberta prompt4
                roberta_prompt5 = "Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + ". The conjunction between Arg1 and Arg2 is <mask>."  # roberta prompt5
                roberta_prompt6 = "Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + ". The connective between Arg1 and Arg2 is <mask>."  # roberta prompt6
                roberta_prompt7 = "<s>Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + ". The conjunction between Arg1 and Arg2 is <mask>.</s>"  # roberta prompt7
                roberta_prompt8 = "<s>Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + ". The connective between Arg1 and Arg2 is <mask>.</s>"  # roberta prompt8
                roberta_prompt9 = "<s>Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + ". In summary, the discourse relation between Arg1 and Arg2 is <mask>.</s>"  # roberta prompt9
                roberta_prompt10 = "Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + ". In summary, the discourse relation between Arg1 and Arg2 is <mask>."  # roberta prompt10

                inputs = self.tokenizer(roberta_prompt5, max_length=512, truncation=True)

                # if self.tokenizer.mask_token_id not in inputs.input_ids:  # 如果arg1超过512限制则舍弃
                #     continue
                mask_token_id = inputs.input_ids.index(self.tokenizer.mask_token_id)

                if self.mode in ["train", "val", "test"]:
                    # sense_list.append(sense)
                    samples.append(InputSample(
                        arg1=arg1, arg2=arg2,
                        connective=connective,
                        sense=sense
                    ))
                    features.append(InputFeature(
                        input_ids=inputs.input_ids,
                        attention_mask=inputs.attention_mask,
                        # token_type_ids=inputs.token_type_ids,
                        mask_token_id=mask_token_id,
                        label=label
                    ))

            if datum.Relation == "Explicit":
                continue
                # if datum.arg1_contains_arg2() or datum.arg2_contains_arg1():
                #     continue
                arg1:str = datum.Arg1_RawText.strip()
                arg2:str = datum.Arg2_RawText.strip()
                sense:str = datum.ConnHeadSemClass1
                connective:str = datum.Connective_RawText.strip()

                if sense not in self.label2words.keys():
                    continue
                mask_word = self.label2words[sense][0]  # roberta
                # mask_word = self.label2words[sense][0][1:]  # bert
                label = self.tokenizer.convert_tokens_to_ids(mask_word)

                roberta_prompt1 = "Arg1: " + arg1.capitalize() + ". Arg2: " + arg2.capitalize() + \
                                  ". The connective between Arg1 and Arg2 is " + connective.lower() + \
                                  ". In summary, the discourse relation between Arg1 and Arg2 is <mask>."
                                  #  ". In summary, Arg2 is the <mask> of Arg1."

                inputs = self.tokenizer(roberta_prompt1, max_length=512, truncation=True)
                if self.tokenizer.mask_token_id not in inputs.input_ids:  # 如果prompt的总长度超过512限制则舍弃
                    continue
                mask_token_id = inputs.input_ids.index(self.tokenizer.mask_token_id)

                if self.mode in ["train", "val", "test"]:
                    sense_list.append(sense)
                    samples.append(InputSample(
                        arg1=arg1, arg2=arg2,
                        connective=connective,
                        sense=sense
                    ))
                    features.append(InputFeature(
                        input_ids=inputs.input_ids,
                        attention_mask=inputs.attention_mask,
                        # token_type_ids=inputs.token_type_ids,
                        mask_token_id=mask_token_id,
                        label=label
                    ))

        # print(dict(Counter(sense_list)))
        print(f"{str(len(samples))} samples, {str(len(features))} features in total for {self.mode}")

        return samples, features

    def __len__(self):
        return len(self.features)

    def __getitem__(self, index):
        return self.features[index]

    @staticmethod
    def collate_fn(batch):
        test = batch[0].label is None
        max_len = min(max([len(x.input_ids) for x in batch]), 512)

        # 将batch_size条feature转换成Tensor
        input_ids = torch.tensor(sequence_padding([x.input_ids for x in batch], length=max_len))
        attention_mask = torch.tensor(sequence_padding([x.attention_mask for x in batch], length=max_len))
        # token_type_ids = torch.tensor(sequence_padding([x.token_type_ids for x in batch], length=max_len))
        mask_token_ids = torch.tensor([x.mask_token_id for x in batch])
        labels = torch.tensor([x.label for x in batch]) if not test else None
        batch = InputBatch(
            input_ids=input_ids,
            attention_mask=attention_mask,
            # token_type_ids=token_type_ids,
            mask_token_ids=mask_token_ids,
            labels=labels
        )
        return batch

class PromptDataModule(pl.LightningDataModule):

    dataset_mapping = {
        'conll16': CoNll16Dataset,
        'pdtb2': PDTB2Dataset
    }

    def __init__(self, config):
        super().__init__()
        self.config = config.data
        # self.tokenizer = BertTokenizerFast.from_pretrained(config.data.tokenizer)
        self.tokenizer = RobertaTokenizerFast.from_pretrained(config.data.tokenizer)
        print_string("configuration of datamodule")
        print_config(self.config)
        self.DATASET = self.dataset_mapping[self.config.dataset]

    def setup(self, stage=None):
        """
        根据模型运行的阶段，加载对应的数据，并实例化Dataset对象
        """
        if stage == 'fit' or stage is None:
            self.trainset = self.DATASET(self.config, self.tokenizer, dataset_mode='train')
            self.valset = self.DATASET(self.config, self.tokenizer, dataset_mode='val')

        if stage == 'test' or stage is None:
            self.testset = self.DATASET(self.config, self.tokenizer, dataset_mode='test')

    def train_dataloader(self):
        return DataLoader(self.trainset, batch_size=self.config.train_bsz, shuffle=True, collate_fn=self.trainset.collate_fn, num_workers=4)

    def val_dataloader(self):
        return DataLoader(self.valset, batch_size=self.config.val_bsz, shuffle=False, collate_fn=self.valset.collate_fn, num_workers=4)

    def test_dataloader(self):
        return DataLoader(self.testset, batch_size=self.config.test_bsz, shuffle=False, collate_fn=self.testset.collate_fn, num_workers=4)

def test_batch():
    config = Config.create({
        "data": {
            'dataset': 'pdtb2',
            'tokenizer': "roberta-large",
            'train_path': os.path.join(PROJ_DIR, "data/causal_relation/pdtb2/dataset/train.csv"),
            'val_path': os.path.join(PROJ_DIR, "data/causal_relation/pdtb2/dataset/dev.csv"),
            'test_path': os.path.join(PROJ_DIR, "data/causal_relation/pdtb2/dataset/test.csv"),
            'mapping_path': os.path.join(PROJ_DIR, "data/causal_relation/pdtb2/pdtb_label2word_implicit.json"),
            'train_bsz': 32,
            'val_bsz': 32,
            'test_bsz': 32,
            'cache_dir': './cached/data_utils',
            'force_reload': True
        }
    })
    dm = PromptDataModule(config)
    dm.setup('fit')
    print_string("one sample example")
    print(dm.trainset.samples[0])
    print_string("one feature example")
    print(dm.trainset.features[0])
    print_string("one batch example")
    for batch in dm.train_dataloader():
        batch.info()
        break

if __name__ == '__main__':
    # test_batch()
    lm = LabelMapping(os.path.join(PROJ_DIR, "data/causal_relation/pdtb2/pdtb_label2word_implicit.json"))
    pprint(sorted(lm.words2label.items(), key=lambda x:x[1]))


"""
socket 套接字非阻塞示例
"""

from socket import *
from time import sleep, ctime

# 日志文件
f = open('log.txt','a+')

# tcp套接字
sockfd = socket()
sockfd.bind(('127.0.0.1', 8888))
sockfd.listen(3)

# 设置套接字为非阻塞
# sockfd.setblocking

# 设置超时检测
sockfd.settimeout(3)

while True:
        print("waiting for connect...")
        # 没有客户端链接每隔3s写一条日志
        try:
            connfd,addr = sockfd.accept()
        except (BlockingIOError,timeout) as e:
            sleep(3)
            f.write("%s ; %s\n"%(ctime(),e))
            f.flush()
        else:
            print("connect from...")
            data=connfd.recv(1024).decode()
            print(data)


"""
93. 复原 IP 地址
给定一个只包含数字的字符串，用以表示一个 IP 地址，返回所有可能从 s 获得的 有效 IP 地址 。你可以按任何顺序返回答案。

有效 IP 地址 正好由四个整数（每个整数位于 0 到 255 之间组成，且不能含有前导 0），整数之间用 '.' 分隔。

例如："0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址，但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。

示例 1：

输入：s = "25525511135"
输出：["255.255.11.135","255.255.111.35"]
示例 2：

输入：s = "0000"
输出：["0.0.0.0"]
示例 3：

输入：s = "1111"
输出：["1.1.1.1"]
示例 4：

输入：s = "010010"
输出：["0.10.0.10","0.100.1.0"]
示例 5：

输入：s = "101023"
输出：["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

提示：

0 <= s.length <= 3000
s 仅由数字组成

tag: 字符串 回溯
"""
from typing import List

class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        return self.restore(s, 4)

    def restore(self, s: str, count: int) -> List[str]:
        if len(s) < count:
            return []
        if count < 1:
            return []
        if count == 1:
            if len(s) > 3:
                return []
            if s[0] == '0' and len(s) > 1:
                return []
            if int(s) > 255:
                return []
            return [s]
        ret = []
        tmp = []
        if s[0] == '0':
            tmp.append([s[0], s[1:]])
        else:
            tmp.append([s[:1], s[1:]])
            tmp.append([s[:2], s[2:]])
            if int(s[:3]) <= 255:
                tmp.append([s[:3], s[3:]])
        for head, tail in tmp:
            tail_ret_list = self.restore(tail, count - 1)
            if tail_ret_list:
                for tail_ret in tail_ret_list:
                    ret.append('.'.join([head, tail_ret]))
        return ret

if __name__ == '__main__':
    solution = Solution()
    s = "25525511135"
    print(solution.restoreIpAddresses(s))
    s = "0000"
    print(solution.restoreIpAddresses(s))
    s = "010010"
    print(solution.restoreIpAddresses(s))
    s = "101023"
    print(solution.restoreIpAddresses(s))


from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals

import logging.config
import os
import shutil
import sys
from sqlite3 import DatabaseError as SQLite3DatabaseError

import django
from diskcache.fanout import FanoutCache
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.management import call_command
from django.core.management.base import handle_default_options
from django.db.utils import DatabaseError

import kolibri
from kolibri.core.device.utils import device_provisioned
from kolibri.core.device.utils import provision_from_file
from kolibri.core.deviceadmin.exceptions import IncompatibleDatabase
from kolibri.core.deviceadmin.utils import get_backup_files
from kolibri.core.upgrade import matches_version
from kolibri.core.upgrade import run_upgrades
from kolibri.core.utils.cache import process_cache
from kolibri.deployment.default.sqlite_db_names import ADDITIONAL_SQLITE_DATABASES
from kolibri.plugins.utils import autoremove_unavailable_plugins
from kolibri.plugins.utils import check_plugin_config_file_location
from kolibri.plugins.utils import enable_new_default_plugins
from kolibri.plugins.utils import run_plugin_updates
from kolibri.utils.conf import KOLIBRI_HOME
from kolibri.utils.conf import LOG_ROOT
from kolibri.utils.conf import OPTIONS
from kolibri.utils.debian_check import check_debian_user
from kolibri.utils.logger import get_base_logging_config
from kolibri.utils.sanity_checks import check_content_directory_exists_and_writable
from kolibri.utils.sanity_checks import check_database_is_migrated
from kolibri.utils.sanity_checks import check_default_options_exist
from kolibri.utils.sanity_checks import check_django_stack_ready
from kolibri.utils.sanity_checks import check_log_file_location
from kolibri.utils.sanity_checks import DatabaseInaccessible
from kolibri.utils.sanity_checks import DatabaseNotMigrated
from kolibri.utils.sanity_checks import ensure_job_tables_created
from kolibri.utils.server import get_status
from kolibri.utils.server import NotRunning

logger = logging.getLogger(__name__)

def version_file():
    """
    During test runtime, this path may differ because KOLIBRI_HOME is
    regenerated
    """
    return os.path.join(KOLIBRI_HOME, ".data_version")

def version_updated(kolibri_version, version_file_contents):
    return kolibri_version != version_file_contents

def should_back_up(kolibri_version, version_file_contents):
    change_version = kolibri_version != version_file_contents
    return (
        # Only back up if there was a previous version
        version_file_contents
        # That version has changed
        and change_version
        # The previous version was not a dev version
        and "dev" not in version_file_contents
        # And the new version is not a dev version
        and "dev" not in kolibri_version
    )

def conditional_backup(kolibri_version, version_file_contents):
    if should_back_up(kolibri_version, version_file_contents):
        # Non-dev version change, make a backup no matter what.
        from kolibri.core.deviceadmin.utils import dbbackup
        from kolibri.core.deviceadmin.utils import default_backup_folder

        try:
            backup = dbbackup(version_file_contents)
            default_path = default_backup_folder()
            backups = get_backup_files()
            if len(backups) > 2:
                for old_backup in backups[2:]:
                    os.remove(os.path.join(default_path, old_backup))
            logger.info("Backed up database to: {path}".format(path=backup))
        except IncompatibleDatabase:
            logger.warning(
                "Skipped automatic database backup, not compatible with "
                "this DB engine."
            )

def get_version():
    try:
        version = open(version_file(), "r").read()
        return version.strip() if version else ""
    except IOError:
        return ""

def _migrate_databases():
    """
    Try to migrate all active databases. This should not be called unless Django has
    been initialized.
    """
    for database in settings.DATABASES:
        call_command("migrate", interactive=False, database=database)

    # load morango fixtures needed for certificate related operations
    call_command("loaddata", "scopedefinitions")

class DefaultDjangoOptions(object):
    __slots__ = ["settings", "pythonpath"]

    def __init__(self, settings, pythonpath):
        self.settings = settings
        self.pythonpath = pythonpath

def setup_logging(debug=False, debug_database=False):
    """
    Configures logging in cases where a Django environment is not supposed
    to be configured.
    """
    # Sets the global DEBUG flag to be picked up in other contexts
    # (Django settings)
    os.environ["KOLIBRI_DEBUG"] = str(debug)
    os.environ["KOLIBRI_DEBUG_LOG_DATABASE"] = str(debug_database)

    # Would be ideal to use the upgrade logic for this, but that is currently
    # only designed for post-Django initialization tasks. If there are more cases
    # for pre-django initialization upgrade tasks, we can generalize the logic here
    if matches_version(get_version(), "<0.12.4"):
        check_log_file_location()

    LOGGING = get_base_logging_config(
        LOG_ROOT, debug=debug, debug_database=debug_database
    )
    logging.config.dictConfig(LOGGING)

def _setup_django():
    """
    Do our django setup - separated from initialize to reduce complexity.
    """
    try:
        django.setup()

    except (DatabaseError, SQLite3DatabaseError) as e:
        if "malformed" in str(e):
            logger.error(
                "Your database appears to be corrupted. If you encounter this,"
                "please immediately back up all files in the .kolibri folder that"
                "end in .sqlite3, .sqlite3-shm, .sqlite3-wal, or .log and then"
                "contact Learning Equality. Thank you!"
            )
        raise

def _copy_preseeded_db(db_name, target=None):
    target = target or "{}.sqlite3".format(db_name)
    target = os.path.join(KOLIBRI_HOME, target)
    if not os.path.exists(target):
        try:
            import kolibri.dist

            db_path = os.path.abspath(
                os.path.join(
                    os.path.dirname(kolibri.dist.__file__),
                    "home/{}.sqlite3".format(db_name),
                )
            )
            shutil.copyfile(db_path, target)
            logger.info(
                "Copied preseeded database from {} to {}".format(db_path, target)
            )
        except (ImportError, IOError, OSError):
            logger.warning(
                "Unable to copy pre-migrated database from {} to {}".format(
                    db_path, target
                )
            )

def _upgrades_before_django_setup(updated, version):
    if version and updated:
        check_plugin_config_file_location(version)

    # Do this here so that we can fix any issues with our configuration file before
    # we attempt to set up django.
    autoremove_unavailable_plugins()

    if updated:
        # Reset the enabled plugins to the defaults
        # This needs to be run before dbbackup because
        # dbbackup relies on settings.INSTALLED_APPS
        enable_new_default_plugins()

    # Ensure that we have done all manipulations of our plugins registry before
    # we do the check for options.ini as that will invoke our plugin registry.
    # Check if there is an options.ini file exist inside the KOLIBRI_HOME folder
    check_default_options_exist()

    if OPTIONS["Database"]["DATABASE_ENGINE"] == "sqlite":
        # If we are using sqlite,
        # we can shortcut migrations by using the preseeded databases
        # that we bundle in the Kolibri whl file.
        if not version:
            logger.info("Attempting to setup using pre-migrated databases")
            # Only copy the default database if this is a fresh install
            _copy_preseeded_db("db", target=OPTIONS["Database"]["DATABASE_NAME"])

        if not version or updated:
            # If this is an upgrade, it is possible we've added an additional
            # database, so we can attempt to copy a preseeded database here.
            for db_name in ADDITIONAL_SQLITE_DATABASES:
                _copy_preseeded_db(db_name)

def _post_django_initialization():
    # Import here to prevent the module level access to Kolibri options
    # which causes premature registration of Kolibri plugins.
    from kolibri.deployment.default.cache import CACHES

    if "process_cache" in CACHES:  # usually it means not using redis
        if "DatabaseCache" not in CACHES["process_cache"]["BACKEND"]:
            try:
                process_cache.cull()
            except SQLite3DatabaseError:
                shutil.rmtree(process_cache.directory, ignore_errors=True)
                os.mkdir(process_cache.directory)
                process_cache._cache = FanoutCache(
                    process_cache.directory,
                    settings.CACHES["process_cache"]["SHARDS"],
                    settings.CACHES["process_cache"]["TIMEOUT"],
                    **settings.CACHES["process_cache"]["OPTIONS"]
                )

def _upgrades_after_django_setup(updated, version):
    # If device is not provisioned, attempt automatic provisioning
    if not device_provisioned() and OPTIONS["Paths"]["AUTOMATIC_PROVISION_FILE"]:
        try:
            provision_from_file(OPTIONS["Paths"]["AUTOMATIC_PROVISION_FILE"])
        except ValidationError as e:
            logging.error(
                "Tried to automatically provision the device but received an error"
            )
            logging.error(e)

def initialize(  # noqa C901
    skip_update=False,
    settings=None,
    debug=False,
    debug_database=False,
    no_input=True,
    pythonpath=None,
):
    """
    This should be called before starting the Kolibri app, it initializes Kolibri plugins
    and sets up Django.
    """
    check_debian_user(no_input)

    setup_logging(debug=debug, debug_database=debug_database)

    default_options = DefaultDjangoOptions(settings, pythonpath)

    handle_default_options(default_options)

    version = get_version()

    updated = version_updated(kolibri.__version__, version)

    if not skip_update:
        _upgrades_before_django_setup(updated, version)

        try:
            ensure_job_tables_created()
        except Exception as e:
            logging.error(
                "The job tables were not fully migrated. Tried to "
                "create them in the database and an error occurred: "
                "{}".format(e)
            )
            raise

    _setup_django()

    _post_django_initialization()

    if updated and not skip_update:
        conditional_backup(kolibri.__version__, version)

        if version:
            logger.info(
                "Version was {old}, new version: {new}".format(
                    old=version, new=kolibri.__version__
                )
            )
        else:
            logger.info("New install, version: {new}".format(new=kolibri.__version__))
        update(version, kolibri.__version__)

    check_content_directory_exists_and_writable()

    if not skip_update:
        # Run any plugin specific updates here in case they were missed by
        # our Kolibri version based update logic.
        run_plugin_updates()

        check_django_stack_ready()

        try:
            check_database_is_migrated()
        except DatabaseNotMigrated:
            try:
                _migrate_databases()
            except Exception as e:
                logging.error(
                    "The database was not fully migrated. Tried to "
                    "migrate the database and an error occurred: "
                    "{}".format(e)
                )
                raise
        except DatabaseInaccessible as e:
            logging.error(
                "Tried to check that the database was accessible "
                "and an error occurred: {}".format(e)
            )
            raise

        _upgrades_after_django_setup(updated, version)

def update(old_version, new_version):
    """
    Called whenever a version change in kolibri is detected
    """

    logger.info("Running update routines for new version...")

    try:
        # Check if there are other kolibri instances running
        # If there are, then we need to stop users from starting kolibri again.
        get_status()
        logger.error(
            "There is a Kolibri server running. "
            "Running updates now could cause a database error. "
            "Please use `kolibri stop` and try again. "
        )
        sys.exit(1)

    except NotRunning:
        pass

    _migrate_databases()

    run_upgrades(old_version, new_version)

    with open(version_file(), "w") as f:
        f.write(kolibri.__version__)


n = int(input())
grid = [list(map(int, input().split())) for _ in range(n)]
field = [[0]*n for _ in range(n)]

result = 0
bomb = 0
bomb_list = []
for i in range(n):
    for j in range(n):
        if grid[i][j] == 1:
            bomb += 1
            bomb_list.append([i, j])

def explode_or_cleanup(num, x, y, v):
    field[x][y] += v
    if num == 1:
        dxs, dys = [-2, -1, 1, 2], [0, 0, 0, 0]
    elif num == 2:
        dxs, dys = [-1, 1, 0, 0], [0, 0, -1, 1]
    else:
        dxs, dys = [-1, -1, +1, +1], [-1, +1, -1, +1]
    for dx, dy in zip(dxs, dys):
        nx, ny = x+dx, y+dy
        if 0 <= nx < n and 0 <= ny < n:
            field[nx][ny] += v

def print_answer():
    exploded = 0
    global result
    for i in range(n):
        for j in range(n):
            if field[i][j] >= 1:
                exploded += 1
    result = max(exploded, result)

# Phase = (bomb)개
def explode(phase):
    # 탈출 로직 = 그리드 안 1의 개수만큼 돌았을 때
    if phase == bomb + 1:
        print_answer()
        return

    # 각 폭탄 경우마다 칠할 수 있는 곳은 1로 바꿔놓기

    i, j = bomb_list[phase-1]
    # print(i, j)
    for num in range(1, 4):
        # print(f'num:{num}')
        explode_or_cleanup(num, i, j, 1)
        # print('explode')
        # print(field)
        explode(phase + 1)
        # print('cleanup')
        explode_or_cleanup(num, i, j, -1)# cleanup logic
        # print(field)
    # print()
    return

# print(bomb_list)
explode(1)
print(result)

곽민규/백트래킹/ch1/강력한 폭발.py


"""Median calculator."""
"""ENTER YOUR SOLUTION HERE!"""
def median(numbers):
    numbers = sorted(numbers)
    n = len(numbers)
    index = n // 2
    if n % 2:
        return numbers[index]
    else:
        return (sum(numbers[index-1:index+1]))/2

while True:
    try:
        print("Enter a list of numbers separated by commas: ")
        numbers = [float(value) for value in input().split(",")]
    except ValueError:
        print("Some input could not be converted to a number!")
    else:
        break
print(numbers)
medianResult = median(numbers)
print(medianResult)


"""Given two words word1 and word2, find the minimum number of steps
required to make word1 and word2 the same, where in each step you can
delete one character in either string."""

class Solution(object):
    def minDistance(self, word1, word2):
        n = len(word1)
        m = len(word2)
        dp = [[0 for i in range(m+1)] for i in range(n+1)]
        for i in range(n+1):
            for j in range(m+1):
                if i == 0 or j == 0:
                    dp[i][j] = 0
                elif word1[i-1] == word2[j-1]:
                    dp[i][j] = 1 + dp[i-1][j-1]
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])
        return n + m - 2*dp[n][m]


import csv
import re
import matplotlib.pyplot as plt
from datetime import datetime

def error_reader(filename):
    with open(filename, "r") as error_log:
        ourlist = []
        for x in error_log:
            if("djovanoska" in x):
                ourlist.append(x)

        ourlist = ''.join(ourlist)
        regexp = r"(?<=\[)(.*?)(?=\])"
        errordata = re.findall(regexp, ourlist)
        return(errordata)

def write_csv(errorlist):
    with open('error_log.csv', 'w') as csvfile:
        writer = csv.writer(csvfile)
        header = ['timestamp ', 'error ', 'pid ', 'requestby ']
        writer.writerow(header)
        count =  0
        for item in errorlist:
            if count == 0:
                time = item
                count += 1
            elif count == 1:
                type = item
                count +=1
            elif count == 2:
                pid = item
                count +=1
            elif count == 3:
                client = item
                writer.writerow((time, type, pid, client))
                count = 0

    print("Write Successful...")

def create_error_timeline(errorlist):
    timestamps = errorlist[::4]
    timestamps = [datetime.strptime(ts, "%a %b %d %H:%M:%S.%f %Y") for ts in timestamps]

    plt.figure(figsize=(10, 6))
    plt.plot(timestamps, range(len(timestamps)), marker='o', linestyle='-', color='red')
    plt.xlabel('Timestamp')
    plt.ylabel('Error Occurrences')
    plt.title('Error Occurrences Timeline')
    plt.xticks(rotation=45)
    plt.tight_layout()
    # plt.show()
    plt.savefig('error_timeline.pdf')
    print("Plot saved as error_timeline.pdf")

if __name__ == "__main__":
    error_list = error_reader('/var/log/apache2/error_log')
    write_csv(error_list)

    create_error_timeline(error_list)


import random

HANGMAN_PICS = ['''
       +---+
           |
           |
           |
          ===''', '''
       +---+
       O   |
           |
           |
          ===''', '''
       +---+
       O   |
       |   |
           |
          ===''', '''
       +---+
       O   |
      /|   |
           |
          ===''', '''
       +---+
       O   |
      /|\  |
           |
          ===''', '''
       +---+
       O   |
      /|\  |
      /    |
          ===''', '''
       +---+
       O   |
      /|\  |
      / \  |
          ===''']

words = """
ant baboon badger bat bear beaver camel cat clam cobra cougar coyote crow
deer dog donkey duck eagle ferret fox frog goat goose hawk
lion lizard llama mole monkey moose mouse mule newt otter owl panda
parrot pigeon python rabbit ram rat raven rhino salmon seal shark sheep
skunk sloth snake spider stork swan tiger toad trout turkey turtle
weasel whale wolf wombat zebra""".split()

name= input('Please Enter your name: \n')

print(f"Welcome to hangman game, {name}")

print('---------------------')
print('')
print('Try to guess the word in less than 7 attempts:')
word = random.choice(words)
print(word)
validletters= 'abcdefghijklmnopkrstuvwxyz'
uword = ['-' for i in word]
num = 0
att = 7
guessed = []
while '-' in uword:
    print(''.join(uword))
    guess = input('Guess a letter: \n').lower()
    if guess == '' or guess not in validletters :
        print('This letter is not a valid guess, try again')
        continue
    elif guess in word and guess not in guessed:
        index=word.index(guess)
        uword[index] = guess
        guessed.append(guess)
        if '-' not in uword:
            print('Congratulations, you did it')
            break

    elif guess in word and guess in guessed:
        index=word.index(guess)
        sindex=word.index(guess, index+1)
        uword[sindex] = guess
        if '-' not in uword:
            print('Congratulations, you did it')
            break

    else:
        att -= 1
        print(f"You have {att} left")
        if att == 0:
            print('You ran out of attempts, Game Over')
            break
        try:
            print(HANGMAN_PICS[num])
            num+=1
        except IndexError:
            print('Game Over')
            break


import pandas as pd
import os

CHROMS_DIR = '/home/mminbay/summer_research/summer23_aylab/data/imputed_data/FAULTY_dominant_model/'
SELECT_PATH = '/home/mminbay/summer_research/summer23_aylab/data/dom_overall/feat_select/chi2_top250.csv'

def main():
    select_snps = pd.read_csv(SELECT_PATH, index_col = 0)['SNP'].tolist()
    files = [file for file in os.listdir(CHROMS_DIR) if '.csv' in file]
    result = pd.DataFrame()
    first = pd.read_csv(os.path.join(CHROMS_DIR, files[0]), index_col = 0).sort_values('ID_1')
    result['ID_1'] = first['ID_1']
    result['Sex'] = first['Sex']
    result['PHQ9_binary'] = first['PHQ9_binary']

    columns_set = set(first.columns.tolist())
    for snp in select_snps:
        if snp in columns_set:
            result[snp] = first[snp]

    for file in files[1:]:
        df = pd.read_csv(os.path.join(CHROMS_DIR, file), index_col = 0).sort_values('ID_1')
        columns_set = set(df.columns.tolist())
        for snp in select_snps:
            if snp in columns_set:
                result[snp] = df[snp]

    result.to_csv(os.path.join(SELECT_PATH, '250snps_overall.csv'))

if __name__ == '__main__':
    main()


#!/usr/bin/env python3
"""  Function that adds two matrices element-wise """

def add_matrices2D(mat1, mat2):
    """ adds two matrices element-wise """

    shape1 = [len(mat1), len(mat1[0])]
    shape2 = [len(mat2), len(mat2[0])]

    if shape1 != shape2:
        return None

    response = []

    # run trough first matrix and get each index and row
    for i, row1 in enumerate(mat1):
        row2 = mat2[i]
        # add each element of the both list or rows and generates a new row
        new_row = [row1[j] + row2[j] for j in range(shape1[1])]
        response.append(new_row)

    return response


#
# ps1pr3.py - Problem Set 1, Problem 3
#
# Functions with numeric inputs
#
# name: abdulshaheed alqunber
# email: asq@bu.edu
#

# function 0
def opposite(x):
    """ returns the opposite of its input
        input x: any number (int or float)
    """
    return -1*x

# put your definitions for the remaining functions below

# function 1
def root(x):
    """ returns the the square root of input x"""
    return x**0.5

# function 2
def gap(num1, num2):
    """ returns the "gap" in positive value between the two inputs"""
    if num1 == num2:
        return 0
    elif num1 >= num2:
        return num1 - num2
    elif num1 <= num2:
        return num2 - num1

# function 3
def larger_gap(a1, a2, b1, b2):
    """compute the gap between a1 and a2 and the gap between b1 and b2
    and returns either gap if they are equal
    otherwise returns the larger gap"""
    gap1 = gap(a1, a2)
    gap2 = gap(b1, b2)
    if gap1 == gap2:
        return gap1
    elif gap1 >= gap2:
        return gap1
    elif gap1 <= gap2:
        return gap2

# function 4
import math     #to get the square root function
def distance(x1, y1, x2, y2):
    """compute and returns the distance value between
    two points in the coordinates system"""
    x = square_diff(x1,x2)
    y = square_diff(y1,y2)
    summation = x + y
    dist = summation ** 0.5
    return dist

def square_diff(x,y):
    s = (y - x) **2
    return s

# sample test call for function 0
print('opposite(-8) returns', opposite(-8))

# optional but encouraged: add test calls for your functions below
print("root(9) returns", root(9))

print("gap(11, 9) returns", gap(11, 9))

print("larger_gap(9, 4, 6, 8) returns", larger_gap(9, 4, 6, 8))

print("distance(6, 8, 9, 4) returns", distance(6, 8, 9, 4))


from bs4 import BeautifulSoup
from yyyy_mm_dd import *

def test_id(testId):
    return {"data-testid": testId}

def extract_10_day_forecast(html):
    soup = BeautifulSoup(html, features='html.parser')
    daily_forecast = soup.find(attrs=test_id("DailyForecast"))
    summaries = daily_forecast.find_all("summary")

    result = []
    for delta, summary in enumerate(summaries):
        item = extract_day_forecast(summary, delta)
        result.append(item)

    return result

def extract_day_forecast(summary, delta):
    item = {
        "type": "daily",
        "forecast_delta": delta,
        "precipitation": get_precipitation(summary),
        "summary": summary.find(attrs=test_id("wxIcon")).find("span").get_text()
    }
    temperature = summary.find(attrs=test_id("detailsTemperature"))
    item["max"] = parse_temperature(temperature.find(
        attrs=test_id("TemperatureValue")))
    item["min"] = parse_temperature(temperature.find(attrs=test_id(
        "lowTempValue")).find("span"))

    return item

def extract_hourly_forecast(html, now=now()):
    soup = BeautifulSoup(html, features='html.parser')
    daily_forecast = soup.find(attrs=test_id("HourlyForecast"))
    summaries = daily_forecast.find_all("summary")

    delta = 0
    # if it's quarter past the hour TWC shows forecast for next hour
    if to_datetime(now).minute > 15:
        delta = 1
    result = []
    for summary in summaries:
        item = extract_hour_forecast(summary, delta)
        delta = delta + 1
        result.append(item)

    return result

def extract_hour_forecast(summary, delta):
    item = {
        "type": "hourly",
        "forecast_delta": delta,
        "precipitation": get_precipitation(summary),
        "summary": summary.find(attrs=test_id("wxIcon")).find("span").get_text()
    }
    temperature = summary.find(attrs=test_id("detailsTemperature"))
    item["temperature"] = parse_temperature(temperature.find(
        attrs=test_id("TemperatureValue")))

    return item

def get_precipitation(summary):
    precipitation = summary.find(attrs=test_id("Precip"))
    if precipitation:
        precipitation = precipitation.find(
            attrs=test_id("PercentageValue")).get_text()
        precipitation = int(precipitation.replace("%", ""))
        return precipitation

    return 0

def parse_temperature(node):
    temperature = node.get_text().replace("°", "")
    try:
        return int(temperature)
    except:
        return None


from abc import (
    ABCMeta,
    abstractmethod
)

from lib.utils.misc import load_config

class BaseSourceGenerator(object):
    __metaclass__ = ABCMeta

    def __init__(self, **kwargs):
        self.root_config = load_config()
        self.generator_config = load_config()['source_generator']

    @abstractmethod
    def generate_source_data(self, **kwargs):
        raise NotImplementedError


def calculateHandlen(hand):
    """
    Returns the length (number of letters) in the current hand.

    hand: dictionary (string int)
    returns: integer
    """
    hand_value = 0
    for k, v in hand.items():
    	hand_value += v
    return hand_value


import random

# prompt format "a something of a" + "subject" + "of something(optional)", + "comma-separated modifiers" + "4k, 8k"

subjects = []
styles = []
adjectives = []
aspect_ratios = ["3:2", "2:3"]
outfile = "prompts.txt"

def loadFile(filename, inarr):
    f = open(filename)
    for line in f:
        inarr.append(line.rstrip())

prompts = []
loadFile('subjects', subjects)
loadFile('styles', styles)
loadFile('adjectives', adjectives)

print(subjects)

prompt_count = 500
max_adjectives = 2
max_styles = 8

adj_count = random.randint(1, max_adjectives)
style_count = random.randint(1, max_styles)
subj_length = len(subjects)
adj_length = len(adjectives)
style_length = len(styles)
out = open(outfile, 'w')

for _ in range(prompt_count):
    new_prompt = "a "
    for _ in range(random.randint(1, max_adjectives) + 1):
        adj = random.randint(0,adj_length - 2)
        new_prompt = new_prompt + " " + adjectives[adj]
    subj = random.randint(0, subj_length - 2)
    new_prompt = new_prompt + " of a " + subjects[subj] + ","
    for _ in range(random.randint(1, max_styles) + 1):
        style = random.randint(0, style_length - 2)
        new_prompt = new_prompt + " " + styles[style] + ","
    new_prompt = new_prompt + " --ar " + aspect_ratios[random.randint(0,1)]
    out.write(new_prompt + "\n")


from os.path import join
import numpy as np
import torch
import pandas as pd

def synthesize_data(f, f_name, project_root, input_dim, N=10000):
    input = torch.rand(N, input_dim)
    output = f(input)
    y = [np.random.choice([1, 0], p=[p.item(), 1 - p.item()]) for p in output]
    df = pd.DataFrame(
        torch.cat((input, output), dim=1).detach().numpy(),
        columns=["x1", "x2", "target_p"],
    )
    df["target_y"] = y
    # write a pandas dataframe to gzipped CSV file

    path = join(project_root, f"data/raw/{f_name}.csv.gz")
    print("saving to :", path)
    df.to_csv(path, index=False, compression="gzip")
    print("saved")
    return df, path


'''
@ Youssef Dahab
@ 2016 / 06 / 16
'''
"""
 Pygame base template for opening a window

 Sample Python/Pygame Programs
 Simpson College Computer Science
 http://programarcadegames.com/
 http://simpson.edu/computer-science/

 Explanation video: http://youtu.be/vRB_983kUMc

Font/Text:

http://programarcadegames.com/python_examples/f.php?file=move_game_controller.py
"""

import pygame
import random
import time

# Define beginning colours and values.
PI = 3.141592654
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
ORANGE = (255, 140, 0)

''' Subprogram for point system.'''
def point_System(player_1_score, player_2_score):
     player_1_score = player_1_score
     player_2_score = player_2_score

     # Check if player 2 scored a goal.
     if(ball.rect.x <= 40 and ball.rect.y >= 310 and ball.rect.y <= 490):
          player_2_score = player_2_score + 1

     # Check if player 1 scored a goal.
     elif (ball.rect.x >= 1240 and ball.rect.y >= 310 and ball.rect.y <= 490):
          player_1_score = player_1_score + 1

     return (player_1_score, player_2_score)

''' Subprogram to draw the soccer field.'''
def draw_soccer_field():

     # Draw the soccer field.
     pygame.draw.rect(screen, GREEN, [0, 0, 1300, 800], 0)
     pygame.draw.rect(screen, WHITE, [50, 20, 1200, 760], 5)
     pygame.draw.line(screen, WHITE, [650, 20], [650, 780], 5)
     pygame.draw.circle(screen, WHITE, [650, 400], 100, 5)

     # Draw the nets.
     pygame.draw.rect(screen, RED, [0, 300, 50, 200], 5)
     pygame.draw.rect(screen, BLUE, [1250, 300, 50, 200], 5)

# Create class for soccer players.
class Player(pygame.sprite.Sprite):
     def __init__(self, colour, collision_list):

          # Call the parent class (Sprite) constructor.
          pygame.sprite.Sprite.__init__(self)

          # Attributes for Player class.
          self.collide_list = collision_list
          self.radius = 0
          self.change_of_x = 0
          self.change_of_y = 0
          self.colour = colour
          self.width = 40
          self.height = 40
          self.image = pygame.Surface([self.width,self.height])
          self.image.fill(WHITE)
          self.image.set_colorkey(WHITE)

          # Draw the players.
          pygame.draw.ellipse(self.image, self.colour, [0, 0, self.width, self.height])
          self.rect = self.image.get_rect()
          self.rect.x = 0
          self.rect.y = 0

     # Method to move the player.
     def move(self):
          self.rect.x += self.change_of_x
          self.rect.y += self.change_of_y

          # Setting boundries for the players.
          if(self.rect.x <=0 or self.rect.x >=1260):
               self.change_of_x = 0

          elif(self.rect.y <=0 or self.rect.y >=760):
               self.change_of_y = 0

     # Method to check for colliding.
     def check_colliding(self):
          collide_list = pygame.sprite.spritecollide(self, self.collide_list, False)

          # If player collides with other player, they bounce off each other.
          if collide_list:
               self.change_of_x = self.change_of_x * -1
               self.change_of_y = self.change_of_y * -1

     # Method to update the players.
     def update(self):
          self.check_colliding()
          self.move()

# Inheritance of Player class.
class Soccer_ball(Player):
     def __init__(self, collision_list):

          # Call the parent class (Sprite) constructor.
          Player.__init__(self, BLACK, collision_list)

          # Attributes for Soccer ball class.
          self.ball_x = 640
          self.ball_y = 400
          self.ball_change_x = 15
          self.ball_change_y = 5
          self.collide_list = collision_list
          self.width = 20
          self.height = 20
          self.image = pygame.Surface([self.width,self.height])
          self.image.fill(WHITE)
          self.image.set_colorkey(WHITE)

          # Draw the soccer ball.
          pygame.draw.ellipse(self.image, self.colour, [0, 0, self.width, self.height])
          self.rect = self.image.get_rect()
          self.rect.x = 630
          self.rect.y = 380

     # Method to move the ball
     def move(self):
          self.rect.x += self.ball_change_x
          self.rect.y += self.ball_change_y

          # Boundries for soccer ball.
          if(self.rect.x <=0 and self.rect.y >= 490):
               self.ball_change_x = self.ball_change_x * -1

          elif(self.rect.x <= 0 and self.rect.y <= 310):
               self.ball_change_x = self.ball_change_x * -1

          elif(self.rect.x >=1280 and self.rect.y >= 490):
               self.ball_change_x = self.ball_change_x * -1

          elif(self.rect.x >=1280 and self.rect.y <= 310):
               self.ball_change_x = self.ball_change_x * -1

          elif(self.rect.x >=0 and self.rect.y <=0):
               self.ball_change_y = self.ball_change_y * -1

          elif(self.rect.x >=0 and self.rect.y >= 780):
               self.ball_change_y = self.ball_change_y * -1

     # Method to check for collision with soccer ball.
     def check_colliding(self):
          collide_list = pygame.sprite.spritecollide(self, self.collide_list, False)

          # If ball collides with a player, it bounces off the player.
          if collide_list:
               self.ball_change_x = self.ball_change_x * -1
               self.ball_change_y = random.randrange(-3, 3)

     # Method to update the soccer ball.
     def update(self):
          self.check_colliding()
          self.move()

# Creating lists for collisions.
ball_collision_list = pygame.sprite.Group()
player1_collision_list = pygame.sprite.Group()
player2_collision_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()

# Creating players.
player_1 = Player(RED, player1_collision_list)
player_2 = Player(BLUE, player2_collision_list)

# Creating stats for Player 1.
player_1.rect.x = 50
player_1.rect.y = 400
player_1.radius = 20
player_1.change_of_x = 0
player_1.change_of_y = 0

# Creating stats for Player 2.
player_2.rect.x = 1200
player_2.rect.y = 400
player_2.radius = 20
player_2.change_of_x = 0
player_2.change_of_y = 0

# Creating soccer ball.
ball = Soccer_ball(ball_collision_list)

# Creating lists to check for collisions.
all_sprites_list.add(player_1)
all_sprites_list.add(player_2)
all_sprites_list.add(ball)
player1_collision_list.add(player_2)
player2_collision_list.add(player_1)
ball_collision_list.add(player_1)
ball_collision_list.add(player_2)

# Initializing pygame.
pygame.init()

# Set the width and height of the screen.
size = (1300, 800)
screen = pygame.display.set_mode(size)

pygame.display.set_caption("SOCCER BATTLE!")

# Select the font to use, size, bold, italics.
font = pygame.font.SysFont('Calibri', 50, True, False)

# Initial score for point system.
player_1_score = 0
player_2_score = 0

# Create an empty list for sparks.
spark_list = []
spark_color = [YELLOW, RED, ORANGE, YELLOW, ORANGE]

# Loop to create random sparks and add them to a list.
for i in range(100):
     x = random.randrange(0, 1300)
     y = random.randrange(0, 800)
     spark_list.append([x, y])

# Background image.
screen.fill(WHITE)

# Used to manage how fast the screen updates.
clock = pygame.time.Clock()

# Loops until user(s) click close button.
done = False

# Help with displaying instructions.
instructions_read = False

# Main program loop.
while not done:

     # Main event loop.
     for event in pygame.event.get():
          if event.type == pygame.QUIT:
               done = True

          # Player 1 and player 2 pressing down keys.
          elif event.type == pygame.KEYDOWN:

               # Player 2 pressing down arrow keys.
               if event.key == pygame.K_UP:
                    player_2.change_of_y = -3

               if event.key == pygame.K_DOWN:
                    player_2.change_of_y = 3

               if event.key == pygame.K_RIGHT:
                    player_2.change_of_x = 3

               if event.key == pygame.K_LEFT:
                    player_2.change_of_x = -3

               # Player 1 pressing down WASD keys.
               if event.key == pygame.K_w:
                    player_1.change_of_y = -3

               if event.key == pygame.K_s:
                    player_1.change_of_y = 3

               if event.key == pygame.K_d:
                    player_1.change_of_x = 3

               if event.key == pygame.K_a:
                    player_1.change_of_x = -3

          # Player 1 and player 2 lets go of keys.
          elif event.type == pygame.KEYUP:

               # Player 2 lets go of arrow keys.
               if event.key == pygame.K_UP:
                    player_2.change_of_y = 0

               if event.key == pygame.K_DOWN:
                    player_2.change_of_y = 0

               if event.key == pygame.K_RIGHT:
                    player_2.change_of_x = 0

               if event.key == pygame.K_LEFT:
                    player_2.change_of_x = 0

            # Player 1 lets go of WASD keys.
               if event.key == pygame.K_w:
                    player_1.change_of_y = 0

               if event.key == pygame.K_s:
                    player_1.change_of_y = 0

               if event.key == pygame.K_d:
                    player_1.change_of_x = 0

               if event.key == pygame.K_a:
                    player_1.change_of_x = 0

     # Generate the soccer field.
     draw_soccer_field()

     # Displaying initial score of soccer game.
     text = font.render(str(player_1_score) + "-" + str(player_2_score), True, BLACK)
     screen.blit(text, [620, 25])

     # Check if player 1 or player 2 scored a goal.
     if(ball.rect.x <= 40 and ball.rect.y >= 310 and ball.rect.y <= 490 or ball.rect.x >= 1240 and ball.rect.y >= 310 and ball.rect.y <= 490):
          (player_1_score, player_2_score) = point_System(player_1_score, player_2_score)
          text = font.render(str(player_1_score) + "-" + str(player_2_score), True, BLACK)

          # Display score on screen.
          screen.blit(text, [620, 25])

          # Reset soccer ball and players.
          ball.rect.x = 650
          ball.rect.y = 400
          player_1.rect.x = 50
          player_1.rect.y = 400
          player_2.rect.x = 1200
          player_2.rect.y = 400
          ball.change_x = 0
          ball.change_y = 0
          all_sprites_list.update()
          all_sprites_list.draw(screen)

          # Continue soccer game.
          time.sleep(1)
          ball.change_x = random.randint(-15, 15)
          ball.change_y = random.randint(-3, 3)

     elif(player_1_score >= 3 or player_2_score >= 3):

          # Reset soccer ball and players to end game.
          ball.rect.x = 650
          ball.rect.y = 400
          player_1.rect.x = 50
          player_1.rect.y = 400
          player_2.rect.x = 1200
          player_2.rect.y = 400
          ball.change_x = 0
          ball.change_y = 0

     # Check if player 1 won the game.
     if(player_1_score >= 3):
          text = font.render("Congrats Player 1, YOU WIN!!!", True, RED)
          screen.blit(text, [400, 400])

          # Process each spark in the list
          for i in range(len(spark_list)):

               # Draw the spark
               pygame.draw.arc(screen,spark_color[random.randint(0,len(spark_color)-1)],[spark_list[i][0],spark_list[i][1], 50, 50], PI/2, PI, 5)
               pygame.draw.arc(screen,spark_color[random.randint(0,len(spark_color)-1)],[spark_list[i][0],spark_list[i][1], 50, 50], 3*PI/2, 2*PI, 5)

               # Move the sparks down 1 pixel.
               spark_list[i][1] += 1

     # Check if player 2 won the game.
     elif(player_2_score >= 3):
          text = font.render("Congrats Player 2, YOU WIN!!!", True, BLUE)
          screen.blit(text, [400, 400])

           # Process each spark in the list
          for i in range(len(spark_list)):

               # Draw the spark
               pygame.draw.arc(screen,spark_color[random.randint(0,len(spark_color)-1)],[spark_list[i][0],spark_list[i][1], 50, 50], PI/2, PI, 5)
               pygame.draw.arc(screen,spark_color[random.randint(0,len(spark_color)-1)],[spark_list[i][0],spark_list[i][1], 50, 50], 3*PI/2, 2*PI, 5)

               # Move the sparks down 1 pixel.
               spark_list[i][1] += 1

     # Displays instructions long enough for players to read them.
     while not instructions_read:
          text = font.render("First to 3 is the winner.", True, BLACK)
          screen.blit(text, [500, 400])
          pygame.display.flip()
          time.sleep(3)
          instructions_read = True

     # Generating players in game.
     all_sprites_list.update()
     all_sprites_list.draw(screen)

     # Update the screen with what we've drawn.
     pygame.display.flip()

     # Limit to 60 frames per second.
     clock.tick(60)

# Close the window and quit.
pygame.quit()


import torch
import math
import torch.nn as nn
import torch.nn.functional as F

from ntu_diar.scr.dataio.dataio import length_to_mask

class TDNNBlock(nn.Module):
    def __init__(
        self,
        in_channels,
        out_channels,
        kernel_size,
        dilation,
        activation=nn.ReLU,
        groups=1,
    ):
        super(TDNNBlock, self).__init__()
        self.conv = Conv1d(
            in_channels=in_channels,
            out_channels=out_channels,
            kernel_size=kernel_size,
            dilation=dilation,
            groups=groups,
        )
        self.activation = activation()
        self.norm = BatchNorm1d(input_size=out_channels)

    def forward(self, x):
        """ Processes the input tensor x and returns an output tensor."""
        return self.norm(self.activation(self.conv(x)))

class SERes2NetBlock(nn.Module):
    """An implementation of building block in ECAPA-TDNN, i.e.,
    TDNN-Res2Net-TDNN-SEBlock.
    Arguments
    ----------
    out_channels: int
        The number of output channels.
    res2net_scale: int
        The scale of the Res2Net block.
    kernel_size: int
        The kernel size of the TDNN blocks.
    dilation: int
        The dilation of the Res2Net block.
    activation : torch class
        A class for constructing the activation layers.
    groups: int
    Number of blocked connections from input channels to output channels.
    Example
    -------
    >>> x = torch.rand(8, 120, 64).transpose(1, 2)
    >>> conv = SERes2NetBlock(64, 64, res2net_scale=4)
    >>> out = conv(x).transpose(1, 2)
    >>> out.shape
    torch.Size([8, 120, 64])
    """

    def __init__(
        self,
        in_channels,
        out_channels,
        res2net_scale=8,
        se_channels=128,
        kernel_size=1,
        dilation=1,
        activation=nn.ReLU,
        groups=1,
    ):
        super().__init__()
        self.out_channels = out_channels
        self.tdnn1 = TDNNBlock(
            in_channels,
            out_channels,
            kernel_size=1,
            dilation=1,
            activation=activation,
            groups=groups,
        )
        self.res2net_block = Res2NetBlock(
            out_channels, out_channels, res2net_scale, kernel_size, dilation
        )
        self.tdnn2 = TDNNBlock(
            out_channels,
            out_channels,
            kernel_size=1,
            dilation=1,
            activation=activation,
            groups=groups,
        )
        self.se_block = SEBlock(out_channels, se_channels, out_channels)

        self.shortcut = None
        if in_channels != out_channels:
            self.shortcut = Conv1d(
                in_channels=in_channels,
                out_channels=out_channels,
                kernel_size=1,
            )

    def forward(self, x, lengths=None):
        """ Processes the input tensor x and returns an output tensor."""
        residual = x
        if self.shortcut:
            residual = self.shortcut(x)

        x = self.tdnn1(x)
        x = self.res2net_block(x)
        x = self.tdnn2(x)
        x = self.se_block(x, lengths)

        return x + residual

class AttentiveStatisticsPooling(nn.Module):
    """This class implements an attentive statistic pooling layer for each channel.
    It returns the concatenated mean and std of the input tensor.
    Arguments
    ---------
    channels: int
        The number of input channels.
    attention_channels: int
        The number of attention channels.
    Example
    -------
    >>> inp_tensor = torch.rand([8, 120, 64]).transpose(1, 2)
    >>> asp_layer = AttentiveStatisticsPooling(64)
    >>> lengths = torch.rand((8,))
    >>> out_tensor = asp_layer(inp_tensor, lengths).transpose(1, 2)
    >>> out_tensor.shape
    torch.Size([8, 1, 128])
    """

    def __init__(self, channels, attention_channels=128, global_context=True):
        super().__init__()

        self.eps = 1e-12
        self.global_context = global_context
        if global_context:
            self.tdnn = TDNNBlock(channels * 3, attention_channels, 1, 1)
        else:
            self.tdnn = TDNNBlock(channels, attention_channels, 1, 1)
        self.tanh = nn.Tanh()
        self.conv = Conv1d(
            in_channels=attention_channels, out_channels=channels, kernel_size=1
        )

    def forward(self, x, lengths=None):
        """Calculates mean and std for a batch (input tensor).
        Arguments
        ---------
        x : torch.Tensor
            Tensor of shape [N, C, L].
        """
        L = x.shape[-1]

        def _compute_statistics(x, m, dim=2, eps=self.eps):
            mean = (m * x).sum(dim)
            std = torch.sqrt(
                (m * (x - mean.unsqueeze(dim)).pow(2)).sum(dim).clamp(eps)
            )
            return mean, std

        if lengths is None:
            lengths = torch.ones(x.shape[0], device=x.device)

        # Make binary mask of shape [N, 1, L]
        mask = length_to_mask(lengths * L, max_len=L, device=x.device)
        mask = mask.unsqueeze(1)

        # Expand the temporal context of the pooling layer by allowing the
        # self-attention to look at global properties of the utterance.
        if self.global_context:
            # torch.std is unstable for backward computation
            # https://github.com/pytorch/pytorch/issues/4320
            total = mask.sum(dim=2, keepdim=True).float()
            mean, std = _compute_statistics(x, mask / total)
            mean = mean.unsqueeze(2).repeat(1, 1, L)
            std = std.unsqueeze(2).repeat(1, 1, L)
            attn = torch.cat([x, mean, std], dim=1)
        else:
            attn = x

        # Apply layers
        attn = self.conv(self.tanh(self.tdnn(attn)))

        # Filter out zero-paddings
        attn = attn.masked_fill(mask == 0, float("-inf"))

        attn = F.softmax(attn, dim=2)
        mean, std = _compute_statistics(x, attn)
        # Append mean and std of the batch
        pooled_stats = torch.cat((mean, std), dim=1)
        pooled_stats = pooled_stats.unsqueeze(2)

        return pooled_stats

class _BatchNorm1d(nn.Module):
    def __init__(
        self,
        input_shape=None,
        input_size=None,
        eps=1e-05,
        momentum=0.1,
        affine=True,
        track_running_stats=True,
        combine_batch_time=False,
        skip_transpose=False,
    ):
        super().__init__()
        self.combine_batch_time = combine_batch_time
        self.skip_transpose = skip_transpose

        if input_size is None and skip_transpose:
            input_size = input_shape[1]
        elif input_size is None:
            input_size = input_shape[-1]

        self.norm = nn.BatchNorm1d(
            input_size,
            eps=eps,
            momentum=momentum,
            affine=affine,
            track_running_stats=track_running_stats,
        )

    def forward(self, x):
        shape_or = x.shape
        if self.combine_batch_time:
            if x.ndim == 3:
                x = x.reshape(shape_or[0] * shape_or[1], shape_or[2])
            else:
                x = x.reshape(
                    shape_or[0] * shape_or[1], shape_or[3], shape_or[2]
                )

        elif not self.skip_transpose:
            x = x.transpose(-1, 1)

        x_n = self.norm(x)

        if self.combine_batch_time:
            x_n = x_n.reshape(shape_or)
        elif not self.skip_transpose:
            x_n = x_n.transpose(1, -1)

        return x_n

class BatchNorm1d(_BatchNorm1d):

    def __init__(self, *args, **kwargs):
        super().__init__(skip_transpose=True, *args, **kwargs)

class _Conv1d(nn.Module):

    def __init__(
        self,
        out_channels,
        kernel_size,
        input_shape=None,
        in_channels=None,
        stride=1,
        dilation=1,
        padding="same",
        groups=1,
        bias=True,
        padding_mode="reflect",
        skip_transpose=False,
        weight_norm=False,
    ):
        super().__init__()
        self.kernel_size = kernel_size
        self.stride = stride
        self.dilation = dilation
        self.padding = padding
        self.padding_mode = padding_mode
        self.unsqueeze = False
        self.skip_transpose = skip_transpose

        if input_shape is None and in_channels is None:
            raise ValueError("Must provide one of input_shape or in_channels")

        if in_channels is None:
            in_channels = self._check_input_shape(input_shape)

        self.in_channels = in_channels

        self.conv = nn.Conv1d(
            in_channels,
            out_channels,
            self.kernel_size,
            stride=self.stride,
            dilation=self.dilation,
            padding=0,
            groups=groups,
            bias=bias,
        )

        if weight_norm:
            self.conv = nn.utils.weight_norm(self.conv)

    def forward(self, x):

        if not self.skip_transpose:
            x = x.transpose(1, -1)

        if self.unsqueeze:
            x = x.unsqueeze(1)

        if self.padding == "same":
            x = self._manage_padding(
                x, self.kernel_size, self.dilation, self.stride
            )

        elif self.padding == "causal":
            num_pad = (self.kernel_size - 1) * self.dilation
            x = F.pad(x, (num_pad, 0))

        elif self.padding == "valid":
            pass

        else:
            raise ValueError(
                "Padding must be 'same', 'valid' or 'causal'. Got "
                + self.padding
            )

        wx = self.conv(x)

        if self.unsqueeze:
            wx = wx.squeeze(1)

        if not self.skip_transpose:
            wx = wx.transpose(1, -1)

        return wx

    def _manage_padding(
        self, x, kernel_size: int, dilation: int, stride: int,
    ):

        # Detecting input shape
        L_in = self.in_channels

        # Time padding
        padding = get_padding_elem(L_in, stride, kernel_size, dilation)

        # Applying padding
        x = F.pad(x, padding, mode=self.padding_mode)

        return x

    def _check_input_shape(self, shape):

        if len(shape) == 2:
            self.unsqueeze = True
            in_channels = 1
        elif self.skip_transpose:
            in_channels = shape[1]
        elif len(shape) == 3:
            in_channels = shape[2]
        else:
            raise ValueError(
                "conv1d expects 2d, 3d inputs. Got " + str(len(shape))
            )

        # Kernel size must be odd
        if self.kernel_size % 2 == 0:
            raise ValueError(
                "The field kernel size must be an odd number. Got %s."
                % (self.kernel_size)
            )
        return in_channels

    def remove_weight_norm(self):
        """Removes weight normalization at inference if used during training.
        """
        self.conv = nn.utils.remove_weight_norm(self.conv)

class Conv1d(_Conv1d):
    """1D convolution. Skip transpose is used to improve efficiency."""

    def __init__(self, *args, **kwargs):
        super().__init__(skip_transpose=True, *args, **kwargs)

class Res2NetBlock(nn.Module):
    def __init__(
        self, in_channels, out_channels, scale=8, kernel_size=3, dilation=1
    ):
        super(Res2NetBlock, self).__init__()
        assert in_channels % scale == 0
        assert out_channels % scale == 0

        in_channel = in_channels // scale
        hidden_channel = out_channels // scale

        self.blocks = nn.ModuleList(
            [
                TDNNBlock(
                    in_channel,
                    hidden_channel,
                    kernel_size=kernel_size,
                    dilation=dilation,
                )
                for i in range(scale - 1)
            ]
        )
        self.scale = scale

    def forward(self, x):
        """ Processes the input tensor x and returns an output tensor."""
        y = []
        for i, x_i in enumerate(torch.chunk(x, self.scale, dim=1)):
            if i == 0:
                y_i = x_i
            elif i == 1:
                y_i = self.blocks[i - 1](x_i)
            else:
                y_i = self.blocks[i - 1](x_i + y_i)
            y.append(y_i)
        y = torch.cat(y, dim=1)
        return y

class SEBlock(nn.Module):

    def __init__(self, in_channels, se_channels, out_channels):
        super(SEBlock, self).__init__()

        self.conv1 = Conv1d(
            in_channels=in_channels, out_channels=se_channels, kernel_size=1
        )
        self.relu = torch.nn.ReLU(inplace=True)
        self.conv2 = Conv1d(
            in_channels=se_channels, out_channels=out_channels, kernel_size=1
        )
        self.sigmoid = torch.nn.Sigmoid()

    def forward(self, x, lengths=None):
        """ Processes the input tensor x and returns an output tensor."""
        L = x.shape[-1]
        if lengths is not None:
            mask = length_to_mask(lengths * L, max_len=L, device=x.device)
            mask = mask.unsqueeze(1)
            total = mask.sum(dim=2, keepdim=True)
            s = (x * mask).sum(dim=2, keepdim=True) / total
        else:
            s = x.mean(dim=2, keepdim=True)

        s = self.relu(self.conv1(s))
        s = self.sigmoid(self.conv2(s))

        return s * x

class Linear(torch.nn.Module):

    def __init__(
        self,
        n_neurons,
        input_shape=None,
        input_size=None,
        bias=True,
        combine_dims=False,
    ):
        super().__init__()
        self.combine_dims = combine_dims

        if input_shape is None and input_size is None:
            raise ValueError("Expected one of input_shape or input_size")

        if input_size is None:
            input_size = input_shape[-1]
            if len(input_shape) == 4 and self.combine_dims:
                input_size = input_shape[2] * input_shape[3]

        # Weights are initialized following pytorch approach
        self.w = nn.Linear(input_size, n_neurons, bias=bias)

    def forward(self, x):
        if x.ndim == 4 and self.combine_dims:
            x = x.reshape(x.shape[0], x.shape[1], x.shape[2] * x.shape[3])

        wx = self.w(x)

        return wx

def get_padding_elem(L_in: int, stride: int, kernel_size: int, dilation: int):
    if stride > 1:
        padding = [math.floor(kernel_size / 2), math.floor(kernel_size / 2)]

    else:
        L_out = (
            math.floor((L_in - dilation * (kernel_size - 1) - 1) / stride) + 1
        )
        padding = [
            math.floor((L_in - L_out) / 2),
            math.floor((L_in - L_out) / 2),
        ]
    return padding


import pygame as pg
from PyQt5.QtWidgets import QApplication, QDialog, QListWidget, QVBoxLayout
from pathlib import Path
from threading import Thread
import sys, os

from header import *

class SearchBar:
    def __init__(self, x, y, text):
        # color, font, text, and various variables for this searchbar
        self.color = pg.Color(*COLOR_PAL[WHITE])
        self.font = pg.font.Font(CHALK_FONT, CHALK_FONTSIZE)
        self.default_text = text
        self.text = text
        self.active = False
        self.results = []
        # a text surface and a rectangle hitbox makes up a search bar
        self.text_surface = self.font.render(text, True, self.color)
        self.rect = pg.Rect(x, y, self.text_surface.get_width() + 10, CHALK_FONTSIZE + 5)

    def handle_event(self, event):
        interacted = False
        if event.type == pg.MOUSEBUTTONDOWN and event.button == 1:
            # click on search bar to activate it
            if self.rect.collidepoint(event.pos):
                interacted = True
                self.active = not self.active
            else:
                self.active = False
            # re-render the text for the search bar
            self.text = '' if self.active else self.default_text
            self.text_surface = self.font.render(self.text, True, self.color)
        # keyboard input when active
        elif self.active and event.type == pg.KEYDOWN:
            interacted = True
            # {ENTER} searches
            if event.key == pg.K_RETURN:
                Thread(target=self._search, args=(self.text,), daemon=True).start()
            # {BACKSPACE} removes 1 char, , or 1 word if {CTRL} is held down
            elif event.key == pg.K_BACKSPACE:
                keystates = pg.key.get_pressed()
                if keystates[pg.K_LCTRL]:
                    i = self.text.rstrip().rfind(" ")
                    self.text = self.text[:i+1] if i >= 0 else ''
                else:
                    self.text = self.text[:-1]
            # {ESC} clears the search bar
            elif event.key == pg.K_ESCAPE:
                if self.text == '':
                    self.active = False
                    self.text = self.default_text
                else:
                    self.text = ''
            # typing char
            else:
                self.text += event.unicode
            # render new text
            self.text_surface = self.font.render(self.text, True, self.color)
        return interacted

    def _search(self, file):
        # internal method for searching: uses SearchGUI to display search results
        q = QApplication(sys.argv)
        window = SearchGUI(self.results)
        Thread(target=window.searchItems, args=(file,), daemon=True).start()
        window.show()
        q.exec_()

    def get_search_results(self):
        # extract search results out
        if len(self.results) == 0:
            return self.results
        else:
            temp = self.results
            self.results = []
            return temp

    def move(self, x, y):
        self.rect = pg.Rect(x, y, self.text_surface.get_width() + 10, CHALK_FONTSIZE + 5)

    def update(self):
        # update the rectangle hitbox wrt the current text size
        self.rect.w = self.text_surface.get_width() + 10

    def draw(self, screen):
        # draw the text (surface), rectangle hitbox is not drawn
        screen.blit(self.text_surface, (self.rect.x+5, self.rect.y+5))

class SearchGUI(QDialog):
    def __init__(self, results):
        # QDialog widget
        super(SearchGUI, self).__init__()
        self.setStyleSheet("background-color: rgb(30, 30, 30);")
        self.results = results
        # contains a list widget to display the search results
        self.list_widget = QListWidget()
        self.list_widget.setStyleSheet("color: rgb(211, 211, 211);")
        self.list_widget.setFixedHeight(600)
        self.list_widget.setMinimumWidth(400)
        self.list_widget.itemDoubleClicked.connect(self.addAndReturn)
        # list widget sits on top of layout
        layout = QVBoxLayout(self)
        layout.addWidget(self.list_widget)

    def searchItems(self, file):
        for path in Path('/').rglob(file):
            self.list_widget.addItem(str(path))

    def addAndReturn(self, item):
        # quits GUI after picking
        self.results.append(item.text())
        QApplication.quit()

class OptionsMenu():
    def __init__(self, parent):
        # reference to the parent item
        self.p = parent
        self.options = []
        self.opt_rects = []
        self.rect_colors = []

    def setpos(self, x, y):
        h = OPTMENU_FONTSIZE + 10
        for i in range(len(self.options)):
            self.opt_rects[i].x, self.opt_rects[i].y = x, y + i*h

    def handle_event(self, event):
        # pressing any key closes the option menu
        if event.type == pg.KEYDOWN:
            self.p.options_opened = False
        # hovering over an option changes its color
        elif event.type == pg.MOUSEMOTION:
            for i in range(len(self.opt_rects)):
                if self.opt_rects[i].collidepoint(event.pos):
                    self.rect_colors[i] = OPTMENU_COLOR_HOVERED
                else:
                    self.rect_colors[i] = OPTMENU_COLOR

    def draw(self, screen):
        # draw the background of the options menu
        for i in range(len(self.opt_rects)):
            pg.Surface.fill(screen, self.rect_colors[i], self.opt_rects[i])
        # draw in the indivdual options
        for i in range(len(self.options)):
            screen.blit(self.options[i], (self.opt_rects[i].x + 2, self.opt_rects[i].y + 2))

class AppOptionsMenu(OptionsMenu):
    def __init__(self, app):
        super().__init__(app)
        # 4 options: launch, remove, rename, color
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Launch", True, OPTMENU_TEXT_COLOR))
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Remove", True, OPTMENU_TEXT_COLOR))
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Rename", True, OPTMENU_TEXT_COLOR))
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Color >>", True, pg.Color(*COLOR_PAL[self.p.color_idx])))
        # rectangles for the options
        w = self.options[3].get_width() + 10
        h = OPTMENU_FONTSIZE + 10
        for i in range(len(self.options)):
            self.opt_rects.append(pg.Rect(0, 0, w, h))
        # color of option rectangles (changes when hovered)
        self.rect_colors = [OPTMENU_COLOR] * len(self.opt_rects)

    def setpos(self, x, y):
        super().setpos(x, y)

    def handle_event(self, event):
        if event.type == pg.MOUSEBUTTONUP and event.button == 1:
            # click on launch option
            if self.opt_rects[0].collidepoint(event.pos):
                os.startfile(self.p.path)
                self.p.options_opened = False
            # click on remove option
            if self.opt_rects[1].collidepoint(event.pos):
                self.p.keep = False
                self.p.options_opened = False
            # click on rename option
            elif self.opt_rects[2].collidepoint(event.pos):
                self.p.text_color = pg.Color(*EDITING_COLOR)
                self.p.renaming = True
                self.p.text_surface = self.p.font.render(self.p.name, True, self.p.text_color)
                self.p.options_opened = False
            # click on color >>
            elif self.opt_rects[3].collidepoint(event.pos):
                self.p.color_idx = (self.p.color_idx + 1) % NUM_COLORS
                self.p.text_color = pg.Color(*COLOR_PAL[self.p.color_idx])
                self.options[3] = pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Color >>", True, self.p.text_color)
                self.p.text_surface = self.p.font.render(self.p.name, True, self.p.text_color)
            # clicking anywhere else closes this options menu
            else:
                self.p.options_opened = False
        super().handle_event(event)

    def draw(self, screen):
        super().draw(screen)

class ChalkTextOptionsMenu(OptionsMenu):
    def __init__(self, chalkText):
        super().__init__(chalkText)
        # 4 options: erase, edit, color, size
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Erase", True, OPTMENU_TEXT_COLOR))
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Edit", True, OPTMENU_TEXT_COLOR))
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Color >>", True, pg.Color(*COLOR_PAL[self.p.color_idx])))
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("- Size +", True, OPTMENU_TEXT_COLOR))
        # rectangles for the options
        w = self.options[2].get_width() + 10
        h = OPTMENU_FONTSIZE + 10
        for i in range(len(self.options)):
            self.opt_rects.append(pg.Rect(0, 0, w, h))
        # special setup for size option
        self.opt_rects[-1].width = w//2
        self.opt_rects.append(pg.Rect(0, 0, w//2, h))
        self.w = w
        # color of option rectangles (changes when hovered)
        self.rect_colors = [OPTMENU_COLOR] * len(self.opt_rects)

    def setpos(self, x, y):
        super().setpos(x, y)
        # special setup for size option
        x, y = self.opt_rects[-2].x + self.w//2, self.opt_rects[-2].y
        self.opt_rects[-1].x, self.opt_rects[-1].y = x, y

    def handle_event(self, event):
        if event.type == pg.MOUSEBUTTONUP and event.button == 1:
            # click on erase option
            if self.opt_rects[0].collidepoint(event.pos):
                self.p.keep = False
                self.p.options_opened = False
            # click on edit option
            elif self.opt_rects[1].collidepoint(event.pos):
                self.p.active = True
                self.p.color = pg.Color(*EDITING_COLOR)
                self.p.text_surface = self.p.font.render(self.p.text, True, self.p.color)
                self.p.options_opened = False
            # click on color >>
            elif self.opt_rects[2].collidepoint(event.pos):
                self.p.color_idx = (self.p.color_idx + 1) % NUM_COLORS
                self.p.color = pg.Color(*COLOR_PAL[self.p.color_idx])
                self.options[2] = pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Color >>", True, self.p.color)
                self.p.text_surface = self.p.font.render(self.p.text, True, self.p.color)
            # click on size -
            elif self.opt_rects[3].collidepoint(event.pos):
                if self.p.fontsize > 2:
                    self.p.fontsize -= 2
                    self.p.font = pg.font.Font(CHALK_FONT, self.p.fontsize)
                    self.p.text_surface = self.p.font.render(self.p.text, True, self.p.color)
            # click on size +
            elif self.opt_rects[4].collidepoint(event.pos):
                self.p.fontsize += 2
                self.p.font = pg.font.Font(CHALK_FONT, self.p.fontsize)
                self.p.text_surface = self.p.font.render(self.p.text, True, self.p.color)
            # clicking anywhere else closes this options menu
            else:
                self.p.options_opened = False
        super().handle_event(event)

    def draw(self, screen):
        super().draw(screen)

class ChalkLineOptionsMenu(OptionsMenu):
    def __init__(self, chalkLine):
        super().__init__(chalkLine)
        # 4 options: erase, adjust, color, size
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Erase", True, OPTMENU_TEXT_COLOR))
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Adjust", True, OPTMENU_TEXT_COLOR))
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Color >>", True, pg.Color(*COLOR_PAL[self.p.color_idx])))
        self.options.append(
            pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("- Size +", True, OPTMENU_TEXT_COLOR))
        # rectangles for the options
        w = self.options[2].get_width() + 10
        h = OPTMENU_FONTSIZE + 10
        for i in range(len(self.options)):
            self.opt_rects.append(pg.Rect(0, 0, w, h))
        # special setup for size option
        self.opt_rects[-1].width = w//2
        self.opt_rects.append(pg.Rect(0, 0, w//2, h))
        self.w = w
        # color of option rectangles (changes when hovered)
        self.rect_colors = [OPTMENU_COLOR] * len(self.opt_rects)

    def setpos(self, x, y):
        super().setpos(x, y)
        # special setup for size option
        x, y = self.opt_rects[-2].x + self.w//2, self.opt_rects[-2].y
        self.opt_rects[-1].x, self.opt_rects[-1].y = x, y

    def handle_event(self, event):
        if event.type == pg.MOUSEBUTTONUP and event.button == 1:
            # click on erase option
            if self.opt_rects[0].collidepoint(event.pos):
                self.p.keep = False
                self.p.options_opened = False
            # click on adjust option
            elif self.opt_rects[1].collidepoint(event.pos):
                self.p.drawn = False
                self.p.color = pg.Color(*EDITING_COLOR)
                self.p.options_opened = False
            # click on color >>
            elif self.opt_rects[2].collidepoint(event.pos):
                self.p.color_idx = (self.p.color_idx + 1) % NUM_COLORS
                self.p.color = pg.Color(*COLOR_PAL[self.p.color_idx])
                self.options[2] = pg.font.Font(OPTMENU_FONT, OPTMENU_FONTSIZE).render("Color >>", True, self.p.color)
            # click on size -
            elif self.opt_rects[3].collidepoint(event.pos):
                if self.p.width > 1:
                    self.p.width -= 1
            # click on size +
            elif self.opt_rects[4].collidepoint(event.pos):
                self.p.width += 1
            # clicking anywhere else closes this options menu
            else:
                self.p.options_opened = False
        super().handle_event(event)

    def draw(self, screen):
        super().draw(screen)


"""
Make it more robust.
Stop episode once the finger stop at the final position for 50 steps.
Feature & reward engineering.
"""
#from final.env import ArmEnv
#from final.rl import DDPG
from env import ArmEnv
from rl import DDPG
import vrepInterface

#MAX_EPISODES = 900
MAX_EPISODES = 900
#MAX_EP_STEPS = 200
MAX_EP_STEPS = 100
ON_TRAIN = True

# set env
env = ArmEnv()
s_dim = env.state_dim
a_dim = env.action_dim
a_bound = env.action_bound

# set RL method (continuous)
rl = DDPG(a_dim, s_dim, a_bound)

steps = []
def train():

    vrepInterface.connect()
    vrepInterface.start()

    # start training
    for i in range(MAX_EPISODES):
        env.get_goal()
        s = env.reset()
        # print('the start s is: ',s)
        ep_r = 0.
        for j in range(MAX_EP_STEPS):
            # env.render()

            a = rl.choose_action(s)
            # print('STEP ', j, ' a is: ', a)

            s_, r, done = env.step(a)
            # print('STEP ', j, 's is :', s_)
            # print('STEP ', j, 'r is :', r)

            rl.store_transition(s, a, r, s_)

            ep_r += r
            if rl.memory_full:
                # start to learn once has fulfilled the memory
                rl.learn()
                # print('start to learn')

            s = s_
            if done or j == MAX_EP_STEPS-1:
                print('Ep: %i | %s | ep_r: %.1f | step: %i' % (i, '---' if not done else 'done', ep_r, j))
                break
    rl.save()
    vrepInterface.disconnect()

def eval():
    rl.restore()
    vrepInterface.connect()
    vrepInterface.start()
    # env.render()
    # env.viewer.set_vsync(True)
    env.get_goal()
    s = env.reset()
    while True:
        # env.render()
        a = rl.choose_action(s)
        s, r, done = env.step(a)

if ON_TRAIN:
    train()
else:
    eval()


# reddit scraper, by subreddit
# results will be saved to csv file named <subreddit>.csv

import csv
import os
import requests

reddit_fields = ['subreddit', 'url']
headers = {'User-agent': 'nlp scraper 0.0.1'}
sort = '?sort=top&t=all&limit=100'

whitelist = []

# read in whitelist
with open('whitelist.txt') as f:
    whitelist = f.readlines()
whitelist = [line.strip() for line in whitelist]

def main():
    REDDIT_BASE = 'https://old.reddit.com/r/'
    after = None

    subreddits = input('Enter subreddits to scrape: ').split(' ')

    for s in subreddits:
        for _ in range(5):
            page = f'&after={after}' if after else ''
            r = requests.get(
                f'{REDDIT_BASE}{s}/top/.json{sort}{page}', headers=headers)
            if r.ok:
                res = r.json()['data']
                posts = process_reddit_response(res['children'])
                write_subreddit_to_csv(s, posts)
                after = res['after']

def process_reddit_response(sub_response):
    posts = []
    for post in sub_response:
        p = post['data']
        if p and not p['stickied'] and accepted(p['url']):
            # get subreddit name and url
            d = {x: p[x] for x in reddit_fields}
            # check if post's url is on whitelist
            posts.append(d)
    return posts

def accepted(url):
    accept = True
    blacklist = ['i.redd.it', 'imgur', 'reddit',
                 'streamable', 'facebook.com',
                 'twitter.com', 'instagram.com', 'redd.it',
                 '.gif', '.jpg', '.mp4', '.png', 'youtube.com',
                 'youtu.be', 'decisiondeskhq.com', 'duckduckgo']

    for b in blacklist:
        accept = accept and b not in url

    return accept

def write_subreddit_to_csv(subreddit, posts):
    filename = f'{subreddit}.csv'
    mode = 'a' if os.path.exists(filename) else 'w'
    with open(filename, mode=mode) as f:
        writer = csv.writer(f)
        if mode == 'w':
            writer.writerow(reddit_fields)
        for p in posts:
            row = [p[x] for x in reddit_fields]
            writer.writerow(row)

def url_in_whitelist(url):
    return any(sitename in url for sitename in whitelist)

if __name__ == '__main__':
    main()


#create Dictionary for eye colour
EyeColours = {}
Contient = {}
Sex = {}

#method to read from eyecolours.txt into dictioanry
def FillDictionarys():
    with open('Eye colours.txt', 'r') as ReadOnto:
        for line in ReadOnto:
            component = line.split()

            if component[0] == "EYE":
                EyeColours[component[1]] = str(component[2])

            elif component[0] == "CONTINENT":
                if component[1] == "South":
                    Contient[component[1] +" "+ component[2]] = str(component[3])
                elif component[1] == "North":
                    Contient[component[1] +" "+ component[2]] = str(component[3])
                else:
                    Contient[component[1]] = str(component[2])

            elif component[0] == "SEX":
                Sex[component[1]] = str(component[2])

#return the output of the users Eye colour
def ReturnEyeComparison(UserKey):
    global EyeColours
    return ("You have a " +UserKey+ " eyes, which is a trait shared by  " +EyeColours.get(UserKey)+ "%" + " of the population")

def ReturnContComparison(UserKey):
    global Contient
    return ("You live in " +UserKey+ ", " +UserKey+ " is also home to " +Contient.get(UserKey)+ "%" + " of the population")

def ReturnSexComparison(UserKey):
    global Sex
    return ("Your sex is " +UserKey+ ", this means your the same sex as " +Sex.get(UserKey)+ "%" + " of the population")

#list all keys within an dictionary
def ListKeysOfDic(Dictionary):
    counter = 1
    for keys in Dictionary.keys():
        print(str(counter)+". " + keys + " ")
        counter = counter + 1

#gets the users input
def GetEyeUserInput():
    UserEyeColour = input("Choose from the list of Eye colours and enter which colour most accuratly describes yours: ")
    return(UserEyeColour)

#get the user input
def GetContientUserInput():
    UserContienet = input("Choose from the list of Contient and enter which Continet most accurtly describes where you come from: ")
    return(UserContienet)

#get the user input
def GetSexInput():
    UserSex = input("Choose from the list of sexs which most accurtly describes what sex you are: ")
    return(UserSex)

#conbines functionality of getting user input and listing keys
def ComputeInputEyeColour():
    ListKeysOfDic(EyeColours)
    val = GetEyeUserInput()
    return(val)

#combines Funcitonaliy of getting userinput and listing keys
def ComputeInputContienet():
    ListKeysOfDic(Contient)
    val = GetContientUserInput()
    return(val)

#combines functonaliy of getting userinput and listing keys
def ComputeInputSex():
    ListKeysOfDic(Sex)
    val = GetSexInput()
    return(val)

FillDictionarys()
print(ReturnEyeComparison(ComputeInputEyeColour()))
print(ReturnContComparison(ComputeInputContienet()))
print(ReturnSexComparison(ComputeInputSex()))


def setadmin(id, msg, sender, cur, myconn):
    try:
        if msg.startswith('/setadmin'):
            msg5 = msg.split(' ')[1]
            msg6 = msg.split(' ')[2]
            cur.execute(f"SELECT * from accounts WHERE name = '{msg5}'")
            rowsss = cur.fetchall()
            if cur.rowcount > 0:
                if f"{msg6}" >= '1' and f"{msg6}" < '8':
                    cur.execute(f"UPDATE accounts set admin = {msg6} where name = '{msg5}'")
                    myconn.commit()
                    sender(id, f"{msg5} назначен на пост администратора {msg6} уровня")
                if f"{msg6}" == '0':
                    cur.execute(f"UPDATE accounts set admin = '0' where name = '{msg5}'")
                    myconn.commit()
                    sender(id, f'{msg5} снят с поста администратора')
                if f"{msg6}" < '0' or f"{msg6}" >= '8':
                    sender(id, 'От 1 до 7')
            else:
                sender(id, 'Данный пользователь не найден')
    except Exception as e:
        sender(id, 'Используйте: /setadmin Nick лвл')
        print(e)