#!/usr/bin/env python3

#import aiml as aiml_std
from transformers import BertTokenizer, BertForNextSentencePrediction
import torch
import xml.etree.ElementTree as ET
import re
import os
import string
import random
from dotenv import load_dotenv
import math
import argparse
import subprocess
import shutil
from pathlib import Path
from urllib.parse import urlparse

load_dotenv()

try:
    AIML_DIR=os.environ['AIML_DIR']
except:
    AIML_DIR=''

try:
    BATCH_SIZE=int(os.environ['BATCH_SIZE'])
except:
    BATCH_SIZE = 32

try:
    WORD_FACTOR=int(os.environ['WORD_FACTOR'])
except:
    WORD_FACTOR = -1

try:
    DOUBLE_COMPARE=int(os.environ['DOUBLE_COMPARE'])
except:
    DOUBLE_COMPARE = 0

try:
    MAX_LENGTH=int(os.environ['MAX_LENGTH'])
except:
    MAX_LENGTH = 16

try:
    CUDA=int(os.environ['CUDA'])
except:
    CUDA = 0

try:
    BERT_MODEL=int(os.environ['BERT_MODEL'])
except:
    BERT_MODEL = 0

try:
    WEIGHT_TEMPLATE=float(os.environ['WEIGHT_TEMPLATE'])
except:
    WEIGHT_TEMPLATE= 1.0

try:
    WEIGHT_PATTERN=float(os.environ['WEIGHT_PATTERN'])
except:
    WEIGHT_PATTERN= 1.0

try:
    AIML_FILE=str(os.environ['AIML_FILE'])
except:
    AIML_FILE = ''

try:
    SRAI_LITERAL=int(os.environ['SRAI_LITERAL'])
except:
    SRAI_LITERAL = 1

