# Показать первую цифру дробной части числа
N = float(input('N = '))
X = N * 10
X = X // 1
while X >= 10:
    X = round(X - 10)
print(X)

# def drob(N):
#     X = N * 10
#     X = X // 1
#     while X >= 10:
#         X = round(X - 10)
#     return X

# W = float(input('W = '))

# print(drob(W))


import math
import numpy as np

class Player():
    def __init__(self):
        self.score = 0
        self.history = []

    def choice_after_mistake(self,initial_choice,M):
        p = np.random.uniform(0,1)
        #print(p)
        if p > M :
            mistake = False
        else :
            mistake = True

        if mistake == False:
            final_choice = initial_choice
        elif (mistake == True) and initial_choice=="0":
            final_choice = "1"
        elif (mistake == True) and initial_choice=="1":
            final_choice = "0"
        return final_choice

    def update_history(self,choice_made):
        self.history.append(choice_made)

    def update_score(self,binary_result,PayOff):
        if binary_result == "00":
            result = 0
        elif binary_result == "01":
            result = 1
        elif binary_result == "10":
            result = 2
        elif binary_result == "11":
            result = 3
        else :
            print("ERROR!!")
            exit()
        self.score+=PayOff[result]

# All Cheat
class CH(Player):
    def __init__(self):
        Player.__init__(self)

    def make_choice(self,own_history,opponent_history,M):
        choice = "0"
        final_choice = self.choice_after_mistake(choice,M)
        return final_choice

# All Co-operate
class CO(Player):
    def __init__(self):
        Player.__init__(self)

    def make_choice(self,own_history,opponent_history,M):
        choice = "1"
        final_choice = self.choice_after_mistake(choice,M)
        return final_choice

# Random Player
class R(Player):
    def __init__(self):
        Player.__init__(self)

    def make_choice(self,own_history,opponent_history,M):
        choice = str(math.floor(np.random.uniform(0,1)/0.5))
        final_choice = self.choice_after_mistake(choice,M)
        return final_choice

# Copycat
class CC(Player):
    def __init__(self):
        Player.__init__(self)

    def make_choice(self,own_history,opponent_history,M):
        if (len(opponent_history)==0):
            choice =  "1"
        else :
            choice = opponent_history[-1]

        final_choice = self.choice_after_mistake(choice,M)
        return final_choice

# CopyKitten
class CK(Player):
    def __init__(self):
        Player.__init__(self)

    def make_choice(self,own_history,opponent_history,M):
        if (len(opponent_history)==0) or (len(opponent_history)==1):
            choice =  "1"
        else :
            if ((opponent_history[-1]=="0") and (opponent_history[-2]=="0")):
                choice = "0"
            else :
                choice = "1"

        final_choice = self.choice_after_mistake(choice,M)
        return final_choice

# Grudger
class GR(Player):
    def __init__(self):
        Player.__init__(self)

    def make_choice(self,own_history,opponent_history,M):
        if (len(opponent_history)==0):
            choice =  "1"
        elif ("0" in opponent_history) :
            choice = "0"
        else :
            choice = "1"

        final_choice = self.choice_after_mistake(choice,M)
        return final_choice

# Simpleton
class ST(Player):
    def __init__(self):
        Player.__init__(self)

    def make_choice(self,own_history,opponent_history,M):
        if (len(opponent_history)==0):
            choice =  "1"
        else:
            if (opponent_history[-1] == "1"):
                choice = own_history[-1]
            elif (opponent_history[-1] == "0") :
                if (own_history[-1] == "0"):
                    choice = "1"
                elif (own_history[-1] == "1"):
                    choice = "0"

        final_choice = self.choice_after_mistake(choice,M)
        return final_choice

# Detective
class DE(Player):
    def __init__(self):
        Player.__init__(self)

    def make_choice(self,own_history,opponent_history,M):
        if (len(opponent_history)<=3):
            if (len(opponent_history)==1):
                choice = "0"
            else :
                choice = "1"
        elif ("0" in opponent_history[0:4]) :
            choice = opponent_history[-1]
        else :
            choice = "0"

        final_choice = self.choice_after_mistake(choice,M)
        return final_choice


#!/usr/bin/env python3

from __future__ import print_function, division, absolute_import
from os import path

import docopt
import sys
import screed

__author__ = "lteasnail"

CLI_ARGS = """
USAGE:
alignment_summerise.py [options]

OPTIONS:
 -t STRING        String to count

counts the number of each base pair
"""

def GC_caluator(filename):
    GC_dict = {}
    for seq in screed.open(filename):
        seq_name = seq.name
        seq = seq.sequence
        length = len(seq)
        base_count = {}
        for base in seq:
            base_count[base] = base_count.get(base, 0) + 1
        parp = base_count['C'] + base_count['G']
        GC_content = parp/length
        GC_dict[seq_name] = GC_content
    return GC_dict

# If I am being run as a script...
if __name__ == '__main__':
    opts = docopt.docopt(CLI_ARGS)
    fasta_file = opts['-t']
    GC_diction = GC_caluator(fasta_file)
    max_GC = 0
    max_name = ''
    for key in GC_diction:
        if GC_diction[key] > max_GC:
            max_GC = GC_diction[key]
            max_name = key
    max_GC = GC_diction[max_name] * 100
    print("{} {}".format(max_name, max_GC), file=sys.stderr)


import sys
sys.path.extend([
    "./",
])

import os
import torch
from tqdm import tqdm
import time
import numpy as np
import argparse
import umap
import yaml
import json
import pandas as pd
import re
import plotly.express as px
import seaborn as sns
import matplotlib.pyplot as plt

import src.custom_metrics.preparation as pp
from src.general_utils import util_data
from src.general_utils import util_path
from src.custom_metrics import features
from src.general_utils import util_general
from src.general_utils import util_reports

from src.data_util import Dataset_

def get_parser():

    parser = argparse.ArgumentParser()

    parser.add_argument("-cfg", "--cfg_file", type=str, default="./src/configs/")
    parser.add_argument('--source_dir', type=str, default='./reports/pneumoniamnist', help='Directory name to fake samples.') #/home/lorenzo/GAN-Ensembles/reports/
    parser.add_argument('--dataset_name', type=str, default='pneumoniamnist', choices=['pneumoniamnist'],  help='The name of dataset')
    parser.add_argument('--gpu_ids', type=str, default='1', help='gpu ids: e.g. 0  use -1 for CPU')
    parser.add_argument('--batch_size', type=int, default='64', help='Batch size')
    parser.add_argument('--gan_models', type=util_general.parse_comma_separated_list, default='ACGAN-Mod-ADC,SAGAN,ReACGAN-ADA', help='List of GANs to enable in the ensemble')
    parser.add_argument('--gan_steps', type=util_general.parse_comma_separated_list, default='100000', help='Iter or Iters to sample each GAN')
    parser.add_argument('--gan_steps_ensemble', type=util_general.parse_comma_separated_list, default='100000', help='Iter or Iters to sample each GAN')
    parser.add_argument('--gan_models_ensemble', type=util_general.parse_comma_separated_list, default='ACGAN-Mod-ADC,SAGAN', help='List of GANs to enable in the ensemble')
    parser.add_argument('--gan_steps_ensemble', type=util_general.parse_comma_separated_list, default='100000', help='Iter or Iters to sample each GAN')
    parser.add_argument('--gan_models_steps_ensemble', type=util_general.parse_comma_separated_list, default=None, help='Combinations models_steps.')
    parser.add_argument("--post_resizer", type=str, default="friendly", help="which resizer will you use to evaluate GANs in ['legacy', 'clean', 'friendly']")
    parser.add_argument('--eval_backbone', type=str, default='ResNet50_torch', help="[InceptionV3_torch, ResNet50_torch, SwAV_torch, resnet_ae_50_pneumoniamnist, disc_resnet_50_pneumoniamnist, cnn_resnet_50_pneumoniamnist")
    parser.add_argument('--n_samples', type=int, default='50000',  help='Total number of images generated by the ensemble.')
    parser.add_argument('--split', type=str, default='train', choices=['train', 'val'])

    return parser

