import logging
import apache_beam as beam
from apache_beam.io import WriteToText
from apache_beam.io.gcp.bigquery import ReadFromBigQuery, WriteToBigQuery

# change the abbreviated US state names to their full name
class StandardizeState(beam.DoFn):
  def process(self, element):
    # get individual columns from element
    # get state name in uppercase without leading/trailing whitespace
    l_id = element['id']
    fips = element['fips']
    admin2 = element['admin2']
    city = element['city']
    state = element['state'].strip().upper()
    country = element['country']
    lat = element['latitude']
    longi = element['longitude']
    combine = element['combined_key']

    # state abbreviation dictionary
    us_states = {
    'AL': 'Alabama',
    'AK': 'Alaska',
    'AS': 'American Samoa',
    'AZ': 'Arizona',
    'AR': 'Arkansas',
    'CA': 'California',
    'CO': 'Colorado',
    'CT': 'Connecticut',
    'DE': 'Delaware',
    'DC': 'District of Columbia',
    'FL': 'Florida',
    'GA': 'Georgia',
    'GU': 'Guam',
    'HI': 'Hawaii',
    'ID': 'Idaho',
    'IL': 'Illinois',
    'IN': 'Indiana',
    'IA': 'Iowa',
    'KS': 'Kansas',
    'KY': 'Kentucky',
    'LA': 'Louisiana',
    'ME': 'Maine',
    'MD': 'Maryland',
    'MA': 'Massachusetts',
    'MI': 'Michigan',
    'MN': 'Minnesota',
    'MS': 'Mississippi',
    'MO': 'Missouri',
    'MT': 'Montana',
    'NE': 'Nebraska',
    'NV': 'Nevada',
    'NH': 'New Hampshire',
    'NJ': 'New Jersey',
    'NM': 'New Mexico',
    'NY': 'New York',
    'NC': 'North Carolina',
    'ND': 'North Dakota',
    'MP': 'Northern Mariana Islands',
    'OH': 'Ohio',
    'OK': 'Oklahoma',
    'OR': 'Oregon',
    'PA': 'Pennsylvania',
    'PR': 'Puerto Rico',
    'RI': 'Rhode Island',
    'SC': 'South Carolina',
    'SD': 'South Dakota',
    'TN': 'Tennessee',
    'TX': 'Texas',
    'UT': 'Utah',
    'VT': 'Vermont',
    'VI': 'Virgin Islands',
    'VA': 'Virginia',
    'WA': 'Washington',
    'WV': 'West Virginia',
    'WI': 'Wisconsin',
    'WY': 'Wyoming'
    }

    # return record with new state name
    if (state in us_states.keys()):
        state = us_states[state]
        record = {'id': l_id, 'fips': fips, 'admin2': admin2, 'city': city, 'state': state, 'country': country,'latitude': lat,'longitude': longi, 'combined_key': combine}
        return [record]
    # return None for state since US is not a state name
    elif (state == 'US'):
        record = {'id': l_id, 'fips': fips, 'admin2': admin2, 'city': city, 'state': None, 'country': country,'latitude': lat,'longitude': longi, 'combined_key': combine}
        return [record]
    # state did not match a dictionary key, print element for debugging
    else:
        print(element)
        return

def run():
     # set up
     PROJECT_ID = 'lunar-analyzer-302702'
     BUCKET = 'gs://apachebeam-bucket/temp'
     options = {
     'project': PROJECT_ID
     }
     opts = beam.pipeline.PipelineOptions(flags=[], **options)

     # use DirectRunner
     p = beam.Pipeline('DirectRunner', options=opts)

     # BigQuery query with LIMIT clause for less than 500
     sql = 'SELECT * FROM datamart.new_locations WHERE country="US" AND LENGTH(TRIM(state))=2 ORDER BY city, state LIMIT 499'
     bq_source = ReadFromBigQuery(query=sql, use_standard_sql=True, gcs_location=BUCKET)

     # create a PCollection from the BigQuery query results
     query_results = p | 'Read from BQ' >> beam.io.Read(bq_source)

     # feed query_results PCollection to PTransform Pardo(StandardizeState()) to get a PCollection of elements with standarized state names
     state_pcoll = query_results | 'Standardize State Names' >> beam.ParDo(StandardizeState())

     # write the PCollection of standardized state locations to 'output.txt'
     state_pcoll | 'Log output' >> WriteToText('output.txt')

     # setup variables for writing the PCollection of unique locations to a new BigQuery table
     dataset_id = 'datamart'
     table_id = PROJECT_ID + ':' + dataset_id + '.' + 'locations_Beam'
     schema_id = 'id:INTEGER,fips:INTEGER,admin2:STRING,city:STRING,state:STRING,country:STRING,latitude:FLOAT,longitude:FLOAT,combined_key:STRING'

     # write the PCollection of standardized state locations to a new BigQuery table or replace the table if it exists
     state_pcoll | 'Write to BQ' >> WriteToBigQuery(table=table_id, schema=schema_id, custom_gcs_temp_location=BUCKET, write_disposition='WRITE_TRUNCATE')

     # run the pipeline until finshed
     result = p.run()
     result.wait_until_finish()

# call run()
if __name__ == '__main__':
  logging.getLogger().setLevel(logging.ERROR)
  run()


from fer import FER2013
from torch.autograd import Variable
from models import *
import torch
import torch.nn as nn
import transforms
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt
import utils

cut_size = 44
bs = 1
model_path = 'FER2013_Resnet18/PublicTest_model.t7'

epls = [0.001 * i for i in range(11)]

transform_train = transforms.Compose([
    transforms.RandomCrop(44),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
])

transform_test = transforms.Compose([
    transforms.CenterCrop(cut_size),
    transforms.ToTensor(),
])

transform_eval = transforms.Compose([
    transforms.TenCrop(cut_size),
    transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])),
])
tbs = 32
trainset = FER2013(split='Training', transform=transform_train)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=tbs, shuffle=True, num_workers=1)
PublicTestset = FER2013(split='PublicTest', transform=transform_eval)
PublicTestloader = torch.utils.data.DataLoader(PublicTestset, batch_size=tbs, shuffle=False, num_workers=1)
PrivateTestset = FER2013(split='PrivateTest', transform=transform_eval)
PrivateTestloader = torch.utils.data.DataLoader(PrivateTestset, batch_size=tbs, shuffle=False, num_workers=1)
criterion = nn.CrossEntropyLoss()
best_PublicTest_acc = 0  # best PublicTest accuracy
best_PublicTest_acc_epoch = 0
best_PrivateTest_acc = 0  # best PrivateTest accuracy
best_PrivateTest_acc_epoch = 0

def fgsm_attack(img, eps, data_grad):
    sign_data_grad = data_grad.sign()
    perturbed_img = img + eps * sign_data_grad
    perturbed_img = torch.clamp(perturbed_img, 0, 1)
    return perturbed_img

def test(model, device, test_loader, eps):
    correct = 0
    adv_egs = []
    for data, target in test_loader:
        # batch_size, ncrops, c, h , w = np.shape(data)
        # data = data.view(-1, c, h, w)

        data, target = data.to(device), target.to(device)
        data.requires_grad = True
        output = model(data)
        init_pred = output.max(1, keepdim=True)[1]
        if init_pred.item() != target.item():
            continue

        loss = F.nll_loss(output, target)
        model.zero_grad()
        loss.backward()

        data_grad = data.grad.data
        perturbed_data = fgsm_attack(data, eps, data_grad)
        output = model(perturbed_data)
        final_pred = output.max(1, keepdim=True)[1]
        if final_pred.item() == target.item():
            correct += 1
            if (eps == 0) and (len(adv_egs) < 5):
                adv_eg = perturbed_data.squeeze().detach().cpu().numpy()
                adv_egs.append((init_pred.item(), final_pred.item(), adv_eg))
        else:
            if len(adv_egs) < 5:
                adv_eg = perturbed_data.squeeze().detach().cpu().numpy()
                adv_egs.append((init_pred.item(), final_pred.item(), adv_eg))

    final_acc = correct / float(len(test_loader))
    print('Epsilon: %.4f Test Accuracy； %d / %d = %.3f' % (eps, correct, len(test_loader), final_acc))
    return final_acc, adv_egs

def PublicTest(epoch, net):
    global PublicTest_acc
    global best_PublicTest_acc
    global best_PublicTest_acc_epoch
    net.eval()
    PublicTest_loss = 0
    correct = 0
    total = 0
    for batch_idx, (inputs, targets) in enumerate(PublicTestloader):
        bs, ncrops, c, h, w = np.shape(inputs)
        inputs = inputs.view(-1, c, h, w)
        inputs, targets = inputs.to(device), targets.to(device)

        outputs = net(inputs)
        outputs_avg = outputs.view(bs, ncrops, -1).mean(1)  # avg over crops
        loss = criterion(outputs_avg, targets)
        PublicTest_loss += loss.item()
        _, predicted = torch.max(outputs_avg.data, 1)
        total += targets.size(0)

        correct += (predicted == targets).sum().item()
        utils.progress_bar(batch_idx, len(PublicTestloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)'
                           % (PublicTest_loss / (batch_idx + 1), 100. * correct / total, correct, total))

    # Save checkpoint.
    PublicTest_acc = 100.*correct/total
    # writer.add_scalars('Loss', {'PublicTest': PublicTest_loss / len(PublicTestloader)}, epoch)
    # writer.add_scalars('Accuracy', {'PublicTest': PublicTest_acc}, epoch)
    if PublicTest_acc > best_PublicTest_acc:
        print('Saving..')
        print("best_PublicTest_acc: %0.3f" % PublicTest_acc)
        best_PublicTest_acc = PublicTest_acc
        best_PublicTest_acc_epoch = epoch

def PrivateTest(epoch, net):
    global PrivateTest_acc
    global best_PrivateTest_acc
    global best_PrivateTest_acc_epoch
    net.eval()
    PrivateTest_loss = 0
    correct = 0
    total = 0
    for batch_idx, (inputs, targets) in enumerate(PrivateTestloader):
        bs, ncrops, c, h, w = np.shape(inputs)
        inputs = inputs.view(-1, c, h, w)
        inputs, targets = inputs.to(device), targets.to(device)

        outputs = net(inputs)
        outputs_avg = outputs.view(bs, ncrops, -1).mean(1)  # avg over crops
        loss = criterion(outputs_avg, targets)
        PrivateTest_loss += loss.item()
        _, predicted = torch.max(outputs_avg.data, 1)
        total += targets.size(0)

        correct += (predicted == targets).sum().item()
        utils.progress_bar(batch_idx, len(PublicTestloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)'
            % (PrivateTest_loss / (batch_idx + 1), 100. * correct / total, correct, total))
    # Save checkpoint.
    PrivateTest_acc = 100.*correct/total
    # writer.add_scalars('Loss', {'PrivateTest': PrivateTest_loss / len(PrivateTestloader)}, epoch)
    # writer.add_scalars('Accuracy', {'PrivateTest': PrivateTest_acc}, epoch)

    if PrivateTest_acc > best_PrivateTest_acc:
        print('Saving..')
        print("best_PrivateTest_acc: %0.3f" % PrivateTest_acc)
        best_PrivateTest_acc = PrivateTest_acc
        best_PrivateTest_acc_epoch = epoch

def aecurve(eps, accs):
    plt.figure(figsize=(5, 5))
    plt.plot(eps, accs, '*-')
    plt.xticks(np.arange(0, 0.012, step=0.001))
    plt.yticks(np.arange(0, 1.1, step=0.1))
    plt.title('Accuracy & Epsilon')
    plt.xlabel('Epsilon')
    plt.ylabel('Accuracy')
    plt.show()

