"""
We referred to the examples provided by
https://github.com/pytorch/examples/tree/master/vae and
https://github.com/wiseodd/generative-models/tree/master/VAE/conditional_vae
"""
import torch as th
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable

class Value(nn.Module):
    """
    Define a value network for estimating state values.
    """
    def __init__(self):
        super(Value, self).__init__()
        self.fc1 = nn.Linear(6, 600)
        self.fc2 = nn.Linear(600, 1)

    def forward(self, s):
        """

        Parameters
        ----------
        s: Variable whose data is Tensor of shape n x 6 with requires_grad=False
            state signal sent by the environment

        Returns
        -------
        v: Variable whose data is Tensor of shape n x 1 with requires_grad=True
            This estimates the state value at s.
        """
        return self.fc2(F.tanh(self.fc1(s)))

class Fnn(nn.Module):
    """
    Define a feedforward neural network which will be used as the feedforward policy.
    """
    def __init__(self):
        super(Fnn, self).__init__()
        self.fc1 = nn.Linear(6, 600)
        self.fc2 = nn.Linear(600, 3)

    def forward(self, s):
        """

        Parameters
        ----------
        s: Variable whose data is Tensor of shape 1 x 6 with requires_grad=False
            state signal sent by the environment

        Returns
        -------
        p: Variable whose data is Tensor of shape 1 x 3 with requires_grad=True
           The data of p may be interpreted as probability of taking discrete
           action 1, 2, 3 separately.
        """
        s_ = F.tanh(self.fc1(s))
        p = F.softmax(F.tanh(self.fc2(s_)))
        return p

class Cvae(nn.Module):
    """
    Define a CVAE model which will be used as the CVAE policy.
    """
    def __init__(self):
        super(Cvae, self).__init__()
        self.fc1 = nn.Linear(9, 500)
        self.fc21 = nn.Linear(500, 24)
        self.fc22 = nn.Linear(500, 24)
        self.fc3 = nn.Linear(30, 3)

    def encode(self, x):
        """

        Parameters
        ----------
        x: Variable whose data is Tensor of shape n x 9 with requires_grad=False
            x = (s, a) with a one-hot representation of a. Note when we are collecting
            real-time experience, where the corresponding actions are unknown, simply set
            a = [0, 0, 0].

        Returns
        -------
        mu_h: Variable whose data is Tensor of shape n x 24 with requires_grad=True
            mean of the modeled gaussian distribution for h
        log_var_h: Variable whose data is Tensor of shape n x 24 with requires_grad=True
            logarithm of the covariance of the modeled gaussian distribution for h
        """
        x_ = F.tanh(self.fc1(x))
        return F.tanh(self.fc21(x_)), F.tanh(self.fc22(x_))

    @staticmethod
    def reparameterize(mu_h, log_var_h):
        """
        Perform the reparametrization trick. The reparametrization trick in VAE
        makes it tractable for BP to improve the distribution of h.

        Parameters
        ----------
        mu_h: Variable whose data is Tensor of shape n x 24 with requires_grad=True
            mean of the modeled gaussian distribution for h
        log_var_h: Variable whose data is Tensor of shape n x 24 with requires_grad=True
            logarithm of the covariance of the modeled gaussian distribution for h

        Returns
        -------
        h_sampled: Variable whose data is Tensor of shape n x 24 with requires_grad=True
            h_sampled = mu_h + epsilon x covariance, where epsilon is sampled from a
            standard normal distribution
        """
        std = log_var_h.mul(0.5).exp_()
        epsilon = th.Tensor(std.size()).normal_()
        epsilon = Variable(epsilon, requires_grad=False).type(th.Tensor)
        return epsilon.mul(std).add_(mu_h)

    def forward(self, x):
        """
        Reconstruct a given (s,a).

        Parameters
        ----------
        x: Variable whose data is Tensor of shape n x 9 with requires_grad=False
            x = (s, a) with a one-hot representation of a. Note when we are collecting
            real-time experience, where the corresponding actions are unknown, simply set
            a = [0, 0, 0].

        Returns
        -------
        p: Variable whose data is Tensor of shape n x 3 with requires_grad=True
           The data of p may be interpreted as probability of taking discrete
           action 1, 2, 3 separately.
        """
        mu_h, log_var_h = self.encode(x)
        indices = th.arange(0, 6).type(th.LongTensor)
        h = self.reparameterize(mu_h, log_var_h)
        p = F.softmax(F.tanh(self.fc3(th.cat([x.index_select(1, indices), h], 1))))
        # Note we return the mean and covariance of the modeled Gaussian and they will be
        # used to calculate the closed form KL divergence between the distribution of
        # p(h|s,a) and the distribution of p(h|s).
        return mu_h, log_var_h, p


# -*- coding: utf-8 -*-
"""
    Straply
    ~~~~~~~~

    Main views
"""

import requests

from pprint import pprint

from flask import Blueprint, render_template, flash, redirect, url_for, request, abort, jsonify
from flask_security import login_required, current_user, login_user, logout_user

from . import route
from ..core import db
from ..services import _User
from ..models import User, Card
from ..forms import userSettingsForm

bp = Blueprint('main', __name__)

@route(bp, '/')
def index():
    """Returns the index."""
    return render_template('index.html')

@route(bp, '/trello-router', methods=['GET', 'POST'])
def trello_router():
    """Routes updates to a trello card to the right message on Slack."""
    # pprint(request.json)
    webhook_resp = request.json
    if not webhook_resp:
        return jsonify(dict(OK=True))
    delta = webhook_resp.get('action')
    card_id = delta['data']['card']['id']
    pprint(request.json)

    if delta['type'] in ["createCard", "copyCommentCard"]:
        card = Card(trello_card_id=card_id)
        db.session.add(card)
        db.session.commit()
        print("card id", card_id)

    # Fetch the card from the database
    card = Card.query.filter_by(trello_card_id=card_id).first()

    if delta['type'] == "addLabelToCard":
        # Check to see if it's the weekly commit label
        details = delta['data']
        if "label" in details:
            if details['label']['name'] == "Weekly Commits":
                card = Card.query.filter_by(trello_card_id=card_id).first()
                card.weekly_commits = True
                db.session.commit()

    if delta['type'] == "removeLabelFromCard":
        # Check to see if it's the weekly commit label
        details = delta['data']
        if "label" in details:
            if details['label']['name'] == "Weekly Commits":
                card = Card.query.filter_by(trello_card_id=card_id).first()
                card.weekly_commits = False
                db.session.commit()

    if delta['type'] in ['createCheckItem', 'deleteCheckItem', 'updateCheckItemStateOnCard', 'updateCheckItem']:
        # Is this a weekly commit card?
        if card.weekly_commits:
            print("This is a weekly commit card")
            # Fetch the whole card
            r = requests.get("https://trello.com/1/cards/" + card_id, params={
                "key": "TRELLO_KEY",
                "token": "TRELLO_USER_TOKEN",
                "checklists": "all"
            })
            if r.status_code != 200:
                abort(500)
            full_card = r.json()
            # Send a message to Slack
            pprint(full_card)
            checklist = full_card['checklists'][0]
            text = ""
            for i in checklist['checkItems']:
                if i['state'] == "incomplete":
                    text = text + ":white_square: " + i['name'] + "\n"
                else:
                    text = text + ":white_check_mark:  " + i['name'] + "\n"
            print(text)
            if not card.slack_message_id:
                url = "https://slack.com/api/chat.postMessage"
                data = {
                    "token": "SLACK_TOKEN",
                    "channel": "SLACK_CHANNEL",
                    "as_user": "true",
                    "text": text
                }
            else:
                url = "https://slack.com/api/chat.update"
                data = {
                    "token": "SLACK_TOKEN",
                    "channel": "SLACK_CHANNEL",
                    "as_user": "true",
                    "text": text,
                    "ts": card.slack_message_id
                }
            # Add the message on Slack
            print("Sending this card to slack!")
            sr = requests.post(url, data)
            smessage = sr.json()
            pprint(smessage)
            if 'message' in smessage:
                card.slack_message_id = smessage['message']['ts']
            elif 'ts' in smessage:
                card.slack_message_id = smessage['ts']
            db.session.commit()
        else:
            print("Not a weekly commit card!")

    else:
        card = Card.query.filter_by(trello_card_id=card_id).first()
        if card:
            print("found card", card.trello_card_id, card.slack_message_id)

    return render_template('index.html')

@route(bp, '/preferences', methods=['GET', 'POST'])
@login_required
def preferences():
    """Allows user to change account prefs"""
    form = userSettingsForm(obj=current_user)
    if form.validate_on_submit():
        form.populate_obj(current_user)
        db.session.commit()
        flash('Successfully updated your profile', 'success')
    return render_template('preferences.html', form=form)


from selenium import webdriver
import time

class driverCall():
    def __init__(self):
        options = webdriver.ChromeOptions()
        options.add_argument("--incognito")
        options.add_argument("window-size=500,500")
        driver = webdriver.Chrome(chrome_options=options)
        driver.get('https://youtu.be/8rqgGZrsB7g')
        driver.find_element_by_xpath("//button[@class='ytp-play-button ytp-button']").click()
        driver.find_element_by_xpath("//button[@class='ytp-mute-button ytp-button']").click()
        driver.find_element_by_xpath("//button[@class='ytp-button ytp-settings-button']").click()
        driver.find_element_by_xpath("//div[@class='ytp-menuitem-label']").click()
        element = driver.find_element_by_xpath("//div[@class='ytp-menuitem-content']")
        driver.minimize_window()
        time.sleep(601)
        driver.quit()
while(True):
    objs = {}
    for x in range(10) :
        objs[x]= driverCall()


import sys
import json
import time
import spacy
#from spacy.tokens import Doc
import random
import logging
import argparse
from collections import defaultdict
from noise.Noiser import Noiser
#from utils.FlaubertTok import FlaubertTok
#from utils.Lexicon import Lexicon
from utils.Utils import create_logger#, MAX_IDS_LEN, KEEP, get_linear, shape_of_word, reshape, build_sentence, Word, PUNCTUATION
#from noise.LemRules import LemRules
#from noise.Misspell import Misspell
#from model.Vocab import Vocab

