"""
Wrapper around MAFFT and other tools to harmonize phased variants
"""
import os
import re
import sys
import shutil
import logging
import argparse
import multiprocessing
from io import BytesIO
from functools import partial
from collections import defaultdict

import pysam
from pysam import bcftools, samtools
from intervaltree import IntervalTree
from pywfa.align import WavefrontAligner  # pylint: disable=no-name-in-module
import truvari

DEFAULT_MAFFT_PARAM = "--auto --thread 1"

def parse_regions(argument):
    """
    Parse the --region argument
    returns list of regions
    """
    ret = []
    if not argument:
        return ret
    if os.path.exists(argument):
        for i in truvari.opt_gz_open(argument):
            try:
                chrom, start, end = i.strip().split('\t')[:3]
                start = int(start)
                end = int(end)
            except Exception:  # pylint: disable=broad-except
                logging.error("Unable to parse bed line %s", i)
                sys.exit(1)
            ret.append((chrom, start, end))
    else:
        for i in argument.split(','):
            try:
                chrom, start, end = re.split(':|-', i)
                start = int(start)
                end = int(end)
            except ValueError:
                logging.error("Unable to parse region line %s", i)
                sys.exit(1)
            ret.append((chrom, start, end))
    return ret

def merged_region_file(regions, buff=100):
    """
    Write a file for extracting reference regions with samtools
    returns the name of the temporary file made
    """
    m_dict = defaultdict(list)
    for i in regions:
        m_dict[i[0]].append((max(0, i[1] - buff), i[2] + buff))

    out_file_name = truvari.make_temp_filename()
    with open(out_file_name, 'w') as fout:
        for chrom in sorted(m_dict.keys()):
            intvs = IntervalTree.from_tuples(m_dict[chrom])
            intvs.merge_overlaps()
            for i in sorted(intvs):
                fout.write(f"{chrom}:{i.begin}-{i.end}\n")
    return out_file_name

def extract_reference(reg_fn, ref_fn):
    """
    Pull the reference
    """
    out_fn = truvari.make_temp_filename(suffix='.fa')
    with open(out_fn, 'w') as fout:
        fout.write(samtools.faidx(ref_fn, "-r", reg_fn))
    return out_fn

def make_haplotype_jobs(base_vcf, bSamples=None, comp_vcf=None, cSamples=None, prefix_comp=False):
    """
    Sets up sample parameters for extract haplotypes
    returns list of tuple of (VCF, sample_name, should_prefix, haplotype_number) and the sample names
    to expect in the haplotypes' fasta
    """
    ret = []
    if bSamples is None:
        bSamples = list(pysam.VariantFile(base_vcf).header.samples)
    for hap in [1, 2]:
        ret.extend([(base_vcf, samp, False, hap) for samp in bSamples])

    if comp_vcf:
        if cSamples is None:
            cSamples = list(pysam.VariantFile(comp_vcf).header.samples)
        for hap in [1, 2]:
            ret.extend([(comp_vcf, samp, prefix_comp or samp in bSamples, hap)
                        for samp in cSamples])

    samp_names = sorted({('p:' if prefix else '') + samp
                         for _, samp, prefix, _ in ret})
    return ret, samp_names

def fasta_reader(fa_str, name_entries=True):
    """
    Parses a fasta file as a string and yields tuples of (location, entry)
    if name_entries, the entry names are written to the value and location is honored
    """
    cur_name = None
    cur_entry = BytesIO()
    for i in fa_str.split('\n'):
        if not i.startswith(">"):
            cur_entry.write(i.encode())
            continue
        if cur_name is not None:
            cur_entry.write(b'\n')
            cur_entry.seek(0)
            yield cur_name, cur_entry.read()
        cur_name = i[1:]
        cur_entry = BytesIO()
        if name_entries:
            cur_name = cur_name.split('_')[-1]
            cur_entry.write((i + '\n').encode())

    cur_entry.write(b'\n')
    cur_entry.seek(0)
    yield cur_name, cur_entry.read()

def extract_haplotypes(data, ref_fn):
    """
    Given a data tuple of VCF, sample name, and prefix bool
    Call bcftools consensus
    Returns list of tuples [location, fastaentry] for every haplotype,
    so locations are duplicated
    """
    vcf_fn, sample, prefix, hap = data
    prefix = 'p:' if prefix else ''
    cmd = (f"--sample {sample} --prefix {prefix}{sample}_{hap}_ "
           f"-H{hap} -f {ref_fn} {vcf_fn}").split(' ')
    # Can't return generator from process
    return list(fasta_reader(bcftools.consensus(*cmd)))

def collect_haplotypes(ref_haps_fn, hap_jobs, threads):
    """
    Calls extract haplotypes for every hap_job
    """
    all_haps = defaultdict(BytesIO)
    with multiprocessing.Pool(threads, maxtasksperchild=1) as pool:
        to_call = partial(extract_haplotypes, ref_fn=ref_haps_fn)
        for haplotype in pool.imap(to_call, hap_jobs):
            for location, fasta_entry in haplotype:
                all_haps[location].write(fasta_entry)
        pool.close()
        pool.join()
    return all_haps

def consolidate_haplotypes_with_reference(all_haps, ref_haps_fn):
    """
    Generator for putting the reference into the haplotypes
    """
    m_ref = pysam.FastaFile(ref_haps_fn)
    for location in list(m_ref.references):
        all_haps[location].write(
            f">ref_{location}\n{m_ref[location]}\n".encode())
        all_haps[location].seek(0)
        yield all_haps[location].read()

def expand_cigar(seq, ref, cigar):
    """
    Put gaps '-' in sequence where needed
    """
    seq_pos = 0
    seq = list(seq)
    ref_pos = 0
    ref = list(ref)
    for code, span in cigar:
        if code == 2:
            seq.insert(seq_pos, '-' * span)
            seq_pos += 1
            ref_pos += span
        elif code == 1:
            ref.insert(ref_pos, '-' * span)
            seq_pos += span
            ref_pos += 1
        else:
            seq_pos += span
            ref_pos += span
    return "".join(ref), "".join(seq)

def wfa_to_vars(seq_bytes):
    """
    Align haplotypes independently with WFA
    Much faster than mafft, but may be less accurate at finding parsimonous representations
    """
    fasta = {k: v.decode() for k, v in fasta_reader(seq_bytes.decode(), False)}
    ref_key = [_ for _ in fasta.keys() if _.startswith("ref_")][0]
    reference = fasta[ref_key]

    aligner = WavefrontAligner(reference, span="end-to-end",
                               heuristic="adaptive")
    for haplotype in fasta:
        if haplotype == ref_key:
            continue
        seq = fasta[haplotype]
        aligner.wavefront_align(seq)
        assert aligner.status == 0
        fasta[haplotype] = expand_cigar(seq, reference, aligner.cigartuples)
    return truvari.msa2vcf(fasta)

def mafft_to_vars(seq_bytes, params=DEFAULT_MAFFT_PARAM):
    """
    Run mafft on the provided sequences provided as a bytestr and return msa2vcf lines
    """
    # Dev only method for overwriting test answers - don't use until code is good
    dev_name = None
    if "PHAB_WRITE_MAFFT" in os.environ and os.environ["PHAB_WRITE_MAFFT"] == "1":
        import hashlib  # pylint: disable=import-outside-toplevel
        dev_name = hashlib.md5(seq_bytes).hexdigest()

    cmd = f"mafft --quiet {params} -"
    ret = truvari.cmd_exe(cmd, stdin=seq_bytes)
    if ret.ret_code != 0:
        logging.error("Unable to run MAFFT")
        logging.error(ret.stderr)
        return ""

    if dev_name is not None:
        with open("repo_utils/test_files/external/fake_mafft/lookup/fm_" + dev_name + ".msa", 'w') as fout:
            fout.write(ret.stdout)

    fasta = {}
    for name, sequence in fasta_reader(ret.stdout, name_entries=False):
        fasta[name] = sequence.decode()
    return truvari.msa2vcf(fasta)

def harmonize_variants(harm_jobs, mafft_params, base_vcf, samp_names, output_fn, threads, method="mafft"):
    """
    Parallel processing of variants to harmonize. Writes to output
    """
    if method == "mafft":
        align_method = partial(mafft_to_vars, params=mafft_params)
    else:
        align_method = wfa_to_vars

    with open(output_fn[:-len(".gz")], 'w') as fout:
        fout.write(
            '##fileformat=VCFv4.1\n##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">\n')
        for ctg in pysam.VariantFile(base_vcf).header.contigs.values():
            fout.write(str(ctg.header_record))
        fout.write("#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO\tFORMAT\t")
        fout.write("\t".join(samp_names) + "\n")

        with multiprocessing.Pool(threads) as pool:
            for result in pool.imap_unordered(align_method, harm_jobs):
                fout.write(result)
            pool.close()
            pool.join()

    truvari.compress_index_vcf(output_fn[:-len(".gz")], output_fn)

# pylint: disable=too-many-arguments
# This is just how many arguments it takes
def phab(var_regions, base_vcf, ref_fn, output_fn, bSamples=None, buffer=100,
         mafft_params=DEFAULT_MAFFT_PARAM, comp_vcf=None, cSamples=None,
         prefix_comp=False, threads=1, method="mafft"):
    """
    Harmonize variants with MSA. Runs on a set of regions given files to create
    haplotypes and writes results to a compressed/indexed VCF

    :param `var_regions`: List of tuples of region's (chrom, start, end)
    :type `var_regions`: :class:`list`
    :param `base_vcf`: VCF file name
    :type `base_vcf`: :class:`str`
    :param `ref_fn`: Reference file name
    :type `ref_fn`: :class:`str`
    :param `output_fn`: Output VCF.gz
    :param `bSamples`: Samples from `base_vcf` to create haplotypes
    :type `bSamples`: :class:`list`
    :param `buffer`: Flanking reference bases to added to regions
    :type `buffer`: :class:`int`
    :param `mafft_params`: Parameters for mafft
    :type `mafft_params`: :class:`str`
    :param `comp_vcf`: VCF file name
    :type `comp_vcf`: :class:`str`
    :param `cSamples`: Samples from `comp_vcf` to create haplotypes
    :type `cSamples`: :class:`list`
    :param `prefix_comp`: Ensure unique sample names by prefixing comp samples
    :type `prefix_comp`: :class:`bool`
    :param `threads`: Number of threads to use
    :type `threads`: :class:`int`
    :param `method`: Alignment method to use mafft or wfa
    :type `method`: :class:`str`
    """
    logging.info("Preparing regions")
    region_fn = merged_region_file(var_regions, buffer)

    logging.info("Extracting haplotypes")
    ref_haps_fn = extract_reference(region_fn, ref_fn)
    hap_jobs, samp_names = make_haplotype_jobs(base_vcf, bSamples,
                                               comp_vcf, cSamples,
                                               prefix_comp)
    sample_haps = collect_haplotypes(ref_haps_fn, hap_jobs, threads)
    harm_jobs = consolidate_haplotypes_with_reference(sample_haps, ref_haps_fn)

    logging.info("Harmonizing variants")
    harmonize_variants(harm_jobs, mafft_params, base_vcf,
                       samp_names, output_fn, threads, method)
# pylint: enable=too-many-arguments

######
# UI #
######

