#!/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 rlib import html_unescape, validate_object
from datetime import datetime
import urlparse

class Thing(object):
    def __init__(self, json):
        data = json['data']

        self.id = data.get('id')

        self.name = data.get('name')
        self.full_name = data.get('name')

        self.kind = json.get('kind')

    @staticmethod
    def parse(reddit, json):
        kind = json.get('kind')

        if kind == 't1':
            return Comment(reddit, json)
        elif kind == 't2':
            return Account(reddit, json)
        elif kind == 't3':
            return Link(reddit, json)
        elif kind == 't5':
            return Subreddit(reddit, json)
        else:
            raise NotImplementedError()

class Content(Thing):
    def __init__(self, json):
        super(Content, self).__init__(json)

        data = json['data']

        self.author = data.get('author')
        self.author_flair_css_class = data.get('author_flair_css_class')
        self.author_flair_text = data.get('author_flair_text')

        self.banned_by = data.get('banned_by')
        self.approved_by = data.get('approved_by')

        self.saved = data.get('saved')

        self.created = datetime.fromtimestamp(data.get('created'))
        self.created_utc = datetime.utcfromtimestamp(data.get('created_utc'))

        self.edited = data.get('edited')
        self.distinguished = data.get('distinguished')

        self.ups = data.get('ups')
        self.downs = data.get('downs')
        self.likes = data.get('likes')
        self.score_hidden = data.get('score_hidden')

        self.num_reports = data.get('num_reports')

        self.subreddit = data.get('subreddit')
        self.subreddit_id = data.get('subreddit_id')

class Comment(Content):
    prefix = 't1'

    URL_COMMENT_PERMALINK = "/r/%s/comments/%s/_/%s"

    def __init__(self, reddit, json):
        super(Comment, self).__init__(json)

        self._reddit = reddit
        data = json['data']

        self.body = data.get('body')
        self.body_html = html_unescape(data.get('body_html'))

        self.gilded = data.get('gilded')

        self.parent_id = data.get('parent_id')

        self.link_id = data.get('link_id')
        self.link_title = data.get('link_title')

        # Parse replies
        self.replies = []
        if data["replies"] and len(data["replies"]) > 0:
            for comment in data["replies"]["data"]["children"]:
                if comment.get('kind') != 't1':
                    continue

                self.replies.append(Comment(reddit, comment))

        validate_object(self, data, ['replies'])

        # Create permalink
        self.permalink = self.create_permalink("http://%s" % self._reddit.domain, self)

    @staticmethod
    def create_permalink(base, comment):
        link_id = comment.link_id
        if link_id.startswith("t3_"):
            link_id = link_id[3:]

        return urlparse.urljoin(
            base,
            Comment.URL_COMMENT_PERMALINK % (
                comment.subreddit, link_id, comment.id
            )
        )

class Account(Thing):
    prefix = 't2'

    URL_OVERVIEW = "/user/%s.json"
    URL_COMMENTS = "/user/%s/comments.json"
    URL_LINKS = "/user/%s/submitted.json"
    URL_SUBSCRIBED_SUBREDDITS = "/subreddits/mine.json"

    def __init__(self, reddit, json):
        super(Account, self).__init__(json)

        self._reddit = reddit
        data = json['data']

        self.link_karma = data.get('link_karma')
        self.comment_karma = data.get('comment_karma')

        self.created = datetime.fromtimestamp(data.get('created'))
        self.created_utc = datetime.utcfromtimestamp(data.get('created_utc'))

        self.has_mail = data.get('has_mail')
        self.has_mod_mail = data.get('has_mod_mail')
        self.has_verified_email = data.get('has_verified_email')

        self.is_friend = data.get('is_friend')
        self.is_gold = data.get('is_gold')
        self.is_mod = data.get('is_mod')

        self.over_18 = data.get('over_18')

        validate_object(self, data)

    def get_overview(self):
        pass

    def get_comments(self):
        return Listing(self._reddit, Account.URL_COMMENTS % self.name)

    def get_posts(self):
        pass

    def get_subscribed_subreddits(self):
        pass

class Link(Content):
    prefix = 't3'

    def __init__(self, reddit, json):
        super(Link, self).__init__(json)

        self._reddit = reddit
        data = json['data']

        self.title = data.get('title')
        self.url = data.get('url')
        self.domain = data.get('domain')
        self.thumbnail = data.get('thumbnail')

        self.link_flair_css_class = data.get('link_flair_css_class')
        self.link_flair_text = data.get('link_flair_text')

        self.stickied = data.get('stickied')
        self.clicked = data.get('clicked')
        self.visited = data.get('visited')
        self.is_self = data.get('is_self')
        self.over_18 = data.get('over_18')
        self.hidden = data.get('hidden')

        self.selftext = data.get('selftext')
        self.selftext_html = html_unescape(data['selftext_html']) if data.get('selftext_html') else None

        self.score = data.get('score')

        self.num_comments = data.get('num_comments')

        self.media = data.get('media')
        self.media_embed = data.get('media_embed')

        self.secure_media = data.get('secure_media')
        self.secure_media_embed = data.get('secure_media_embed')

        self.permalink = 'http://%s%s' % (self._reddit.domain, data.get('permalink'))

        validate_object(self, data)