if __name__ == '__main__':
    mode = 'test'

    PublicTestset1 = FER2013(split='PublicTest', transform=transform_test)
    PublicTestloader1 = torch.utils.data.DataLoader(PublicTestset1, batch_size=bs, shuffle=False, num_workers=1)
    PrivateTestset1 = FER2013(split='PrivateTest', transform=transform_test)
    PrivateTestloader1 = torch.utils.data.DataLoader(PrivateTestset1, batch_size=bs, shuffle=False, num_workers=1)
    device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
    # device = torch.device('cpu')
    print('Device: ', device)
    model = ResNet18()
    checkpoint = torch.load(model_path)
    print('Loading model from %s' % model_path)
    model.load_state_dict(checkpoint['net'])

    # best_PublicTest_acc = checkpoint['best_PublicTest_acc']
    # best_PrivateTest_acc = checkpoint['best_PrivateTest_acc']
    # best_PublicTest_acc_epoch = checkpoint['best_PublicTest_acc_epoch']
    # best_PrivateTest_acc_epoch = checkpoint['best_PrivateTest_acc_epoch']

    model.to(device)
    model.eval()

    if mode == 'test':
        PublicTest(1, model)
        PrivateTest(1, model)
        exit()

    accs = []
    egs = []
    for e in epls:
        acc, eg = test(model, device, PrivateTestloader1, e)
        accs.append(acc)
        egs.append(eg)
    aecurve(eps=epls, accs=accs)
    print(epls, accs)

    cnt = 0
    plt.figure(figsize=(8, 10))
    for i in range(len(epls)):
        for j in range(len(egs[i])):
            cnt += 1
            plt.subplot(len(epls), len(egs[0]), cnt)
            plt.xticks([], [])
            plt.yticks([], [])
            if j == 0:
                plt.ylabel("Eps: {}".format(epls[i]), fontsize=14)
            orig, adv, ex = egs[i][j]
            plt.title("{} -> {}".format(orig, adv))
            plt.imshow(ex)
    plt.tight_layout()
    plt.show()


from django.utils.html import strip_tags
from django.core.management.base import BaseCommand, CommandError
from apps.subscription.models import *
from django.template.loader import render_to_string
from django.core.mail import EmailMultiAlternatives
from rollbardecorator import logexception

import datetime
import logging

logger = logging.getLogger(__name__)

PLAN_TO_USE = 3002  # the gold monthly plan

class Command(BaseCommand):

    @logexception
    def handle(self, *args, **options):
        today = datetime.datetime.now()
        mdiff = datetime.timedelta(hours=-2)
        date_2hours_ago = today + mdiff
        mdiff = datetime.timedelta(hours=-1)
        date_1hours_ago = today + mdiff

        for organization in Organization.objects.filter(created__gte=date_2hours_ago, created__lte=date_1hours_ago):
            sub = organization.subscription
            if not sub.had_trial and sub.plan.price_val == Decimal("0.0") and sub.token == "":
                self.setupAccount(organization, sub)
                self.sendEmail( organization )
                # self.logAction(organization)

    # def logAction( self, org ):
    #     # record_event(org.slug, "auto_trial")
    #     try:
    #         k = KM()
    #         k.identify(org.slug);
    #         k.set({'sub_mode' : 'auto_trial_2'})
    #         k.record('auto_trial')
    #     except:
    #         logger.error("could not update KM")

    def setupAccount(self, organization, sub):
        # plan = getSubscriptionPlan( PLAN_TO_USE )
        organization.subscription.plan_id = PLAN_TO_USE
        organization.subscription.expires = datetime.date.today() + datetime.timedelta(days=30)
        organization.subscription.is_trial = True
        organization.subscription.had_trial = True
        organization.subscription.save()

    def sendEmail(self, org ):
        logger.info("Sending email to %s " % org.creator.email)
        subject = "Set up your premium trial"
        body = render_to_string("subscription/emails/default_trial.txt" , {"org_slug":org.slug} )
        text_body = strip_tags(body)
        msg = EmailMultiAlternatives(subject, text_body, "Ajay Reddy <support@scrumdo.com>" , [ probable_email(org.creator) ])
        msg.attach_alternative(body, "text/html")
        msg.send()


import page as p
import frames as f
from EventType import EventType

class LFU(p.Page):
    def __init__(self, page_sequence, frame_count, page_count):
        super().__init__(page_sequence, frame_count, page_count)
        self.frames = []
        for i in range(frame_count):
            self.frames.append(LFU_Frames(i, page_count))
        self.lfu()

    def lfu(self):
        """
        Simulates the LFU algorithm.
        """
        index = 0
        for page in self.page_sequence:
            # Check if page is in a frame
            if self.check_for_page(page):
                self.page_hit_events(index)
                self.frames[self.find_page(page)].increment_page_frequency()
            # Check if there is an empty frame
            elif self.check_for_empty_frame():
                self.page_fault_events(index)
                self.add_page_to_empty_frame(page, index)
            # If there is no empty frame and page is not in a frame
            # Find the oldest page and replace it
            else:
                self.page_fault_events(index)
                self.page_replacement_event(
                    index, page, self.find_least_frequently_used())

            index += 1

        self.calculate_rates()
        self.print_lfu_table()

    def find_least_frequently_used(self):
        least_frequently_used = self.frames[0]
        for frame in self.frames:
            if frame.get_page_frequency() < least_frequently_used.get_page_frequency():
                least_frequently_used = frame
            elif frame.get_page_frequency() == least_frequently_used.get_page_frequency():
                if frame.get_frame_current_page_birth() < least_frequently_used.get_frame_current_page_birth():
                    least_frequently_used = frame
        return least_frequently_used.get_frame_id()

    def print_lfu_table(self):
        """
        Prints the LFU table.
        """
        print(f"+------------+")
        print(f"| LFU TABLE  |", )

        self.print_sequence()
        self.print_frames()
        self.print_rates()

class LFU_Frames(f.Frame):
    def __init__(self, frame_count, event_count):
        super().__init__(frame_count, event_count)
        self.page_frequency = 0

    def get_page_frequency(self):
        return self.page_frequency

    def increment_page_frequency(self):
        self.page_frequency += 1

    def replace_page(self, page, index):
        self.frame_current_page = page
        self.frame_current_page_age = 0
        self.frame_current_page_birth = index
        self.page_frequency = 0
        self.set_current_event(index, EventType.PAGE_REPLACEMENT, page)

def main():
    # page_sequence = [7, 0, 1, 2, 0, 3, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7]
    # frame_count = 3
    # page_count = 17

    page_sequence = [7, 0, 1, 2, 0, 3, 0, 4,
                     2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1]
    frame_count = 3
    page_count = 20
    lfu = LFU(page_sequence, frame_count, page_count)

if __name__ == "__main__":
    main()


import time
from pathlib import Path

import torch
import upsilonconf
from torch import nn
from torch.utils.data import random_split, DataLoader
from torch.utils.tensorboard import SummaryWriter
from torchvision import datasets
from torchvision.transforms import transforms
from upsilonconf import save_config
from tensorboard.backend.event_processing import event_accumulator

from convex_modules import ConvexLinear, LazyClippedPositivity, LinearSkip, ExponentialPositivity, NoPositivity
from convex_init import TraditionalInitialiser, ConvexInitialiser
from pre_processing import Whiten
from trainer import Trainer
from utils import make_deterministic

def get_data(name: str, root: str, pre_process: str = "normal", train_split: float = 0.9):
    """
    Create train- and valid dataset for experiment.

    Parameters
    ----------
    name : str
        The name of the dataset to use.
    root : str
        Path to where the data is stored on disk.
    train_split : float, optional
        The fraction of data to use for training.

    Returns
    -------
    (train, valid) : tuple of two Datasets
        A tuple of datasets for updating and evaluating the network.
    (in_shape, class_count) : tuple of torch.Size and int
        A tuple with the input shape and number of classes for this dataset.
    """
    name = name.lower().strip()
    pre_process = pre_process.lower().strip()

    if name == "mnist":
        dataset = datasets.MNIST
        mean, std = (0.1307, ), (0.3081, )
        shapes = torch.Size((1, 28, 28)), 10
    elif name == "cifar10":
        dataset = datasets.CIFAR10
        mean, std = (0.4914, 0.4822, 0.4465), (0.2470, .2435, 0.2616)
        shapes = torch.Size((3, 32, 32)), 10
    elif name == "cifar100":
        dataset = datasets.CIFAR100
        mean, std = (0.5071, 0.4865, 0.4409), (0.2673, 0.2564, 0.2762)
        shapes = torch.Size((3, 32, 32)), 100
    else:
        raise ValueError(f"unknown dataset '{name}'")

    pre_processing = transforms.Compose([transforms.ToTensor()])
    data = dataset(root, train=True, transform=pre_processing)
    if pre_process == "normal":
        pre_processing.transforms.append(transforms.Normalize(mean, std))
    elif pre_process == "pca":
        pre_processing.transforms.append(Whiten(data, zca=False))
    elif pre_process == "zca":
        pre_processing.transforms.append(Whiten(data, zca=True))

    num_train = int(train_split * len(data))
    return random_split(data, [num_train, len(data) - num_train]), shapes

def get_model(img_shape: torch.Size, num_classes: int, hidden: tuple = (),
              convex: str = None, fix_init: bool = True, skip: bool = False):
    """
    Create neural network for experiment.

    Parameters
    ----------
    img_shape : torch.Size
        The array shape of a single input image.
    num_classes : int
        The number of classes for the prediction task.
    hidden : tuple of ints, optional
        The number of neurons for each hidden layer in the network.
    convex : str, optional
        What type of convexity to use (none by default).
    fix_init : bool, optional
        Fix the initialisation of convex networks (true by default).
    skip : bool, optional
        Add skip-connections from the input to every layer (false by default).

    Returns
    -------
    model : torch.nn.Module
        Simple multi-layer perceptron, ready to train.
    """
    width = img_shape.numel()
    widths = (width, *hidden, num_classes)

    if convex is None or convex == "":
        positivity = NoPositivity()
    elif convex == "icnn":
        positivity = LazyClippedPositivity()
    elif convex == "exp":
        positivity = ExponentialPositivity()
    else:
        raise ValueError()

    # first layer is special
    layer1 = nn.Linear(width, widths[0])
    phi = nn.ReLU()
    layers = [layer1, *(
        nn.Sequential(phi, ConvexLinear(n_in, n_out, positivity=positivity))
        for n_in, n_out in zip(widths[:-1], widths[1:])
    )]

    lecun_init = TraditionalInitialiser()
    lecun_init(layer1.weight, layer1.bias)
    init = ConvexInitialiser() if (convex and fix_init) else TraditionalInitialiser(gain=2.)
    for seq in layers[1:]:
        init(seq[-1].weight, seq[-1].bias)

    if skip:
        skipped = LinearSkip(width, widths[1], nn.Sequential(*layers[:2]))
        for layer, num_out in zip(layers[2:], widths[2:]):
            skipped = LinearSkip(width, num_out, nn.Sequential(skipped, layer))
        layers = [skipped]

    return nn.Sequential(nn.Flatten(), *layers)

def run(hparams, sys_config):
    result_path = Path("results", "mlp_search")
    for p in result_path.glob(f"{hparams.id}_*"):
        if p.is_dir():
            try:
                event_path = next(p.glob(f"events.out.tfevents.*"))
                ea = event_accumulator.EventAccumulator(str(event_path))
                events = ea.Reload().Scalars("valid/acc")
                if len(events) == hparams.num_epochs + 1:
                    print(f"found existing results for {hparams.id}")
                    max_event = max(events, key=lambda e: e.value)
                    return max_event.step, max_event.value
                else:
                    print(f"run for {hparams.id} broke after {len(events)} epochs, re-running")
                    raise KeyError
            except KeyError:
                for file in p.iterdir():
                    file.unlink()

                p.rmdir()

    log_dir = result_path / time.strftime(f"{hparams.id}_%y%j-%H%M%S")
    make_deterministic(hparams.seed)

    (train, valid), shapes = get_data(root=sys_config.data_root, **hparams.data)
    train_loader = DataLoader(train, shuffle=True, batch_size=hparams.batch_size,
                              num_workers=sys_config.num_workers)
    valid_loader = DataLoader(valid, batch_size=len(valid),
                              num_workers=sys_config.num_workers)

    if sys_config.device is None:
        sys_config.overwrite("device", "cuda" if torch.cuda.is_available() else "cpu")
    model = get_model(*shapes, **hparams.model).to(sys_config.device)

    trainer = Trainer(
        model=model,
        objective=nn.CrossEntropyLoss(reduction="sum"),
        optimiser=torch.optim.Adam(model.parameters(), **hparams.adam),
        tb_writer=SummaryWriter(log_dir),
    )

    # logging
    trainer.logger.add_graph(model, next(iter(train_loader))[0].to(sys_config.device))
    save_config(hparams, f"{log_dir}/config.yaml")
    tup = hparams.pop("model.hidden")
    hparams["model.hidden"] = torch.tensor(tup) if tup else torch.tensor([-1])
    trainer.log_hparams(hparams, {
        "valid/acc": float("nan"),
        "valid/loss": float("nan"),
    })
    hparams.overwrite("model.hidden", tup)  # reset for later usage

    results = trainer.train(train_loader, valid_loader, hparams.num_epochs)
    trainer.logger.close()
    return None, results["acc"]