def parse_args(args):
    """
    Pull the command line parameters
    """
    parser = argparse.ArgumentParser(prog="phab", description=__doc__,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("-r", "--region", type=str, required=True,
                        help="Bed filename or comma-separated list of chrom:start-end regions to process")
    parser.add_argument("-b", "--base", type=str, required=True,
                        help="Baseline vcf to MSA")
    parser.add_argument("-c", "--comp", type=str, default=None,
                        help="Comparison vcf to MSA")
    parser.add_argument("-f", "--reference", type=str, required=True,
                        help="Reference")
    parser.add_argument("--buffer", type=int, default=100,
                        help="Number of reference bases before/after region to add to MSA (%(default)s)")
    parser.add_argument("-o", "--output", type=str, default="phab_out.vcf.gz",
                        help="Output VCF")
    parser.add_argument("--bSamples", type=str, default=None,
                        help="Subset of samples to MSA from base-VCF")
    parser.add_argument("--cSamples", type=str, default=None,
                        help="Subset of samples to MSA from comp-VCF")
    parser.add_argument("-m", "--mafft-params", type=str, default=DEFAULT_MAFFT_PARAM,
                        help="Parameters for mafft, wrap in a single quote (%(default)s)")
    parser.add_argument("--align", type=str, choices=["mafft", "wfa"], default="mafft",
                        help="Alignment method accurate (mafft) or fast (wfa) (%(default)s)")
    parser.add_argument("-t", "--threads", type=int, default=1,
                        help="Number of threads (%(default)s)")
    parser.add_argument("--debug", action="store_true",
                        help="Verbose logging")
    args = parser.parse_args(args)
    return args

def check_requirements(align):
    """
    ensure external programs are in PATH
    """
    check_fail = False
    if align == "mafft":
        if not shutil.which("mafft"):
            logging.error("Unable to find mafft in PATH")
            check_fail = True
    return check_fail

def check_params(args):
    """
    Ensure files are okay to use
    """
    check_fail = False
    if not args.output.endswith(".vcf.gz"):
        logging.error("Output file must be a '.vcf.gz', got %s", args.output)
        check_fail = True
    if os.path.exists(args.output):
        logging.error("Output file already exists")
        check_fail = True
    if args.comp is not None and not os.path.exists(args.comp):
        logging.error("File %s does not exist", args.comp)
        check_fail = True
    if not os.path.exists(args.base):
        logging.error("File %s does not exist", args.base)
        check_fail = True
    if args.comp is not None and not args.comp.endswith(".gz"):
        logging.error(
            "Comparison vcf %s does not end with .gz. Must be bgzip'd", args.comp)
        check_fail = True
    if args.comp is not None and not os.path.exists(args.comp + '.tbi'):
        logging.error(
            "Comparison vcf index %s.tbi does not exist. Must be indexed", args.comp)
        check_fail = True
    if not args.base.endswith(".gz"):
        logging.error(
            "Base vcf %s does not end with .gz. Must be bgzip'd", args.base)
        check_fail = True
    if not os.path.exists(args.base + '.tbi'):
        logging.error(
            "Base vcf index %s.tbi does not exist. Must be indexed", args.base)
        check_fail = True
    if not os.path.exists(args.reference):
        logging.error("Reference %s does not exist", args.reference)
        check_fail = True

    return check_fail

def phab_main(cmdargs):
    """
    Main
    """
    args = parse_args(cmdargs)
    truvari.setup_logging(args.debug, show_version=True)
    if check_requirements(args.align) or check_params(args):
        logging.error("Couldn't run Truvari. Please fix parameters\n")
        sys.exit(100)

    if args.bSamples is not None:
        args.bSamples = args.bSamples.split(',')

    if args.comp and args.cSamples is not None:
        args.cSamples = args.cSamples.split(',')

    all_regions = parse_regions(args.region)
    phab(all_regions, args.base, args.reference, args.output, args.bSamples, args.buffer,
         args.mafft_params, args.comp, args.cSamples, threads=args.threads, method=args.align)

    logging.info("Finished phab")


import os
from pathlib import Path

from crispy_forms.utils import render_crispy_form
from django.test.html import Element, parse_html

TEST_DIR = os.path.dirname(os.path.abspath(__file__))

def contains_partial(haystack, needle, ignore_needle_children=False):
    """Search for a html element with at least the corresponding elements
    (other elements may be present in the matched element from the haystack)
    """
    if not isinstance(haystack, Element):
        haystack = parse_html(haystack)
    if not isinstance(needle, Element):
        needle = parse_html(needle)

    if len(needle.children) > 0 and not ignore_needle_children:
        raise NotImplementedError(
            "contains_partial does not check needle's children:%s"
            % str(needle.children)
        )

    if needle.name == haystack.name and set(needle.attributes).issubset(
        haystack.attributes
    ):
        return True
    return any(
        contains_partial(child, needle, ignore_needle_children=ignore_needle_children)
        for child in haystack.children
        if isinstance(child, Element)
    )

def parse_expected(expected_file):
    test_file = Path(TEST_DIR) / "results" / expected_file
    with open(test_file) as f:
        return parse_html(f.read())

def parse_form(form):
    html = render_crispy_form(form)
    return parse_html(html)


from flask import Flask, jsonify, request, make_response
from app.models.database import DatabaseConnection

db = DatabaseConnection()
app = Flask(__name__)

@app.route('/users/orders', methods=['POST'])
def make_an_order():
    data = request.get_json()
    if not data:
        return jsonify({'Error': 'Please fill in the neccssary data'}), 400
    user_id = data['user_id']
    menu_id = data['menu_id']
    contact = data['contact']
    quantity = data['quantity']
    order_status = data['order_status']
    if not contact == type(int):
        return({'Error': 'Contact has to be an integer'}), 400
    if contact.strip() == '':
        return({'Error': 'Contact can not be empty'}), 400
    if not len(contact) == 9:
        return({'Error': 'Contact has 9 integers'}), 400

    if not quantity == type(int):
        return({'Error': 'quantity has to be an integer'}), 400
    if quantity.strip() == '':
        return({'Error': 'quantity can not be empty'}), 400

    db.create_order(user_id, menu_id, contact, quantity, order_status)
    return jsonify({'message': 'Order created'}), 201

@app.route('/orders/<order_id>', methods=['GET'])
def get_an_order(order_id):
    order = db.get_an_order(order_id)
    if not order:
        return jsonify({'message': 'No order placed by that id'}), 400
    return jsonify({'message': order}), 200
    return 'one order'

@app.route('/orders/', methods=['GET'])
def get_orders():
    orders = db.get_all_orders()
    if not orders:
        return jsonify({'message': 'No orders made'}), 400
    return jsonify({'message': orders}), 200

@app.route('/orders/<order_id>', methods=['PUT'])
def update_an_order(order_id):
    data = request.get_json()
    order_status = data['order_status']
    db.update_order_status(order_status, order_id)
    return jsonify({'message': order_status})

@app.route('/menu', methods=['GET'])
def get_menu():
    menu = db.get_menu()
    if not menu:
        return jsonify({'message': 'No menu found'}), 400
    return jsonify({'message': menu}), 200

@app.route('/menu', methods=['POST'])
def add_a_menu():
    data = request.get_json()
    menu_item = data['menu_item']
    price = data['price']

    if not menu_item == type(str):
        return({'Error': 'menu_item has to be a string'}), 400
    if menu_item.strip() == '':
        return({'Error': 'menu_item can not be empty'}), 400

    if not price == type(int):
        return({'Error': 'price has to be a string'}), 400
    if price.strip() == '':
        return({'Error': 'price can not be empty'}), 400
    db.create_menu(menu_item, price)
    return jsonify({'message': 'Menu item added successfully'}), 201


#!/usr/bin/env python

print("Importing packages ...")

import os
import json
import re
from transformers import AutoTokenizer, AutoModelForQuestionAnswering
from torch.multiprocessing import cpu_count
import torch.multiprocessing as mp
import queue
import torch
import numpy as np
import time

context_length=200

#BERT_Squad_Model='bert-large-uncased-whole-word-masking-finetuned-squad'
#BERT_Squad_Model='bert-base-uncased'
BERT_Squad_Model='distilbert-base-uncased-distilled-squad'
#BERT_Squad_Model='./scibert/scibert_scivocab_uncased_pt'
#BERT_Squad_Model='trained_models/wwm_uncased_finetuned_squad'

def process_file(publication_pool,q,tokenizer,model,question):
    max_score=0
    best_answer=""

    for filename in publication_pool:
        path=os.path.join("search_engine_contexts",filename)
        with open(path) as read_file:
            data=json.load(read_file)
        read_file.close()
        context_full=""
        for i in range(len(data['body_text'])):
            context_full+=data['body_text'][i]['text']
        context_full=context_full.replace("\"","'")
        paper_id=data['paper_id']
        print("Checking ",paper_id," ...")

        inilist = [m.start() for m in re.finditer(r" ", context_full)]
        part_list=[0]+inilist
        part_list=part_list[::context_length]
        part_list=part_list+[len(context_full)]

        try:
            for i in range(len(part_list)-1):
                context=context_full[part_list[i]:part_list[i+1]]
                context=r'{}'.format(context)

                print("Performing BERT Question-Answering ...")
                with torch.no_grad():
                    inputs = tokenizer.encode_plus(question, context, add_special_tokens=True, return_tensors="pt")
                    inputs.to('cuda')
                input_ids = inputs["input_ids"].tolist()[0]

                if(len(input_ids)>512):
                    print("Token size exceeded\n")
                    continue

                with torch.no_grad():
                    text_tokens = tokenizer.convert_ids_to_tokens(input_ids)
                    answer_start_scores, answer_end_scores = model(**inputs)
                    answer_start = torch.argmax(answer_start_scores)
                    answer_end = torch.argmax(answer_end_scores) + 1
                    answer = tokenizer.convert_tokens_to_string(tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end]))
                    answer = answer.replace('[CLS] '+question.lower()[:-1]+' ? [SEP]',"")
                    answer = answer.replace('[CLS]',"")
                    answer = answer.replace('[SEP]',"")
                    answer = answer.strip()

                with torch.no_grad():
                    score=(torch.max(answer_start_scores)+torch.max(answer_end_scores)).item()
                if(answer==""):
                    score=-1

                print("Score received =  ",score)

                if(score>max_score):
                    max_score=score
                    best_answer=answer
                del score, answer_start_scores, answer_end_scores

            print("Finished ",paper_id," ...")

            del inputs

        except RuntimeError:
            torch.cuda.empty_cache()
            return

    torch.cuda.empty_cache()

    response=(max_score,best_answer)
    q.put(response,block=False)

def chunk(l, n):
    # loop over the list in n-sized chunks
    for i in range(0, len(l), n):
        # yield the current n-sized chunk to the calling function
        yield l[i: i + n]

if __name__ == "__main__":
    question = input("Search Phrase: ")

    print("Loading SQUAD tokenizer...")
    tokenizer = AutoTokenizer.from_pretrained(BERT_Squad_Model)
    print("Loading SQUAD model...")
    model = AutoModelForQuestionAnswering.from_pretrained(BERT_Squad_Model)
    model.to('cuda')
    model.share_memory()

    print("Accessing research papers...")
    procs=cpu_count()
    chunkedPaths = list(chunk(os.listdir('search_engine_contexts'), int(np.ceil(len(os.listdir('search_engine_contexts'))/float(procs/2)))))
    ctx = mp.get_context('spawn')
    q = ctx.Queue()

    processes=[]
    for i in range(len(chunkedPaths)):
        try:
            p=ctx.Process(target=process_file,args=(chunkedPaths[i],q,tokenizer,model,question,))
            processes.append(p)
            p.start()
        except RuntimeError:
            print("Breaking at number of processes = ",len(processes))
            torch.cuda.empty_cache()
            break

    results=[]
    liveprocs = processes
    while liveprocs:
        try:
            while True:
                return_sequence=q.get(block=False)
                results.append(return_sequence)
        except queue.Empty:
            pass

        time.sleep(0.5)
        if not q.empty():
            continue
        liveprocs = [p for p in liveprocs if p.is_alive()]

    for p in processes:
        p.join()

    while not q.empty():
        return_sequence=q.get(block=False)
        results.append(return_sequence)

    best_answer=max(results,key=lambda item:item[0])

    print("\n\n\n\n",best_answer,"\n\n\n\n")

    print("\n\n\n\n")
    with open("QAResults.txt",'w+') as f:
        line=str(best_answer[0])+" : "+str(best_answer[1])
        f.write(line)
    f.close()
    print("Results published!")


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from selenium import webdriver
import pickle
import sys

url_ps4 = "https://m.cafe.naver.com/jgameshop/4228"  # JGame NaverCafe Mobile Page Used PS4 Titles