class Subreddit(Thing):
    prefix = 't5'

    def __init__(self, reddit, json):
        super(Subreddit, self).__init__(json)

        self._reddit = reddit
        data = json['data']

        self.title = data.get('title')
        self.display_name = data.get('display_name')

        self.url = data.get('url')

        self.created = datetime.fromtimestamp(data.get('created'))
        self.created_utc = datetime.utcfromtimestamp(data.get('created_utc'))

        self.subscribers = data.get('subscribers')
        self.accounts_active = data.get('accounts_active')

        self.header_img = data.get('header_img')
        self.header_size = data.get('header_size')
        self.header_title = data.get('header_title')

        self.submit_text = data.get('submit_text')
        self.submit_text_html = html_unescape(data.get('submit_text_html'))
        self.submit_text_label = data.get('submit_text_label')
        self.submit_link_label = data.get('submit_link_label')

        self.description = data.get('description')
        self.description_html = html_unescape(data.get('description_html'))
        self.public_description = data.get('public_description')

        self.user_is_banned = data.get('user_is_banned')
        self.user_is_moderator = data.get('user_is_moderator')
        self.user_is_subscriber = data.get('user_is_subscriber')
        self.user_is_contributor = data.get('user_is_contributor')

        self.over18 = data.get('over18')
        self.public_traffic = data.get('public_traffic')
        self.subreddit_type = data.get('subreddit_type')
        self.submission_type = data.get('submission_type')
        self.comment_score_hide_mins = data.get('comment_score_hide_mins')

        validate_object(self, data)

class Listing(object):
    def __init__(self, reddit, url):
        self._reddit = reddit
        self._url = url

        self._before = None
        self._after = None
        self._cur_page_index = None
        self._cur_page = None

    def __iter__(self):
        return self

    def __next__(self):
        return self.next()

    def _fetch_next_page(self):
        url = self._url
        if self._after:
            if '?' in url:
                url += '&after=' + self._after
            else:
                url += '?after=' + self._after

        json = self._reddit.request(url)

        if json.get('kind') != 'Listing':
            raise Exception()

        self._parse_page(json)

    def _parse_page(self, json):
        data = json['data']
        children = data['children']

        self._cur_page = []
        for child in children:
            self._cur_page.append(Thing.parse(self._reddit, child))

        self._after = data.get('after')
        self._before = data.get('before')

        self._cur_page_index = 0

    def next(self):
        if not self._cur_page:
            self._fetch_next_page()

        self._cur_page_index += 1

        if self._cur_page_index >= len(self._cur_page):
            if not self._after:
                raise StopIteration()

            self._fetch_next_page()

        return self._cur_page[self._cur_page_index]


#!/usr/bin/env python

from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument("paramFile",help="calculate the FED fragment sizes using the parameters in the given file")
parser.add_argument("relEventSize",type=float,help="scale the event size by this factor")
parser.add_argument("outputFile",help="file name of the output file")
args = vars(parser.parse_args())

eventSize = 0
with open(args['outputFile'],'w') as outputFile:
    outputFile.write("#fedId,size,rms\n")
    with open(args['paramFile']) as paramFile:
        for line in paramFile:
            try:
                (fedIds,a,b,c,rms) = line.split(',',5)
            except ValueError:
                (fedIds,a,b,c,rms,_) = line.split(',',6)
            try:
                for id in fedIds.split('+'):
                    fedSize = float(a)+float(b)*args['relEventSize']+float(c)*args['relEventSize']**2
                    outputFile.write("%d,%d,%d,1\n" % (int(id),int(fedSize)&~0x7,int(fedSize*float(rms))&~0x7))
                    eventSize += int(fedSize)
            except ValueError:
                pass

print("Total event size is %1.3f MB\n" % (float(eventSize)/1000000.))


from ..Commons import *
from ..Language.DataStructure import *
from ..Language.Syntax import *

def post_endo_fiss_prod(self,TABLE,**args) :
    if args.get('__all__'):
        return ([maillage_sdaster], [table_sdaster])
    self.type_sdprod(TABLE,table_sdaster)
    return maillage_sdaster

POST_ENDO_FISS=MACRO(nom="POST_ENDO_FISS",
                     op=OPS('code_aster.MacroCommands.post_endo_fiss_ops.post_endo_fiss_ops'),
                     sd_prod=post_endo_fiss_prod,
                     reentrant='n',
                     fr=tr("Individuation du trace d'une fissure a partir d'un champ scalaire pertinant"),

            TABLE  = SIMP(statut = 'o', typ = CO,),

            regles = (UN_PARMI("RESULTAT","CHAM_GD"),
                      ),
            OUVERTURE  = SIMP(statut = 'f', typ = 'TXM', into=('OUI','NON',), defaut = 'NON' ),
            b_resultat = BLOC(condition  = """exists("RESULTAT")""",
                              regles     = (UN_PARMI('NUME_ORDRE','INST'),),
                              NUME_ORDRE = SIMP(statut = 'f', typ = 'I', validators = NoRepeat(), ),
                              INST       = SIMP(statut = 'f', typ = 'R', validators = NoRepeat(), ),
                              ),

            #b_champ    = BLOC(condition = """exists("CHAM_GD")""",),

            CHAM_GD         = SIMP(statut = 'f',typ = (cham_gd_sdaster)),
            RESULTAT        = SIMP(statut = 'f',typ = (evol_noli)),
            NOM_CMP         = SIMP(statut = 'o',typ='TXM',),
            NOM_CHAM        = SIMP(statut = 'o', typ = 'TXM',
                                   fr = tr("nom du champ a post-traiter"),),

            RECHERCHE = FACT(statut = 'o',min=1,max='**',
                             regles = (
                                       PRESENT_ABSENT('TOUT','GROUP_MA',),
                                    ),
                              LONG_ORTH  = SIMP(statut='o', typ='R'),
                              NB_POINT   = SIMP(statut='f', typ='I', defaut = 500),
                              PAS        = SIMP(statut='o', typ='R', ),
                              LONG_REG   = SIMP(statut='o', typ='R'),
                              BORNE_MIN  = SIMP(statut='f', typ='R', defaut=0.5),
                              ANGL_MAX   = SIMP(statut='f', typ='R', defaut=120.),
                              TOUT       = SIMP(statut='f', typ='TXM', into=('OUI',) ),
                              GROUP_MA   = SIMP(statut='f', typ=grma,  validators=NoRepeat(), ),
                              BORNE_MAX  = SIMP(statut='f', typ='R'),
                              ),
                   )


# Determines input read criterion
from sys import stdin
JUDGE = 0
FILE = 1
INPUT_SRC = FILE
# INPUT_SRC = JUDGE
if INPUT_SRC == FILE:
 inputSrc = open("750.txt", "r")