class Kernel:

    def __init__(self):
        self.filename = 'name'
        self.verbose_response = True
        self.output = ""
        self.srai_list = []
        self.num = 0
        self.srai_completion = False
        #self.kernel = aiml_std.Kernel()
        self.tree = None
        self.root = None
        self.l = []
        self.z = []
        self.score = []
        self.memory = {}
        self.index = -1
        self.incomplete = False
        self.depth_limit = 10
        self.depth = 0
        self.files = []
        self.files_size = 0
        self.input = None
        self.used = []
        self.used_num = 0
        self.output_dict = {}
        self.answers = []
        self.answers_length = 5
        self.time1 = None
        self.time2 = None
        self.args = None

        parser = argparse.ArgumentParser(description="Bert Aiml", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        parser.add_argument('--raw-pattern', action='store_true', help='output all raw patterns.')
        parser.add_argument('--count', action='store_true', help='count number of responses.')
        parser.add_argument('--name', default='calculate', help='name for "count" operation output files.')
        parser.add_argument('--disable-ok', action='store_true', help='disable "ok" operation for BERT output.')
        parser.add_argument('--pic-cmd', default='xdg-open', help='define slideshow-type png viewing command.')
        parser.add_argument('--slideshow', action='store_true', help='enable slideshow presentation.')
        parser.add_argument('--pic-tmp', default='temp.png', help='name for temp slideshow pic.')
        self.args = parser.parse_args()

        #print(self.args)

        name = [ 'bert-base-uncased', 'bert-large-uncased', 'google/bert_uncased_L-8_H-512_A-8' ]
        index = BERT_MODEL
        self.tokenizer = BertTokenizer.from_pretrained(name[index])
        self.model = BertForNextSentencePrediction.from_pretrained(name[index])
        if CUDA == 1:
            self.model = self.model.to('cuda')

        if not self.args.pic_tmp.startswith('/') :
                self.args.pic_tmp = os.getcwd() + '/' + '../pic/' + self.args.pic_tmp
                pass
        self.slideshow()

    def verbose(self, isverbose):
        #print(isverbose)
        self.verbose_response = isverbose
        #self.kernel.verbose(isverbose)

    def learn(self, file):
        self.filename = file
        if self.filename in self.files:
            return
        self.files.append(file)

        #self.kernel.learn(file)
        #self.l = []
        #self.score = []
        tree = ET.parse(file)
        root = tree.getroot()
        self.files_size =  len(root)

        self.pattern_factory_topic(root)

    def respond(self, inputx):
        x = self.respond_bert(inputx)

        if x not in self.srai_list:
            self.srai_list.append(x)

        if len(self.srai_list) > 1:
            self.srai_list.reverse()
            #x = ' '.join(self.srai_list)
            #print(self.srai_list,'x')

        if len(self.srai_list) == 1:
            self.srai_list = []

        for i in x.split():
            self.slide_change(i)

        self.output = x
        return self.output

    def respond_srai(self, input):
        self.l = []
        num = 0
        input = str(re.sub(' +', ' ', input).upper().strip())
        input = input.translate(str.maketrans('','', string.punctuation))

        for j in range(len(self.z)):
            self.l.append(self.z[j])
            i = self.z[j]
            ii = str(re.sub(' +', ' ', i['pattern']).upper().strip())
            ii = ii.translate(str.maketrans('','', string.punctuation))
            #print(ii)
            if input.strip().upper() == ii.strip().upper():
                num = j
                #print(i['template'],'found')
                #return i['template']

        return self.update_dictionary(num, input)

    def respond_bert(self, input):
        self.score = []
        self.index = -1
        self.incomplete = False
        self.input = str(re.sub(' +', ' ', input).upper().strip())
        self.input = self.input.translate(str.maketrans('','', string.punctuation))

        self.l = []
        word_factor = WORD_FACTOR
        i_length = len(input.strip().split(' '))
        #print(len(self.l), 'list')
        for j in range(len(self.z)):
            p = self.z[j]['pattern']
            p_len = len(p.strip().split(' '))
            if i_length >= p_len + word_factor and word_factor != -1:
                continue
            if i_length <= p_len - word_factor and word_factor != -1:
                continue
            self.l.append(self.z[j])
            pass

        #print(len(self.z), len(self.l), 'len')

        batch_pattern = []
        batch_input = []
        batch_template = []
        #self.target = []

        ## input pattern batch ##
        batch_size = BATCH_SIZE
        num = 0
        replacements = 0
        for ii in range(0, len(self.l) , batch_size):
            #print(ii, ii+batch_size)

            if ii + batch_size > len(self.l):
                batch_size = len(self.l) - ii
            #print(batch_size, '< bs')
            batch_pattern = []
            batch_template = []
            batch_input = []
            #self.target = []
            for j in range(ii, ii+batch_size):
                #print(j, end=',')

                i = self.l[j]
                i['star'] = None
                input_02, d = self.mod_input(i, input)
                #self.l[num] = d ## <-- ???
                ip = i['pattern']
                ip = str(re.sub('\*', '', ip).upper().strip())

                it = i['template']

                if DOUBLE_COMPARE >= 1:
                    if len(it.strip()) == 0 and i['initial_template'] is not None:
                        it = i['initial_template'].text
                    if len(it.strip()) == 0 and i['initial_srai'] is not None:
                        it = i['initial_srai'].text
                    if len(it.strip()) == 0 :
                        it = i['pattern']
                        replacements += 1
                        #print('empty input template', it, j)

                #print(it, num, 'it')
                if i['initial_that'] is not None and len(i['initial_that']) > 0:
                    ip += ' ' + i['initial_that']
                #print(ii, num)

                ## batches start
                if DOUBLE_COMPARE <  2: batch_pattern.append(ip)
                if DOUBLE_COMPARE >= 1: batch_template.append(it)
                batch_input.append(input_02)

                num += 1

            if DOUBLE_COMPARE < 2:
                s = self.bert_batch_compare(batch_pattern, batch_input)
                batch_pattern = None #[]
            if DOUBLE_COMPARE >= 1:
                si = self.bert_batch_compare(batch_input, batch_template)
                batch_template = None #[]
            batch_input = None #[]

            num_s = 0
            j = 0
            #print()
            batch_size = BATCH_SIZE
            if ii + batch_size > len(self.l):
                batch_size = len(self.l) - ii
            for j in range(ii, ii + batch_size):
                #print(j, num, end=',')
                score = []
                if DOUBLE_COMPARE < 2:
                    score.extend(s[num_s])
                    pass
                if DOUBLE_COMPARE >= 1:
                    score.extend(si[num_s])
                self.score.append( score ) # ((*s[num_s], *si[num_s]))
                #print(self.score[num_s], num_s, 'score')
                num_s += 1
            #print('< score')

        print(len(self.l) // BATCH_SIZE, 'batches')
        if replacements > 0: print(replacements, 'replacements', len(self.l), 'total')

        ## find highest entry ##
        high = 0
        num = 0
        index = -1
        inputx = ''
        while inputx.strip() == '':
            ## find highest entry ##
            high = 0
            num = 0
            index = -1
            for _ in self.score:
                i = self.score[num]
                #i = (i[0] - i[1])
                if DOUBLE_COMPARE == 1:
                    i = abs ((i[0] - i[1]) * WEIGHT_PATTERN + (i[2] - i[3]) * WEIGHT_TEMPLATE)
                else:
                    i = abs (i[0] - i[1])
                i = self.mod_that(self.l[num], input, i)

                if i > high:
                    high = i
                    index = num
                num += 1

            inputx = self.check_ok(input, index)
            if inputx == '':
                if DOUBLE_COMPARE == 1: self.score[index] = (0, 0, 0, 0)
                else: self.score[index] = (0, 0)

        return self.update_dictionary(index, inputx)

    def update_dictionary(self, index, inputx):
        ## update dictionary ##

        d = self.mod_respond_dict(self.l[index], inputx)

        z = self.mod_template_out(self.l[index], inputx) ## includes srai output

        self.index = index

        r = self.choose_output(self.l[index]) ## random
        if r == '' and z != '':
            self.output = z
        else:
            self.output = r

        pre_output = self.output.strip()

        if len(self.output) > 0: self.depth = 0

        self.output = str(re.sub(' +', ' ', self.output).upper().strip())
        self.output = self.output.translate(str.maketrans('','', string.punctuation))

        if self.output not in self.answers:
            self.answers.append(self.output.upper().strip())

        self.answers = self.answers[- self.answers_length:] ## last few
        #print(self.answers, '???')

        if self.args.count: self.count_output(self.output)

        self.output = pre_output

        '''
        m = [[self.l[x]['pattern'], self.score[x][0] - self.score[x][1]] for x in range(len(self.l))]
        #print(m[:15])
        def spec(x):
            return x[1]
        m.sort(reverse=True,key=spec)
        print(m[:15])
        '''

        return self.output

    def check_ok(self, inputx, index):
        output = inputx
        if not self.args.disable_ok:
            print(self.l[index]['pattern'],"(Y/n):", end=' ')
            n = input()
            if n.strip().lower() not in ['y', 'yes', '']:
                output = ''
        else:
            output = inputx
        return output

    def slideshow(self):
        if self.args.slideshow:
            if not os.path.isfile(self.args.pic_tmp):
                Path(self.args.pic_tmp).touch
            subprocess.run([self.args.pic_cmd , self.args.pic_tmp])
        pass

    def slide_change(self, name):
        if self.args.slideshow:
            n = urlparse(name)
            if n.scheme != 'file' or len(n.netloc) == 0:
                return
            name = n.netloc
            if not name.startswith('/'):
                name = os.getcwd() + '/' + '../pic/' + name
            try:
                if not os.path.isfile(name):
                    return
                shutil.copy(name, self.args.pic_tmp)
            except:
                print('filename', name)
                pass
        pass

    def choose_output(self, d):
        if len(d['random_list']) > 0:
            return random.choice(d['random_list'])
        #elif True:
        #return d['template_modified'].strip()
        return ''

    def bert_batch_compare(self, prompt1, prompt2):
        encoding = self.tokenizer(prompt1, prompt2, return_tensors='pt', padding=True, truncation=True, add_special_tokens=True, max_length=MAX_LENGTH)
        #target = torch.LongTensor(self.target)
        target = torch.ones((1,len(prompt1)), dtype=torch.long)
        if CUDA == 1:
            encoding = encoding.to('cuda')
            target = target.to('cuda')

        outputs = self.model(**encoding, next_sentence_label=target)
        logits = outputs.logits.detach()
        #print(outputs, '< logits')
        return logits

    def pattern_factory_topic(self, root):
        num = 0
        for child in root:
            if child.tag == "topic":
                topic = ''
                if child.attrib['name'] is not None and len(child.attrib['name'].strip()) > 0:
                    topic = child.attrib['name'].upper().strip()

                for ch2 in child:
                    pat_dict = self.pattern_factory(ch2, topic)
                    pat_dict['index'] = num

                    self.z.append(pat_dict)

                    num += 1
                    pass

            if child.tag == "category":
                pat_dict = self.pattern_factory(child)
                pat_dict['index'] = num

                self.z.append(pat_dict)

                num += 1
        pass

    def raw_pattern(self):
        print('raw patterns')
        t = open('output.txt', 'w')
        for i in self.z:
            if self.verbose_response: print(i['pattern'])
            t.write(i['pattern'] + '\n')
        t.close()
        pass

    def count_output(self, output):
        output = output.strip()

        if self.used_num % BATCH_SIZE == 0:
            print(self.used_num, 'used', len(self.l), 'size in mem')
        self.used_num += 1
        if output not in self.used:
            self.used.append(output)

        if output in self.output_dict:
            self.output_dict[output] += 1
        else:
            self.output_dict[output] = 1
        pass

    def pattern_factory(self, category, topic=None):
        pat = None
        tem = None
        set = None
        get = None
        z = None
        srai = None
        learn = None
        that = ''
        random = None
        condition = None
        random_list = []
        star_list = []
        that_star_list = []
        that_wo_start = None
        that_wo_end = None
        start = ""
        end = ""
        tem_02 = ""
        pat_02 = ""
        original = ""

        star_list_start = []
        star_list_end = []
        star_list_mem = {}

        for i in category:
            #original = i.text

            if i.tag == 'pattern':
                pat = i.text
                if pat is None: pat = ''
                pat = ' '.join(pat.split(' ')).strip()
                #original = ET.tostring(i)

                if '*' in pat:
                    x = pat.strip().split(' ')
                    for ii in range(len(x)):
                        y = x[ii]
                        if y == "*":
                            star_list.append(ii + 1 )

                set = i
                get = i
                start = pat.split(" ")[0]
                end = pat.split(" ")[-1]
                pat_02 = pat.strip()

            if i.tag == 'template':
                tem = i
                if tem.text is None: tem.text = ''
                tem_02 = i.text

                set = i.find('./set')
                get = i.find('./get')
                srai = i.find('./srai')
                learn = i.find('./learn')
                random = i.find('./random')
                #that = i.find('./that')

                start = pat.split(" ")[0]
                end = pat.split(" ")[-1]
                #print(learn, "<-- ")

                if learn is not None: tem.text += learn.text

            if i.tag == "that":
                that = i.text

        wo_start = False
        wo_end = False
        ###################
        max_list_len = 2
        if pat_02.strip().endswith('*'):
            max_list_len = 1

        if "*" in pat_02:
            xx = pat_02.split(' ')
            #tem_02 = tem_02.split(' ')
            star_list_start = [ None for _ in range(min( len(xx) // 2 , max_list_len))]
            star_list_end = [ None for _ in range(min(len(xx) // 2, max_list_len))]

            for ii in range(len(star_list_start)):
                if xx[ii] == "*" :
                    star_list_start[ii] = '*'

            start_of_xx = len(xx) - len(star_list_end)
            for ii in range(len(star_list_end)):
                if xx[start_of_xx + ii] == "*" :
                    star_list_end[ ii] = '*'

        ###################
        if (pat_02.startswith('_') or pat_02.startswith('*')) and ( pat_02.endswith('*')):
            wo_start_end = True # pat_txt
            pass
        else:
            wo_start_end = False # pat_txt

        if  pat_02.endswith('*'):
            wo_end = True
        else:
            wo_end = False

        if pat_02.startswith('_') or pat_02.startswith('*'):
            wo_start = True
        else:
            wo_start = False
        ###################
        if  that.endswith('*'):
            that_wo_end = True
        else:
            that_wo_end = False

        if that.startswith('_') or that.startswith('*'):
            that_wo_start = True
        else:
            that_wo_start = False
        ###################
        d = {
            'start': start,
            'end': end,
            'wo_start': wo_start,
            'wo_end': wo_end,
            'wo_start_end': wo_start_end,
            'pattern': pat,
            'template': tem.text.strip(),
            'template_modified': '',
            'initial_template': tem,
            'initial_srai' : srai,
            'initial_learn' : learn,
            'initial_that': that,
            'index': None,
            'set_exp': set,
            'get_exp': get,
            'tem_wo_start': wo_start,
            'tem_wo_end': wo_end,
            'that_wo_start': that_wo_start,
            'that_wo_end': that_wo_end,
            'star': None,
            'star_list': star_list,
            'star_list_start': star_list_start,
            'star_list_end': star_list_end,
            'star_list_mem': star_list_mem,
            'that_star_list': that_star_list,
            #'original': original,
            'topic': topic,
            'random': random,
            'random_list': random_list,
            'condition': condition,
            'encounter_think': False
        }

        if random is not None:
            self.mod_pattern_factory_random_tag(d['random'], d)
            #print(d)

        return d

    def mod_pattern_factory_random_tag(self, element, d_dict):
        d = d_dict
        d['random_list'] = []

        for x in element:
            if x.tag == "li" :
                d['random_list'].append(x.text)

        return ''

    def mod_that(self, d_list, input, score):
        d = d_list
        d['that_star_list'] = []
        #print(d['that_star_list'],'< star list:', input)
        if d['initial_that'] is not None and len(d['initial_that']) > 0:
            out = d['initial_that']
            out = str(re.sub(' +', ' ', out).strip())

            if d['that_wo_end'] and len(out.split(' ')) > 0:
                d['that_star_list'].append(len(out.split(' ')) - 1)
                d['initial_that'] = d['initial_that'][:-1]
            if d['that_wo_start'] and len(out.split(' ')) > 0:
                d['that_star_list'].append(0)
                d['initial_that'] = d['initial_that'][1:]

            out = out.translate(str.maketrans('','', string.punctuation))
            if out.upper().strip() not in self.answers:
                score = 0
        if d['topic'] is not None and 'topic' in self.memory:
            if self.memory['topic'] != d['topic']:
                score = 0
        if d['topic'] is not None and len(d['topic']) > 0 and 'topic' not in self.memory:
            score = 0

        return score

    def mod_input(self, d_list, input):
        d = d_list
        l = str(re.sub(' +', ' ', input).strip())
        l = l.split(' ')
        d['star_list_mem'] = {}
        #print(l)
        ll = str(re.sub(' +', ' ',input).strip())
        ll = ll.split(' ')

        num = 0
        if len(d['star_list_start']) > 0 or len(d['star_list_end']) > 0 and len(d['star_list_start']) >= len(ll):

            for ii in range(len(d['star_list_start'])):
                if d['star_list_start'][ii] is not None and ii < len(ll):
                    d['star_list_mem'][num] = ll[ii]
                    ll.pop(ii)
                    num += 1
                    pass

            start_of_xx = len(ll) - len(d['star_list_end'])
            start_of_xx = max(start_of_xx, 0)
            for ii in range(len(d['star_list_end'])):
                if d['star_list_end'][ii] is not None and ii < len(ll):
                    d['star_list_mem'][num] = ll[start_of_xx + ii]
                    ll.pop(start_of_xx + ii)
                    num += 1
                pass

        input = ' '.join(ll)

        return input, d

    def mod_template_out(self, d_list, input):
        d = d_list
        #if input is None: input = d['template']
        l = input.split(' ')

        #print(d, 'd')
        if not self.srai_completion:
            d['template_modified'] = ''
            pass
        else:
            self.srai_list = []

        if d['initial_template'] is not None or True:
            d['template_modified'] = ''
            #print(d['initial_template'], 'nothing?')
            xx = self.consume_template(d['initial_template'], d)
            xx = ' '.join(xx.split(' '))
            xx = str(re.sub(' +', ' ', xx).strip())
            d['template'] = xx
            #print(xx, ': d-template')
            #d['srai_completion'] = False
            return xx

        #d['srai_completion'] = False
        return ''

    def mod_set(self, d):
        set = d['set_exp']

        if set is None: return
        t = ''
        for x in set:
            if x.tag == "star":
                if 'index' in x.attrib.keys() and int(x.attrib['index']) > 0:
                    t = d['star_list_mem'][int(x.attrib['index'])]
                else:
                    t = d['star_list_mem'][0]
                pass
            elif set is not None and set.text is not None:
                t = set.text.strip()

        self.memory[set.attrib['name'].upper()] = t

    def mod_respond_dict(self, d, input):
        set = d['set_exp']
        get = d['get_exp']
        tem = d['initial_template']
        sta = d['star']
        self.mod_set(d)

        tem_x = str(ET.tostring(tem)).replace('<template>', '', -1).replace('</template>', '', -1)
        tem_x = tem_x.replace("b'", '').replace("'","")

        tem_x = tem_x.replace('\\n', '')

        tem_x = str(re.sub(' +', ' ', tem_x).strip())
        tem_x = str(' '.join(tem_x.split(' ')))
        tem_x = re.sub('^\s+', 'z', tem_x)
        tem_x = re.sub('\s+$', 'z', tem_x)

        #print(tem_x, '= x')

        d['tem_wo_start'] = tem_x.startswith("<") or tem_x.startswith('_') or tem_x.startswith('*')
        d['tem_wo_end'] = tem_x.endswith("*") or tem_x.endswith(">")
        #print(z, self.memory)
        t = ''
        if get is not None:

            #t = ''
            if get.attrib['name'].upper() in self.memory.keys():
                t = self.memory[get.attrib['name'].upper()]
                if t is  None or t == '':
                    self.incomplete = True

                    d['template'] = ''
                    return d #['template']
        ####
        if t is not None and t != '':
            tt = ''

            if d['tem_wo_end']:
                tt = tem.text.strip() + ' ' + t
            elif d['tem_wo_start']:
                tt = t + ' ' + tem.text.strip()

            d['template'] = tt #tem
            #print(d, 'd')
            return d

        return d

    ## Start consume functions ##

    def consume_template(self, element, d):
        #print('template :', element.text, element.tag, element.attrib)
        r = ''
        l = []
        local_text = ''
        z = ''
        if element.text is not None:
            t = element.text.strip()
            #d['template_modified'] += t
            local_text += t
            #l.append(t)

        for x in element:

            if x.tag == "srai" :
                #d['template_modified'] = ''
                #d['srai_completion'] = True
                self.srai_completion = True
                #print('srai')
                z = self.consume_srai(x, d)
                if z is not None and len(z) > 0:
                    #d['template_modified'] =  z ## replace, not concatenate!
                    #print(z,'z')
                    self.depth += 1
                    if self.depth < self.depth_limit:
                        self.index = 0
                        self.output = ''
                        self.incomplete = False
                        #d['srai_completion'] = True
                        if SRAI_LITERAL == 1:
                            r = self.respond_srai(z)
                            if r not in self.srai_list:
                                self.srai_list.append(r)
                            #d['template_modified'] = r
                        else:
                            r = self.respond_bert(z)
                            if r not in self.srai_list:
                                self.srai_list.append(r)
                        #l.append(r)
                        #print(r, '<<<r')

            if x.tag == "learn" :
                self.consume_learn(x, d)
                local_text = ''
            if x.tag == "get" :
                z = self.consume_get(x, d)
                #d['template_modified'] += " " + z
                local_text += ' ' + z
            if x.tag == "set" :
                z = self.consume_set(x, d)
                if z is not None:
                    #d['template_modified'] += " " + z
                    local_text += ' ' + z

            if x.tag == "star" :
                z = self.consume_star_tag(x, d)
                if z is not None:
                    #d['template_modified'] += " " + z
                    local_text += ' ' + z

            if x.tag == "think":
                self.consume_think(x, d)
            if x.tag == "condition":
                z = self.consume_condition(x, d)
                if z is not None and len(z.strip()) > 0:
                    if z not in l :
                        l.append(z)
                    local_text += ' ' + z.strip()
                    pass
            if x.tail is not None and len(x.tail) > 0: local_text += ' ' + x.tail.strip()

            #print(x.tag, 'tag', local_text, '++')

        if len(r) > 0:
            local_text += ' ' + r

        return local_text

    def consume_srai(self, element, d):
        #print('srai :', element.text, element.tag, element.attrib, d['template_modified'])

        local_text = ''
        if element.text is not None and len(element.text.strip()) > 0:
            #print(element.text)
            #return element.text
            local_text  += ' ' + element.text

        for x in element:

            if x.tag == "get" :
                z = self.consume_get(x, d)
                d['template_modified'] += " " + z
                local_text += ' ' + z
                #print(local_text)
            if x.tag == "set" :
                z = self.consume_set(x, d)
                if z is not None:
                    d['template_modified'] += " " + z
                    local_text += ' ' + z

            if x.tag == "star" :
                z = self.consume_star_tag(x, d)
                if z is not None:
                    d['template_modified'] += " " + z
                    local_text += ' ' + z
            if x.tag == "think":
                self.consume_think(x, d)

            if x.tail is not None and len(x.tail) > 0: local_text += ' ' + x.tail.strip()

        #print('srai internal :', local_text)

        return local_text # d['template_modified']

    def consume_set(self, element, d):
        #print('set :', element.text, element.tag, element.attrib)
        z = ''
        if element.text is not None:
            z = element.text.strip()

        for x in element:
            if x.tag == "set" :
                z = self.consume_set(x, d)
                #if z is not None and not d['encounter_think']:
                #    d['template_modified']  += ' ' + z
            if x.tag == "star" :
                z = self.consume_star_tag(x, d)

            if x.tag == "get" :
                z = self.consume_get(x, d)
                #d['template_modified'] += " " + z
                #local_text += ' ' + z
                #print(local_text)

            #if x.tail is not None and len(x.tail) > 0: z += ' ' + x.tail.strip()

        if 'name' in element.attrib:
            #print(element.attrib,'attrib', self.memory)
            self.memory[element.attrib['name'].upper()] = z.upper().strip()

        return z.upper().strip()

    def consume_learn(self, element, d):
        #print('set :', element.text, element.tag, element.attrib)
        if element.text is not None:
            d['template_modified'] += element.text

        if self.args.count == True:
            return ''

        x = ''
        if d['initial_learn'] is not None:
            x = d['initial_learn'].text.strip()
            d['initial_learn'].text = ''
        if not x.startswith('/'):
            cwd = os.getcwd() + '/'
            x = cwd + AIML_DIR + x
            if not os.path.isfile(x):
                print(x, ': bad file specification')
                return ''
        print(x, '<<')
        self.learn(x)
        return ''

    def consume_get(self, element, d):
        #print('get :', element.text, element.tag, element.attrib)
        z = ''
        if element.text is not None:
            d['template_modified'] += ' ' + element.text
            z += ' ' + element.text
        for xx in element.attrib:
            #print(xx)
            pass

        if 'name' in element.attrib.keys() and element.attrib['name'].upper() in self.memory.keys():
            #print(self.memory, '<< memory get')
            y = self.memory[element.attrib['name'].upper()]
            #print(y)
            return y

        for x in element:

            if x.tag == "star" :
                z = self.consume_star_tag(x, d)

            if x.tail is not None and len(x.tail) > 0: z += ' ' + x.tail.strip()

        return z

    def consume_star_tag(self, element, d):
        #print('star :', element.text, element.tag, element.attrib)

        s = d['star_list']
        z = element.attrib
        p = self.input.strip()
        p = ' '.join(p.split(' '))
        r = ''
        #print(z,'< before')
        if 'index' in z:
            x = int(z['index']) - 1
        else: x = 0
        #print(x, '< x')
        if len(s) > 0:
            if x <= len(s) : x = int(s[x]) -1
            z = p.split(' ')
            if x < len(z):
                r = z[x]
        #print(s, r,'< after ')
        #print('---')

        return r

    def consume_think(self, element, d):

        d['encounter_think'] = True

        for x in element:

            if x.tag == "set" :
                self.consume_set(x, d)

        d['encounter_think'] = False
        return '' # d['template_modified']

    def consume_condition(self, element, d):
        #print(element.attrib)
        r = ''
        name = ''
        value = ''
        z = ''
        match = False
        fallback = ''
        local_text = ''
        if element.attrib is not None:
            if 'name' in element.attrib.keys():
                name = element.attrib['name'].upper().strip()
                d['condition'] = name
            if 'value' in element.attrib.keys():
                value = element.attrib['value'].upper().strip()

        present = ((name.upper() in self.memory.keys() or name in self.memory.keys()) and
            (value.upper() == self.memory[name.upper()].upper() or value.upper() == self.memory[name].upper()
            or value == self.memory[name]))

        if present and element.text is not None and len(element.text) > 0:
            local_text += ' ' + element.text
            d['template_modified'] += ' '+ element.text
            pass

        #if True:
        for x in element:
            if x.tag == "think" and present:
                self.consume_think(x, d)
                #d['template_modified'] = ''

            if x.tag == "srai" and present:
                #d['template_modified'] = ''
                z = self.consume_srai(x, d)
                if z is not None and len(z) > 0:
                    d['template_modified'] = z ## replace, not concatenate!
                    #print(self.depth, "< depth")
                    #local_text += ' ' + z
                    self.depth += 1
                    if self.depth < self.depth_limit:
                        self.index = 0
                        self.output = ''
                        self.incomplete = False
                        #print('z:', z)
                        if SRAI_LITERAL == 1 :
                            r = self.respond_srai(z)
                            if r not in self.srai_list:
                                self.srai_list.append(r)
                        else:
                            r = self.respond_bert(z)
                            if r not in self.srai_list:
                                self.srai_list.append(r)

            if present and x.tail is not None and len(x.tail) > 0: local_text += ' ' + x.tail.strip()

        if present and r is not None and len(r.strip()) > 0:
            pass
            local_text += ' ' + r
            #return r
        #print('=', local_text, '=')

        return local_text

if __name__ == '__main__':

    k = Kernel()
    k.verbose(False)
    k.learn('../aiml/startup.xml')
    if len(AIML_FILE) > 0:
        if AIML_FILE.startswith('/'):
            k.learn(AIML_FILE)
        else:
            x = os.getcwd() + '/' + AIML_DIR + AIML_FILE
            if os.path.isfile(x):
                k.learn(x)
                print(x,'<<')
            else:
                print('bad file specification')
                exit()
    print(k.args)
    if k.args.raw_pattern:
        k.raw_pattern()
        exit()
    while True:
        try:
            y = input("> ")
        except EOFError:
            if not k.args.count: exit()
            name = ''
            if DOUBLE_COMPARE == 0: name = '.pat'
            if DOUBLE_COMPARE == 1: name = '.pat.tem'
            if DOUBLE_COMPARE == 2: name = '.tem'
            print(len(k.z), len(k.used), 'used', k.used_num, 'attempts')
            z = open( k.args.name + '.ratio' + name + '.txt', 'w')
            z.write(str(len(k.z)) + ' total categories\n' )
            z.write(str(len(k.used)) + ' total used\n')
            z.write(str(k.used_num) + ' total number of attempts\n')
            z.close()
            l = []

            for key in k.output_dict:
                l.append([key, k.output_dict[key]])
            ####
            def func(i):
                return i[1]
            ####
            l.sort(key=func, reverse=True)
            z = open( k.args.name + '.tab' + name + '.txt', 'w')
            for a in l:
                z.write(a[0] + '\t' + str(a[1]) + '\n')
            z.close()

            exit()
        x = ''
        if len(x.strip()) == 0 :
            r = k.respond(y)

            print(r)
        else:
            print(x)


from collections import OrderedDict

def integer_encode(mylist):
    return {v: i for i, v in enumerate(mylist)}

def integer_encode_without_zero_index(mylist):
    return {v: i+1 for i, v in enumerate(mylist)}

def get_key_from_value(mydict, myvalue):
    return [k for k, v in mydict.items() if v == myvalue]

def append_result(context, file_indexes, recommend, contexts_list, output):
    contexts_list.append([file_indexes[x] for x in context])
    output.append(recommend)
    return contexts_list, output

def make_dataset(trace, file_indexes, category_indexes, window_size, step, lookup, is_remove_dupe=False):
    if is_remove_dupe:
        event_tuple_list = trace.event_tuple_list_groupby
    else:
        event_tuple_list = trace.event_tuple_list

    # input and output
    contexts_list, output = [], []

    for i in range(len(event_tuple_list) - window_size):
        context = event_tuple_list[i:(i+window_size)]
        recommend = []

        if context[-1][0] == 'edit':
            recommend = [category_indexes[x[1]] for x in event_tuple_list[(i + window_size):(i + window_size + lookup)] if x[0] is 'edit' and x != context[-1]]
            # recommend = [category_indexes[x[1]] for x in event_tuple_list[(i+window_size):(i+window_size+lookup)] if x[0] is 'edit' and x[1] not in list(map(lambda x: x[1], context))]
            # recommend = [category_indexes[x[1]] for x in event_tuple_list[(i+window_size):(i+window_size+lookup)] if x[0] is 'edit' and x not in context]
            # recommend = [category_indexes[x[1]] for x in event_tuple_list[(i+window_size):(i+window_size+lookup)] if x[0] is 'edit']

        if recommend:
            recommend = list(OrderedDict.fromkeys([x for x in recommend]))[:step]
            contexts_list, output = append_result(context, file_indexes, recommend, contexts_list, output)

    return contexts_list, output

if __name__ == '__main__':
    import numpy as np
    from keras.preprocessing import sequence
    from libs.interaction_traces import InteractionTraces

    # directory of interaction traces
    directory_name = '../dataset/Project_ECF/'
    interaction_trace_set = InteractionTraces(directory_name)
    trace = interaction_trace_set.interaction_trace_set[1]
    file_indexes = integer_encode_without_zero_index(interaction_trace_set.event_set)
    category_indexes = integer_encode(interaction_trace_set.edit_set)

    x_train, y_train = make_dataset(trace, file_indexes, category_indexes, window_size=4, step=5, lookup=30, is_remove_dupe=False)
    x_test, y_test = make_dataset(trace, file_indexes, category_indexes, window_size=4, step=5, lookup=30, is_remove_dupe=False)

    print("x_train")
    print(x_train)

    x_train = np.array(x_train)
    x_train = sequence.pad_sequences(x_train, maxlen=4)

    # y_train = [np.array(x) for x in y_train]
    # y_train = [to_categorical(x, num_category) for x in y_train]
    # y_train = np.array([x.sum(axis=0) for x in y_train])
    print("x_train")
    print(x_train)
    print("y_train")
    print(y_train)
    print("x_test")
    print(x_test)
    print("y_test")
    print(y_test)

    # print(x_train.shape)
    # print(y_train.shape)


import redis

# 加载模块即初始化Redis单例对象
REDIS_PROTO = None

# Redis链接
HOST = "localhost"
PORT = 6379

def getRedis():
    global REDIS_PROTO
    if not REDIS_PROTO:
        REDIS_PROTO = redis.Redis(host=HOST, port=PORT, decode_responses=True)
    return REDIS_PROTO

def rPushBullet(list_key, char):
    global REDIS_PROTO
    REDIS_PROTO = getRedis()
    if getBulletSwitchStatus():
        return REDIS_PROTO.rpush(list_key, char) > 0
    return False

# 弹幕开关状态
BULLET_SWITCH_KEY = "bullet_switch"
SWITCH_ON_STATUS = 'on'
SWITCH_OFF_STATUS = 'off'

def getBulletSwitchStatus():
    global REDIS_PROTO
    REDIS_PROTO = getRedis()
    if REDIS_PROTO.get(BULLET_SWITCH_KEY) == SWITCH_ON_STATUS:
        return True
    return False

def setBulletSwitchStatus(status: str):
    global REDIS_PROTO
    REDIS_PROTO = getRedis()
    return REDIS_PROTO.set(BULLET_SWITCH_KEY, status) > 0

def tapBulletSwitch():
    if getBulletSwitchStatus():
        setBulletSwitchStatus(SWITCH_OFF_STATUS)
    else:
        setBulletSwitchStatus(SWITCH_ON_STATUS)
    return getBulletSwitchStatus()


from itertools import cycle
import random
import sys
import pygame

from pygame.locals import *

FPS = 30
SCREENWIDTH  = 846#282 * 3
SCREENHEIGHT = 358#179 * 2
# amount by which base can maximum shift to left
PIPEGAPSIZE  = 100 # gap between upper and lower part of pipe
#BASEY        = SCREENHEIGHT * 0.79
# image, sound and hitmask  dicts
IMAGES, SOUNDS, HITMASKS = {}, {}, {}
BACKGROUNDS = ('naipe_doble.jpg')
BACKGROUNDS_LIST = (
    'imagenesPvZ/Balde.png',
    'imagenesPvZ/Bandera.png',
    'imagenesPvZ/Bomba.png',
    'imagenesPvZ/Cono.png',
    'imagenesPvZ/Diario.png',
    'imagenesPvZ/Grandulon.png',
    'imagenesPvZ/HongoNocturno.png',
    'imagenesPvZ/Jugador.png',
    'imagenesPvZ/NocheGrande.png',
    'imagenesPvZ/Nuez.png',
    'imagenesPvZ/Peashooter.png',
    'imagenesPvZ/Repetidor.png',
    'imagenesPvZ/Repollo.png',
    'imagenesPvZ/Sunflower.png',
)

def main():
    global SCREEN, FPSCLOCK
    FPSCLOCK = pygame.time.Clock()
    pygame.init()
    SCREEN = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
    pygame.display.set_caption('PvZ')
    IMAGES['background'] = pygame.image.load(BACKGROUNDS).convert()
    posx = 0;
    #pygame.mixer.music.load('tumblr_m9v2ujdS2q1r5dxz2o1.mp3');
    posy = 0;
    SCREEN.blit(IMAGES['background'], (0,0));
    #pygame.mixer.music.play(1, 0);
    while True:
        for event in pygame.event.get():

            if event.type == KEYDOWN:
                if event.key == K_SPACE:
                    posx=0; posy=0
                    randBg = random.randint(0, len(BACKGROUNDS_LIST) - 1)
                    IMAGES['background'] = pygame.image.load(BACKGROUNDS_LIST[randBg]).convert()
                    SCREEN.blit(IMAGES['background'], (0,0))
                if event.key == K_RETURN:
                    posx=0; posy=0
                    IMAGES['background'] = pygame.image.load(BACKGROUNDS).convert()
                    SCREEN.blit(IMAGES['background'], (posx,posy))
                if event.key == K_b:
                    posx=0; posy=0
                    IMAGES['background'] = pygame.image.load('imagenesPvZ/Balde.png').convert()
                    SCREEN.blit(IMAGES['background'], (0,0))
                if event.key == K_RIGHT:
                    if posx < 846:
                        posx = posx + 20
                    SCREEN.blit(IMAGES['background'], (posx,posy))
                if event.key == K_LEFT:
                    if posx > 0:
                        posx = posx - 20
                    SCREEN.blit(IMAGES['background'], (posx,posy))
                if event.key == K_DOWN:
                    if posy < 358:
                        posy = posy + 30
                    SCREEN.blit(IMAGES['background'], (posx,posy))
                if event.key == K_UP:
                    if posy > 0:
                        posy=posy - 30
                    SCREEN.blit(IMAGES['background'], (posx,posy))
                if event.key == K_ESCAPE:
                    #pygame.mixer.music.stop();
                    pygame.quit();
                    sys.exit();
                if event.type == QUIT:
                    #pygame.mixer.music.stop();
                    pygame.quit();
                    sys.exit();
        pygame.display.flip()
        FPSCLOCK.tick(FPS)

if __name__ == '__main__':
    main()


import os
import shutil
from time import sleep
import discord
from discord import SyncWebhook
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import StatesGroup, State
from aiogram import Bot, Dispatcher, executor, types
from asyncio import sleep
from time import sleep
import threading
from db_import import db, GROUPS, GUILDS, LINKED, TG_LINKED, WEBHOOKS
from tokens import TG_TOKEN

if not os.path.isdir("tempdata"):
    os.mkdir("tempdata")

access_error = 'Для данного действия необходимо обладать\nправами администратора телеграм-группы!'
bot = Bot(token=TG_TOKEN)
dp = Dispatcher(bot, storage=MemoryStorage())

# class UserState(StatesGroup):
#     unlink_discord = State()
#     forecast = State()

@dp.message_handler(commands=['help', 'start', 'info', 'hey'])
async def send_welcome(message: types.Message):
    await message.reply("*__Вас приветствует RotexBot\!__*\n\n"
                        "Я разработан специально для организации двусторонней\n"
                        "связи между Telegram чатами и Discord каналами\n\n"
                        "*Команды, которые я поддерживаю:*\n"
                        "/help \- помощь\n"
                        "/id \- узнать id данной телеграм группы\n"
                        "/discord \- привязать к чату дискорд канал\n"
                        "/undiscord \- отвязать дискорд канал от чата",
                        parse_mode='MarkdownV2')

@dp.message_handler(commands=['undiscord', 'андискорд', 'unlink', 'отвязать'])
async def unlink_discord(message: types.Message):
    user = await bot.get_chat_member(message.chat.id, message.from_user.id)
    if not user.is_chat_admin():
        respond = await message.reply(access_error)
        await sleep(5)
        await respond.delete()
        return

    if db.get(GROUPS, str(message.chat.id)).LINKED_CHANNEL_ID:
        buttons = [
            [
                types.InlineKeyboardButton(text="отвязать", callback_data="отвязать"),
                types.InlineKeyboardButton(text="отменить", callback_data="отменить"),
            ],
        ]
        keyboard = types.InlineKeyboardMarkup(inline_keyboard=buttons)
        await message.answer('Вы уверены, что хотите\nотвязать дискорд сервер?', reply_markup=keyboard)
    else:
        await message.reply("Данная телеграм-группа не связана\nни с одним дискордм сервером!")

@dp.callback_query_handler()
async def callback_func(callback: types.CallbackQuery):
    chat_id = str(callback.message.chat.id)
    user = await bot.get_chat_member(int(chat_id), callback.from_user.id)
    if callback.data == 'отвязать':
        if user.is_chat_admin():
            for o in db.query(GUILDS).all():
                if o.TG_LINKED_CHANNELS_ID and db.get(TG_LINKED, chat_id).LINKED_CHANNEL_ID in o.TG_LINKED_CHANNELS_ID:
                    guild = o
                    break
            group = db.get(GROUPS, chat_id)
            linked_group = db.get(TG_LINKED, chat_id)
            linked_channel = db.get(TG_LINKED, linked_group.LINKED_CHANNEL_ID)
            webhook = db.get(WEBHOOKS, linked_channel.CHANNEL_ID)
            group.LINKED_CHANNEL_ID = None
            if ':' in guild.TG_LINKED_CHANNELS_ID:
                groups = guild.TG_LINKED_CHANNELS_ID.split(":")
                groups.remove(linked_channel.CHANNEL_ID)
                guild.TG_LINKED_CHANNELS_ID = ":".join(groups)
            else:
                guild.TG_LINKED_CHANNELS_ID = None
            db.delete(linked_group)
            db.delete(webhook)
            db.delete(linked_channel)
            db.add_all([group, guild])
            db.commit()
            await callback.message.answer('Отвязка завершена успешно!')
            await callback.message.delete()
        else:
            respond = await callback.message.reply(access_error)
            await sleep(5)
            await respond.delete()
    elif callback.data == 'отменить':
        if user.is_chat_admin():
            await callback.message.delete()
        else:
            respond = await callback.message.reply(access_error)
            await sleep(5)
            await respond.delete()

@dp.message_handler(commands=['discord', 'дискорд', 'link_discord', 'привязать_дискорд'])
async def link_discord(message: types.Message):
    user = await bot.get_chat_member(message.chat.id, message.from_user.id)
    if not user.is_chat_admin():
        respond = await message.reply(access_error)
        await sleep(15)
        await respond.delete()
        return
    if db.get(GROUPS, str(message.chat.id)).LINKED_CHANNEL_ID:
        await message.reply(f'Данная телеграм группа уже связана\n'
                            f'с дискорд каналом, id которого:\n'
                            f'{db.get(GROUPS, str(message.chat.id)).LINKED_CHANNEL_ID}\n\n'
                            f'Если хотите отвязать дискорд канал,\n'
                            f'воспользуйтесь командой: /undiscord')
        return
    if ' ' in message.text:
        ds_guild_id = message.text.split()[1]
        tg_group_id = str(message.chat.id)
    else:
        await message.reply('Чтобы привязать дискорд канал к телеграм гурппе,\n'
                            'нужно установить дискорд бота Rotex\n'
                            'на целевой дискорд сервер.\n'
                            'Ссылка для приглашения дискорд бота:'
                            'https://discord.com/api/oauth2/authorize?client_id=1088509697524519115&permissions=8&scope=bot%20applications.commands\n\n'
                            'После этого, с дискорд сервера необходимо отправить\n'
                            'приглашение на создание общего чата при помощи команды\n'
                            '/link_telegram , использованной в дискорд сервере.\n\n'
                            'После того, как приглашение создать общий чат придёт\n'
                            'в эту телеграм-группу, необходимо узнать id\n'
                            'дискорд сервера,где находится канал, а затем\n'
                            'использовать команду /discord [id дисокрд сервера]\n'
                            'Чтобы завершить привязку.\n'
                            'Пример использования команды:\n\n'
                            '/discord 10832845374377255078\n\n'
                            '(узнать id дискорд сервера можно с помощью команды /id\n'
                            'использованной в желаемом дискорд сервере)')
        return

    if not db.get(GUILDS, ds_guild_id):
        await message.reply('ОШИБКА!\n'
                            'Пожалуйста, проверьте правильность введённых данных!\n\n'
                            'P.S. для работы общего telegram-discord чата\n'
                            'На дискорд сервер также необходимо пригласить бота Rotex.\n'
                            'Ссылка для приглашения дискорд-бота:\n'
                            'https://discord.com/api/oauth2/authorize?client_id=1088509697524519115&permissions=8&scope=bot%20applications.commands')
        return
    if db.get(GROUPS, tg_group_id).LINKED_CHANNEL_ID:
        await message.reply('ОШИБКА!\n'
                            'Эта группа уже связанна с дискорд сервером!\n\n'
                            'Отвязать дискорд сервер:\n'
                            '/undiscord')
    if not db.get(GUILDS, ds_guild_id).TG_LINK_WATING_GROUP_ID and not db.get(GUILDS,
                                                                              ds_guild_id).TG_LINK_WATING_CHANNEL_ID:
        await message.reply(f"На данный момент у вас нет вхожящих\n"
                            f"запросов на создание общего дискорд-телеграм чата.\n"
                            f"Если желаете установить двустороннее соединение\n"
                            f"с дискорд сервером, попросите его администратора\n"
                            f"отправить вам запрос на создание общего\n"
                            f"дискорд-телеграм чата.\n\n"
                            f"Id данной телеграм группы: {message.chat.id}")
        return
    else:
        try:
            guild_object = db.get(GUILDS, ds_guild_id)
            group_object = db.get(GROUPS, tg_group_id)
            ds_channel_id = guild_object.TG_LINK_WATING_CHANNEL_ID

            if guild_object.TG_LINKED_CHANNELS_ID:
                channels_list = guild_object.TG_LINKED_CHANNELS_ID.split(":")
                if ds_channel_id not in channels_list:
                    channels_list.append(ds_channel_id)
                guild_object.TG_LINKED_CHANNELS_ID = ":".join(channels_list)
            else:
                guild_object.TG_LINKED_CHANNELS_ID = ds_channel_id
            group_object.LINKED_CHANNEL_ID = ds_channel_id
            db.add(group_object)
            db.add(guild_object)
            db.commit()
            if not db.get(TG_LINKED, tg_group_id) and not db.get(TG_LINKED, ds_channel_id):
                channel_link = TG_LINKED(CHANNEL_ID=ds_channel_id, LINKED_CHANNEL_ID=tg_group_id)
                group_link = TG_LINKED(CHANNEL_ID=tg_group_id, LINKED_CHANNEL_ID=ds_channel_id)
                db.add(channel_link)
                db.add(group_link)
                db.commit()
            group_object.LINK_WAITING_GUILD_ID = None
            guild_object.TG_LINK_WATING_GROUP_ID = None
            guild_object.TG_LINK_WATING_CHANNEL_ID = None
            db.add(guild_object)
            db.add(group_object)
            db.commit()
            await message.reply("Привязка завершена успешно!\n"
                                "(если хотите отвязать дискорд канал,\n"
                                "воспользуйтесь /undiscord )")
        except Exception as e:
            print(e)

@dp.message_handler(commands=['id', 'айди', 'ID', 'Id', 'iD'])
async def group_id(message: types.Message):
    await message.reply(
        f"Айди данной телеграмм группы:\n\n{message.chat.id}\n\nВнимание! Минус перед цифрами (если он есть)\nтак же является частью id!")

@dp.message_handler(content_types=['new_chat_members'])
async def join_group(message: types.Message):
    bot_object = await bot.get_me()
    chat_id = str(message.chat.id)
    for chat_member in message.new_chat_members:
        if chat_member.id == bot_object.id and not db.get(GROUPS, chat_id):
            GROUP = GROUPS(GROUP_ID=chat_id)
            db.add(GROUP)
            db.commit()
    print(f"Телеграм бот стал членом группы с айди:   {chat_id}")

@dp.message_handler(content_types=['left_chat_member'])
async def leave_group(message: types.Message):
    bot_object = await bot.get_me()
    chat_id = str(message.chat.id)
    if message.left_chat_member.id == bot_object.id and db.get(GROUPS, chat_id):
        db.delete(db.get(GROUPS, chat_id))

        if db.get(TG_LINKED, chat_id):
            channel_id = db.get(TG_LINKED, chat_id).LINKED_CHANNEL_ID
            db.delete(db.get(TG_LINKED, chat_id))
            db.delete(db.get(TG_LINKED, channel_id))
        if db.get(WEBHOOKS, channel_id):
            db.delete(db.get(WEBHOOKS, channel_id))
        for guild_object in db.query(GUILDS).all():
            if guild_object.TG_LINKED_CHANNELS_ID and channel_id in guild_object.TG_LINKED_CHANNELS_ID.split(':'):
                if ':' in guild_object.TG_LINKED_CHANNELS_ID:
                    channels_list = guild_object.TG_LINKED_CHANNELS_ID.split(":")
                    channels_list.remove(channel_id)
                    guild_object.TG_LINKED_CHANNELS_ID = ":".join(channels_list)
                else:
                    guild_object.TG_LINKED_CHANNELS_ID = None
                    db.add(guild_object)
                break
        db.commit()
    print(f"Телеграм бот покинул группу с айди:   {chat_id}")

@dp.message_handler(content_types=types.ContentTypes.ANY)
async def resend(message: types.Message):
    if not db.get(GROUPS, str(message.chat.id)):
        return
    if db.get(GROUPS, str(message.chat.id)).LINKED_CHANNEL_ID:
        try:
            text = None
            files = []
            file_size_error = 'Вложение не было доставлено в дискорд канал из за превышения допустимого размера(25Mb)'

            if message.text:
                text = message.text
            if message.voice:
                if message.voice.file_size >= 26214400:
                    respond = await message.reply(file_size_error)
                    await sleep(15)
                    await respond.delete()
                else:
                    file = await bot.get_file(message.voice.file_id)
                    await bot.download_file(file.file_path, f'tempdata/voice_message.mp3')
                    files.append(discord.File('tempdata/voice_message.mp3'))
            elif message.audio:
                if message.audio.file_size >= 26214400:
                    respond = await message.reply(file_size_error)
                    await sleep(15)
                    await respond.delete()
                else:
                    file = await bot.get_file(message.audio.file_id)
                    await bot.download_file(file.file_path, f'tempdata/{message.audio.title}.mp3')
                    files.append(discord.File(f'tempdata/{message.audio.title}.mp3'))
                text = message.caption
            elif message.photo:
                if message.photo[-1]['file_size'] >= 26214400:
                    respond = await message.reply(file_size_error)
                    await sleep(15)
                    await respond.delete()
                else:
                    file = await bot.get_file(message.photo[-1]["file_id"])
                    await bot.download_file(file.file_path,
                                            f'tempdata/{message.photo[-1].file_unique_id}.{file.file_path.split(".")[-1]}')
                    files.append(
                        discord.File(f'tempdata/{message.photo[-1].file_unique_id}.{file.file_path.split(".")[-1]}'))
                text = message.caption
            elif message.video:
                if message.video.file_size >= 26214400:
                    respond = await message.reply(file_size_error)
                    await sleep(15)
                    await respond.delete()
                else:
                    file = await bot.get_file(message.video.file_id)
                    await bot.download_file(file.file_path, f'tempdata/{message.video.file_name}')
                    files.append(discord.File(f'tempdata/{message.video.file_name}'))
                text = message.caption
            elif message.video_note:
                if message.video_note.file_size >= 26214400:
                    respond = await message.reply(file_size_error)
                    await sleep(15)
                    await respond.delete()
                else:
                    file = await bot.get_file(message.video_note.file_id)
                    await bot.download_file(file.file_path,
                                            f'tempdata/videomessage_from_{message.from_user.first_name}.{file.file_path.split(".")[-1]}')
                    files.append(discord.File(
                        f'tempdata/videomessage_from_{message.from_user.first_name}.{file.file_path.split(".")[-1]}'))
            elif message.animation:
                if message.animation.file_size >= 26214400:
                    respond = await message.reply(file_size_error)
                    await sleep(15)
                    await respond.delete()
                else:
                    file = await bot.get_file(message.animation.file_id)
                    if not file.file_path.endswith('tgs'):
                        await bot.download_file(file.file_path, f'tempdata/{message.animation.file_name}')
                        files.append(discord.File(f'tempdata/{message.animation.file_name}'))
                text = message.caption
            elif message.document:
                if message.document.file_size >= 26214400:
                    respond = await message.reply(file_size_error)
                    await sleep(15)
                    await respond.delete()
                else:
                    file = await bot.get_file(message.document.file_id)
                    await bot.download_file(file.file_path, f'tempdata/{message.document.file_name}')
                    files.append(discord.File(f'tempdata/{message.document.file_name}'))
                text = message.caption
            elif message.sticker:
                if message.sticker.file_size >= 26214400:
                    respond = await message.reply(file_size_error)
                    await sleep(15)
                    await respond.delete()
                else:
                    file = await bot.get_file(message.sticker.file_id)
                    if file.file_path.endswith('tgs'):
                        pass
                    else:
                        await bot.download_file(file.file_path,
                                                f'tempdata/{message.sticker.file_unique_id}.{file.file_path.split(".")[-1]}')
                        files.append(
                            discord.File(f'tempdata/{message.sticker.file_unique_id}.{file.file_path.split(".")[-1]}'))
                text = message.caption
            try:
                if text or files:
                    webhook = SyncWebhook.from_url(
                        db.get(WEBHOOKS, (db.get(GROUPS, str(message.chat.id)).LINKED_CHANNEL_ID)).WEBHOOK_URL)
                    webhook.send(content=text,
                                 username=f'{message.from_user.first_name}〔TG〕',
                                 avatar_url="https://logos-download.com/wp-content/uploads/2016/07/Telegram_2.x_version_2014_Logo.png",
                                 files=files)
            except Exception as e:
                await message.answer(f"Если вы видите данное сообщение,\n"
                                     f"значит произошла программная ошибка,\n"
                                     f"из за которой сообщение не было доставлено\n"
                                     f"в дискорд канал, связанный с данной группой\.\n\n"
                                     f"Приносим свои извинения за произошедшее, отчёт\n"
                                     f"о сбое уже оправлен разработчикам для\n"
                                     f"вяснения причин и устранения неполадок\."
                                     f"Если данная ошибка стала появляться регулярно,\n"
                                     f"воспользуйтесь /undiscord , а затем перенастройте связь\n"
                                     f"с дискород-сервером с помощью /discord"
                                     f"Код ошибки:\n"
                                     f"```{e}```", parse_mode="'MarkdownV2")
                print(f"АХТУНГ!!! АХТУНГ!!! АХТУНГ!!!\n"
                      f"сбой в работе ds-tg канала (ошибка вебхука). Код ошибки:\n"
                      f"{e}")
        except Exception as e:
            await message.answer(f"Если вы видите данное сообщение,\n"
                                 f"значит произошла программная ошибка,\n"
                                 f"из за которой сообщение не было доставлено\n"
                                 f"в дискорд канал, связанный с данной группой\.\n\n"
                                 f"Приносим свои извинения за произошедшее, отчёт\n"
                                 f"о сбое уже оправлен разработчикам для\n"
                                 f"вяснения причин и устранения неполадок\."
                                 f"Если данная ошибка стала появляться регулярно,\n"
                                 f"воспользуйтесь /undiscord , а затем перенастройте связь\n"
                                 f"с дискород-сервером с помощью /discord"
                                 f"Код ошибки:\n"
                                 f"```{e}```", parse_mode="'MarkdownV2")
            print(f"АХТУНГ!!! АХТУНГ!!! АХТУНГ!!!\n"
                  f"сбой в работе ds-tg канала. Код ошибки:\n"
                  f"{e}")

def ready():
    print('Telegram-bot started successfully!')

def clearing():
    while True:
        sleep(60)
        try:
            shutil.rmtree('tempdata')
            os.mkdir("tempdata")
        except:
            continue

t = threading.Thread(target=clearing, daemon=True)
t.start()
executor.start_polling(dp, on_startup=ready())


#!/usr/bin/env python3
#*******************************************************************************
#rrr_anl_map_mag_mod.py
#*******************************************************************************

#Purpose:
#Given a netCDF file from RAPID outputs, the name of a CSV file, and a
#percentile value, this program computes a series of metrics concerning the
#magnitude of the output variable (e.g. river discharge) for each individual
#river reach and saves the output in the CSV file. If optional ISO 8601
#character strings for the beginning and the end of the analysis are provided,
#the metrics are only computed over the desired time range.
#Author:
#Cedric H. David, 2021-2023

#*******************************************************************************
#Import Python modules
#*******************************************************************************
import sys
import netCDF4
import numpy
import datetime
import calendar
import heapq
import csv

#*******************************************************************************
#Declaration of variables (given as command line arguments)
#*******************************************************************************
# 1 - rrr_out_ncf
# 2 - ZS_prc
# 3 - YS_title
# 4 - rrr_map_csv
#(5)- rrr_beg_iso
#(6)- rrr_end_iso

#*******************************************************************************
#Get command line arguments
#*******************************************************************************
IS_arg=len(sys.argv)
if IS_arg < 5 or IS_arg > 7:
     print('ERROR - A minimum of 4 and a maximum of 6 arguments can be used')
     raise SystemExit(22)

rrr_out_ncf=sys.argv[1]
ZS_prc=float(sys.argv[2])
YS_title=sys.argv[3]
rrr_map_csv=sys.argv[4]
if IS_arg>=6:
     rrr_beg_iso=sys.argv[5]
if IS_arg>=7:
     rrr_end_iso=sys.argv[6]

#*******************************************************************************
#Print input information
#*******************************************************************************
print('Command line inputs')
print('- '+rrr_out_ncf)
print('- '+str(ZS_prc))
print('- '+YS_title)
print('- '+rrr_map_csv)
if IS_arg>=6:
     print('- '+rrr_beg_iso)
if IS_arg>=7:
     print('- '+rrr_end_iso)

#*******************************************************************************
#Check if files exist
#*******************************************************************************
try:
     with open(rrr_out_ncf) as file:
          pass
except IOError as e:
     print('ERROR - Unable to open '+rrr_out_ncf)
     raise SystemExit(22)

if ZS_prc<0 or ZS_prc>100:
     print('ERROR - Percentile value: '+str(ZS_prc)+', must be within [0,100]')
     raise SystemExit(22)

#*******************************************************************************
#Open netCDF file
#*******************************************************************************
print('Opening netCDF file')

f = netCDF4.Dataset(rrr_out_ncf, 'r')

#*******************************************************************************
#Read netCDF file static data
#*******************************************************************************
print('Reading netCDF file static data')

#-------------------------------------------------------------------------------
#Get dimensions/variables names
#-------------------------------------------------------------------------------
if 'COMID' in f.dimensions:
     YS_id_name='COMID'
elif 'rivid' in f.dimensions:
     YS_id_name='rivid'
else:
     print('ERROR - neither COMID nor rivid exist in'+rrr_out_ncf)
     raise SystemExit(22)

if 'Time' in f.dimensions:
     YS_time_name='Time'
elif 'time' in f.dimensions:
     YS_time_name='time'
else:
     print('ERROR - Neither Time nor time exist in '+rrr_out_ncf)
     raise SystemExit(22)

if 'Qout' in f.variables:
     YS_out_name='Qout'
elif 'V' in f.variables:
     YS_out_name='V'
else:
     print('ERROR - neither Qout nor V exist in'+rrr_out_ncf)
     raise SystemExit(22)

#-------------------------------------------------------------------------------
#Get variable sizes
#-------------------------------------------------------------------------------
IS_riv_bas=len(f.variables[YS_id_name])
print('- Number of river reaches: '+str(IS_riv_bas))

IS_time=len(f.variables[YS_out_name])
print('- Number of time steps: '+str(IS_time))

#-------------------------------------------------------------------------------
#Get river IDs
#-------------------------------------------------------------------------------
print('- Getting river IDs')
IV_riv_bas_id=f.variables[YS_id_name]

#-------------------------------------------------------------------------------
#Getting or making time variable values
#-------------------------------------------------------------------------------
print('- Getting or making time variable values')
ZV_time=numpy.zeros(IS_time)
if YS_time_name in f.variables and                                             \
     f.variables[YS_time_name][0]!=netCDF4.default_fillvals['i4']:
     #If the time variable exists but was not populated it holds the default
     #netCDF _fillValue and should be ignored here
     print(' . Values of time variable obtained from netCDF metadata')
     ZV_time=f.variables[YS_time_name][:]
     ZS_TauR=f.variables[YS_time_name][1]-f.variables[YS_time_name][0]
else:
     rrr_str_iso='2004-01-01T06:00:00'
     #The start time for the first time step in the input netCDF file.
     #ISO 8601 format: '1970-01-01T00:00:00', make sure UTC is used
     ZS_TauR=10800
     #The duration (s) of the time steps in the input netCDF, 3h is most common
     print(' . WARNING: netCDF file does not have values of time variable')
     print('            Assuming file starts at '+rrr_str_iso)
     print('            Assuming time step is '+str(ZS_TauR)+' s')

     rrr_str_obj=datetime.datetime.strptime(rrr_str_iso,'%Y-%m-%dT%H:%M:%S')
     ZV_time[0]=calendar.timegm(rrr_str_obj.timetuple())
     for JS_time in range(1,IS_time):
          ZV_time[JS_time]=ZV_time[JS_time-1]+ZS_TauR

#*******************************************************************************
#Read netCDF file dynamic data
#*******************************************************************************
print('Reading netCDF file dynamic data')

#-------------------------------------------------------------------------------
#Determine time steps to include in analysis
#-------------------------------------------------------------------------------
print('Determining time steps to include in analysis')

if 'rrr_beg_iso' in locals():
     rrr_beg_obj=datetime.datetime.strptime(rrr_beg_iso,'%Y-%m-%dT%H:%M:%S')
     ZS_beg=calendar.timegm(rrr_beg_obj.timetuple())
else:
     ZS_beg=ZV_time[0]

if 'rrr_end_iso' in locals():
     rrr_end_obj=datetime.datetime.strptime(rrr_end_iso,'%Y-%m-%dT%H:%M:%S')
     ZS_end=calendar.timegm(rrr_end_obj.timetuple())
else:
     ZS_end=ZV_time[IS_time-1]

print('- Performing the analysis for times steps between those starting at:')
print('  '+datetime.datetime.utcfromtimestamp(ZS_beg).isoformat())
print('  '+datetime.datetime.utcfromtimestamp(ZS_end).isoformat())
print('  (both included)')

IS_beg=numpy.where(ZV_time==ZS_beg)[0]
if len(IS_beg)==1:
     IS_beg=IS_beg[0]
else:
     print('ERROR - Could not locate requested begin time in'+rrr_out_ncf)
     raise SystemExit(22)

IS_end=numpy.where(ZV_time==ZS_end)[0]
if len(IS_end)==1:
     IS_end=IS_end[0]
else:
     print('ERROR - Could not locate requested end time in'+rrr_out_ncf)
     raise SystemExit(22)

#-------------------------------------------------------------------------------
#Computing average, maximum, and minimum
#-------------------------------------------------------------------------------
print('Computing average, maximum, and minimum')

IV_one=numpy.ones(IS_riv_bas).astype(int)
IV_npt=numpy.zeros(IS_riv_bas).astype(int)
ZV_avg=numpy.zeros(IS_riv_bas)
ZV_max=numpy.zeros(IS_riv_bas)
ZV_min=numpy.zeros(IS_riv_bas)
ZV_min[:]=1000000000

for JS_time in range(IS_beg,IS_end+1):
     ZV_out=f.variables[YS_out_name][JS_time,:]
     #values read from the netCDF file
     if numpy.ma.is_masked(ZV_out):
          BV_yes=~ZV_out.mask
     else:
          BV_yes=[True]*IS_riv_bas
     #locations where the netCDF values are not masked (~ inverts all booleans)
     IV_npt=numpy.where(BV_yes,IV_npt+IV_one,IV_npt)
     #updating the number of actual values (i.e. not NaN) for each reach
     ZV_avg=numpy.where(BV_yes,ZV_avg+ZV_out,ZV_avg)
     #updating the average
     ZV_max=numpy.where((BV_yes)&(ZV_out>ZV_max),ZV_out,ZV_max)
     #updating the maximum
     ZV_min=numpy.where((BV_yes)&(ZV_out<ZV_min),ZV_out,ZV_min)
     #updating the minimum

IV_npt=numpy.where(IV_npt==0,-9999,IV_npt)
#Replacing number of values by -9999 only where there was 0 values to avoid
#runtime warning during division below
ZV_avg=numpy.where(IV_npt>0,ZV_avg/IV_npt,numpy.NaN)
#Dividing sum of values by number of values. Otherwise: NaN
ZV_max=numpy.where(IV_npt>0,ZV_max,numpy.NaN)
#Replacing max value by NaN where there only masked data
ZV_min=numpy.where(IV_npt>0,ZV_min,numpy.NaN)
#Replacing max value by NaN where there only masked data

#-------------------------------------------------------------------------------
#Computing percentile
#-------------------------------------------------------------------------------
print('Computing percentile')

ZS_kth=ZS_prc/100.
#The kth statistic corresponding to the desired percentile
ZV_rat=numpy.zeros(IS_riv_bas)
#List of ratios, one ratio per reach, used as weight between two percentiles
ZH_hea=[[] for JS_riv_bas in range(IS_riv_bas)]
#List of heaps, one heap per reach, each will be built with appropriate size
ZV_til=numpy.empty(IS_riv_bas)
ZV_til[:]=numpy.nan
#Initialized numpy array for percentile values

for JS_riv_bas in range(IS_riv_bas):
     IS_npt=IV_npt[JS_riv_bas]
     #The number of points in the timeseries for this river reach
     if IS_npt>0: ZV_rat[JS_riv_bas]=ZS_kth*(IS_npt-1)-int(ZS_kth*(IS_npt-1))
     if ZS_kth>=0.5:
          IS_nhp=IS_npt-int(ZS_kth*(IS_npt-1))
          #The number of elements to retain for percentile computation
          ZH_hea[JS_riv_bas]=[-999999999]*IS_nhp
          heapq.heapify(ZH_hea[JS_riv_bas])
     if ZS_kth<0.5:
          IS_nhp=int(ZS_kth*(IS_npt-1))+2
          #The number of elements to retain for percentile computation
          ZH_hea[JS_riv_bas]=[999999999]*IS_nhp
          heapq.heapify(ZH_hea[JS_riv_bas])

for JS_time in range(IS_beg,IS_end+1):
     ZV_out=f.variables[YS_out_name][JS_time,:]
     #values read from the netCDF file
     if numpy.ma.is_masked(ZV_out):
          BV_yes=~ZV_out.mask
     else:
          BV_yes=[True]*IS_riv_bas
     #locations where the netCDF values are not masked (~ inverts all booleans)
     for JS_riv_bas in range(IS_riv_bas):
          if (BV_yes[JS_riv_bas] and ZS_kth>=0.5):
               heapq.heappushpop(ZH_hea[JS_riv_bas],ZV_out[JS_riv_bas])
          if (BV_yes[JS_riv_bas] and ZS_kth<0.5):
               heapq._heappushpop_max(ZH_hea[JS_riv_bas],ZV_out[JS_riv_bas])

for JS_riv_bas in range(IS_riv_bas):
     if IV_npt[JS_riv_bas]>0:
          ZS_rat=ZV_rat[JS_riv_bas]
          if ZS_kth>=0.5:
               ZV_two=heapq.nsmallest(2,ZH_hea[JS_riv_bas])
          if ZS_kth<0.5:
               ZV_two=heapq.nlargest(2,ZH_hea[JS_riv_bas])
          ZV_two.sort()
          ZV_til[JS_riv_bas]=ZV_two[0]+ZS_rat*(ZV_two[1]-ZV_two[0])

#*******************************************************************************
#Write CSV file
#*******************************************************************************
print('Writing CSV file')

with open(rrr_map_csv, 'w') as csvfile:
     csvwriter = csv.writer(csvfile, dialect='excel')
     IV_line=[YS_title,                                                        \
              YS_out_name+'_avg',                                              \
              YS_out_name+'_max',                                              \
              YS_out_name+'_min',                                              \
              YS_out_name+'_'+str(int(ZS_prc))+'p']
     csvwriter.writerow(IV_line)

     for JS_riv_bas in range(IS_riv_bas):
          IV_line=[IV_riv_bas_id[JS_riv_bas],                                  \
                   round(ZV_avg[JS_riv_bas],2),                                \
                   round(ZV_max[JS_riv_bas],2),                                \
                   round(ZV_min[JS_riv_bas],2),                                \
                   round(ZV_til[JS_riv_bas],2)]
          csvwriter.writerow(IV_line)

#*******************************************************************************
#End
#*******************************************************************************


#!/usr/bin/env python

# This panel will create folders to start projects
# W. Scott Meador

# TODO:
# DEAL WITH DUPLICATE FOLDER ENTRIES
# ADD HELP TO THE RIGHT SIDE OF TREECTRL

import os
import wx
import images
import xml.etree.cElementTree as ET
import wsm_paths as wsm

class runPanel(wx.Panel):
    def __init__(self, obj, parent):
        wx.Panel.__init__(self, parent)
        self.dirPath = ""

        # Buttons - Choose, Add, Create Folders, Remove (or with the delete key)
        wx.Button(self, 1, 'Choose Project Folder', (10, 5))
        wx.Button(self, 2, 'Add', (10, 435))
        wx.Button(self, 3, 'Remove', (88,435))
        wx.Button(self, 4, 'Make Defaults', (170,435))
        wx.Button(self, 5, 'Create Folders', (295, 435))

        self.tree = wx.TreeCtrl(self, -1, (10,30), wx.Size(400,400), style=wx.SIMPLE_BORDER|wx.TR_HAS_BUTTONS)

        isz = (16,16)
        il = wx.ImageList(isz[0], isz[1])
        self.fldridx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER,      wx.ART_OTHER, isz))
        self.fldropenidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN,   wx.ART_OTHER, isz))
        self.fileidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, isz))
        self.smileidx = il.Add(images.getSmilesBitmap())

        self.tree.SetImageList(il)
        self.il = il

        # Get XML file
        # Call fillmeup
        tmpPath = os.path.split((os.path.abspath(wsm.__file__)))
        wsm.userpaths = tmpPath[0] + '/user_paths.xml'
        self.xml = ET.parse(wsm.userpaths) # Consider trying '//user_paths.xml'
        root = self.fillmeup()

        # expand root
        self.tree.Expand(root)
        # Bindings
        self.Bind(wx.EVT_BUTTON, self.OnChoose, id=1)
        self.Bind(wx.EVT_BUTTON, self.OnAdd, id=2)
        self.Bind(wx.EVT_BUTTON, self.OnRemove, id=3)
        self.Bind(wx.EVT_BUTTON, self.userDefaults, id=4)
        self.Bind(wx.EVT_BUTTON, self.OnCreate, id=5)

        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, self.tree)
        self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.tree)
        self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnEndEdit, self.tree)

        self.tree.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
        self.tree.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)

    def fillmeup(self):
        xml = self.xml.getroot() #goes to root of xml file
        tree = self.tree #tree control
        root = tree.AddRoot(xml.tag) #adds root, which is first tag in file
        def add(parent, elem): #add function gets root and rest of xml
            for e in elem:
                text = e.text.strip()
                val = tree.AppendItem(parent, text)
                tree.SetPyData(val, e)
                tree.SetItemImage(val, self.fldridx, wx.TreeItemIcon_Normal)
                tree.SetItemImage(val, self.fldropenidx, wx.TreeItemIcon_Expanded)
                add(val, e)
        add(root, xml) #root = treeCtrl, xml = xml root
        return root

    def OnChoose(self, event):
        dlg = wx.DirDialog(self, "Choose a directory:", style=wx.DD_DEFAULT_STYLE)
        if dlg.ShowModal() == wx.ID_OK:
            #print ('You selected: %s\n' % dlg.GetPath())
            pass
        dlg.Destroy()

        self.dirPath = dlg.GetPath()
        self.dirname = os.path.basename(dlg.GetPath())
        # make directory name the same as the root folder
        self.tree.SetItemText(self.tree.GetRootItem(),self.dirname)

    def OnAdd(self, event):
        # Consider a text entry box
        cursel = self.tree.GetSelection()
        sub = self.tree.AppendItem(cursel, 'untitled')
        self.tree.SetPyData(sub, None)
        self.tree.SetItemImage(sub, self.fldridx, wx.TreeItemIcon_Normal)
        self.tree.SetItemImage(sub, self.fldropenidx, wx.TreeItemIcon_Expanded)
        self.tree.EditLabel(sub)
        # Note self.tree.SortChildren()

    def OnRemove(self, event):
        cursel = self.tree.GetSelection()
        root = self.tree.GetRootItem()
        if cursel == root:
            wx.Bell()
            # print "Can't remove root folder"
            event.Veto()
        else:
            self.tree.Delete(cursel)

    def folderList(self, child, folder):
        # make a list and feed into os.makedirs
        self.list.append(folder)
        parent = self.tree.GetItemParent(child)
        self.list.insert(0,self.tree.GetItemText(parent))
        # loop through list to find parent and build a path and then empty list
        while True:
            parent = self.tree.GetItemParent(parent)
            if parent:
                self.list.insert(0,self.tree.GetItemText(parent))
            else:
                break
        self.list.pop(0)
        try:
            os.makedirs(self.dirPath + '/' + ('/'.join(self.list))) # make directories here
        except os.error:
            pass
        self.list = []

    def subFolders(self, folder, cookie, parentDir):
        item,cookie = self.tree.GetFirstChild(folder)
        self.folderList(item,self.tree.GetItemText(item))
        while True:
            if self.tree.ItemHasChildren(item):
                self.subFolders(item,item,self.tree.GetItemText(item))
            item = self.tree.GetNextSibling(item)
            if not item:
                break
            self.folderList(item,self.tree.GetItemText(item))

    def OnCreate(self, event):
        self.list = []
        if self.dirPath == "":
            dlg = wx.MessageDialog(self, 'Choose a Project Folder',
                        "Can't do it yet",
                        wx.OK | wx.ICON_INFORMATION
                        #wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_INFORMATION
                        )
            dlg.ShowModal()
            dlg.Destroy()
        else:
            #check if project folder already exists - throw up a dialog to check if overwrite
            cookie = 0
            rootItem = self.tree.GetRootItem()
            item,cookie = self.tree.GetFirstChild(rootItem)

            while True:
                if not item:
                    # Confirm with a dialog box
                    dlg = wx.MessageDialog(self, 'Folders Created!',
                                'DONE',
                                wx.OK | wx.ICON_INFORMATION
                                #wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_INFORMATION
                                )
                    dlg.ShowModal()
                    dlg.Destroy()
                    break
                self.folderList(item,self.tree.GetItemText(item)) # adds main tree members
                if self.tree.ItemHasChildren(item):
                    self.subFolders(item,item,self.tree.GetItemText(item)) # adds tree child members
                item = self.tree.GetNextSibling(item)

    def OnRightDown(self, event):
        pt = event.GetPosition();
        item, flags = self.tree.HitTest(pt)
        if item:
            self.tree.SelectItem(item)

    def OnRightUp(self, event):
        pt = event.GetPosition();
        item, flags = self.tree.HitTest(pt)
        if item:
            self.tree.EditLabel(item)

    def OnBeginEdit(self, event):
        # show how to prevent edit...
        item = event.GetItem()
        root = self.tree.GetRootItem()
        if item == root: #and self.tree.GetItemText(item)
            wx.Bell()
            #print "You can't edit this one...\n"
            event.Veto()

    def OnEndEdit(self, event):
        pass

    def OnSelChanged(self, event):
        pass

    def userDefaults(self, event):
        xmlroot = ET.Element("Project_Builder")
        cookie = 0
        rootItem = self.tree.GetRootItem()
        item,cookie = self.tree.GetFirstChild(rootItem)

        def subNodes(folder, cookie, elem):
            item,cookie = self.tree.GetFirstChild(folder)
            new = ET.SubElement(elem, "node")
            new.text = self.tree.GetItemText(item)

            while True:
                if self.tree.ItemHasChildren(item):
                    subNodes(item,item,new)
                item = self.tree.GetNextSibling(item)
                if not item:
                    break
                current = ET.SubElement(elem, "node")
                current.text = self.tree.GetItemText(item)

        while True:
            if not item:
                break
            new = ET.SubElement(xmlroot, "node")
            new.text = self.tree.GetItemText(item)
            if self.tree.ItemHasChildren(item):
                subNodes(item,item, new) # adds tree child members
            item = self.tree.GetNextSibling(item)

        tree = ET.ElementTree(xmlroot)
        #tree.write("/Applications/TD_Tool/user_paths.xml")
        tree.write(wsm.userpaths)