def print_games(games, start=0):
    """
    :param games: 게임목록 리스트
    :param start: 출력을 시작할 행
    :return:
    """
    current = -1
    for i in games:
        current += 1
        if current < start:
            continue
        if i[0] == '#':
            continue
        print(i)

def check_equal_lists(list1, list2):
    for i in list1:
        if i not in list2:
            return False
    for j in list2:
        if j not in list1:
            return False
    return True

# 지난 정보 로딩
try:
    games_ps4_old = []
    f = open('ps4', 'rb')
    games_ps4_old = pickle.load(f)
    f.close()
except:
    print("ERROR : ps4 file read error")
finally:
    pass
    # print_games(games_ps4_old, 11)

# Chrome Headless 웹드라이버 설정
options = webdriver.ChromeOptions()
options.add_argument('headless')
driver = webdriver.Chrome('chromedriver', options=options)

# 새 정보 읽기
driver.get(url_ps4)
games_ps4_new = driver.find_element_by_xpath('//*[@id="postContent"]').text.split('\n')  # '\n' 으로 끊어서 List로
driver.quit()
# print(games_ps4_new[11:])

if check_equal_lists(games_ps4_old, games_ps4_new):
    print("변경이 없으므로 프로그램을 종료합니다.")
    sys.exit()

# 새 파일로 덮어쓰기
try:
    f = open('ps4', 'wb')
    pickle.dump(games_ps4_new, f)
    f.close()
except:
    print("ERROR : ps4 file write error")
finally:
    pass

# 게임변경 검색
games_ps4_sold = []
games_ps4_incomming = []
for old in games_ps4_old:
    if old not in games_ps4_new:
        games_ps4_sold.append(old)

for new in games_ps4_new:
    if new not in games_ps4_old:
        games_ps4_incomming.append(new)

print("팔린 PS4 Games")
print(games_ps4_sold)
print("새로들어온 PS4 Games")
print(games_ps4_incomming)


import discord

from discord import app_commands
from discord.ext import commands

PATRON_PERK_ROLES = [605349824472154134, 683559116731318423]
HELPER_ROLE = 705550299699478609

class NoConfigFailure(commands.CheckFailure):
    pass

async def helper_check(bot, user):
    try:
        support_member = await bot.get_guild(594276321937326091).fetch_member(user.id)
    except discord.NotFound:
        return False
    else:
        if any(r.id == HELPER_ROLE for r in support_member.roles):
            return True
        else:
            return False

async def check_guild_permissions(intr, perms, check=all):
    if await intr.client.is_owner(intr.user):
        return True
    is_owner = await intr.client.is_owner(intr.user)
    if is_owner:
        return True

    if intr.guild is None:
        raise commands.CheckFailure('You must be in a guild to run this command!')
    if intr.guild_id == 594276321937326091:
        # custom message for the support server
        raise commands.CheckFailure("You should run this command in your server! Get the invite link with `+invite`.")
    if await helper_check(intr.client, intr.user):
        return True

    resolved = intr.user.resolved_permissions
    return check(getattr(resolved, name, None) == value for name, value in perms.items())

def manage_guild():
    async def pred(interaction: discord.Interaction):
        perms = await check_guild_permissions(interaction, {'manage_guild': True})
        if not perms:
            raise commands.CheckFailure('You must have `Manage Server` permissions to use this command!')
        return True
    return app_commands.check(pred)

def is_patron_pred(ctx):
    if ctx.author.id in ctx.bot.owner_ids:
        return True

    guild = ctx.bot.get_guild(594276321937326091)
    if not guild:
        return False

    member = guild.get_member(ctx.author.id)
    if not member:
        return False

    return any(r.id in PATRON_PERK_ROLES for r in member.roles)

def is_patron():
    return commands.check(is_patron_pred)

async def before_invoke(ctx):
    config_type = getattr(ctx, 'config_type', None)
    if not config_type:
        return

    # invalidate = getattr(ctx, 'invalidate', False)
    error = getattr(ctx, 'error_without_config', False)
    channel = getattr(ctx, 'custom_channel', ctx.channel)

    if config_type in ['donationboard', 'trophyboard', 'lastonlineboard']:
        ctx.config = await ctx.bot.utils.board_config(channel.id)

    elif config_type == 'event':
        ctx.config = await ctx.bot.utils.event_config(ctx.guild.id)

    elif config_type == 'donationlog':
        ctx.config = await ctx.bot.utils.log_config(channel.id, 'donation')

    elif config_type == 'trophylog':
        ctx.config = await ctx.bot.utils.log_config(channel.id, 'trophy')

    elif config_type == 'legendlog':
        ctx.config = await ctx.bot.utils.log_config(channel.id, 'legend')

    if error and not ctx.config:
        raise NoConfigFailure(f'Please create a {config_type} with `+help add {config_type}`')

async def after_invoke(ctx):
    if not getattr(ctx, 'invalidate', False):
        return
    config_type = getattr(ctx, 'config_type', None)
    if not config_type:
        return

    if not getattr(ctx, 'config', None):
        return
    return ctx

def requires_config(config_type, error=False):
    async def pred(ctx):
        ctx.before_invoke = before_invoke
        ctx.after_invoke = after_invoke
        ctx.config_type = config_type
        ctx.error_without_config = error
        return True
    return commands.check(pred)


import fileio
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
from sklearn.metrics import accuracy_score
from sklearn.metrics import average_precision_score
import numpy as np
from matplotlib import pyplot as plt

trainX = fileio.pklOpener('trainSetDF.pkl')
testX = fileio.pklOpener('testSetDF.pkl')
trainY = trainX['SepsisLabel']
testY = testX['SepsisLabel']
trainX.drop(['SepsisLabel', 'Filename'], axis=1, inplace=True)
testX.drop(['SepsisLabel', 'Filename'], axis=1, inplace=True)

dictionaryroc = {}
dictionarypr = {}

cols = list(trainX.columns)
for column in cols:
    clf = LogisticRegression(max_iter=250, class_weight='balanced').fit(np.array(trainX[column]).reshape(-1, 1), trainY)
    out_prob = clf.predict_proba(np.array(testX[column]).reshape(-1, 1))
    auc = roc_auc_score(np.array(testY).reshape(-1, 1), out_prob[:, 1])
    ap = average_precision_score(np.array(testY).reshape(-1, 1), out_prob[:, 1])
    dictionaryroc[column] = auc
    dictionarypr[column] = ap

figroc = plt.figure(1, figsize=(10, 5))
figpr = plt.figure(2, figsize=(10, 5))

plt.figure(1)
plt.bar(list(dictionaryroc.keys()), list(dictionaryroc.values()))
plt.xticks(rotation=90, fontsize=6)
plt.xlabel("Feature")
plt.ylabel("AUROC w/ Logistic Regression")
figroc.savefig('uniAUROC')

plt.figure(2)
plt.bar(list(dictionarypr.keys()), list(dictionarypr.values()), color='red')
plt.xticks(rotation=90, fontsize=6)
plt.xlabel("Feature")
plt.ylabel("AUPRC w/ Logistic Regression")
figpr.savefig('uniAUPRC')


from persistente import *
from interface import WidgetInterface
from PyQt5.QtWidgets import QApplication

# Carrega tarefas do arquivo
load_task_list('task_bank.txt')

# Solicita ao usuário que insira tarefas
#get_user_tasks()

# Salva tarefas no arquivo
save_task_list('task_bank.txt')

## Bloco de chamada da interface gráfica
def startInterface():
    app = QApplication([])
    widget = WidgetInterface()
    widget.show()
    app.exec_()

if __name__ == '__main__':
    startInterface()
## Fim do bloco


import requests
import bs4
import re
from data.data import HEADERS

class Article:

    def __init__(self, url):
        response = requests.get(url, headers=HEADERS)
        response.raise_for_status()
        text = response.text
        soup = bs4.BeautifulSoup(text, features='html.parser')
        self.desc = soup.find(class_="tm-article-presenter__content tm-article-presenter__content_narrow")
        self.link = url

    def get_title(self):
        result = self.desc.find("h1").find("span")
        if not result:
            result = ""
        else:
            result = result.text

        return result

    def get_date(self):
        return self.desc.find(class_="tm-article-snippet__datetime-published").find("time").attrs["title"]

    def get_user(self):
        result = self.desc.find(class_="tm-user-info__username")
        if not result:
            result = ""
        else:
            result = result.text

        return result

    def get_hubs(self):
        result = ""
        list_text = self.desc.find_all(class_="tm-hubs-list__link")
        for elem in list_text:
            result += elem.text

        temp_text = self.desc.find(class_="tm-hubs-list__link router-link-active")
        if temp_text:
            result += temp_text.text

        return result

    def get_tags(self):
        result = ""
        list_text = self.desc.find_all(class_="tm-tags-list__link")
        for elem in list_text:
            result = result + elem.text + " "

        return result.strip()

    def get_body(self):
        return self.desc.find(class_="tm-article-body").text


from flask import Blueprint, render_template, redirect, request, flash
from . import db
from .models import Deck, Card
from datetime import datetime

views = Blueprint('views', __name__)

@views.route('/')
def index():
    return render_template('index.html')

@views.route('/dashboard/<username>')
def dashboard(username):
    decks = Deck.query.filter_by(creator=username).all()
    return render_template('dashboard.html', username=username, decks=decks)

@views.route('/begin/<deck_name>')
def begin(deck_name):
    t = datetime.now()
    deck = Deck.query.filter_by(deck_name=deck_name).first()
    deck.last_reviewed = t
    db.session.commit()

    return redirect('/review/' + deck_name)

@views.route('/review/<deck_name>')
def review(deck_name):
    card = Card.query.filter_by(part_of_deck=deck_name, card_id=1).first()
    if card == None:
        flash('Please create a card to review it.')
        return render_template('create_card.html', deck_name=deck_name)

    deck = Deck.query.filter_by(deck_name=deck_name).first()
    username = deck.creator
    return render_template('review.html',
                           card=card,
                           deck_name=deck_name,
                           username=username)

@views.route('/review/<deck_name>/<card_id>', methods=["GET", "POST"])
def review_next(deck_name, card_id):
    if request.method == "POST":
        partialscore = request.values.get('partialscore')

        c = Card.query.filter_by(part_of_deck=deck_name,
                                 card_id=card_id).first()
        c.partial = int(partialscore)

        db.session.commit()

        cards = Card.query.filter_by(part_of_deck=deck_name).all()
        total = 0
        for cd in cards:
            total = total + cd.partial

        count = Card.query.filter_by(part_of_deck=deck_name).count()
        new_score = int(total / count)

        deck = Deck.query.filter_by(deck_name=deck_name).first()

        username = deck.creator
        deck.score = new_score
        db.session.commit()

        card_id = int(card_id) + 1
        card = Card.query.filter_by(part_of_deck=deck_name,
                                    card_id=card_id).first()
        if card == None:
            return redirect('/dashboard/' + username)

        return render_template('review.html',
                               card=card,
                               deck_name=deck_name,
                               username=username)
    else:
        card = Card.query.filter_by(part_of_deck=deck_name,
                                    card_id=card_id).first()
        return render_template('review.html', card=card, deck_name=deck_name)

@views.route('/about')
def about():
    return render_template('about.html')

@views.route('/all_cards/<deck_name>')
def all_cards(deck_name):
    cards = Card.query.filter_by(part_of_deck=deck_name).all()
    deck = Deck.query.filter_by(deck_name=deck_name).first()
    print(deck)
    username = deck.creator
    return render_template('all_cards.html',
                           cards=cards,
                           deck_name=deck_name,
                           username=username)

@views.route('/create_card/<deck_name>')
def create_card(deck_name):
    return render_template('create_card.html', deck_name=deck_name)

@views.route('/create_card/<deck_name>', methods=["POST"])
def created_card(deck_name):
    front = request.form.get('front')
    back = request.form.get('back')

    if front == "" or back == "":
        flash('Card cannot be empty. Please try again.')
        return redirect('/create_card/' + deck_name)

    count = Card.query.filter_by(part_of_deck=deck_name).count()
    count = count + 1
    card = Card.query.filter_by(front=front, back=back,part_of_deck=deck_name).first()
    if card:
        flash('Card already exists')
        return redirect('/create_card/' + deck_name)

    new_card = Card(card_id=count,
                    part_of_deck=deck_name,
                    front=front,
                    back=back)

    db.session.add(new_card)
    db.session.commit()

    cards = Card.query.filter_by(part_of_deck=deck_name).all()
    return render_template('all_cards.html', cards=cards, deck_name=deck_name)