else:
 inputSrc = stdin

def isSafe(board, row, col):
	for i in range(col):
		if (board[row][i]):
			return False
	i = row
	j = col
	while i >= 0 and j >= 0:
		if(board[i][j]):
			return False
		i -= 1
		j -= 1

	i = row
	j = col
	while j >= 0 and i < 8:
		if(board[i][j]):
			return False
		i = i + 1
		j = j - 1

	return True

def solveNQUtil(board, col):
  if (col == 8):
    v = []
    for i in board:
      for j in range(len(i)):
          if i[j] == 1:
            v.append(j+1)
    result.append(v)
    return True

  res = False
  for l in range(8):
    if (isSafe(board,l , col)):
      board[l][col] = 1
      res = solveNQUtil(board, col + 1) or res
      board[l][col] = 0
  return res

def solveNQ(n):
  result.clear()
  board = [[0 for o in range(n)]for m in range(n)]
  solveNQUtil(board, 0)
  result.sort()
  return result

while True:
  result = []
  inp=inputSrc.readline().strip()
  if len(inp) == 0:
    break
  num_datasets=int(inp)
  print ("SOLN      COLUMN")
  for _ in range(num_datasets):
    inputSrc.readline().strip()
    r,c=list(map(int,inputSrc.readline().strip().split()))
    n = 8
    res = solveNQ(n)
    # print (res)

    print (" #     "+" ".join(str(p+1) for p in range(n)))
    print ()
    cnt=0
    for k in range(len(res)):

      if res[k][0] == r:
        cnt=cnt+1
        print (" "+str(cnt)+"     "+" ".join(str(g) for g in res[k]))

    print ()


#Question: Easy
"""
Given numBottles full water bottles, you can exchange numExchange empty water bottles for one full water bottle.

The operation of drinking a full water bottle turns it into an empty bottle.

Return the maximum number of water bottles you can drink.
"""
import logging

class Solution:
    def numWaterBottles(self, numBottles: int, numExchange: int) -> int:
        total = numBottles
        remainder = 0
        while True:
            temp_numBottles = numBottles
            numBottles = (remainder + numBottles) // numExchange
            total += numBottles
            remainder = temp_numBottles % numExchange
            if (numBottles+remainder) < numExchange:
                break
        return total

if __name__ == "__main__":
    format = '%(asctime)s: %(message)s'
    logging.basicConfig(format=format, level=logging.INFO, datefmt='%H:%M:%S')
    logging.getLogger().setLevel(logging.DEBUG)
    numBottles = 9
    numExchange = 3
    numBottles2 = 15
    numExchange2 = 4
    numBottles3 = 5
    numExchange3 =5
    numBottles4 = 2
    numExchange4 = 3
    numBottles5 = 15
    numExchange5 = 8
    result = Solution()
    logging.info(f'Amount of water drink: {result.numWaterBottles(numBottles2, numExchange2)}')


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def sumEvenGrandparent(self, root: TreeNode) -> int:
        def getSumVal(node, grandparent, parent):
            sum = 0
            if node is None:
                return 0

            if grandparent is not None and grandparent % 2 == 0:
                sum += node.val

            sum += getSumVal(node.left, parent, node.val)
            sum += getSumVal(node.right, parent, node.val)
            return sum

        return getSumVal(root, None, None)


import random
from termcolor import colored
import timeit
import time

def show():
    for i in q:
        for j in i:
            print(j, end=" ")
        print()
    print("**********")

def check_game(lastplayer):
    if (q[0][0]==q[0][1]==q[0][2]!="_" or q[1][0]==q[1][1]==q[1][2]!="_" or q[2][0]==q[2][1]==q[2][2]!="_" or q[0][0]==q[1][0]==q[2][0]!="_" or q[0][1]==q[1][1]==q[2][1]!="_" or q[0][2]==q[1][2]==q[2][2]!="_"  or q[0][0]==q[1][1]==q[2][2]!="_"  or q[0][2]==q[1][1]==q[2][0]!="_"):
        print(lastplayer+"win")
        stop = timeit.default_timer()
        print('Time: ', stop - start)
        exit()
    elif("_" not in str(sum(q, []))):
        print("tie")
        stop = timeit.default_timer()
        print('Time: ', stop - start)
        exit()

def valid(x):
    if x==0 or x==1 or x==2 :
        return 1
    else:
        return 0

playtype = int(input("Another Player: 1 \nComputer: 2"))
start = timeit.default_timer()
q =[["_" for i in range(3)] for j in range(3)]

show()

if playtype==1:
    lastplayer="o"
    while 1:
        if lastplayer=="o":
            x1,y1=map(int,input().split())
            if valid(x1) and valid(y1)and q[x1][y1]=="_" :
                q[x1][y1]=colored("x", "red")
                show()
                lastplayer="x"
                check_game(lastplayer)
            else:
                print("not available chose again")
                continue
        if lastplayer=="x":
            x2,y2=map(int,input().split())
            if valid(x2) and valid(y2) and q[x2][y2]=="_":
                q[x2][y2]=colored("o", "blue")
                show()
                lastplayer="o"
                check_game(lastplayer)
            elif(lastplayer=="x"):
                print("not available chose again")
                continue

else:
    lastplayer="user"
    while 1:
        if lastplayer=="user":
            x2=random.randint(0,2)
            y2=random.randint(0,2)
            if  valid(x2) and valid(y2) and q[x2][y2]=="_" :
                q[x2][y2]=colored("o", "blue")
                time.sleep(2)
                show()
                lastplayer="computer"
                check_game(lastplayer)
            else:
                continue
        if lastplayer=="computer":
            x1,y1=map(int,input().split())
            if  valid(x1) and valid(y1)and q[x1][y1]=="_":
                q[x1][y1]=colored("x", "red")
                show()
                lastplayer="user"
                check_game(lastplayer)
            else:
                print("not available chose again")
            continue

print(q)