if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('--lex', type=str, default=None, help='Lexicon (pickle) file [required]', required=True)
    parser.add_argument('--pho', type=str, default=None, help='Homophones (pickle) file [required]', required=True)
    parser.add_argument('--lem', type=str, default=None, help='LemRules config file [required]', required=True)
    #
    parser.add_argument('--errors', type=str, default=None, help='Error vocabulary (None) [required]', required=True)
    parser.add_argument('--correc',  type=str, default=None, help='Correction vocabulary (None) [required]', required=True)
    parser.add_argument('--lfeats', type=str, default=None, help='Linguistic features vocabulary (None) [required]', required=True)
    parser.add_argument('--shapes', type=str, default=None, help='Shape vocabulary (None) [required]', required=True)
    parser.add_argument('--inlexi', type=str, default=None, help='Inlexicon vocabulary (None) [required]', required=True)
    #
    parser.add_argument('--max_n', type=int, default=7, help='Maximum number of noises per sentence (7)')
    parser.add_argument('--max_r', type=float, default=0.3, help='Maximum ratio of noises/words per sentence (0.3)')
    parser.add_argument('--p_cor', type=float, default=0.5, help='probability of using cor layer without err (0.5)')
    parser.add_argument('--p_lng', type=float, default=0.5, help='probability of using lng layer without err (0.5)')
    #
    parser.add_argument('--w_phon', type=int, default=4, help='Weight of PHON noise [err/cor] (4)')
    parser.add_argument('--w_lemm', type=int, default=6, help='Weight of LEMM noise [err/cor] (6)')
    parser.add_argument('--w_spel', type=int, default=2, help='Weight of SPEL noise [err/cor] (2)')
    parser.add_argument('--w_apnd', type=int, default=1, help='Weight of APND noise [err/cor] (1)')
    parser.add_argument('--w_splt', type=int, default=1, help='Weight of SPLT noise [err/cor] (1)')
    parser.add_argument('--w_dele', type=int, default=1, help='Weight of DELE noise [err] (1)')
    parser.add_argument('--w_mrge', type=int, default=1, help='Weight of MRGE noise [err] (1)')
    parser.add_argument('--w_hyph', type=int, default=5, help='Weight of HYPH noise [err] (5)')
    parser.add_argument('--w_swap', type=int, default=1, help='Weight of SWAP noise [err] (1)')
    parser.add_argument('--w_case', type=int, default=1, help='Weight of CASE noise [err] (1)')
    #
    parser.add_argument('--seed', type=int, default=0, help='Seed for randomness (0)')
    parser.add_argument('--log', type=str, default="info", help='Log level (info)')
    args = parser.parse_args()
    create_logger(None, args.log)
    logging.info("Options = {}".format(args.__dict__))

    noises = []
    for k,v in args.__dict__.items():
        if k.startswith('w_'):
            noises.append([k[2:], v])

    noiser = Noiser(noises,args.lem,args.lex,args.pho,args.errors,args.correc,args.lfeats,args.shapes,args.inlexi,args.max_n,args.max_r,args.p_cor,args.p_lng,args.seed)

    n_sents = 0
    tic = time.time()
    for l in sys.stdin:
        ldict = noiser(json.loads(l))
        print(json.dumps(ldict, ensure_ascii=False))
        n_sents += 1
        if n_sents%10000 == 0:
            noiser.debug(tic)
    logging.info('Done')
    noiser.debug(tic)


from django.core.mail import send_mail, EmailMultiAlternatives
from django.conf import settings
from django.template.loader import get_template

def email_confirmation(email, conf_number, url, first_name, last_name):
    subject=f'STAUD Agent Confirmation'
    body=f""
    from_email=settings.EMAIL_HOST_USER
    recipient_list=[email]
    message = EmailMultiAlternatives(subject=subject, body=body, from_email=from_email, to=recipient_list)
    html_template = get_template('accounts/agent_confirmation.html').render(context={'email': email, "conf_number": conf_number, "url": url,
                                                                                'first_name':first_name, 'last_name': last_name})
    message.attach_alternative(html_template, 'text/html')
    message.send()


import pandas as pd
import torch
import numpy as np
import soundfile as sf
import os

model = torch.hub.load('harritaylor/torchvggish', 'vggish')
model.eval()
df=pd.DataFrame(np.load('./resources/working_data/data.npy',allow_pickle = True),columns=['video_id','start_time','mid_ts','label','audio'])

df['vggish']=''
for index,row in df.iterrows():
    file_name = './resources/working_data/'+f'block_{index}.wav'
    sf.write(file_name, row['audio'], 44100)
    vgg = model.forward(file_name)
    df['vggish'][index] = vgg
    if os.path.exists(file_name):
        os.remove(file_name)
    else:
        print("The file does not exist")

    if index == 1:
        break

out = df.to_numpy()
np.save('../resources/working_data/data_with_vggish.npy', out)


import sys
sys.path.append('../../')
import argparse
import random
import numpy as np
import time
import pickle
import torch
from collections import defaultdict
from itertools import chain
from pathlib import Path
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.distributions import Categorical
from collections import namedtuple
from random import sample

SavedAction = namedtuple('SavedAction', ['log_prob', 'value'])
from data.path.rl_model import *

import math

class Prepared_data:
    def __init__(self, **kargs):
        self.ui_dict = dict()
        self.iu_dict = dict()
        self.ic_dict = dict()
        self.ci_dict = dict()
        self.ib_dict = dict()
        self.bi_dict = dict()
        self.usize = kargs.get('usize')
        self.isize = kargs.get('isize')
        self.csize = kargs.get('csize')
        self.bsize = kargs.get('bsize')
        self.embeddings = np.zeros((self.usize + self.isize + self.csize + self.bsize, 100))
        self.user_embedding = np.zeros((self.usize, 100))
        self.item_embedding = np.zeros((self.isize, 100))
        self.category_embedding = np.zeros((self.csize, 100))
        self.brand_embedding = np.zeros((self.bsize, 100))

        self.userid = torch.arange(0, self.usize)
        self.itemid = torch.arange(self.usize, self.usize + self.isize)
        self.categoryid = torch.arange(self.usize + self.isize, self.usize + self.isize + self.csize)
        self.brandid = torch.arange(self.usize + self.isize + self.csize,
                                    self.usize + self.isize + self.csize + self.bsize)

        print('Begin to load data')
        start = time.time()

        self.load_embedding(kargs.get('node_emb_dic'))

        self.load_ui(kargs.get('ui_relation_file'))
        self.load_ic(kargs.get('ic_relation_file'))
        self.load_ib(kargs.get('ib_relation_file'))

        end = time.time()
        print('Load data finished, used time %.2fs' % (end - start))

    def load_embedding(self, embfile):
        nodewv_dic = pickle.load(open(embfile, 'rb'))
        nodewv_tensor = []
        all_nodes = list(range(len(nodewv_dic.keys())))
        for node in all_nodes:
            nodewv_tensor.append(nodewv_dic[node].numpy())
        nodewv_tensor = torch.Tensor(nodewv_tensor)
        self.embeddings = nodewv_tensor
        # because when we save all embeddings, the order is user, item, category and brand
        self.user_embedding = nodewv_tensor[:self.usize, :]
        self.item_embedding = nodewv_tensor[self.usize : self.usize + self.isize, :]
        self.category_embedding = nodewv_tensor[self.usize + self.isize : self.usize + self.isize + self.csize, :]
        self.brand_embedding = nodewv_tensor[self.usize + self.isize + self.csize : self.usize + self.isize + self.csize + self.bsize, :]

        return self.user_embedding, self.item_embedding, self.category_embedding, self.brand_embedding

    def load_ui(self, uifile):
        user_item_data = open(uifile, 'r').readlines()
        for user_item_ele in user_item_data:
            user_item_ele_list = user_item_ele.strip().split(',')
            user = int(user_item_ele_list[0])
            item = int(user_item_ele_list[1])
            if item not in self.iu_dict.keys():
                self.iu_dict[item] = [user]
            else:
                self.iu_dict[item].append(user)

            if user not in self.ui_dict.keys():
                self.ui_dict[user] = [item]
            else:
                self.ui_dict[user].append(item)
        return self.ui_dict, self.iu_dict

    def load_ib(self, ibfile):
        item_brand_data = open(ibfile, 'r').readlines()
        for item_brand_ele in item_brand_data:
            item_brand_ele_list = item_brand_ele.strip().split(',')
            item = int(item_brand_ele_list[0])
            brand = int(item_brand_ele_list[1])
            if item not in self.ib_dict.keys():
                self.ib_dict[item] = [brand]
            else:
                self.ib_dict[item].append(brand)

            if brand not in self.bi_dict.keys():
                self.bi_dict[brand] = [item]
            else:
                self.bi_dict[brand].append(item)
        return self.ib_dict, self.bi_dict

    def load_ic(self, icfile):
        item_category_data = open(icfile, 'r').readlines()
        for item_category_ele in item_category_data:
            item_category_ele_list = item_category_ele.strip().split(',')
            item = int(item_category_ele_list[0])
            category = int(item_category_ele_list[1])
            if item not in self.ic_dict.keys():
                self.ic_dict[item] = [category]
            else:
                self.ic_dict[item].append(category)

            if category not in self.ci_dict.keys():
                self.ci_dict[category] = [item]
            else:
                self.ci_dict[category].append(item)
        return self.ic_dict, self.ci_dict

def find_candidate(start, data, no_neighobor=[]):

    # The strategy to explore user-item paths and item-item paths is the same.

    userid = data.userid
    itemid = data.itemid
    categoryid = data.categoryid
    brandid = data.brandid
    candidate_neighbors = []
    try:
        if start in userid:
            candidate_neighbors = data.ui_dict[start]

        elif start in itemid:
            candidate_neighbors = data.ic_dict[start] + data.ib_dict[start]

        elif start in categoryid:
            candidate_neighbors = data.ci_dict[start]

        elif start in brandid:
            candidate_neighbors = data.bi_dict[start]

        if len(candidate_neighbors) < 50:
            candidate_neighbors_without_noneighbor = [item for item in candidate_neighbors if item not in no_neighobor]
            return candidate_neighbors_without_noneighbor
        else:
            return candidate_neighbors
    except KeyError:
        return -1

