import os
import time
from itertools import chain
from scipy.stats import pearsonr
import numpy as np
import torch as pt
import torch.nn as nn
from torch import optim
from Layers.GGR import ESGGR

class MTAweGNN(nn.Module):

    def __init__(self, layer_list, eta_rng=None, kappa_rng=(2, 5), tau_rng=(0.5, 1.5), ker='lor', datasets=['LC50DM','LC50','IGC50','LD50'],
                 model_num='', opt='AMSGrad', betas=(0.9, 0.999)):

        # Allow methods from nn.Module
        super(MTAweGNN, self).__init__()

        # Initialize the geometric graph representation layer and the input normalization layer
        self.GGR = ESGGR(eta_rng=eta_rng, kappa_rng=kappa_rng, ker=ker, tau_rng=tau_rng)
        self.scaling = nn.BatchNorm1d(self.GGR.num_feat)

        # Add the hidden layers
        self.layers = nn.ModuleList(layer_list)

        # Find the number of features of the last hidden layer
        i = 1
        while True:
            print(i)
            try:
                num_neurons_last_layer = layer_list[-i].out_features
                break
            except:
                i += 1

        # Add the output layers
        self.out = nn.ModuleList([nn.Linear(num_neurons_last_layer, 1) for _ in datasets])

        # Initialize the chosen optimizer
        if opt == 'Adam':
            self.optimizer = optim.Adam(self.parameters(), 0, betas=betas)
        if opt == 'AMSGrad':
            self.optimizer = optim.Adam(self.parameters(), 0, betas=betas, amsgrad=True)
        if opt == 'RMSprop':
            self.optimizer = optim.RMSprop(self.parameters(), 0, momentum=betas[0], centered=False)
        if opt == 'SGD':
            self.optimizer = optim.SGD(self.parameters(), 0, momentum=betas[0], nesterov=False)
        if opt == 'Adagrad':
            self.optimizer = optim.Adagrad(self.parameters(), 0)

        # Record intial options for saving
        self.kappa_rng = kappa_rng
        self.eta_rng = eta_rng
        self.tau_rng = tau_rng
        self.ker = ker
        self.opt = opt
        self.betas = betas
        self.datasets = datasets
        self.model_num = model_num

        # Initialize modes
        self.save_mode = False
        self.stats_mode = False

        # Other attributes for saving
        self.save_sched = [0]
        self.save_directory = os.getcwd()
        self.model_stats = None

        # Keep a running tally of the amount of time it takes to complete an epoch
        self.time_list = []

    def forward(self, data_list):
        # Record a staggered number of samples in each data set for later
        n = [0]
        for i in range(len(data_list)):
            n.append(n[-1] + len(data_list[i][0]))

        # Combine the distances and sparse indices from each data set separately
        dist = list(chain(*[data[0] for data in data_list]))
        spar_ind = np.concatenate([data[1] for data in data_list], axis=0)

        # Combine into one piece of data for input
        X = (dist, spar_ind)

        # Run through the input layer
        X = self.GGR(X)
        X = self.scaling(X)

        # Run through the hidden layers
        for layer in self.layers:
            X = layer(X)

        # Split the samples up, then run through the separate outputs
        hidden_out = [X[n[i]:n[i+1], :] for i in range(len(data_list))]
        return tuple(self.out[i](hidden_out[i]) for i in range(len(data_list)))

    def test(self, x_list):
        self.eval()
        y_list = self(x_list)
        self.train()
        return y_list

    def display_stats(self, y_train_list, y_train_hat_list, y_test_list, y_test_hat_list, epoch):

        # Display the relevant statistics
        if len(self.time_list) != 0:
            print('Epoch %d completed in %.2f sec. Average completion time is %.2f sec'%(epoch, self.time_list[-1], sum(self.time_list)/(epoch)))
        for i, data_name in enumerate(self.datasets):
            print(data_name)
            print('-----')
            print('Train MAE:', pt.sum(pt.abs(y_train_hat_list[i] - y_train_list[i]) / y_train_list[i].shape[0]).item())
            print('Train RMSE:', pt.sqrt(pt.sum((y_train_hat_list[i] - y_train_list[i])**2) / y_train_list[i].shape[0]).item())
            print('Train pearson:', pearsonr(y_train_hat_list[i].detach().cpu().view(-1), y_train_list[i].cpu().detach().view(-1))[0])
            print('')
            print('Test MAE:', pt.sum(pt.abs(y_test_hat_list[i] - y_test_list[i]) / y_test_list[i].shape[0]).item())
            print('Test RMSE:', pt.sqrt(pt.sum((y_test_hat_list[i] - y_test_list[i])**2) / y_test_list[i].shape[0]).item())
            print('Test R2 score:', pearsonr(y_test_hat_list[i].cpu().detach().view(-1), y_test_list[i].cpu().detach().view(-1))[0]**2)
            print('----------------------------------')

    def save(self, y_train_hat_list, y_test_hat_list, epoch):

        # Get strings representing the hidden layers, betas, and learning schedule
        lay_str = '-'.join([str(w.shape[0]) for w in self.parameters() if len(w.shape) == 2])[:-2*len(self.datasets)]
        lr_sched_str = str(self.lr_sched[0])+'-'+str(self.lr_sched[1])
        betas_str = str(self.betas[0])+'-'+str(self.betas[1])

        # Figure out tau or eta initialization
        if self.tau_rng != None:
            param_str = f'_tau{self.tau_rng[0]}-{self.tau_rng[1]}'
        else:
            param_str = f'_eta{self.eta_rng[0]}-{self.eta_rng[1]}'

        # Write the base filename
        stats_filename = ('MT_'+'_'.join(self.datasets)+'_epochs'+str(self.total_epochs)+'_batch'+str(self.num_batches)+
                          '_lay'+lay_str+'_lr'+str(self.lr)+'_alpha'+str(self.alpha)+param_str+'_kappa'+str(self.kappa_rng[0])+
                          '-'+str(self.kappa_rng[1])+'_ker'+self.ker+'_opt'+self.opt+'_lrsch'+lr_sched_str+'_betas'+
                          betas_str+'_model'+self.model_num)

        # Initialize recording of the statistics for the first time
        if epoch == 0:
            self.model_stats = {'saved_etas':pt.zeros(self.GGR.num_grps, self.total_epochs+1),
                                'saved_kappas':pt.zeros(self.GGR.num_grps, self.total_epochs+1),
                                'model_state':{}}
            for i, data_name in enumerate(self.datasets):
                self.model_stats[f'{data_name}_train_predictions'] = pt.zeros(len(y_train_hat_list[i]), self.total_epochs+1)
                self.model_stats[f'{data_name}_test_predictions'] = pt.zeros(len(y_test_hat_list[i]), self.total_epochs+1)
        # Or change the existing statistics
        else:
            self.model_stats['saved_etas'][:, epoch] = self.GGR.eta.detach().cpu()
            self.model_stats['saved_kappas'][:, epoch] = self.GGR.kappa.detach().cpu()
            for i, data_name in enumerate(self.datasets):
                self.model_stats[f'{data_name}_train_predictions'][:, epoch] = y_train_hat_list[i].view(-1).detach().cpu()
                self.model_stats[f'{data_name}_test_predictions'][:, epoch] = y_test_hat_list[i].view(-1).detach().cpu()

        # Record statistics dictionary at special times (default: beginning and end)
        if epoch in self.save_sched:
            stats_dict = {'model_state_dict':self.state_dict(),
                          'optimizer_state_dict':self.optimizer.state_dict(),
                          'save_schedule':self.save_sched,
                          'scheduler':self.scheduler,
                          'time_list':self.time_list}

            self.model_stats['model_state'][epoch] = stats_dict

        # Save the model statitics dictionary into the specified save directory (default: current directory)
        pt.save(self.model_stats, f'{self.save_directory}/{stats_filename}')

    def fit(self, D_train_list, y_train_list, D_test_list, y_test_list, lr=0.001, total_epochs=2000, num_batches=20, alpha=0, start=1,
            lr_sched=None):

        # Set the variables for potential saving access
        self.lr = lr
        self.total_epochs = total_epochs
        self.num_batches = num_batches
        self.alpha = alpha
        self.lr_sched = lr_sched
        self.save_sched.append(total_epochs)

        # Set the loss function
        loss_function = nn.MSELoss()

        # Sets the parameter learning rates
        for param_group in self.optimizer.param_groups:
            param_group['lr'] = lr
            param_group['initial_lr'] = lr

        # Set the learning rate scheduler
        if lr_sched != None:
            self.scheduler = optim.lr_scheduler.StepLR(self.optimizer, lr_sched[0], lr_sched[1])
        else:
            self.scheduler = None

        # Gather the distance data, sparse indices, number of samples, and batch_sizes for each data set separately
        D_list = [pair[0] for pair in D_train_list]
        spar_ind_list = [pair[1] for pair in D_train_list]
        num_samp_list = [len(D) for D in D_list]
        batch_size_list = [num_samp//num_batches for num_samp in num_samp_list]

        # Preliminarily save or display stats
        if start == 1 and (self.save_mode == True or self.stats_mode == True):

            # Run through full train and test data
            y_train_hat_list = self.test(D_train_list)
            y_test_hat_list = self.test(D_test_list)

            # Save and/or display stats
            if self.save_mode == True:
                self.save(y_train_hat_list, y_test_hat_list, epoch=0)
            if self.stats_mode == True:
                self.display_stats(y_train_hat_list, y_train_list, y_test_hat_list, y_test_list, epoch=0)

        # Begin the fitting at the given starting epoch
        for epoch in range(start, total_epochs+1):

            # Start the timer for the epoch
            start_time = time.time()

            print('epoch', epoch)
            print('----------------------------------')

            # Mix the indices
            idx_list = [np.random.choice(num_samp, num_samp, replace=False) for num_samp in num_samp_list]

            for param_group in self.optimizer.param_groups: # sets the parameter learning rates
                print(param_group['lr'])

            print('epoch', epoch)
            print('----------------------------------')

            # Go through each mini-batch
            for batch_num in range(1, num_batches+1):

                print('batch', batch_num)

                # Get the batch indices for each data set
                batch_idx_list = []
                for i, batch_size in enumerate(batch_size_list):

                    start = (batch_num - 1) * batch_size  # Get the starting index
                    if batch_num == num_batches:  # Go to the end of the list for the last batch
                        end = num_samp_list[i]
                    else:
                        end = batch_num * batch_size
                    batch_idx_list.append(list(idx_list[i][start:end]))

                # Get the batches for each data set
                batch_list = []
                for i in range(len(D_list)):
                    batch_list.append(([D_list[i][ind] for ind in batch_idx_list[i]], spar_ind_list[i][batch_idx_list[i]]))

                # Run batches through to get all the outputs
                y_hats = self(batch_list)

                # Get the average of the losses
                loss = sum([loss_function(y_hats[i], y_train_list[i][batch_idx_list[i]]) for i in range(len(D_list))]) / len(D_list)

                # Regularization
                for w in self.parameters():
                    if len(w.shape) == 2:
                        loss += alpha*pt.sum(w**2)

                print('train loss:', loss.item())
                print('--------------')

                # Back propagation and reset gradient
                loss.backward()
                self.optimizer.step()
                self.optimizer.zero_grad()

            # Update the scheduler if there is one
            if lr_sched != None:
                self.scheduler.step()

            # Add time to list
            self.time_list.append(time.time()-start_time)

            # Preliminarily save or display stats
            if self.save_mode == True or self.stats_mode == True:

                # Run through full train and test data
                y_train_hat_list = self.test(D_train_list)
                y_test_hat_list = self.test(D_test_list)

                # Save and/or display stats
                if self.save_mode == True:
                    self.save(y_train_hat_list, y_test_hat_list, epoch=epoch)
                if self.stats_mode == True:
                    self.display_stats(y_train_hat_list, y_train_list, y_test_hat_list, y_test_list, epoch=epoch)


import argparse
import sys
from datetime import datetime
from datetime import timedelta

import requests
from pycoingecko import CoinGeckoAPI
from rich.console import Console
from rich.progress import Progress
from rich.table import Table

__author__ = "a9lli"
__copyright__ = "a9lli"
__license__ = "MIT"

TIMESPANS = {
    '24h': timedelta(days=1),
    '48h': timedelta(days=2),
    '7d': timedelta(days=7),
    '14d': timedelta(days=14),
    '30d': timedelta(days=30)
}

CURRENCIES = {
    'eur': '€',
    'usd': '$'
}

def beautify(h: dict):
    console = Console()

    name = ' '.join(h["name"].split('-')).title()
    console.print(f'Name: [bold red]{name}[/bold red]')

    if 'online' in h['status']:
        status = ':green_circle:'
    else:
        status = ':red_circle:'
    console.print(f'Status: {status}')

    reward_scale = h["reward_scale"]
    if reward_scale >= 75:
        reward_color = 'green'
    elif reward_scale >= 50:
        reward_color = 'yellow'
    else:
        reward_color = 'red'
    console.print(f'Reward scale: [bold {reward_color}]{reward_scale} %'
                  f'[/bold {reward_color}]')

    console.print(f'Witnesses: {h["witnesses"]}')

    currency = h['currency']
    cg = CoinGeckoAPI()
    crcy = cg.get_price(ids='helium', vs_currencies=currency).get('helium').get(currency)

    hnt_reward_last = round(h["rewards_last"], 3)
    eur_reward_last = round(crcy * hnt_reward_last, 2)

    table = Table(show_header=True, header_style="bold")
    table.add_column("Date")
    table.add_column("Reward amount", justify="center")
    table.add_column("Reward type", justify="center")

    for r in h['rewards']:
        table.add_row(
            f'{r["time"]}',
            f'[bold]{round(r["amount"], 3):.3f}[/bold] HNT',
            r["type"]
        )

    console.print(table)

    console.print(f'Total reward in last {h["last"].days} days: '
                  f'{hnt_reward_last} HNT ({eur_reward_last}{CURRENCIES[currency]})')
    console.print()

def do_magic(args, progress):
    base_url = f'https://api.helium.io/v1/hotspots/{args.wallet_id}'
    activity_url = f'{base_url}/activity'
    witness_url = f'{base_url}/witnesses'

    task = progress.add_task("[red]Fetching wallet data...", total=100)

    r = requests.get(base_url)
    data = r.json().get('data')
    if not data:
        print('Invalid wallet id or an error occurred')
        exit(1)
    progress.update(task, advance=25)

    r = requests.get(witness_url)
    witnesses = len(r.json().get('data'))
    progress.update(task, advance=50)

    hotspot = {
        'name': data['name'],
        'status': data['status']['online'],
        'reward_scale': round(data['reward_scale'] * 100, 2),
        'witnesses': witnesses,
        'rewards': []
    }

    r = requests.get(activity_url)
    cursor = r.json().get('cursor')
    progress.update(task, advance=75)
    r = requests.get(activity_url, params={'cursor': cursor}).json()
    data = r.get('data')
    reward_amount_last = 0.
    while True:
        for d in data:
            if 'rewards' in d.keys():
                reward_time = datetime.fromtimestamp(d['time'])
                if reward_time < datetime.today() - TIMESPANS[args.last]:
                    break
                for reward in d['rewards']:
                    reward_amount = reward['amount'] / 1e8
                    reward_type = reward['type'].replace('poc_', '')
                    hotspot['rewards'].append({
                        'time': reward_time,
                        'type': reward_type,
                        'amount': reward_amount
                    })
                    reward_amount_last += reward_amount
        cursor = r.get('cursor')
        if cursor is None:
            break
        r = requests.get(activity_url, params={'cursor': cursor}).json()
        data = r.get('data')
    hotspot['rewards_last'] = reward_amount_last
    hotspot['last'] = TIMESPANS[args.last]
    hotspot['currency'] = args.currency
    progress.update(task, advance=100)
    return hotspot

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=f'Track your Helium '
                                                 f'wallet activities')
    parser.add_argument(dest='wallet_id',
                        help='Helium wallet ID',
                        type=str)
    parser.add_argument('--last',
                        choices=['24h', '48h', '7d', '14d', '30d'],
                        default='24h',
                        help='Select between different time periods')
    parser.add_argument('--currency',
                        choices=['eur', 'usd'],
                        default='eur',
                        help='Choose preferred currency')

    if len(sys.argv) == 1:
        parser.print_usage()
        sys.exit(1)

    args = parser.parse_args(sys.argv[1:])
    Console().clear()
    with Progress(transient=True) as progress:
        hotspot = do_magic(args, progress)
    beautify(hotspot)