@views.route('/create_deck/<username>')
def create_deck(username):
    return render_template('create_deck.html', username=username)

@views.route('/create_deck/<username>', methods=["POST"])
def created_deck(username):
    deck_name = request.form.get('deck_name')

    count = Deck.query.count()
    count = count + 1
    deck = Deck.query.filter_by(deck_name=deck_name).first()

    if deck_name == "":
        flash('Deck name cannot be empty. Please try again.')
        return redirect('/create_deck/' + username)

    if deck:
        flash('Deck already exists')
        return redirect('/create_deck/' + username)

    new_deck = Deck(deck_id=count,
                    deck_name=deck_name,
                    creator=username,
                    score=None,
                    is_public=True)

    db.session.add(new_deck)
    db.session.commit()

    return redirect('/dashboard/' + username)

@views.route('/edit_card/<deck_name>/<card_id>')
def edit_card(deck_name, card_id):
    card = Card.query.filter_by(part_of_deck=deck_name,
                                card_id=card_id).first()

    return render_template('edit_card.html', card=card)

@views.route('/edit_card/<deck_name>/<card_id>', methods=["POST"])
def edited_card(deck_name, card_id):
    front = request.form.get('front')
    back = request.form.get('back')

    if front == "" or back == "":
        flash('Card cannot be empty. Please try again.')
        return redirect('/edit_card/' + deck_name + '/' + card_id)

    card = Card.query.filter_by(front=front, back=back,part_of_deck=deck_name).first()
    if card:
        flash('Card already exists')
        return redirect('/create_card/' + deck_name)

    Card.query.filter_by(card_id=card_id,
                         part_of_deck=deck_name).update(dict(front=front))
    Card.query.filter_by(card_id=card_id,
                         part_of_deck=deck_name).update(dict(back=back))
    db.session.commit()

    cards = Card.query.filter_by(part_of_deck=deck_name).all()
    return render_template('all_cards.html', cards=cards, deck_name=deck_name)

@views.route('/delete_card/<deck_name>/<card_id>')
def delete_card(deck_name, card_id):
    card = Card.query.filter_by(part_of_deck=deck_name,
                                card_id=card_id).first()

    db.session.delete(card)
    db.session.commit()

    return redirect('/all_cards/' + deck_name)

@views.route('/delete_deck/<deck_name>')
def delete_deck(deck_name):
    cards = Card.query.filter_by(part_of_deck=deck_name).all()
    for card in cards:
        db.session.delete(card)
    db.session.commit()

    deck = Deck.query.filter_by(deck_name=deck_name).first()
    username = deck.creator
    db.session.delete(deck)
    db.session.commit()

    return redirect('/dashboard/' + username)

@views.route('/edit_deck/<username>/<deck_name>')
def edit_deck(deck_name,username):
    deck = Deck.query.filter_by(deck_name=deck_name).first()
    return render_template('edit_deck.html', deck=deck,username=username)

@views.route('/edit_deck/<username>/<deck_name>', methods=["POST"])
def edited_deck(deck_name,username):
    new_deck_name = request.form.get('deck_name')

    deck = Deck.query.filter_by(deck_name=new_deck_name,creator=username).first()

    if deck:
        flash('Deck already exists')
        return redirect('/edit_deck/'+username+'/' + deck_name)

    Card.query.filter_by(part_of_deck=deck_name).update(dict(part_of_deck=new_deck_name))

    Deck.query.filter_by(deck_name=deck_name).update(
        dict(deck_name=new_deck_name))
    deck = Deck.query.filter_by(deck_name=new_deck_name).first()
    username = deck.creator
    db.session.commit()

    return redirect('/dashboard/' + username)


# Use https://www.si.umich.edu/programs/bachelor-science-
# information/bsi-admissions as a template.
# STEPS
# Create a similar HTML file but
# 1) Replace every occurrence of the word “student” with “AMAZING
# student.”
# 2) Replace the main picture with a picture of yourself.
# 3) Replace any local images with the image I provided in media.  (You
# must keep the image in a separate folder than your html code.

# Deliverables
# Make sure the new page is uploaded to your GitHub account.

import urllib.request, urllib.parse, urllib.error
from bs4 import BeautifulSoup

url = "https://www.si.umich.edu/programs/bachelor-science-information/bsi-admissions"
page = urllib.request.urlopen(url).read()
soup = BeautifulSoup(page, "html.parser")

soup1 = str(soup)
soup2 = soup1.replace("student", "AMAZING student")
soup3 = soup2.replace("https://www.youtube.com/embed/mimp_3gquc4?feature=oembed", "me.jpg")

final_soup = BeautifulSoup(soup3, "html.parser")

for p in final_soup.find_all(class_= "logo"):
	if p.img:
		p.img['src'] = "media/logo.png"
for p1 in final_soup.find_all(class_= "footer-logo"):
	if p1.img:
		p1.img['src'] = "media/logo.png"

f = open("bshw3.html", "w")
f.write (final_soup.prettify())
f.close()


import os, sys, pickle, math, time, re, xlwt
from nltk.tokenize import RegexpTokenizer

def sum_dict(a, b):
    temp = dict()
    for key in a.keys() | b.keys():
        temp[key] = sum([d.get(key, 0) for d in (a, b)])
    return temp

def get_size(obj, seen=None):
    size = sys.getsizeof(obj)
    if seen is None:
        seen = set()
    obj_id = id(obj)
    if obj_id in seen:
        return 0

    seen.add(obj_id)
    if isinstance(obj, dict):
        size += sum([get_size(v, seen) for v in obj.values()])
        size += sum([get_size(k, seen) for k in obj.keys()])
    elif hasattr(obj, '__dict__'):
        size += get_size(obj.__dict__, seen)
    elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)):
        size += sum([get_size(i, seen) for i in obj])
    return size

def rename():
    global map_num2oldPath, file_cnt
    if not os.path.exists(PATH):
        print("Wrong input path")
        exit(-1)
    if not os.path.exists(PATH_NEW):
        os.makedirs(PATH_NEW)

    cnt = 0
    for root, dirs, files in os.walk(PATH, topdown=True):
        for file in files:
            if cnt == 0:
                cnt += 1
                continue
            old_file_path = os.path.join(root, file)
            new_file_path = os.path.join(PATH_NEW, str(cnt))
            map_num2oldPath[cnt] = os.path.abspath(old_file_path)
            with open(old_file_path, "r+", newline="", encoding="ISO-8859-1") as f:
                content = f.readlines()[:]
            with open(new_file_path, "w+", newline="", encoding="ISO-8859-1") as f:
                f.writelines(content)
            cnt += 1
    file_cnt = cnt - 1

class InvertedIndex:
    def __init__(self):
        self.map_token = dict()
        self.map_token_chunk = dict()
        self.map_doc2len = dict()
        self.chunk_cnt = 1

    def build(self):
        if not os.path.exists(PATH_CHUNKS):
            os.makedirs(PATH_CHUNKS)
        i = 1
        for root, dirs, files in os.walk(PATH_NEW, topdown=True):
            dirs.sort()
            for file in sorted(files):
                self.spimi_invert(os.path.join(PATH_NEW, str(i)), i)
                i += 1

        chunk_path = os.path.join(PATH_CHUNKS, str(self.chunk_cnt) + ".txt")
        with open(chunk_path, "wb") as f:
            pickle.dump(self.map_token_chunk, f)
        self.map_token_chunk.clear()
        self.spimi_merge()

    def spimi_invert(self, doc_path, doc_id):
        with open(doc_path, "r+", encoding="ISO-8859-1") as file:
            content = file.read().lower()

        for term in RegexpTokenizer('[A-Za-z]+').tokenize(content):
            if sys.getsizeof(self.map_token_chunk) > 1000000:
                chunk_path = os.path.join(PATH_CHUNKS, str(self.chunk_cnt) + ".txt")
                with open(chunk_path, "wb") as file:
                    pickle.dump(self.map_token_chunk, file)
                self.map_token_chunk.clear()
                self.chunk_cnt += 1
            if term in self.map_token_chunk:
                if doc_id in self.map_token_chunk[term]:
                    self.map_token_chunk[term][doc_id] += 1
                else:
                    self.map_token_chunk[term][doc_id] = 1
            else:
                self.map_token_chunk[term] = dict()
                self.map_token_chunk[term][doc_id] = 1

    def spimi_merge(self):
        self.map_token.clear()
        for i in range(self.chunk_cnt):
            chunk_path = os.path.join(PATH_CHUNKS, str(i + 1) + ".txt")
            with open(chunk_path, "rb") as file:
                self.map_token_chunk = pickle.loads(file.read())
            term_total = set(self.map_token_chunk.keys()).union(set(self.map_token.keys()))
            for term in term_total:
                if term in self.map_token_chunk and term in self.map_token:
                    self.map_token[term] = sum_dict(self.map_token[term], self.map_token_chunk[term])
                elif term in self.map_token_chunk:
                    self.map_token[term] = self.map_token_chunk[term]

    def get_len(self):
        global file_cnt
        self.map_doc2len = dict()

        for term in self.map_token:
            df = file_cnt / len(self.map_token[term])
            for doc_id in self.map_token[term]:
                temp = (1 + math.log10(self.map_token[term][doc_id])) * math.log10(df)
                if doc_id in self.map_doc2len:
                    self.map_doc2len[doc_id] += temp * temp
                else:
                    self.map_doc2len[doc_id] = temp * temp
        for term in self.map_doc2len:
            self.map_doc2len[term] = math.sqrt(self.map_doc2len[term])

    def cosine_search(self, query):
        global file_cnt
        query_cnt = dict()
        scores = dict()
        for term in query.lower().split(" "):
            if term in query_cnt:
                query_cnt[term] += 1
            else:
                query_cnt[term] = 1
        for term in query_cnt:
            if term in self.map_token:
                df = file_cnt / len(self.map_token[term])
                for doc_id in self.map_token[term]:
                    token_w = (1 + math.log10(self.map_token[term][doc_id])) * math.log10(df)
                    query_w = (1 + math.log10(query_cnt[term])) * math.log10(df)
                    if doc_id in scores:
                        scores[doc_id] += token_w * query_w
                    else:
                        scores[doc_id] = token_w * query_w
        for term in scores:
            scores[term] /= self.map_doc2len[term]
        return scores

if __name__ == "__main__":
    PATH = "D:/Code_PyCharm/IR/20_newsgroups"
    PATH_NEW = "D:/Code_PyCharm/IR/new_files"
    PATH_CHUNKS = "D:/Code_PyCharm/IR/chunks"
    map_num2oldPath = dict()
    file_cnt = 0
    print("IR System is starting, please wait for a minute...")
    rename()
    words = InvertedIndex()
    words.build()
    words.get_len()
    print("Finished.")
    while True:
        user_input = input("What do you wanna search?")
        top10 = list(words.cosine_search(user_input).items())
        top10.sort(key=lambda x: x[1], reverse=True)
        print("Result:")
        if top10:
            for doc_term in top10[:10]:
                print(map_num2oldPath[doc_term[0]])
        else:
            print('Sorry. Nothing found.')