# main
if __name__ == "__main__":

    parser = get_parser()
    args, unknown = parser.parse_known_args()

    with open(args.cfg_file) as file:
        cfg = yaml.load(file, Loader=yaml.FullLoader)

    # Directories.
    split= args.split
    source_dir = args.source_dir
    dataset_name = args.dataset_name
    samples_dir = os.path.join(source_dir, 'samples')
    cache_dir = os.path.join(source_dir, 'features')
    reports_dir = os.path.join(source_dir, 'umap_embeddings')
    util_path.create_dir(reports_dir)

    # Parameters.
    eval_backbone= args.eval_backbone
    post_resizer= args.post_resizer
    n_samples = args.n_samples
    batch_size = args.batch_size
    n_max_dim_red = np.inf

    # Device.
    gpu_ids = int(args.gpu_ids)
    print(f'gpu_ids: {gpu_ids}')

    if gpu_ids >= 0:
        # Check if available.
        if not torch.cuda.is_available():
            raise ValueError('GPU specified but not available.')
        device = torch.device('cuda:{}'.format(gpu_ids))
    else:
        device = torch.device('cpu')

    # GANs
    gan_models_steps = args.gan_models_steps
    if len(gan_models_steps) != 0:
        gan_models = [x.split('_')[0] for x in gan_models_steps]
        gan_steps = [x.split('_')[1] for x in gan_models_steps]
    else:
        gan_models = args.gan_models
        gan_steps = args.gan_steps
    gan_models_steps_ensemble = args.gan_models_steps_ensemble
    if len(gan_models_steps) != 0:
        gan_models_ensemble = [x.split('_')[0] for x in gan_models_steps_ensemble]
        gan_steps_ensemble = [x.split('_')[1] for x in gan_models_steps_ensemble]
    else:
        gan_models_ensemble = args.gan_models_ensemble
        gan_steps_ensemble = args.gan_steps_ensemble
    gan_aval = os.listdir(samples_dir)
    filename = f'umap_{split}_{eval_backbone}_{post_resizer}_{n_samples}'

    # Create the entire path for each gan.
    gan_folders = [os.path.join(root_dir, x, f'fake__{split}') for x in gan_aval if any(f'{gan_model}-train-' in x for gan_model in gan_models)]
    gan_folders = [os.path.join(x, f"step={y}") for x in gan_folders for y in gan_steps]

    gan_folders_ensemble = [os.path.join(samples_dir, x, 'fake') for x in gan_aval if any(y in x for y in gan_models_ensemble)]
    gan_folders_ensemble = [os.path.join(x, f"step={y}") for x in gan_folders_ensemble for y in gan_steps_ensemble]

    eval_model = pp.LoadEvalModel(
        eval_backbone=eval_backbone,
        post_resizer=post_resizer,
        device=device
    )
    tot_comb = len(gan_folders)

    real_dataset = Dataset_(data_name=cfg['DATA']['name'],
                            data_dir=cfg['DATA']['data_dir'],
                            train=True if split == 'train' else False,
                            crop_long_edge=cfg['PRE']['crop_long_edge'],
                            resize_size=cfg['PRE']['resize_size'],
                            resizer=cfg['PRE']['pre_resizer'],
                            random_flip=cfg['PRE']['apply_rflip'],
                            normalize=cfg['PRE']['normalize'],
                            cfgs=cfg)
    n_max_dim_red = min(n_max_dim_red, len(real_dataset))  # take the minimum between n_max_dim_red and the length of real dataset

    real_loader = torch.utils.data.DataLoader(real_dataset, batch_size=batch_size, shuffle=False)

    # real
    print('Load feature real.')
    stats1 = features.compute_feature(
        dataloader=real_loader,
        eval_model=eval_model,
        batch_size=batch_size,
        quantize=True,
        device=device,
        cache_dir=cache_dir + f'/real_{split}',
        capture_all=True,
        capture_mean_cov=True
    )
    feat_real = stats1.get_all()

    # Main cycle.
    feat_all = []
    y_all = []
    feat_all.append(feat_real)
    y_all.append(np.zeros(feat_real.shape[0], dtype=int))
    gan_names = {
       'real': 0
    }

    # Compute features for all possible GANs.
    with tqdm(total=tot_comb) as pbar:
        for idx, gan_sel in enumerate(gan_folders):

            print("\n")
            print(gan_sel)

            tik = time.time()
            # Dataset
            gan0_dataset = util_data.EnsembleDataset(folders=[gan_sel], weights=[1.0])

            # Dataloder
            dataloader0 = torch.utils.data.DataLoader(gan0_dataset, batch_size=batch_size, shuffle=False)

            # Compute the features representations.
            stats0 = features.compute_feature(
                dataloader=dataloader0,
                eval_model=eval_model,
                batch_size=batch_size,
                quantize=True,
                device=device,
                cache_dir=cache_dir + gan_sel.split('samples')[-1],
                max_items=n_samples,
                capture_all=True,
                capture_mean_cov=True
            )
            feat_synth = stats0.get_all()
            feat_synth = feat_synth[:n_max_dim_red]  # select only n_max_dim_red samples
            feat_all.append(feat_synth)
            y_all.append(np.full(feat_synth.shape[0], idx + 1, dtype=int))
            gan_names[gan_sel.split('samples')[-1]] = idx + 1

    with open(os.path.join(reports_dir, f'{filename}_gan_label_map.txt'), "w") as f:
        json.dump(gan_names, f, indent=4)

    feat_real = feat_all[0]
    feat_real = np.array(feat_real).astype(np.float32)
    y_real = y_all[0]
    y_real = np.array(y_real).astype(np.int32)

    feat_all_gans = feat_all[1:]
    feat_all_gans = np.concatenate(feat_all_gans, axis=0).astype(np.float32)
    y_all_gans = y_all[1:]
    y_all_gans = np.concatenate(y_all_gans, axis=0).astype(np.int32)

    feat_ensemble = [feat_all[gan_names.get(x.split('samples')[-1])] for x in gan_folders_ensemble]
    feat_ensemble = np.concatenate(feat_ensemble, axis=0).astype(np.float32)
    y_ensemble = [y_all[gan_names.get(x.split('samples')[-1])] for x in gan_folders_ensemble]
    y_ensemble = np.concatenate(y_ensemble, axis=0).astype(np.int32)

    # Fit umap.
    print('Fit umap.')
    reducer = umap.UMAP(random_state=42)
    output_name = filename + '_' + 'fit_real'
    transformer = reducer.fit(feat_real)

    # Project latent points.
    print('Project latent points.')
    embedding_real = transformer.transform(feat_real)
    embedding_all_gans = transformer.transform(feat_all_gans)
    embedding_ensemble = transformer.transform(feat_ensemble)

    # Create a dataframe from embeddings.
    df_real = pd.DataFrame(embedding_real, columns=['umap-1', 'umap-2'])
    df_real['exp'] = 'real'

    df_naive = pd.DataFrame(embedding_all_gans, columns=['umap-1', 'umap-2'])
    df_naive['exp'] = 'naive'

    df_DGE = pd.DataFrame(embedding_ensemble, columns=['umap-1', 'umap-2'])
    df_DGE['exp'] = 'DGE'

    # Concatenate all these dataframes
    df = pd.concat([df_real, df_naive, df_DGE], ignore_index=True)

    # Save to the disk.
    df.to_excel(os.path.join(reports_dir, f'{filename}.xlsx'), index=False)
    df_real.to_excel(os.path.join(reports_dir, f'{filename}_real.xlsx'), index=False)
    df_naive.to_excel(os.path.join(reports_dir, f'{filename}_naive.xlsx'), index=False)
    df_DGE.to_excel(os.path.join(reports_dir, f'{filename}_DGE.xlsx'), index=False)

    print('May the force be with you.')


"""Defines preprocessing filters which can be applied by preprocessing.get_data.

Kyle Roth. 2019-02-12.
"""

import librosa
import numpy as np
from scipy import fft
from scipy import signal

# used by mel function
_mel = librosa.filters.mel(16000, 2048, n_mels=80)  # linear transformation, (80,1025)