from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from tortoise import Tortoise
from src.database.register import register_tortoise
from src.database.config import TORTOISE_ORM

from src.routes import users, weatherapis

Tortoise.init_models(["src.database.models"], "models")

app = FastAPI()

# NEW
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:8080"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.include_router(users.router)
app.include_router(weatherapis.router)

register_tortoise(app, config=TORTOISE_ORM, generate_schemas=False)

@app.get("/")
def home():
    return "Simple API Service"


'''
Faça um programa que leia o ano de nascimento de um jovem e informe, de acordo com a sua idade,
se ele ainda vai se alistar ao serviço militar, se é a hora exata de se alistar ou se já passou do tempo do
alistamento. Seu programa também deverá mostrar o tempo que falta ou que passou do prazo.
'''
from datetime import date

anoNascimento = int(input("Informe seu ano de nascimento: "))
#pegando o ano atual do sistema
anoAtual = date.today().year

idade = anoAtual - anoNascimento

if (idade < 18):
    print("Quem nasceu em {} tem {} em {}".format(anoNascimento, idade, anoAtual))
    print("Ainda faltam {} anos para o alistamento\n"
          "Seu alistamento será em {}".format(18 - idade, anoNascimento + 18))
elif (idade > 18):
    print("Quem nasceu em {} tem {} em {}".format(anoNascimento, idade, anoAtual))
    print("Você já deveria ter se alistado há {} anos\n"
          "Seu alistamento foi em {}".format(idade - 18, anoNascimento + 18))