def top_k(start, candidate_neighbors, data):
    refinefolder = args.refinefolder
    ic_relation_file = refinefolder + 'item_category.relation'
    ib_relation_file = refinefolder + 'item_brand.relation'
    ui_relation_file = refinefolder + 'user_item.relation'
    node_emb_dic = args.basedatafolder + 'nodewv.dic'
    user_history_file = args.userhistoryfile
    usize = args.usize
    isize = args.isize
    csize = args.csize
    bsize = args.bsize

    h1 = data.embeddings[start]
    h1 = torch.Tensor(h1)

    action_values = []
    candidate_id = []

    if len(candidate_neighbors) <= 50:
        # if this neighbor doesn't have a neighbor, then not visit it.
        for n in candidate_neighbors:
            if find_candidate(n, data) == -1:
                candidate_neighbors.remove(n)

    if len(candidate_neighbors) > 50:
        candidate_neighbors = sample(candidate_neighbors, 50)

    for n in candidate_neighbors: # candidate_neighbors without no neighbor nodes
        # calculate score
        h2 = data.embeddings[n]
        h2 = torch.Tensor(h2)

        cos = nn.CosineSimilarity(dim=0, eps=1e-6)
        action_value = cos(h1, h2)

        action_values.append(action_value)
        candidate_id.append(n)

    action_values = torch.Tensor(action_values)
    if len(action_values) >= args.k:
        topk = torch.topk(action_values, args.k)
        topk_value = topk[0]
        topk_index = topk[1]

        neighbour_id = []
        for n in topk_index:
            neighbour_id.append(candidate_id[n])
    else:
        neighbour_id = candidate_id
        topk_value = action_values
    return neighbour_id, topk_value

def action_to_index(action, topk_index, topk_value):
    action_1 = action.detach().numpy()
    action_2 = int(action_1)
    h = len(topk_index)
    if action_2 > h:
        action_3 = int(action_2 / ACTION_RANGE / 2 * h)
        next_state = topk_index[action_3-1]
        next_state_value = topk_value[action_3-1]
    else:
        next_state = topk_index[action_2-1]
        next_state_value = topk_value[action_2 - 1]
    return next_state, next_state_value

def train_path(args, start, end, data):
    rl_planner = SMCP()

    refinefolder = args.refinefolder
    ic_relation_file = refinefolder + 'item_category.relation'
    ib_relation_file = refinefolder + 'item_brand.relation'
    ui_relation_file = refinefolder + 'user_item.relation'
    node_emb_dic = args.basedatafolder + 'nodewv.dic'
    user_history_file = args.userhistoryfile
    usize = args.usize
    isize = args.isize
    csize = args.csize
    bsize = args.bsize

    outputinstancesfolder = args.outputinstancesfolder
    output_ui_paths_filename = outputinstancesfolder + 'ui.paths'
    output_ii_paths_filename = outputinstancesfolder + 'ii.paths'

    # The strategy to explore user-item paths and item-item paths is the same.

    userid = data.userid
    itemid = data.itemid
    categoryid = data.categoryid
    brandid = data.brandid

    candidate_neighbors = find_candidate(start, data)

    topk_index, topk_value = top_k(start, candidate_neighbors, data)

    state = start
    state_emb = data.embeddings[state]
    done = 2

    reward = 1
    paths_list = []
    path_score_list = []
    no_neighobor = [] # do not visit these nodes again
    start_time = time.time()
    for epi in range(args.max_episode):
        epi_time = time.time()
        print(f'{epi} try time: {epi_time-start_time}')
        path = []
        values = []
        path.append(start)

        for k in range(args.max_length - 1):

            # state 100,
            action, _ = rl_planner.policy.get_action(state_emb)

            next_state, next_state_value = action_to_index(action, topk_index, topk_value)

            next_state_emb = data.embeddings[next_state]

            path.append(next_state)
            values.append(next_state_value)

            if next_state == end:
                done = 1

                reward += 100

                reward = torch.from_numpy(np.array(reward))
                done = torch.from_numpy(np.array(done))
                next_state_emb = next_state_emb.squeeze()

                if type(state_emb) is np.ndarray:
                    state_emb = torch.Tensor(state_emb)
                state_emb = state_emb.detach().numpy()
                action = action.detach().numpy()
                reward = reward.detach().numpy()
                next_state_emb = next_state_emb.detach().numpy()
                done = done.detach().numpy()

                rl_planner.buffer.push(state_emb, action, reward, next_state_emb, done)
                print('end_path:', path)
                path_score = np.average(values)
                paths_list.append(path)
                path_score_list.append(path_score)
                break

            candidate_neighbors=find_candidate(next_state, data, no_neighobor)
            if k != 0 and k != args.max_length - 2:
                if candidate_neighbors != -1:
                    if end in candidate_neighbors:
                        done = 1
                        reward += 100
                        reward = torch.from_numpy(np.array(reward))
                        done = torch.from_numpy(np.array(done))
                        next_state_emb = next_state_emb.squeeze()

                        if type(state_emb) is np.ndarray:
                            state_emb = torch.Tensor(state_emb)
                        state_emb = state_emb.detach().numpy()
                        action = action.detach().numpy()
                        reward = reward.detach().numpy()
                        next_state_emb = next_state_emb.detach().numpy()
                        done = done.detach().numpy()

                        rl_planner.buffer.push(state_emb, action, reward, next_state_emb, done)
                        state = next_state
                        state_emb = data.embeddings[state]
                        end_emb = data.embeddings[end]
                        # score of state to end
                        cos = nn.CosineSimilarity(dim=0, eps=1e-6)
                        next_state_value = cos(torch.Tensor(state_emb), torch.Tensor(end_emb))

                        path.append(end)
                        values.append(next_state_value)
                        print('end_path:', path)
                        path_score = np.average(values)
                        paths_list.append(path)
                        path_score_list.append(path_score)
                        break

            reward = torch.from_numpy(np.array(reward))
            done = torch.from_numpy(np.array(done))
            next_state_emb = next_state_emb.squeeze()

            if type(state_emb) is np.ndarray:
                state_emb = torch.Tensor(state_emb)
            state_emb = state_emb.detach().numpy()
            action = action.detach().numpy()
            reward = reward.detach().numpy()
            next_state_emb = next_state_emb.detach().numpy()
            done = done.detach().numpy()

            state_1 = state_emb

            rl_planner.buffer.push(state_emb, action, reward, next_state_emb, done)

            state = next_state

            state_emb = data.embeddings[state]

            if candidate_neighbors == -1 or len(candidate_neighbors) == 0:
                no_neighobor.append(state)
                reward -= 10
                done = 1

                rl_planner.buffer.push(state_1, action, reward, state_emb, done)
                break

            topk_index, topk_value = top_k(state, candidate_neighbors, data)

            if k == args.max_length - 1:
                if state != end:
                    reward -= 100

            if len(rl_planner.buffer) > args.batch_size:
                rl_planner.soft_q_update()

        print('path:', path)

    return paths_list, path_score_list

def get_path(args, start, end, data):
    paths_list, path_score_list = train_path(args, start, end, data)
    rl_planner = SMCP()

    state = start
    state_emb = data.embeddings[state]
    done = 2

    reward = 1

    candidate_neighbors = find_candidate(start, data)

    topk_index, topk_value = top_k(start, candidate_neighbors, data)

    good_path = []
    values = []

    for k in range(args.max_length - 1):
        # state 100,

        path = []
        scores = []
        path.append(start)

        # state 100,
        action, _ = rl_planner.policy.get_action(state_emb)

        next_state, next_state_value = action_to_index(action, topk_index, topk_value)
        next_state_emb = data.embeddings[next_state]
        path.append(next_state)
        values.append(next_state_value)

        if next_state == end:
            done = 1

            reward += 10

            reward = torch.from_numpy(np.array(reward))
            done = torch.from_numpy(np.array(done))
            next_state_emb = next_state_emb.squeeze()

            state_emb = state_emb.detach().numpy()
            action = action.detach().numpy()
            reward = reward.detach().numpy()
            next_state_emb = next_state_emb.detach().numpy()
            done = done.detach().numpy()

            rl_planner.buffer.push(state_emb, action, reward, next_state_emb, done)
            print('end_path:', path)
            good_path.append(path)
            path_score = np.average(values)
            paths_list.append(path)
            path_score_list.append(path_score)
            break

        candidate_neighbors = find_candidate(next_state, data)
        if k != 0 and k != args.max_length - 2:
            if candidate_neighbors != -1:
                if end in candidate_neighbors:
                    done = 1
                    reward += 100
                    reward = torch.from_numpy(np.array(reward))
                    done = torch.from_numpy(np.array(done))
                    next_state_emb = next_state_emb.squeeze()

                    if type(state_emb) is np.ndarray:
                        state_emb = torch.Tensor(state_emb)
                    state_emb = state_emb.detach().numpy()
                    action = action.detach().numpy()
                    reward = reward.detach().numpy()
                    next_state_emb = next_state_emb.detach().numpy()
                    done = done.detach().numpy()
                    rl_planner.buffer.push(state_emb, action, reward, next_state_emb, done)
                    state = next_state
                    state_emb = data.embeddings[state]
                    end_emb = data.embeddings[end]
                    # score of state to end
                    cos = nn.CosineSimilarity(dim=0, eps=1e-6)
                    next_state_value = cos(torch.Tensor(state_emb), torch.Tensor(end_emb))

                    path.append(end)
                    values.append(next_state_value)
                    print('end_path:', path)
                    path_score = np.average(values)
                    paths_list.append(path)
                    path_score_list.append(path_score)
                    break

        reward = torch.from_numpy(np.array(reward))
        done = torch.from_numpy(np.array(done))
        next_state_emb = next_state_emb.squeeze()

        state_emb = state_emb.detach().numpy()
        action = action.detach().numpy()
        reward = reward.detach().numpy()
        next_state_emb = next_state_emb.detach().numpy()
        done = done.detach().numpy()

        rl_planner.buffer.push(state_emb, action, reward, next_state_emb, done)

        state = next_state

        state_emb = data.embeddings[state]

        if candidate_neighbors == -1 or len(candidate_neighbors) == 0:
            break

        topk_index, topk_value = top_k(state, candidate_neighbors, data)

        if k == args.max_length - 1:
            if state != end:
                reward -= 100

        if len(rl_planner.buffer) > args.batch_size:
            rl_planner.soft_q_update()

    print('get path:', path)

    # return good_path
    return paths_list, path_score_list