import cv2
import matplotlib.pyplot as plt
import numpy as np
from Word_segmentation import word
from segment_lines import line_segment
from questionHistogram import projection
from Question_segmentation import question

question_partitions = []
line_partitions = []
character_partitions = []
word_partitions = []

def segmentation(Thresh_Image, axis_value):

    final_Image = Thresh_Image.copy();

    height, width = Thresh_Image.shape
    print("Height : ", height)
    print("Width : ", width)

    Thresh_Image[Thresh_Image == 0] = 1
    Thresh_Image[Thresh_Image == 255] = 0

    horizontal_projection = np.sum(Thresh_Image, axis_value)
    print(horizontal_projection)
    #
    blankImage = np.zeros((height, width, 3), np.uint8)

    for row in range(height):
        cv2.line(blankImage, (0, row), (int(horizontal_projection[row] * width / height), row), (255, 255, 255), 1)

############################################################################################################
# for loop for segmenting
    # segmentingLoop(horizontal_projection, row_index, limit, start_list, end_list)

    limit = 0
    if(axis_value == 1):
        limit = height
    if(axis_value == 0):
        limit = width

    row_index = 0
    start_list = []
    end_list = []

    line_segment(horizontal_projection, row_index, limit, start_list, end_list)

#############################################################################################################
    # kadena images tika wena wenama array ekakata append karagaththa
    if axis_value == 1:

        # print("\n- - - - - line cordinations > > > > > > > > ")
        # print(start_list)
        #  print(end_list)

        # question - - - -

        name = plt.imshow(blankImage, cmap='gray')
        plt.title("Horizontal Projections")
        plt.show()

        line_slices = []
        for x in range(len(start_list)):
                line_slices.append(final_Image[start_list[x]:end_list[x], 0:width])
                name = "line - " + str(x+1)
                Imgname = plt.imshow(line_slices[x], cmap='gray')
                plt.title(name)
                plt.show()

        global line_partitions
        line_partitions = line_slices

    if axis_value == 0:

        word_start = [start_list[0]]
        word_end = []
        word(start_list, end_list, word_start, word_end)

        word_slices = []
        for t in range(0, len(word_start)):
            word_slices.append(final_Image[0:height, word_start[t]:word_end[t]])
            name = "Word - " + str(t+1)
            Imgname = plt.imshow(word_slices[t], cmap='gray')
            plt.title(name)
            plt.show()

        character_slices = []
        for i in range(0, len(start_list)):
            character_slices.append(final_Image[0:height, start_list[i]:end_list[i]])
            charName = "character - " + str(i+1)
            # cv2.imshow(name, character_slices[i])
            name = plt.imshow(character_slices[i], cmap='gray')
            plt.title(charName)
            plt.show()

        global character_partitions
        character_partitions = character_slices

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


from lib.binary import pad_zeroes, create_encoded_text_parts
from lib.utils import create_str_parts_array, join
from math import sqrt, ceil
from PIL import Image
from sys import argv

FILE = 'ocean.jpg'
STEG_FILE = 'steganographic.png'
START_INDICATION_PIXELS = 4  # number of pixels used for indicating text size
ENCODING_ERROR = 'Can\'t encode {} characters text on {} pixels rgb image'
ARGUMENTS_INFO = """
Please provide arguments:
  (*) --encode, -e [ text ]
  (*) --decode, -d
  (*) --diff, -c
""".strip()

# determines how many pixels are needed to encode text when changing the 2 least significant bits
def get_required_pixels_for_text_encoding(text_size):
    return ceil(text_size * 4 / 3)

def is_encodable(text, image_data):
    image_data_size = len(image_data)
    required_image_data_size = get_required_pixels_for_text_encoding(len(text))
    return START_INDICATION_PIXELS + required_image_data_size <= image_data_size

def convert_image_data(image_data, interceptors=[], skip=0, iterations=None):
    image_size = len(image_data)
    iterations = image_size if iterations is None else iterations
    to = min(skip + iterations, image_size)
    for i in range(skip, to):
        for interceptor in interceptors:
            image_data[i] = tuple(map(interceptor, image_data[i]))

    return image_data

def get_encode_conversion_interceptors(parts):
    return [
        lambda x: pad_zeroes(bin(x), 8),
        lambda x: (x[:6] + parts.pop()) if len(parts) > 0 else x,
        lambda x: int(x, 2),
    ]