if __name__ == "__main__":
    from concurrent.futures import ProcessPoolExecutor
    from argparse import ArgumentParser
    parser = ArgumentParser()
    parser.add_argument("config_dir", metavar="PATH", type=Path)
    parser.add_argument("--parallel", "-P", type=int, default=5)
    sys_config, ns = upsilonconf.from_cli(parser=parser)
    if not ns.config_dir.is_dir():
        raise ValueError(f"not a directory: {ns.config_dir}")

    def _run(conf_file):
        hparams = upsilonconf.load(conf_file)
        try:
            return run(hparams, sys_config), hparams
        except RuntimeError as err:
            print(f"run {hparams.id} failed:", err)
            return -1, hparams

    pool = ProcessPoolExecutor(max_workers=ns.parallel)
    accuracies = pool.map(_run, Path.glob(ns.config_dir, "*.yaml"), chunksize=16)

    best_acc = 0.
    best_params = None
    for (epoch, acc), hparams in accuracies:
        if epoch is not None:
            hparams.overwrite("num_epochs", epoch)
        if acc > best_acc:
            best_acc = acc
            best_params = hparams
    pool.shutdown()

    if best_params is not None:
        save_config(best_params, f"results/best_{best_params.id}.yaml")
        print(f"best config: {best_params.id} ({100 * best_acc:05.2f}%)")
        print(best_params)


import pygame
from src.constants import SPRITES_COLUMMS, SPRITES_LINES, sprite_size, Y_SIZE,\
    X_SIZE

pygame.init()
window_title = "Save MacGyver"
pygame.display.set_caption(window_title)
windows_surface = (SPRITES_COLUMMS, SPRITES_LINES)
window = pygame.display.set_mode(windows_surface)
rect_window = window.get_rect()

IMAGE_REF = {"floor": "src/ressource/Floor.png",
             "wall": "src/ressource/Wall4.png",
             "player": "src/ressource/MacGyver.png",
             "guardian": "src/ressource/Gardien.png",
             "needle": "src/ressource/aiguille.png",
             "pipe": "src/ressource/tube_plastique.png",
             "ether": "src/ressource/ether.png"
             }

def load_image(image):
    return pygame.transform.scale(
        pygame.image.load(image), (sprite_size, sprite_size)).convert()

def display(matrix, message, message_item, message_win):
    window.fill((31, 49, 52))
    for i in range(Y_SIZE):
        for j in range(X_SIZE):
            if matrix[i][j] == '+':
                window.blit(load_image(
                    IMAGE_REF["wall"]), (j * sprite_size,
                                         (i + 1) * sprite_size))
            elif matrix[i][j] == '-':
                window.blit(load_image(
                    IMAGE_REF["floor"]), (j * sprite_size,
                                          (i + 1) * sprite_size))
            elif matrix[i][j] == 'D':
                window.blit(load_image(
                    IMAGE_REF["player"]), (j * sprite_size,
                                           (i + 1) * sprite_size))
            elif matrix[i][j] == 'A':
                window.blit(load_image(
                    IMAGE_REF["guardian"]), (j * sprite_size,
                                             (i + 1) * sprite_size))
            elif matrix[i][j] == 'needle':
                window.blit(load_image(
                    IMAGE_REF["needle"]), (j * sprite_size,
                                           (i + 1) * sprite_size))
            elif matrix[i][j] == 'plastic_tube':
                window.blit(load_image(
                    IMAGE_REF["pipe"]), (j * sprite_size,
                                         (i + 1) * sprite_size))
            elif matrix[i][j] == 'ether':
                window.blit(load_image(
                    IMAGE_REF["ether"]), (j * sprite_size,
                                          (i + 1) * sprite_size))

    font = pygame.font.SysFont("helvetica.ttc", 20)
    message = font.render(
        message, True, pygame.Color("#FFFFFF"))
    message_rect = message.get_rect()
    message_rect.bottom = rect_window.bottom
    window.blit(message, message_rect)

    font_item = pygame.font.SysFont("helvetica.ttc", 20)
    message_item = font_item.render(
        message_item, True, pygame.Color("#FFFFFF"))
    message_rect = message.get_rect()
    message_rect.left = rect_window.left
    window.blit(message_item, message_rect)

    font_win = pygame.font.SysFont("helvetica bold.ttc", 60)
    message_win = font_win.render(
        message_win, True, pygame.Color("#FFFFFF"))
    message_rect = message_win.get_rect()
    message_rect.center = rect_window.center
    window.blit(message_win, message_rect)
    pygame.display.flip()


from enum import IntEnum

from typing import Optional

class uSwidHashAlg(IntEnum):
    """Represents an enumerated type of hash"""

    UNKNOWN = 0
    SHA256 = 1
    SHA384 = 7
    SHA512 = 8

    @classmethod
    def from_string(cls, alg_id: str) -> "uSwidHashAlg":
        """Creates a uSwidHashAlg from a string identifier"""
        return cls(
            {
                "SHA256": uSwidHashAlg.SHA256,
                "SHA384": uSwidHashAlg.SHA384,
                "SHA512": uSwidHashAlg.SHA512,
            }[alg_id]
        )

class uSwidHash:
    """Represents a SWID link"""

    def __init__(
        self,
        alg_id: Optional[uSwidHashAlg] = None,
        value: Optional[str] = None,
    ):
        """Initializes uSwidHash"""
        self.alg_id: Optional[uSwidHashAlg] = alg_id
        """Algorigth ID, e.g. ``uSwidHashAlg.SHA256``"""
        self.value: Optional[str] = value
        """Checksum value"""

    @property
    def alg_id_for_display(self) -> Optional[str]:
        """Returns the value"""
        if not self.alg_id:
            return None
        return {
            uSwidHashAlg.SHA256: "SHA-256",
            uSwidHashAlg.SHA384: "SHA-384",
            uSwidHashAlg.SHA512: "SHA-512",
        }.get(self.alg_id)

    @property
    def value(self) -> Optional[str]:
        """Returns the value"""
        return self._value

    @value.setter
    def value(self, value: Optional[str]) -> None:
        """Sets the value, guessing the alg_id from the length if unset"""
        if self.alg_id is None and value:
            if len(value) == 64:
                self.alg_id = uSwidHashAlg.SHA256
            elif len(value) == 96:
                self.alg_id = uSwidHashAlg.SHA384
            elif len(value) == 128:
                self.alg_id = uSwidHashAlg.SHA512
        self._value = value

    def __repr__(self) -> str:
        alg_id_str = self.alg_id.name if self.alg_id else uSwidHashAlg.UNKNOWN.name
        return f'uSwidHash(alg_id={alg_id_str},value="{self.value}")'


import sys
from Adafruit_IO import MQTTClient
import time
import random
from dotenv import load_dotenv
import os
from faceAI import faceAI

load_dotenv()
AIO_FEED_ID = ["btnled", "btndoor", "btnfan"]
AIO_USERNAME = os.environ.get('USER_NAME')
AIO_KEY = os.environ.get('KEY')

def connected(client):
    print("Ket noi thanh cong ...")
    for topic in AIO_FEED_ID:
        client.subscribe(topic)

def subscribe(client, userdata, mid, granted_qos):
    print("Subscribe thanh cong ...")

def disconnected(client):
    print("Ngat ket noi ...")
    sys.exit(1)

def message(client, feed_id, payload):
    print("Nhan du lieu: " + payload + ",feed id: " + feed_id)

client = MQTTClient(AIO_USERNAME, AIO_KEY)
client.on_connect = connected
client.on_disconnect = disconnected
client.on_message = message
client.on_subscribe = subscribe
client.connect()
client.loop_background()

count = 10
while True:
    if (count <= 0):
        print("Publish data to server Adafruit")
        time.sleep(5)
        print("Publish face AI")
        client.publish("ai",faceAI())
        time.sleep(5)
        print("Publish temperature")
        client.publish("temperature", random.randint(28, 38))
        time.sleep(5)
        print("Publish humidity")
        client.publish("humidity", random.randint(0, 100))
        time.sleep(5)
        print("Publish light")
        client.publish("light", random.randint(0, 500))
        count = 10
    count -= 1
    time.sleep(1)


# adata.gui.basic
'''
My WX helpers - old 2006 code - needs cleaning
'''

#__all__ = ['app','sizer','panel']

import os
import sys
import time
import datetime
import platform
import wx
import wx.lib.buttons as buttons
import wx.lib.masked as masked
from wx import adv
from wx.lib.wordwrap import wordwrap
from urllib.request import urlopen
from urllib.error import URLError

class Dictionary(dict):
    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return key

class DictionaryDefault(dict):
    def __init__(self, default=None):
        dict.__init__(self)
        self.default = default

    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.default

PATH = os.path.dirname(os.path.dirname(__file__))
PATH_IMAGE = os.path.join(PATH, 'data', 'image')
PATH_ICON = os.path.join(PATH_IMAGE, 'icon')
BRD = 8
BRB = 5
try:
    EXA = wx.EXPAND|wx.ALL
except:
    # Mock
    EXA = 8432

POS = wx.DefaultPosition
SIZE = wx.DefaultSize

TEXT = Dictionary()
TEXT_DB = Dictionary()
HELP = Dictionary()
MSG = Dictionary()
ERROR = Dictionary()
IMAGE = DictionaryDefault("missing.png")
ICON = DictionaryDefault("missing.png")

def PlatformStyle():
    if 'wxMSW' in wx.PlatformInfo: return {
        'times'     : 'Times New Roman',
        'mono'      : 'Courier New',
        'sans'      : 'Arial',
        'size'      : 11,
    }

    if 'wxMac' in wx.PlatformInfo: return {
        'times'     : 'Lucida Grande',
        'mono'      : 'Monaco',
        'sans'      : 'Geneva',
        'size'      : 12,
    }

    if 'gtk2' in wx.PlatformInfo or 'gtk3' in wx.PlatformInfo: return {
        'times'     : 'Serif',
        'mono'      : 'Monospace',
        'sans'      : 'Sans',
        'size'      : 10,
    }

    return {
        'times'     : 'Times',
        'mono'      : 'Courier',
        'sans'      : 'Helvetica',
        'size'      : 12,
    }

def ImageLoad(name):
    path = os.path.join(PATH_IMAGE, name)
    return wx.Image(path, wx.BITMAP_TYPE_JPEG)

def Icon(name):
    filename = os.path.join(PATH_ICON, ICON[name])
    return wx.Icon(filename, wx.BITMAP_TYPE_PNG)

def SetValues(data, controls):
    for i in controls.keys():
        d = data[i]
        if d is None: value = ""
        elif type(d)==type(0) or type(d)==type(0.0): value=str(d)
        else: value = d
        controls[i].SetValue(value)

#  .d8888. d888888b d88888D d88888b d8888b. .d8888.
#  88'  YP   `88'   YP  d8' 88'     88  `8D 88'  YP
#  `8bo.      88       d8'  88ooooo 88oobY' `8bo.
#    `Y8b.    88      d8'   88~~~~~ 88`8b     `Y8b.
#  db   8D   .88.    d8' db 88.     88 `88. db   8D
#  `8888Y' Y888888P d88888P Y88888P 88   YD `8888Y'

def Border(sizer, border):
    s = SizerV()
    s.Add(sizer, 1, wx.EXPAND|wx.ALL, border)
    return s

class SizerV(wx.BoxSizer):
    def __init__(self):
        super(SizerV, self).__init__(wx.VERTICAL)

class SizerH(wx.BoxSizer):
    def __init__(self):
        super(SizerH, self).__init__(wx.HORIZONTAL)

class SizerVB(wx.BoxSizer):
    def __init__(self, items, border=8):
        super(SizerVB, self).__init__(wx.VERTICAL)
        style = EXA
        style_first = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP
        style_last = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM
        if len(items)==1:
            self.Add(items[0][0], items[0][1], style, border)
            return
        last = len(items)-1
        self.Add(items[0][0], items[0][1], style_first, border)
        for i in range(1, last):
            self.Add(items[i][0], items[i][1], style, border)
        self.Add(items[last][0], items[last][1], style_last, border)