import numpy as np
import unittest
import copy
import pathlib

UNIT = 1e-3

MASS_DICT = {
    'K0_S': 497.611 * UNIT,
    'pi+': 139.57018 * UNIT,
    'D0': 1865.84 * UNIT,
    'phi': 1019.461 * UNIT,
    # 'pi0' : 134.9766,
}

def make_hist(data, range=None, nbins=100, density=False):
    if range is None:
        range = (np.min(data), np.max(data))
    dhist, dbins = np.histogram(data, bins=nbins, density=density, range=range)
    dbins = 0.5 * (dbins[1:] + dbins[:-1])
    norm = np.sum(dhist) / data.shape[0]
    errors = np.array([-0.5 + np.sqrt(dhist / norm + 0.25),
                       0.5 + np.sqrt(dhist / norm + 0.25)]) * norm
    return (dbins, dhist, errors)

def gamma(beta):
    """ Lorentz factor """
    return 1. / np.sqrt(1. - beta**2)

def lorentz_boost(lv, bv):
    """ Relativistic transformation """
    beta = np.linalg.norm(bv)
    gam, n = gamma(beta), bv / beta
    t, r = lv[:, 0].reshape(-1, 1), lv[:, 1:]
    return np.column_stack([gam * t - beta * np.dot(r, n.T),
                            r + (gam - 1) * np.dot(r, n.T) * n - gam * t * beta * n])

def energy(mass, p3):
    """ Energy from mass and 3-momentum """
    return np.sqrt(mass**2 + np.sum(p3**2, axis=-1))

def ks2pipi(N, pk=None):
    """ Generator of the Ks0 -> pi+ pi- decays """
    mks, mpi = [MASS_DICT[key] for key in ['K0_S', 'pi+']]
    epi = 0.5*mks
    ppi = np.sqrt(epi**2 - mpi**2)
    costh = 2.*np.random.rand(N) - 1
    phi = 2.*np.random.rand(N)*np.pi
    sinth = np.sqrt(1. - costh**2)
    sinphi, cosphi = np.sin(phi), np.cos(phi)
    p3pip = ppi*np.array([sinth*cosphi, sinth*sinphi, costh]).T

    if pk is not None:
        p4pip, p4pim = [np.empty((p3pip.shape[0], 4)) for _ in range(2)]
        p4pip[:, 0], p4pim[:, 0] = epi, epi
        p4pip[:, 1:], p4pim[:, 1:] = p3pip, -p3pip
        bv = -(pk.reshape(-1, 1) / energy(mks, pk)).T
        p4pip, p4pim = [lorentz_boost(x, bv) for x in [p4pip, p4pim]]
        return (p4pip[:, 1:], p4pim[:, 1:])

    return (p3pip, -p3pip)

def measurement_sampler(p3pip, p3pim, cov):
    """ Samples measurement error """
    assert cov.shape == (3, 3)
    N = p3pip.shape[0]
    dp = np.random.multivariate_normal([0, 0, 0], cov, 2*N)
    p3pip += dp[:N]
    p3pim += dp[N:]
    return (p3pip, p3pim)

def generate(N, cov, ptot=None):
    """ Generates N events for a given covariance matrix """
    p3pip, p3pim = ks2pipi(N, ptot)
    return (measurement_sampler(copy.deepcopy(p3pip), copy.deepcopy(p3pim), cov), p3pip, p3pim)

def generate_decay(cov, ptot=None):
    (p3pip, p3pim), p3pip_mc, p3pim_mc = generate(1, cov, ptot)
    return (p3pip[0], p3pim[0]), p3pip_mc[0], p3pim_mc[0]


import cv2
import numpy as np

# 读取两个图像
image1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)

# 计算两个图像的直方图
hist_1 = cv2.calcHist([image1], [0], None, [256], [0, 256])
hist_2 = cv2.calcHist([image2], [0], None, [256], [0, 256])

# 比较直方图并计算相似度分数
similarity = cv2.compareHist(hist_1, hist_2, cv2.HISTCMP_CORREL)
print(f"Histogram Similarity Score: {similarity}")

import cv2
import numpy as np

# 读取两个图像
image1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)

# 计算结构相似性指数并计算相似度分数
similarity = cv2.compareSSIM(image1, image2, win_size=3)
print(f"SSIM Similarity Score: {similarity}")

import cv2
import numpy as np

# 读取两个图像并提取特征点
image1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)
detector = cv2.SIFT_create()
keypoints1, descriptors1 = detector.detectAndCompute(image1, None)
keypoints2, descriptors2 = detector.detectAndCompute(image2, None)

# 匹配特征点并计算相似度分数
matcher = cv2.BFMatcher()
matches = matcher.knnMatch(descriptors1, descriptors2, k=2)
similarity = len(np.where(np.array(matches[0, :]) < 0)[0]) / len(matches[0, :])
print(f"Feature Matching Similarity Score: {similarity}")

import cv2
import numpy as np

# 读取两个图像
image1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)

# 计算两个图像的平均差异值
mse = np.mean((image1 - image2) ** 2)
print(f"MSE Similarity Score: {mse}")


#!/usr/bin/env python3
import sys
sys.setrecursionlimit(4100000)
import math
def error(*args, end="\n"): print("[stderr]", *args, end=end, file=sys.stderr)
from bisect import bisect, bisect_left, bisect_right
from collections import defaultdict, deque
MOD = 998244353
INF = float("inf")
MINF = -float("inf")

N, K = map(int, input().split())
A = list(map(int, input().split()))
#print(A)

# init
cnt = 0
X = 0
# 周期計算用
d = defaultdict(lambda:-1)
loop_length = 0
loop_sum = 0
loop_times = 0

for ii in range(K):
    # update
    X = cnt % N