def get_decode_conversion_interceptors():
    return [lambda x: pad_zeroes(bin(x), 2)]

def encode_image(text, file=FILE, steganographic_file=STEG_FILE):
    with Image.open(file) as im:
        if not im.mode == 'RGB':
            im = im.convert('RGB')

        image_data = list(im.getdata())
        if not is_encodable(text, image_data):
            raise Exception(ENCODING_ERROR.format(len(text), len(image_data)))

        text_size = len(text)

        text_size_binary = pad_zeroes(bin(text_size), 24)
        encoded_text_size_parts = create_str_parts_array(text_size_binary, is_reversed=True)
        convert_image_data(
            image_data,
            get_encode_conversion_interceptors(encoded_text_size_parts),
            iterations=START_INDICATION_PIXELS,
        )

        text_parts = create_encoded_text_parts(text)
        convert_image_data(
            image_data,
            get_encode_conversion_interceptors(text_parts),
            skip=START_INDICATION_PIXELS,
            iterations=get_required_pixels_for_text_encoding(text_size),
        )

        im.putdata(image_data)
        im.save(steganographic_file)

def decode_image(file=STEG_FILE):
    with Image.open(file) as im:
        if not im.mode == 'RGB':
            im = im.convert('RGB')

        image_data = list(im.getdata())
        decode_interceptors = get_decode_conversion_interceptors()

        convert_image_data(
            image_data,
            decode_interceptors,
            iterations=START_INDICATION_PIXELS,
        )

        start_indicating_bit_string = join([join(image_data[i]) for i in range(0, START_INDICATION_PIXELS)])
        text_size = int(start_indicating_bit_string, 2)

        required_pixels_for_text_encoding = get_required_pixels_for_text_encoding(text_size)
        text_bits_count = text_size * 8  # number of bits that represent the text
        convert_image_data(
            image_data,
            decode_interceptors,
            skip=START_INDICATION_PIXELS,
            iterations=required_pixels_for_text_encoding,
        )

        start, end = START_INDICATION_PIXELS, required_pixels_for_text_encoding + START_INDICATION_PIXELS
        bit_string = join([join(image_data[i]) for i in range(start, end)])
        bit_string = bit_string[:text_bits_count]  # normalize bit string to text bit size
        bits_array = create_str_parts_array(bit_string, 8)
        decoded_text_array = list(map(lambda x: chr(int(x, 2)), bits_array))

        return join(decoded_text_array)

def calc_square_distance(rgb_1, rgb_2):
    r1, g1, b1 = rgb_1
    r2, g2, b2 = rgb_2
    return pow(r1 - r2, 2) + pow(g1 - g2, 2) + pow(b1 - b2, 2)

def get_diff(f1=FILE, f2=STEG_FILE):
    with Image.open(f1) as im1:
        with Image.open(f2) as im2:
            image1_data, image2_data = list(map(lambda im: im.getdata(), [im1, im2]))

            diff_factor = 0
            for i in range(0, len(image1_data)):
                diff_factor += calc_square_distance(image1_data[i], image2_data[i])

    return {'pixels': len(image1_data), 'diff': ceil(sqrt(diff_factor))}

def main():
    if len(argv) > 1:
        arguments, args_dict = argv[1:], {}

        args_pairs_list = create_str_parts_array(arguments)
        for args_pair in args_pairs_list:
            args_pair_size = len(args_pair)

            if args_pair_size == 1:
                args_dict[args_pair[0]] = True

            elif args_pair_size == 2:
                arg, value = args_pair
                args_dict[arg] = value

        file, steg_file = FILE, STEG_FILE
        dict_keys = args_dict.keys()

        if '-f' in dict_keys or '--file' in dict_keys:
            file = args_dict.get('-f') or args_dict.get('--file')

        if '-sf' in dict_keys or '--steg-file' in dict_keys:
            steg_file = args_dict.get('-sf') or args_dict.get('--steg-file')

        if '-c' in dict_keys or '--diff' in dict_keys:
            print(get_diff(file, steg_file))

        elif '-d' in dict_keys or '--decode' in dict_keys:
            print(decode_image(steg_file))

        elif '-e' in dict_keys or '--encode' in dict_keys:
            encode_text = args_dict.get('-e') or args_dict.get('--encode')
            encode_image(encode_text, file, steg_file)
    else:
        print(ARGUMENTS_INFO)

if __name__ == '__main__':
    main()


import json

from pymongo import MongoClient

from pydatalab.config import CONFIG

client = MongoClient(CONFIG.MONGO_URI)

db = client.datalabvue

all_documents = db.items.find()

nodes = []
edges = []
for document in all_documents:
    if ("parent_items" not in document) and ("child_items" not in document):
        continue
    nodes.append(
        {"data": {"id": document["item_id"], "name": document["name"], "type": document["type"]}}
    )
    if "parent_items" not in document:
        continue
    for parent_id in document["parent_items"]:
        target = document["item_id"]
        source = parent_id
        edges.append(
            {
                "data": {
                    "id": f"{source}->{target}",
                    "source": source,
                    "target": target,
                    "value": 1,
                }
            }
        )

with open("cy_links_production.json", "w") as f:
    json.dump({"nodes": nodes, "edges": edges}, f)


def div(num1,num2):
    return num1/num2

num1 = int(input("Enter num1...:"))
num2 = int(input("Enter num2...:"))

try:
    print(div(num1,num2))
except Exception as e:
    print(f"Something Happened {e}".format(e))
else:
    print("Execute this block when there is no error")
finally:
    print("This block gets executed regardless of the exception")
####################################################


def sum_of_div(n):
    """This function calculates and returns the sum of the divisors, including 1."""
    s = 1
    for i in range(2, n - 1):
        if n % i == 0:
            s += i
    return s

def is_perfect(n):
    """The function checks if the number is perfect or not.
      It returns True if the number is perfect and False otherwise."""
    if n == sum_of_div(n):
        return True
    else:
        return False
    return True

def smaller_perf(n):
    """Generates the first perfect number smaller that a given number n."""
    while is_perfect(n) == False:
        n -= 1
        if is_perfect(n) == True:
            return n

n = int(input("Enter the number: "))

print(int(sum_of_div(n)))

if is_perfect(n):
    print("The number is perfect")
else:
    print("The number is not perfect")
print(str(smaller_perf(n)))


import os
from typing import List

from dokidokimd.models import MangaSite
from dokidokimd.tools.ddmd_logger import get_logger
from dokidokimd.tools.translator import translate as _

logger = get_logger(__name__)

class MangaStorage(object):
    def __init__(self):
        self.site_extension = 'ddmd'  # type: str

    def store_sites(self, sites_location, sites_to_store) -> bool:
        try:
            if not os.path.isdir(sites_location):
                os.makedirs(sites_location, exist_ok=True)
        except Exception as e:
            logger.critical(_(F'Could not make or access directory {sites_location}\nError message: {e}'))
            return False

        for manga_site in sites_to_store:
            data = manga_site.dump()
            path_to_file = os.path.join(sites_location, F'{manga_site.site_name}.{self.site_extension}')

            try:
                # create new file
                with open(path_to_file, 'wb') as the_file:
                    the_file.write(data)
            except Exception as e:
                logger.critical(
                    _(F'Could not save {manga_site.site_name} site to a file{path_to_file}\nError message: {e}'))
        return True

    def load_sites(self, sites_location) -> List[MangaSite]:
        restored_manga_sites = []
        if not os.path.isdir(sites_location):
            os.makedirs(sites_location, exist_ok=True)
            logger.info(_('No saved state. Creating dir for fresh DB'))
        for file_name in os.listdir(sites_location):
            if file_name.endswith(self.site_extension):
                if os.path.isfile(os.path.join(sites_location, file_name)):
                    logger.info(_(F'Loading last state for {file_name}'))
                    try:
                        with open(os.path.join(sites_location, file_name), 'rb') as the_file:
                            data = the_file.read()
                            manga_site = MangaSite.load_dumped_site(data)
                            restored_manga_sites.append(manga_site)
                    except Exception as e1:
                        logger.warning(_(F'Could not load last state. Error message: {e1}'))
        return restored_manga_sites


from datetime import datetime
from enum import Enum
from typing import Optional, Union

import stringcase
from pydantic import Field
from pydantic.main import BaseModel

from app.server.utils.common import to_camel

class FlowText(BaseModel):
    EN: Optional[str]

class FlowData(BaseModel):
    text: Optional[FlowText]

class AttachmentItem(BaseModel):
    file_name: str = Field(alias='fileName')
    url: str

class ButtonTypeEnum(str, Enum):
    URL = 'web_url'
    FLOW = 'flow'
    POSTBACK = 'postback'
    PHONE = 'phone_number'

    # deprecated
    ELEMENT_SHARE = 'element_share'

class QuickReplyPayload(BaseModel):
    flow_id: Optional[str] = Field(alias='flowId')
    params: Optional[list[str]]

class QuickReplyItem(BaseModel):
    text: dict
    payload: Union[QuickReplyPayload, str]
    value: Optional[str]

class QuickReplyComponentSaveTo(BaseModel):
    attribute_name: Optional[str] = Field(alias='attributeName')
    is_temporary: Optional[bool] = Field(alias='isTemporary')

class QuickReplyComponent(BaseModel):
    quick_replies: Optional[list[QuickReplyItem]] = Field(alias='quickReplies')
    save_to: Optional[QuickReplyComponentSaveTo] = Field(alias='saveTo')

class ButtonItem(BaseModel):
    title: Optional[dict]
    type: ButtonTypeEnum
    payload: Optional[Union[QuickReplyPayload, str]]
    url: Optional[str]

class GenericTemplateItem(BaseModel):
    file_name: Optional[str] = Field(alias='fileName')
    image_url: Optional[str] = Field(alias='imageUrl')
    title: Optional[dict]
    subtitle: dict
    buttons: list[ButtonItem]

class AttachmentItemComponent(BaseModel):
    attachments: Optional[list[AttachmentItem]]
    url: Optional[str]

class GenericTemplateComponent(BaseModel):
    elements: Optional[list[GenericTemplateItem]]

class TextComponent(BaseModel):
    text: Optional[dict]

class FlowFlow(BaseModel):
    flow_id: Optional[str] = Field(alias='flowId')
    params: Optional[list[str]]

class FlowComponent(BaseModel):
    flow: Optional[FlowFlow]