class SizerBox(wx.StaticBoxSizer):
    def __init__(self, parent, title):
        box = wx.StaticBox(parent, -1, title)
        super(SizerBox, self).__init__(box, wx.VERTICAL)

class SizerRow(wx.FlexGridSizer):
    def __init__(self, items):
        super(SizerRow, self).__init__(1, len(items), 0, 0)
        self.AddGrowableCol(0)
        prop = 1
        for item in items:
            self.Add(item, prop, wx.EXPAND)
            if prop==1: prop=0

class SizerTable(wx.FlexGridSizer):
    def __init__(self, parent, items, expand=[]):
        super(SizerTable, self).__init__(len(items), 2, 5, 5)
        self.AddGrowableCol(1)
        for row in expand:
            self.AddGrowableRow(row)
        for label, widget in items:
            self.Add(wx.StaticText(parent, -1, label+":"), 0, wx.ALL, 4) #wx.ALIGN_CENTER_VERTICAL
            self.Add(widget, 0, wx.EXPAND)

#  d8888b.  .d8b.  d8b   db d88888b db      .d8888.
#  88  `8D d8' `8b 888o  88 88'     88      88'  YP
#  88oodD' 88ooo88 88V8o 88 88ooooo 88      `8bo.
#  88~~~   88~~~88 88 V8o88 88~~~~~ 88        `Y8b.
#  88      88   88 88  V888 88.     88booo. db   8D
#  88      YP   YP VP   V8P Y88888P Y88888P `8888Y'

class Panel(wx.Panel):
    def __init__(self, parent):
        super(Panel, self).__init__(parent, -1,
                            style=wx.BORDER_NONE|wx.TAB_TRAVERSAL)

    def Visible(self, value=True):
        if value:
            self.Show()
            self.GetParent().Layout()
        else:
            self.Hide()

class DateTimePicker(wx.Panel):
    def __init__(self, parent, call=None, *args,**kwargs):
        super(DateTimePicker, self).__init__(parent, *args, **kwargs)
        self.box_date = DatePicker(self)
        self.box_time = TimePicker(self)
        self.box_time.Now()
        s = SizerH()
        s.Add(self.box_date,1,wx.EXPAND)
        s.Add(self.box_time,0,wx.EXPAND)
        self.SetSizer(s)
        if call is not None:
            self.box_time.Bind(masked.EVT_TIMEUPDATE, call)
            self.box_date.Bind(wx.EVT_DATE_CHANGED, call)

    def SetValue(self,value):
        pass

    def GetValue(self):
        date = self.box_date.GetValue()
        time = self.box_time.GetValue()
        return datetime.datetime(date.year, date.month, date.day,
                                 int(time[0:2]), int(time[3:5]))

class Image(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id)
        self.image = None  # wxPython image
        wx.EVT_SIZE(self,self.OnSize)
        wx.EVT_PAINT(self, self.OnPaint)

    def display(self, path):
        print("Image display",path)
        if os.path.exists(path):
            self.image = wx.Image(path, wx.BITMAP_TYPE_ANY)
        else:
            self.image = None
        self.Refresh(True)

    def OnSize(self, event):
        self.Width, self.Height = self.GetClientSizeTuple()

    def OnPaint(self, evt):
        dc = wx.PaintDC(self)
        if not self.image:
            return
        W, H = self.Width, self.Height
        w, h = self.image.GetWidth(), self.image.GetHeight()
        A, a = W/float(H), w/float(h)
        if A < a:
            sw, sh = W, W/a
            ow, oh = 0, (H-sh)/2
        else:
            sw, sh = H*a, H
            ow, oh = (W-sw)/2, 0
        scaled = self.image.Scale(sw, sh, wx.IMAGE_QUALITY_HIGH)
        dc.DrawBitmap(scaled.ConvertToBitmap(), ow, oh)

class ProgressBar(wx.Panel):
    def __init__(self, parent, color=(255,255,255), bgcolor=(0,0,0)):
        wx.Panel.__init__(self, parent,
                          style=wx.BORDER_NONE | wx.NO_FULL_REPAINT_ON_RESIZE)
        wx.EVT_SIZE(self,self.OnSize)
        wx.EVT_PAINT(self,self.OnPaint)
        #self.SetDoubleBuffered(True)
        self.SetBackgroundColour(bgcolor)
        self.SetForegroundColour(color)
        self.value = 0
        self.color = color
        self.OnSize(None)

    def SetValue(self, value):
        self.value = value
        self.UpdateDrawing()

    def OnSize(self, event=None):
        self.Width, self.Height = self.GetClientSizeTuple()
        self._Buffer = wx.EmptyBitmap(self.Width, self.Height)
        self.Draw()

    def OnPaint(self,event):
        event.Skip()
        self.Draw()

    def UpdateDrawing(self):
        dc = wx.BufferedDC(wx.ClientDC(self), self._Buffer)
        self.Draw(dc)

    def Draw(self, dc=None):
        if dc is None: dc = wx.ClientDC(self)
        width,height = self.Width, self.Height#self.GetSize()
        w=int(width*self.value)
        if w<8:w=8
        h=height
        x=(width-w)/2
        y=0
        dc.BeginDrawing()
        dc.Clear()
        dc.SetBrush(wx.Brush((0,0,0)))
        dc.DrawRectangle(0,0,width,height)
        dc.SetBrush(wx.Brush(self.color))

        dc.DrawRoundedRectangle(0,0,width,height,4)
        dc.SetBrush(wx.Brush((0,0,0)))
        dc.DrawRoundedRectangle(4,4,width-8,height-8,4)
        dc.SetBrush(wx.Brush(self.color))
        dc.DrawRoundedRectangle(6,6,int(self.value*(width-12)),height-12,4)
        #dc.SetPen(wx.Pen((255,255,255), 12, wx.SOLID))
        #dc.DrawText(str(int(self.value*100))+"%",0,0)
        dc.EndDrawing()

#   .o88b.  .d88b.  d8b   db d888888b d8888b.  .d88b.  db      .d8888.
#  d8P  Y8 .8P  Y8. 888o  88 `~~88~~' 88  `8D .8P  Y8. 88      88'  YP
#  8P      88    88 88V8o 88    88    88oobY' 88    88 88      `8bo.
#  8b      88    88 88 V8o88    88    88`8b   88    88 88        `Y8b.
#  Y8b  d8 `8b  d8' 88  V888    88    88 `88. `8b  d8' 88booo. db   8D
#   `Y88P'  `Y88P'  VP   V8P    YP    88   YD  `Y88P'  Y88888P `8888Y'

class Text(wx.TextCtrl):
    def __init__(self, parent, edit=True, multiline=False, value="",
                 change=None, key=None, font=None, size=(32,24), style=None):
        if style is None:
            if edit: style = wx.BORDER_SUNKEN
            else: style = wx.TE_READONLY | wx.SIMPLE_BORDER
        if multiline: style = style | wx.TE_MULTILINE
        style = style | wx.TE_RICH | wx.TE_RICH2
        #super(Text, self).__init__(parent, -1, value, style=style, size=size)
        super(Text, self).__init__(parent, -1, style=style, size=size)
        if change is not None: self.Bind(wx.EVT_KILL_FOCUS, change)
        if key is not None: self.Bind(wx.EVT_TEXT, key)
        if font is not None: self.SetFont(font)

class Button(buttons.GenBitmapTextButton):
    """ Image button
    """
    def __init__(self, parent, caption, call, image=None, size=(100,32)):
        #x = wx.Button(parent, -1, caption)
        if image is not None: caption="  "+caption
        if size[0]>100: self.DrawLabel = self.DrawLabelRight
        super(Button, self).__init__(parent, -1, None, caption, size=size)
        if image is not None: self.SetBitmapLabel(image)
        self.Bind(wx.EVT_BUTTON, call)

    def DrawLabelRight(self, dc, width, height, dx=0, dy=0):
        bmp = self.bmpLabel
        if bmp is not None:     # if the bitmap is used
            if self.bmpDisabled and not self.IsEnabled():
                bmp = self.bmpDisabled
            if self.bmpFocus and self.hasFocus:
                bmp = self.bmpFocus
            if self.bmpSelected and not self.up:
                bmp = self.bmpSelected
            bw,bh = bmp.GetWidth(), bmp.GetHeight()
            if not self.up:
                dx = dy = self.labelDelta
            hasMask = bmp.GetMask() is not None
        else:
            bw = bh = 0     # no bitmap -> size is zero

        dc.SetFont(self.GetFont())
        if self.IsEnabled():
            dc.SetTextForeground(self.GetForegroundColour())
        else:
            dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))

        label = self.GetLabel()
        tw, th = dc.GetTextExtent(label)        # size of text
        if not self.up:
            dx = dy = self.labelDelta

        #pos_x = (width-bw-tw)/2+dx      # adjust for bitmap and text to centre
        pos_x = 8
        if bmp is not None:
            dc.DrawBitmap(bmp, pos_x, (height-bh)/2+dy, hasMask) # draw bitmap if available
            pos_x = pos_x + 2   # extra spacing from bitmap

        dc.DrawText(label, pos_x + dx+bw, (height-th)/2+dy)      # draw the text

class CheckBox(wx.CheckBox):
    def __init__(self, parent, caption, call):
        super(CheckBox, self).__init__(parent, -1, caption)
        self.Bind(wx.EVT_CHECKBOX, call)

class ListBox(wx.ListBox):
    def __init__(self, parent, call=None, double=None):
        self.key={}
        super(ListBox, self).__init__(parent, -1, size=(80,80), style=wx.LB_SINGLE)
        if call is not None:
            self.Bind(wx.EVT_LISTBOX, call)
        if double is not None:
            self.Bind(wx.EVT_LISTBOX_DCLICK, double)

    def GetKey(self):
        value = self.GetStringSelection()
        if value in self.key:
            return self.key[value]

    def GetItemsFromData(self, data):
        l, self.key = [], {}
        selected = self.GetStringSelection()
        if len(data)>0:
            if len(data[0])>1:
                for result in data:
                    value = result[1]
                    if len(result)>2:
                        for i in range(2,len(result)): value+=","+result[i]
                    self.key[value]=result[0]
                    l.append(value)
            else:
                for result in data: l.append(result[0])
        if self.GetItems()!=l:
            self.SetItems(l)
        if selected in l:
            self.SetSelection(l.index(selected))
        return l

class ComboBox(wx.ComboBox):
    """ Una lista de opciones
    """
    def __init__(self, parent, choices=None, call=None, edit=True,
                 sort=False, first=None):
        if sort: style = wx.CB_SORT
        else: style = 0
        if not edit: style = style | wx.CB_READONLY
        self.first = first
        if first is not None:
            if choices is None: choices=[first]
            else: choices=[first]+choices
        if choices is None: choices=[]
        super(ComboBox, self).__init__(parent, -1, "", style=style ,
                                       choices=choices)
        if call is not None:
            self.Bind(wx.EVT_KILL_FOCUS, call)
            self.Bind(wx.EVT_COMBOBOX, call)
        self.key = {}

    def GetKey(self):
        value = self.GetValue()
        if value in self.key:
            return self.key[value]
        else:
            return value

    def GetItemsFromData(self, data):
        #data = self.DB.result("SELECT DISTINCT type FROM sequences ORDER BY type")
        selected = self.GetValue()

        if self.first is None:
            l=[]
            self.key={}
        else:
            l = [self.first]
            self.key={self.first:None}
        if len(data)>0:
            if len(data[0])>1:
                for result in data:
                    value = result[1]
                    if len(result)>2:
                        for i in range(2,len(result)):
                            value+=", "+result[i]
                    self.key[value]=result[0]
                    l.append(value)
            else:
                for result in data: l.append(result[0])

        if "" in l: l.remove("")
        if self.GetItems()!=l: self.SetItems(l)
        if selected in l:
            self.SetSelection(l.index(selected))
        else:
            if self.first is not None:
                self.selected = l[0]
                self.SetSelection(0)
        return l

#def DatePicker(parent, call):
#    x = MyDatePickerCtrl(parent, style = wx.DP_DROPDOWN)
#    x.Bind(wx.EVT_DATE_CHANGED, call)
#    return x