r"""Animate the display or removal of a mobject from a scene.

.. manim:: CreationModule
    :hide_source:

    from manim import ManimBanner
    class CreationModule(Scene):
        def construct(self):
            s1 = Square()
            s2 = Square()
            s3 = Square()
            s4 = Square()
            VGroup(s1, s2, s3, s4).set_x(0).arrange(buff=1.9).shift(UP)
            s5 = Square()
            s6 = Square()
            s7 = Square()
            VGroup(s5, s6, s7).set_x(0).arrange(buff=2.6).shift(2 * DOWN)
            t1 = Text("Write", font_size=24).next_to(s1, UP)
            t2 = Text("AddTextLetterByLetter", font_size=24).next_to(s2, UP)
            t3 = Text("Create", font_size=24).next_to(s3, UP)
            t4 = Text("Uncreate", font_size=24).next_to(s4, UP)
            t5 = Text("DrawBorderThenFill", font_size=24).next_to(s5, UP)
            t6 = Text("ShowIncreasingSubsets", font_size=22).next_to(s6, UP)
            t7 = Text("ShowSubmobjectsOneByOne", font_size=22).next_to(s7, UP)

            self.add(s1, s2, s3, s4, s5, s6, s7, t1, t2, t3, t4, t5, t6, t7)

            texts = [Text("manim", font_size=29), Text("manim", font_size=29)]
            texts[0].move_to(s1.get_center())
            texts[1].move_to(s2.get_center())
            self.add(*texts)

            objs = [ManimBanner().scale(0.25) for _ in range(5)]
            objs[0].move_to(s3.get_center())
            objs[1].move_to(s4.get_center())
            objs[2].move_to(s5.get_center())
            objs[3].move_to(s6.get_center())
            objs[4].move_to(s7.get_center())
            self.add(*objs)

            self.play(
                # text creation
                Write(texts[0]),
                AddTextLetterByLetter(texts[1]),
                # mobject creation
                Create(objs[0]),
                Uncreate(objs[1]),
                DrawBorderThenFill(objs[2]),
                ShowIncreasingSubsets(objs[3]),
                ShowSubmobjectsOneByOne(objs[4]),
                run_time=3,
            )

            self.wait()

"""

__all__ = [
    "Create",
    "Uncreate",
    "DrawBorderThenFill",
    "Write",
    "Unwrite",
    "ShowPartial",
    "ShowIncreasingSubsets",
    "AddTextLetterByLetter",
    "ShowSubmobjectsOneByOne",
    "AddTextWordByWord",
]

import itertools as it
from typing import (
    TYPE_CHECKING,
    Callable,
    Dict,
    Iterable,
    Optional,
    Sequence,
    Tuple,
    Union,
)

import numpy as np
from colour import Color

if TYPE_CHECKING:
    from manim.mobject.svg.text_mobject import Text

from ..animation.animation import Animation
from ..animation.composition import Succession
from ..mobject.mobject import Group, Mobject
from ..mobject.types.opengl_surface import OpenGLSurface
from ..mobject.types.opengl_vectorized_mobject import OpenGLVMobject
from ..mobject.types.vectorized_mobject import VMobject
from ..utils.bezier import integer_interpolate
from ..utils.rate_functions import double_smooth, linear, smooth

class ShowPartial(Animation):
    """Abstract class for Animations that show the VMobject partially.

    Raises
    ------
    :class:`TypeError`
        If ``mobject`` is not an instance of :class:`~.VMobject`.

    See Also
    --------
    :class:`Create`, :class:`~.ShowPassingFlash`

    """

    def __init__(
        self, mobject: Union[VMobject, OpenGLVMobject, OpenGLSurface, None], **kwargs
    ):
        pointwise = getattr(mobject, "pointwise_become_partial", None)
        if not callable(pointwise):
            raise NotImplementedError("This animation is not defined for this Mobject.")
        super().__init__(mobject, **kwargs)

    def interpolate_submobject(
        self,
        submobject: Mobject,
        starting_submobject: Mobject,
        alpha: float,
    ) -> None:
        submobject.pointwise_become_partial(
            starting_submobject, *self._get_bounds(alpha)
        )

    def _get_bounds(self, alpha: float) -> None:
        raise NotImplementedError("Please use Create or ShowPassingFlash")

class Create(ShowPartial):
    """Incrementally show a VMobject.

    Parameters
    ----------
    mobject : :class:`~.VMobject`
        The VMobject to animate.

    Raises
    ------
    :class:`TypeError`
        If ``mobject`` is not an instance of :class:`~.VMobject`.

    Examples
    --------
    .. manim:: CreateScene

        class CreateScene(Scene):
            def construct(self):
                self.play(Create(Square()))

    See Also
    --------
    :class:`~.ShowPassingFlash`

    """

    def __init__(
        self,
        mobject: Union[VMobject, OpenGLVMobject, OpenGLSurface],
        lag_ratio: float = 1.0,
        **kwargs,
    ) -> None:
        super().__init__(mobject, lag_ratio=lag_ratio, **kwargs)

    def _get_bounds(self, alpha: float) -> Tuple[int, float]:
        return (0, alpha)

class Uncreate(Create):
    """Like :class:`Create` but in reverse.

    Examples
    --------
    .. manim:: ShowUncreate

        class ShowUncreate(Scene):
            def construct(self):
                self.play(Uncreate(Square()))

    See Also
    --------
    :class:`Create`

    """

    def __init__(
        self,
        mobject: Union[VMobject, OpenGLVMobject],
        rate_func: Callable[[float], float] = lambda t: smooth(1 - t),
        remover: bool = True,
        **kwargs,
    ) -> None:
        super().__init__(mobject, rate_func=rate_func, remover=remover, **kwargs)

class DrawBorderThenFill(Animation):
    """Draw the border first and then show the fill.

    Examples
    --------
    .. manim:: ShowDrawBorderThenFill

        class ShowDrawBorderThenFill(Scene):
            def construct(self):
                self.play(DrawBorderThenFill(Square(fill_opacity=1, fill_color=ORANGE)))
    """

    def __init__(
        self,
        vmobject: Union[VMobject, OpenGLVMobject],
        run_time: float = 2,
        rate_func: Callable[[float], float] = double_smooth,
        stroke_width: float = 2,
        stroke_color: str = None,
        draw_border_animation_config: Dict = {},  # what does this dict accept?
        fill_animation_config: Dict = {},
        **kwargs,
    ) -> None:
        self._typecheck_input(vmobject)
        super().__init__(vmobject, run_time=run_time, rate_func=rate_func, **kwargs)
        self.stroke_width = stroke_width
        self.stroke_color = stroke_color
        self.draw_border_animation_config = draw_border_animation_config
        self.fill_animation_config = fill_animation_config
        self.outline = self.get_outline()

    def _typecheck_input(self, vmobject: Union[VMobject, OpenGLVMobject]) -> None:
        if not isinstance(vmobject, (VMobject, OpenGLVMobject)):
            raise TypeError("DrawBorderThenFill only works for vectorized Mobjects")

    def begin(self) -> None:
        self.outline = self.get_outline()
        super().begin()

    def get_outline(self) -> Mobject:
        outline = self.mobject.copy()
        outline.set_fill(opacity=0)
        for sm in outline.family_members_with_points():
            sm.set_stroke(color=self.get_stroke_color(sm), width=self.stroke_width)
        return outline

    def get_stroke_color(self, vmobject: Union[VMobject, OpenGLVMobject]) -> Color:
        if self.stroke_color:
            return self.stroke_color
        elif vmobject.get_stroke_width() > 0:
            return vmobject.get_stroke_color()
        return vmobject.get_color()

    def get_all_mobjects(self) -> Sequence[Mobject]:
        return [*super().get_all_mobjects(), self.outline]

    def interpolate_submobject(
        self,
        submobject: Mobject,
        starting_submobject: Mobject,
        outline,
        alpha: float,
    ) -> None:  # Fixme: not matching the parent class? What is outline doing here?
        index: int
        subalpha: int
        index, subalpha = integer_interpolate(0, 2, alpha)
        if index == 0:
            submobject.pointwise_become_partial(outline, 0, subalpha)
            submobject.match_style(outline)
        else:
            submobject.interpolate(outline, starting_submobject, subalpha)

class Write(DrawBorderThenFill):
    """Simulate hand-writing a :class:`~.Text` or hand-drawing a :class:`~.VMobject`.

    Examples
    --------
    .. manim:: ShowWrite

        class ShowWrite(Scene):
            def construct(self):
                self.play(Write(Text("Hello", font_size=144)))

    .. manim:: ShowWriteReversed

        class ShowWriteReversed(Scene):
            def construct(self):
                self.play(Write(Text("Hello", font_size=144), reverse=True))
    """

    def __init__(
        self,
        vmobject: Union[VMobject, OpenGLVMobject],
        rate_func: Callable[[float], float] = linear,
        reverse: bool = False,
        **kwargs,
    ) -> None:
        run_time: Optional[float] = kwargs.pop("run_time", None)
        lag_ratio: Optional[float] = kwargs.pop("lag_ratio", None)
        run_time, lag_ratio = self._set_default_config_from_length(
            vmobject,
            run_time,
            lag_ratio,
        )
        self.reverse = reverse
        super().__init__(
            vmobject,
            rate_func=rate_func,
            run_time=run_time,
            lag_ratio=lag_ratio,
            **kwargs,
        )

    def _set_default_config_from_length(
        self,
        vmobject: Union[VMobject, OpenGLVMobject],
        run_time: Optional[float],
        lag_ratio: Optional[float],
    ) -> Tuple[float, float]:
        length = len(vmobject.family_members_with_points())
        if run_time is None:
            if length < 15:
                run_time = 1
            else:
                run_time = 2
        if lag_ratio is None:
            lag_ratio = min(4.0 / length, 0.2)
        return run_time, lag_ratio

    def reverse_submobjects(self) -> None:
        self.mobject.invert(recursive=True)

    def begin(self) -> None:
        if self.reverse:
            self.reverse_submobjects()
        super().begin()

    def finish(self) -> None:
        super().finish()
        if self.reverse:
            self.reverse_submobjects()

class Unwrite(Write):
    """Simulate erasing by hand a :class:`~.Text` or a :class:`~.VMobject`.

    Parameters
    ----------
    reverse : :class:`bool`
        Set True to have the animation start erasing from the last submobject first.

    Examples
    --------

    .. manim :: UnwriteReverseTrue

        class UnwriteReverseTrue(Scene):
            def construct(self):
                text = Tex("Alice and Bob").scale(3)
                self.add(text)
                self.play(Unwrite(text))

    .. manim:: UnwriteReverseFalse

        class UnwriteReverseFalse(Scene):
            def construct(self):
                text = Tex("Alice and Bob").scale(3)
                self.add(text)
                self.play(Unwrite(text, reverse=False))
    """

    def __init__(
        self,
        vmobject: VMobject,
        rate_func: Callable[[float], float] = linear,
        reverse: bool = True,
        **kwargs,
    ) -> None:

        run_time: Optional[float] = kwargs.pop("run_time", None)
        lag_ratio: Optional[float] = kwargs.pop("lag_ratio", None)
        run_time, lag_ratio = self._set_default_config_from_length(
            vmobject,
            run_time,
            lag_ratio,
        )
        super().__init__(
            vmobject,
            run_time=run_time,
            lag_ratio=lag_ratio,
            rate_func=lambda t: -rate_func(t) + 1,
            reverse=reverse,
            **kwargs,
        )

class ShowIncreasingSubsets(Animation):
    """Show one submobject at a time, leaving all previous ones displayed on screen.

    Examples
    --------

    .. manim:: ShowIncreasingSubsetsScene

        class ShowIncreasingSubsetsScene(Scene):
            def construct(self):
                p = VGroup(Dot(), Square(), Triangle())
                self.add(p)
                self.play(ShowIncreasingSubsets(p))
                self.wait()
    """

    def __init__(
        self,
        group: Mobject,
        suspend_mobject_updating: bool = False,
        int_func: Callable[[np.ndarray], np.ndarray] = np.floor,
        **kwargs,
    ) -> None:
        self.all_submobs = list(group.submobjects)
        self.int_func = int_func
        for mobj in self.all_submobs:
            mobj.set_opacity(0)
        super().__init__(
            group, suspend_mobject_updating=suspend_mobject_updating, **kwargs
        )

    def interpolate_mobject(self, alpha: float) -> None:
        n_submobs = len(self.all_submobs)
        index = int(self.int_func(alpha * n_submobs))
        self.update_submobject_list(index)

    def update_submobject_list(self, index: int) -> None:
        for mobj in self.all_submobs[:index]:
            mobj.set_opacity(1)