class ButtonTemplateComponent(BaseModel):
    text: Optional[dict]
    title: Optional[dict]
    buttons: Optional[list[ButtonItem]]

class InputComponent(BaseModel):
    input_name: Optional[str] = Field(alias='inputName')
    input_type: Optional[str] = Field(alias='inputType')
    custom_regex: Optional[str] = Field(alias='customRegex')
    invalid_message: Optional[str] = Field(alias='invalidMessage')
    is_temporary: Optional[bool] = Field(alias='isTemporary')

class FunctionComponent(BaseModel):
    function: Optional[str]

class UserAttributeComponent(BaseModel):
    action_type: Optional[str] = Field(alias='actionType')
    attribute_name: Optional[str] = Field(alias='attributeName')
    attribute_value: Optional[str] = Field(alias='attributeValue')
    is_temporary: Optional[bool] = Field(alias='isTemporary')

class EntitySearchFilterEntity(BaseModel):
    user_attribute: Optional[str] = Field(alias='userAttribute')
    memory_attribute: Optional[str] = Field(alias='memoryAttribute')

class OperatorTypeEnum(str, Enum):
    MORE = '>'
    LESS = '<'
    EQUAL = '='
    NOT_EQUAL = '!='
    MORE_THAN_OR_EQUAL = '>='
    LESS_THAN_OR_EQUAL = '<='
    IN = 'in'
    CONTAINS = 'contains'

class EntitySearchFilter(BaseModel):
    attribute: str
    operator: OperatorTypeEnum
    value: Union[str, EntitySearchFilterEntity]

class EntitySearchSort(BaseModel):
    attribute: str
    direction: int

class EntitySearchSearch(BaseModel):
    primary_entity: Optional[str] = Field(alias='primaryEntity')
    filters: list[EntitySearchFilter]
    sort: list[EntitySearchSort]

class EntitySearchDisplay(BaseModel):
    configure: bool

class EntitySearchFoundFlow(BaseModel):
    function_name: Optional[str] = Field(alias='functionName')

class EntitySearchComponent(BaseModel):
    search: Optional[EntitySearchSearch]
    display_attribute_answer: Optional[str] = Field(alias='displayAttributeAnswer')
    show_filter_msg: Optional[bool] = Field(alias='showFilterMsg')
    show_sort_msg: Optional[bool] = Field(alias='showSortMsg')
    skip_selection_when_one_result: Optional[bool] = Field(alias='skipSelectionWhenOneResult')
    display: Optional[EntitySearchDisplay]
    found_flow: Optional[EntitySearchFoundFlow] = Field(alias='foundFlow')
    not_found_flow: Optional[EntitySearchFoundFlow] = Field(alias='notFoundFlow')

class FlowComponents(AttachmentItemComponent, GenericTemplateComponent, TextComponent, FlowComponent,
                     ButtonTemplateComponent, InputComponent, FunctionComponent,
                     UserAttributeComponent, EntitySearchComponent, QuickReplyComponent):
    pass

class FlowTypeEnum(str, Enum):
    GENERIC_TEMPLATE = 'genericTemplate'
    IMAGES = 'images'
    FILE = 'file'
    FILES = 'files'
    BUTTON_TEMPLATE = 'buttonTemplate'
    FLOW = 'flow'
    MESSAGE = 'message'
    VIDEOS = 'videos'
    INPUT = 'input'
    CUSTOM = 'custom'
    IMAGE = 'image'
    AUDIO = 'audios'
    VIDEO = 'video'

    # not supported yet
    USER_ATTRIBUTE = 'userAttribute'
    ENTITY_SEARCH = 'entitySearch'

    def __str__(self):
        if self.value == self.IMAGES:
            return 'images'
        elif self.value == self.VIDEOS:
            return 'videos'
        return stringcase.snakecase(self.value)

class FlowItem(BaseModel):
    type: FlowTypeEnum
    data: FlowComponents

class FlowItemCreateIn(BaseModel):
    name: Optional[str]
    flow: list[FlowItem]
    is_active: Optional[bool] = Field(alias='isActive')

    class Config:
        schema_extra = {
            "example": {
                "name": "new",
                "flow": [
                    {
                        "type": "genericTemplate",
                        "data": {
                            "elements": [
                                {
                                    "fileName": "test.png",
                                    "imageUrl": "https://pandai-admin-portal.s3-ap-southeast-1.amazonaws.com/portal/flows/%E2%80%94Pngtree%E2%80%94futuristic%20circuit%20board%2Cillustration%20high%20computer_1071790.png",
                                    "title": {
                                        "EN": ""
                                    },
                                    "subtitle": {
                                        "EN": ""
                                    },
                                    "buttons": [
                                        {
                                            "title": {
                                                "EN": "button text1"
                                            },
                                            "type": "web_url",
                                            "url": "www.apple.com"
                                        }
                                    ]
                                },
                                {
                                    "buttons": [
                                        {
                                            "payload": {
                                                "flow_id": "5f6c2e46e3fbc4968da41d88",
                                                "params": [
                                                    "Bunny"
                                                ]
                                            },
                                            "title": {
                                                "EN": "Select"
                                            },
                                            "type": "postback"
                                        }
                                    ],
                                    "fileName": "",
                                    "imageUrl": "https://gelm2dev.oss-ap-southeast-3.aliyuncs.com/portal/flows/flow-attachment-1600888929-557.png",
                                    "subtitle": {
                                        "EN": "",
                                        "ZH": ""
                                    },
                                    "title": {
                                        "EN": "Bunny Greeting Card",
                                        "ZH": ""
                                    }
                                }
                            ],
                            "quickReplies": [
                                {
                                    "payload": {
                                        "flowId": "5f97a0833c137c45a8f162c2",
                                        "params": [

                                        ]
                                    },
                                    "text": {
                                        "EN": "IL PBEAR (U186)"
                                    }
                                },
                                {
                                    "payload": "Continue",
                                    "text": {
                                        "EN": "IL PBEAR (U186)"
                                    }
                                }
                            ],
                            "saveTo": {
                                "attributeName": "epay_process",
                                "isTemporary": True
                            }
                        }
                    },
                    {
                        "type": "imageAttachment",
                        "data": {
                            "attachments": [
                                {
                                    "fileName": "test.pdf",
                                    "url": "https://pandai-admin-portal.s3-ap-southeast-1.amazonaws.com/portal/flows/If%20You%20Suspect%20That%20You%20Are%20Infected%20With%20Covid-19%20%28210124TEH%29%20%281%29.pdf"
                                }
                            ]
                        }
                    },
                    {
                        "type": "fileAttachment",
                        "data": {
                            "attachments": [
                                {
                                    "fileName": "test.pdf",
                                    "url": "https://pandai-admin-portal.s3-ap-southeast-1.amazonaws.com/portal/flows/If%20You%20Suspect%20That%20You%20Are%20Infected%20With%20Covid-19%20%28210124TEH%29%20%281%29.pdf"
                                }
                            ]
                        }
                    },

                    {
                        "type": "videoAttachment",
                        "data": {
                            "attachments": [
                                {
                                    "fileName": "test.mp4",
                                    "url": "https://pandai-admin-portal.s3-ap-southeast-1.amazonaws.com/portal/flows/If%20You%20Suspect%20That%20You%20Are%20Infected%20With%20Covid-19%20%28210124TEH%29%20%281%29.mp4"
                                }
                            ]
                        }
                    },
                    {
                        "type": "buttonTemplate",
                        "data": {
                            "text": {
                                "EN": "TEST"
                            },
                            "buttons": [
                                {
                                    "title": {
                                        "EN": "button text1"
                                    },
                                    "type": "web_url",
                                    "content": {
                                        "EN": "www.apple.com"
                                    }
                                }
                            ]
                        }
                    },
                    {
                        "type": "flow",
                        "data": {
                            "flow": {
                                "flowId": "5e315217a38e6703b4d3f81d",
                                "params": [

                                ]
                            }
                        }
                    },
                    {
                        "type": "message",
                        "data": {
                            "text": {
                                "EN": "TEST"
                            }
                        }
                    },
                    {
                        "type": "input",
                        "data": {
                            "isTemporary": True,
                            "inputName": "agent_ic",
                            "inputType": "custom",
                            "customRegex": "^\\d{3}$",
                            "invalidMessage": "You have entered an invalid format, please try again (etc. 123):"
                        }
                    },
                    {
                        "type": "custom",
                        "data": {
                            "function": "display_agent_birthyears"
                        }
                    },
                    {
                        "type": "image",
                        "data": {
                            "url": "https://s3-ap-southeast-1.amazonaws.com/choy-san/flow-image-1554258915.png"
                        }
                    },
                    {
                        "type": "video",
                        "data": {
                            "url": "https://gelm2prod.oss-ap-southeast-3.aliyuncs.com/portal/ePolicy%20agents.mp4"
                        }
                    },
                    {
                        "type": "userAttribute",
                        "data": {
                            "actionType": "set",
                            "attributeName": "life_claim",
                            "attributeValue": "Living Assurance",
                            "isTemporary": True
                        }
                    },
                    {
                        "type": "entitySearch",
                        "data": {
                            "search": {
                                "primaryEntity": "5ecdf7db51cc76038ea56e11",
                                "filters": [
                                    {
                                        "attribute": "ba218205-e72c-4cad-8b78-b13afb492886",
                                        "operator": "=",
                                        "value": {
                                            "userAttribute": "epay_bank"
                                        }
                                    },
                                    {
                                        "attribute": "ba218205-e72c-4cad-8b78-b13afb492886",
                                        "operator": "=",
                                        "value": {
                                            "memoryAttribute": "epay_attribute-value=a79ab047-c889-4735-adb2-1841c1f5f9ee"
                                        }
                                    },
                                    {
                                        "attribute": "name",
                                        "operator": "contains",
                                        "value": "Bharu"
                                    }
                                ],
                                "sort": [
                                    {
                                        "attribute": "name",
                                        "direction": 1
                                    },
                                    {
                                        "attribute": "ee0438e6-8514-4ac2-ae07-81bb7309bdde",
                                        "direction": -1
                                    }
                                ]
                            },
                            "displayAttributeAnswer": "c4282f1c-4351-424f-9558-889eb50f7903",
                            "showFilterMsg": False,
                            "showSortMsg": False,
                            "skipSelectionWhenOneResult": False,
                            "display": {
                                "configure": False
                            },
                            "foundFlow": {"functionName": "epay_documents_other"},
                            "notFoundFlow": {}
                        }
                    }
                ]
            }
        }