def ui_path(args):
    refinefolder = args.refinefolder
    ic_relation_file = refinefolder + 'item_category.relation'
    ib_relation_file = refinefolder + 'item_brand.relation'
    ui_relation_file = refinefolder + 'user_item.relation'
    node_emb_dic = args.basedatafolder + 'nodewv.dic'
    usize = args.usize
    isize = args.isize
    csize = args.csize
    bsize = args.bsize

    outputinstancesfolder = args.outputinstancesfolder
    output_ui_paths_filename = outputinstancesfolder + 'ui.paths'+'.'+str(args.start_user)+'-'+str(args.end_user)

    # load data
    data = Prepared_data(ib_relation_file=ib_relation_file, ic_relation_file=ic_relation_file,
                         ui_relation_file=ui_relation_file, node_emb_dic=node_emb_dic,
                         usize=usize, isize=isize, csize=csize, bsize=bsize)

    userid = data.userid
    itemid = data.itemid
    categoryid = data.categoryid
    brandid = data.brandid
    ui_file = open(output_ui_paths_filename, 'w+')

    part_user_id = torch.arange(args.start_user, args.end_user)
    for m in part_user_id:
        start = m.item()

        if find_candidate(start, data) == -1:
            break

        for n in data.ui_dict[start]:
            end = n
            print(f'\n\nstart:{start}\t end:{end}')

            paths_list, path_score_list = get_path(args, start, end, data)
            paths_list_unique = []
            path_score_list_unique = []
            #delete same paths
            for index,i in enumerate(paths_list):
                if i not in paths_list_unique:
                    paths_list_unique.append(i)
                    path_score_list_unique.append(path_score_list[index])
            zipped_paths_scores = list(zip(paths_list_unique, path_score_list_unique))
            res = sorted(zipped_paths_scores, key=lambda x: x[1],reverse=True)

            if len(paths_list_unique) >= args.top_n_paths:
                res = res[:args.top_n_paths]
            print(res)

            res_len = len(res)
            if res_len > 0:
                ui_file.write(str(start) + ',' + str(end) + '\t')
                ui_file.write(str(res_len)+'\t')
                for path,score in res:
                    path_str = [str(i) for i in path]
                    ui_file.write(' '.join(path_str))
                    ui_file.write('\t')
                ui_file.write('\n')
    ui_file.close()

def ii_path(args):
    refinefolder = args.refinefolder
    ic_relation_file = refinefolder + 'item_category.relation'
    ib_relation_file = refinefolder + 'item_brand.relation'
    ui_relation_file = refinefolder + 'user_item.relation'
    node_emb_dic = args.basedatafolder + 'nodewv.dic'
    usize = args.usize
    isize = args.isize
    csize = args.csize
    bsize = args.bsize

    outputinstancesfolder = args.outputinstancesfolder
    output_ii_paths_filename = outputinstancesfolder + 'ii.paths' + '.' + str(args.start_user) + '-' + str(
        args.end_user)

    # load data
    data = Prepared_data(ib_relation_file=ib_relation_file, ic_relation_file=ic_relation_file,
                         ui_relation_file=ui_relation_file, node_emb_dic=node_emb_dic,
                         usize=usize, isize=isize, csize=csize, bsize=bsize)

    userid = data.userid
    itemid = data.itemid
    categoryid = data.categoryid
    brandid = data.brandid
    ii_file = open(output_ii_paths_filename, 'w+')

    part_user_id = torch.arange(args.start_user, args.end_user)
    for user in part_user_id:
        user = user.item()

        num_item = len(data.ui_dict[user])
        item = data.ui_dict[user]
        for m in range(num_item - 1):
            start = item[m]
            end = item[m + 1]
            print(f'\n\nuser: {user}\t start item: {start}\t end item: {end}')

            if find_candidate(start, data) == -1:
                break

            paths_list, path_score_list = get_path(args, start, end, data)
            paths_list_unique = []
            path_score_list_unique = []
            for index, i in enumerate(paths_list):
                if i not in paths_list_unique:
                    paths_list_unique.append(i)
                    path_score_list_unique.append(path_score_list[index])
            zipped_paths_scores = list(zip(paths_list_unique, path_score_list_unique))
            res = sorted(zipped_paths_scores, key=lambda x: x[1], reverse=True)

            if len(paths_list_unique) >= args.top_n_paths:
                res = res[:args.top_n_paths]
            print(res)

            res_len = len(res)
            if res_len > 0:
                ii_file.write(str(start) + ',' + str(end) + '\t')
                ii_file.write(str(res_len) + '\t')
                for path, score in res:
                    path_str = [str(i) for i in path]
                    ii_file.write(' '.join(path_str))
                    ii_file.write('\t')
                ii_file.write('\n')
    ii_file.close()

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='generate user item and item item instances')
    parser.add_argument('start_user', type=int, default=0, nargs='?')
    parser.add_argument('end_user', type=int, default=11800, nargs='?')
    parser.add_argument('path_type', type=str, default='user',
                        nargs='?', help='user for user-item paths; item for item-item paths')

    parser.add_argument('basedatafolder', type=str, default='../Amazon_Music/',
                        nargs='?', help='this data base folder')
    parser.add_argument('outputinstancesfolder', type=str,
                        default='../Amazon_Music/path/all_ui_ii_instance_paths/',
                        nargs='?', help='this instances folder')
    parser.add_argument('refinefolder', type=str, default='../Amazon_Music/refine/',
                        nargs='?',
                        help='output to refine folder')
    parser.add_argument('userhistoryfile', type=str,
                        default='../Amazon_Music/path/user_history/user_history.txt',
                        nargs='?',
                        help='user history file')

    parser.add_argument('usize', type=int, default=1450, nargs='?')
    parser.add_argument('isize', type=int, default=11457, nargs='?')
    parser.add_argument('csize', type=int, default=429, nargs='?')
    parser.add_argument('bsize', type=int, default=1185, nargs='?')

    parser.add_argument('k', type=int, default=10, nargs='?')
    parser.add_argument('top_n_paths', type=int, default=10, nargs='?')
    parser.add_argument('max_length', type=int, default=6, nargs='?')
    parser.add_argument('replay_buffer_size', type=int, default=100000, nargs='?')
    parser.add_argument('max_episode', type=int, default=50, nargs='?')

    parser.add_argument('batch_size', type=int, default=1024, nargs='?')
    args = parser.parse_args()

    Path(args.outputinstancesfolder).mkdir(parents=True, exist_ok=True)

    if args.path_type == 'user':
        ui_path(args)
    elif args.path_type == 'item':
        ii_path(args)
    else:
        print('Please enter correct path type: user or item')


from datetime import datetime
import os
from datetime import timedelta
import openpyxl
import methoden
from time import  sleep
print("Das einzugebende format ist mit 0 ")
dan = input("Tag anfang")
man= input ("Monat anfang")
jan= input("Jahr anfang")

den = input("Tag Ende ")
men= input ("Monat Ende")
jen= input("Jahr Ende")
anfang = datetime.strptime(f"{dan}-{man}-{jan}",'%d-%m-%Y')
ende= datetime.strptime(f"{den}-{men}-{jen}",'%d-%m-%Y')
akt = anfang
while akt<= ende:
    if os.path.exists(f"Z:/Kassenblatt/{akt.year}/{akt.month}/{akt.day}.xlsx"):
        wb=openpyxl.load_workbook(f"Z:/Kassenblatt/{akt.year}/{akt.month}/{akt.day}.xlsx")
        sheet= wb.active
        sheet=methoden.bar(sheet,akt)
        wb.save(f"Z:/Kassenblatt/{akt.year}/{akt.month}/{akt.day}.xlsx")
        sleep(1)
    else:
        methoden.haupt(akt)
    #os.startfile(f"Z:/Kassenblatt/{akt.year}/{akt.month}/{akt.day}.xlsx","print")

    akt=akt+timedelta(1)


import shutil
import subprocess
import sys

from pathlib import Path
from typing import Dict, IO, List, Tuple

def main() -> int:
    # Parse command line arguments:
    args: List[str, ] = sys.argv[1:]
    # print(f"args={args}")
    if len(args) == 0:
        print(f"Usage: serial_agent.py [WORKSPACE_DIR] [PACKAGE_NAME]")

    workspace_directory: Path = Path("/tmp/dev_ws") if len(args) <= 1 else Path(args[0])
    package_name: str = "serial_agent" if len(args) <= 2 else args[1]
    # print(f"workspace_directory='{workspace_directory}' package_name='{package_name}'")

    # Create the various directories:
    ros2_package_directory: Path = workspace_directory / "src" / package_name
    python_package_directory: Path = ros2_package_directory / package_name
    python_package_directory.mkdir(parents=True, exist_ok=True)

    # Write out the `package.xml` and `__init__.py` files:
    package_xml_create(ros2_package_directory, package_name)
    init_py_create(python_package_directory)
    setup_cfg_create(ros2_package_directory, package_name)
    setup_py_create(ros2_package_directory, package_name)
    resource_create(ros2_package_directory, package_name)

    # Read in
    serial_agent_py_source: Path = Path("serial_agent.py")
    serial_agent_py_destination: Path = python_package_directory / "serial_agent.py"

    if True:
        shutil.copyfile(serial_agent_py_source, serial_agent_py_destination)
        print(f"{serial_agent_py_source} copied to {serial_agent_py_destination}")
        return 0

    # Temporary testing of SerialAgentGenerator class:
    serial_agent_generator: SerialAgentGenerator = SerialAgentGenerator()
    # Temporary:
    serial_agent_generator.publisher_add("std_msgs.msg", "String", "topic")
    serial_agent_generator.subscription_add("std_msgs.msg", "String", "topic")
    serial_agent_generator.client_add("example_interfaces", "AddTwoInts", "add_two_ints")
    serial_agent_generator.server_add("example_interfaces", "AddTwoInts", "add_two_ints")
    serial_agent_generator.timer_add("add_two_ints", "String", 4.0)
    serial_agent_generator.serial_agent_py_create(ros2_package_directory, package_name)

    return 0