#    print("--", X, A[X])
#    if False:
    if d[X] != -1:
        #print("cnt", cnt)
        #print(ii, d[X], X)
        # loop detected
        loop_length = ii - d[X]
        loop_times = (K - d[X]) // loop_length
        loop_times_mod = (K - d[X]) % loop_length
        # loop sum
        tmp_cnt = X
        for jj in range(loop_length):
            tmp_X = tmp_cnt % N
            a = A[tmp_X]
            tmp_cnt += a
        loop_sum = tmp_cnt - X
        # cnt
        #print(loop_length)
        #print(loop_times)
        #print(loop_times_mod)
        #print(loop_sum)
        #print("cnt", cnt)
        cnt += loop_sum * (loop_times-1)
        #print("cnt", cnt)
        # 余り
        tmp_cnt = X
        for jj in range(loop_times_mod):
            tmp_X = tmp_cnt % N
            # add candy
            a = A[tmp_X]
            tmp_cnt += a
        cnt += (tmp_cnt - X)
        break
    else:
        d[X] = ii

    # add candy
    a = A[X]
    cnt += a

print(cnt)


from src.model.avc_trainer import avcNet_generator
import src.features.features_parameters as feat_p
from src.features.utils import *

import torch

from tqdm import tqdm
import argparse
import resampy
import librosa
import inspect
import random
import pickle
import gzip
import sys
import os

import tensorflow as tf
TF_CONFIG_ = tf.ConfigProto()
TF_CONFIG_.gpu_options.allow_growth = True
sess = tf.Session(config = TF_CONFIG_)

def parse_arguments():
    parser = argparse.ArgumentParser(description='Moves data from a single folder to train test folder')
    parser.add_argument('--data-dir',
                        action='store',
                        type=str,
                        help='Path to directory where audio (wav) files are stored')

    parser.add_argument('--trained-model',
                        action='store',
                        type=str,
                        default=None,
                        help='Path to directory where audio (wav) files are stored')

    parser.add_argument('--output-dir',
                        action='store',
                        type=str,
                        help='Path to directory where output files will be stored')

    return parser.parse_args()

def extract_features(model, data_dir, output_dir, limit = -1, is_openl3 = False):
    if(model != None):
        model = model.audioNet
        model.cuda()
        model.eval()
        for par in model.parameters():
             par.requires_grad = False

    file_list = os.listdir(data_dir)
    # audio_file_list = [audio_file_list[i].split('.')[:-1][0] for i in range(len(audio_file_list))]

    if limit == -1:
        limit = len(file_list)

    audioSignal_folds = {'1': [], '2': [], '3': [], '4': [], '5': []}
    classLabel_folds = {'1': [], '2': [], '3': [], '4': [], '5': []}
    for i in tqdm(range(len(file_list))):

        audio_path = os.path.join(data_dir, file_list[i])

        audioSignal, sr = sf.read(audio_path, dtype='int16', always_2d=True)
        audioSignal = audioSignal.mean(axis=-1).astype('int16')
        audioSignal = resampy.resample(audioSignal, sr, 48000)

        if(not is_openl3):
            spectrograms = audio_feat(audioSignal, 48000)

            spectrograms = torch.from_numpy(spectrograms)
            spectrograms = spectrograms.to("cuda")

            features = model.forward(spectrograms)
            features = features.cpu().numpy()

        basename = file_list[i].split('.')[0]
        class_label = int(basename.split('-')[-1])

        if(not is_openl3):
            with open(os.path.join(output_dir, 'fold' + basename.split('-')[0], basename + '.pkl'), 'wb') as f:
                pickle.dump((features, class_label), f)

        if(is_openl3):
            # Creating audio list to avoid GPU memory overflow while inferencing
            audioSignal_folds[basename.split('-')[0]].append(audioSignal)
            classLabel_folds[basename.split('-')[0]].append(class_label)

    if(is_openl3):
        for fold in range(5):   #iterate in folds
            spectrograms_openL3 = audio_feat(audioSignal_folds[str(fold + 1)], 48000, is_openl3=is_openl3)
            for x, sample in enumerate(spectrograms_openL3):
                with open(os.path.join(output_dir, 'fold{}'.format(fold + 1), '{}.pkl'.format(x)), 'wb') as f:
                    pickle.dump((sample, classLabel_folds[str(fold + 1)][x]), f)

if __name__ == "__main__":
    args = parse_arguments()

    if(not args.trained_model == None):
        avcModel = avcNet_generator()
        avcModel.load_state_dict(torch.load(args.trained_model))
        is_openl3 = False
    else:
        avcModel = None
        is_openl3 = True

    for i in range(1, 6):
        os.makedirs(os.path.join(args.output_dir, 'fold' + str(i)), exist_ok=True)

    extract_features(avcModel, args.data_dir, args.output_dir, limit = feat_p.ESC_limit, is_openl3 = is_openl3)


import argparse

def str2bool(v):
    return v.lower() in ("true", "1")

arg_lists = []
parser = argparse.ArgumentParser()

def add_argument_group(name):
    arg = parser.add_argument_group(name)
    arg_lists.append(arg)
    return arg

# -----------------------------------------------------------------------------
# Network
net_arg = add_argument_group("Network")
net_arg.add_argument(
    "--net_depth", type=int, default=12, help=""
    "number of layers. Default: 12")
net_arg.add_argument(
    "--clusters", type=int, default=500, help=""
    "cluster number in OANet. Default: 500")
net_arg.add_argument(
    "--iter_num", type=int, default=1, help=""
    "iteration number in the iterative network. Default: 1")
net_arg.add_argument(
    "--net_channels", type=int, default=128, help=""
    "number of channels in a layer. Default: 128")
net_arg.add_argument(
    "--use_fundamental", type=str2bool, default=False, help=""
    "train fundamental matrix estimation. Default: False")
net_arg.add_argument(
    "--share", type=str2bool, default=False, help=""
    "share the parameter in iterative network. Default: False")
net_arg.add_argument(
    "--use_ratio", type=int, default=0, help=""
    "use ratio test. 0: not use, 1: use before network, 2: use as side information. Default: 0")
net_arg.add_argument(
    "--use_mutual", type=int, default=0, help=""
    "use matual nearest neighbor check. 0: not use, 1: use before network, 2: use as side information. Default: 0")