class TimePicker(masked.TimeCtrl):
    def __init__(self, parent, call=None, *args,**kwargs):
        #wx.DatePickerCtrl.__init__(self, parent, *args,**kwargs)
        super(TimePicker, self).__init__(parent, style=adv.DP_DROPDOWN,
                                         *args, **kwargs)
        if call is not None:
            self.Bind(masked.EVT_TIMEUPDATE, call)

    def Now(self):
        t = datetime.datetime(2000,1,1).today()
        wxvalue=wx.DateTime()
        wxvalue.Set(year=t.year, month=t.month-1, day=t.day,
                    hour=t.hour, minute=t.minute)
        self.SetValue(wxvalue)

class DatePicker(adv.DatePickerCtrl):
    def __init__(self, parent, call=None, *args,**kwargs):
        #wx.DatePickerCtrl.__init__(self, parent, *args,**kwargs)
        super(DatePicker, self).__init__(parent, style=adv.DP_DROPDOWN,
                                         *args, **kwargs)
        if call is not None:
            self.Bind(wx.EVT_DATE_CHANGED, call)

    def SetValue(self,value):
        """Set either datetime.datetime or wx.DateTime"""
        if isinstance(value,(datetime.date,datetime.datetime)):
            wxvalue=wx.DateTime()
            wxvalue.Set(year=value.year,month=value.month-1,day=value.day)
            value=wxvalue
        elif value is None:
            value=wx.DateTime()
        wx.DatePickerCtrl.SetValue(self,value)

    def GetValue(self):
        """Returns datetime.datetime values"""
        value=wx.DatePickerCtrl.GetValue(self)
        if not value.IsValid():    #Manage null dates (useful when wx.DP_ALLOWNONE is set)
            return None
        else:
            return datetime.datetime(value.GetYear(),value.GetMonth()+1,value.GetDay())

# d88888b d8888b. d8888b.  .d88b.  d8888b. .d8888.
# 88'     88  `8D 88  `8D .8P  Y8. 88  `8D 88'  YP
# 88ooooo 88oobY' 88oobY' 88    88 88oobY' `8bo.
# 88~~~~~ 88`8b   88`8b   88    88 88`8b     `Y8b.
# 88.     88 `88. 88 `88. `8b  d8' 88 `88. db   8D
# Y88888P 88   YD 88   YD  `Y88P'  88   YD `8888Y'

class ErrorWindow(wx.Frame):
    def __init__(self, value, tb):
        # based on a frame, so set up the frame
        print("ERROR: %s" % value)
        #print(dir(value))

        title=value.__class__.__name__

        if hasattr(value, "filename"): title += " %s" % value.filename
        if hasattr(value, "lineno"):   title += " #%s" % value.lineno

        wx.Frame.__init__(self, None, -1, title, size=(720, 480))
        font = wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.NORMAL, wx.NORMAL)

        self.text = Text(self, multiline=True, font=font)
        #self.text = StyledText(self)
        self.text.SetBackgroundColour((255,255,255))
        self.text.SetForegroundColour((255,0,0))
        #self.text.echo("%s\n" % value)
        #self.text.echo("\n\nTraceback:\n\n", "fore:#FF0F0F,back:#0F0000,bold")
        self.text.write("%s\n" % value)
        self.text.write("\n\nTraceback:\n\n")
        #self.text.SetForegroundColour((0,0,0))

        traceback.print_tb(tb, file = self.text)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.text,1,wx.EXPAND)
        self.SetSizer(self.sizer)
        self.SetAutoLayout(1)
        #self.sizer.Fit(self)
        self.Show()

ART = [
    "ART_ERROR",
    "ART_GOTO_LAST",
    "ART_FILE_SAVE_AS",
    "ART_QUESTION",
    "ART_PRINT",
    "ART_DELETE",
    "ART_WARNING",
    "ART_HELP",
    "ART_COPY",
    "ART_INFORMATION",
    "ART_TIP",
    "ART_CUT",
    "ART_ADD_BOOKMARK",
    "ART_REPORT_VIEW",
    "ART_PASTE",
    "ART_DEL_BOOKMARK",
    "ART_LIST_VIEW",
    "ART_UNDO",
    "ART_HELP_SIDE_PANEL",
    "ART_NEW_DIR",
    "ART_REDO",
    "ART_HELP_SETTINGS",
    "ART_FOLDER",
    "ART_PLUS",
    "ART_HELP_BOOK",
    "ART_FOLDER_OPEN",
    "ART_MINUS",
    "ART_HELP_FOLDER",
    "ART_GO_DIR_UP",
    "ART_CLOSE",
    "ART_HELP_PAGE",
    "ART_EXECUTABLE_FILE",
    "ART_QUIT",
    "ART_GO_BACK",
    "ART_NORMAL_FILE",
    "ART_FIND",
    "ART_GO_FORWARD",
    "ART_TICK_MARK",
    "ART_FIND_AND_REPLACE",
    "ART_GO_UP",
    "ART_CROSS_MARK",
    "ART_HARDDISK",
    "ART_GO_DOWN",
    "ART_MISSING_IMAGE",
    "ART_FLOPPY",
    "ART_GO_TO_PARENT",
    "ART_NEW",
    "ART_CDROM",
    "ART_GO_HOME",
    "ART_FILE_OPEN",
    "ART_GOTO_FIRST",
    "ART_FILE_SAVE"
]


#! Python 3
# opencv_demo03.py
# 09/07/2018 sample created
#--------------------------
import os
import cv2
import glob

basedir = os.path.abspath(os.path.dirname(__file__))
os.chdir(basedir)

images=glob.glob("*.jpg")

for image in images:
    img=cv2.imread(image,-1)
    #re=cv2.resize(img,(200,100))
    re=cv2.resize(img,(int(img.shape[1]/6),int(img.shape[0]/6)))
    cv2.imshow(image,re)
    cv2.imwrite("resized_"+image,re)

cv2.waitKey(0)
cv2.destroyAllWindows()


"""
Functions for numerical approximation
"""

import math
from typing import Callable

import numpy as np

def first_derivative(function: Callable, x_point: float, x_step: float) -> float:
    """
    Numerically estimate the first derivative of the given function.

    :param function: A function for which the derivative is approximated.
    :param x_point: X value where to evaluate derivative
    :param x_step: X step size to use for the evaluation. Smaller value will
    give an estimate with less error.
    :returns: An approximation of the derivative at x_point, as a float
    """

    # The formula for approximating with error O(h^2) is evaluated and returned.
    # The error grows exponentially with step size x_step.
    return (function(x_point + x_step) - function(x_point - x_step)) / (2 * x_step)

def second_derivative(function: Callable, x_point: float, x_step: float):
    """
    Numerically estimate the second derivative of the given function.

    :param function: A function for which the derivative is approximated.
    :param x_point: X value where to evaluate derivative
    :param x_step: X step size to use for the evaluation. Smaller value will
    give an estimate with less error.
    :returns: An approximation of the derivative at x_point, as a float
    """
    return (function(x_point + x_step) + function(x_point - x_step) -
            2*function(x_point)) / x_step**2

def riemann_sum(function: Callable, num_points: int, x_start: float, x_stop: float) -> float:
    """
    Implements Riemann sum formula for approximating an intergral numerically.

    The Riemann sum assumes that the integrated function is (approximately) a
    constant in each small interval. Hence accuracy should improve with
    increasing N (num_points).

    :param function: Function for which the integral is evaluated
    :param num_points: Number of approximation intervals. An integer is expect.
    If a float is given, will truncate to an integer
    :param x_start: X coordinate for beginning of integration interval.
    :param x_stop: X coordinate for ending of integration interval.
    """

    # Make sure an integer amount of approximation points is given
    num_points = int(num_points)

    # Then form an array of evaluation points in uniform grid.
    # This way, we will always use the point at the beginning (left) of an interval.
    points = np.linspace(x_start, x_stop, num_points)
    # We can also easily get delta x form the resulting array
    delta_x = points[1] - points[0]

    # The formula is simple enough to be computed and returned on one line.
    # Use Python's list comprehension to evaluate function at evaluation
    # points in the given range, then sum the points weighted by step size.
    return sum([function(x_i)*delta_x for x_i in points])

def trapezoid_rule(function: Callable, num_points: int, x_start: float, x_stop: float) -> float:
    """
    Implements Trapezoid rule formula for approximating an intergral numerically.

    Accuracy should improve with increasing N (num_points).

    :param function: Function for which the integral is evaluated
    :param num_points: Number of approximation intervals. An integer is expect.
    If a float is given, will truncate to an integer
    :param x_start: X coordinate for beginning of integration interval.
    :param x_stop: X coordinate for ending of integration interval.
    """

    # Make sure an integer amount of approximation points is given
    num_points = int(num_points)

    # Then form an array of evaluation points and find the step size (delta x)
    points = np.linspace(x_start, x_stop, num_points)
    delta_x = points[1] - points[0]

    # Use Python's list comprehension to iterate over evaluation points x_i.
    # At each point, effectively we add the mean of the function in the
    # interval, but division by 2 can be taken out of the summation. Intervals
    # are weighted with step size (delta x).
    return 0.5 * sum([(function(x_i) + function(x_i+delta_x))*delta_x for x_i in points])

def simpson_rule(function: Callable, num_points: int, x_start: float, x_stop: float) -> float:
    """
    Implements Simpson rule formula for approximating an intergral numerically.

    Accuracy should improve with increasing N (num_points).

    :param function: Function for which the integral is evaluated
    :param num_points: Number of approximation intervals. An integer is expect.
    If a float is given, will truncate to an integer
    :param x_start: X coordinate for beginning of integration interval.
    :param x_stop: X coordinate for ending of integration interval.
    """

    # Make sure an integer amount of approximation points is given
    num_points = int(num_points)

    # Then form an array of evaluation points and find the step size (delta x)
    points = np.linspace(x_start, x_stop, num_points)
    delta_x = points[1] - points[0]

    # We need to consider whether there is an even or odd number of intervals.
    # If we divide the number of points in two and truncate to integer, we get a
    # minimum range that we always need to compute anyway.
    half_points = int(num_points / 2)

    # To make the following formulation a bit prettier (shorter) we can evaluate function
    # at every point already.
    values = [function(x) for x in points]

    # Calculate an intermediate result with an even grid. We now iterate only
    # until N/2 - 1 points, and this is accounted for in the range() function.
    # Use the index of current iteration point to access correct coordinates
    # from the value array.
    even_grid_sum = (delta_x / 3) * sum(
        [values[2 * ind] + 4 * values[2 * ind + 1] + values[2 * ind + 2]
         for ind in range(half_points - 1)])
    # This can be checked with the modulus operator
    if num_points % 2 == 0: # Even

        return even_grid_sum

    # Add the last slice, where N is the index of the last point, we subtract 1
    # from the number of points due to zero-based indexing
    N = num_points - 1
    return even_grid_sum + (delta_x / 12) * (
        -1 * function(points[N - 2]) + 8 * function(points[N - 1]) + 5 *
        function(points[N]))

def test_first_derivative(relative_tolerance: float = 0.01) -> bool:
    """
    Test the first_derivative function.

    :param relative_tolerance: Tolerance for testing the accuracy of
    first_derivative function. A relative tolerance is used. Defaults to 0.01 (1%).
    :returns: Boolean True if first_derivative returns a correct approximation,
    else return False
    """

    # First define a function that is used for testing. Let's use something for
    # which the analytical solution of first derivative is available.
    # I'll use the lambda formalism because it is a neat and readable way of
    # defining simple functions, for example here we will use f(x) = x^2 + x.
    test_fun = lambda x: x**2 + x

    # Let's test first_derivative at x = 1 and use a very small step.
    # The first derivative of this function is 2x + 1.
    # At x = 1, the first derivative of our test_fun is 3.
    x_test = 1.
    x_step = 1e-2
    true_result = 3.

    # Get the estimate from our approximation:
    estimate = first_derivative(test_fun, x_test, x_step)

    # Since our approximation cannot be assumed to give a perfect result, we
    # cannot do a simple comparison of numerical values with '=='. Instead we
    # need to use a comparison function that accepts a tolerance. We will return
    # the output of the comparison directly
    return math.isclose(true_result, estimate, rel_tol=relative_tolerance)