class AddTextLetterByLetter(ShowIncreasingSubsets):
    """Show a :class:`~.Text` letter by letter on the scene.

    Parameters
    ----------
    time_per_char : :class:`float`
        Frequency of appearance of the letters.

    .. tip::

        This is currently only possible for class:`~.Text` and not for class:`~.MathTex`

    """

    def __init__(
        self,
        text: "Text",
        suspend_mobject_updating: bool = False,
        int_func: Callable[[np.ndarray], np.ndarray] = np.ceil,
        rate_func: Callable[[float], float] = linear,
        time_per_char: float = 0.1,
        run_time: Optional[float] = None,
        **kwargs,
    ) -> None:
        # time_per_char must be above 0.06, or the animation won't finish
        self.time_per_char = time_per_char
        if run_time is None:
            run_time = np.max((0.06, self.time_per_char)) * len(text)

        super().__init__(
            text,
            suspend_mobject_updating=suspend_mobject_updating,
            int_func=int_func,
            rate_func=rate_func,
            run_time=run_time,
            **kwargs,
        )

class ShowSubmobjectsOneByOne(ShowIncreasingSubsets):
    """Show one submobject at a time, removing all previously displayed ones from screen."""

    def __init__(
        self,
        group: Iterable[Mobject],
        int_func: Callable[[np.ndarray], np.ndarray] = np.ceil,
        **kwargs,
    ) -> None:
        new_group = Group(*group)
        super().__init__(new_group, int_func=int_func, **kwargs)

    def update_submobject_list(self, index: int) -> None:
        current_submobjects = self.all_submobs[:index]
        for mobj in current_submobjects[:-1]:
            mobj.set_opacity(0)
        if len(current_submobjects) > 0:
            current_submobjects[-1].set_opacity(1)

# TODO, this is broken...
class AddTextWordByWord(Succession):
    """Show a :class:`~.Text` word by word on the scene. Note: currently broken."""

    def __init__(
        self,
        text_mobject: "Text",
        run_time: float = None,
        time_per_char: float = 0.06,
        **kwargs,
    ) -> None:
        self.time_per_char = time_per_char
        tpc = self.time_per_char
        anims = it.chain(
            *(
                [
                    ShowIncreasingSubsets(word, run_time=tpc * len(word)),
                    Animation(word, run_time=0.005 * len(word) ** 1.5),
                ]
                for word in text_mobject
            )
        )
        super().__init__(*anims, **kwargs)


"""
test_opsiservice
"""

from pathlib import Path

import pytest

from opsicli.config import OPSIService, config
from opsicli.opsiservice import jsonrpc_client  # pylint: disable=unused-import
from opsicli.opsiservice import (
	get_service_connection,
	get_service_credentials_from_backend,
)

from .utils import container_connection

@pytest.mark.skipif(not Path("/etc/opsi/backends").exists(), reason="need local backend for this test")
def test_get_service_credentials_from_backend() -> None:
	(host_id, host_key) = get_service_credentials_from_backend()
	assert host_id
	assert host_key

@pytest.mark.skipif(not Path("/etc/opsi/backends").exists(), reason="need local backend for this test")
def test_get_service_connection_local() -> None:
	local_connection = get_service_connection()
	assert local_connection
	result = local_connection.jsonrpc("backend_getInterface")
	print(result)
	assert "host_getObjects" in str(result)

@pytest.mark.skipif(not Path("/etc/opsi/backends").exists(), reason="need local backend for this test")
def test_get_service_connection_half_configured_service() -> None:
	global jsonrpc_client  # pylint: disable=global-statement
	jsonrpc_client = None
	config.services.append(OPSIService("pytest_test_service", "https://localhost:4447"))
	config.service = "pytest_test_service"
	connection = get_service_connection()
	result = connection.jsonrpc("backend_getInterface")
	print(result)
	assert "host_getObjects" in str(result)

@pytest.mark.requires_testcontainer
def test_get_service_connection() -> None:
	with container_connection():
		connection = get_service_connection()
		assert connection
		result = connection.jsonrpc("backend_getInterface")
		print(result)
		assert "host_getObjects" in str(result)


"""Wind prediction model"""

import os
import pandas as pd
import numpy as np
from statsmodels.tsa.arima.model import ARIMAResults, ARIMA
from statsmodels.tsa.statespace.varmax import VARMAX, VARMAXResults
from typing import Tuple
from tqdm.autonotebook import trange
import statsmodels.api as sm

INTERVAL = pd.Timedelta(minutes=15)

def read_file(dir_path='./', processed=False) -> pd.DataFrame:
    if os.path.exists(dir_path+'ERDCSlow.hdf5') and processed:
        df = pd.read_hdf(dir_path+'ERDCSlow.hdf5', key='table', index_col='Time')
    else:
        df = pd.read_csv(dir_path + 'ERDCSlow.csv',
                        index_col='Time', parse_dates=['Time'])
        cols = []
        for col in df.columns:
            c = pd.to_numeric(df[col], errors='coerce', downcast='float')
            cols.append(c)
        df = pd.concat(cols, axis=1)

        df = df[['Speed', 'Direction', 'Temp']]
        df = df.dropna(axis=0, how='any')
        df.to_hdf(dir_path + '/ERDCSlow.hdf5', key='table')
    df['dx'] = np.cos(df.Direction)
    df['dy'] = np.sin(df.Direction)
    return df

def find_sequences(df, interval=pd.Timedelta(minutes=1), agg_fn='mean'):
    resampler = df.resample(interval)
    if agg_fn=='mean':
        dfm = resampler.mean()
    elif agg_fn=='max':
        dfm = resampler.max()
    elif isinstance(agg_fn, float):
        dfm = resampler.quantile(agg_fn)
    i, ii = 0, dfm.index[0]
    j, jj = 1, dfm.index[1]
    seqs = []
    while j < len(dfm):
        while i < len(dfm):
            if not np.isnan(dfm.Speed.iloc[i]):
                break
            i += 1
        j = i+1
        while j <= len(dfm):
            if j==len(dfm) or np.isnan(dfm.Speed.iloc[j]):
                seqs.append(dfm.iloc[i:j])
                i = j+1
                break
            j += 1

    for s in seqs:
        s.index.freq = interval

    return [s for s in seqs if len(s)>=4]

def pretrain(model_class, data: pd.DataFrame, exog=None, **kwargs) -> ARIMA:
    model = model_class(data, exog=exog, **kwargs)
    return model.fit()

def update(result: ARIMAResults, data: pd.DataFrame, exog, interval, append=True):
    if data.index[-1] - result.data.dates[-1] > interval:
        model = result.model.clone(data, exog=exog)
        result = model.fit(start_params=result.params)
    else:
        if append:
            result = result.append(data, exog=exog, refit=True)
        else:
            result = result.extend
    return result

def predict(result: ARIMAResults, data: pd.DataFrame, exog, interval, in_sample=True) -> Tuple[ARIMAResults, float]:
    if data.index[0] - result.data.dates[-1] > interval:
       result = result.apply(data, exog=exog)
    else:
        result = result.append(data, exog=exog)
    if in_sample:
        pred = result.predict(start=data.index[0], dynamic=False)
    else:
        # pred = result.forecast(steps=1)
        pred = result.predict(start=data.index[0], dynamic=0)
    return result, pred

def trial(
    interval, order, df, seq_kwargs={}, filter_fn=lambda df: df, split=0.25,
    endog_col='Speed', exog_cols=None
):
    df = filter_fn(df)
    seqs = find_sequences(df, interval, **seq_kwargs)
    # leave one out testing
    rmses = []
    rmses_persistent = []
    ntest = 0
    splits = int(len(seqs) * split)

    for i in trange(len(seqs), leave=False, desc='splits'):
        if isinstance(split, float) and 0<split<1:
            ntrain = int(len(seqs[i]) * (1-split))
            dtrain = [seqs[i].iloc[:ntrain]]
            dtest = [seqs[i].iloc[ntrain:]]
        else:
            if i==split:
                break
            dtest = [seqs[i]]
            dtrain = [seqs[j] for j in range(splits) if j!=i]

        endog = dtrain[0][endog_col]
        exog = exog_cols if exog_cols is None else dtrain[0][exog_cols]
        res = pretrain(sm.tsa.ARIMA, endog, exog=exog, order=order)
        for dft in dtrain[1:]:
            endog = dft[endog_col]
            exog = exog_cols if exog_cols is None else dft[exog_cols]
            res = update(res, endog, exog=exog, interval=interval)
        for dft in dtest:
            if dft.index[0] < res.data.dates[-1]:
                dft = dft.copy()
                dft.index += (res.data.dates[-1] - dft.index[0]) + (2 * interval)
                dft.index.freq = interval
            ntest += len(dft)
            # predictions = []
            # for k in trange(len(dft.Speed), leave=False, desc='instance'):
            #     res, pred = predict(res, dft.Speed.iloc[k:k+1], interval)
            #     predictions.append(pred)
            # pred = pd.concat(predictions)
            endog = dft[endog_col]
            exog = exog_cols if exog_cols is None else dft[exog_cols]
            res, pred = predict(res, endog, exog, interval)
            rmses.append(sm.tools.eval_measures.rmse(pred, endog) * len(dft))
            rmses_persistent.append(sm.tools.eval_measures.rmse(endog.iloc[:-1], endog.iloc[1:]) * (len(dft)-1))
            print(f'Split {i} \tRMSE: {rmses[-1]/len(dft):.2f}')
    return dict(
        rmse=sum(rmses) / ntest,
        rmse_persistent=sum(rmses_persistent) / (ntest - splits)
    )

def train_model(interval, order, df, endog_col, exog_cols, seq_kwargs={}):
    seqs = find_sequences(df, interval, **seq_kwargs)
    endog = seqs[0][endog_col]
    exog = exog_cols if exog_cols is None else seqs[0][exog_cols]
    res = pretrain(sm.tsa.ARIMA, endog, exog=exog, order=order)
    for dft in seqs[1:]:
        endog = dft[endog_col]
        exog = exog_cols if exog_cols is None else dft[exog_cols]
        res = update(res, endog, exog=exog, interval=interval)
    return res

def save_arma_model(res, path):
    pass

def load_arma_model(path) -> ARIMA:
    pass

def save_combined_model(models, path='arma_model.pickle'):
    import pickle
    with open(path, 'wb') as f:
        pickle.dump(models, f)

def load_combined_model(path='arma_model.pickle'):
    import pickle
    with open(path, 'rb') as f:
        return pickle.load(f)

def combined_predict(df, res=Tuple[ARIMAResults, ARIMAResults, ARIMAResults], interval=INTERVAL):
    arma_speed, arma_dx, arma_dy = res
    arma_speed, pred_speed = predict(arma_speed, df.Speed, None, interval=interval)
    arma_dx, pred_dx = predict(arma_dx, df.dx, None, interval=interval)
    arma_dy, pred_dy = predict(arma_dy, df.dy, None, interval=interval)
    pred = pd.concat((pred_speed, pred_dx, pred_dy), axis=1)
    pred.columns = ['Speed', 'dx', 'dy']
    return(arma_speed, arma_dx, arma_dy), pred

if __name__=='__main__':
    import sys
    df = read_file(processed=True)
    dfog = df # original dataframe with all data
    # Testing data
    dft = dfog.loc['2022-06-28':'2022-07-07']
    # Training data
    df = dfog.loc['2022-03-10':'2022-06-27']
    if sys.argv[1]=='train':
        print('Training models')
        arma_speed = train_model(INTERVAL, (1,0,20), df, 'Speed', None)
        arma_dx = train_model(INTERVAL, (1,0,20), df, 'dx', None)
        arma_dy = train_model(INTERVAL, (1,0,20), df, 'dy', None)

        save_combined_model((arma_speed, arma_dx, arma_dy))
    else:
        print('Loading and testing model')
        res = load_combined_model()
        seqs = find_sequences(dft, INTERVAL)
        res, pred = combined_predict(seqs[0], res)
        print(pred.head())

        rmse_speed = sm.tools.eval_measures.rmse(pred.Speed, seqs[0].Speed)
        rmse_dx = sm.tools.eval_measures.rmse(pred.dx, seqs[0].dx)
        rmse_dy = sm.tools.eval_measures.rmse(pred.dx, seqs[0].dy)
        print(f'rmse_speed (m/s)={rmse_speed:.2f}')
        print(f'rmse_dx (cos(direction))={rmse_dx:.2f}')
        print(f'rmse_dy (sin(direction))={rmse_dy:.2f}')