elif (idade == 18):
    print("Quem nasceu em {} tem {} anos em {}".format(anoNascimento, idade, anoAtual))
    print("Você tem que se alistar IMEDIATAMENTE")


"""
Este programa controla el eqipo neocera ltc-11
Nos vamos a conectar con pyvisa y a
setear un setpoint de temperatura para que el equipo
vaya a ese valor
"""

import visa
import time
import matplotlib.pyplot as plt
import numpy as np

class handler():
    """
		Maneja los eventos de matplotlib y el control de temperatura
    """
    def __init__(self,line,puerto):
        self.line = line
        self.puerto = puerto
        self.setP = 0 #set point
        self.setPex = 0 #punto decimal del set point
        self.new = True # habilita la entrada de un nuevo dato
        self.xs = line.get_xdata()
        self.ys = line.get_ydata()
        self.STOP = False # frena la iteracion
        self.cid = line.figure.canvas.mpl_connect('close_event',self.stop)
        self.cidkey = line.figure.canvas.mpl_connect('key_press_event',self.setPoint)

    def stop(self,event):
        self.STOP = True

    def cambiarSetP(self):
        print('nuevo set point: ', self.setP)
        self.puerto.write('SMON;')
        self.puerto.write('SETP1,'+str(self.setP)+';')# setea el setPoint a 80
        self.puerto.write('SCONT;')
		#self.puerto.write('SCONT;')# modo control

    def setPoint(self, event):
        try:
            n = int(event.key)
            if self.new:
                self.setP = n
                self.setPex = 0
                self.new = False
            elif self.setPex==0 :
                self.setP = self.setP*10 + n
            else:
                self.setP = self.setP + n*(10**self.setPex)
                self.setPex -= 1
        except:
            if event.key == '.':
                self.setPex = -1
            if event.key == 'enter':
                self.new = True
                self.cambiarSetP()
            if event.key == 'backspace':
                self.new = True
            if event.key == 'p':
            	plt.cla()
            	print ('reset grafico')