def test_second_derivative(relative_tolerance: float = 0.01) -> bool:
    """
    Test the second_derivative function.

    :param relative_tolerance: Tolerance for testing the accuracy of
    second_derivative function. A relative tolerance is used. Defaults to 0.01 (1%).
    :returns: Boolean True if second_derivative returns a correct approximation,
    else return False
    """

    # Define a test function for which analytical solution is known.
    # I'll use f(x) = x^3 + x^2 + x. The first derivative is
    # 3x^2 + 2x + 1 and the second is 6x + 2. At test point x=1 the second
    # derivative should evaluate to 8.
    test_fun = lambda x: x**3 + x**2 + x
    x_test = 1.
    x_step = 1e-2
    true_result = 8.

    # Return the result of comparison with a tolerance
    return math.isclose(true_result,
                        second_derivative(test_fun, x_test, x_step),
                        rel_tol=relative_tolerance)

def test_riemann_sum(relative_tolerance: float = 0.01) -> bool:
    """
    Test the riemann_sum function.

    :param relative_tolerance: Tolerance for testing the accuracy of
    the function. A relative tolerance is used. Defaults to 0.01 (1%).
    :returns: Boolean True if function returns a correct approximation,
    else return False
    """

    # Define a test function, use something for which the analytical result is
    # known. For example integrating sin(x) from zero to pi should give 2.
    num_points = 1000
    x_start = 0
    x_stop = math.pi
    true_result = 2.

    # Return the result of comparison with a tolerance
    return math.isclose(true_result,
                        riemann_sum(math.sin, num_points, x_start, x_stop),
                        rel_tol=relative_tolerance)

def test_trapezoid_rule(relative_tolerance: float = 0.01) -> bool:
    """
    Test the trapezoid_rule function.

    :param relative_tolerance: Tolerance for testing the accuracy of
    the function. A relative tolerance is used. Defaults to 0.01 (1%).
    :returns: Boolean True if function returns a correct approximation,
    else return False
    """

    # Define a test function, use something for which the analytical result is
    # known. For example integrating sin(x) from zero to pi should give 2.
    num_points = 1000
    x_start = 0.
    x_stop = math.pi
    true_result = 2.

    # Return the result of comparison with a tolerance
    return math.isclose(true_result,
                        trapezoid_rule(math.sin, num_points, x_start, x_stop),
                        rel_tol=relative_tolerance)

def test_simpson_rule(relative_tolerance: float = 0.01) -> bool:
    """
    Test the simpson_rule function.

    :param relative_tolerance: Tolerance for testing the accuracy of
    the function. A relative tolerance is used. Defaults to 0.01 (1%).
    :returns: Boolean True if function returns a correct approximation,
    else return False
    """

    # Define a test function, use something for which the analytical result is
    # known. For example integrating sin(x) from zero to pi should give 2.
    num_points = 99
    x_start = 0
    x_stop = math.pi
    true_result = 2.

    # Return the result of comparison with a tolerance
    return math.isclose(true_result,
                        simpson_rule(math.sin, num_points, x_start, x_stop),
                        rel_tol=relative_tolerance)

def main():
    """
    doc
    """
    first_deriv_test_res = test_first_derivative(1e-4)
    print("Test result for function first_derivate() is {}".format(
        first_deriv_test_res))

    second_deriv_test_res = test_second_derivative(1e-4)
    print("Test result for function second_derivate() is {}".format(
        second_deriv_test_res))

    riemann_test_res = test_riemann_sum(1e-4)
    print("Test result for function riemann_sum() is {}".format(
        riemann_test_res))

    trapezoid_test_res = test_trapezoid_rule(1e-4)
    print("Test result for function trapezoid_rule() is {}".format(
        trapezoid_test_res))

    simpson_test_res = test_simpson_rule(1e-4)
    print("Test result for function simpson_rule() is {}".format(
        simpson_test_res))

if __name__ == "__main__":
    main()


from PySimpleGUI import PySimpleGUI as sg
import pygame as pg
from itertools import combinations
from math import ceil

from Vector import Vector2, Vector3

"""
TODO
-Use combinations to calculate bodies trajectories
Ex: [Earth, Moon, Mars, Saturn] = [(Earth, Moon), (Earth, Mars), (Earth, Saturn), (Moon, Mars), (Moon, Saturn), (Mars, Saturn)]
-Trajectory
Create a class in other file
"""

G = 6.674080324960551e-11

def vec3_ignore_z(VEC3):
    return Vector2(VEC3.x, VEC3.y)

class Body:
    def __init__(self, name, r0, v0, mass, radius) -> None:
        self.name = name
        self.r0 = r0
        self.v0 = v0
        self.r = [self.r0]
        self.v = [self.v0]
        self.mass = mass
        self.radius = radius
        self.GM = G * self.mass

def get_body_by_name(body_name):
    for body in bodies:
        if body.name.lower() == body_name.lower():
            return body
    return False

def rk4_body(p, body):
    accel = Vector3(0, 0, 0)

    for other_body in bodies:
        if other_body is not body:
            delta_pos = other_body.r[-1] - p
            dist = delta_pos.magnitude()
            direction = delta_pos / dist

            accel += (other_body.GM/(dist**2)) * direction

    return accel

def rk4_vessel(p):
    accel = Vector3()

    for body in bodies:
        delta_pos = body.r[0] - p
        dist = delta_pos.magnitude()
        direction = delta_pos / dist

        accel += (body.GM/dist**2) * direction # gravity

    return accel

def calc_bodies():
    steps = ceil(body_sim_time / body_step_size)

    for body in bodies:
        body.r = [body.r0]
        body.v = [body.v0]

    for step in range(steps):
        for body in bodies:
            k1v = rk4_body(body.r[-1], body)
            k1r = body.v[-1]

            k2v = rk4_body(body.r[-1]+k1r*body_step_size*.5, body)
            k2r = body.v[-1]+k1v*body_step_size*.5

            k3v = rk4_body(body.r[-1]+k2r*body_step_size*.5, body)
            k3r = body.v[-1]+k2v*body_step_size*.5

            k4v = rk4_body(body.r[-1]+k3r*body_step_size, body)
            k4r = body.v[-1]+k3v*body_step_size

            dv = (body_step_size/6)*(k1v + 2*k2v + 2*k3v + k4v)
            dr = (body_step_size/6)*(k1r + 2*k2r + 2*k3r + k4r)

            body.v.append(body.v[-1] + dv)
            body.r.append(body.r[-1] + dr)

def calc_vessel(r0, v0, total_time):
    r = [r0]
    v = [v0]

    steps = ceil(total_time / vessel_step_size)

    for step in range(steps):
        #print(f"SIM: {(step/steps * 100):.0f}%")

        k1v = rk4_vessel(r[-1])
        k1r = v[-1]

        k2v = rk4_vessel(r[-1]+k1r*vessel_step_size*.5)
        k2r = v[-1]+k1v*vessel_step_size*.5

        k3v = rk4_vessel(r[-1]+k2r*vessel_step_size*.5)
        k3r = v[-1]+k2v*vessel_step_size*.5

        k4v = rk4_vessel(r[-1]+k3r*vessel_step_size)
        k4r = v[-1]+k3v*vessel_step_size

        dv = (vessel_step_size/6)*(k1v + 2*k2v + 2*k3v + k4v)
        dr = (vessel_step_size/6)*(k1r + 2*k2r + 2*k3r + k4r)

        v.append(v[-1] + dv)
        r.append(r[-1] + dr)

    return r, v

def update_screen():
    screen.blit(surface_enviroment, (0, 0))
    screen.blit(surface_maneuver, (0, 0))
    pg.display.update()

def render_maneuver():
    if len(r) == 0: return
    surface_maneuver.fill((0, 0, 0, 0))

    for i in range(len(maneuver_r)-1): # maneuver trajectory
        a = maneuver_r[i]
        b = maneuver_r[i+1]
        pg.draw.line(surface_maneuver, (0, 255, 0), camera_pos + vec3_ignore_z(a)*scale, camera_pos + vec3_ignore_z(b)*scale)
    pg.draw.circle(surface_maneuver, (100, 100, 100), camera_pos + vec3_ignore_z(r[maneuver_index])*scale, 5)

def render_enviroment():
    surface_enviroment.fill("#3C3846")

    for body in bodies: # draw bodies
        for i in range(len(body.r)-1): # draw body main trajectory
            a = vec3_ignore_z(body.r[i])
            b = vec3_ignore_z(body.r[i+1])
            pg.draw.line(surface_enviroment, (255, 0, 255), camera_pos + a*scale, camera_pos + b*scale)
        pg.draw.circle(surface_enviroment, (0, 0, 100), camera_pos + vec3_ignore_z(body.r[maneuver_index])*scale, body.radius*scale)

    for i in range(len(r)-1): # draw vessel main trajectory
        a = r[i]
        b = r[i+1]
        pg.draw.line(surface_enviroment, (255, 0, 0), camera_pos + vec3_ignore_z(a)*scale, camera_pos + vec3_ignore_z(b)*scale)

def mouse_down_handler(pos):
    global maneuver_index

    # set index on click
    if len(r) == 0: return
    min_index = 0
    min_dist = 9999999
    for i, p in enumerate(r):
        p_2d = camera_pos + vec3_ignore_z(p)*scale
        dist = (Vector2(pos) - p_2d).magnitude()
        if dist < min_dist:
            min_dist = dist
            min_index = i
    update_man_index(min_index)
    render_maneuver()
    update_screen()

def key_down_handler(key):
    global scale, camera_pos

    if key == pg.K_KP_PLUS or key == pg.K_PLUS:
        scale *= 1 + delta_scale
        render_enviroment()
        render_maneuver()
        update_screen()
        return
    if key == pg.K_KP_MINUS or key == pg.K_MINUS:
        scale *= 1 - delta_scale
        render_enviroment()
        render_maneuver()
        update_screen()
        return
    if key == pg.K_UP:
        camera_pos.y += camera_speed
        render_enviroment()
        render_maneuver()
        update_screen()
        return
    if key == pg.K_DOWN:
        camera_pos.y -= camera_speed
        render_enviroment()
        render_maneuver()
        update_screen()
        return
    if key == pg.K_RIGHT:
        camera_pos.x -= camera_speed
        render_enviroment()
        render_maneuver()
        update_screen()
        return
    if key == pg.K_LEFT:
        camera_pos.x += camera_speed
        render_enviroment()
        render_maneuver()
        update_screen()
        return

def controller_event_handler(event, values):
    global vessel_step_size, vessel_sim_time, maneuver_sim_time

    steps = values.copy()

    for key, value in steps.items():
        try:
            steps[key] = int(value)
        except (ValueError, TypeError):
            steps[key] = 1

    # SIMULATION
    if event == "add_sim-step-size":
        vessel_step_size += steps["step_sim-step-size"]
        window_controller["display_sim-step-size"].update(vessel_step_size)
        return
    if event == "sub_sim-step-size":
        vessel_step_size -= steps["step_sim-step-size"]
        window_controller["display_sim-step-size"].update(vessel_step_size)
        return
    if event == "add_sim-time":
        vessel_sim_time += steps["step_sim-time"]
        window_controller["display_sim-time"].update(vessel_sim_time)
        return
    if event == "sub_sim-time":
        vessel_sim_time -= steps["step_sim-time"]
        window_controller["display_sim-time"].update(vessel_sim_time)
        return
    if event == "btn_sim-exec":
        global r, v
        r, v = calc_vessel(r0, v0, vessel_sim_time)
        render_enviroment()
        update_screen()
        return

    # BODY
    if event == "btn_body-sim-exec":
        calc_bodies()
        render_enviroment()
        update_screen()
        return

    # maneuver
    if event == "add_man-time":
        maneuver_sim_time += steps["step_man-time"]
        window_controller["display_man-time"].update(maneuver_sim_time)
        return
    if event == "sub_man-time":
        maneuver_sim_time -= steps["step_man-time"]
        window_controller["display_man-time"].update(maneuver_sim_time)
        return
    if event == "add_man-index":
        update_man_index(maneuver_index + steps["step_man-index"])
        return
    if event == "sub_man-index":
        update_man_index(maneuver_index - steps["step_man-index"])
        return

    # VEL
    if event == "add_man-vel-tg":
        maneuver_vel.x += steps["step_man-vel-tg"]
        window_controller["display_man-vel-tg"].update(maneuver_vel.x)
        return
    if event == "add_man-vel-norm":
        maneuver_vel.y += steps["step_man-vel-norm"]
        window_controller["display_man-vel-norm"].update(maneuver_vel.y)
        return
    if event == "add_man-vel-rad":
        maneuver_vel.z += steps["step_man-vel-rad"]
        window_controller["display_man-vel-rad"].update(maneuver_vel.z)
        return

    if event == "sub_man-vel-tg":
        maneuver_vel.x -= steps["step_man-vel-tg"]
        window_controller["display_man-vel-tg"].update(maneuver_vel.x)
        return
    if event == "sub_man-vel-norm":
        maneuver_vel.y -= steps["step_man-vel-norm"]
        window_controller["display_man-vel-norm"].update(maneuver_vel.y)
        return
    if event == "sub_man-vel-rad":
        maneuver_vel.z -= steps["step_man-vel-rad"]
        window_controller["display_man-vel-rad"].update(maneuver_vel.z)
        return

    # maneuver EXEC
    if event == "btn_man-sim-exec":
        global maneuver_v, maneuver_r
        print("maneuver RUNNING...")

        tg = maneuver_vel.x
        m_vel = v[maneuver_index].normalize() * tg

        maneuver_r, maneuver_v = calc_vessel(r[maneuver_index], v[maneuver_index] + m_vel, maneuver_sim_time)

        render_maneuver()
        update_screen()
        return