class FlowItemEditIn(FlowItemCreateIn):
    id: str

    class Config:
        schema_extra = {
            "example": {
                "id": "60235ffcb38bfe49acb97c3a",
                "name": "new",
                "flow": [
                    {
                        "type": "genericTemplate",
                        "data": {
                            "elements": [
                                {
                                    "fileName": "test.png",
                                    "imageUrl": "https://pandai-admin-portal.s3-ap-southeast-1.amazonaws.com/portal/flows/%E2%80%94Pngtree%E2%80%94futuristic%20circuit%20board%2Cillustration%20high%20computer_1071790.png",
                                    "title": {
                                        "EN": ""
                                    },
                                    "subtitle": {
                                        "EN": ""
                                    },
                                    "buttons": [
                                        {
                                            "title": {
                                                "EN": "button text1"
                                            },
                                            "type": "web_url",
                                            "url": "www.apple.com"
                                        }
                                    ]
                                },
                                {
                                    "buttons": [
                                        {
                                            "payload": {
                                                "flow_id": "5f6c2e46e3fbc4968da41d88",
                                                "params": [
                                                    "Bunny"
                                                ]
                                            },
                                            "title": {
                                                "EN": "Select"
                                            },
                                            "type": "postback"
                                        }
                                    ],
                                    "fileName": "",
                                    "imageUrl": "https://gelm2dev.oss-ap-southeast-3.aliyuncs.com/portal/flows/flow-attachment-1600888929-557.png",
                                    "subtitle": {
                                        "EN": "",
                                        "ZH": ""
                                    },
                                    "title": {
                                        "EN": "Bunny Greeting Card",
                                        "ZH": ""
                                    }
                                }
                            ],
                            "quickReplies": [
                                {
                                    "payload": {
                                        "flowId": "5f97a0833c137c45a8f162c2",
                                        "params": [

                                        ]
                                    },
                                    "text": {
                                        "EN": "IL PBEAR (U186)"
                                    }
                                },
                                {
                                    "payload": "Continue",
                                    "text": {
                                        "EN": "IL PBEAR (U186)"
                                    }
                                }
                            ]
                        }
                    },
                    {
                        "type": "imageAttachment",
                        "data": {
                            "attachments": [
                                {
                                    "fileName": "testasdasd.pdf",
                                    "url": "https://pandai-admin-portal.s3-ap-southeast-1.amazonaws.com/portal/flows/If%20You%20Suspect%20That%20You%20Are%20Infected%20With%20Covid-19%20%28210124TEH%29%20%281%29.pdf"
                                }
                            ]
                        }
                    },
                    {
                        "type": "fileAttachment",
                        "data": {
                            "attachments": [
                                {
                                    "fileName": "testassas.pdf",
                                    "url": "https://pandai-admin-portal.s3-ap-southeast-1.amazonaws.com/portal/flows/If%20You%20Suspect%20That%20You%20Are%20Infected%20With%20Covid-19%20%28210124TEH%29%20%281%29.pdf"
                                }
                            ]
                        }
                    },

                    {
                        "type": "videoAttachment",
                        "data": {
                            "attachments": [
                                {
                                    "fileName": "testasa.mp4",
                                    "url": "https://pandai-admin-portal.s3-ap-southeast-1.amazonaws.com/portal/flows/If%20You%20Suspect%20That%20You%20Are%20Infected%20With%20Covid-19%20%28210124TEH%29%20%281%29.mp4"
                                }
                            ]
                        }
                    },
                    {
                        "type": "buttonTemplate",
                        "data": {
                            "text": {
                                "EN": "TEST"
                            },
                            "buttons": [
                                {
                                    "title": {
                                        "EN": "button text1"
                                    },
                                    "type": "web_url",
                                    "content": {
                                        "EN": "www.apple.com"
                                    }
                                }
                            ]
                        }
                    },
                    {
                        "type": "flow",
                        "data": {
                            "flowId": "5e315217a38e6703b4d3f81d",
                            "params": [

                            ]
                        }
                    },
                    {
                        "type": "message",
                        "data": {
                            "text": {
                                "EN": "TEST"
                            }
                        }
                    }
                ]
            }
        }

class QuickReplyPayloadOut(QuickReplyPayload):
    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class ButtonItemOut(ButtonItem):
    payload: Optional[Union[QuickReplyPayloadOut, str]]
    title: Optional[Union[str, dict]]
    subtitle: Optional[Union[str, dict]]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class AttachmentItemOut(AttachmentItem):
    file_name: Optional[str] = Field(alias='fileName')

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class GenericTemplateItemOut(GenericTemplateItem):
    buttons: list[ButtonItemOut]
    title: Union[str, dict]
    subtitle: Optional[Union[str, dict]]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class QuickReplyItemOut(QuickReplyItem):
    payload: Union[QuickReplyPayloadOut, str]
    text: Optional[Union[str, dict]]
    title: Optional[str]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class QuickReplyComponentSaveToOut(QuickReplyComponentSaveTo):
    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class QuickReplyComponentOut(QuickReplyComponent):
    quick_replies: Optional[list[QuickReplyItemOut]] = Field(alias='quickReplies')
    save_to: Optional[QuickReplyComponentSaveToOut] = Field(alias='saveTo')

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class AttachmentItemComponentOut(AttachmentItemComponent):
    attachments: Optional[list[AttachmentItemOut]]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class GenericTemplateComponentOut(GenericTemplateComponent):
    elements: Optional[list[GenericTemplateItemOut]]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class TextComponentOut(TextComponent):
    text: Optional[Union[str, dict]]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class FlowFlowOut(FlowFlow):
    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class FlowComponentOut(FlowComponent):
    flow: Optional[FlowFlowOut]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class ButtonTemplateComponentOut(ButtonTemplateComponent):
    buttons: Optional[list[ButtonItemOut]]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class InputComponentOut(InputComponent):
    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class FunctionComponentOut(FunctionComponent):
    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class UserAttributeComponentOut(UserAttributeComponent):
    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class EntitySearchFilterEntityOut(EntitySearchFilterEntity):
    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class EntitySearchFilterOut(EntitySearchFilter):
    value: Union[str, EntitySearchFilterEntityOut]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class EntitySearchSortOut(EntitySearchSort):
    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class EntitySearchSearchOut(EntitySearchSearch):
    filters: list[EntitySearchFilterOut]
    sort: list[EntitySearchSortOut]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class EntitySearchDisplayOut(EntitySearchDisplay):
    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class EntitySearchFoundFlowOut(EntitySearchFoundFlow):
    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class EntitySearchComponentOut(EntitySearchComponent):
    search: Optional[EntitySearchSearchOut]
    display: Optional[EntitySearchDisplayOut]
    found_flow: Optional[EntitySearchFoundFlowOut] = Field(alias='foundFlow')
    not_found_flow: Optional[EntitySearchFoundFlowOut] = Field(alias='notFoundFlow')

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class FlowComponentsOut(AttachmentItemComponentOut, GenericTemplateComponentOut, TextComponentOut, FlowComponentOut,
                        ButtonTemplateComponentOut, InputComponentOut, FunctionComponentOut,
                        UserAttributeComponentOut, EntitySearchComponentOut, QuickReplyComponentOut):
    pass

class FlowTypeEnumOut(str, Enum):
    GENERIC_TEMPLATE = 'generic_template'
    IMAGES = 'images'
    FILE = 'file'
    FILES = 'files'
    BUTTON_TEMPLATE = 'button_template'
    FLOW = 'flow'
    MESSAGE = 'message'
    VIDEOS = 'videos'
    INPUT = 'input'
    IMAGE = 'image'
    VIDEO = 'video'
    AUDIO = 'audios'
    CUSTOM = 'custom'

    # for conversation
    POSTBACK = 'postback'

    # not supported yet on portal
    USER_ATTRIBUTE = 'user_attribute'
    ENTITY_SEARCH = 'entity_search'
    STICKER = 'sticker'

    def __str__(self):
        if self.value == self.IMAGES:
            return 'images'
        elif self.value == self.VIDEOS:
            return 'videos'
        return stringcase.camelcase(self.value)

class FlowItemOut(FlowItem):
    type: FlowTypeEnum
    data: FlowComponentsOut

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class FlowSchemaDb(BaseModel):
    id: str
    created_at: datetime
    created_by: Optional[str]
    updated_at: datetime
    updated_by: Optional[str]
    topic: Optional[str]
    is_active: bool
    name: Optional[str]
    flow: list[FlowItem]
    type: str
    platforms: Optional[list[str]]
    params: Optional[list[str]]
    triggered_count: Optional[int]

class FlowSchemaDbOut(FlowSchemaDb):
    flow: list[FlowItemOut]

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class FlowResponse(BaseModel):
    data: FlowSchemaDbOut

    class Config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class GetFlowsTable(BaseModel):
    data: list[FlowSchemaDbOut]
    success: bool
    total: int

class NewFlow(BaseModel):
    topic: str
    type: str
    flow_items: list[dict]

class DeleteFlows(BaseModel):
    key: list[str]

    class Config:
        schema_extra = {
            "example": {
                "key": ['6023502e837a202bee7d8e3e', '60235061837a202bee7d8e40']
            }
        }


import pymarket as pm
import numpy as np