#H = handler(line)

rm = visa.ResourceManager()
rm.list_resources()
tc = rm.open_resource('GPIB::10::INSTR')

print(tc.query('*IDN?;'))

file = open('nadagrafico40-30-11.txt','a')
control = 1
t0 = time.time()
t = t0

fig = plt.figure()
ax = fig.add_subplot(111)
line, = ax.plot([],[])

H = handler(line,tc)
H.setPoint(290.0)
#tiempos = []
#temperaturas = []

while not H.STOP:
	T_aux = tc.query('QSAMP?1;')
	T = float(T_aux[0:len(T_aux)-3])
	t = time.time()
#	print(T_aux+str(t-t0))
	file.write(T_aux+str(t-t0))

	#tiempos.append(t)
	#temperaturas.append(T)

	#plt.plot(t-t0,T,"r*")
	#plt.pause(0.5) # muestra los datos y espera 0.5 segundos
	ax.plot(t-t0,T,"r*")
	plt.pause(0.5) # muestra los datos y espera 0.5 segundos
#	time.sleep(1)

file.close()


from typing import List
from ._types import EvalDecentralisationPayload, EvalDecentralisationResponse, StakeOptimizePayload, StakeOptimizeResponse, StakingTarget

from ._evaluation import eval_decentralization
from ._optimizer import stake_optimize