def update_man_index(index):
    global maneuver_index
    if index < 0 or index >= len(r) or index == maneuver_index: return
    maneuver_index = index
    window_controller["display_man-index"].update(index)
    render_maneuver()
    render_enviroment()
    update_screen()

bodies = []
with open("bodies_earth_ref.txt", "r") as file: # load bodies
    for line in file.readlines()[1:]:
        name, pos, vel, mass, radius = line.replace("\n", "").split("|")
        pos = Vector3(eval(pos))
        vel = Vector3(eval(vel))
        pos.z = 0 # ignore height
        vel.z = 0 # ignore height
        mass = float(mass)
        radius = float(radius)
        bodies.append(Body(name, pos, vel, mass, radius))
earth = get_body_by_name("Earth")
moon = get_body_by_name("Moon")

bodies = [earth, moon]

# RK4
vessel_step_size = 50
body_step_size = 1000

vessel_sim_time = 5000
maneuver_sim_time = 5000
body_sim_time = 5000000

# trajectory - vessel
r = []
v = []
r0 = earth.r[0] - Vector3(0, earth.radius+400000)
v0 = Vector3(7660, 0, 0)

# bodies orbit propagation
# bodies_comb = combinations(bodies, 2)

# PG
screen_size = Vector2(800, 800)
screen = pg.display.set_mode(screen_size)
pg.display.set_caption("Orbit")

surface_enviroment = pg.Surface(screen_size)
surface_maneuver = pg.Surface(screen_size, pg.SRCALPHA)

delta_scale = 1e-1
scale = 15e-6

camera_pos = screen_size * 0.5
camera_speed = 100

maneuver_index = 0
maneuver_scale = 10
maneuver_vel = Vector3(0, 0, 0) # tg | norm | radial
maneuver_r = []
maneuver_v = []

# SG
font_sizes = [10, 12, 20, 30, 35]
font_by_size = lambda size: ("DS-Digital", size)
sg.theme("Dark")
sg.set_options(font=font_by_size(font_sizes[2]))
layout = [
    [sg.Text("==SIMULATION==", font=font_by_size(font_sizes[4]))],
    [sg.Text("Step Size"), sg.Text(str(vessel_step_size), key="display_sim-step-size", font=font_by_size(font_sizes[2])), sg.Button("+", key="add_sim-step-size"), sg.Button("-", key="sub_sim-step-size"), sg.InputText("1", size=(5, 1), key="step_sim-step-size")],
    [sg.Text("Time"), sg.Text(str(vessel_sim_time), key="display_sim-time", font=font_by_size(font_sizes[2])), sg.Button("+", key="add_sim-time"), sg.Button("-", key="sub_sim-time"), sg.InputText("1", size=(5, 1), key="step_sim-time")],
    [sg.Button("Simulate", key="btn_sim-exec", font=font_by_size(font_sizes[2]))],
    [sg.Text("==BODIES==", font=font_by_size(font_sizes[4]))],
    [sg.Button("Simulate", key="btn_body-sim-exec", font=font_by_size(font_sizes[2]))],
    [sg.Text("==MANEUVER==", font=font_by_size(font_sizes[4]))],
    [sg.Text("Index"), sg.Text(str(maneuver_index), key="display_man-index", font=font_by_size(font_sizes[2])), sg.Button("+", key="add_man-index"), sg.Button("-", key="sub_man-index"), sg.InputText("1", size=(5, 1), key="step_man-index")],
    [sg.Text("Time"), sg.Text(str(maneuver_sim_time), key="display_man-time", font=font_by_size(font_sizes[2])), sg.Button("+", key="add_man-time"), sg.Button("-", key="sub_man-time"), sg.InputText("1", size=(5, 1), key="step_man-time")],
    [sg.Text("--Vel--")],
    [sg.Text("tg"), sg.Text(str(maneuver_vel.x), key="display_man-vel-tg", font=font_by_size(font_sizes[2])), sg.Button("+", key="add_man-vel-tg"), sg.Button("-", key="sub_man-vel-tg"), sg.InputText("1", size=(5, 1), key="step_man-vel-tg")],
    [sg.Text("norm"), sg.Text(str(maneuver_vel.y), key="display_man-vel-norm", font=font_by_size(font_sizes[2])), sg.Button("+", key="add_man-vel-norm"), sg.Button("-", key="sub_man-vel-norm"), sg.InputText("1", size=(5, 1), key="step_man-vel-norm")],
    [sg.Text("rad"), sg.Text(str(maneuver_vel.z), key="display_man-vel-rad", font=font_by_size(font_sizes[2])), sg.Button("+", key="add_man-vel-rad"), sg.Button("-", key="sub_man-vel-rad"), sg.InputText("1", size=(5, 1), key="step_man-vel-rad")],
    [sg.Button("Execute maneuver", key="btn_man-sim-exec")],
]
window_controller = sg.Window("Controller", layout)

calc_bodies()
render_enviroment()
update_screen()

while True:
    # PG - Renderer
    for event in pg.event.get():
        if event.type == pg.QUIT:
            pg.quit()
            break
        if event.type == pg.KEYDOWN:
            key_down_handler(event.key)
        elif event.type == pg.MOUSEBUTTONDOWN:
            mouse_down_handler(pg.mouse.get_pos())

    # SG - Controller
    event, values = window_controller.read(timeout=100)

    if event == sg.WIN_CLOSED:
        pg.quit()
        break

    if event is not None: controller_event_handler(event, values)


import urllib2
import json
import random

def lambda_handler(event, context):
    """ Route the incoming request based on type (LaunchRequest, IntentRequest,
    etc.) The JSON body of the request is provided in the event parameter.
    """
    print("event.session.application.applicationId=" +
          event['session']['application']['applicationId'])

    """
    Uncomment this if statement and populate with your skill's application ID to
    prevent someone else from configuring a skill that sends requests to this
    function.
    """
    # if (event['session']['application']['applicationId'] !=
    #         "amzn1.echo-sdk-ams.app.[unique-value-here]"):
    #     raise ValueError("Invalid Application ID")

    if event['session']['new']:
        on_session_started({'requestId': event['request']['requestId']},
                           event['session'])

    if event['request']['type'] == "LaunchRequest":
        return on_launch(event['request'], event['session'])
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
        return on_session_ended(event['request'], event['session'])

def on_session_started(session_started_request, session):
    """ Called when the session starts """

    print("on_session_started requestId=" + session_started_request['requestId']
          + ", sessionId=" + session['sessionId'])