def mel(X, y):
    """Mel spectrogram preprocessing."""
    out = []
    for x in X:
        spectrum = np.log(np.abs(fft(x))[:len(x)//2])
        spectrum = signal.resample(spectrum, 1025)
        x_mel = np.dot(_mel, spectrum)
        out.append(x_mel)
    X = np.array(out)
    y = np.array(y)

    # remove NaNs
    is_nan = np.isnan(X).any(axis=1)
    X, y = X[~is_nan], y[~is_nan]

    return X, y

def resample(data, y):
    """Resample audio to 800 points."""
    out = []
    for thing in data:
        out.append(signal.resample(thing, 800))
    return np.array(out), y

def get_filter(name):  # pylint: disable=too-many-return-statements
    """Get the preprocessor specified by the name given.

    Args:
        name (str): name of model constructor to be called.
    Returns:
        (callable): model constructor to be called.
    """
    name = name.lower()
    if name == 'mel':
        return mel
    if name == 'resample':
        return resample
    raise ValueError("filter must be one of {mel, resample}")


from parse import * # pip install parse
import pprint
import xml.etree.ElementTree as ET
import sys

###########################################################################
# Helper Functions

def convertInterfaceToBoolDict(root):
    alphabet = {}
    keyLength = 0 # This will determine the length of the key that we will use to capture the dictionary
    for alphabetItem in root.iter("Interface"):
        for child in alphabetItem:
            if child.get("Type") != "bool":
                print("Support for boolean interfaces only!")
                assert(child.get("Type") == "bool")
            if child.get("Constant") == "false":
                print("Added ", child.get("Name"))
                keyLength += 1
                alphabet[child.get("Name")] = None

    return alphabet, keyLength

def parse_validateNoBrackets(conditionStr):
    if conditionStr.__contains__("(") or conditionStr.__contains__(")"):
        print("Condition string provided has brackets CHECK!")
        return False
    else:
        return True

def parse_isOR(conditionStr):
    assert(parse_validateNoBrackets(conditionStr))
    if parse("{}or{}", conditionStr) is None:
        return False
    else:
        return True

def parse_isAND(conditionStr):
    assert(parse_validateNoBrackets(conditionStr))
    if parse("{}and{}", conditionStr) is None:
        return False
    else:
        return True

def areAnyNone(unwound):
    for anyK in unwound:
        any = unwound[anyK]
        for k in any:
            if any[k] is None:
                return True
    return False

def getKey(alphabetOption):
    key = ""
    for k in alphabetOption:
        if alphabetOption[k] == True:
            key += "1"
        elif alphabetOption[k] == False:
            key += "0"
        else:
            key += "2"
    return key

def unwindConditions(conditions):
    # print('Unwinding')
    # print('Unwinding ', conditions)
    unwound = {}
    # print("At start are any more to unwind??", areAnyNone(conditions))
    if not areAnyNone(conditions):
        for conditionKey in conditions:
            unwound[conditionKey] = conditions[conditionKey]
    for conditionKey in conditions:
        condition = conditions[conditionKey]
        for k in condition:
            if condition[k] is None:
                trueOption = condition.copy()
                trueOption[k] = True
                falseOption = condition.copy()
                falseOption[k] = False
                unwound[getKey(trueOption)] = trueOption
                unwound[getKey(falseOption)] = falseOption
    # print("Any more to unwind??", areAnyNone(unwound))
    while areAnyNone(unwound) == True:
        unwound = unwindConditions(unwound)
    # print("Unwound to", unwound)
    return unwound

def pad(number, width):
    b = '{0:b}'.format(number)
    # Pad with 0s as required to meet length
    toPad = width - len(b)
    b = "0" * toPad + b
    return b

def getAllConditions(alphabet):
    # Get list of boolean combinations
    keys = alphabet.keys()
    width = len(keys)

    highest = pow(2, width)

    conditions = []

    for i in range(0, highest):
        conditions.append(pad(i, width))

    # Take each bool combo and turn into dict
    newConditions = {}
    for condition in conditions:
        newCondition = {}
        i = 0
        for key in keys:
            newCondition[key] = condition[i]
            i += 1
        newConditions[condition] = newCondition

    return newConditions

def addIfNotPresent(existing, new):
    notPresent = []
    for n in new:
        for e in existing:
            if n == e:
                break
        notPresent.append(n)
    existing = existing + notPresent
    return existing

def parse_singleSignal(signalString):
    if signalString[0] == "!":
        return {"signal":str(signalString[1:]).upper(),"value": False}
    else:
        return {"signal":str(signalString).upper(),"value": True}

def isClockCondition(conditionString):
    # In non-valued enforcement, we can assume any condition like <= < > >=
    if ("<" in conditionString) or ("<=" in conditionString) or (">" in conditionString) or (">=" in conditionString):
        return True
    else:
        return False

def isSingleSignal(conditionString, alphabetTemplate):
    if conditionString[0] == "!":
        conditionString = conditionString[1:]

    for option in alphabetTemplate:
        print(conditionString, option, alphabetTemplate[option])
        if conditionString == option:
            return True
    return False

def getCharacterRepeated(count, char):
    repeated = ""
    for number in range(0, count) : repeated = repeated + str(char)
    return repeated

def getIntersection(first, second):
    intersection = {}
    for f in first:
        # if f in second:
        for s in second:
            if f == s:
                # print("Found a match")
                intersection[f] = second[f]
        # else:
            # print("Found NO match", first[f])
    # print("First: ", first)
    # print("Second: ", second)
    # print("Intersection: ", intersection)
    return intersection

def removeClockConditions(conditions, alphabetTemplate):
    withoutClockConditions = {}
    for condition in conditions:
        # print(condition,conditions[condition])
        conditionValue = {}
        for value in conditions[condition]:
            if value in alphabetTemplate:
                conditionValue[value] = conditions[condition][value]
        # print(condition[0:len(alphabetTemplate)], conditionValue)
        withoutClockConditions[condition[0:len(alphabetTemplate)]] = conditionValue
    return withoutClockConditions

def removeClockConditionKeys(conditions, alphabetTemplate):
    assert(False)
    withoutClockConditions = {}
    for condition in conditions:
        # print('hi2', condition, conditions)#[condition], len(alphabetTemplate))
        # conditionValue = {}
        # for value in conditions[condition]:
        #     if value in alphabetTemplate:
        #         conditionValue[value] = conditions[condition][value]
        # print(condition[0:len(alphabetTemplate)], conditionValue)
        withoutClockConditions[condition[0:len(alphabetTemplate)]] = conditions[condition]
    return withoutClockConditions

def stripClockConditionsFromKey(key, alphabetKeyLength):
    # print("alphabetKeyLength:", alphabetKeyLength, "long, Key is", len(key), "long")
    return key[0:alphabetKeyLength]

def convertKeyToBools(key, alphabetTemplate, allowNone=False):
    dictCondition = {}
    alphabet = list(alphabetTemplate.keys())
    for i in range(0, len(alphabet)):
        if key[i] == "1":
            dictCondition[alphabet[i]] = True
        elif key[i] == "0":
            dictCondition[alphabet[i]] = False
        else:
            if allowNone:
                dictCondition[alphabet[i]] = None
            else:
                assert(False)
    return dictCondition

def convertConditionListToDictOfBools(listOfConditions, alphabetTemplate):
    dictOfConditionSets = {}
    for conditionSet in listOfConditions:
        label = ""
        for key in alphabetTemplate.keys():
            if conditionSet[key] == True:
                label += "1"
            elif conditionSet[key] == False:
                label += "0"
            elif conditionSet[key] is None:
                label += "2"
            else:
                assert(False)

        dictOfConditionSets[label] = conditionSet

    # dictOfConditionSets = unwindConditions(dictOfConditionSets)

    return [dictOfConditionSets, None]

    # print(alphabetTemplate)
    print(conditionString)

    # Remove spaces
    a = conditionString.replace(" ", "")
    # print("Original", a)

    # Count number of brackets
    left = a.count("(")
    right = a.count(")")
    assert(left == right)

    # If even count of brackets, there is a missing set of brackets on outer most (true always?)
    if (left % 2 == 0):
        # print("Even;", left)
        count = 1
    else:
        # print("Odd;", left)
        count = 0

    # Remove topmost brackets
    b = parse("({})", a)
    if b is not None:
        while True:
            # Keep going till all top brackets gone
            if parse("({})", b[0]) is not None:
                # print("Part:", b[0])
                b = parse("({})", b[0])
                count += 1
            else:
                break

        # print("Top brackets removed:", count, b[0])
    else:
        b=[]
        # print("No brackets to remove..?", a)
        b.append(a)

    if count > 0:
        # Separate into LHS, condition and RHS
        # Example: !AandB)or(AandB
        # Becomes: <Result ('!AandB', 'or', 'AandB') {}>
        formatString = "{}" + getCharacterRepeated(count, ")") + "{}" + getCharacterRepeated(count, "(") + "{}"
        # print(formatString)
        topCondition = parse(formatString, b[0])

        # print(topCondition)
        # assert (topCondition is not None)
        if (topCondition is None):
            print("You need to do something Mr Alex")

        # TODO: Recursively find all transitions - keep going till you have ONLY ANDS in a list/table

        LHS = topCondition[0]
        RHS = topCondition[2]

        # print("LHS:", LHS, "RHS:", RHS)
        # L = parse_noBracketsCondition(LHS, alphabetTemplate)
        L, clkL = convertConditionToDictOfBools("("+LHS+")", alphabetTemplate)
        # R = parse_noBracketsCondition(RHS, alphabetTemplate)
        R, clkR = convertConditionToDictOfBools("("+RHS+")", alphabetTemplate)

        # Condition is either "AND" or "OR"
        # print("top condition: ", topCondition)

        # Check if either is clock condition
        if isClockCondition(topCondition[0]):
            # print(topCondition[0], "is clock condition")
            topCondition = {**R}
            clk = {**L}
        elif isClockCondition(topCondition[2]):
            # print(topCondition[2], "is clock condition")
            topCondition = {**L}
            clk = {**R}
        else:
            # Neither is sole clock condition, so check how we need to combine
            condition = topCondition[1].lower()
            if (condition == "or"):
                # OR means APPEND sets of conditions for transition to violation
                print("OR")
                topCondition = {**L, **R}
            elif (condition == "and"):
                # AND means INTERSECTION of sets of conditions for transition to violation
                print("AND")
                topCondition = getIntersection(L, R)

            clk = {}
    else:
        print(b, b[0])
        topCondition, clk = parse_noBracketsCondition(b[0], alphabetTemplate)

    # print("Returning: ", topCondition, "and clk", clk)
    return topCondition, clk

def convertConditionToDictOfBools(conditionString, alphabetTemplate):
    import stringConditionParser

    listOfConditions = stringConditionParser.parseConditionString(conditionString, alphabetTemplate)

    return convertConditionListToDictOfBools(listOfConditions, alphabetTemplate)

def getAcceptableTransitions(violationConditions, allConditions):
    violationConditionsNoClocks = violationConditions #removeClockConditionKeys(violationConditions, alphabetTemplate)
    # print("with clocks:", violationConditions)
    # print("without clocks:", violationConditionsNoClocks)
    acceptableTransitions = {}
    allConditions = allConditions.copy()
    for condition in allConditions: # TODO: Come up with a way to compare while ignoring any clock conditions?
        if condition in violationConditionsNoClocks:
            pass
        else:
            acceptableTransitions[condition] = allConditions[condition]

    # print("Acceptable Transitions (", len(acceptableTransitions), ") -", acceptableTransitions)
    print("Acceptable Transitions (", len(acceptableTransitions), ")")
    print("Violating Transitions (", len(violationConditions), ")")
    print("All Conditions (", len(allConditions), ")")
    # print("Violating Transitions (", len(violationConditions), ") -", violationConditions)
    assert(len(acceptableTransitions) + len(violationConditions) == len(allConditions))
    return acceptableTransitions

# Provided two binary numbers (as STRINGS)
# This function will calculate the number of bits difference between the two
def calculateDistanceBetween(condition1, condition2):
    assert(len(condition1) == len(condition2))
    # assert(type(condition1) == type.String)
    distance = 0
    for i in range(0, len(condition1)):
        # print(i, condition1[i], condition2[i], condition1[i] == condition2[i])
        if (condition1[i] != condition2[i]):
            distance += 1
    return (distance)

def convertBinaryStringToTextCondition(binaryString, alphabetTemplate):
    # print(binaryString)
    i = 0
    condition = []
    for k in alphabetTemplate:
        if int(binaryString[i]) == 1:
            condition.append(k)
        else:
            condition.append("!"+k)

        # print(k, binaryString[i], condition)
        i += 1

    textCondition = "(" + condition[0]
    i = 0
    for i in range(1, len(condition)):
        textCondition += " and " + condition[i]
    textCondition += ")"

    return textCondition

def convertBinaryRecoveryStringToTextListRecovery(recoveryString, alphabetTemplate):
    recoveryList = []

    i = 0
    for a in alphabetTemplate:
        recoveryList.append({
            "VarName": a,
            "Value": recoveryString[i]
        })
        i += 1

    return recoveryList

def writeNewXML_two(root, input_filename, output_filename, policies, alphabetTemplate, list_intersections, references, individualRecoveryKeys):
    print("======================================")
    print(" WRITING XML FILE")
    print("======================================")
    from bs4 import BeautifulSoup

    # Reading data from the xml file
    with open(input_filename, 'r') as f:
        data = f.read()

    # Passing the data of the xml
    # file to the xml parser of
    # beautifulsoup
    bs_data = BeautifulSoup(data, features='xml')

    for policyTag in bs_data.find_all("Policy"):
        policy = policyTag.attrs["Name"]
        # location = tag.find("Source").text
        for tag in policyTag.find_all("PTransition"):
            location = tag.find("Source").text

            # Change the value of RecoveryReference to match the references list
            recoveries = tag.find_all("RecoveryReference")
            for recovery in recoveries:
                recovery.string = str(references[policy][location])
                # NOTE: Could add something here to add in individualRecoveryKeys[policy][location] to the xml for easier compiling

    # TODO: LUT with policies variable
    topEnfFnTag = bs_data.find("EnforcedFunction")
    selectLUTTag = bs_data.new_tag("SelectLUT")
    for row in list_intersections:
        rowTag = bs_data.new_tag("Row")

        recoveryTag = bs_data.new_tag("Recovery")
        recoveryTag.append(row["randEdit"]["key"])
        recoveryKeyTag = bs_data.new_tag("RecoveryKey")
        # recoveryKeyTag.append(row["recoveryKey"])
        recoveryKeyTag.append(row["recoveryKey"])

        for policy in policies:
            pRefTag = bs_data.new_tag("PolicyRef", Policy=str(policy), RecoveryReference=str(references[policy][row[policy]]), RecoveryReferenceKey=str(individualRecoveryKeys[policy][row[policy]]))
            rowTag.append(pRefTag)

        for signal in row["randEdit"]["signals"].keys():
            sigName = str(signal)
            sigValue = str(row["randEdit"]["signals"][sigName])

            if sigValue != "None":
                pRecoverTag = bs_data.new_tag("Recover")
                pSig = bs_data.new_tag("Signal")
                pSig.append(sigName)
                pVal = bs_data.new_tag("Value")
                pVal.append(sigValue)
                pRecoverTag.append(pSig)
                pRecoverTag.append(pVal)
                rowTag.append(pRecoverTag)

        rowTag.append(recoveryTag)
        rowTag.append(recoveryKeyTag)
        selectLUTTag.append(rowTag)

    topEnfFnTag.append(selectLUTTag)

    # Output the contents of the
    # modified xml file
    with open(output_filename, "w") as f2:
        # f2.write(str(bs_data.prettify()))
        f2.write(str(bs_data))
        f2.close()

###########################################################################

def main(dir, file):
    print("======================================")
    print(" READING & PARSING EXISTING XML FILE")
    print("======================================")

    # Passing the path of the
    # xml document to enable the
    # parsing process
    input_filename = "example/"+dir+"/"+file+".xml"
    output_filename = "example/"+dir+"/"+file+"_modified.xml"
    # tree = ET.parse('example/abc5/abc5.xml')
    tree = ET.parse(input_filename)

    # getting the parent tag of
    # the xml document
    originalXMLRoot = tree.getroot()

    # printing the root (parent) tag
    # of the xml document, along with
    # its memory location
    print("Enforced Function: ", originalXMLRoot.attrib.get("Name"))

    alphabetTemplate, alphabetKeyLength = convertInterfaceToBoolDict(originalXMLRoot)

    # root.tag
    # root.attrib
    # for child in root:
    #     print(child.tag, child.attrib)
    #     for childchild in child:
    #         print("\t", childchild.tag, childchild.attrib)

    print("==========================================")
    print(" DETERMINE ALL POSSIBLE CONDITIONS")
    print("==========================================")
    print(" - This may take a moment")
    allConditions = getAllConditions(alphabetTemplate.copy())
    print(" - Unique combinations of I/O: ", len(allConditions))

    print("==========================================")
    print(" COLLECTING ALL VIOLATING TRANSITIONS")
    print("==========================================")

    # Find each policies violating transitions
    policies = {}
    table_acceptingTransitions = {}
    table_violatingTransitions = {}
    for policy in originalXMLRoot.iter("Policy"):

        allViolationTransitions = []
        policyViolationCount = 0
        locations = []
        for transition in policy.iter('PTransition'):
            # if (transition.find('Recover')):
            if (transition.find('Destination').text == "violation"):
                # Recovery Statement / PTransition -> Violating

                violatingConditionString = transition.find("Condition").text
                violatingCondition, _ = convertConditionToDictOfBools(violatingConditionString, alphabetTemplate)

                pName = policy.attrib.get("Name")
                location = transition.find("Source").text
                condition = {
                    "string": violatingConditionString,
                    "bool": violatingCondition
                }

                if pName not in table_violatingTransitions.keys():
                    table_violatingTransitions[pName] = {}

                if location not in table_violatingTransitions[pName]:
                    table_violatingTransitions[pName][location] = []

                table_violatingTransitions[pName][location].append(condition)

                break

                # print(policy.attrib.get("Name"), " ", transition.find("Source").text, " to ", transition.find("Destination").text, " on ", transition.find("Condition").text, ". Recovers with ", child.find("VarName").text, child.find("Value").text)
                violationConditions, _ = convertConditionToDictOfBools(transition.find("Condition").text, alphabetTemplate)
                # print(policy.attrib.get("Name"), " ", transition.find("Source").text, " to ", transition.find("Destination").text, " on ", transition.find("Condition").text, ". Recovers with ", child.find("VarName").text, child.find("Value").text)
                # print("Violation Conditions: ", violationConditions)
                acceptable = getAcceptableTransitions(violationConditions, allConditions)
                location = transition.find("Source").text

                for violatingCondition in violationConditions:
                    # Put each violating signal set into table, [policy, reference, location, A, B, C, acceptable resolutions]
                    policyViolationCount += 1 # TODO: Review renaming this, not always a violating trans
                    allViolationTransitions.append({
                        "policy":policy.attrib.get("Name"),
                        "violationRef":policyViolationCount,
                        "location":location,
                        "violatingConditionString":transition.find("Condition").text,
                        "violatingCondition":stripClockConditionsFromKey(violatingCondition, alphabetKeyLength),
                        "acceptableConditions":acceptable
                    })

                if location not in locations:
                    locations.append(location)
                    policyViolationCount += 1 # TODO: Review renaming this
                    allViolationTransitions.append({
                        "policy":policy.attrib.get("Name"),
                        "violationRef":policyViolationCount,
                        "location":location,
                        "violatingConditionString":"NONE",
                        "violatingCondition":"NONE",
                        "acceptableConditions":acceptable
                    })
            else:
                # Normal Transition Statement / PTransition -> Accepting
                acceptConditionString = transition.find("Condition").text
                acceptCondition, _ = convertConditionToDictOfBools(acceptConditionString, alphabetTemplate)

                pName = policy.attrib.get("Name")
                location = transition.find("Source").text
                condition = {
                    "string": acceptConditionString,
                    "bool": acceptCondition
                }

                if pName not in table_acceptingTransitions.keys():
                    table_acceptingTransitions[pName] = {}

                if location not in table_acceptingTransitions[pName]:
                    table_acceptingTransitions[pName][location] = []

                table_acceptingTransitions[pName][location].append(condition)

        policies[policy.attrib.get("Name")] = allViolationTransitions

    # Add non-violation for each location in each policy
    # (because there is still some set of acceptable I/O for each policy+location,
    # and we need to capture this to ensure edit action doesnt inadvertantly violate)
    def getUniqueLocations(policy):
        locations = []
        for violation in policy:
            if violation["location"] not in locations:
                locations.append(violation["location"])
        return locations

    def addRecovery(recoveries, transitionInfo, recovery):
        recoveries[transitionInfo["policy"]+"-"+transitionInfo["location"]+"-"+transitionInfo["violatingCondition"]] = {
            "policy":transitionInfo["policy"],
            "location":transitionInfo["location"],
            "violationRef":transitionInfo["violationRef"],
            "violatingConditionString":transitionInfo["violatingConditionString"],
            "violatingCondition":transitionInfo["violatingCondition"],
            "recovery":recovery
        }
        return

    print("==========================================")
    print(" CREATING VIOLATION REF TABLE")
    print("==========================================")

    def getNumberLocations(policy):
        return len(getUniqueLocations(policy))

    # Create template to be used as rows (each policy should have a column, which will hold the violation reference)
    rowTemplate = {}
    for policy in policies:
        rowTemplate[policy] = 1

    numberRowsExpected = 1
    # recoveryKeyLength = {} NOTE: Determined later
    for policy in policies:
        # numberLocations = getNumberLocations(policies[policy])
        numberRowsExpected = numberRowsExpected * (len(policies[policy]))
        # recoveryKeyLength[policy] = len('{0:b}'.format(len(policies[policy])))  NOTE: Determined later

    print("Expected Recovery Rows:", numberRowsExpected)

    rowsExample = []
    rowsExample.append(rowTemplate)
    for policy in policies:
        rowCount = len(rowsExample)
        for i in range(rowCount):
            for violation in policies[policy]:
                if violation["violationRef"] > 1: # Added check here to remove don't cares
                    row = rowsExample[i].copy()
                    row[policy] = violation["violationRef"]
                    rowsExample.append(row)

    # assert(len(rowsExample) == numberRowsExpected)

    # List of dictionaries with each policy and violation refs
    import pprint
    # pprint.pprint(rowsExample)

    print("=============================================")
    print(" PRE-CRUNCHING EDITS FOR VIOLATION REF COMBO")
    print("=============================================")

    def convertTableRow_policy_location_to_boolCondition(row_policy_location_condition):
        condition = {}
        for cdtn in row_policy_location_condition:
            condition.update(cdtn["bool"])
        return condition

    def appendViolatingTransitionsToList(combinations, violatingPolicyLocations):
        newCombinations = []
        for combination in combinations:
            newCombinations.append(combination)
        return newCombinations

    def appendPolicyLocationsToList(combinations, policyLocations):
        newCombinations = []
        for combination in combinations:
            policy = policyLocations[0]
            locations = policyLocations[1]
            if policy not in combination.keys():
                for location in locations:
                    combination[policy] = location
                    newCombinations.append(combination.copy())
            else:
                newCombinations.append(combination)

        return newCombinations

    # Make a nice list of policies, with a list inside of each location
    # policies_and_locations = [ [ policy 1 name, [policy location 1, policy location 2, .. ]] ]
    print(" - Getting acceptable actions")
    policies_and_locations = []
    policies = list(table_acceptingTransitions.keys())
    for policy in policies:
        locations = list(table_acceptingTransitions[policy].keys())
        policies_and_locations.append([policy, locations])

    # TODO: Add non-violating for each

    # Now, for some fun..
    # So we need precompute the intersection of acceptable actions for each location within each policy
    #
    # What?
    #
    # At any time, each policy is in any one location, and there is a set of acceptable actions in that policy
    # At the same time, EVERY other policy is in any one location, also with a set of acceptable actions
    #
    # In order to precompute edits, we need to determine the intersection of each possible set of locations
    # [Policy1 Locations] X [Policy 2 Locations] X [Policy 3 Locations] and so on
    #
    # Yes it is exponential. So maybe we won't precompute the intersection, but knowing the list of these combinations will be handy.. I think!
    combinations = []
    firstPolicy = policies_and_locations[0]
    for location in firstPolicy[1]:
        combinations.append({firstPolicy[0]: location})
    for policy in policies_and_locations:
        combinations = appendPolicyLocationsToList(combinations, policy)

    def unionDictTransitions(list):
        start = {}
        for i in list:
            start = {**start, **i["bool"]}
        return start

    def intersectionDictTransitions(one, two, alphabetTemplate):
        oneKeys = []
        for item in one:
            # oneKeys.append(list(item["bool"].keys())[0])
            # oneKeys.append(item["bool"].keys())
            oneKeys = oneKeys + list(item["bool"].keys())
        twoKeys = []
        for item in two:
            twoKeys = twoKeys + list(item["bool"].keys())
            # twoKeys.append(list(item["bool"].keys())[0])

        intersection = []
        # for each key in one
        # for oneKey in oneKeys:
        #     # if key is in two
        #     if oneKey in twoKeys:
        #         # add to intersection
        #         intersection[oneKey] = convertKeyToBools(oneKey, alphabetTemplate, allowNone=True) #one[oneKey]

        # If intersection is none, then we need to be more thoughtful
        # intersectionFound = False
        # Specifically comparing for 2s, which are nones- and therefore we dont mind what they are
        for oneKey in oneKeys:
            for twoKey in twoKeys:
                match = True
                for i in range(0, len(oneKey)):
                    # If 0 in onekey, then accept 0 / 2 in twokey
                    if (oneKey[i] == "0"):
                        if (twoKey[i] != "0") and (twoKey[i] != "2"):
                            # Key doesn't match
                            match = False
                            break
                    # If 1 in onekey, then accept 1 / 2 in twokey
                    elif (oneKey[i] == "1"):
                        if (twoKey[i] != "1") and (twoKey[i] != "2"):
                            # Key doesn't match
                            match = False
                            break

                    # If 2 in onekey, then accept any in twokey
                    elif (oneKey[i] == "2"):
                        continue

                if match:
                    jointKey = ""
                    for i in range(0, len(oneKey)):
                        if (oneKey[i] == "2"):
                            jointKey += twoKey[i]
                        elif (twoKey[i] == "2"):
                            jointKey += oneKey[i]
                        else:
                            jointKey += oneKey[i]
                    intersection.append(
                        {"bool":
                         {jointKey: convertKeyToBools(jointKey, alphabetTemplate, allowNone=True)}
                         })
                    # print("Match", oneKey, twoKey, jointKey)
                # else:
                    # print("No-Match", oneKey, twoKey)

                # for oAK in oneAgnosticKey:
                #     if oAK in twoAgnosticKey:
                #         intersection[oAK] = convertKeyToBools(oAK, alphabetTemplate)
                        # intersectionFound = True
                        # break

        return intersection

    print(" - Getting intersection of acceptable actions")
    # For every combination of locations
    list_intersections = []
    # for combination in combinations:
    #     policies = list(combination.keys())
    #     firstPolicy = policies[0]
    #     firstLocation = combination[firstPolicy]
    #     # Union of acceptable for the first policy
    #     acceptableTransitions = unionDictTransitions(table_acceptingTransitions[firstPolicy][firstLocation])

    #     # Then for each other policy
    #     for next in policies:
    #         # nextPolicy = next[0]
    #         nextPolicy = next
    #         nextLocation = combination[nextPolicy]
    #         if nextPolicy != firstPolicy:
    #             # Get union of acceptable
    #             someNewAcceptableTransitions = unionDictTransitions(table_acceptingTransitions[nextPolicy][nextLocation])
    #             # Get intersection
    #             acceptableTransitions = intersectionDictTransitions(acceptableTransitions, someNewAcceptableTransitions, alphabetTemplate)

    #     import random
    #     numAccTrans = len(acceptableTransitions)
    #     assert(numAccTrans > 0)
    #     if numAccTrans > 1:
    #         randInt = random.randrange(len(acceptableTransitions)-1)
    #     else:
    #         randInt = 0

    #     randKey = list(acceptableTransitions.keys())[randInt]
    #     # Now we have the intersection, add it to the list
    #     list_intersections.append({
    #         **combination,
    #         "intersection":acceptableTransitions,
    #         "randEdit":{"key":randKey, "signals":acceptableTransitions[randKey]}
    #     })

    print(" - For each violation")
    for combination in combinations:
        # Combination holds a location for each policy
        # In this combination we can have one or more violating transitions
        # TODO: We need to solve each one of these
        first = True
        accepting = {}
        for policy in policies:
            location = combination[policy]
            # print(policy, location, "violating transitions:", len(table_violatingTransitions[policy][location]), "condition[0]", table_violatingTransitions[policy][location][0]["string"])
            # print("accepting:", table_acceptingTransitions[policy][location][0]['bool'])
            if first:
                accepting = table_acceptingTransitions[policy][location]
                first = False
            else:
                accepting = intersectionDictTransitions(accepting, table_acceptingTransitions[policy][location], alphabetTemplate)
        # print(" - Combination ", combination, "has resolutions:")
        # pprint.pprint(accepting)

        import random
        numAccTrans = len(accepting)
        assert(numAccTrans > 0)
        if numAccTrans > 1:
            randInt = random.randrange(0, len(accepting)) # may need len -1
        else:
            randInt = 0

        print("\t - Found " + str(numAccTrans) + " accepting solutions. Picked index " + str(randInt))
        # randKey = list(accepting.keys())[randInt]
        # randKey = accepting[randInt]
        randKey = list(accepting[randInt]["bool"].keys())[0]
        randValues = accepting[randInt]["bool"][randKey]
        # Now we have the intersection, add it to the list
        list_intersections.append({
            **combination,
            "intersection":accepting,
            "randEdit":{"key":randKey, "signals":randValues}
        })

    # Quick fix to add recovery references to the list of intersections
    print(" - Add recovery references to the list of intersections")
    references = {}
    recoveryKeyLength = {}
    for p_and_l in policies_and_locations:
        ref = 0
        policy = p_and_l[0]
        if policy not in references.keys():
            references[policy] = {}
        for location in p_and_l[1]:
            references[policy] = {**references[policy], location: ref}
            ref += 1
        recoveryKeyLength[policy] = len('{0:b}'.format(ref))

    # Get binary recoveryKeys
    # Stored in the "list_intersections" list1 under key "recoveryKey" for each row
    print(" - Add binary recovery keys")
    individualRecoveryKeys = {} # This one holds individual keys, this might be helpful on the compiler side
    for intersection in list_intersections:
        recoveryKey = ""
        for policy in policies:
            b = '{0:b}'.format(references[policy][intersection[policy]])
            # Pad with 0s as required to meet length
            toPad = recoveryKeyLength[policy] - len(b)
            b = "0" * toPad + b
            recoveryKey += b

            if policy not in individualRecoveryKeys.keys():
                individualRecoveryKeys[policy] = {}
            if intersection[policy] not in individualRecoveryKeys[policy].keys():
                individualRecoveryKeys[policy][intersection[policy]] = {}
            individualRecoveryKeys[policy][intersection[policy]] = b
            # individualRecoveryKeys[policy][intersection[policy]]["binary"] = "TODO"

        intersection["recoveryKey"]= recoveryKey

    writeNewXML_two(originalXMLRoot, input_filename, output_filename, policies, alphabetTemplate, list_intersections, references, individualRecoveryKeys)

    return

    # Now iterate through this list, pulling each set of acceptable from policies object
    rowNumber = 0
    lastPrinted = 100
    for row in rowsExample:
        # print(row)
        totalRows = len(rowsExample)
        rowNumber += 1
        # print(rowNumber / totalRows * 100, totalRows, rowNumber)
        if (int(rowNumber / totalRows * 100)) % 10 == 0:
            if (lastPrinted != (int(rowNumber / totalRows * 100))):
                print(int(rowNumber / totalRows * 100), "%\t", rowNumber, "of", totalRows)
                lastPrinted = int(rowNumber / totalRows * 100)

        acceptableSets = []
        for policy in row:
            if row[policy] == 0:
                print("Dont Care - Add things that dont violate the policy.. in this location..?")
            else:
                # print("Add", policy, row[policy]-1)#, policies[policy][row[policy]-1]["acceptableConditions"])
                acceptableSets.append(policies[policy][row[policy]-1]["acceptableConditions"])

        # Do an intersection
        intersection = acceptableSets[0]
        for i in range(1, len(acceptableSets)):
            intersection = getIntersection(intersection, acceptableSets[i])

        # print("Intersection:", end=" ")
        # pprint.pprint(intersection)

        # NOTE: This will fail when intersection is empty set!
        # NOTE: The script currently ONLY supports CAPS LOCK inputs and outputs! A reason you may be here is because of that...!
        assert(len(intersection) > 0)
        # We are expecting this to occur for some examples, just need to handle it gracefully.
        # In some cases this assert will fail when the designer has created unenforceable policies
        # In other cases, the policies will never emit the two violationRef signals at the same time, thus this row/edit/enforcement action doesnt need to exist

        # TODO: Then do a minEdit
        selectedRecovery = intersection[list(intersection.keys())[0]]

        # Get binary recoveryKeys
        recoveryKey = ""
        for policy in row:
            b = '{0:b}'.format(row[policy])
            # Pad with 0s as required to meet length
            toPad = recoveryKeyLength[policy] - len(b)
            b = "0" * toPad + b
            recoveryKey += b
        row["recoveryKey"] = recoveryKey

        row["recovery"] = list(intersection.keys())[0]
        row["recoveryValue"] = intersection[list(intersection.keys())[0]]

    writeNewXML(originalXMLRoot, input_filename, output_filename, policies, alphabetTemplate, rowsExample)

###########################################################################

if __name__ == "__main__":
    if (len(sys.argv) != 3):
        print("ERROR\nExpecting 2 arguments: project directory then project file.")
        print("For the AB example: python rtecomp/main.py AB AB\n")
        assert(len(sys.argv) == 3)
    projectDir = sys.argv[1]
    projectFile = sys.argv[2]

    # import cProfile
    # import re
    # cProfile.run("main(projectDir,projectFile)")

    main(projectDir, projectFile)

###########################################################################


from tkinter import *

root = Tk()
root.title('привет, я вован')

c=Canvas(root, width=400, height=400)
c.configure(bg="black")

c.body_color="white"

body=c.create_oval(35, 20, 365, 350, outline=c.body_color, fill=c.body_color)

ear_left=c.create_polygon(75, 80, 75, 10, 165, 70, outline=c.body_color, fill=c.body_color)
ear_right=c.create_polygon(270, 45, 325, 10, 325, 77, outline=c.body_color, fill=c.body_color)

mouth_normal=c.create_line(170, 250, 200, 272, 230, 250, width=2, smooth=1)

foot_left=c.create_oval(65, 320, 145, 360, outline=c.body_color, fill=c.body_color)
foot_right=c.create_oval(250, 320, 330, 360, outline=c.body_color, fill=c.body_color)

eye_left=c.create_oval(130, 110, 160, 170, outline="black", fill="white")
eye_left=c.create_oval(230, 110, 260, 170, outline="black", fill="white")

pupil_left=c.create_oval(140, 145, 150, 155, outline="black", fill="black")
pupil_right=c.create_oval(240, 145, 250, 155, outline="black", fill="black")

c.pack()

root.mainloop()


#!/usr/bin/env python
import csv
import time
import sys

from live_data_stream import LiveDataStream

import pdb

def transform_data_vector(data_vector):
    ''' Add a line to the CSV from new data.'''
    new_csv_row = []

    new_csv_row.append(str(data_vector.timestamp))
    new_csv_row.append(str(data_vector.gaze_x))
    new_csv_row.append(str(data_vector.gaze_y))

    new_csv_row.append(str(data_vector.field_width))
    new_csv_row.append(str(data_vector.field_height))

    # Handle Aruco Data
    new_csv_row.append(str(data_vector.aruco_markers_present))
    if data_vector.aruco_markers_present:
        # Turn each array into a colon delimited list.
        aruco_IDs = ":".join(data_vector.aruco_IDs)
        aruco_X_vals = ":".join(data_vector.aruco_X_vals)
        aruco_Y_vals = ":".join(data_vector.aruco_Y_vals)

    else:
        aruco_IDs = "None"
        aruco_X_vals = "None"
        aruco_Y_vals = "None"

    new_csv_row.append(aruco_IDs)
    new_csv_row.append(aruco_X_vals)
    new_csv_row.append(aruco_Y_vals)

    new_csv_row.append(str(data_vector.left_pupil_x))
    new_csv_row.append(str(data_vector.left_pupil_y))
    new_csv_row.append(str(data_vector.left_pupil_width))
    new_csv_row.append(str(data_vector.left_pupil_height))
    new_csv_row.append(str(data_vector.left_pupil_angle))

    new_csv_row.append(str(data_vector.right_pupil_x))
    new_csv_row.append(str(data_vector.right_pupil_y))
    new_csv_row.append(str(data_vector.right_pupil_width))
    new_csv_row.append(str(data_vector.right_pupil_height))
    new_csv_row.append(str(data_vector.right_pupil_angle))

    return new_csv_row

if __name__ == "__main__":

    output_path = sys.argv[1]
    # Number of seconds to record for.
    recording_time = int(sys.argv[2])

    title_row = []
    title_row.append("timestamp")
    title_row.append("gaze_x")
    title_row.append("gaze_y")

    title_row.append("field_width")
    title_row.append("field_height")

    title_row.append("aruco_markers_present")
    title_row.append("aruco_IDs")
    title_row.append("aruco_X_vals")
    title_row.append("aruco_Y_vals")

    title_row.append("left_pupil_x")
    title_row.append("left_pupil_y")
    title_row.append("left_pupil_width")
    title_row.append("left_pupil_height")
    title_row.append("left_pupil_angle")

    title_row.append("right_pupil_x")
    title_row.append("right_pupil_y")
    title_row.append("right_pupil_width")
    title_row.append("right_pupil_height")
    title_row.append("right_pupil_angle")

    with open(output_path, 'wb+') as csvfile:
        gaze_data_writer = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
        gaze_data_writer.writerow(title_row)

        data_stream = LiveDataStream()

        raw_input("[INFO:] Press Enter to record gaze data for " + str(recording_time) + " seconds.")

        start_time = time.time()
        while (True):
            new_data_vector = data_stream.read()
            # Parse and write.
            new_csv_row = transform_data_vector(new_data_vector)
            gaze_data_writer.writerow(new_csv_row)

            cur_time = time.time()
            if cur_time - start_time > recording_time:
                break


import sqlite3
from tkinter import *

def createtable():
    conn = sqlite3.connect("Database.db")
    cur = conn.cursor()
    cur.execute("CREATE TABLE IF NOT EXISTS data(Id INTEGER PRIMARY KEY ,Date TEXT,Earning INTEGER,Exercise TEXT,Study TEXT,Diet TEXT,python TEXT)")
    conn.commit()
    conn.close()

def insert_data(Date,Earning,Exercise,Study,Diet,Python):
    conn = sqlite3.connect("Database.db")
    cur = conn.cursor()
    cur.execute("INSERT INTO data VALUES(NULL, ?,?,?,?,?,?)",(Date,Earning,Exercise,Study,Diet,Python))
    conn.commit()
    conn.close()

def view():
    conn = sqlite3.connect("Database.db")
    cur = conn.cursor()
    cur.execute("SELECT * FROM data")
    rows = cur.fetchall()
    conn.commit()
    conn.close()
    return rows

def delete(id):
    conn = sqlite3.connect("Database.db")
    cur = conn.cursor()
    cur.execute("DELETE FROM data WHERE Id = ?", (id,))
    conn.commit()
    conn.close()

def search(date='' , earnings='' , exercise='' , study='' , diet='' , python=''):
    conn = sqlite3.connect('Database.db')
    cur = conn.cursor()
    cur.execute("SELECT * FROM data WHERE Date=?  OR Earning=? OR Exercise=? OR Study=? OR Diet=? OR Python=?" , (date , earnings , exercise , study , diet , python))
    rows = cur.fetchall()
    conn.commit()
    conn.close()
    return rows

createtable()


import zmx_api
import zmx
import numpy as np
import math as mt

TheSystem, ZOSAPI, ZOSAPI_NetHelper = zmx_api.connect_zmx_interactive()
MFE = TheSystem.MFE
op_types = ZOSAPI.Editors.MFE.MeritOperandType

# constants
L321_surf_num, _, _ = zmx.get_lens_surfaces(TheSystem)
#L321_diameter_mm = [158, 152, 177] # 8mm clearance
#L321_diameter_mm = [158, 148, 173] # 8mm clearance

L321_diameter_mm = [158, 138, 163] # 15mm clearance
# end constants

# delete merit function and add a few operands
def initialize_merit_function(MFE):
    MFE.RemoveOperandsAt(1, MFE.NumberOfOperands)
    MFE.AddOperand()
    MFE.AddOperand()
    zmx.set_MFE_row(op_types.CVIG, 2, MFE, ZOSAPI)

def write_L321_diameter_constraints(MFE, start_at_row,
                                    L321_surf_num, L321_diameter_mm,
                                    weight_l1illum=1e10,
                                    hardweight=1e13):

    MFE.AddOperand()

    current_row = start_at_row
    lens_index = 0

    weights_for_exact_diameter = [weight_l1illum,
                                  0.0,
                                  weight_l1illum]
    for lens_index in range(len(L321_surf_num)):
        zmx.set_MFE_row(op_types.BLNK, current_row, MFE, ZOSAPI,
                        param1val="Lens Diameter")
        MFE.AddOperand()
        current_row += 1
        zmx.set_MFE_row(op_types.DMLT, current_row, MFE, ZOSAPI,
                        param1val=L321_surf_num[lens_index],
                        weight=hardweight,
                        target=L321_diameter_mm[lens_index])
        current_row += 1
        MFE.AddOperand()
        zmx.set_MFE_row(op_types.DMLT, current_row, MFE, ZOSAPI,
                        param1val=L321_surf_num[lens_index] + 1,
                        weight=hardweight,
                        target=L321_diameter_mm[lens_index])

        current_row += 1
        MFE.AddOperand()
        zmx.set_MFE_row(op_types.DMVA,
                        current_row, MFE, ZOSAPI,
                        param1val=L321_surf_num[lens_index],
                        weight=0.0)

        current_row += 1
        MFE.AddOperand()
        zmx.set_MFE_row(op_types.DMVA,
                        current_row, MFE, ZOSAPI,
                        param1val=L321_surf_num[lens_index]+1,
                        weight=0.0)
        current_row += 1
        MFE.AddOperand()

        zmx.set_MFE_row(op_types.MAXX, current_row, MFE, ZOSAPI,
                    param1val=current_row - 2,
                    param2val=current_row -1,
                    target=L321_diameter_mm[lens_index] - 0.1,
                    weight=weights_for_exact_diameter[lens_index])
        current_row += 1
        MFE.AddOperand()
    return current_row

def write_thickness_constraints(MFE, start_at_row,
                                surfaces_to_control_thickness=[2, 4, 6, 9],
                                max_thickness=400.,
                                weight=1e5):
    MFE.AddOperand()
    current_row = start_at_row

    zmx.set_MFE_row(op_types.BLNK, current_row, MFE, ZOSAPI,
                        param1val= "Thickness constraints")

    MFE.AddOperand()
    current_row += 1

    zmx.set_MFE_row(op_types.TTHI, current_row, MFE, ZOSAPI,
                    param1val=2, param2val=11)
    MFE.AddOperand()
    current_row += 1
    MFE.AddOperand()

    zmx.set_MFE_row(op_types.OPLT, current_row, MFE, ZOSAPI, target=800,
                    weight=weight, param1val=current_row-1)
    MFE.AddOperand()
    current_row += 1
    MFE.AddOperand()

    for j, surf_num in enumerate(surfaces_to_control_thickness):
        zmx.set_MFE_row(op_types.CTLT, current_row, MFE, ZOSAPI,
                        param1val=surf_num, target=max_thickness,
                        weight=weight)
        MFE.AddOperand()
        current_row += 1
        MFE.AddOperand()

    for j, surf_num in enumerate(surfaces_to_control_thickness):
        zmx.set_MFE_row(op_types.CTGT, current_row, MFE, ZOSAPI,
                        param1val=surf_num, target=0.0,
                        weight=weight)
        MFE.AddOperand()
        current_row += 1
        MFE.AddOperand()
    return current_row

def write_fnumber(MFE, start_at_row,
                  Hx, Hy, direction):
    current_row = start_at_row
    Hx = float(Hx)
    Hy = float(Hy)

    zmx.set_MFE_row(op_types.BLNK, current_row, MFE, ZOSAPI,
            param1val= "fnum Hx,Hy: %1.2f %1.2f" % (Hx, Hy))

    MFE.AddOperand()
    current_row+=1
    if direction == 'x':
        zmx.set_MFE_row(op_types.REAX, current_row, MFE, ZOSAPI,
                        param1val=1, param2val=1, param3val=Hx, param4val=Hy,
                        param5val=1.0, param6val=0.0,
                        weight=0)
        MFE.AddOperand()
        current_row += 1
        zmx.set_MFE_row(op_types.REAX, current_row, MFE, ZOSAPI,
                        param1val=1, param2val=1,
                        param3val=Hx, param4val=Hy, param5val=-1., param6val=0.,
                        weight=0)
        MFE.AddOperand()
    elif direction == 'y':
        zmx.set_MFE_row(op_types.REAY, current_row, MFE, ZOSAPI,
                        param1val=1, param2val=1, param3val=Hx, param4val=Hy,
                        param5val=0.0, param6val=1.0,
                        weight=0)
        MFE.AddOperand()
        current_row += 1
        zmx.set_MFE_row(op_types.REAY, current_row, MFE, ZOSAPI,
                        param1val=1, param2val=1,
                        param3val=Hx, param4val=Hy, param5val=0., param6val=-1.,
                        weight=-0.0)
        MFE.AddOperand()

    current_row += 1
    zmx.set_MFE_row(op_types.DIFF, current_row, MFE, ZOSAPI,
                    param1val=current_row-2, param2val=current_row-1)
    MFE.AddOperand()
    current_row += 1
    zmx.set_MFE_row(op_types.CONS, current_row, MFE, ZOSAPI,
                    target=1e5)
    MFE.AddOperand()
    current_row +=1
    zmx.set_MFE_row(op_types.DIVI, current_row, MFE, ZOSAPI,
                    param1val=current_row-1, param2val=current_row-2)
    MFE.AddOperand()
    fnum_cell_num = current_row
    return fnum_cell_num

def write_fnum_constraint(MFE, start_at_row,
                          center_fnum_cell_num, side_fnum_cell_num,
                          max_ratio=1.12, weight=1e13):
    MFE.AddOperand()
    current_row = start_at_row
    zmx.set_MFE_row(op_types.BLNK, current_row, MFE, ZOSAPI,
                    param1val= "fnum")
    MFE.AddOperand()
    current_row += 1

    zmx.set_MFE_row(op_types.DIVI, current_row, MFE, ZOSAPI,
                    param1val=center_fnum_cell_num, param2val=side_fnum_cell_num)
    current_row += 1
    MFE.AddOperand()
    zmx.set_MFE_row(op_types.OPLT, current_row, MFE, ZOSAPI,
                    param1val=current_row-1, weight=weight, target=max_ratio)
    MFE.AddOperand()
    current_row += 1
    return current_row

def write_primary_footprint(MFE, start_at_row,
                            Hx, Hy,
                            weight=5e6, Npoints=4):
    MFE.AddOperand()
    current_row = start_at_row
    zmx.set_MFE_row(op_types.BLNK, current_row, MFE, ZOSAPI,
                    param1val= "Primary footprint Hx, Hy: %1.2f, %1.2f" % (Hx, Hy))

    MFE.AddOperand()
    current_row += 1

    ts = np.linspace(0, 2*np.pi, Npoints+1)[:-1]

    start_row = start_at_row
    for t in ts:
        px = mt.cos(t)
        py = mt.sin(t)
        zmx.set_MFE_row(op_types.REAX,
                        current_row, MFE, ZOSAPI,
                        param1val=44,
                        param2val=1,
                        param3val=Hx,
                        param4val=Hy,
                        param5val=float(px),
                        param6val=py,
                        weight=0.)
        MFE.AddOperand()
        current_row+=1
    end_row = current_row-1
    zmx.set_MFE_row(op_types.OSUM,
                    current_row, MFE, ZOSAPI,
                    param1val=start_row,
                    param2val=end_row,
                    weight=weight,
                    target=0.0)

    MFE.AddOperand()
    current_row+=1
    start_row = current_row
    for t in ts:
        px = mt.cos(t)
        py = mt.sin(t)
        zmx.set_MFE_row(op_types.REAY,
                        current_row, MFE, ZOSAPI,
                        param1val=44,
                        param2val=1,
                        param3val=Hx,
                        param4val=Hy,
                        param5val=px,
                        param6val=py,
                        weight=0.)
        MFE.AddOperand()
        current_row+=1
    end_row = current_row-1
    zmx.set_MFE_row(op_types.OSUM,
                    current_row, MFE, ZOSAPI,
                    param1val=start_row,
                    param2val=end_row,
                    weight=weight,
                    target=0.0)
    MFE.AddOperand()
    current_row+=1
    return current_row

def write_telecentric_angle_cons(MFE, start_at_row,
                                 weight=1e4):
    Hxs = [0.0, 1.0, -1.0, 0.0,  0.0]
    Hys = [0.0, 0.0,  0.0, 1.0, -1.0]
    MFE.AddOperand()
    current_row = start_at_row
    zmx.set_MFE_row(op_types.BLNK, current_row, MFE, ZOSAPI,
                        param1val= "Telecentric angle")
    MFE.AddOperand()
    current_row+=1

    for j in range(len(Hxs)):
        Hx, Hy = Hxs[j], Hys[j]
        zmx.set_MFE_row(op_types.RAID,
                        current_row, MFE, ZOSAPI,
                        param1val=1,
                        param2val=1,
                        param3val=Hx,
                        param4val=Hy,
                        param5val=0.0,
                        param6val=0.0,
                        weight=0.0)
        MFE.AddOperand()
        current_row+=1
    zmx.set_MFE_row(op_types.MAXX,
                    current_row, MFE, ZOSAPI,
                    param1val=start_at_row,
                    param2val=current_row-1)
    current_row+=1
    zmx.set_MFE_row(op_types.OPLT,
                    current_row, MFE, ZOSAPI,
                    param1val=current_row-1,
                    target=2.5,
                    weight=1e10)
    current_row += 1
    return current_row

def write_primary_aperture_diameter(MFE, start_at_row,
                                    weight=1e10,
                                    radius_mm=2450):
    def ap_diameter(px, py, Hxs, Hys, row_start,
                    direction):
        current_row = row_start
        for hxhy in zip(Hxs, Hys):
            Hx, Hy = hxhy
            zmx.set_MFE_row(op_types.REAX,
                            current_row, MFE, ZOSAPI,
                            param1val=44,
                            param2val=1,
                            param3val=float(Hx),
                            param4val=float(Hy),
                            param5val=px,
                            param6val=py)
            MFE.AddOperand()
            current_row+=1
        MFE.AddOperand()
        if direction == 'xp':
            op_type = op_types.MINN
        elif direction == 'xm':
            op_type = op_types.MAXX
        zmx.set_MFE_row(op_type,
                        current_row, MFE, ZOSAPI,
                        param1val=row_start,
                        param2val=current_row-1)
        current_row+=1
        return current_row

    zmx.set_MFE_row(op_types.BLNK, start_at_row, MFE, ZOSAPI,
                        param1val= "Radius")
    MFE.AddOperand()
    start_at_row+=1

    Hxs = list(np.arange(-1.0, 1.1, 0.1))
    Hys = [0.0] * len(Hxs)
    px, py = -1.0, 0.0
    row1 = ap_diameter(px, py, Hxs, Hys, start_at_row,
                      'xm')

    px, py = 1.0, 0.0
    row2 = ap_diameter(px, py, Hxs, Hys, row1,'xp')

    current_row = row2
    zmx.set_MFE_row(op_types.CONS,
                    current_row, MFE, ZOSAPI,
                    target=-1)

    MFE.AddOperand()
    current_row+=1
    zmx.set_MFE_row(op_types.PROD,
                    current_row, MFE, ZOSAPI,
                    param1val=current_row-1,
                    param2val=current_row-2)

    MFE.AddOperand()
    current_row+=1
    zmx.set_MFE_row(op_types.OPVA,
                    current_row, MFE,ZOSAPI,
                    param1val=row1-1)

    MFE.AddOperand()
    current_row+=1
    zmx.set_MFE_row(op_types.MAXX,
                    current_row, MFE, ZOSAPI,
                    param1val=current_row-2,
                    param2val=current_row-1,
                    target=radius_mm,
                    weight=weight)

    MFE.AddOperand()
    current_row+=1
    zmx.set_MFE_row(op_types.BLNK, current_row, MFE, ZOSAPI,
                        param1val= "Collimate")

    MFE.AddOperand()
    current_row+=1
    zmx.set_MFE_row(op_types.EQUA,
                    current_row, MFE, ZOSAPI,
                    param1val=start_at_row,
                    param2val=row1-2,
                    weight=1e5)

    MFE.AddOperand()
    current_row+=1
    zmx.set_MFE_row(op_types.EQUA,
                    current_row, MFE, ZOSAPI,
                    param1val=row1,
                    param2val=row1 + (row1-start_at_row)-2,
                    weight=1e5)

    return current_row

def write_img_qual_MF(MFE, row_start, weight):
    w = MFE.SEQOptimizationWizard
    w.Data=1
    w.OverallWeight=weight
    w.Ring = 5;
    w.Arms=1

    w.IsGlassUsed = False;
    w.IsAirUsed = False
    w.IsAssumeAxialSymmetryUsed = False
    w.Configuration = 1

    w.StartAt = row_start+3
    w.Apply();
    MFE.RemoveOperandAt(row_start+5)

initialize_merit_function(MFE)

current_row = write_L321_diameter_constraints(MFE, 3, L321_surf_num, L321_diameter_mm)

current_row = write_thickness_constraints(MFE, current_row+1)

f_cen_row = write_fnumber(MFE, current_row+1, 0, 0, 'x')
f_side1_row = write_fnumber(MFE, f_cen_row+1, 0, 1, 'x')
f_side2_row = write_fnumber(MFE, f_side1_row+1, 0, 1, 'y')

current_row = write_fnum_constraint(MFE, f_side2_row+1,
                      f_side2_row, f_cen_row)

weight_pri_footprint = 1e6
current_row = write_primary_footprint(MFE, current_row,
                                      0.0, 0.0,
                                      Npoints=16,
                                      weight=weight_pri_footprint)

current_row = write_primary_footprint(MFE, current_row,
                                      1.0, 0.0,
                                      Npoints=16,
                                      weight=weight_pri_footprint)

current_row = write_primary_footprint(MFE, current_row,
                                      -1.0, 0.0,
                                      Npoints=16,
                                      weight=weight_pri_footprint)

current_row = write_primary_footprint(MFE, current_row,
                                      0.0, 1.0,
                                      Npoints=16,
                                      weight=weight_pri_footprint)

current_row = write_primary_footprint(MFE, current_row,
                                      0.0, -1.0,
                                      Npoints=16,
                                      weight=weight_pri_footprint)

current_row = write_telecentric_angle_cons(MFE,
                                           current_row+1)

current_row = write_primary_aperture_diameter(MFE, current_row+1,
                                              radius_mm=2450.0)

write_img_qual_MF(MFE, current_row, weight=0.5)

TheSystem.UpdateStatus()

import os
fname_out = os.path.join(os.path.abspath('./'),
                         'groups_info/merit_function.MF')
MFE.SaveMeritFunction(fname_out)


'''

'''

def subset_sum(n, s_value, array):
    s_set = set(s_value)

    array.sort()

    cur_sum = 0

    for i in array:
        temp = cur_sum + i
        if temp in s_set:
            cur_sum = temp
            s_set.remove(temp)
    return array

if __name__ == "__main__":
    test_cases = int(input())
    for test in range(test_cases):
        n = int(input())
        s_value = list(map(int, input().split()))
        array = list(range(n))
        result = subset_sum(n, s_value, array)
        print(" ".join(str(i) for i in result))


import datetime

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.chrome.options import Options

chrome_opt = Options()      # keep it open
chrome_opt.add_experimental_option('detach', True)
# from get_flight_data import FlightSearch

go_port = 'HKG'     # assumed we can get this result from previous operation
dest_port = 'NRT'
# flight_info = FlightSearch(current_port=go_port, dest_port=dest_port)
now = datetime.datetime.now()

go_date = now + datetime.timedelta(days=3) #departure date
back_date = go_date + datetime.timedelta(days=3) #return date

month_dict = {1: "January", 2: "February", 3: "March", 4: "April", 5: "May", 6: "June",
              7: "July", 8: "August", 9: "September", 10: "October", 11: "November", 12: "December"}

path = Service('chromedriver.exe')

class buy_ticket:
    def __init__(self):
        self.go_buy()

    def go_buy(self):
        driver = webdriver.Chrome(service=path, chrome_options=chrome_opt)

        driver.get('https://www.cathaypacific.com/cx/en_HK/book-a-trip.html')

        start_port = driver.find_element(By.XPATH, '//*[@id="depart-label"]')  # departure airport choice
        start_port.send_keys(go_port)
        start_port.send_keys(Keys.ENTER)

        end_port = driver.find_element(By.XPATH, '//*[@id="destination-label"]')  # destination airport choice
        end_port.send_keys(dest_port)
        end_port.send_keys(Keys.ENTER)

        dep_date = driver.find_element(By.XPATH, '//*[@id="dpuxzabv"]/span[2]/span[3]')  #departure date choice
        dep_date.click()

        # first_month = driver.find_element(By.XPATH, '//*[@id="dp1668851740859"]/div/div[1]/table/caption/span[1]')  # calender front part month
        # second_month = driver.find_element(By.XPATH, '//*[@id="dp1668851740859"]/div/div[2]/table/caption/span[1]')  #calender last part month

        # if first_month.text == month_dict[ flight_info.date.month]:  # departure date in first month choice

        calendar_dep_day = driver.find_elements(By.CLASS_NAME, 'ui-state-default')[::-1] # inverse to make sure it's valid even when it go to second month
        departure_day = go_date.day
        for ele in calendar_dep_day:
            if ele.text == departure_day:
                try:
                    ele.click()
                except NoSuchElementException:
                    continue

        re_day = driver.find_element(By.XPATH, '//*[@id="dppdvs3"]/span[2]/span[3]')  # return date choice
        re_day.click()

        calendar_re_day = driver.find_elements(By.CLASS_NAME, 'ui-state-default')[::-1] # inverse to make sure it's valid even when it go to second month
        play_duration = datetime.timedelta(days=3)
        return_day = back_date.day
        for ele in calendar_re_day:
            if ele.text == return_day:
                try:
                    ele.click()
                except NoSuchElementException:
                    continue

        submit_btm = driver.find_element(By.XPATH, '//*[@id="book-trip-flight"]/div[1]/form/button')
        submit_btm.click()


def check_instructions(instructions, instruction_table, dependency_table):
    '''Judging the rationality of instructions
    instructions :instruction set
    instruction_table :Supported Instruction Tables
    dependency_table :Instruction Dependency Table
    '''
    invalid_instructions = []
    for i in range(len(instructions)):
        if isinstance(instructions, dict):
            instruction = instructions[i]['instruction_name']
        else:
            instruction = instructions[i]
        if instruction not in instruction_table:
            invalid_instructions.append(instruction)
        else:
            dependencies = dependency_table.get(instruction, [])
            for dependency in dependencies:
                if dependency not in instructions[:i]:
                    invalid_instructions.append(instruction)
                    break
    return invalid_instructions
class instruction_parameters():
    def __init__(self,instruction_parameters_data:dict|None) -> None:
        self.parameters = instruction_parameters_data
    def get(self,parameter_name:str) -> str|bool|None:
        '''
        If False is return, then parameter not found \n
        If None is return, then No parameters used, parameters not found \n
        '''
        try:
            return self.parameters.get(parameter_name)
        except KeyError:
            return False
            raise KeyError(f'parameter not found:{parameter_name}')
        except AttributeError:
            return None
            raise AttributeError(f"No parameters used, parameters not found:'{parameter_name}'")
class Execution:
    def __init__(self,instruction,instruction_name_list:list,instruction_func_list:list,global_parameters:dict):
        '''Responsible for parsing each instruction'''
        self.instruction = instruction
        self.instruction_name_list = instruction_name_list
        self.instruction_func_list = instruction_func_list
        self.global_parameters = global_parameters # global's parameters
    def extract_command(self):
        if isinstance(self.instruction, dict):
            self.instruction_name = self.instruction['instruction_name']
            self.instruction_parameters = instruction_parameters(self.instruction['instruction_parameters'])
        else:
            self.instruction_name = self.instruction
            self.instruction_parameters = instruction_parameters(instruction_parameters_data=None)
    def execute(self):
        '''Execute the instruction'''
        try:
            self. extract_command()
            if self.instruction_name in self.instruction_name_list:
                # Call the corresponding method based on the instruction name
                if isinstance(self.instruction_func_list, list):
                    result = self.instruction_func_list[self.instruction_name_list.index(self.instruction_name)](self.instruction_parameters)
                else:
                    # Extract functions from modules through strings
                    result = getattr(self.instruction_func_list, self.instruction_name)(self.instruction_parameters)
                return result
            else:
                raise ValueError(f"Invalid instruction: {self. instruction_name}")
        except Exception as e:
            # Handle the error appropriately
            ep = f"Error executing instruction: {e}"
            return ep

    def _execute_example_instruction(self, parameters):
        # Implement the logic for executing the "example_instruction" here
        # Use the parameters as needed
        # Return the result of the execution
        pass

def run(instruction_set: list,
        instruction_name_list:list,
        instruction_func_list:list|object,
        dependency_table:dict={},
        global_parameters:dict|None = None) -> list:
    '''This function is a function that utilizes the instruction set to operate on another
    Parameters:
        instruction_set: Instruction set, which is a list of dictionaries:
        >>> instruction_set = [{'instruction_name': "<instruction_name>", <instruct_parameters>...}]
        >>> instruction_name_list = [<instruct1>,<instruct2>,...]
        >>> instruction_func_list = [<instruct_func1>,<instruct_func2>,...]
        >>> global_parameters = {'other':<other:obj>}
        >>> # instruction_func_list = module_name # Extract functions from modules through strings
        >>> dependency_table = {<instruct1>:[<instruct2>,<instruct3>],...}
        >>> # Instructions: dependent instructions of instructions (Need to execute an instruction dependent instruction first)
        >>> def instruct_func1(parameters:dict({'parameters':value})|None):
        >>>     return <execution_results>
    Usage method:
        >>> run(instruction_set,instruction_name_list,instruction_func_list,dependency_table,global_parameters)
    '''
    if not dependency_table == {} :

        invalid_instructions = check_instructions(instruction_set,instruction_name_list,dependency_table)

        if invalid_instructions:
            e = 'The following instructions have dependency issues: '
            for invalid_instruction in invalid_instructions:
                e += f'"{invalid_instruction}",'
            raise ValueError(e)

    # Define a helper function for executing a single instruction
    def execute_instruction(instruction):
        executor = Execution(instruction,instruction_name_list,instruction_func_list,global_parameters)
        return executor.execute()

    # Execute instructions synchronously
    results = []
    for instruction_index in range(len(instruction_set)):
        results.append(execute_instruction(instruction_set[instruction_index]))

    return results

def mod_js():
    from fileApi.file import New as file
    f = file('.\sdk\instructs\\')
    return f.openr('requests_instructs.js')


import fnmatch
import os
import shlex
import time

def _combine(*iterables):
    iterables = [iter(iterable) for iterable in iterables]
    size = len(iterables)
    while True:
        to_yield = [None] * size
        for idx, iterable in enumerate(iterables):
            if iterable is None:
                continue
            try:
                to_yield[idx] = iterable.next()
            except StopIteration:
                iterables[idx] = None
        if not [iterable for iterable in iterables if iterable is not None]:
            break
        yield tuple(to_yield)

class CommandLine(object):
    """Simple helper for executing subprocesses."""

    def __init__(self, executable, args, input=None, cwd=None):
        """Initialize the CommandLine object.

        :param executable: the name of the program to execute
        :param args: a list of arguments to pass to the executable
        :param input: string or file-like object containing any input data for
                      the program
        :param cwd: the working directory to change to before executing the
                    command
        """
        self.executable = executable
        self.arguments = [str(arg) for arg in args]
        self.input = input
        self.cwd = cwd
        if self.cwd:
            assert os.path.isdir(self.cwd)
        self.returncode = None

    if os.name == 'nt': # windows

        def execute(self, timeout=None):
            """Execute the command, and return a generator for iterating over
            the output written to the standard output and error streams.

            :param timeout: number of seconds before the external process
                            should be aborted (not supported on Windows)
            """
            args = [self.executable] + self.arguments
            for idx, arg in enumerate(args):
                if arg.find(' ') >= 0:
                    args[idx] = '"%s"' % arg
            #log.debug('Executing %s', args)

            if self.cwd:
                old_cwd = os.getcwd()
                os.chdir(self.cwd)

            import tempfile
            in_name = None
            if self.input:
                if isinstance(self.input, basestring):
                    in_file, in_name = tempfile.mkstemp(prefix='bitten_',
                                                        suffix='.pipe')
                    os.write(in_file, self.input)
                    os.close(in_file)
                    in_redirect = '< "%s" ' % in_name
                else:
                    in_redirect = '< "%s" ' % self.input.name
            else:
                in_redirect = ''

            out_file, out_name = tempfile.mkstemp(prefix='bitten_',
                                                  suffix='.pipe')
            os.close(out_file)
            err_file, err_name = tempfile.mkstemp(prefix='bitten_',
                                                  suffix='.pipe')
            os.close(err_file)

            try:
                cmd = '( %s ) > "%s" %s 2> "%s"' % (' '.join(args), out_name,
                                                    in_redirect, err_name)
                self.returncode = os.system(cmd)
                #log.debug('Exited with code %s', self.returncode)

                out_file = file(out_name, 'r')
                err_file = file(err_name, 'r')
                out_lines = out_file.readlines()
                err_lines = err_file.readlines()
                out_file.close()
                err_file.close()
            finally:
                if in_name:
                    os.unlink(in_name)
                if out_name:
                    os.unlink(out_name)
                if err_name:
                    os.unlink(err_name)
                if self.cwd:
                    os.chdir(old_cwd)

            for out_line, err_line in _combine(out_lines, err_lines):
                yield out_line and out_line.rstrip().replace('\x00', ''), \
                      err_line and err_line.rstrip().replace('\x00', '')

    else: # posix

        def execute(self, timeout=None):
            """Execute the command, and return a generator for iterating over
            the output written to the standard output and error streams.

            :param timeout: number of seconds before the external process
                            should be aborted (not supported on Windows)
            """
            import popen2, select
            if self.cwd:
                old_cwd = os.getcwd()
                os.chdir(self.cwd)

            #log.debug('Executing %s', [self.executable] + self.arguments)
            pipe = popen2.Popen3([self.executable] + self.arguments,
                                 capturestderr=True)
            if self.input:
                if isinstance(self.input, basestring):
                    in_data = self.input
                else:
                    in_data = self.input.read()
            else:
                pipe.tochild.close()
                in_data = ''

            out_data, err_data = [], []
            in_eof = out_eof = err_eof = False
            if not in_data:
                in_eof = True
            while not out_eof or not err_eof:
                readable = [pipe.fromchild] * (not out_eof) + \
                           [pipe.childerr] * (not err_eof)
                writable = [pipe.tochild] * (not in_eof)
                ready = select.select(readable, writable, [], timeout)
                if not (ready[0] or ready[1]):
                    raise TimeoutError('Command %s timed out' % self.executable)
                if pipe.tochild in ready[1]:
                    sent = os.write(pipe.tochild.fileno(), in_data)
                    in_data = in_data[sent:]
                    if not in_data:
                        pipe.tochild.close()
                        in_eof = True
                if pipe.fromchild in ready[0]:
                    data = os.read(pipe.fromchild.fileno(), 1024)
                    if data:
                        out_data.append(data)
                    else:
                        out_eof = True
                if pipe.childerr in ready[0]:
                    data = os.read(pipe.childerr.fileno(), 1024)
                    if data:
                        err_data.append(data)
                    else:
                        err_eof = True
                out_lines = self._extract_lines(out_data)
                err_lines = self._extract_lines(err_data)
                for out_line, err_line in _combine(out_lines, err_lines):
                    yield out_line, err_line
                #time.sleep(.1)
            self.returncode = os.WEXITSTATUS(pipe.wait())
            #log.debug('%s exited with code %s', self.executable,
            #          self.returncode)

            if self.cwd:
                os.chdir(old_cwd)

    def _extract_lines(self, data):
        extracted = []
        def _endswith_linesep(string):
            for linesep in ('\n', '\r\n', '\r'):
                if string.endswith(linesep):
                    return True
        buf = ''.join(data)
        lines = buf.splitlines(True)
        if len(lines) > 1:
            extracted += lines[:-1]
            if _endswith_linesep(lines[-1]):
                extracted.append(lines[-1])
                buf = ''
            else:
                buf = lines[-1]
        elif _endswith_linesep(buf):
            extracted.append(buf)
            buf = ''
        data[:] = [buf] * bool(buf)

        return [line.rstrip() for line in extracted]

def locate(fn):
    """Locates a binary on the path.

    Returns the fully-qualified path, or None.
    """
    if os.name == 'nt':
        fn += '.exe'

    for p in ["."] + os.environ['PATH'].split(os.pathsep):
        f = os.path.join(p, fn)
        if os.path.exists(f):
            return f
    return None


# Access log parser v1.0
# Author: Sergei Safarov <inbox@sergeysafarov.com>

import csv
import os
import re
import sys
import geoip2.database
import wget
import gzip
import shutil
import glob

from os import path
from user_agents import parse

########################################################################################################################
# Functions declarations
# Start
########################################################################################################################

def file_name(filename):
    return os.path.splitext(os.path.basename(filename))[0]

def file_size(filename):
    return os.path.getsize(filename)

########################################################################################################################
# Settings
########################################################################################################################
deafult_log_file = 'https://cti-developer-dropbox.s3.amazonaws.com/gobankingrates.com.access.log'

lang = 'en'
input_file = 'log/access.log'
geoip_database = 'GeoLite2-Country.mmdb'
geoip_db_source = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz'

########################################################################################################################
# Script body
########################################################################################################################

if not path.exists(input_file):
    print('Access log file not found in local folder. Trying to download from default remote location ' + deafult_log_file)
    wgt_result = wget.download(deafult_log_file, 'log/')
    if wgt_result:
        print('Access log file downloaded from default remote location.')
        file_list = glob.glob ('log/*.log')
        if len(file_list) > 0 and path.exists(file_list[0]):
            input_file = file_list[0]
            print('Using downloaded file ' + input_file)

if not path.exists(input_file):
    sys.exit('Inboud log file not found. Stopped')

if_size = file_size(input_file)

if if_size == 0:
    sys.exit('Inboud log file is empty. Stopped')

if not path.exists(geoip_database):
    print('Geo IP database not found. Trying to download from ' + geoip_db_source)
    wgt_result = wget.download(geoip_db_source)
    if wgt_result:
        with gzip.open('GeoLite2-Country.mmdb.gz', 'rb') as f_in:
            with open('GeoLite2-Country.mmdb', 'wb') as f_out:
                print('Geo IP database downloaded. Extracting.')
                shutil.copyfileobj(f_in, f_out)
                print('Geo IP database extracted.')
        # Clean downloaded compressed db file
        if path.exists('GeoLite2-Country.mmdb.gz'):
            os.remove('GeoLite2-Country.mmdb.gz')

if not path.exists(geoip_database):
    print('Geo IP database not found. Countries will not be retrieved. ')
    print('Please obtain the database ' + geoip_database + ' file and put it into the script folder')
else:
    geo_ip_reader = geoip2.database.Reader(geoip_database)

output_file = file_name(input_file) + '.csv'

print('Parsing ' + input_file + ' [' + str(if_size) + ' bytes]')
print('Writing ' + output_file)

with open(input_file, encoding="UTF8") as fi, open(output_file, 'w', encoding="UTF8") as fo:
    writer = csv.writer(fo, quotechar='"', quoting=csv.QUOTE_NONNUMERIC)
    writer.writerow(['#', 'IP', 'Country', 'Browser', 'Device', 'Type', 'RAW LINE'])

    i = 1
    for line in fi:
        sys.stdout.write("Processing line: %d   \r" % (i))
        sys.stdout.flush()

        ip_address = re.findall(r'[0-9]+(?:\.[0-9]+){3}', line)[0]
        try:
            # No problems here in case of geo DB not found as we are inside try/except block
            location = geo_ip_reader.country(ip_address)

            if location and location.country and location.country.names:
                country = location.country.names[lang]
            else:
                country = 'N/A'
        except:
            country = 'N/A'

        try:
            line_parts = re.findall(r'\"(.+?)\"', line)
            ua_record = line_parts[len(line_parts) - 1]
            parsed_ua = parse(ua_record)

            browser = parsed_ua.browser.family
            device_family = parsed_ua.device.family

            if parsed_ua.is_mobile:
                device_type = 'Mobile'
            elif parsed_ua.is_tablet:
                device_type = 'Tablet'
            elif parsed_ua.is_pc:
                device_type = 'Desktop'
            elif parsed_ua.is_bot:
                device_type = 'Bot'
            else:
                device_type = 'Unknown'
        except:
            browser = 'N/A'
            device_family = 'N/A'
            device_type = 'N/A'

        writer.writerow([i, ip_address, country, browser, device_family, device_type, line])
        i += 1

print("Parsing finished. " + str(i - 1) + " lines processed.")