from flask import Flask, request

app = Flask(__name__)

import json

@app.route("/api/dev", methods=["GET"])
def dev():
    """
    payload = EvalDecentralisationPayload(
        stakes=request.args.get("stakes"),
        total_supply=request.args.get("total_supply")
    )
    """

    return json.dumps({"response": "ok"})  # resp.to_json()

@app.route("/api/eval", methods=["POST"])
def eval_decentralisation():
    """
    payload = EvalDecentralisationPayload(
        stakes=request.args.get("stakes"),
        total_supply=request.args.get("total_supply")
    )
    """
    payload: EvalDecentralisationPayload = EvalDecentralisationPayload.from_dict(
        request.get_json())

    resp = EvalDecentralisationResponse(
        eval_decentralization(payload.stakes)  # , payload.total_supply)
    )

    return resp.to_json()  # resp.to_json()

@app.route("/api/optimize", methods=["POST"])
def optimize():
    payload: StakeOptimizePayload = StakeOptimizePayload.from_dict(
        request.get_json()
    )

    # compute weights
    weights = stake_optimize(payload.amount_to_stake, payload.validator_set)

    # compute new stakes
    to_stake_per_val = [
        weights[i] * payload.amount_to_stake for i in range(len(payload.validator_set))]
    new_stakes = [
        payload.validator_set[i].curr_stake + to_stake_per_val[i] for i in range(len(payload.validator_set))
    ]

    # compute our new decentralisation ratio
    decentralisation_ratio = eval_decentralization(new_stakes)

    # recompose for response
    targets: List[StakingTarget] = [
        StakingTarget(
            moniker=payload.validator_set[i].moniker,
            address=payload.validator_set[i].address,
            amount_to_stake=weights[i] * payload.amount_to_stake
        ) for i in range(len(payload.validator_set))
    ]

    # prune validators with 0 to stake
    targets = list(filter(lambda x: x.amount_to_stake > 0, targets))
    # prune validators with < 0.0000001 to stake
    targets = list(filter(lambda x: x.amount_to_stake > 0.000001, targets))

    # create response obj and return
    resp = StakeOptimizeResponse(
        expected_yield=0.0,
        decentralisation_ratio=decentralisation_ratio,
        targets=targets
    )
    return resp.to_json()