def on_launch(launch_request, session):
    """ Called when the user launches the skill without specifying what they
    want
    """

    print("on_launch requestId=" + launch_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # Dispatch to your skill's launch
    return get_story()

def on_intent(intent_request, session):
    """ Called when the user specifies an intent for this skill """

    print("on_intent requestId=" + intent_request['requestId'] +
          ", sessionId=" + session['sessionId'])

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    # Dispatch to your skill's intent handlers
    if intent_name == "StoryTeller":
        return get_icebreaker_story(intent, session)
    else:
        raise ValueError("Invalid intent")

def on_session_ended(session_ended_request, session):
    """ Called when the user ends the session.

    Is not called when the skill returns should_end_session=true
    """
    print("on_session_ended requestId=" + session_ended_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # add cleanup logic here

#store mp3 on s3 with a suffix 0-5 to get random samples
def getUrl():
    #return "https://s3.amazon.com/gwc/sample_" + random.randint(0, 5) + ".mp3"
    return "https://s3.amazonaws.com/audible-girls-who-code/dreamhouse.mp3"

def get_icebreaker_story(intent, session):

    url = getUrl()
    output = "<speak> Girls who code welcome to Audible. Here is the story you requested:  <break time=\"1s\"/> <audio src=\""  + url + "\"/>  </speak>"
    card_title = intent['name']
    session_attributes = {}
    should_end_session = True
    reprompt_text = 'Please ask me to tell a story'

    return build_response(session_attributes, build_speechlet_response(
          card_title, output, reprompt_text, should_end_session))

def get_story(intent, session):
    asin = 'B0118CYHCK'   #TODO: get random ASIN

    url = 'https://api.audible.com/1.0/catalog/products/' + asin + '?response_groups=sample'
    response = urllib2.urlopen(url)
    data = json.load(response)
    offset = 10000;
    sample_url = data['product']['sample_url']

    card_title = intent['name']
    session_attributes = {}
    should_end_session = True
    reprompt_text = 'Please ask me to tell a story'

    return build_response(session_attributes, build_audioplayer_speechlet_response(
          card_title, reprompt_text, should_end_session, sample_url, offset))

# --------------- Helpers that build all of the responses ----------------------
# ADD AudioPlayer here

def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'SSML',
            'ssml': output
        },
        'card': {
            'type': 'Simple',
            'title': 'SessionSpeechlet - ' + title,
            'content': 'SessionSpeechlet - ' + output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }

def build_audioplayer_speechlet_response(title, reprompt_text, should_end_session, audioURL, offset):
    return {
        'directives': [ {
           'type': 'AudioPlayer.Play',
           'playBehavior': 'REPLACE_ALL', #Setting to REPLACE_ALL means that this track will start playing immediately
           'audioItem': {
                'stream': {
                    'url': audioURL,
                    'token': "0", #Unique token for the track - needed when queueing multiple tracks
                    'expectedPreviousToken': None, # The expected previous token - when using queues, ensures safety
                    'offsetInMilliseconds': offset
                }
            }
        }],
        'card': {
            'type': 'Simple',
            'title': 'SessionSpeechlet - ' + title,
            'content': 'SessionSpeechlet - ' + 'Test'
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }

def build_response(session_attributes, speechlet_response):
    return {
        'version': '1.0',
        'sessionAttributes': session_attributes,
        'response': speechlet_response
    }


from bs4 import BeautifulSoup
import urllib
import os

def page_exists(url):
    local_filename, headers = urllib.request.urlretrieve(url)
    html = open(local_filename)
    soup = BeautifulSoup(html, "html.parser")
    next = soup.find_all("a", class_="pagInfo-page-numbers-next empty")
    html.close()
    os.remove(local_filename)

    if len(next) == 0:
        return True
    else:
        return False

def get_num_dished(cuisine):
    url = "https://www.bbc.com/food/recipes/search?cuisines[]=" + cuisine
    local_filename, headers = urllib.request.urlretrieve(url)
    html = open(local_filename)
    soup = BeautifulSoup(html, "html.parser")
    text = str(soup.find_all("div", id="queryBox"))
    text = text.split("
")[1].split(" ")[0]
    return int(text)

def det_add_dishes_dict(cuisine):
    dict_add_dish = {}
    with open("/home/umberto/Desktop/NoLinkIngr/" + cuisine + ".txt") as file:
        for line in file:
            line = line.replace("\n", "")
            name = line.split("| ")[0]
            new_name = line.split("| ")[1]
            dict_add_dish[name.replace(" ", "")] = new_name

    return dict_add_dish

#
cuisines = [#"african", "american", "british", "caribbean",
            #"chinese", "east_european", "french", "greek",
           #"indian", "irish", "italian", "japanese",
           #"korean",
            "mexican", "nordic", "north_african",
           "pakistani", "portuguese", "south_american",
           "spanish", "thai_and_south-east_asian",
           "turkish_and_middle_eastern"]

recepies_dataset = "/home/umberto/Desktop/data/DetasetRecepies/"
#images_dataset = "/home/umberto/Desktop/DatasetImages/"

file_url = open("/home/umberto/Desktop/data/urls.csv", "a")

for cuisine in cuisines:
    num_of_dishes_for_page = 15
    num_dished = get_num_dished(cuisine)
    print("Current letter: ", cuisine, "  --  num of dishes: ", num_dished)

    dataset_name = recepies_dataset + cuisine + ".csv"
    dataset = open(dataset_name, "w")

    upp = int(num_dished/num_of_dishes_for_page)
    if num_dished % num_of_dishes_for_page != 0:
        upp += 1

    dict_add_dish = det_add_dishes_dict(cuisine)

    for i in range(1, upp+1):
        url = "https://www.bbc.com/food/recipes/search?page=" + str(i) +"&cuisines%5B0%5D=" + cuisine + "&sortBy=lastModified"
        local_filename, headers = urllib.request.urlretrieve(url)
        html = open(local_filename)
        soup = BeautifulSoup(html, "html.parser")

        for dish in soup.find_all("div", class_="left with-image"):
            domain = "https://www.bbc.com"
            link = str(dish).split("href=")[1].split("\"")[1]
            name = str(dish).split("")[0].split(">")[-1]

            url2 = domain + link
            file, h = urllib.request.urlretrieve(url2)
            html2 = open(file)
            soup2 = BeautifulSoup(html2, "html.parser")
            list_ingr = ""

            for ingr in soup2.find_all("a", class_="recipe-ingredients__link"):
                list_ingr += str(ingr).split(">")[1][:-3] + ";"

            for ingr in soup2.find_all("li", class_="recipe-ingredients__list-item"):
                if "" not in str(ingr):
                    name_ing = str(ingr).split("<")[1].split(">")[-1]
                    if name_ing != "":
                        dict_value = dict_add_dish[name_ing.replace(" ", "")]
                        if dict_value != " ":
                            list_ingr += dict_value + ";"

            dataset.write(name + ";" + list_ingr + "\n")
            file_url.write(name + ";" + url2 + "\n")

            #imm = soup2.find_all("div", class_="responsive-image-container__16/9")[0]
            #link_imm = str(imm).split("src=")[1].split("\"")[1]

            #if not os.path.exists(images_dataset + cuisine):
            #    os.makedirs(images_dataset + cuisine)

            #urllib.request.urlretrieve(link_imm, images_dataset + cuisine + "/" + name + ".jpg")

            html2.close()
            os.remove(file)

        file_url.flush()

        html.close()
        os.remove(local_filename)
    dataset.close()
file_url.close()


from itertools import permutations
n = int(input())
k = int(input())
a = []
for i in range(1,n+1):
    a.append(i)
l= list(permutations(a,n))
l_ = []
for i in range(len(l)):
    s = ''
    for j in range(n):
        s += str(l[i][j])
    l_.append(s)
l_.sort()
print(l_[k-1])


import requests
import json

class Dingding_Robot_new():
    def __init__(self, dingding_cfg=None):
        self.appkey = dingding_cfg.appkey
        self.appsecret = dingding_cfg.appsecret
        self.chatid = dingding_cfg.chatid

    def getAccess_token(self):
        appkey = self.appkey  # 管理员账号登录开发者平台，应用开发-创建应用-查看详情-appkey
        appsecret = self.appsecret  # 应用里的appsecret
        # https://oapi.dingtalk.com/gettoken?appkey=key&appsecret=secret
        url = 'https://oapi.dingtalk.com/gettoken'
        headers = {
            'Content-Type': "application/x-www-form-urlencoded"
        }
        data = {'appkey': appkey,
                'appsecret': appsecret}
        r = requests.get(url=url, params=data, headers=headers)
        # print(r.text)
        access_token = r.json()["access_token"]

        print(access_token)
        return access_token

    def getMedia_id(self):
        access_token = self.getAccess_token()  # 拿到接口凭证
        path = 'C:/Users/Long/Desktop/123.txt'  # 文件路径
        url = 'https://oapi.dingtalk.com/media/upload?access_token=' + access_token + '&type=file'
        files = {'media': open(path, 'rb')}
        data = {'access_token': access_token,
                'type': 'file'}
        response = requests.post(url, files=files, data=data)
        json = response.json()
        print(json)
        return json["media_id"]

    def SendFile(self):
        access_token = self.getAccess_token()
        media_id = self.getMedia_id()
        chatid = self.chatid  # 通过jsapi工具获取的群聊id
        url = 'https://oapi.dingtalk.com/chat/send?access_token=' + access_token
        header = {
            'Content-Type': 'application/json'
        }
        data = {'access_token': access_token,
                'chatid': chatid,
                'msg': {
                    'msgtype': 'file',
                    'file': {'media_id': media_id}
                }}
        r = requests.request('POST', url, data=json.dumps(data), headers=header)
        print(r.json())

if __name__ == "__main__":
    run = Dingding_Robot_new()
    run.SendFile()


import datetime
import logging

from flask import Blueprint, request

from app.constants import REBOOKINGS_SPREADSHEET_ID, SheetHeaderIndex
from app.services.google_sheets_client import google_sheets

logger = logging.getLogger(__name__)

blueprint = Blueprint("blvd_appointment_created", __name__, url_prefix="/blvd")

@blueprint.route("/appointment_created", methods=["POST"])
def appointment_created():
    request_json = request.get_json()

    if request_json.get("event") == "ping":
        logger.info(
            f"Received ping for {request_json.get('url')}. "
            f"ID: {request_json.get('webhookId')}"
        )
        return request_json

    client_data = request_json.get("data", {}).get("node")
    appt_client_id = client_data.get("clientId")

    sheet_client_ids = google_sheets.get_values_from_sheet(
        REBOOKINGS_SPREADSHEET_ID, "rebookings!A2:A", major_dimension="COLUMNS"
    )[0]

    try:
        # Checking if value exists - if it does not, a ValueError is raised
        row_number = sheet_client_ids.index(appt_client_id) + 2

        row_data = google_sheets.get_values_from_sheet(
            REBOOKINGS_SPREADSHEET_ID, f"rebookings!{row_number}:{row_number}"
        )[0]
        current_time = datetime.datetime.now()
        sheet_input_datetime = datetime.datetime.fromisoformat(
            row_data[SheetHeaderIndex.INPUT_TIME.value]
        )

        if row_data[SheetHeaderIndex.INITIAL_APPT_BOOKED.value] == "FALSE":
            row_data[SheetHeaderIndex.INITIAL_APPT_BOOKED.value] = "TRUE"
        elif (
            sheet_input_datetime
            <= current_time
            <= (sheet_input_datetime + datetime.timedelta(seconds=15))
        ):
            logger.info(f"Initial appt already booked: {row_data}")
            return {"row_data": row_data}
        elif row_data[SheetHeaderIndex.REBOOKED.value] == "FALSE":
            row_data[SheetHeaderIndex.REBOOKED.value] = "TRUE"
        else:
            return {"row_data": row_data}

        row_data[SheetHeaderIndex.ROW_LAST_UPDATED_TIME.value] = str(current_time)

        body_data = [
            [
                appt_client_id,
                str(current_time),
                str(client_data),
            ]
        ]

        rebookings_update_response = google_sheets.update_sheet(
            REBOOKINGS_SPREADSHEET_ID,
            f"rebookings!{row_number}:{row_number}",
            [row_data],
        )
        google_sheets.append_to_sheet(
            REBOOKINGS_SPREADSHEET_ID,
            "new_client_appointments!A:A",
            body_data,
        )

        logger.info(
            f"Updated sheet with new Boulevard Appointment: "
            f"{rebookings_update_response}"
        )

        return rebookings_update_response

    except ValueError:
        logger.info(
            f"NOT FOUND: Attempted to find client_id {appt_client_id} in google sheet."
        )
        return request_json


import unittest
from appium import webdriver
from time import sleep
import HTMLTestRunner
import time
import my_testRunner

class MyTestCase(unittest.TestCase):

    @classmethod
    def setUpClass(self):
        desired_caps = {'platformName': 'Android',
                        'platformVersion': '6.0',
                        'deviceName': '192.168.163.101:5555',
                        'app': 'C:\\Users\\admin\\Desktop\\selendroid-test-app-0.17.0.apk',
                        'appPackage': 'io.selendroid.testapp',
                        'appActivity': '.HomeScreenActivity',
                        'unicodeKeyboard': True,
                        'resetKeyboard': True,
                        'automationName': 'Selendroid',
                        'noReset': True}
        self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
        self.driver.implicitly_wait(5)

    @classmethod
    def tearDownClass(self):
        self.driver.quit()

    def test_1(self):
        driver = self.driver
        driver.find_element_by_id('buttonStartWebview').click()
        driver.find_element_by_id('spinner_webdriver_test_data').click()
        driver.find_element_by_link_text('xhtmlTestPage').click()
        sleep(2)
        # 此时验证的信息在WEBVIEW_0的context中，所以需要切换到web app
        driver.switch_to.context('WEBVIEW_0')
        self.assertTrue(driver.page_source.__contains__('XHTML Might Be The Future'))
        # print(driver.contexts)  # 打印当前界面中的所有上下

    def test_2(self):
        driver = self.driver
        driver.find_elements_by_link_text('click me')[0].click()
        sleep(2)
        self.assertTrue(driver.page_source.__contains__('List of stuff'))
        driver.switch_to.context('NATIVE_APP')
        driver.find_element_by_id('goBack').click()
        sleep(1)
        self.assertTrue(driver.find_element_by_id('buttonTest').is_displayed())

if __name__ == '__main__':
    cases_MyTestCase = unittest.TestLoader().loadTestsFromTestCase(MyTestCase)
    cases_my_testRunner = unittest.TestLoader().loadTestsFromTestCase(my_testRunner.TestOne)
    suite = unittest.TestSuite([cases_MyTestCase, cases_my_testRunner])
    suite.addTest(my_testRunner.TestOne('test_2'))
    now = time.strftime('%Y-%m-%d_%H-%M-%S', time.localtime(time.time()))
    fp = open(now + 'Result.html', 'wb')
    runner = HTMLTestRunner.HTMLTestRunner(stream=fp, verbosity=2, title='Test Report', description=u'Result:')
    runner.run(suite)
    print(now)
    fp.close()


from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import json

def set_chrome_driver():
    chrome_options = webdriver.ChromeOptions()
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
    return driver

options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-logging'])

# 브라우저 생성
driver = webdriver.Chrome(service=Service('/Users/user/chromedriver'), options=options)

# 웹사이트 열기
driver.get('https://google.com')

# 로딩이 끝날 동안 2초 기다린다
driver.implicitly_wait(3)

# 화면 크기 최대화
driver.maximize_window()

# 검색창 클릭
search = browser.find_element(By.NAME, 'q')
search.click()

# 검색어 입력
search.send_keys('교보문고')
search.send_keys(Keys.ENTER)

# 교보문고 홈페이지 링크 클릭 및 이동
driver.find_element(By.XPATH, '//*[@id="rso"]/div[1]/div/div/div/div/div/div/div/div[1]/a/h3').click()

# 교보문고 홈페이지로 이동하는 동안 2초 기다린다
time.sleep(2)

# 국내도서
driver.find_element(By.XPATH, '//*[@id="header"]/div[3]/ul[1]/li[1]/a').click()

# 유아(0~7세)
driver.find_element(By.XPATH, '//*[@id="main_snb"]/div[1]/ul[3]/li[1]/a/em').click()

# 베스트셀러
driver.find_element(By.XPATH, '//*[@id="container"]/div[2]/div/div/div[3]/ul/li[2]/a').click()


import random
from typing import Callable, Any

def validate_args(func: Callable) -> Callable:

    def wrapped_func(*args) -> Any:
        if len(args) < 1:
            print('Not enough arguments')
            return

        if len(args) > 1:
            print('Too many arguments')
            return

        inp = args[0]
        if not isinstance(inp, int):
            print('Wrong types')
            return

        if inp < 0:
            print('Negative argument')
            return
        else:
            return func(inp)

    return wrapped_func

# @validate_args
# def somefunc(number):
#     result = number + random.randint(-number, 100)
#     return 'Ваш психологический возраст: {} лет!'.format(result)
#
#
# ans = somefunc(24)
# print(ans)