class ImportManager(object):
    """Class to keep track of import statements.

    It is really easy for different packages to conflict on the type names that
    they create.  This package attempts to detect these errors and fail with a
    a semi useful error message.
    """

    # ImportManager.__init__():
    def __init__(self) -> None:
        """Initialize ImportManager"""
        self.all_tags: Tuple[str, ...] = ()  # All allowed tags
        self.tag_to_import_lines: Dict[str, List[str]] = {}  # tag => lines
        self.tag_to_comment_line: Dict[str, str] = {}  # tag => comment line
        self.import_lines_to_tag: Dict[str, str] = {}  # import_line => tag
        self.global_to_import_line: Dict[str, str] = {}  # global_name => import_line

    # ImportManager.tag_create():
    def tag_create(self, tag: str, comment_line: str) -> None:
        """Create an import tag."""
        assert tag not in self.all_tags, "Duplicate tag '{tag}' creation."
        self.all_tags += (tag,)
        self.tag_to_comment_line[tag] = comment_line
        self.tag_to_import_lines[tag] = []

    # ImportManager.insert():
    def insert(self, tag: str, global_name: str, import_line: str, comment: str) -> None:
        if global_name == "AddTwoInts":
            print(f">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> {tag}")
        assert tag in self.all_tags, f"Tag '{tag}' is not one of {self.all_tags}."
        if global_name in self.global_to_import_line:
            # Duplicate global name.  It may be OK:
            previous_import_line: str = self.global_to_import_line[global_name]
            assert import_line  == previous_import_line, (
                f"'{global_name}' is defined by both '{previous_import_line}' and '{import_line}'")
        else:
            if import_line not in self.tag_to_import_lines[tag]:
                self.global_to_import_line[global_name] = import_line
                self.import_lines_to_tag[import_line] = tag
                if comment:
                    import_line += f"  # {comment}"
                self.tag_to_import_lines[tag].append(import_line)

    # ImportManager.simple_import():
    def simple_import(self, tag: str, global_name: str, comment: str = "") -> None:
        """Generate a simple import statement."""
        import_line: str = f"import {global_name}"
        self.insert(tag, global_name, import_line, comment)

    # ImportManager.import_as():
    def import_as(self, tag: str, import_name: str, global_name: str, comment: str = "") -> None:
        """Generate an import/as statement."""
        import_line: str = f"import {import_name} as {global_name}"
        self.insert(tag, global_name, import_line, comment)

    # ImportManager.from_import():
    def from_import(self, tag: str, import_name: str, global_name: str, comment: str = "") -> None:
        """Generate an from/import statement."""
        assert global_name != "topic", f"tag='{tag}"  # Debug only
        import_line: str = f"from {import_name} import {global_name}"
        self.insert(tag, global_name, import_line, comment)

    # ImportManager.from_import_as():
    def from_import_as(self, tag: str, import_name: str,
                       actual_name: str, global_name: str, comment: str = "") -> None:
        """Generate a from/import/as statement."""
        import_line: str = f"from {import_name} import {actual_name} as {global_name}"
        self.insert(tag, global_name, import_line, comment)

    # ImportManager.import_lines_get():
    def import_lines_get(self) -> List[str]:
        """Return a list of all of the imports."""
        # Standard import lines go first:
        import_lines: List[str] = [
            "",
            "# Type hint imports:",
            "from typing import Any, Callable, Dict, List, Optional, Set",
        ]

        # Append the remaining import lines on a tag by tag basis:
        tag: str
        for tag in self.all_tags:
            tag_import_lines: List[str] = self.tag_to_import_lines[tag]
            if tag_import_lines:
                comment_line: str = self.tag_to_comment_line[tag]
                import_lines.extend(["", comment_line] + sorted(self.tag_to_import_lines[tag]))

        return import_lines

    # ImportManager.service_types_import():
    def service_types_import(self, service_package: str, service_type: str) -> Tuple[str, str]:
        """Import the types needed for a service."""

        # Ensure that the service message type is imported.
        # self.from_import("server", service_package, service_type, "type: ignore")

        # Also ensure that associated Request and Response types are imported:
        request_type: str = f"{service_type}.Request"
        response_type: str = f"{service_type}.Response"
        self.from_import("service", f"{service_package}.srv", service_type, "type: ignore")
        return request_type, response_type

# TaggedLines:
class TaggedLines(object):
    """Class for managing the tagged lines."""

    # TaggedLines.__init__():
    def __init__(self) -> None:
        """Initialize the InitManager."""

        self.tags: Tuple[str, ...] = ()
        self.lines: Dict[str, List[str]] = {}
        self.prefix_lines: Dict[str, List[str]] = {}

    # TaggedLines.tag_create():
    def tag_create(self, tag: str, prefix_lines: List[str]) -> None:
        """Create a new tag tagged buffer."""

        assert tag not in self.tags, f"Defining a duplicate tag: '{tag}'"
        self.tags += (tag,)
        self.lines[tag] = []
        self.prefix_lines[tag] = prefix_lines

    # TaggedLine.prefix_set():
    def prefix_set(self, tag: str, prefix_lines: List[str]) -> None:
        """Set the prefix lines."""
        assert tag in self.tags, f"Unknown tag '{tag}'"
        self.prefix_lines[tag] = prefix_lines

        # Force the prefix to show up.
        self.lines[tag].append("")

    # TaggedLines.extend():
    def extend(self, tag: str, lines: List[str]) -> None:
        """Append some lines to a tagged buffer."""
        assert tag in self.tags, f"Unknonw tag '{tag}'"
        self.lines[tag].extend(lines)

    # TaggegLines.lines_get():
    def lines_get(self) -> List[str]:
        """Return the tagged lines as a single list of lines."""
        all_lines: List[str] = []
        tag: str
        for tag in self.tags:
            lines: List[str] = self.lines[tag]
            # Empty lines a the end for rce
            if lines:
                # Empty lines are trimmed.  Thus, a prefix only can be output:
                while lines and lines[0] == "":
                    lines.pop(0)
                all_lines.extend([""] + self.prefix_lines[tag] + lines)
        return all_lines