from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import json
from pydantic import BaseModel

palabras_1 = {
    "q1": ['z'],
    "q2": ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q'],
    "q3": ['r']
}
palabras_2 = {
    "q1": ['r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'],
    "q2": ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'],
    "q3": ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r']
}
numeros = ["1" ,"2", "3", "4", "5", "6", "7", "8", "9"]
numeros2 = ["0", "1" ,"2", "3", "4", "5", "6", "7", "8", "9"]
abecedario = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

app = FastAPI()

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

@app.post("/q0")
async def q0(palabra):
    caracter = palabra[0]
    for clavere, subfamiliasre in palabras_1.items():
        if caracter in subfamiliasre:
            flujo = clavere
            print(flujo)
    return flujo

@app.post("/q1")
async def q1(palabra):
    caracter = palabra[1]
    if caracter in palabras_2["q1"]:
        flujo = "q4"
        print(flujo)
    return flujo

@app.post("/q2")
async def q2(palabra):
    caracter = palabra[1]
    if caracter in palabras_2["q2"]:
        flujo = "q4"
        print(flujo)
    return flujo

@app.post("/q3")
async def q3(palabra):
    caracter = palabra[1]
    if caracter in palabras_2["q3"]:
        flujo = "q4"
        print(flujo)
    return flujo