class MarketInterface(pm.Market):
    """
    Extends a normal market to add
    the ability to recieve a callback.
    It is assumed that only one bid will be recieved
    for each broker

    """

    def __init__(self, r=None):
        super().__init__()
        self.callbacks = {}
        self.used_buying_prices = set()
        self.used_selling_prices = set()

        if r is None:
            self.r = np.random.RandomState(1234)
        else:
            self.r = r

        self.users = -1
        self.users_to_key = {}
        self.key_to_users = {}
        self.users_added = set()

    def accept_bid(self, bid, callback):
        uset = self.used_buying_prices if bid[3] else self.used_selling_prices
        new_p = bid[1]
        owner_id = bid[2]
        eps = 0
        counter = 0
        while ((bid[1] + eps) in uset) and (counter < 1e4):
            eps = self.r.randint(-1e3, 1e3) / 1e4
            counter += 1
        if counter == 1e4:
            raise ValueError('bid could not be added')
        else:
            uset.add(bid[1] + eps)
            if owner_id in self.users_to_key:
                uid = self.users_to_key[owner_id]
            else:
                self.users += 1
                uid = self.users
                self.key_to_users[uid] = owner_id
                self.users_to_key[owner_id] = uid
            new_bid = (bid[0], bid[1] + eps, uid, bid[3], bid[4])
            id_ = super().accept_bid(*new_bid)
            self.callbacks[uid] = callback
            return id_

    def clear(self, method='muda', r=None):
        if len(self.used_buying_prices) == 0 or len(self.used_selling_prices) == 0:
            for k in self.callbacks:
                self.callbacks[k](0, 0, {})
            results = []
        else:
            self.method = method
            if method=='huang':
                tr, ex = self.run(method)
            else:
                tr, ex = self.run(method, r=r)
            results = []
            for k in self.callbacks:
                q, p = self.get_user_result(k)
                self.callbacks[k](q, p, ex)
                results.append((self.key_to_users[k], q, p))

        self.results = results

    def get_user_result(self, user_id):
        """
        Finds the total quantity and price traded
        by a given broker
        """
        tr = self.transactions.get_df()
        bids = self.bm.get_df()
        extra = self.extra

        bid_id = bids.index[bids.user == user_id].tolist()
        buying = bids.iloc[bid_id[0], :].buying
        trans = tr[tr.bid.isin(bid_id)]
        if trans.shape[0] > 0:
            quantity_traded = trans.quantity.sum()
            price = trans.apply(lambda x: x.quantity * x.price, axis=1).sum()
            if self.method == 'muda':
                price += extra['fees'][user_id]
            #price_per_unit = price / quantity_traded if quantity_traded > 0 else 0
            if not buying:
                quantity_traded *= -1.0
                price *= -1.0
            return quantity_traded, price
        else:
            return 0, 0


import asyncio
import time
from turtle import down, left, right, up
import pygame
import random

SCREEN_WIDTH = 40
SCREEN_HEIGHT = 30
CELL_SIZE = 20

# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)

# This class represents the snake
class Snake:
    # Initialize the snake
    def __init__(self):
        self.length = 1
        self.positions = [((SCREEN_WIDTH / 2), (SCREEN_HEIGHT / 2))]
        self.direction = random.choice([up, down, left, right])
        self.color = WHITE

    # This method will move the snake
    def move(self):
        # Get the current position of the head of the snake
        cur = self.positions[0]
        x, y = cur
        # If the direction is UP, subtract 1 from y
        if self.direction == up:
            y -= 1
        # If the direction is DOWN, add 1 to y
        elif self.direction == down:
            y += 1
        # If the direction is LEFT, subtract 1 from x
        elif self.direction == left:
            x -= 1
        # If the direction is RIGHT, add 1 to x
        elif self.direction == right:
            x += 1
        # Set the new position of the snake's head
        self.positions = [(x, y)] + self.positions#[:-1]

        self.positions = self.positions[:self.length]

    # This method will draw the snake on the screen
    def draw(self, screen):
        for p in self.positions[:self.length]:
            draw_object(screen, self.color, p)

# This class represents the apple that the snake will eat
class Apple:
    # Initialize the apple
    def __init__(self):
        self.position = (0, 0)
        self.color = RED
        self.randomize_position()

    # This method will randomly place the apple
    def randomize_position(self):
        self.position = (random.randint(0, SCREEN_WIDTH - 1), random.randint(0, SCREEN_HEIGHT - 1))

    # This method will draw the apple on the screen
    def draw(self, screen):
        draw_object(screen, self.color, self.position)

    def drawGoldApple(self, snake, goldApple, screen, goldAppleVisible):
        if(goldAppleVisible == True):
            goldApple.draw(screen)
            if(check_eat(snake, goldApple)):
                print("golden apple")
                snake.length += 4
                goldAppleVisible = False

        if(goldAppleVisible == False):
            goldenAppleTimer = random.randint(0, 30)
            if(goldenAppleTimer == 15):
                # Draw the gold apple
                goldAppleVisible = True
        return goldAppleVisible

# This function will draw an object (either a snake or an apple) on the screen
def draw_object(screen, color, pos):
    r = pygame.Rect((pos[0] * CELL_SIZE, pos[1] * CELL_SIZE), (CELL_SIZE, CELL_SIZE))
    pygame.draw.rect(screen, color, r)
    pygame.display.update()

# This function will check if the snake has eaten an apple
def check_eat(snake, apple):
    if snake.positions[0] == apple.position:
        print("snake ate apple")
        snake.length += 1
        apple.randomize_position()
        return True
    # return snake

# This function will check if the snake has run into a wall or itself
def check_collision(snake):
    print(snake.positions[1:])
    if snake.positions[0] in snake.positions[1:]:
        print("snake collision")
        return True

    if snake.positions[0][0] < 0: # or snake.positions[0][0] > SCREEN_WIDTH - 1:
        x = SCREEN_WIDTH
        y = snake.positions[0][1]
        snake.positions = [(x, y)] + snake.positions[:-1]

        print("left wall collision")
        return False

    if snake.positions[0][0] > SCREEN_WIDTH - 1:
        x = 0
        y = snake.positions[0][1]
        snake.positions = [(x, y)] + snake.positions[:-1]
        print("right wall collision")
        return False

    if snake.positions[0][1] < 0: # or snake.positions[0][1] > SCREEN_HEIGHT - 1:
        x = snake.positions[0][0]
        y = SCREEN_HEIGHT
        snake.positions = [(x, y)] + snake.positions[:-1]
        print("top wall collision")
        return False

    if snake.positions[0][1] > SCREEN_HEIGHT - 1:
        x = snake.positions[0][0]
        y = 0
        snake.positions = [(x, y)] + snake.positions[:-1]
        print("bottom wall collision")
        return False

    return False

def main():
    print('Welcome to Snake!')
    # Initialize pygame
    pygame.init()

    # Set the screen size
    screen = pygame.display.set_mode((SCREEN_WIDTH * CELL_SIZE, SCREEN_HEIGHT * CELL_SIZE))

    # Set the title of the window
    pygame.display.set_caption('Snake')

    # Create a clock
    clock = pygame.time.Clock()

    # Create a snake and an apple
    snake = Snake()
    apple = Apple()

    goldApple = Apple()
    goldApple.color = YELLOW

    goldAppleVisible = False

    # Main game loop
    while True:
        # Handle events
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP and snake.direction != down:
                    snake.direction = up
                elif event.key == pygame.K_DOWN and snake.direction != up:
                    snake.direction = down
                elif event.key == pygame.K_LEFT and snake.direction != right:
                    snake.direction = left
                elif event.key == pygame.K_RIGHT and snake.direction != left:
                    snake.direction = right

        # Draw the background
        screen.fill(BLACK)

        # Draw the apple
        apple.draw(screen)

        goldAppleVisible = goldApple.drawGoldApple(snake, goldApple, screen, goldAppleVisible)

        # Move the snake
        snake.move()

        # Check if the snake has eaten an apple
        check_eat(snake, apple)

        # Check if the snake has collided with itself or a wall
        if check_collision(snake):
            break

        # Draw the snake
        snake.draw(screen)

        # Update the screen
        pygame.display.update()

        # Set the speed of the game
        clock.tick(5)

    print('Final length: ', snake.length)
    pygame.quit()

if __name__ == '__main__':
    main()


s,k=map(int,input().split())
head=s//k
print(head)
remain=s%k
print(remain)
result=1
for i in range(0,k):
    if i<remain:
        result=result*(head+1)
    else:
        result=result*head
    print(result)
print(result)


#!/usr/bin/python3
# 10-student.py
"""Contains a class named  Student."""

class Student:
    """Represents student."""

    def __init__(self, first_name, last_name, age):
        """New Student is initialized .
        Args:
            first_name (str): The first name of the student.
            last_name (str): The last name of the student.
            age (int): The age of the student.
        """
        self.first_name = first_name
        self.last_name = last_name
        self.age = age

    def to_json(self, attrs=None):
        """Dictionary representing the Student.
        If attrs is list of strings, represents only attributes that are
        included in the list.
        Args:
            attrs (list): Attributes to represent.
        """
        if (type(attrs) == list and
                all(type(ele) == str for ele in attrs)):
            return {key: getattr(self, key)
                    for key in attrs if hasattr(self, key)}
        return self.__dict__


class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        nrows = len(matrix)
        ncols = len(matrix[0])
        zrow = False
        zcol = False
        for i in range(nrows):
            if matrix[i][0] == 0:
                zrow = True
                break
        for j in range(ncols):
            if matrix[0][j] == 0:
                zcol = True
                break
        for i in range(1, nrows):
            for j in range(1, ncols):
                if matrix[i][j] == 0:
                    matrix[i][0] = 0
                    matrix[0][j] = 0
        for i in range(1, nrows):
            if matrix[i][0] == 0:
                for j in range(ncols):
                    matrix[i][j] = 0
        for i in range(1, ncols):
            if matrix[0][i] == 0:
                for j in range(nrows):
                    matrix[j][i] = 0
        if zrow:
            for i in range(nrows):
                matrix[i][0] = 0
        if zcol:
            for j in range(ncols):
                matrix[0][j] = 0


""" Wrapper around TRF to annotate a VCF """
import sys
import logging
import argparse
import tempfile
from collections import defaultdict

import pysam
import pyfaidx
import truvari
from acebinf import cmd_exe, setup_logging

# Start with just insertions and that sequence
# Eventually you can intersect with known tandem repeat regions as well
# and use those regions (with the edit) to better predict a 'difference' in number of copies
# Or you can just annotate the absolute number of the individual... probably bot

# Also, running single threaded isn't great, but also I don't care at this point...
# It'll be a heavy step, but I'm not judging the software on speed for a bit...