# SerialAgentGenerator:
class SerialAgentGenerator(object):
    """Class for generating a serial agent."""

    # SerialAgentGenerator.__init__():
    def __init__(self) -> None:
        """Initialize SerialAgentGenerator."""

        # Create all of the import tags for *import_manager*:
        import_manager: ImportManager = ImportManager()
        import_manager.tag_create("required", "# Required imports:")
        import_manager.tag_create("publisher", "# Publisher required imports:")
        import_manager.tag_create("subscription", "# Subscription required imports:")
        import_manager.tag_create("message", "# Message type required imports:")
        import_manager.tag_create("client", "# Client required imports:")
        import_manager.tag_create("server", "# Server required imports:")
        import_manager.tag_create("service", "# Service type required imports:")
        import_manager.tag_create("timer", "# Timer required imports:")
        self.import_manager: ImportManager = import_manager

        # Fill in the requried imports:
        import_manager.simple_import("required", "rclpy", "type: ignore")
        import_manager.from_import_as("required", "rclpy.impl.rcutils_logger",
                                      "RcutilsLogger", "Logger", "type: ignore")
        import_manager.from_import("required", "rclpy.node", "Node", "type: ignore")

        # Various sections of generated code.
        indent: str = " " * 8
        init_tagged_lines: TaggedLines = TaggedLines()
        init_tagged_lines.tag_create("publisher", [])
        init_tagged_lines.tag_create("subscription", [])
        init_tagged_lines.tag_create("client", [])
        init_tagged_lines.tag_create("server", [])
        init_tagged_lines.tag_create("timer", [])

        # This comes last:
        init_tagged_lines.tag_create("server_wait", [])  # Prefix lines filled elsewhere

        self.init_tagged_lines: TaggedLines = init_tagged_lines

        # Callback methods are added to this list:
        callback_tagged_lines: TaggedLines = TaggedLines()
        callback_tagged_lines.tag_create("subscription", [])
        callback_tagged_lines.tag_create("client", [])
        callback_tagged_lines.tag_create("server", [])
        callback_tagged_lines.tag_create("timer", [])
        self.callback_tagged_lines: TaggedLines = callback_tagged_lines

        # Copyright lines for the beginning of the file:
        self.copyright_lines: List[str] = [
            "# Code generated by ros2_serial_manager.py.",
            "# Generated code is not really covered by copyright law.",
        ]

        # Create the main() function:
        dq1: str = "\""
        dq3: str = dq1 * 3
        self.main_lines: List[str] = [
            "",
            "",
            "# main():",
            "def main(args: Optional[List[str]] = None) -> None:",
            "    # Initialize the Python ROS2 interface library.",
            "    rclpy.init(args=args)",
            "",
            "    # Create the serial agent Node:",
            "    serial_agent: SerialAgent = SerialAgent()",
            "",
            "    # Start the serial agent Node.  All activity occurs via callback routines:",
            "    print('Starting rclpy.spin()')",
            "    rclpy.spin(serial_agent)",
            "",
            "    # Destroy the serial agent node explicitly.",
            "    serial_agent.destroy_node()",
            "",
            "    # Shut down the Python ROS2 interface library.",
            "    rclpy.shutdown()",
        ]

        # Serial Agent class lines:
        self.class_header_lines: List[str] = [
            "",
            "",
            "# SerialAgent:",
            "class SerialAgent(Node):",
            f"    {dq3}Serial Agent for managing ROS2 topics and services.{dq3}",
        ]

        self.init_start_lines: List [str] = [
            "",
            "    # SerialAgent.init():",
            "    def __init__(self) -> None:",
            f"        {dq3}Initialize SerialAgent class.{dq3}",
            "",
            "        # Initialize the Node super-class:",
            "        super().__init__('serial_agent')",
        ]

        # The boiler plate code to call main() goes here:
        self.main_call_lines: List[str] = [
            "",
            "",
            "# Call main():",
            "if __name__ == '__main__':",
            "    main(args=None)",
        ]

    # SerialAgent.serial_agent_pyt_create():
    def serial_agent_py_create(self, ros2_package_directory: Path, package_name: str) -> None:
        """Write out `serial_agent.py` file."""
        dq1: str = "\""
        dq3: str = dq1 * 3

        # Joint all of the import lines into *all_import_lines*:
        all_import_lines: List[str] = self.import_manager.import_lines_get()
        all_init_lines: List[str] = self.init_start_lines + self.init_tagged_lines.lines_get()
        all_callback_lines: List[str] = self.callback_tagged_lines.lines_get()

        # Join all of the lines that make up the class into *all_class_lines*:
        all_class_lines: List[str] = (
            self.class_header_lines +
            all_init_lines +
            all_callback_lines
        )

        # Join all the lines together into *all_lines* and create a single
        all_lines: List[str] = (
            self.copyright_lines +
            all_import_lines +
            self.main_lines +
            all_class_lines +
            self.main_call_lines +
            [""]  # Trick to get the final new-line on the file content
        )

        # Generate the `serial_agent.py` file:
        all_content: str = "\n".join(all_lines)
        serial_agent_py_path: Path = ros2_package_directory / package_name / "serial_agent.py"
        serial_agent_py_file: IO[str]
        with open(serial_agent_py_path, "w") as serial_agent_py_file:
            serial_agent_py_file.write(all_content)

    # SerialAgent.publisher_add():
    def publisher_add(self, topic_package_name: str, topic_type: str, topic_name: str) -> None:
        """Add a publisher to the serial agent."""

        # Make sure the Publisher type is imported:
        import_manager: ImportManager = self.import_manager
        import_manager.from_import("publisher", "rclpy.publisher", "Publisher", "type: ignore")
        import_manager.from_import("message", topic_package_name, topic_type, "type: ignore")

        # Make sure the publisher tables are created:
        init_tagged_lines: TaggedLines = self.init_tagged_lines
        init_tagged_lines.prefix_set("publisher", [
            f"        # Create all topic Publisher's here:",
            f"        self.publishers_table: Dict[str, Publisher] = {{}}",
            f"        self.publishers_counter: Dict[str, int] = {{}}",
        ])

        # Add publisher here:
        subscription_callback_name: str = f"{topic_name}_subscription_callback"
        init_tagged_lines.extend("publisher", [
            f"        self.publishers_table['{topic_name}'] = self.create_publisher(",
            f"            {topic_type}, '{topic_name}', 10)",
            f"        self.publishers_counter['{topic_name}'] = 0",
        ])

    # SerialAgent.timer_add():
    def timer_add(self, timer_name: str, timer_type: str, period: float) -> None:
        """Add a timer callback."""

        # Ensure that the Timer type is imported:
        import_manager: ImportManager = self.import_manager
        import_manager.from_import("timer", "rclpy.timer", "Timer", "type: ignore")

        # Create the timer here:
        callback_name: str = f"{timer_name}_timer"
        init_tagged_lines: TaggedLines = self.init_tagged_lines
        init_tagged_lines.prefix_set("timer", [
            f"        # Create all Timer's here:",
            f"        self.timers_table: Dict[str, Timer] = {{}}",
            f"        self.timers_counter: Dict[str, int] = {{}}",
        ])
        init_tagged_lines.extend("timer", [
            f"        self.timers_table['{timer_name}'] = (",
            f"            self.create_timer({period}, self.{callback_name}))",
            f"        self.timers_counter['{timer_name}'] = 0",
        ])

        # Create the callback counter and function:
        dq1: str = "\""
        dq3: str = dq1 * 3
        callback_tagged_lines: TaggedLines = self.callback_tagged_lines
        callback_tagged_lines.extend("timer", [
            "",
            f"    # SerialAgent.{callback_name}:",
            f"    def {callback_name}(self) -> None:",
            f"        {dq3}Callback for {timer_name} Timer.{dq3}",
            "",
            f"        count: int = self.timers_counter['{timer_name}']",
            f"        message: {timer_type} = {timer_type}()",
            f"        message.data = f'Counter={{count}}'",
            "",
            f"        # Temporary:",
            f"        publisher: Publisher = self.publishers_table['topic']",
            f"        publisher.publish(message)",
            f"        print('\\nTimer({dq1}{timer_name}{dq1}): '",
            f"              f'Publish {{message}} to Topic({dq1}{timer_name}{dq1})')",
            "",
            f"        self.timers_counter['{timer_name}'] = count + 1",
            f"        # print('<=SerialAgent.{callback_name}()')",
        ])

    # SerialAgent.client_add():
    def client_add(self, service_package: str, service_type: str, client_name: str) -> None:
        """Add a client to the serial agent."""

        # Ensure that the Client type is imported:
        import_manager: ImportManager = self.import_manager
        import_manager.from_import("client", "rclpy.task", "Future", "type: ignore")
        import_manager.from_import("client", "rclpy.client", "Client", "type: ignore")

        request_type: str
        response_type: str
        request_type, response_type = import_manager.service_types_import(
            service_package, service_type)

        # Ensure that the client wait code is added to the __init__ startup.
        init_tagged_lines: TaggedLines = self.init_tagged_lines
        init_tagged_lines.prefix_set("server_wait", [
            "        # Wait for all requested client services to become available:",
            "        logger: Logger = self.get_logger()",
            "        while self.client_waits:",
            "            client_name: str",
            "            for client_name in tuple(self.client_waits):",
            "                client: Client = self.clients_table[client_name]",
            "                if client.wait_for_service():",
            "                    self.client_waits.remove(client_name)",
            "            if not self.client_waits:",
            "                logger.info(f'Waiting for {{client_waits}} to become available')",
        ])

        # Create the client and add it to the clients dictionariers:
        init_tagged_lines.prefix_set("client", [
            f"        # Client send rouines are defined here:",
        ])
        init_tagged_lines.prefix_set("client", [
            f"        # Create all service Client's here:",
            f"        self.clients_table: Dict[str, Client] = {{}}",
            f"        self.clients_counter: Dict[str, int] = {{}}",
            f"        self.client_waits: Set[str] = set()",
        ])
        init_tagged_lines.extend("client", [
            f"        self.clients_table['{client_name}'] = self.create_client(",
            f"            {service_type}, '{client_name}')",
            f"        self.clients_counter['{client_name}'] = 0",
            f"        self.client_waits.add('{client_name}')",
        ])

        # Generate a request routine with a callback for the eventual response:
        dq1: str = "\""
        dq3: str = dq1 * 3
        request_send_name: str = f"{client_name}_request_send"
        response_callback_name: str = f"{client_name}_response_callback"
        indent: str = " " * (len(request_send_name) + 1)
        callback_tagged_lines: TaggedLines = self.callback_tagged_lines
        callback_tagged_lines.extend("client", [
            "",
            f"    # SerialAgent.{request_send_name}()",
            f"    # Debugging:",
            f"    def {request_send_name}(self, a: int, b: int,",
            f"        {indent}response_callback: Callable[[Any], None]) -> None:",
            f"        {dq3}Initiate a request/response to/from {client_name} server.{dq3}",
            "",
            f"        request: {request_type} = {request_type}()",
            f"        request.a = a",
            f"        request.b = b",
            f"        client: Client = self.clients_table['{client_name}']",
            f"        response_future: Future = client.call_async(request)",
            f"        # Debugging:",
            f"        print(f'response_future={{response_future}})')",
            f"        response_future.add_done_callback(response_callback)",
            f"        print('Client({dq1}{client_name}{dq1}): '",
            f"              f'Sent {dq1}{{request}}{dq1}')",
        ])

        callback_tagged_lines.extend("client", [
            "",
            f"    # SerialAgent.{response_callback_name}():",
            f"    # Debugging:",
            f"    def {response_callback_name}(self, response_future: Future) -> None:",
            f"        {dq3}Response callback routine for {client_name}.{dq3}",
            "",
            f"        # Debugging:",
            f"        try:",
            f"            response: Any = response_future.result()",
            f"        except Exception as error:",
            f"            assert False, 'Fixme!'",
            f"        else:",
            f"            assert isinstance(response, {response_type})",
            f"            print('Client({dq1}{client_name}{dq1}): '",
            f"                  f'Got response={dq1}{{response}}{dq1}')",
        ])

    # SerialAgent.server_add():
    def server_add(self, service_package_name: str, service_type: str, server_name: str) -> None:
        """Add a server to the serial agent."""

        # Ensure that the Server type is imported.
        # Note rclpy.service.Service is changed to Server to be more consistent.
        import_manager: ImportManager = self.import_manager
        import_manager.from_import_as(
            "server", "rclpy.service", "Service", "Server", "type: ignore")

        # Ensure that the service Request and Response types are imported.
        request_type: str
        response_type: str
        request_type, response_type = import_manager.service_types_import(
            service_package_name, service_type)

        # Ensure that the server dictionaries are first initalized to empty:
        init_tagged_lines: TaggedLines = self.init_tagged_lines
        init_tagged_lines.prefix_set("server", [
            "        # Create all service Server's here:",
            "        self.servers_table: Dict[str, Server] = {}",
            "        self.servers_counter: Dict[str, int] = {}",
        ])

        # Create the server and add it to the servers dictionary:
        callback_name: str = f"{server_name}_server_callback"
        init_tagged_lines.extend("server", [
            f"        # Create all topic Subscription's here:",
            f"        self.servers_table['{server_name}'] = self.create_service(",
            f"            {service_type}, '{server_name}', self.{callback_name})",
            f"        self.servers_counter['{server_name}'] = 0",
        ])

        # Create the callback method for the server:
        dq1: str = "\""
        dq3: str = dq1 * 3
        indent: str = " " * len(callback_name)
        callback_tagged_lines: TaggedLines = self.callback_tagged_lines
        callback_tagged_lines.extend("server", [
            "",
            f"    # SerialAgent.{callback_name}() -> {response_type}:",
            f"    def {callback_name}(self,",
            f"         {indent}request: {request_type},",
            f"         {indent}response: {response_type}) -> None:",
            "",
            f"        {dq3}Callback for '{server_name}' service request.{dq3}",
            f"        # Debugging only:",
            f"        print(f'Service({dq1}{server_name}{dq1}): Got {dq1}{{request}}{dq1}')",
            f"        response.sum = request.a + request.b",
            f"        print(f'Service({dq1}{server_name}{dq1}): Sent {dq1}{{response}}{dq1}')",
            f"        return response",
        ])

    # SerialAgent.subscription_add():
    def subscription_add(self, subscription_package_name: str,
                         subscription_type: str, subscription_name: str) -> None:
        """Add a subscription to the serial agent."""

        # Make sure the Subscription type is imported:
        import_manager: ImportManager = self.import_manager
        import_manager.from_import(
            "subscription", "rclpy.subscription", "Subscription", "type: ignore")
        import_manager.from_import(
            "message", subscription_package_name, subscription_type, "type: ignore")

        # Ensure that the subscriptions dictionary is initalized to empty:
        init_tagged_lines: TaggedLines = self.init_tagged_lines
        init_tagged_lines.prefix_set("subscription", [
                "        # Create all topic Subscription's here:",
                "        self.subscriptions_table: Dict[str, Subscription] = {}",
                "        self.subscriptions_counter: Dict[str, int] = {}",
        ])

        # Create the subscription and add it to the subscriptions dictionary:
        callback_name: str = f"{subscription_name}_subscription_callback"
        init_tagged_lines.extend("subscription", [
            f"        self.subscriptions_table['{subscription_name}'] = self.create_subscription(",
            f"            {subscription_type}, '{subscription_name}', self.{callback_name}, 10)",
            f"        self.subscriptions_counter['{subscription_name}'] = 0",
        ])

        # Create the callback method for the subscription:
        dq1: str = "\""
        dq3: str = dq1 * 3
        callback_tagged_lines: TaggedLines = self.callback_tagged_lines
        callback_tagged_lines.extend("subscription", [
            "",
            f"    # SerialAgent.{callback_name}():",
            f"    def {callback_name}(self, message: {subscription_type}) -> None:",
            f"        {dq3}Callback for '{subscription_name}' topic subscription.{dq3}",
            f"        count: int = self.subscriptions_counter['{subscription_name}']",
            f"        count += 1",
            f"        self.subscriptions_counter['{subscription_name}'] = count",
            f"        # Debgging only:",
            f"        print(f'Subscription({dq1}{subscription_name}{dq1}): '"
            f"              f'Got {dq1}{{message.data}}{dq1}')",
            "",
            f"        # Debugging:",
            f"        a: int = count",
            f"        b: int = count + 1",
            f"        self.add_two_ints_request_send(a, b, self.add_two_ints_response_callback)",
        ])