net_arg.add_argument(
    "--ratio_test_th", type=float, default=0.8, help=""
    "ratio test threshold. Default: 0.8")

# -----------------------------------------------------------------------------
# Data
data_arg = add_argument_group("Data")
data_arg.add_argument(
    "--data_tr", type=str, default='../data_dump/yfcc-sift-2000-train.hdf5', help=""
    "name of the dataset for train")
data_arg.add_argument(
    "--data_va", type=str, default='../data_dump/yfcc-sift-2000-val.hdf5', help=""
    "name of the dataset for valid")
data_arg.add_argument(
    "--data_te", type=str, default='../data_dump/yfcc-sift-2000-test.hdf5', help=""
    "name of the unseen dataset for test")

# -----------------------------------------------------------------------------
# Objective
obj_arg = add_argument_group("obj")
obj_arg.add_argument(
    "--obj_num_kp", type=int, default=2000, help=""
    "number of keypoints per image")
obj_arg.add_argument(
    "--obj_top_k", type=int, default=-1, help=""
    "number of keypoints above the threshold to use for "
    "essential matrix estimation. put -1 to use all. ")
obj_arg.add_argument(
    "--obj_geod_type", type=str, default="episym",
    choices=["sampson", "episqr", "episym"], help=""
    "type of geodesic distance")
obj_arg.add_argument(
    "--obj_geod_th", type=float, default=1e-4, help=""
    "theshold for the good geodesic distance")

# -----------------------------------------------------------------------------
# Loss
loss_arg = add_argument_group("loss")
loss_arg.add_argument(
    "--weight_decay", type=float, default=0, help=""
    "l2 decay")
loss_arg.add_argument(
    "--momentum", type=float, default=0.9, help=""
    "momentum")
loss_arg.add_argument(
    "--loss_classif", type=float, default=1.0, help=""
    "weight of the classification loss")
loss_arg.add_argument(
    "--loss_essential", type=float, default=0.5, help=""
    "weight of the essential loss")
loss_arg.add_argument(
    "--loss_essential_init_iter", type=int, default=20000, help=""
    "initial iterations to run only the classification loss")
loss_arg.add_argument(
    "--geo_loss_margin", type=float, default=0.1, help=""
    "clamping margin in geometry loss")

# -----------------------------------------------------------------------------
# Training
train_arg = add_argument_group("Train")
train_arg.add_argument(
    "--run_mode", type=str, default="train", help=""
    "run_mode")
train_arg.add_argument(
    "--train_lr", type=float, default=1e-3, help=""
    "learning rate")
train_arg.add_argument(
    "--train_batch_size", type=int, default=32, help=""
    "batch size")
train_arg.add_argument(
    "--gpu_id", type=str, default='0', help='id(s) for CUDA_VISIBLE_DEVICES')
train_arg.add_argument(
    "--num_processor", type=int, default=8, help='numbers of used cpu')
train_arg.add_argument(
    "--train_iter", type=int, default=500000, help=""
    "training iterations to perform")
train_arg.add_argument(
    "--log_base", type=str, default="./log/", help=""
    "save directory name inside results")
train_arg.add_argument(
    "--log_suffix", type=str, default="", help=""
    "suffix of log dir")
train_arg.add_argument(
    "--val_intv", type=int, default=10000, help=""
    "validation interval")
train_arg.add_argument(
    "--save_intv", type=int, default=1000, help=""
    "summary interval")

# -----------------------------------------------------------------------------
# Testing
test_arg = add_argument_group("Test")
test_arg.add_argument(
    "--use_ransac", type=str2bool, default=True, help=""
    "use ransac when testing?")
test_arg.add_argument(
    "--model_path", type=str, default="", help=""
    "saved best model path for test")
test_arg.add_argument(
    "--res_path", type=str, default="", help=""
    "path for saving results")

# -----------------------------------------------------------------------------
# Visualization
vis_arg = add_argument_group('Visualization')
vis_arg.add_argument(
    "--tqdm_width", type=int, default=79, help=""
    "width of the tqdm bar"
)

def get_config():
    config, unparsed = parser.parse_known_args()
    return config, unparsed

def print_usage():
    parser.print_usage()

#
# config.py ends here


#!/usr/bin/env python

import pickle
import argparse
from tqdm import tqdm
import numpy as np
from numpy.random import permutation

import matplotlib
matplotlib.use('agg')

import torch
torch.manual_seed(1)  # cpu
torch.cuda.manual_seed(1)  # gpu
np.random.seed(1)  # numpy
torch.backends.cudnn.deterministic = True  # cudnn