class TRFAnno():
    """ Class for trf annotation """
    TRNAME = tempfile.NamedTemporaryFile().name # Need to remove this
    FANAME = tempfile.NamedTemporaryFile().name # Need to remove this
    TRFCOLS = [("TRF_starts", int),
               ("TRF_ends", int),
               ("TRF_periods", int),
               ("TRF_copies", float),
               ("TRF_consizes", int),
               ("TRF_pctmats", int),
               ("TRF_pctindels", int),
               ("TRF_scores", int),
               ("TRF_As", int),
               ("TRF_Cs", int),
               ("TRF_Gs", int),
               ("TRF_Ts",  int),
               ("TRF_entropies", float),
               ("TRF_repeats", str),
               ("unk1", None),
               ("unk2", None),
               ("unk3", None)]

    def __init__(self, in_vcf, out_vcf="/dev/stdout", executable="trf409.linux64",
                 min_length=50, threshold=0.8, full=False,
                 trf_params="2 7 7 80 10 50 500 -m -f -h -d -ngs",
                 refanno=None, ref=None, pctovl=0.2):
        """ The setup """
        self.in_vcf = in_vcf
        self.out_vcf = out_vcf
        self.executable = executable
        self.min_length = min_length
        self.threshold = threshold
        self.full = full

        if "-ngs" not in trf_params:
            trf_params = trf_params + " -ngs "
        self.trf_params = trf_params

        if refanno and not ref:
            logging.error("-R requires -r")
            exit(1)

        self.refanno = truvari.make_bedanno_tree(refanno) if refanno else None
        self.ref = pyfaidx.Fasta(ref) if ref else None
        self.pctovl = pctovl

        self.n_header = self.edit_header()
        self.cmd = f"{self.executable} {TRFAnno.FANAME} {self.trf_params} > {TRFAnno.TRNAME}"

    def edit_header(self):
        """
        New VCF INFO fields
        """
        header = None
        with pysam.VariantFile(self.in_vcf, 'r') as fh:
            header = fh.header.copy()
        # if intersect_only: Do I want to sometimes turn this off?
        # Probably, actully
        header.add_line(('##INFO=<ID=TRF_repeats,Number=.,Type=String,'
                         'Description="TRF repeat sequences">'))
        header.add_line(('##INFO=<ID=TRF_periods,Number=.,Type=Integer,'
                         'Description="TRF periods">'))
        header.add_line(('##INFO=<ID=TRF_copies,Number=.,Type=Float,'
                         'Description="TRF repeat copies">'))
        header.add_line(('##INFO=<ID=TRF_scores,Number=.,Type=Integer,'
                         'Description="TRF repeat scores">'))

        # Take this out
        if self.refanno and self.ref:
            header.add_line(('##INFO=<ID=TRF_diffs,Number=.,Type=Float,'
                             'Description="Alternate allele copy number difference from '
                             'its reference SREP_repeat copy number">'))
        if self.refanno:
            for headinfo in self.refanno[1]:
                header.add_line(headinfo)

        if self.full:
            header.add_line(('##INFO=<ID=TRF_starts,Number=.,Type=Integer,'
                             'Description="TRF starts">'))
            header.add_line(('##INFO=<ID=TRF_ends,Number=.,Type=Integer,'
                             'Description="TRF ends">'))
            header.add_line(('##INFO=<ID=TRF_periods,Number=.,Type=Integer,'
                             'Description="TRF periods">'))
            header.add_line(('##INFO=<ID=TRF_consizes,Number=.,Type=Integer,'
                             'Description="TRF consizes">'))
            header.add_line(('##INFO=<ID=TRF_pctmats,Number=.,Type=Integer,'
                             'Description="TRF pctmats">'))
            header.add_line(('##INFO=<ID=TRF_pctindels,Number=.,Type=Integer,'
                             'Description="TRF pctindels">'))
            header.add_line(('##INFO=<ID=TRF_As,Number=.,Type=Integer,'
                             'Description="TRF As">'))
            header.add_line(('##INFO=<ID=TRF_Cs,Number=.,Type=Integer,'
                             'Description="TRF Cs">'))
            header.add_line(('##INFO=<ID=TRF_Gs,Number=.,Type=Integer,'
                             'Description="TRF Gs">'))
            header.add_line(('##INFO=<ID=TRF_Ts,Number=.,Type=Integer,'
                             'Description="TRF Ts">'))
            header.add_line(('##INFO=<ID=TRF_entropies,Number=.,Type=Float,'
                             'Description="TRF entropies">'))
            # TRF HIT - if refanno, just report if we hit a reference TRF region
            # Might want some pct/ovl -- this is handled... nowhere
            pass
        # TODO: Need to put a source line that says this thing was run with whatever parameters
        return header

    def run_trf(self, seq):
        """
        Runs trf on the ref/alt sequences
        returns list of hits
        """
        def parse_output():
            """
            Parse the outputs from trf, turn to a dictionary
            """
            hits = []
            with open(TRFAnno.TRNAME, 'r') as fh:
                name = fh.readline()
                if name == "": # no hits
                    return hits
                name = name.strip()[1:]
                while True:
                    # If there are multiple, need to parameters for 'take best' or take top N or something
                    # Will need name now that there's ref/alt seq
                    data = fh.readline()
                    if data == "":
                        break
                    if data.startswith("@"):
                        name = data.strip()[1:]
                        continue
                    data = data.strip().split(' ')
                    data = {x[0]: x[1](y) for x, y in zip(TRFAnno.TRFCOLS, data) if not x[0].startswith("unk")}
                    # don't really need until parallel
                    data["TRF_scores"] = int(data["TRF_scores"])
                    hits.append(data)
            return hits

        with open(TRFAnno.FANAME, 'w') as fout:
            #for seq in seqs:
            fout.write(">a\n%s\n" % (seq))

        ret = cmd_exe(self.cmd)
        if ret.ret_code != 0:
            logging.error("Couldn't run trf")
            logging.error(str(ret))
            exit(ret.ret_code)
        return parse_output()

    def __old_srep(self):
        """
        legacy code
        """
        srep_hits = None
        # Make srep_hits if we have the bed
        if self.refanno:
            srep_hits = self.refanno[0][entry.chrom].overlap(entry.start, entry.stop)

    def annotate(self, entry, altseq):
        """
        Annotates an Insertion, returns the annotation information
        """
        trf_hits = self.run_trf(altseq)
        best_hit = None
        entry_size = truvari.entry_size(entry)
        for hit in trf_hits:
            size_trf = abs(hit["TRF_ends"] - hit["TRF_starts"]) + 1
            pct = size_trf / entry_size  # The TR that covers the most of the insertion
            if pct < self.threshold:
                continue
            if best_hit is None:
                best_hit = hit
                continue
            if best_hit is None \
               or (hit["TRF_periods"] < best_hit["TRF_periods"] \
               and hit["TRF_copies"] > best_hit["TRF_copies"]):
                best_hit = hit
        return best_hit

    def annotate_entry(self, entry, altseq):
        """
        Annotates an insertion. Insertions are assumed to have a
        refspan of a single anchor base and full ALT sequence
        Returns the edited entry
        """
        return self.edit_entry(entry, [self.annotate(entry, altseq)])

    def edit_entry(self, entry, trf_annos):
        """
        puts the annos in vcf entry
        return the edited entry
        """
        if not trf_annos:
            return entry

        # Let's assume we're only doing the alt allele
        srep_hits = None
        try:
            entry = truvari.copy_entry(entry, self.n_header)
        except TypeError:
            return entry
        n_dat = defaultdict(list)
        for i in trf_annos:
            if i is None:
                continue
            if self.full:
                for key, cnvt in TRFAnno.TRFCOLS:
                    if cnvt:
                        n_dat[key].append(cnvt(i[key]))
            else:
                n_dat["TRF_repeats"].append(i["TRF_repeats"])
                n_dat["TRF_periods"].append(int(i["TRF_periods"]))
                n_dat["TRF_copies"].append(float(i["TRF_copies"]))
                n_dat["TRF_scores"].append(int(i["TRF_scores"]))

        # Adding srep hits to n_dat also
        # this is getting kinda choppy with the converters
        # may have over engineered it early
        if srep_hits is not None:
            for i in srep_hits:
                for k,v in i.data.items():
                    n_dat[k].extend(v)

        # Can calculate the diffs
        if self.refanno and self.ref and srep_hits and alt_annos:
            lookup = {}
            diffs = []
            # make a lookup of the trf_annos from the reference
            for i in srep_hits:
                i = i.data
                lookup[i["SREP_repeats"][0]] = i["SREP_copies"][0]

            has_diff = False
            # Subtract each alt_repeat from its corresponding ref_repeat
            for alt_repeat, alt_copy in zip(n_dat["TRF_repeats"], n_dat["TRF_copies"]):
                if alt_repeat in lookup:
                    has_diff = True
                    diffs.append(alt_copy - lookup[alt_repeat])
                else:
                    diffs.append(None)

            if has_diff:
                n_dat["TRF_diffs"] = diffs

        for key in n_dat:
            entry.info[key] = n_dat[key]

        return entry

    def run(self):
        """
        The work
        """
        logging.info("Annotating VCF")
        # should probably 'batch' it instead of running individually
        with pysam.VariantFile(self.in_vcf) as vcf, \
                pysam.VariantFile(self.out_vcf, 'w', header=self.n_header) as output:
            for entry in vcf:
                sz = truvari.entry_size(entry)
                if sz >= self.min_length \
                   and truvari.entry_variant_type(entry) == "INS":
                    entry = self.annotate_entry(entry, entry.alts[0])
                output.write(entry)