def resource_create(ros2_package_directory: Path, package_name: str) -> None:
    """Create the resource directory an fill it in."""
    resource_directory: Path = ros2_package_directory / "resource"
    resource_directory.mkdir(parents=True, exist_ok=True)

    # Write out an empty file:
    resource_package_path: Path = resource_directory / package_name
    resource_package_file: IO[str]
    with open(resource_package_path, "w") as resource_package_file:
        pass

def setup_py_create(ros2_package_directory: Path, package_name: str) -> None:
    """Create the `setup.py` file. """
    email: str = email_get()
    maintainer: str = maintainer_get()
    setup_py_lines: Tuple[str, ...] = (
        "from setuptools import setup",
        "",
        f"package_name = '{package_name}'",
        "",
        "setup(",
        "    name=package_name,",
        "    version='0.0.0',",
        "    packages=[package_name],",
        "    data_files=[",
        "        ('share/ament_index/resource_index/packages',",
        "            ['resource/' + package_name]),",
        "        ('share/' + package_name, ['package.xml']),",
        "    ],",
        "    install_requires=['setuptools'],",
        "    zip_safe=True,",
        f"    maintainer='{maintainer}',",
        f"    maintainer_email='{email}',",
        "    description='ROS2 Serial line package',",
        "    license='MIT',",
        "    tests_require=['pytest'],",
        "    entry_points={",
        "        'console_scripts': [",
        f"            'serial_agent = {package_name}.serial_agent:main',",
        "        ],",
        "    },",
        ")",
        "",
    )
    setup_py_content: str ="\n".join(setup_py_lines)

    # Write *setup_py_lines_content* to *setup_py_path:
    setup_py_path: Path = ros2_package_directory / "setup.py"
    setup_py_file: IO[str]
    with open(setup_py_path, "w") as setup_py_file:
        setup_py_file.write(setup_py_content)

def package_xml_create(ros2_package_directory: Path, package_name: str) -> None:
    """Create the `package.xml` file."""
    # Get the *maintainer* and *email*:
    email: str = email_get()
    maintainer: str = maintainer_get()

    # Create the *package_xml_text* content.  Use single quotes for strings since XML
    # files tend to use double quotes a lot:
    package_xml_lines: Tuple[str, ...] = (
        '<?xml version="1.0"?>',
        ('<?xml-model href="http://download.ros.org/schema/package_format3.xsd"'
         ' schematypens="http://www.w3.org/2001/XMLSchema"?>'),
        '<package format="3">',
        f'  <name>{package_name}</name>',
        '  <version>0.0.0</version>',
        '  <description>Package for interacting with serial line.</description>',
        f'  <maintainer email="{email}">{maintainer}</maintainer>',
        '  <license>MIT</license>',
        '  <exec_depend>rclpy</exec_depend>',
        '  <exec_depend>std_msgs</exec_depend>',
        '',
        '  <test_depend>ament_copyright</test_depend>',
        '  <test_depend>ament_flake8</test_depend>',
        '  <test_depend>ament_pep257</test_depend>',
        '  <test_depend>python3-pytest</test_depend>',
        '',
        '  <export>',
        '    <build_type>ament_python</build_type>',
        '  </export>',
        '</package>',
        ''
    )
    package_xml_content: str = "\n".join(package_xml_lines)

    # Write out the *package_xml_content* to the `package.xml` file:
    package_xml_path: Path = ros2_package_directory / "package.xml"
    package_xml_file: IO[str]
    with open(package_xml_path, "w") as package_xml_file:
        package_xml_file.write(package_xml_content)

def init_py_create(python_package_directory: Path) -> None:
    """Create the empty `__init__.py` file."""
    init_py_path: Path = python_package_directory / "__init__.py"
    init_py_file: IO[str]
    with open(init_py_path, "w") as init_py_file:
        pass  # An empty file is what is desired

def setup_cfg_create(ros_package_directory: Path, package_name: str) -> None:
    """Create the `setup.cfg` file."""
    # Create the *setup_cfg_content*:
    setup_cfg_lines: Tuple[str, ...] = (
        "[develop]",
        f"script-dir=$base/lib/{package_name}",
        "[install]",
        f"install-scripts=$base/lib/{package_name}",
        "",
    )
    setup_cfg_content: str = "\n".join(setup_cfg_lines)

    # Write *setup_cfg_content* to *set_up_cfg_file*:
    setup_cfg_path: Path = ros_package_directory / "setup.cfg"
    setup_cfg_file: IO[str]
    with open(setup_cfg_path, "w") as setup_cfg_file:
        setup_cfg_file.write(setup_cfg_content)

def email_get() -> str:
    """Return the maintainer E-mail from git."""
    done: subprocess.CompletedProcess = subprocess.run(
        ["git", "config", "--get", "user.email"], capture_output=True, encoding="UTF-8")
    assert done.returncode == 0, "git config --get user.name has error code of {done.returncode}"
    return done.stdout.strip("\n")

def maintainer_get() -> str:
    """Return the maintainer name from git."""
    done: subprocess.CompletedProcess = subprocess.run(
        ["git", "config", "--get", "user.name"], capture_output=True, encoding="UTF-8")
    assert done.returncode == 0, "git config --get user.name has error code of {done.returncode}"
    return done.stdout.strip("\n")

if __name__ == "__main__":
    main()

# [Multiple futures await](https://stackoverflow.com/questions/46785274/asyncio-speculatively-await-multiple-futures)

#   client = MinimalClientAsync()
#   while rclpy.ok():
#       rclpy.spin_once()
#       response_futures: List[asyncio.Future] =
#       done_futures: List[asyncio.Future]
#       pending_futures: List[asyncio.Future]
#       done_futures, pending_futures = (
#           await asyncio.wait(response_futures, return_when=FIRST_COMPLETED))
#       # Ignore pending_futures
#       done_future: asyncio.Future
#       for done_future in done_futures:
#            try:
#                response = done_future.result()
#            except Exception as e:
#                # Remove from all_futures
#                # do something error like here
#            else:
#                # Remove from all_futures
#                # Response is valid here
#                # Do someithing with response

# request = example_interfaces.srv._add_two_ints.AddTwoInts_Request(1, 2)
# request.get_fields_and_types()  => {'a': 'int64', 'b': 'int64'}
#
# response = example_interfaces.srv._add_two_ints.AddTwoInts_Response()
# response.get_fields_and_types() => {'sum': 'int64'}


import cv2 as cv
import os as os
import skimage as skimage
from random import randint
import numpy as np