from model import AspectMemoryEncoder, OrthogonalityLoss
from data_utils import batch_generator, batch_test_generator, load_aspects
from utils import evaluate

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "1"

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('data', help="Dataset name (without extension)", type=str)
    parser.add_argument('--test_data', help="pkl file for test", type=str, default='')
    parser.add_argument('--dev_data', help="pkl file for train", type=str, default='')
    parser.add_argument('--domain', help="domain of the review data", type=str, default='')
    parser.add_argument('--min_len', help="Minimum number of non-stop-words in segment (default: 2)", type=int,
                        default=2)
    parser.add_argument('--aspects', help="Number of aspects (default: 10)", type=int, default=10)
    parser.add_argument('--extend_aspects', help="Number of aspects to be extended (default: 0)", type=int, default=0)
    parser.add_argument('--aspect_seeds', help='file that contains aspect seed words (overrides number of aspects)',
                        type=str, default='')
    parser.add_argument('--epochs', help="Number of epochs (default: 15)", type=int, default=15)
    parser.add_argument('--lr', help="Learning rate (default: 0.001)", type=float, default=0.001)
    parser.add_argument('--l', help="Orthogonality loss coefficient (default: 100)", type=float, default=100)
    parser.add_argument('-q', '--quiet', help="No information to stdout", action='store_true')
    args = parser.parse_args()

    if not args.quiet:
        print('Loading data...')

    # load tow dicts
    id2word = {}
    word2id = {}
    with open(args.data + '_word_mapping.txt', 'r') as fvoc:
        for line in fvoc:
            word, id = line.split()
            id2word[int(id)] = word
            word2id[word] = int(id)

    with open(args.data + '.pkl', 'rb') as frb:
        dataset = pickle.load(frb)

    w_emb_array = dataset['w2v']
    w_emb = torch.from_numpy(w_emb_array)
    vocab_size, emb_size = w_emb.size()

    with open(args.test_data + '.pkl', 'rb') as frb:
        dataset_test = pickle.load(frb)
    with open(args.dev_data + '.pkl', 'rb') as frb:
        dataset_dev = pickle.load(frb)

    a_emb = load_aspects(args.aspect_seeds, word2id, w_emb_array)
    args.aspects = a_emb.shape[0]
    print("Overwrite the number of aspects as {}".format(args.aspects))

    if not args.quiet:
        print('Building model..')

    net = AspectMemoryEncoder(vocab_size, emb_size, w_emb=w_emb, a_emb=torch.from_numpy(a_emb), extend_aspect=args.extend_aspects)
    if torch.cuda.is_available():
        net = net.cuda()

    orth_loss = OrthogonalityLoss()
    if args.extend_aspects:
        params = filter(lambda p: p.requires_grad, net.parameters())
        optimizer = torch.optim.Adam(params, lr=args.lr)

    if not args.quiet:
        print('Starting training...')
    dev_perf, test_perf = 0, 0

    if not args.extend_aspects:
        args.epochs = 1

    for epoch in range(args.epochs):

        if args.extend_aspects:
            # model training
            net.train()
            if not args.quiet:
                print('Epoch {}'.format(epoch + 1))
            epoch_loss = {'prob_loss': 0, 'orth_loss': 0}

            # generate the batches
            batch_size = 300
            num_batches_per_epoch = int((len(dataset['data']) - 1) / batch_size) + 1
            batched_data = batch_generator(dataset, batch_size)

            with tqdm(total=num_batches_per_epoch) as pbar:
                for inputs, _ in batched_data:
                    pbar.update(1)
                    if inputs.shape[1] < args.min_len:
                        continue
                    if torch.cuda.is_available():
                        inputs = inputs.cuda()

                    enc_out, attention = net(inputs)
                    a_probs = net.predict_by_aspect(enc_out)
                    if a_probs.size(0) > 0:
                        pred_prob, pred_label = a_probs.max(-1)
                        loss = -torch.logsumexp(a_probs, dim=1).sum()
                    epoch_loss['prob_loss'] -= loss.item()

                    aspects = net.get_aspects()
                    orth_loss_asp = args.l * orth_loss(aspects)
                    epoch_loss['orth_loss'] += orth_loss_asp.item()
                    loss += orth_loss_asp

                    optimizer.zero_grad()
                    loss.backward()
                    optimizer.step()

            print('Train Epoch: {} Prob Loss: {:.6f} Orth Loss: {:.6f}'.format(
                epoch, epoch_loss['prob_loss'], epoch_loss['orth_loss']))

        # model eval
        net.eval()

        batch_size = 100
        num_batches_per_epoch = int((len(dataset_dev['data']) - 1) / batch_size) + 1
        batched_data = batch_test_generator(dataset_dev, batch_size)
        true_labels_dev, pred_labels_dev = dataset_dev['labels'], []  # true labels: list of list

        for inputs in batched_data:
            if torch.cuda.is_available():
                inputs = inputs.cuda()
            with torch.no_grad():
                enc_out, attention = net(inputs)
                a_probs = net.predict_by_aspect(enc_out)
            if a_probs.size(0) > 0:
                pred_prob, pred_label = a_probs.max(-1)
                pred_labels_dev.append(pred_label.data.cpu().numpy())

        pred_labels_dev = np.concatenate(pred_labels_dev, axis=0)
        f1 = evaluate(true_labels_dev, pred_labels_dev, args.domain, 'multi_label')
        if f1 > dev_perf:
            dev_perf = f1
            print('New best f_1 on dev: {}'.format(dev_perf))

            batch_size = 100
            num_batches_per_epoch = int((len(dataset_test['data']) - 1) / batch_size) + 1

            batched_data = batch_test_generator(dataset_test, batch_size)
            true_labels_test, pred_labels_test = dataset_test['labels'], []  # true labels: list of list

            for inputs in batched_data:
                if torch.cuda.is_available():
                    inputs = inputs.cuda()
                with torch.no_grad():
                    enc_out, attention = net(inputs)
                    a_probs = net.predict_by_aspect(enc_out)
                if a_probs.size(0) > 0:
                    pred_prob, pred_label = a_probs.max(-1)
                    pred_labels_test.append(pred_label.data.cpu().numpy())

            pred_labels_test = np.concatenate(pred_labels_test, axis=0)
            test_perf = evaluate(true_labels_test, pred_labels_test, args.domain, 'multi_label')
            print("Micro f_1 scores on test: {}".format(test_perf))

    print("Final f_1 scores on test: {}".format(test_perf))


import time
import json
from datetime import date, datetime, timedelta

import random

# import requests
# import urllib
import useragents
import proxies

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.proxy import Proxy, ProxyType
from selenium.webdriver.common.keys import Keys

__author__ = 'Gautham Kolluru'

START_DATE = date.today()-timedelta(days=1)

# Json File Name
JFN = "navigation.json"
# JFN = "navigation1.json"

def read_json(fn):
    with open(fn) as fp:
        # file info
        fi = json.load(fp)
    return fi

def read_date_from_string(string_date):
    return datetime.strptime(string_date, "%m-%d-%Y").date()

def get_no_of_days(start_date, end_date):
    return (end_date - start_date).days

def get_dates(start_date=START_DATE, end_date=date.today()):
    while get_no_of_days(start_date, end_date) > 31:
        yield start_date, start_date + timedelta(days=31)
        start_date += timedelta(days=31)
    yield start_date, end_date