def parse_args(args):
    """
    Pull the command line parameters
    """
    def restricted_float(x):
        x = float(x)
        if x < 0.0 or x > 1.0:
            raise argparse.ArgumentTypeError("%r not in range [0.0, 1.0]" % (x,))
        return x
    parser = argparse.ArgumentParser(prog="trf", description=__doc__,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("-i", "--input", type=str, default="/dev/stdin",
                        help="VCF to annotate (stdin)")
    parser.add_argument("-o", "--output", type=str, default="/dev/stdout",
                        help="Output filename (stdout)")
    parser.add_argument("-e", "--executable", type=str, default="trf409.linux64",
                        help="Path to tandem repeat finder (%(default)s)")
    parser.add_argument("-f", "--full", action="store_true",
                        help="Write full trf output to entries")
    parser.add_argument("-m", "--min-length", type=int, default=50,
                        help="Minimum size of entry to annotate (%(default)s)")
    parser.add_argument("-t", "--threshold", type=restricted_float, default=.8,
                        help="Threshold for pct of allele covered (%(default)s)")
    parser.add_argument("-T", "--trf-params", type=str, default="2 7 7 80 10 50 500 -m -f -h -d -ngs",
                        help="Default parameters to send to trf (%(default)s)")
    parser.add_argument("-R", "--ref-bed", type=str, default=None,
                        help="Reference bed of simple repeats")
    parser.add_argument("-r", "--ref", type=str, default=None,
                        help="Reference fasta file (use with -R)")
    parser.add_argument("--debug", action="store_true",
                        help="Verbose logging")
    args = parser.parse_args(args)
    setup_logging(args.debug)
    return args

def trf_main(cmdargs):
    """ Main """
    args = parse_args(cmdargs)
    anno = TRFAnno(in_vcf=args.input,
                   out_vcf=args.output,
                   executable=args.executable,
                   min_length=args.min_length,
                   threshold=args.threshold,
                   full=args.full,
                   trf_params=args.trf_params,
                   refanno=args.ref_bed,
                   ref=args.ref)
    anno.run()
    logging.info("Finished trf")

if __name__ == '__main__':
    trf_main(sys.argv[1:])

"""
1) I can't guarantee that TRF alt seq hits are going to happend
    But I'm returning nulls - not good. need to remove I think
    |

So 1- you can give up on the reference, totally un-needed unti you get to 'denovo mode'
Which at this point you should just abandon until it beocmes a feature request
"""


#!/usr/bin/env python
import rospy
import cv2
from cv_bridge import CvBridge
from ir_marker_extractor.msg import ir_markers
from geometry_msgs.msg import Point
from sensor_msgs.msg import Image
from pyclustering.cluster.bsas import bsas
from dynamic_reconfigure.server import Server
from ir_marker_extractor.cfg import ir_marker_extractor_cfgsConfig
import numpy as np

def recongigureator_callback(config,level):
    #Image Thresholding Parameters
    node_processor.marker_extractor.high_threshold=config.high_threshold
    node_processor.marker_extractor.low_threshold=config.low_threshold
    #BSAS Parameters
    node_processor.marker_extractor.bsas_enable=config.bsas_enable
    node_processor.marker_extractor.max_clusters=config.max_clusters
    node_processor.marker_extractor.maxWhitePixels=config.max_white_pixels
    node_processor.marker_extractor.threshold=config.clustering_threshold
    #Blub Detection Parameters
    node_processor.marker_extractor.blubParams.minThreshold=config.blub_min_threshold
    node_processor.marker_extractor.blubParams.maxThreshold=config.blub_max_threshold
    node_processor.marker_extractor.blubParams.filterByArea=config.blub_filterByArea
    node_processor.marker_extractor.blubParams.minArea=config.blub_minArea
    node_processor.marker_extractor.blubParams.filterByCircularity=config.blub_filterByCircularity
    node_processor.marker_extractor.blubParams.minCircularity=config.blub_minCircularity
    node_processor.marker_extractor.blubParams.filterByConvexity=config.blub_filterByConvexity
    node_processor.marker_extractor.blubParams.minConvexity=config.blub_minConvexity
    node_processor.marker_extractor.blubParams.filterByInertia=config.blub_filterByInertia
    node_processor.marker_extractor.blubParams.minInertiaRatio=config.blub_minInertiaRatio
    node_processor.marker_extractor.blubParams.blobColor=config.blub_color
    node_processor.marker_extractor.updateParameters()
    return config
class markerExteractor():
    def __init__(self):
        self.bsas_enable=False
        self.maxWhitePixels=300
        self.low_threshold=100
        self.high_threshold=255
        self.max_clusters = 8
        self.threshold = 20
        self.blubParams = cv2.SimpleBlobDetector_Params()
        self.blubParams.minThreshold = 50;
        self.blubParams.maxThreshold = 255;
        self.blubParams.filterByArea = True
        self.blubParams.minArea = 0
        self.blubParams.filterByCircularity = True
        self.blubParams.minCircularity = 0.3
        self.blubParams.filterByConvexity = True
        self.blubParams.minConvexity = 0.7
        self.blubParams.filterByInertia = True
        self.blubParams.minInertiaRatio = 0.1
        self.blubParams.blobColor = 255

        ver = (cv2.__version__).split('.')
        if int(ver[0]) < 3 :
            self.blubDetector = cv2.SimpleBlobDetector(self.blubParams)
        else :
            self.blubDetector = cv2.SimpleBlobDetector_create(self.blubParams)
    def updateParameters(self):
        ver = (cv2.__version__).split('.')
        if int(ver[0]) < 3 :
            self.blubDetector = cv2.SimpleBlobDetector(self.blubParams)
        else :
            self.blubDetector = cv2.SimpleBlobDetector_create(self.blubParams)
    def detect(self,frame):
        self.cms=[]
        self.image_ROIs=[]
        self.keypoints=[]
        if len(frame.shape)==2:
            img_gray=frame
        else:
            img_gray=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        ret,img_thresh = cv2.threshold(img_gray,
                                       self.low_threshold,self.high_threshold,cv2.THRESH_TOZERO)
        #Find the clusters
        self.nonzro_samples = cv2.findNonZero(img_thresh)
        if self.nonzro_samples is None:
            return -1,None  #No markers in the image
        else:
            self.nonzro_samples=self.nonzro_samples.reshape(-1, 2).astype('float32')
        if self.nonzro_samples.shape[0]<self.maxWhitePixels:
            if self.bsas_enable:
                result=self.process_bsas(img_thresh)
            else:
                result=self.process_no_bsas(img_thresh)
            return result
        else:
            return -2,None
    def process_bsas(self,img_thresh):
            bsas_instance = bsas(self.nonzro_samples, self.max_clusters, self.threshold)
            bsas_instance.process()
            clusters = bsas_instance.get_clusters()
            #Calculate the center of the clusters and the Regions of Interests
            self.ROIs=np.zeros((len(clusters),4))
            for i,cluster in enumerate(clusters):
                current_batch=self.nonzro_samples[cluster]
                self.cms.append(np.sum(current_batch,axis=0)/current_batch.shape[0])
                row_max=np.max(current_batch[:,1],axis=0)+6
                row_min=np.min(current_batch[:,1],axis=0)-6
                col_max=np.max(current_batch[:,0],axis=0)+6
                col_min=np.min(current_batch[:,0],axis=0)-6
                self.ROIs[i,:]=[row_min,row_max,col_min,col_max]
            for roi in self.ROIs.astype('int32'):
                self.image_ROIs.append(img_thresh.copy()[roi[0]:roi[1],roi[2]:roi[3]])
            #Return The Results
            marker_points=[]
            for i,roi in enumerate(self.image_ROIs):
                keys_in_roi=self.blubDetector.detect(roi)
                for key in keys_in_roi:
                    #Calculate the global coordinate of marker points.
                    #The points are returned in (X(Col),Y(Row)) coordinate.
                    marker_points.append([key.pt[0]+self.ROIs.astype('float32')\
                    [i,2],key.pt[1]+self.ROIs.astype('float32')[i,0]])
            return 0,np.array(marker_points)
    def process_no_bsas(self,img_thresh):
        blubs=self.blubDetector.detect(img_thresh)
        marker_points=[]
        for key in blubs:
            marker_points.append([key.pt[0] ,key.pt[1]])
        return 0,np.array(marker_points)

class process():
    def __init__(self,debug_image):
        self.debug_image=debug_image
        self.marker_extractor=markerExteractor()
        self.bridge=CvBridge()
    def process(self,image):
        cv_image=self.bridge.imgmsg_to_cv2(image,desired_encoding='mono8')
        #print(cv_image.shape)
        status,markers=self.marker_extractor.detect(cv_image)
        if self.debug_image:
            img_color=cv2.cvtColor(cv_image,cv2.COLOR_GRAY2BGR)
            if markers is not None:
                for marker in markers:
                    cv2.circle(img_color,(int(round(marker[0])), int(round(marker[1]))), 3,
                                                                           (255,0,255),-1)
            debug_image=self.bridge.cv2_to_imgmsg(img_color)
        else:
            debug_image=None
        return status,markers,debug_image
def image_callback(image):
    markers_msg=ir_markers()
    status,markers,debug_image=node_processor.process(image)
    if debug_image is not None:
        debug_image_pub.publish(debug_image)
    if status==-2: #too many white pixels in the image print
                    #('too many white pixels dtected in the image')
        markers_msg.status=status
        markers_msg.header.stamp=image.header.stamp
        pub.publish(markers_msg)
        return
    if status==-1 or len(markers)==0: #no markers in the image
        #print('no markers in the image')
        markers_msg.status=status
        markers_msg.header.stamp=image.header.stamp
        pub.publish(markers_msg)
        return
    marker_list=[]
    for marker in markers:
        marker_list.append(Point(marker[0],marker[1],0))
    markers_msg.status=status
    markers_msg.header.stamp=image.header.stamp
    markers_msg.markers=marker_list
    #[Point(np.random.randn(),2,3),Point(4,5,6)]#
    pub.publish(markers_msg)

if __name__ =='__main__':
    rospy.init_node('ir_marker_extractor_node')
    if rospy.has_param('~debug_image'):
        debug_image=rospy.get_param('~debug_image')
        debug_image_pub=rospy.Publisher('/ir_marker_extractor/debug_image',Image,queue_size=1)
    else:
        debug_image=False
    node_processor=process(debug_image)
    pub=rospy.Publisher('/ir_marker_extractor/ir_markers',ir_markers,queue_size=1)
    rospy.Subscriber('/camera/image_raw',Image,image_callback)
    srv=Server(ir_marker_extractor_cfgsConfig,recongigureator_callback)
    rospy.spin()


#!/usr/bin/python3
# creates and distributes an archive to your web servers

from fabric.api import *
import os.path
import datetime

env.user = 'ubuntu'
env.hosts = ['34.138.47.31', '54.226.1.15']

def do_pack():
    """ .tgz archive """
    local("mkdir -p versions")
    t = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    archive = local("tar -czvf versions/web_static_{}\
.tgz web_static".format(t))
    if archive.succeeded:
        return ("versions/web_static_{}.tgz".format(t))
    else:
        return None

def do_deploy(archive_path):
    """Fabric script that distrubutes an archive to server"""
    if os.path.exists(archive_path):
        new_path = archive_path.replace('versions/', '')
        file_name = new_path[:-4]
        arc_folder = "/data/web_static/releases/{}".format(new_path)
        put(archive_path, '/tmp/')
        run('mkdir -p /data/web_static/releases/{}'.format(file_name))
        run('tar -xzf /tmp/{} -C {}'.format(new_path, arc_folder[:-4]))
        run('rm /tmp/{}'.format(new_path))
        run('mv {}/web_static/* {}/'.format(arc_folder[:-4], arc_folder[:-4]))
        run('rm -rf {}/web_static'.format(arc_folder[:-4]))
        run('rm -rf /data/web_static/current')
        run('ln -s {} /data/web_static/current'.format(arc_folder[:-4]))
        return True
    else:
        return False

def deploy():
    """Creates and distributes and archive to a server"""
    archive_path = do_pack()
    if archive_path is None:
        return False
    return do_deploy(archive_path)