@app.post("/q4")
async def q4(palabra):
    caracter = palabra[2]
    if caracter == "-":
        print(caracter)
        flujo = "q5"
    return flujo

@app.post("/q5")
async def q5(palabra):
    caracter = palabra[3]
    if caracter == "0":
        flujo = "q6"
    elif caracter in numeros:
        flujo = "q9"
    print(flujo)
    return flujo

@app.post("/q6")
async def q6(palabra):
    caracter = palabra[4]
    if caracter == "0":
        flujo = "q7"
    elif caracter in numeros:
        flujo = "q10"
    print(flujo)
    return flujo

@app.post("/q7")
async def q7(palabra):
    caracter = palabra[5]
    if caracter in numeros:
        flujo = "q8"
    print(flujo)
    return flujo

@app.post("/q8")
async def q8(palabra):
    caracter = palabra[6]
    if caracter == "-":
        print(caracter)
        flujo = "q11"
    return flujo

@app.post("/q9")
async def q9(palabra):
    caracter = palabra[4]
    if caracter in numeros2:
        flujo = "q10"
    print(flujo)
    return flujo

@app.post("/q10")
async def q10(palabra):
    caracter = palabra[5]
    if caracter in numeros2:
        flujo = "q8"
    print(flujo)
    return flujo

@app.post("/q11")
async def q11(palabra):
    caracter = palabra[7]
    if caracter in abecedario:
        flujo = "q12"
    print(flujo)
    return flujo

""" q0(palabra)
q1(palabra)
q2(palabra)
q3(palabra)
q4(palabra)
q5(palabra)
q6(palabra)
q7(palabra)
q8(palabra)
q9(palabra)
q10(palabra)
q11(palabra) """


from albumentations import (
    Resize, Rotate, HorizontalFlip, VerticalFlip, IAAPerspective, ShiftScaleRotate, CLAHE, RandomRotate90,
    Transpose, ShiftScaleRotate, Blur, OpticalDistortion, GridDistortion, HueSaturationValue,
    IAAAdditiveGaussianNoise, GaussNoise, MotionBlur, MedianBlur, IAAPiecewiseAffine, RandomResizedCrop,
    IAASharpen, IAAEmboss, RandomBrightnessContrast, Flip, OneOf, Compose, Normalize, Cutout, CoarseDropout, ShiftScaleRotate, CenterCrop, Resize
)

from albumentations.pytorch import ToTensorV2

def get_train_transforms(img_sz=512):
    return Compose([
            Resize(img_sz, img_sz, always_apply=True),
            Rotate(limit=30, p=0.5),
            HorizontalFlip(p=0.5),
            VerticalFlip(p=0.5),
            Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], max_pixel_value=255.0, p=1.0),
            ToTensorV2(p=1.0),
        ], p=1.)

def get_valid_transforms(img_sz=512):
    return Compose([
            Resize(img_sz, img_sz, always_apply=True),
            Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], max_pixel_value=255.0, p=1.0),
            ToTensorV2(p=1.0),
        ], p=1.)

def get_inference_transforms(img_size):
    return Compose([
            Resize(img_size, img_size, always_apply=True),
            Rotate(limit=30, p=0.5),
            HorizontalFlip(p=0.5),
            VerticalFlip(p=0.5),
            Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], max_pixel_value=255.0, p=1.0),
            ToTensorV2(p=1.0),
        ], p=1.)


import argparse
import json
import logging
import sys
sys.path.append('../..')

from storescraper.utils import get_store_class_by_name  # noqa

def main():
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(levelname)s %(message)s',
                        filename='products.log',
                        filemode='w')

    parser = argparse.ArgumentParser(
        description='Retrieves the products of the given store.')

    parser.add_argument('store', type=str,
                        help='The name of the store to be parsed')

    parser.add_argument('--categories', type=str, nargs='*',
                        help='Specific categories to be parsed')

    parser.add_argument('--with_async', type=bool, nargs='?', default=False,
                        const=True,
                        help='Use async tasks (celery)')

    parser.add_argument('--extra_args', type=json.loads, nargs='?', default={},
                        help='Optional arguments to pass to the parser '
                             '(usually username/password) for private sites)')

    args = parser.parse_args()
    store = get_store_class_by_name(args.store)

    available_products = 0
    unavailable_products = 0

    products_data = store.products(
        categories=args.categories,
        use_async=args.with_async,
        extra_args=args.extra_args)

    for product in products_data['products']:
        if product.is_available():
            available_products += 1
        else:
            unavailable_products += 1
        print(product, '\n')

    urls_with_error = products_data['discovery_urls_without_products']
    print('Discovery URLs without products:')
    if not urls_with_error:
        print('* No empty URLs found')
    for url_with_error in urls_with_error:
        print('* {}'.format(url_with_error))

    print()
    print('Available: {}'.format(available_products))
    print('Unavailable: {}'.format(unavailable_products))
    print('With error: {}'.format(len(urls_with_error)))
    print('Total: {}'.format(available_products + unavailable_products +
                             len(urls_with_error)))

if __name__ == '__main__':
    main()