# db 연동
import sqlite3
from datetime import datetime

# print(sqlite3.version)
# print(sqlite3.sqlite_version)

# # 남짜 생성
now = datetime.now()
# print("now", now)
now_date_time = now.strftime("%Y-%m-%d %H:%M:%S")
# print("now_date_time", now_date_time)

conn = sqlite3.connect("data/database.db", isolation_level=None)

# 커서
cursor = conn.cursor()  # <class 'sqlite3.Cursor'>
print(type(cursor))

# 테이블 생성
cursor.execute(
    "CREATE TABLE IF NOT EXISTS user(id integer primary key,username text, phon text,website text,regdate text)"
)

# insert
# cursor.execute(
#     "INSERT INTO user VALUES(1,'KIM','010-1234-1234','kim.com',?)", (now_date_time,)
# )

# cursor.execute(
#     "INSERT INTO user VALUES(?,?,?,?,?)",
#     (
#         2,
#         "hong",
#         "010-1234-4567",
#         "hong.com",
#         now_date_time,
#     ),
# )

# 여러개 삽입
user_list = (
    (3, "park", "010-4567-1234", "park.com", now_date_time),
    (4, "choi", "010-9876-1234", "choi.com", now_date_time),
    (5, "yoo", "010-3687-1234", "yoo.com", now_date_time),
)

cursor.executemany("INSERT INTO user VALUES(?,?,?,?,?)", user_list)


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

N, M = map(int, input().split())
graph = [[] for _ in range(N+1)]
indgree = [0] * (N+1)

for _ in range(M):
    a, b = map(int, input().split())
    graph[a].append(b)
    indgree[b] += 1

queue = deque()
for i in range(1, N+1):
    if indgree[i] == 0:
        queue.append(i)

result = []
while queue:
    idx = queue.popleft()
    result.append(idx)

    for i in graph[idx]:
        indgree[i] -= 1
        if indgree[i] == 0:
            queue.append(i)

for i in result:
    print(i, end=" ")

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

# n, m = map(int, input().split())
# L = []
# degree = [0] * 32001
# graph = [[] for _ in range(32001)]
# queue = deque()

# for i in range(m):
#     a, b = map(int, input().split())
#     L.append([a, b])

# for a, b in L:
#     degree[b] += 1
#     graph[a].append(b)

# for i in range(1, n + 1):
#     if degree[i] == 0:
#         queue.append(i)

# while queue:
#     student = queue.popleft()
#     for j in graph[student]:
#         degree[j] -= 1
#         if degree[j] == 0:
#             queue.append(j)

#     print(student, end = ' ')


import pygame
from HelperFunctions import load_full_screen_image
from buttons import MouseCollider
from buttons import ButtonType, check_for_and_handle_button_click, Button

class HelpScreen:
    """Handles the visual elements of the help screen and the buttons on it. This includes creating the buttons and responding to button clicks."""

    def __init__(self, display_surface, ScreenDimensions):
        self.display_surface = display_surface
        self.ScreenDimensions = ScreenDimensions
        self.help_screen_1 = load_full_screen_image(
            ScreenDimensions,
            "Assets\\Help Screen\\help_screen_1_high_res.png",
            "Assets\\Help Screen\\help_screen_1.png",
        )
        self.help_screen_2 = load_full_screen_image(
            ScreenDimensions,
            "Assets\\Help Screen\\help_screen_2_high_res.png",
            "Assets\\Help Screen\\help_screen_2.png",
        )
        self.current_help_screen = self.help_screen_1
        self.MouseCollider = MouseCollider(
            pygame.mouse.get_pos(), self.display_surface, self.ScreenDimensions
        )

        self.help_buttons: pygame.sprite.Group() = self.create_buttons()
        self.button_pressed: (None | ButtonType) = None

    def create_buttons(self):
        buttons = pygame.sprite.Group()
        # Level 1
        buttons.add(
            Button(
                button_type=ButtonType.help_home,
                display_surface=self.display_surface,
                ScreenDimensions=self.ScreenDimensions,
            )
        )
        buttons.add(
            Button(
                button_type=ButtonType.help_next,
                display_surface=self.display_surface,
                ScreenDimensions=self.ScreenDimensions,
            )
        )
        return buttons

    def detect_button_interaction(self, help_buttons, MouseCollider, events):
        for help_button in help_buttons:
            if pygame.sprite.collide_mask(MouseCollider, help_button):
                help_button.image = help_button.image_dict["selected"]
                button_clicks = check_for_and_handle_button_click(events, help_button)
                if button_clicks != None:
                    self.button_pressed = button_clicks
            else:
                help_button.image = help_button.image_dict["unselected"]

    def update(self, events):
        self.display_surface.blit(self.current_help_screen, (0, 0))
        if (
            self.current_help_screen == self.help_screen_1
        ):  # conditional statement to only render the next button on the first help screen
            self.help_buttons.update()
        else:
            self.help_buttons.update([ButtonType.help_next])
        self.MouseCollider.update(pygame.mouse.get_pos())
        self.detect_button_interaction(self.help_buttons, self.MouseCollider, events)


#Script to scrape metacritic and exrapolate description, metascore link, and description
from bs4 import BeautifulSoup
from datetime import datetime
from django.utils import timezone
from django.core.cache import cache
import logging, traceback, urllib2

BASE_URL='http://www.metacritic.com'
TEMPLATE_GENRE_URL=BASE_URL + '/browse/games/genre/metascore/GENRE/PLATFORM?view=condensed&page=PAGE'
GENRES=('action','adventure','fighting','first-person','flight',
        'party','platformer','puzzle','racing','real-time','role-playing',
        'simulation','sports','strategy','third-person',)
PLATFORM_MAP={'pc':'pc', 'ps4':'playstation-4', 'ps3':'playstation-3',
  'xboxone':'xbox-one','xbox360':'xbox-360','wii-u':'wii-u','3ds':'3ds',
  'ios':'ios'}
LOGGER = logging.getLogger(__name__)

def parse(link):
  response = urllib2.urlopen(link)
  soup = BeautifulSoup(response.read())
  response.close()
  return soup

#return critic,user rating tuple
def getMetacriticScore(url):
  result=cache.get(url)
  if result is None:
    soup=parse(url)
    try:
      critic=int(soup.find('span',{'itemprop':'ratingValue'}).string)
    except:
      critic='tbd'
    try:
      user=float(soup.find('div',{'class':'metascore_w user large game positive'}).string)
    except:
      user='tbd'
    result=(critic,user,getColor(critic,100),getColor(user,10))
    cache.set(url,result,60*60*24)
  return result

def getColor(score,scale):
  if isinstance(score, basestring):
    return 'LightGray'
  elif score >= scale*.6:
    return 'Green'
  elif score >= scale*.5:
    return 'Orange'
  else:
    return 'Red'

def extractString(element):
  return str(element.contents[0]).strip()

#Parse summary from soup
def parseSummary(soup):
  summary = ''
  for summaryDetailsElement in soup.findAll('ul', attrs={'class':'summary_details'}):
    for summaryElement in summaryDetailsElement.findAll('span', attrs={'class':'blurb blurb_collapsed'}):
      summary = extractString(summaryElement)
    for summaryElement in summaryDetailsElement.findAll('span', attrs={'class':'blurb blurb_expanded'}):
      summary += extractString(summaryElement)
    if summary == '':
      for spanElement in summaryDetailsElement.findAll('span', attrs={'class':'data','itemprop':'description'}):
        summary = spanElement.findNext('span').string.strip()
  if summary == '':
    for element in soup.findAll('meta', attrs={'name':'og:description'}):
      summary = element['content'].strip()
  return summary

#Return (description,published) tuple
def parseGame(url,gamename):
  soup=parse(BASE_URL+url)
  for element in soup.findAll('span', attrs={'itemprop':'datePublished'}):
    published = element.string.strip()
  summary=''
  try:
    summary=parseSummary(soup)
  except:
    LOGGER.error('Failed to parse ' + gamename)
    traceback.print_exc()
    pass
  return (summary,getTime(published))

def getTime(time):
  try:
    return timezone.get_current_timezone().localize(datetime.strptime(time, '%b %d, %Y'))
  except:
    LOGGER.error('Exception converting time ' + time)
    traceback.print_exc()
    return timezone.now()

def isValid(soup):
  return len(soup.findAll('p', attrs={'class':'no_data'})) == 0

#Get all URLS for all games
def getGameURLs(games,tags,genre,platform):
  x=0
  while True:
    url=TEMPLATE_GENRE_URL.replace('GENRE',genre).replace('PAGE',str(x)).replace('PLATFORM',platform)
    x+=1
    LOGGER.info('Getting URL: ' + url)
    try:
      soup=parse(url)
      if not isValid(soup):
        return
      for productTitleContainer in soup.findAll('div', attrs={'class':'basic_stat product_title'}):
        gameElement=productTitleContainer.findNext('a')
        gamename=gameElement.string.strip()

        #keep track of tags
        gametags=list()
        if gamename in tags:
          gametags=tags[gamename]
        gametags.append(genre)
        gametags.append(platform)
        tags[gamename]=gametags

        if not gamename in games:
          link=str(gameElement['href']).strip()
          games[gamename]=link
    except:
      traceback.print_exc()
      pass

def parseGameURL(name,url):
  try:
    summary,published=parseGame(url,name)
  except:
    LOGGER.error('Error encountered on: ' + name + ' with url: ' + url)
    summary=''
    published=timezone.now()
    pass
  return (name,BASE_URL+url,summary,published)

def scrapeGamesAndTags():
  games={}
  tags={}
  for genre in GENRES:
    for platform in PLATFORM_MAP.keys():
      getGameURLs(games,tags,genre,platform)
  return (games,tags)


from fiis_scraping.bot.collect_data.collector import collect_all_b3
from fiis_scraping.util.formata.formata_data import fun_data
from logging import basicConfig, FileHandler, StreamHandler, INFO, DEBUG

def main():
    perido_consulta = fun_data().replace("/", "-")

    # iniciando as configurações de log do programa
    # criando path para o arquivo log do programa
    path_file_log = f'logs/{perido_consulta.replace("/", "-")}_relatorio.log'

    # crindo especificações de log
    file_handler = FileHandler(path_file_log, "a")
    file_handler.setLevel(INFO)
    stream_handler = StreamHandler()

    basicConfig(format='%(asctime)s  %(name)s  %(levelname)s: %(message)s',
                level=INFO,
                handlers=[file_handler, stream_handler])

    # inicia processo de coleta de dados referente aos FIIs
    collect_all_b3(perido_consulta)

if __name__ == '__main__':
    main()


# -*- coding: UTF-8 -*-
from django.contrib import admin
from models import CuentaBancaria, MovimientoBanco
from conciliacion.bancos.models import MovimientoLibro
from conciliacion.bancos.forms import MovimientoLibroForm
from decimal import Decimal
from django.db.models.query_utils import Q
from django.db import transaction

def marcar_conciliado(modeladmin, request, queryset):
    queryset.update(conciliado=True)

marcar_conciliado.short_description = "Marcar como conciliados"

@transaction.commit_manually
def conciliar_por_movimiento(modeladmin, request, queryset):
    for obj in queryset:
        mov = MovimientoBanco.objects.filter(
                             conciliado=False,
                            movimiento__isnull=True,
                            cuenta = obj.cuenta,
                            fecha__month=obj.fecha.month,
                            fecha__year=obj.fecha.year,
                            monto = obj.monto
                            )
        if len(mov) == 1:
            movimiento_banco = mov[0]
            movimiento_banco.movimiento=obj
            movimiento_banco.conciliado=True
            movimiento_banco.save()

            obj.conciliado = True
            obj.save()

    transaction.commit()