class DataAugmentation:
	def random_crop(self, img):
		width, height, chanel = img.shape
		x1 = randint(0, int(width*0.7))
		y1 = randint(0, int(height*0.7))

		edge_size = randint(10, width)
		x2 = min(width-1, x1 + edge_size)
		y2 = min(height-1, y1 + edge_size)
		temp = img[x1:x2, y1:y2, :]
		return cv.resize(temp, (height, width))

	def random_erasing(self, img):
		temp = img.copy()
		width, height, chanel = temp.shape
		x1 = randint(0, width)
		y1 = randint(0, height)

		x2 = randint(x1, width)
		y2 = randint(y1, height)

		temp[x1:x2, y1:y2, :] = 0
		return temp

	def contrast(self, img):
		# alpha value [1.0-3.0], beta value [0-100]
		return cv.convertScaleAbs(img, alpha=randint(100, 300) / 100, beta=randint(0, 100))

	def flip_horizontal(self, img):
		return cv.flip(img, 1)

	def flip_vertical(self, img):
		return cv.flip(img, 0)

	def flip_origin(self, img):
		return cv.flip(img, -1)

	def noise(self, img):
		out = skimage.util.random_noise(img, mode="gaussian")
		norm_image = cv.normalize(out, None, alpha=0, beta=255, norm_type=cv.NORM_MINMAX, dtype=cv.CV_32F)

		return norm_image.astype(np.uint8)

	def rotate_90_clockwise(self, img):
		return cv.rotate(img, cv.ROTATE_90_CLOCKWISE)

	def rotate_90_counter_clockwise(self, img):
		return cv.rotate(img, cv.ROTATE_90_COUNTERCLOCKWISE)

	def random_rotation(self, img):
		angle = randint(30, 330)
		height, width = img.shape[:2]
		rotate_matrix = cv.getRotationMatrix2D(center=(width / 2, height / 2), angle=angle, scale=1)
		return cv.warpAffine(src=img, M=rotate_matrix, dsize=(width, height))

	def translation(self, img):
		height, width, _ = img.shape
		x = int(width * 0.3)
		y = int(height * 0.3)
		M = np.float32([[1, 0, randint(-x, x)], [0, 1, randint(-y, y)]])
		return cv.warpAffine(img, M, (width, height))

	def brightness(self, img):
		value = randint(-100, 100)
		hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
		h, s, v = cv.split(hsv)
		v = cv.add(v, value)
		v[v > 255] = 255
		v[v < 0] = 0
		final_hsv = cv.merge((h, s, v))
		img = cv.cvtColor(final_hsv, cv.COLOR_HSV2BGR)
		return img

	def saturation(self, img):
		value = randint(-100, 100)
		hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
		h, s, v = cv.split(hsv)
		s = cv.add(s, value)
		s[s > 255] = 255
		s[s < 0] = 0
		final_hsv = cv.merge((h, s, v))
		img = cv.cvtColor(final_hsv, cv.COLOR_HSV2BGR)
		return img

	def hue(self, img):
		value = randint(-100, 100)
		hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
		h, s, v = cv.split(hsv)
		h = cv.add(h, value)
		h[h > 255] = 255
		h[h < 0] = 0
		final_hsv = cv.merge((h, s, v))
		img = cv.cvtColor(final_hsv, cv.COLOR_HSV2BGR)
		return img

	def grayScale(self, img):
		return cv.cvtColor(img, cv.COLOR_BGR2GRAY)

class Other:
	@staticmethod
	def file_extentions(directory):
		fileExts = set()
		_, _, filenames = next(os.walk(directory))

		for f in filenames:
			_, ext = os.path.splitext(f)
			fileExts.add(ext)

		if '' in fileExts:  # deleting directory extension if exists
			fileExts.remove('')

		return fileExts

	@staticmethod
	def get_method_with_its_name(func_name):
		return getattr(DataAugmentation, func_name)


from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required
from flask_cors import CORS

from http import HTTPStatus

from .controller import MachineController

machine_api_v1 = Blueprint('machine_api_v1', 'machine_api_v1', url_prefix='/api/v1/machine')
CORS(machine_api_v1)

@machine_api_v1.route('/', methods=['GET'])
@jwt_required()
def api_get_machines():
    try:
        response, status = MachineController.get_machines()
        return jsonify(response), status
    except Exception as e:
        return jsonify({'error': str(e)}), HTTPStatus.BAD_REQUEST

@machine_api_v1.route('/<id>', methods=['GET'])
@jwt_required()
def api_get_machine_by_id(id):
    try:
        response, status = MachineController.get_machine_by_id(id)
        return jsonify(response), status
    except Exception as e:
        return jsonify({'error': str(e)}), HTTPStatus.BAD_REQUEST

@machine_api_v1.route('/create', methods=['POST'])
@jwt_required()
def api_add_machine():
    req = request.get_json()
    try:
        user_id = req.get('user_id')
        receiver_ip = req.get('receiver_ip')
        receiver_port = req.get('receiver_port')
        package_capture_time = req.get('package_capture_time')
        package_capture_interval = req.get('package_capture_interval')
        inactivity_threshold = req.get('inactivity_threshold')

        response, status = MachineController.add_machine(user_id, receiver_ip, receiver_port, package_capture_time, package_capture_interval, inactivity_threshold)
        return jsonify(response), status
    except Exception as e:
        return jsonify({'error': str(e)}), HTTPStatus.BAD_REQUEST

@machine_api_v1.route('/<id>', methods=['DELETE'])
@jwt_required()
def api_delete_machine(id):
    try:
        response, status = MachineController.delete_machine(id)
        return jsonify(response), status
    except Exception as e:
        return jsonify({'error': str(e)}), HTTPStatus.BAD_REQUEST


import re
from PyQt5.Qt import QObject
from PyQt5.QtWebEngineWidgets import QWebEngineProfile
from mc.common import const
from mc.app.Settings import Settings

class UserAgentManager(QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._globalUserAgent = ''
        self._defaultUserAgent = ''

        self._usePerDomainUserAgent = False
        self._userAgentsList = {}  # QHash<QString, QString>

        self._defaultUserAgent = QWebEngineProfile.defaultProfile().httpUserAgent()
        self._defaultUserAgent = re.sub(r'QtWebEngine/[^\s]+', 'App/%s' % const.VERSION, self._defaultUserAgent)

    def loadSettings(self):
        settings = Settings()
        settings.beginGroup('Web-Browser-Settings')
        self._globalUserAgent = settings.value('UserAgent', '', type=str)
        settings.endGroup()

        settings.beginGroup('User-Agent-Settings')
        self._usePerDomainUserAgent = settings.value('UsePerDomainUA', False, type=bool)
        domainList = settings.value('DomainList', [], type=list)
        userAgentsList = settings.value('UserAgentsList', [], type=list)
        settings.endGroup()

        self._usePerDomainUserAgent = self._usePerDomainUserAgent and domainList.count() == userAgentsList.count()

        if self._usePerDomainUserAgent:
            for idx in range(domainList.count()):
                self._userAgentsList[domainList[idx]] = userAgentsList[idx]

        if not self._globalUserAgent:
            userAgent = self._defaultUserAgent
        else:
            userAgent = self._globalUserAgent

        QWebEngineProfile.defaultProfile().setHttpUserAgent(userAgent)

    def globalUserAgent(self):
        return self._globalUserAgent

    def defaultUserAgent(self):
        return self._defaultUserAgent

    def usePerDomainUserAgents(self):
        '''
        @return: bool
        '''
        return self._usePerDomainUserAgent

    def perDomainUserAgentsList(self):
        '''
        @return: QHash<QString, QString>
        '''
        return self._userAgentsList


"""
SQLite managing class definition
"""
import sqlite3
import os
import traceback
from sqlite3 import Error, DatabaseError
from app_lib.utils.files_utils import transform_path

class DataBase:
    """
    Main class to manage SQLite database
    """

    insert_query = "INSERT INTO {table_name} VALUES (?, ? ,? ,?)"
    table_name = ''

    def __init__(self):
        db_location = str(os.getcwd()).split('app_lib')[0] + transform_path('/app_lib/DDBB/sqlite/crypto_database')
        self.connection = sqlite3.connect(db_location)
        self.cursor = self.connection.cursor()

    def close(self) -> None:
        """
        Close the current open connection
        :return:
        """
        self.connection.close()

    def create_table(self) -> None:
        """
        Create table if it does not exist
        :return:
        """
        self.cursor.execute(
            f"CREATE TABLE {self.table_name} (DATE INTEGER, CLOSE REAL, MAXIMUM REAL, MINIMUM REAL)"
        )

    def check_if_table_exists(self) -> bool:
        """
        Checks if selected table already exists
        :return:
        """
        self.cursor.execute(
            f"SELECT name FROM sqlite_master WHERE name == '{self.table_name}'"
        )
        db_result = self.cursor.fetchone()
        if db_result and self.table_name in db_result:
            return True
        return False

    def set_array_data(self, tuples_array: list) -> None:
        """
        Insert many rows into the database
        :param tuples_array:
        :return:
        """
        self.cursor.executemany(
            self.insert_query.format(table_name=self.table_name),
            tuples_array
        )
        self.connection.commit()

    def set_data(self, tuple_data: tuple) -> None:
        """
        Insert a row into the database
        :param tuple_data:
        :return:
        """
        self.cursor.execute(
            self.insert_query.format(table_name=self.table_name),
            tuple_data
        )
        self.connection.commit()

    def get_data(self, date_init: int = None, date_end: int = None, select_columns: str = '*'):
        """
        Search and return data between given dates
        :param date_init: integer with YYYYMMDD form
        :param date_end: integer with YYYYMMDD form
        :param select_columns: columns to select from database
        :return:
        """
        get_query = f"SELECT {select_columns} FROM {self.table_name}"
        if date_init or date_end:
            get_query = get_query + " WHERE "
            if date_init:
                get_query = get_query + f"date >= {date_init}"
            if date_end:
                if date_init:
                    get_query = get_query + " AND "
                get_query = get_query + f"date <= {date_end}"
        get_query += " ORDER BY DATE DESC"
        self.cursor.execute(get_query)
        return self.cursor.fetchall()

    def get_close_prices(self, date_init: int = None, date_end: int = None):
        return_data = []
        try:
            return_data = self.get_data(
                date_init=date_init, date_end=date_end, select_columns='DATE, CLOSE'
            )
        except Error as ex:
            print('%s\n%s', ex, traceback.format_exc())
        except Exception as ex:
            print('%s\n%s', ex, traceback.format_exc())
        finally:
            return return_data