def select_from_dropdown(driver, dropdown_id="", dropdown_name="", option_name=""):
    if dropdown_id:
        dd = driver.find_element_by_id(dropdown_id)
    elif dropdown_name:
        dd = driver.find_element_by_name(dropdown_name)
    else:
        return False
    for option in dd.find_elements_by_tag_name('option'):
        if option.text.strip().upper() == option_name.upper():
            option.click()  # select() in earlier versions of webdriver
            time.sleep(5)
            return True
    return False

def finding_element(driver, name):
    return driver.find_element_by_name(name)

def select_value(el, value):
    for option in el.find_elements_by_tag_name('option'):
        if option.text.strip().lower() == value.lower():
            option.click()  # select() in earlier versions of webdriver
            time.sleep(5)
            return True
    return False

def write_value(el, value):
    el.clear()
    el.send_keys(value)
    return True

def click_button(el):
    return el.click()

def get_element(driver, name="", element_id="", tag_name="", type_name="", class_name="", xpath="", multiple=False):
    if multiple:
        if name:
            return driver.find_elements_by_name(name)
        elif class_name:
            return driver.find_elements_by_class_name(class_name)
        elif element_id:
            return driver.find_elements_by_id(element_id)
        elif tag_name:
            return driver.find_elements_by_tag_name(tag_name)
        elif xpath:
            return driver.find_elements_by_xpath(xpath)

    else:
        if name:
            return driver.find_element_by_name(name)
        elif class_name:
            return driver.find_element_by_class_name(class_name)
        elif element_id:
            return driver.find_element_by_id(element_id)
        elif tag_name:
            return driver.find_element_by_tag_name(tag_name)
        elif xpath:
            return driver.find_element_by_xpath(xpath)
    return False

def set_value(driver, name="", element_id="", tag_name="", type_name="", class_name="", xpath="", value="", multiple=False, additional_specifier=""):
    el = get_element(driver,
                     name=name,
                     element_id=element_id,
                     tag_name=tag_name,
                     type_name=type_name,
                     class_name=class_name,
                     xpath=xpath,
                     multiple=multiple,
                     )

    print(el.tag_name)
    print(el.text)

    if "select" in el.tag_name.lower():
        return select_value(el, value)

    elif "input" in el.tag_name.lower():
        for start_date, end_date in get_dates():
            break
        print(start_date, end_date)
        if additional_specifier:
            if additional_specifier == "from day":
                value = start_date.day
            elif additional_specifier == "from month":
                value = start_date.month
            elif additional_specifier == "from year":
                value = start_date.year
            elif additional_specifier == "to day":
                value = end_date.day
            elif additional_specifier == "to month":
                value = end_date.month
            elif additional_specifier == "to year":
                value = end_date.year
        return write_value(el, value)

    elif "button" in el.tag_name.lower():
        return click_button(el)

    time.sleep(5)

    return True

def sort_dict_values(d) -> list:
    return [v for k, v in sorted(d.items())]

def get_proxy_capabilities(proxy):
    p = Proxy()
    p.proxy_type = ProxyType.MANUAL
    p.http_proxy = proxy
    capabilities = webdriver.DesiredCapabilities.CHROME
    return p.add_to_capabilities(capabilities)

def get_driver(capabilities=None):
    return webdriver.Chrome(desired_capabilities=capabilities)

def main():
    try:
        jd = read_json(JFN)
        if jd:
            url = jd["url"]
            steps = sort_dict_values(jd["steps"])

            access_to_site = False

            i = 0

            while not access_to_site:
                proxy = proxies.getProxy()
                opts = Options()
                opts.add_argument(
                    "user-agent=[{}]".format(useragents.getUserAgent()))
                driver = webdriver.Chrome(
                    desired_capabilities=get_proxy_capabilities(proxy), options=opts)
                driver.get(url)
                if 'notice' not in driver.title.strip().lower():
                    access_to_site = True
                else:
                    print("i = ", i)
                    driver.close()
                if i > 99:
                    break
                i += 1

            print("access to site", access_to_site)
            print("proxy : ", proxy)

            exit(0)

            # driver = get_driver()
            driver.get(url)

            print(driver.title)

            for step in steps:

                set_value(
                    driver=driver,
                    name=step["name"],
                    element_id=step["element_id"],
                    tag_name=step["tag_name"],
                    type_name=step["type_name"],
                    class_name=step["class_name"],
                    xpath=step["xpath"],
                    value=step["value"],
                    multiple=step["multiple"]
                )

    except Exception as e:
        print(e, e.with_traceback())
    finally:
        driver.close()
    return True

main()

# def is_blocked(url, proxyDict={}):
#     print("checking proxy in 'is_blocked' ", proxyDict)
#     print(url, proxyDict, 200 <= requests.get(
#         url=url, proxies=proxyDict).status_code < 300)
#     return 200 <= requests.get(url=url, proxies=proxyDict).status_code < 300


#!/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
#*******************************************************************************


import logging

from odoo import SUPERUSER_ID, api

_logger = logging.getLogger(__name__)

def post_init_hook(cr, registry):
    with api.Environment.manage():
        env = api.Environment(cr, SUPERUSER_ID, {})
        # ACTION 1: Match existing contacts
        contact_model = env["mailing.contact"]
        partner_model = env["res.partner"]
        contacts = contact_model.search([("email", "!=", False)])
        _logger.info("Trying to match %d contacts to partner by email", len(contacts))
        for contact in contacts:
            partners = partner_model.search(
                [("email", "=ilike", contact.email)], limit=1
            )
            if partners:
                contact.write({"partner_id": partners.id})
        # ACTION 2: Match existing statistics
        stat_model = env["mailing.trace"]
        stats = stat_model.search([("model", "!=", False), ("res_id", "!=", False)])
        _logger.info("Trying to link %d mass mailing statistics to partner", len(stats))
        stats.partner_link()