conciliar_por_movimiento.short_description = "Conciliar por 1 movimiento"

class CuentaBancariaAdmin (admin.ModelAdmin):
    fields = ['id','banco','numero','moneda','saldo_inicial']
    list_display = ['id','__unicode__','saldo_inicial']

class MovimientoBancoInLine (admin.TabularInline):
    model = MovimientoBanco
    exclude = ['cuenta','conciliado','descripcion','documento']
    readonly_fields = ['monto',]
    extra = 1

class MovimientoBancoAdmin (admin.ModelAdmin):
    date_hierarchy = 'fecha'
    list_display = ['fecha','movimiento','documento','cuenta','descripcion','monto','saldo','tipo']
    list_filter = ['cuenta','conciliado','tipo']
    actions = [marcar_conciliado]

class MovimientoLibroAdmin (admin.ModelAdmin):
    date_hierarchy = 'fecha'
    list_display = ['fecha','documento','cuenta','descripcion','monto','tipo']
    list_filter = ['cuenta','conciliado']
    inlines = [MovimientoBancoInLine,]
    form = MovimientoLibroForm
    actions = [marcar_conciliado,conciliar_por_movimiento]

    def get_form(self, request, obj=None, **kwargs):

        cleaned_data = request.POST
        if "documento" in cleaned_data and cleaned_data["documento"] == "" and \
            "descripcion" in cleaned_data and cleaned_data["descripcion"] == "" and \
            "cuenta" in cleaned_data and cleaned_data["cuenta"] == "" and \
            "monto" in cleaned_data and cleaned_data["monto"] == "" and \
            "movimiento_banco" in cleaned_data and cleaned_data["movimiento_banco"] != "" :
                linea =  MovimientoBanco.objects.get(pk=cleaned_data["movimiento_banco"])
                request.POST.update({
                                     "documento": linea.documento,
                                     "descripcion": linea.descripcion,
                                     "cuenta": linea.cuenta.pk,
                                     "monto": linea.monto,

                                     })

        form = super(MovimientoLibroAdmin, self).get_form(request, obj, **kwargs)
        if obj is not None:
            form.base_fields['movimiento_banco'].queryset=MovimientoBanco.objects.filter(
                                                                 conciliado=False,
                                                                movimiento__isnull=True,
                                                                cuenta = obj.cuenta,
                                                                fecha__month=obj.fecha.month,
                                                                fecha__year=obj.fecha.year,
                                                                monto = obj.monto
                                                                )
            qs = MovimientoBanco.objects.filter(
                                                    (Q(movimiento=obj) |
                                                                (Q(conciliado=False)&
                                                                Q(movimiento__isnull=True))) &
                                                                Q(cuenta = obj.cuenta) &
                                                                Q(fecha__month=obj.fecha.month) &
                                                                Q(fecha__year=obj.fecha.year) &
                                                                Q(monto__lt=15000 if obj.cuenta.moneda == "US$" else 1500) &
                                                                (
                                                                 Q(tipo__contains="DP") |
                                                                 Q(tipo__contains="DC") |
                                                                 Q(tipo__contains="TF"
                                                                     ))
                                                                )
            form.base_fields['depositos'].queryset=qs
            form.base_fields['depositos'].initial = [l.pk for l in MovimientoBanco.objects.filter(movimiento=obj)]

        else:
            form.base_fields['movimiento_banco'].queryset=MovimientoBanco.objects.filter(conciliado=False,
                                                                movimiento__isnull=True,
                                                                )
        return form

    @transaction.commit_manually
    def save_model(self, request, obj, form, change):
        try:
            super(MovimientoLibroAdmin, self).save_model(request, obj, form, change)
            if form.cleaned_data['movimiento_banco'] != None:
                movimiento_banco = form.cleaned_data['movimiento_banco']
                movimiento_banco.movimiento=obj
                movimiento_banco.conciliado=True
                movimiento_banco.save()
                obj.conciliado=True
                obj.save()

            if "depositos" in form.cleaned_data and len(form.cleaned_data['depositos']) > 0:
                depositos = form.cleaned_data['depositos']
                monto = Decimal('0.00')
                for d in depositos:
                    monto += d.monto
                    d.movimiento=obj
                    d.conciliado=True
                    d.save()

                if monto == d.monto:
                    obj.conciliado=True
                    obj.save()
        except Exception as e:
            transaction.rollback()
            raise e
        else:
            transaction.commit()

admin.site.register(CuentaBancaria,CuentaBancariaAdmin)
admin.site.register(MovimientoBanco,MovimientoBancoAdmin)
admin.site.register(MovimientoLibro,MovimientoLibroAdmin)


import pymongo

import config

client = pymongo.MongoClient(config.MG_URI)
db = client['telegram-media-bot']
users = db.users
images = db.images
audios = db.audios

if __name__ == '__main__':
    print(db.list_collection_names())
    for image in images.find():
        print(image)


"""Distribution sample submssion by year."""
from typing import Union, Tuple

import pandas as pd
from pandas.plotting import register_matplotlib_converters
import matplotlib.pyplot as plt
import seaborn as sns
from statsmodels.formula.api import ols

from ncbi_remap.plotting import NcbiPlotter, update_kwargs

register_matplotlib_converters()

PLOT_DEFAULTS = dict()
AXES_DEFAULTS = dict(ylabel="% Aligned", xlabel="Year")

def get_data(file_name: str) -> Tuple[pd.Series, pd.Series]:
    return (
        pd.read_table(file_name, usecols=["srx", "date_created", "pct_uniquely_aligned"])
        .assign(date_created=lambda x: pd.to_datetime(x.date_created))
        .assign(year=lambda x: x.date_created.dt.year)
        .set_index("srx")
    )

class Plot(NcbiPlotter):
    def __init__(
        self,
        file_name: str,
        plot_kwargs: Union[None, dict] = None,
        ax_kwargs: Union[None, dict] = None,
        ax: plt.Axes = None,
    ):
        """
        Example
        ----------
        >>> from ncbi_remap.plotting.sample_submission import Plot
        >>> plot = Plot("../../../output/paper-wf/srx_prealn.tsv")
        """
        self.update_figsize()
        self.ax = ax or self.get_ax()
        self.ax_joint = None
        self.ax_marg_x = None
        self.ax_marg_y = None

        self.plot_kwargs = update_kwargs(PLOT_DEFAULTS, plot_kwargs)
        self.axes_kwargs = update_kwargs(AXES_DEFAULTS, ax_kwargs)

        self.data = get_data(file_name)
        self.plot()
        self.tweak()

    def plot(self):
        sns.pointplot(
            x="year", y="pct_uniquely_aligned", data=self.data, ax=self.ax, **self.plot_kwargs
        )

    def tweak(self):
        self.ax.set(**self.axes_kwargs)
        plt.setp(self.ax.get_xticklabels(), rotation=45, ha="right")
        sns.despine(ax=self.ax, left=True)


# DQN训练模型测试
# 离散
import time
import gym
import numpy as np
from keras import models
env = gym.make('MountainCar-v0')
model = models.load_model('dqn_1.model')
s = env.reset()
score = 0
while True:
    env.render()
    time.sleep(0.01)
    a = np.argmax(model.predict(np.array([s]))[0])
    s, reward, done, _ = env.step(a)
    score += reward
    if done:
        print('score:', score)
        break
env.close()


import itertools, random

deck = list(itertools.product(range(1,14),
        ['Spade', 'Hearts', 'Diamond', 'Club']))

print('How many cards?')

num_cards = int(input())

random.shuffle(deck)

print("You got:")
for i in range(num_cards):
    print(deck[i][0], "of", deck[i][1])


import cv2
import pytesseract
import numpy as np
from PIL import ImageGrab
import time

pytesseract.pytesseract.tesseract_cmd = 'E:\pythonProject\Github\Tesseract-OCR\\tesseract.exe'
img = cv2.imread('1.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#tesseract 接受RGB
#############################################
#### Detecting Characters  ######
#############################################

print(pytesseract.image_to_string(img))
hImg, wImg, _ = img.shape
print(hImg, wImg)
boxes = pytesseract.image_to_boxes(img)
for b in boxes.splitlines():
    print(b)
    b = b.split(' ')
    print(b)
    x, y, w, h = int(b[1]), int(b[2]), int(b[3]), int(b[4])
    cv2.rectangle(img, (x,hImg- y), (w,hImg- h), (50, 50, 255), 2)
    cv2.putText(img,b[0],(x,hImg- y+25),cv2.FONT_HERSHEY_SIMPLEX,1,(50,50,255),2)

cv2.imshow('img', img)
cv2.waitKey(0)

#可用于图片文字检测数字，字母

Opencv project training/01 Text Detection OCR/code 1.py


"""Create quiz_sessions and quiz_session_questions tables

Revision ID: 24695bbcf22d
Revises: 04_4ef9db4e4e1e
Create Date: 2023-07-19 20:41:48.559343

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = "05_24695bbcf22d"
down_revision = "04_4ef9db4e4e1e"
branch_labels = None
depends_on = None

def upgrade() -> None:
    op.create_table(
        "quiz_sessions",
        sa.Column("id", sa.UUID(), nullable=False, primary_key=True, index=True),
        sa.Column(
            "created_at",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.func.now(),
        ),
        sa.Column(
            "last_modified_at",
            sa.DateTime(timezone=True),
            nullable=True,
            onupdate=sa.func.now(),
        ),
        sa.Column("completed_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("score", sa.Integer(), nullable=True),
        sa.Column("user_id", sa.UUID(), nullable=False),
        sa.ForeignKeyConstraint(
            ["user_id"],
            ["users.id"],
        ),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_table(
        "quiz_session_questions",
        sa.Column("id", sa.UUID(), nullable=False, primary_key=True, index=True),
        sa.Column("question_id", sa.UUID(), nullable=False),
        sa.Column("quiz_session_id", sa.UUID(), nullable=False),
        sa.Column("user_answer", sa.Integer(), nullable=True),
        sa.ForeignKeyConstraint(["question_id"], ["questions.id"], ondelete="CASCADE"),
        sa.ForeignKeyConstraint(
            ["quiz_session_id"], ["quiz_sessions.id"], ondelete="CASCADE"
        ),
        sa.PrimaryKeyConstraint("id"),
    )

def downgrade() -> None:
    op.drop_index(
        op.f("ix_quiz_session_questions_id"), table_name="quiz_session_questions"
    )
    op.drop_table("quiz_session_questions")
    op.drop_index(op.f("ix_quiz_sessions_id"), table_name="quiz_sessions")
    op.drop_table("quiz_sessions")


from urllib.request import Request
from django.shortcuts import redirect, render
from .models import Project

# Create your views here.

def index(request):
    projects = Project.objects.all()[::-1]
    return render(request,'index.html',{'projects':projects})

def add_project(request):
    if request.method == 'POST':
        Project.objects.create(
            title = request.POST['title'],
            des = request.POST['des'],
            tech = request.POST['tech'],
            image = request.FILES['image'] if 'image' in request.FILES else None
        )
        projects = Project.objects.all()[::-1]
        return render(request,'index.html',{'projects':projects,'msg':'Project is Uploaded'})
    projects = Project.objects.all()[::-1]
    return render(request,'index.html',{'projects':projects})

def delete_project(request,pk):
    try:
        project = Project.objects.get(id=pk)
        project.delete()
    except:
        pass
    projects = Project.objects.all()[::-1]
    return render(request,'index.html',{'projects':projects,'msg':'Project Deleted'})

def read_project(request,pk):
    project = Project.objects.get(id=pk)
    return render(request,'read-project.html',{'project':project})

def update_project(request,pk):
    project = Project.objects.get(id=pk)
    if request.method == 'POST':
        project.title = request.POST['title']
        project.des = request.POST['des']
        project.tech = request.POST['tech']
        if 'image' in request.FILES:
            project.image = request.FILES['image']
        project.save()
        projects = Project.objects.all()[::-1]
        return render(request,'index.html',{'projects':projects,'msg':'Project Updated'})
    return render(request,'update-project.html',{'project':project})