import numpy as np
import torch
import os
import yaml
import tqdm
from addict import Dict
from collections import defaultdict
from matplotlib import pyplot as plt
import matplotlib.patches as patches
import pickle
import random
import pytorch_ssim

from skimage.measure import compare_ssim as ssim
from train import build_loaders
from scene_generation.data import imagenet_deprocess_batch
from scene_generation.metrics import jaccard
from scene_generation.model import Model
from scene_generation.args import get_args

#perceptual error
from PerceptualSimilarity import models
#from PerceptualSimilarity.util import util

GPU = 0
PRECOMPUTED = False     # use precomputed samples (saved in the checkpoint) for evaluation
EVAL_ALL = True         # evaluate on all bounding boxes (batch size=1)
USE_GT = True           # use ground truth bounding boxes for evaluation
USE_FEATS = False #True
IGNORE_SMALL = False
SPLIT = '../sg2im/datasets/vg/test.h5'

BATCH_SIZE = 1
PRINT_EVERY = 50
SAVE_EVERY = 500

#EXPERIMENT = 'jitter_L_0.05_FixBoxes'
#EXPERIMENT = 'clean_infeats_64'
EXPERIMENT = "aGCN_SPADE"
ckpt = "checkpoint"
#EXPERIMENT = 'baseline_64_noise_250k'
CHECKPOINT = './output/Nov12_14-43-14_atnavab21/{}_with_model.pt'.format(ckpt)
#config_file = 'experiments/default/logs/{}/args.yaml'.format(EXPERIMENT)
results_file = 'test_results_{}.pickle'

def main():
    if not os.path.isfile(CHECKPOINT):
        print('ERROR: Checkpoint file "%s" not found' % CHECKPOINT)
        return

    # Read config file of the model
    args = get_args()
    print(args)
    torch.manual_seed(1)
    random.seed(1)
    np.random.seed(1)

    # reset some arguments
    args.add_jitter_bbox = None
    args.add_jitter_layout = None
    args.add_jitter_feats = None
    args.batch_size = BATCH_SIZE
    args.test_h5 = SPLIT
    device = torch.device("cuda:0") #torch.cuda.set_device(GPU)

    # Load the model, with a bit of care in case there are no GPUs
    map_location = 'cpu' if device == torch.device('cpu') else None
    checkpoint = torch.load(CHECKPOINT, map_location=map_location)

    if not PRECOMPUTED:
        # initialize model and load checkpoint
        kwargs = checkpoint['model_kwargs']

        model = Model(**kwargs)
        model.load_state_dict(checkpoint['model_state'])
        model.eval()
        model.to(device)

        # create data loaders
        _, train_loader, val_loader, test_loader = build_loaders(args, evaluating=True)

        # testing model
        print('Batch size: ', BATCH_SIZE)
        print('Evaluating on {} set'.format(SPLIT))
        eval_model(args, model, test_loader, device, use_gt=USE_GT, use_feats=USE_FEATS, filter_box=IGNORE_SMALL)
        # losses, samples, avg_iou = results
    else:
        # sample images and scores already computed while training (only one batch)
        samples = checkpoint['val_samples'][-1]    # get last iteration
        original_img = samples['gt_img'].cpu().numpy()
        predicted_img = samples['gt_box_pred_mask'].cpu().numpy()

    return

def eval_model(args, model, loader, device, use_gt=False, use_feats=False, filter_box=False):
    all_losses = defaultdict(list)
    all_boxes = defaultdict(list)
    total_iou = []
    total_boxes = 0
    num_batches = 0
    num_samples = 0
    mae_per_image = []
    mae_roi_per_image = []
    roi_only_iou = []
    ssim_per_image = []
    ssim_rois = []
    rois = 0
    margin = 2

    ## Initializing the perceptual loss model
    lpips_model = models.PerceptualLoss(model='net-lin',net='alex',use_gpu=True)
    perceptual_error_image = []
    perceptual_error_roi = []
    # ---------------------------------------

    with torch.no_grad():
        for batch in tqdm.tqdm(loader):
            num_batches += 1
            # if num_batches > 10:
            #     break
            batch = [tensor.to(device) for tensor in batch]
            masks = None
            if len(batch) == 6:
                imgs, objs, boxes, triples, obj_to_img, triple_to_img = batch
            elif len(batch) == 7:
                imgs, objs, boxes, masks, triples, obj_to_img, triple_to_img = batch
            elif len(batch) == 12:
                imgs, objs, boxes, triples, obj_to_img, triple_to_img, \
                objs_r, boxes_r, triples_r, obj_to_img_r, triple_to_img_r, imgs_in = batch
            elif len(batch) == 13:
                imgs, objs, boxes, triples, obj_to_img, triple_to_img, attributes, \
                objs_r, boxes_r, triples_r, obj_to_img_r, triple_to_img_r, imgs_in = batch
            else:
                assert False
            predicates = triples[:, 1]

            # #EVAL_ALL = True
            if EVAL_ALL:
                imgs, imgs_in, objs, boxes, triples, obj_to_img, \
                dropbox_indices, dropfeats_indices = process_batch(
                    imgs, imgs_in, objs, boxes, triples, obj_to_img, triple_to_img, device,
                    use_feats=use_feats, filter_box=filter_box)
            else:
                dropbox_indices = None
                dropfeats_indices = None
            #
            # if use_gt: # gt boxes
            #     model_out = model(objs, triples, obj_to_img, boxes_gt=boxes, masks_gt=masks, src_image=imgs_in,
            #                       drop_box_idx=None, drop_feat_idx=dropfeats_indices, mode='eval')
            # else:
            #     model_out = model(objs, triples, obj_to_img, boxes_gt=boxes, src_image=imgs_in,
            #                       drop_box_idx=dropbox_indices, drop_feats_idx=dropfeats_indices, mode='eval')

            masks_gt = None
            gt_train = False

            attributes = torch.zeros_like(attributes)

            all_features = None
            # Run the model with predicted masks
            model_out = model(imgs, objs, triples, obj_to_img, boxes_gt=boxes, masks_gt=masks_gt, attributes=attributes,
                              gt_train=gt_train, test_mode=False, use_gt_box=True, features=all_features
                              , drop_box_idx=dropbox_indices, drop_feat_idx= dropfeats_indices, src_image= imgs_in)
            #imgs_pred, boxes_pred, masks_pred, _, layout, _ = model_out

            # OUTPUT
            imgs_pred, boxes_pred, masks_pred, predicate_scores, layout, _ = model_out
            # --------------------------------------------------------------------------------------------------------------
            #imgs_pred *= 3
            #print(imgs_pred.min(), imgs_pred.max())

            # Save all box predictions
            all_boxes['boxes_gt'].append(boxes)
            all_boxes['objs'].append(objs)
            all_boxes['boxes_pred'].append(boxes_pred)
            all_boxes['drop_targets'].append(dropbox_indices)

            # IoU over all
            total_iou.append(jaccard(boxes_pred, boxes).cpu().numpy()) #.detach()
            total_boxes += boxes_pred.size(0)

            # IoU over targets only
            pred_dropbox = boxes_pred[dropbox_indices.squeeze() == 0, :]
            gt_dropbox = boxes[dropbox_indices.squeeze() == 0, :]
            roi_only_iou.append(jaccard(pred_dropbox, gt_dropbox).detach().cpu().numpy())
            rois += pred_dropbox.size(0)
            # assert(pred_dropbox.size(0) == imgs.size(0))

            num_samples += imgs.shape[0]
            imgs = imagenet_deprocess_batch(imgs).float()
            imgs_pred = imagenet_deprocess_batch(imgs_pred).float()

            # Uncomment to plot images (for debugging purposes)
            #visualize_imgs_boxes(imgs, imgs_pred, boxes, boxes)

            # MAE per image
            mae_per_image.append(torch.mean(
                torch.abs(imgs - imgs_pred).view(imgs.shape[0], -1), 1).cpu().numpy())

            for s in range(imgs.shape[0]):
                # get coordinates of target
                left, right, top, bottom = bbox_coordinates_with_margin(boxes[s, :], margin, imgs)
                # calculate errors only in RoI one by one - good, i wanted to check this too since the errors were suspicious pheww
                mae_roi_per_image.append(torch.mean(
                    torch.abs(imgs[s, :, top:bottom, left:right] - imgs_pred[s, :, top:bottom, left:right])).cpu().item())

                ssim_per_image.append(
                    pytorch_ssim.ssim(imgs[s:s+1, :, :, :] / 255.0,
                                      imgs_pred[s:s+1, :, :, :] / 255.0, window_size=3).cpu().item())
                ssim_rois.append(
                    pytorch_ssim.ssim(imgs[s:s+1, :, top:bottom, left:right] / 255.0,
                                      imgs_pred[s:s+1, :, top:bottom, left:right] / 255.0, window_size=3).cpu().item())

                imgs_pred_norm = imgs_pred[s:s+1, :, :, :] / 127.5 - 1 # = util.im2tensor(imgs_pred[s:s+1, :, :, :].detach().cpu().numpy())
                imgs_gt_norm = imgs[s:s+1, :, :, :] / 127.5 - 1  # util.im2tensor(imgs[s:s+1, :, :, :].detach().cpu().numpy())

                #perceptual_error_roi.append(lpips_model.forward(imgs_pred_norm[:,:, top:bottom, left:right],
                #                                                  imgs_gt_norm[:,:, top:bottom, left:right]))

                #print(imgs_pred_norm.shape)
                perceptual_error_image.append(
                    lpips_model.forward(imgs_pred_norm, imgs_gt_norm).detach().cpu().numpy())

            if num_batches % PRINT_EVERY == 0:
                calculate_scores(mae_per_image, mae_roi_per_image, total_iou, roi_only_iou, ssim_per_image, ssim_rois,
                                 perceptual_error_image, perceptual_error_roi)

            if num_batches % SAVE_EVERY == 0:
                save_results(mae_per_image, mae_roi_per_image, total_iou, roi_only_iou, ssim_per_image, ssim_rois,
                 perceptual_error_image, perceptual_error_roi, all_boxes, num_batches)

    # mean_losses = {k: np.mean(v) for k, v in all_losses.items()}

    save_results(mae_per_image, mae_roi_per_image, total_iou, roi_only_iou, ssim_per_image, ssim_rois,
                 perceptual_error_image, perceptual_error_roi, all_boxes, 'final')

    # masks_to_store = masks
    # if masks_to_store is not None:
    #     masks_to_store = masks_to_store.data.cpu().clone()

    # masks_pred_to_store = masks_pred
    # if masks_pred_to_store is not None:
    #     masks_pred_to_store = masks_pred_to_store.data.cpu().clone()

    # batch_data = {
    #     'objs': objs.detach().cpu().clone(),
    #     'boxes_gt': boxes.detach().cpu().clone(),
    #     'masks_gt': masks_to_store,
    #     'triples': triples.detach().cpu().clone(),
    #     'obj_to_img': obj_to_img.detach().cpu().clone(),
    #     'triple_to_img': triple_to_img.detach().cpu().clone(),
    #     'boxes_pred': boxes_pred.detach().cpu().clone(),
    #     'masks_pred': masks_pred_to_store
    # }
    # out = [mean_losses, samples, batch_data, avg_iou]
    # out = [mean_losses, mean_L1, avg_iou]

    return  # mae_per_image, mae_roi_per_image, total_iou, roi_only_iou

def calculate_scores(mae_per_image, mae_roi_per_image, total_iou, roi_only_iou, ssim_per_image, ssim_rois,
                     perceptual_image, perceptual_roi):

    mae_all = np.mean(np.hstack(mae_per_image), dtype=np.float64)
    mae_std = np.std(np.hstack(mae_per_image), dtype=np.float64)
    mae_roi = np.mean(mae_roi_per_image, dtype=np.float64)
    mae_roi_std = np.std(mae_roi_per_image, dtype=np.float64)
    iou_all = np.mean(np.hstack(total_iou), dtype=np.float64)
    iou_std = np.std(np.hstack(total_iou), dtype=np.float64)
    iou_roi = np.mean(np.hstack(roi_only_iou), dtype=np.float64)
    iou_roi_std = np.std(np.hstack(roi_only_iou), dtype=np.float64)
    ssim_all = np.mean(ssim_per_image, dtype=np.float64)
    ssim_std = np.std(ssim_per_image, dtype=np.float64)
    ssim_roi = np.mean(ssim_rois, dtype=np.float64)
    ssim_roi_std = np.std(ssim_rois, dtype=np.float64)
    # percept error -----------
    percept_all = np.mean(perceptual_image, dtype=np.float64)
    #print(perceptual_image, percept_all)
    percept_all_std = np.std(perceptual_image, dtype=np.float64)
    percept_roi = np.mean(perceptual_roi, dtype=np.float64)
    percept_roi_std = np.std(perceptual_roi, dtype=np.float64)
    # ------------------------

    print()
    print('MAE: Mean {:.6f}, Std {:.6f}'.format(mae_all, mae_std))
    print('MAE-RoI: Mean {:.6f}, Std {:.6f}: '.format(mae_roi, mae_roi_std))
    print('IoU: Mean {:.6f}, Std {:.6f}'.format(iou_all, iou_std))
    print('IoU-RoI: Mean {:.6f}, Std {:.6f}'.format(iou_roi, iou_roi_std))
    print('SSIM: Mean {:.6f}, Std {:.6f}'.format(ssim_all, ssim_std))
    print('SSIM-RoI: Mean {:.6f}, Std {:.6f}'.format(ssim_roi, ssim_roi_std))
    print('LPIPS: Mean {:.6f}, Std {:.6f}'.format(percept_all, percept_all_std))
    print('LPIPS-RoI: Mean {:.6f}, Std {:.6f}'.format(percept_roi, percept_roi_std))
    return

def save_results(mae_per_image, mae_roi_per_image, total_iou, roi_only_iou, ssim_per_image, ssim_rois,
                 perceptual_per_image, perceptual_rois, all_boxes, iter):

    results = dict()
    results['mae_per_image'] = mae_per_image
    results['mae_rois'] = mae_roi_per_image
    results['iou_per_image'] = total_iou
    results['iou_rois'] = roi_only_iou
    results['ssim_per_image'] = ssim_per_image
    results['ssim_rois'] = ssim_rois
    results['perceptual_per_image'] = perceptual_per_image
    results['perceptual_rois'] = perceptual_rois
    results['data'] = all_boxes

    with open(results_file.format(iter), 'wb') as p:
        pickle.dump(results, p)

def process_batch(imgs, imgs_in, objs, boxes, triples, obj_to_img, triples_to_img, device,
                  use_feats=True, filter_box=False):
    num_imgs = imgs.shape[0]
    imgs_stack = []
    imgs_in_stack = []
    boxes_stack = []
    objs_stack = []
    triples_stack = []
    obj_to_img_new = []
    candidates_stack = []
    previous_idx = 0

    for i in range(num_imgs):
        start_idx_for_img = (obj_to_img == i).nonzero()[0]
        last_idx_for_img = (obj_to_img == i).nonzero()[-1]
        boxes_i = boxes[start_idx_for_img: last_idx_for_img + 1, :]     # this includes the 'image' box!
        objs_i = objs[start_idx_for_img: last_idx_for_img + 1]

        start_idx_for_img = (triples_to_img == i).nonzero()[0]
        last_idx_for_img = (triples_to_img == i).nonzero()[-1]
        triples_i = triples[start_idx_for_img:last_idx_for_img + 1]

        num_boxes = boxes_i.shape[0]  # number of boxes in current image minus the 'image' box

        if filter_box:
            min_dim = 0.05  # about 3 pixels
            keep = [b for b in range(boxes_i.shape[0] - 1) if
                    boxes_i[b, 2] - boxes_i[b, 0] > min_dim and boxes_i[b, 3] - boxes_i[b, 1] > min_dim]
            print('Ignoring {} out of {} boxes'.format(boxes_i.shape[0] - len(keep), boxes_i.shape[0]))
            times_to_rep = len(keep)
            img_indices = torch.LongTensor(keep)
        else:
            times_to_rep = num_boxes - 1
            img_indices = torch.arange(0, times_to_rep)

        # boxes that will be dropped for each sample (always shift the index by one to get the next box)
        drop_indices = img_indices * (num_boxes + 1)

        # replicate things for current image
        imgs_stack.append(imgs[i, :, :, :].repeat(times_to_rep, 1, 1, 1))
        imgs_in_stack.append(imgs_in[i, :, :, :].repeat(times_to_rep, 1, 1, 1))
        objs_stack.append(objs_i.repeat(times_to_rep))     # replicate object ids #boxes times
        boxes_stack.append(boxes_i.repeat(times_to_rep, 1))   # replicate boxes #boxes times
        obj_to_img_new.append(img_indices.unsqueeze(1).repeat(1, num_boxes).view(-1) + previous_idx)
        previous_idx = obj_to_img_new[-1].max() + 1

        triplet_offsets = (num_boxes * img_indices.unsqueeze(1).repeat(1, triples_i.size(0)).view(-1)).cuda()
        triples_i = triples_i.repeat(times_to_rep, 1)
        triples_i[:, 0] = triples_i[:, 0] + triplet_offsets     # offset for replicated subjects
        triples_i[:, 2] = triples_i[:, 2] + triplet_offsets     # offset for replicated objects
        triples_stack.append(triples_i)

        # create index to drop for each sample
        candidates = torch.ones(boxes_stack[-1].shape[0], device=device)
        candidates[drop_indices] = 0     # set to zero the boxes that should be dropped
        candidates_stack.append(candidates)

    imgs = torch.cat(imgs_stack)
    imgs_in = torch.cat(imgs_in_stack)
    boxes = torch.cat(boxes_stack)
    objs = torch.cat(objs_stack)
    triples = torch.cat(triples_stack)
    obj_to_img_new = torch.cat(obj_to_img_new)
    candidates = torch.cat(candidates_stack).unsqueeze(1)

    if use_feats:
        feature_candidates = torch.ones((candidates.shape[0], 1), device=device)
    else:
        feature_candidates = candidates

    return imgs, imgs_in, objs, boxes, triples, obj_to_img_new, candidates, feature_candidates

def bbox_coordinates_with_margin(bbox, margin, img):
    # extract bounding box with a margin
    left = max(0, bbox[0] * img.shape[3] - margin)
    top = max(0, bbox[1] * img.shape[2] - margin)
    right = min(img.shape[3], bbox[2] * img.shape[3] + margin)
    bottom = min(img.shape[2], bbox[3] * img.shape[2] + margin)

    return int(left), int(right), int(top), int(bottom)

def visualize_imgs_boxes(imgs, imgs_pred, boxes, boxes_pred):

    nrows = imgs.size(0)
    imgs = imgs.detach().cpu().numpy()
    imgs_pred = imgs_pred.detach().cpu().numpy()
    boxes = boxes.detach().cpu().numpy()
    boxes_pred = boxes_pred.detach().cpu().numpy()
    plt.figure()

    for i in range(0, nrows):
        # i = j//2
        ax1 = plt.subplot(2, nrows, i+1)
        img = np.transpose(imgs[i, :, :, :], (1, 2, 0)) / 255.
        plt.imshow(img)

        left, right, top, bottom = bbox_coordinates_with_margin(boxes[i, :], 0, imgs[i:i+1, :, :, :])
        bbox_gt = patches.Rectangle((left, top),
                                    width=right-left,
                                    height=bottom-top,
                                    linewidth=1, edgecolor='r', facecolor='none')
        # Add the patch to the Axes
        ax1.add_patch(bbox_gt)
        plt.axis('off')

        ax2 = plt.subplot(2, nrows, i+nrows+1)
        pred = np.transpose(imgs_pred[i, :, :, :], (1, 2, 0)) / 255.
        plt.imshow(pred)

        left, right, top, bottom = bbox_coordinates_with_margin(boxes_pred[i, :], 0, imgs[i:i+1, :, :, :])
        bbox_pr = patches.Rectangle((left, top),
                                    width=right-left,
                                    height=bottom-top,
                                    linewidth=1, edgecolor='r', facecolor='none')
        # ax2.add_patch(bbox_gt)
        ax2.add_patch(bbox_pr)
        plt.axis('off')

    plt.show()

    return

if __name__ == '__main__':
    main()


import logging
import time
import traceback
from pathlib import Path

from requests_tracker.request import WebRequestType
from requests_tracker.session import WebSessionFactory
from requests_tracker.storage import convert_HAR_to_markdown, write_HAR_to_local_file, CookiesFileStorage
from requests_tracker.util import LogHelper

if __name__ == '__main__':

    logger = LogHelper.configure(logging.DEBUG)

    session_cache_path = Path(__file__).parent.parent.joinpath('session_cache')

    cookies_storage = CookiesFileStorage(session_cache_path)

    # creates session and pre-loads cookies from persisted local cookie storage
    web_session = WebSessionFactory.create(
        cookies_storage,
        default_referer='https://www.jet2holidays.com',
        sensitive_values=[],
        sensitive_params=[],
        retry_count=1,
        timeout=10.00
    )

    try:
        response1 = web_session.get('https://www.jet2holidays.com')

        # print(response1.text)

        time.sleep(1)

        response2 = web_session.post(
            url='https://www.jet2holidays.com/api/jet2/sitesearch/HotelAndRegionList',
            request_type=WebRequestType.XHR,
            data={
                'term': 'radi',
                'maxResults': 30
            }
        )

        print(response2.text)

    except Exception as ex:
        logger.error(traceback.print_exc())
    finally:
        # persists cookies to local file
        cookies_storage.save(web_session.cookies)
        # writes to 'session-cache/session-DD-MM-YYYY HH-MM-SS.har' file
        write_HAR_to_local_file(session_cache_path, web_session.request_session_context)
        # converts HAR file to markdown file + response files in folder 'session-cache/session-DD-MM-YYYY HH-MM-SS/'
        convert_HAR_to_markdown(session_cache_path, web_session.request_session_context)


def convert(h):
    return {'A': 1, 'B': 2, 'C': 3}[h]

score = 0

for round in open('strategy.txt', 'r').read().split('\n'):
    foe, result = round.split(' ')
    foe = convert(foe)
    me = 0

    if (result == 'Y'):
        score += 3
        me = foe

    elif (result == 'Z'):
        score += 6
        if (foe == 1):
            me = 2
        elif (foe == 2):
            me = 3
        elif (foe == 3):
            me = 1

    else:
        if (foe == 1):
            me = 3
        elif (foe == 2):
            me = 1
        elif (foe == 3):
            me = 2

    score += me

print(score)


import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.collections import PolyCollection
#
# fs = 11240.
# t = 10
# time = np.arange(fs*t) / fs
# frequency = 1000.
# mysignal = np.sin(2.0 * np.pi * frequency * time)
#
# nperseg = 2**14
# noverlap = 2**13
# f, t, Sxx = signal.spectrogram(mysignal, fs, nperseg=nperseg,noverlap=noverlap)
#
# myfilter = (f>800) & (f<1200)
#
# f = f[myfilter]
# Sxx = Sxx[myfilter, ...]
#
# fig = plt.figure()
# ax = fig.gca(projection='3d')
#
# ax.plot_surface(f[:, None], t[None, :], 10.0*np.log10(Sxx), cmap=cm.coolwarm)
# plt.show()

import dtw
def colloc(titlename,numberfilter):
    va = pd.read_csv('Plot/' + titlename + '.csv')
    Type = va.Type

    IsSave = va.loc[(va['Type'] == numberfilter)]

    return IsSave
if __name__ == '__main__':
    nf = 11
    savename = 'PutPhone'

    namefile = 'Calling'
    Calling = colloc(namefile,nf)

    namefile = 'Pocket'
    Pocket = colloc(namefile, nf)

    namefile = 'Swinging'
    Swinging = colloc(namefile, nf)

    namefile = 'Texting'
    Texting = colloc(namefile, nf)

    aa = pd.concat([Calling,Pocket,Swinging,Texting], axis = 0)
    aa.to_csv('Plot/test1.csv', index=False)

    va = pd.read_csv('Plot/test1.csv')

    Pose = va.Pose
    posename = []
    for i in range(len(Pose)):
        if Pose[i] == 1:
            posename.append('Calling')
        elif Pose[i] == 2:
            posename.append('Pocket')
        elif Pose[i] == 3:
            posename.append('Swinging')
        elif Pose[i] == 4:
            posename.append('Texting')

    va['PoseName'] = posename
    idarr = []
    sums = 0
    for i in range(len(Pose)):
        idarr.append(sums)
        sums+=1

    va['Timestamp'] = idarr

    va.to_csv('Plot/' + savename + '.csv', index=False)

    print('Done')


import printing

file_name = "game_stat.txt"
gametitle = "Diablo II"

# Export functions
def exportdata(datas):
    with open("export.txt", "w") as data:
        for i in range(len(datas)):
            data.write(str(datas[i]) + "\n")

if __name__ == "__main__":
    gamedata = printing.print_datas(file_name, gametitle)
    exportdata(gamedata)


import copy
import logging
from collections import OrderedDict
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, NamedTuple, Union

import yaml

import cekit
from cekit.cekit_types import _T, RawDescriptor
from cekit.config import Config
from cekit.descriptor import (
    Arg,
    Descriptor,
    Env,
    Label,
    Modules,
    Osbs,
    Packages,
    Port,
    Run,
    Volume,
)
from cekit.descriptor.resource import Resource, create_resource
from cekit.errors import CekitError
from cekit.tools import get_latest_image_version

if TYPE_CHECKING:
    from cekit.descriptor.modules import Install
    from cekit.descriptor.overrides import Overrides
    from cekit.generator.base import ModuleRegistry

logger = logging.getLogger("cekit")
config = Config()

_image_schema = yaml.safe_load(
    """
map:
  name: {type: str, required: True}
  version: {type: text, required: True}
  schema_version: {type: int}
  release: {type: text}
  from: {type: str}
  follow_tag: {type: str}
  description: {type: text}
  args:  {type: any}
  labels: {type: any}
  envs:  {type: any}
  ports: {type: any}
  run: {type: any}
  artifacts: {type: any}
  modules: {type: any}
  packages: {type: any}
  osbs: {type: any}
  volumes: {type: any}
  help:
    map:
      add: {type: bool}
      template: {type: text}"""
)

class ImageOverrides(NamedTuple):
    artifacts: Dict[str, "Resource"]
    modules: Dict[str, "Install"]

def get_image_schema():
    return copy.deepcopy(_image_schema)

class Image(Descriptor):
    def __init__(self, descriptor: RawDescriptor, artifact_dir: str):
        self._artifact_dir: str = artifact_dir
        self.path: str = artifact_dir
        self.schema = _image_schema.copy()
        super(Image, self).__init__(descriptor)
        self.skip_merging = ["description", "version", "name", "release"]
        self._prepare()

    def _prepare(self):
        # TODO: Separating raw image descriptor from a higher level Image class would change this
        # confusing code into a connector/factory.
        self._descriptor["labels"] = [
            Label(x) for x in self._descriptor.get("labels", [])
        ]
        self._descriptor["envs"] = [Env(x) for x in self._descriptor.get("envs", [])]
        self._descriptor["ports"] = [Port(x) for x in self._descriptor.get("ports", [])]
        if "run" in self._descriptor:
            self._descriptor["run"] = Run(self._descriptor["run"])
        self._descriptor["artifacts"] = [
            create_resource(a, directory=self._artifact_dir)
            for a in self._descriptor.get("artifacts", [])
        ]
        self._descriptor["modules"] = Modules(
            self._descriptor.get("modules", {}), self.path
        )
        self._descriptor["packages"] = Packages(
            self._descriptor.get("packages", {}), self.path
        )
        self._descriptor["osbs"] = Osbs(self._descriptor.get("osbs", {}), self.path)
        self._descriptor["volumes"] = [
            Volume(x) for x in self._descriptor.get("volumes", [])
        ]

        # make sure image declarations override any module definitions
        # TODO: Make into a NamedTuple to make types easier to reason about.
        self._image_overrides = ImageOverrides(
            artifacts=Image._to_dict(self.artifacts),
            modules=Image._to_dict(self.modules.install),
        )
        self._all_artifacts: Dict[str, Resource] = Image._to_dict(self.artifacts)

    def process_defaults(self):
        """Prepares default values before rendering"""
        if not self.run:
            self.run = Run({})

        # do we want to force a user?
        if "user" not in self.run:
            self.run._descriptor["user"] = cekit.DEFAULT_USER

        # Default package manager is yum
        if not self.packages.manager:
            self.packages._descriptor["manager"] = "yum"

        # Default directory for supplementary files that should be copied to dist-git directory
        if not self.osbs.extra_dir:
            self.osbs._descriptor["extra_dir"] = "osbs_extra"

        # Placing this here rather than in init as apply_image_overrides runs after that. This means
        # follow_tag is applied *after* overrides.
        if self.follow:
            if not config.get("common", "redhat"):
                raise CekitError(
                    "follow_tag annotation only supported with redhat flag"
                )
            self.base = get_latest_image_version(self.follow)

    @property
    def name(self) -> str:
        return self.get("name")

    @name.setter
    def name(self, value: str):
        self._descriptor["name"] = value

    @property
    def version(self) -> Any:
        # TODO: Convert to string up front to simplify
        return self.get("version")

    @version.setter
    def version(self, value: Any):
        self._descriptor["version"] = value

    # TODO: release is undocumented.
    @property
    def release(self) -> str:
        return self.get("release")

    @release.setter
    def release(self, value: str):
        self._descriptor["release"] = value

    @property
    def base(self) -> str:
        return self.get("from")

    @base.setter
    def base(self, value: str):
        self._descriptor["from"] = value

    @property
    def follow(self) -> str:
        return self.get("follow_tag")

    @follow.setter
    def follow(self, value: str):
        self._descriptor["follow_tag"] = value

    @property
    def description(self) -> str:
        return self.get("description")

    @description.setter
    def description(self, value: str) -> None:
        self._descriptor["description"] = value

    @property
    def labels(self) -> List[Label]:
        return self.get("labels", [])

    @property
    def envs(self) -> List[Env]:
        return self.get("envs", [])

    @property
    def args(self) -> List[Arg]:
        return self.get("args", [])

    @property
    def ports(self) -> List[Port]:
        return self.get("ports", [])

    @property
    def run(self) -> Run:
        return self.get("run")

    @run.setter
    def run(self, value: Run):
        self._descriptor["run"] = value

    @property
    def all_artifacts(self) -> Iterable[Resource]:
        return self._all_artifacts.values()

    @property
    def artifacts(self) -> List[Resource]:
        return self.get("artifacts", [])

    @property
    def modules(self) -> Modules:
        return self.get("modules", Modules({}, self._artifact_dir))

    @property
    def packages(self) -> Packages:
        return self.get("packages", Packages({}, self.path))

    @property
    def osbs(self) -> Osbs:
        return self.get("osbs")

    @osbs.setter
    def osbs(self, value: Osbs):
        self._descriptor["osbs"] = value

    @property
    def volumes(self) -> List[Volume]:
        return self.get("volumes", [])

    @property
    def help(self) -> dict:
        return self.get("help", {})

    def apply_image_overrides(self, overrides: List["Overrides"]):
        """
        Applies overrides to the image descriptor.
        """
        if not overrides:
            return
        for override in overrides:
            if override.name:
                self.name = override.name
            if override.version:
                self.version = override.version
            if override.base:
                self.base = override.base
            if override.description:
                self.description = override.description

            labels = Image._to_dict(self.labels)
            for label in override.labels:
                name = label.name
                if name in labels:
                    labels[name] = label.merge(labels[name])
                else:
                    labels[name] = label
            self._descriptor["labels"] = list(labels.values())

            envs = Image._to_dict(self.envs)
            for env in override.envs:
                name = env.name
                if name in envs:
                    envs[name] = env.merge(envs[name])
                else:
                    envs[name] = env
            self._descriptor["envs"] = list(envs.values())

            ports = Image._to_dict(self.ports)
            for port in override.ports:
                name = port.value
                if name in ports:
                    ports[name] = port.merge(ports[name])
                else:
                    ports[name] = port
            self._descriptor["ports"] = list(ports.values())

            module_repositories = Image._to_dict(self.modules.repositories)
            for repository in override.modules.repositories:
                name = repository.name
                if name in module_repositories:
                    module_repositories[name] = repository.merge(
                        module_repositories[name]
                    )
                else:
                    module_repositories[name] = repository
            self.modules._descriptor["repositories"] = list(
                module_repositories.values()
            )

            self.packages._descriptor = override.packages.merge(self.packages)

            # In case content sets are provided as null values
            # Remove the key entirely.
            # TODO: This should be handled probably at general level, for every key
            for flag in ["content_sets", "content_sets_file"]:
                if flag in override.packages and override.packages[flag] is None:
                    self.packages._descriptor.pop("content_sets", None)
                    self.packages._descriptor.pop("content_sets_file", None)

            # Merge override osbs items into self.
            self.osbs = self.osbs.merge(override.osbs)

            # Using 'or []' to avoid having to set default value in packages.py for _descriptor["remove"]
            for package in override.packages.remove or []:
                if package not in self.packages.remove:
                    self.packages.remove.append(package)

            for package in override.packages.install or []:
                if package not in self.packages.install:
                    self.packages.install.append(package)

            for package in override.packages.reinstall or []:
                if package not in self.packages.reinstall:
                    self.packages.reinstall.append(package)

            artifact_overrides = self._image_overrides.artifacts
            image_artifacts = Image._to_dict(self.artifacts)
            for i, artifact in enumerate(override.artifacts):
                name = artifact.name
                # override.artifact contains override values WITH defaults.
                # override.original_descriptor contains override value WITHOUT defaults.
                # artifact_overrides contains original dictionary
                #
                # Iterating over dest / target / ...
                #   If we have _not_ supplied a target (check original_descriptor),
                #      then check artifact_overrides,
                #         otherwise use default from override.artifact
                override_without_defaults = override.original_descriptor.get(
                    "artifacts"
                )[i]
                for key in ["dest", "target", "description"]:
                    if override_without_defaults.get(key):
                        logger.debug(
                            "Key ({}) found in override as {}".format(
                                key, override_without_defaults.get(key)
                            )
                        )
                        artifact[key] = override_without_defaults.get(key)
                    elif artifact_overrides.get(name) and artifact_overrides.get(
                        name
                    ).get(key):
                        new_value = artifact_overrides.get(name).get(key)
                        logger.debug(
                            "Key ({}) found in original artifact as {}".format(
                                key, new_value
                            )
                        )
                        artifact[key] = new_value

                # collect override so we can apply it to modules
                artifact_overrides[name] = artifact
                # add it to the list of everything
                self._all_artifacts[name] = artifact
                # Apply override to image descriptor
                image_artifacts[name] = artifact
                # Sort the output as it makes it easier to view and test.
                logger.debug(
                    "Final (with override) artifact is {}".format(
                        sorted(artifact.items())
                    )
                )
            self._descriptor["artifacts"] = list(image_artifacts.values())

            module_overrides = self._image_overrides.modules
            image_modules = Image._to_dict(self.modules.install)
            for module in override.modules.install:
                name = module.name
                # collect override so we can apply it to modules.
                # this allows us to override module versions without affecting ordering.
                module_overrides[name] = module
                # Apply override to image descriptor
                # If the module does not exists in the original descriptor, add it there
                image_modules[name] = module
            self.modules._descriptor["install"] = list(image_modules.values())

            if override.run is not None:
                if self.run:
                    self.run = override.run.merge(self.run)
                else:
                    self.run = override.run

    def apply_module_overrides(self, module_registry: "ModuleRegistry"):
        """
        Applies overrides to included modules.  This includes:
            Artifact definitions
            Module dependency version overrides
        Also incorporates module contributed global configuration into the image:
            Run specification
            Package repository definitions
            Required artifacts
        """
        install_list: Dict[str, "Install"] = OrderedDict()

        # index by name for easier access
        self._package_repositories = Image._to_dict(self.packages.repositories)

        # collect final 'run' value from modules
        self._module_run = Run({})

        # process the modules and integrate relevant bits into ourself
        self.process_install_list(
            self, self.modules.install, install_list, module_registry
        )

        # update ourself based on module declarations
        # final order of modules to be installed
        self.modules._descriptor["install"] = list(install_list.values())
        # all package repositories required for installing packages
        self.packages._descriptor["repositories"] = list(
            self._package_repositories.values()
        )

        # final 'run' value
        if self.run:
            self.run = self.run.merge(self._module_run)
        else:
            self.run = self._module_run

    def process_install_list(
        self,
        source: Union["Image"],
        to_install_list: List["Install"],
        install_list: Dict[str, "Install"],
        module_registry: "ModuleRegistry",
    ) -> None:
        # TODO: Return value is passed as parameter in `install_list`
        module_overrides = self._image_overrides.modules
        artifact_overrides = self._image_overrides.artifacts
        for to_install in to_install_list:
            logger.debug(
                "Preparing module '{}' required by '{}'.".format(
                    to_install.name, source.name
                )
            )
            override = module_overrides.get(to_install.name, None)
            if override:
                if override.version != to_install.version:
                    logger.debug(
                        "Module '{}:{}' being overridden with '{}:{}'.".format(
                            to_install.name,
                            to_install.version,
                            override.name,
                            override.version,
                        )
                    )
                # apply module override
                to_install = override

            existing = install_list.get(to_install.name, None)
            # see if we've already processed this
            if existing:
                # check for a version conflict
                if existing.version != to_install.version:
                    logger.warning(
                        "Module version inconsistency for {}: {} requested, but {} will be used.".format(
                            to_install.name, to_install.version, existing.version
                        )
                    )
                continue

            module = module_registry.get_module(to_install.name, to_install.version)
            if not module:
                raise CekitError(
                    "Could not locate module %s version %s. Please verify that it is included in one of the "
                    "specified module repositories."
                    % (to_install.name, to_install.version)
                )

            # collect artifacts and apply overrides
            module_artifacts = Image._to_dict(module.artifacts)
            for artifact in module.artifacts:
                name = artifact.name
                if name in artifact_overrides:
                    override = artifact_overrides[name]
                    self._all_artifacts[name] = override
                    module_artifacts[name] = override
                else:
                    self._all_artifacts[name] = artifact
            module._descriptor["artifacts"] = list(module_artifacts.values())

            # collect package repositories
            for repo in module.packages.repositories:
                name = repo.name
                if name not in self._package_repositories:
                    self._package_repositories[name] = repo

            # collect package manager
            if not self.packages.manager and module.packages.manager:
                logger.debug(
                    f"Applying module package manager of {module.packages.manager} to image"
                )
                self.packages._descriptor["manager"] = module.packages.manager

            # incorporate run specification contributed by module
            if module.run:
                # we're looping in order of install, so we want the current module to override whatever we have
                self._module_run = module.run.merge(self._module_run)

            # prevent circular dependencies. we'll move it to the end after processing
            install_list[to_install.name] = to_install

            # process this modules dependencies
            self.process_install_list(
                module, module.modules.install, install_list, module_registry
            )

            # move this module to the end of the list.
            install_list.pop(to_install.name)
            install_list[to_install.name] = to_install

    # helper to simplify merging lists of objects
    @classmethod
    def _to_dict(cls, named_items: Iterable[_T], key="name") -> Dict[str, _T]:
        # TODO: `key` argument is never used?
        # TODO: This assumes that `name` is always a string, but in fact it isn't for Port
        dictionary = OrderedDict()
        for item in named_items:
            dictionary[item[key]] = item
        return dictionary


# pylint: disable=invalid-name, unused-argument, unspecified-encoding, missing-function-docstring
"""
Implements all winreg functions

https://docs.python.org/3/library/winreg.html#functions
"""
import os
from typing import Union
from re import findall
from tempfile import TemporaryDirectory
from warnings import warn
from typing import Optional, List

from unixreg.key import RegKey
from unixreg.constants import STANDARD_RIGHTS_REQUIRED, KEY_WOW64_64KEY, KEY_WRITE, KEY_READ

KEY_TYPE = Union[str, RegKey]
SUBKEY_TYPE = Union[str, RegKey, None]

_KEY_CACHE: List[RegKey] = []
_ENV_REPLACE = {
    "USERPROFILE": "HOME"
}

_CONFIG_DIR = os.getenv("XDG_CONFIG_HOME")
if not _CONFIG_DIR:
    home = os.getenv("HOME")
    if home:
        _CONFIG_DIR = os.path.join(home, ".config")
    else:
        _CONFIG_DIR = TemporaryDirectory().name
        if not os.getenv("TOX"):
            warn(f"Could not find directory to put registry in. Falling back to {_CONFIG_DIR}")
_CONFIG_DIR = os.path.join(_CONFIG_DIR, "unixreg")

def __init_values(key: KEY_TYPE, sub_key: SUBKEY_TYPE = None, access = STANDARD_RIGHTS_REQUIRED):
    if isinstance(key, str):
        key = RegKey(key)

    if sub_key is not None:
        print(sub_key)
        key = key + sub_key
    key.access = access

    return key

def __create_key(key: RegKey):
    if _CONFIG_DIR and key and key.key:
        path = os.path.join(_CONFIG_DIR, key.key)

        os.makedirs(path, exist_ok=True)

def CloseKey(key: RegKey):
    """
    Closes a previously opened registry key.
    The key argument specifies a previously opened key.
    """
    key.Close()

    try:
        _KEY_CACHE.remove(key)
    except ValueError:
        pass

def ConnectRegistry(computer: Union[str, None], key: RegKey):
    """
    Opens a registry handle on another computer and returns the handle

    If computer_name is None, the local computer is used, otherwise
    OSError is raised to signify the function failing
    """
    if not computer:
        return OpenKey(key, None)
    raise OSError("Not Implemented")

def OpenKeyEx(key: RegKey, sub_key: SUBKEY_TYPE, reserved=0, access=KEY_READ):
    return CreateKeyEx(key, sub_key, reserved, access)

OpenKey = OpenKeyEx

def CreateKey(key: RegKey, sub_key: SUBKEY_TYPE):
    return CreateKeyEx(key, sub_key)

def CreateKeyEx(key: RegKey, sub_key: SUBKEY_TYPE, reserved=0, access=KEY_WRITE):
    key = __init_values(key, sub_key, access)

    __create_key(key)

    _KEY_CACHE.append(key)

    return key

def DeleteKey(key: KEY_TYPE, sub_key: SUBKEY_TYPE):
    return DeleteKeyEx(key, sub_key)

def DeleteKeyEx(key: KEY_TYPE, sub_key: SUBKEY_TYPE, access=KEY_WOW64_64KEY, reserved=0):
    kkey = __init_values(key, sub_key, access)

    if _CONFIG_DIR:
        path = os.path.join(_CONFIG_DIR, kkey.key)
        if os.path.isfile(path):
            os.remove(path)

def DeleteValue(key: KEY_TYPE, value: str):
    kkey = __init_values(key)

    if _CONFIG_DIR:
        filepath = os.path.join(_CONFIG_DIR, kkey.key, value)
        try:
            os.remove(filepath)
        except FileNotFoundError:
            pass

def EnumKey(key: KEY_TYPE, index: int):
    raise NotImplementedError("Not Implemented")

def EnumValue(key: KEY_TYPE, index: int):
    raise NotImplementedError("Not Implemented")

def ExpandEnvironmentStrings(env: str):
    for key, val in _ENV_REPLACE.items():
        env = env.replace(f"%{key}%", f"%{val}%")

    match = findall(r"%(.+?)%", env)

    for val in match:
        valenv = os.getenv(val)
        if valenv:
            env = env.replace(f"%{val}%", valenv)

    env.replace("\\", os.path.sep)
    return env

def FlushKey(key: KEY_TYPE):
    raise NotImplementedError("Not Implemented")

def QueryInfoKey(key: KEY_TYPE):
    raise NotImplementedError("Not Implemented")

def QueryValueEx(key: KEY_TYPE, sub_key: SUBKEY_TYPE) -> str:
    kkey = __init_values(key, sub_key)

    if _CONFIG_DIR:
        filepath = os.path.join(_CONFIG_DIR, kkey.key)
        with open(filepath, "r") as file:
            return file.read()

    return ""

QueryValue = QueryValueEx

def LoadKey(key: RegKey, sub_key: SUBKEY_TYPE, file_name: str):
    # this requires a win32 permission compatibility layer
    raise OSError("Not Implemented")

def SaveKey(key: RegKey, file_name: str) -> None:
    # this requires a win32 permission compatibility layer
    raise OSError("Not Implemented")

def SetValue(key: KEY_TYPE, sub_key: SUBKEY_TYPE, typearg: int, value: str) -> None:
    if isinstance(sub_key, RegKey):
        sub_key = sub_key.key

    if sub_key:
        return SetValueEx(key, sub_key, 0, typearg, value)

def SetValueEx(key: KEY_TYPE, value_name: str, reserved: int, typearg: int, value: str) -> None:
    kkey = __init_values(key)

    if _CONFIG_DIR:
        filepath = os.path.join(_CONFIG_DIR, kkey.key, value_name)
        with open(filepath, "w") as file:
            file.write(value)

def DisableReflectionKey(key: KEY_TYPE):
    raise NotImplementedError("Not Implemented")

def EnableReflectionKey(key: KEY_TYPE):
    raise NotImplementedError("Not Implemented")

def QueryReflectionKey(key: KEY_TYPE):
    raise NotImplementedError("Not Implemented")

# Non winreg functions
def LoadRegFile(file_name: str) -> Optional[str]:

    def _strip_quotes(val) -> str:
        _QUOTE_LIST = ("\"", '\'')
        if val.startswith(_QUOTE_LIST) and val.endswith(_QUOTE_LIST):
            val = val[1:-1]
        return val

    def _strip_brackets(val) -> str:
        _BRACKET_LIST = ("[", "]")
        if val.startswith(_BRACKET_LIST) and val.endswith(_BRACKET_LIST):
            val = val[1:-1]
        return val

    with open(file_name, "r") as reg:
        nextline = reg.readline()

        key: Optional[str] = None

        while nextline:
            line = nextline.strip()
            nextline = reg.readline()

            if len(line) == 1:
                continue

            split = line.split("=")

            keyline = _strip_brackets(line)
            if keyline:
                key = keyline
            elif key and len(split) == 2:
                name, value = split
                name = _strip_quotes(name)
                value = _strip_quotes(value)

                os.makedirs(key, exist_ok=True)

                if _CONFIG_DIR:
                    with open(os.path.join(_CONFIG_DIR, key, name), "w") as regvalue:
                        regvalue.write(value)

                print(f"[{key}] {name}={value}")

    return None


#!/usr/bin/env python3

"""
The main program that will be run on the Raspberry Pi,
which is the controller for the pharmacy client.
DINs of drugs on this pharmacy should be specified in din.cfg
"""

# these libraries come with python
import logging
import datetime
import struct
import asyncio
import json
import base64

# please run setup.sh first to install these libraries
import numpy as np
import cv2
import face_recognition
import aiohttp

# constant: endpoint for the web API
api_endpoint = 'https://example.com/arka'
# constant: current api version
api_version = '0'

# local drug database
din_to_motor = {}

async def dispense(din):
    """
    Try to dispense a drug.
    Returns true if it succeeded.
    """
    motor = din_to_motor[din]

    return False

async def report_dispensed(auth_token, drugs_dispensed):
    """
    Reports back to the server that drugs were dispensed... later
    """
    # get the timestamp NOW
    ts = datetime.datetime.utcnow().timestamp()

    # wait until dispensing should be done
    await asyncio.sleep(30)

    # if nothing was dispensed, easy
    if not drugs_dispensed:
        logging.log(logging.INFO, 'No drug dispensing to report')
        return True

    logging.log(logging.DEBUG, 'Now trying to report drug dispensed')

    # start a HTTP session
    async with aiohttp.ClientSession() as session:
        logging.log(logging.DEBUG, 'HTTP session started from report_dispensed')

        # build the json object to send
        data_send = {
            'version': api_version,
            'id': auth_token,
            'din': drugs_dispensed,
            'timestamp': ts
            }
        # response is assumed none until we get something
        data_response = None

        # it's not done until we've confirmed it's done
        while data_response is None:

            # connect to the api!
            async with session.get(
                api_endpoint + '/user/pharmacy_done',
                json = data_send
                ) as response:

                # get data as json
                data_response = response.json()

                if data_response['version'] != api_version:
                    raise AssertionError('Incorrect API version encountered in report_dispensed')
                elif not data_response['success']:
                    logging.log(logging.INFO, 'API endpoint said drug dispense report failed for whatever reason')
                    data_response = None

            await asyncio.sleep(30)

        logging.log(logging.INFO, 'Drug delivery report completed and confirmed')

def pack_fingerprint(fingerprint):
    """
    Takes the vector which is a face fingerprint and
    creates a bytes object to represent it.
    Some information will be lost.
    """

    # test our assumptions

    if np.any(fingerprint >  1):raise ValueError('Fingerprint contains value greater than 1')
    if np.any(fingerprint < -1):raise ValueError('Fingerprint contains value less than -1')

    # convert from 64-bit float in range [-1, 1] to 16-bit int in full range

    # 1 - 2^-53 is the largest double value below 1
    # by scaling by this much, we prevent the edge case of boundary number 1 which can overflow to -2^15 after scaling
    scale = 1 - 2 ** -53

    if scale >= 1:raise AssertionError('Fingerprint packing uses incorrect scaling factor')

    # scale to get the 16-bit int range
    scale *= 2 ** 15

    # convert to the 16-bit int vector
    values = np.array(np.floor(fingerprint * scale), dtype=np.int16)

    # pack in bytes
    # 128 values, 16-bit integer, little endian -> 256 bytes
    result = struct.pack('<128h', *values)

    return result

async def main_step(capture):
    """
    Contains the code for the main loop.
    A return here will act as a continue in the loop.
    """
    # wait for either user to press the button or a certain number of seconds to pass

    await asyncio.sleep(1)

    logging.log(logging.DEBUG, 'Now trying to capture an image')

    # capture an image
    succeeded, pixels = capture.read()

    logging.log(logging.DEBUG, 'Image capture completed, and it ' + ('succeeded' if succeeded else 'failed'))

    # this line explains itself well
    if not succeeded:return

    # OpenCV uses BGR as its output format but we want RGB
    pixels = cv2.cvtColor(pixels, cv2.COLOR_BGR2RGB)

    logging.log(logging.DEBUG, 'Image colour channels changed to RGB')

    # find face locations in the image
    face_boxes = face_recognition.face_locations(pixels, model='hog')
    num_faces = len(face_boxes)

    logging.log(logging.DEBUG, 'Found ' + str(num_faces) + 'faces in the image')

    # no faces means nothing to do
    if num_faces == 0:return

    # TODO filter faces so only 1 is left, or else give up

    # generate the 128-vector as face fingerprint
    fingerprints = face_recognition.face_encodings(pixels, face_boxes)
    fingerprint = fingerprints[0]

    logging.log(logging.DEBUG, 'Face fingerprint was generated')

    # pack the fingerprint as bytes
    packed_fingerprint = pack_fingerprint(fingerprint)

    logging.log(logging.INFO, 'Packed face fingerprint as ' + packed_fingerprint.hex())

    # start a HTTP session
    async with aiohttp.ClientSession() as session:
        logging.log(logging.DEBUG, 'HTTP session started from main_step')

        # build the json object to send
        data_send = {
            'version': api_version,
            'fingerprint': base64.b64encode(packed_fingerprint)
            }
        # response is assumed none until we get something
        data_response = None

        # connect to the api!
        async with session.get(
            api_endpoint + '/user/pharmacy_get',
            json = data_send
            ) as response:

            logging.log(logging.DEBUG, 'Sent face fingerprint to authenticate')

            # get the response as json
            data_response = await response.json()

            logging.log(logging.DEBUG, 'Decoded response data as JSON')
        # continue if it succeeded
        if data_response is not None and data.get('success', None) and data['version'] == api_version:
            logging.log(logging.DEBUG, 'Authenticated and prescription data acquired')

            # the authentication token for this session
            auth_token = data['id']
            # make a list of drugs that were dispensed
            drugs_dispensed = []

            await asyncio.create_task(report_dispensed(auth_token, drugs_dispensed))

            # loop over all valid prescriptions
            for pres in data['prescriptions']:
                # get the DIN of the drug
                din = pres['din']

                # is this drug in this pharmacy?
                if din in din_to_motor:
                    logging.log(logging.INFO, 'Attempting to dispense drug with DIN ' + din)

                    # try to dispense it
                    drug_was_dispensed = await dispense(din)

                    if drug_was_dispensed:
                        logging.log(logging.INFO, 'Drug dispense reported success')

                        drugs_dispensed.append(din)
                    else:
                        logging.log(logging.INFO, 'Drug dispense reported failure')

async def main_async():
    """
    Actual main function to be used in production.
    """
    # log timing information
    logging.log(logging.INFO, 'Starting main function | Current UTC time is ' + str(datetime.datetime.utcnow()))

    # set up the video capture object
    capture = cv2.VideoCapture(0)

    # the main loop
    while True:
        # log some timing information
        logging.log(logging.DEBUG, 'Starting the main loop | Current UTC time is ' + str(datetime.datetime.utcnow()))
        # try block to prevent errors from breaking the program
        try:
            # special function represents the code of the main loop
            await main_step(capture)
        except KeyboardInterrupt:
            # the user intends to stop the program, so we respect this
            logging.log(logging.INFO, 'Exiting main loop because a keyboard interrupt (SIGINT) was received')
            raise KeyboardInterrupt
        except Exception as exc:
            # any other error must not break the program
            logging.log(logging.ERROR, exc)

    # get rid of the video capture object
    capture.release()

    # say bye bye
    logging.log(logging.WARNING, 'Exiting main function, program is ending | Current UTC time is ' + str(datetime.datetime.utcnow()))

def main():
    """
    Entry point to the program.
    Will first read in the local database from the config file.
    Redirects to main_async.
    """
    global din_to_motor

    with open('din.cfg','r') as file:
        for line in file:
                din, motor = line.strip().split()
                din_to_motor[din] = motor

    asyncio.run(main_async())

def main_test():
    """
    Previous main function left over from testing. Will be removed when it is no longer useful.
    """

    print('start of program')

    cap = cv2.VideoCapture(0)

    print('camera initialized')

    for _ in range(1):
        print('start of main loop')

        # try to capture an image
        # image is a 3d array: (Y, X, bgr)
        ret, frame = cap.read()

        print('image captured')

        # reorder to RGB
        # not necessary to do it this way but it works
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        print('image converted to rgb')

        # we must first detect and locate faces within the image
        # this is separate from the face fingerprinting
        face_boxes = face_recognition.face_locations(frame,
            model='hog')

        print('faces detected in image')

        # face_recognition library includes a premade AI
        # this will spit out a 1d array with 128 floating point entries
        # they seem to be within [-1, 1] and average at 0
        # this fingerprint is a summary of the features of the faces
        # we will later transform this vector and then send that to the server for processing
        fingerprints = face_recognition.face_encodings(frame, face_boxes)

        print('face fingerprints generated')

        print(f'created {len(fingerprints)} fingerprints')

        for index, fingerprint in enumerate(fingerprints):
            print('-'*40)
            print(f'data of fingerprint #{index}')
            print(f'is a vector with shape {fingerprint.shape} and type {fingerprint.dtype}')
            print(f'min is {np.min(fingerprint)}')
            print(f'max is {np.max(fingerprint)}')
            print(f'mean is {np.mean(fingerprint)}')
            print('raw data')
            print(fingerprint)

    print('main loop exited')

    print('cleaning up')

    cap.release()
    cv2.destroyAllWindows()

    print('bye bye!')

# standard way to invoke main but only if this script is run as the program and not a library
if __name__ == '__main__':
    main_test()


import sys
import os
import pefile

# Imprime as seções de um executável
def print_sections(directory, executable):
    pe = pefile.PE(executable if directory is None else directory + "/" + executable)
    sections = []

    for section in pe.sections:
        sections.append(section.Name.decode('utf-8'))

    print(executable + ": [", end="")
    for i, section in enumerate(sections):
        print("'{}'".format(section), end="")
        if i < len(sections) - 1:
            print(', ', end="")
    print("]")

# Checa se o argumento de entrada é um arquivo ou uma pasta
if os.path.isdir(sys.argv[1]):
    for filename in os.listdir(sys.argv[1]):
        if filename.endswith(".exe"):
            print_sections(sys.argv[1], filename)
else:
    print_sections(None, sys.argv[1])


import json
import snappy

from structlog import get_logger
from jwcrypto.common import base64url_decode

from app.data_model.app_models import QuestionnaireState
from app.storage import data_access
from app.storage.storage_encryption import StorageEncryption

logger = get_logger()

class EncryptedQuestionnaireStorage:

    def __init__(self, user_id, user_ik, pepper, stateless_updates_enabled=False):
        if user_id is None:
            raise ValueError('User id must be set')

        self._user_id = user_id
        self.encrypter = StorageEncryption(user_id, user_ik, pepper)
        self.stateless_updates_enabled = stateless_updates_enabled

    def add_or_update(self, data, version):
        compressed_data = snappy.compress(data)
        encrypted_data = self.encrypter.encrypt_data(compressed_data)

        if self.stateless_updates_enabled:
            logger.debug('saving questionnaire data', user_id=self._user_id)
            questionnaire_state = QuestionnaireState(self._user_id, encrypted_data, version)
        else:
            questionnaire_state = self._find_questionnaire_state()

            if questionnaire_state:
                logger.debug('updating questionnaire data', user_id=self._user_id)
                questionnaire_state.state_data = encrypted_data
                questionnaire_state.version = version
            else:
                logger.debug('creating questionnaire data', user_id=self._user_id)
                questionnaire_state = QuestionnaireState(self._user_id, encrypted_data, version)

        data_access.put(questionnaire_state)

    def get_user_data(self):
        questionnaire_state = self._find_questionnaire_state()
        if questionnaire_state:
            version = questionnaire_state.version or 0

            try:
                # legacy data was stored in a dict, base64-encoded, and not compressed
                data = json.loads(questionnaire_state.state_data)['data']
                is_legacy_data = True
            except ValueError:
                data = questionnaire_state.state_data
                is_legacy_data = False

            decrypted_data = self.encrypter.decrypt_data(data)

            if is_legacy_data:
                decrypted_data = base64url_decode(decrypted_data.decode()).decode()
            else:
                decrypted_data = snappy.uncompress(decrypted_data).decode()

            return decrypted_data, version

        return None, None

    def delete(self):
        logger.debug('deleting users data', user_id=self._user_id)
        questionnaire_state = self._find_questionnaire_state()
        if questionnaire_state:
            data_access.delete(questionnaire_state)

    def _find_questionnaire_state(self):
        logger.debug('getting questionnaire data', user_id=self._user_id)
        return data_access.get_by_key(QuestionnaireState, self._user_id)


def isGlodonNumber(num):
    hset = set()
    t = 0
    while t == len(hset):
        num = sum(map(lambda x: int(x)**2, list(str(num))))
        if num == 1:
            return True
        t+=1
        hset.add(num)
    return False

        # if 1 < num < 4:
            # return False
    # return True
    # map(lambda x: x^2, intlist)
print(isGlodonNumber(32))


import bpy
import bmesh
import sys
import time
import argparse

# blender -b -P Resize.py -- --height 0.8  --inm Objects/Bed.obj --outm oBed2.obj

def get_args():
  parser = argparse.ArgumentParser()

  # get all script args
  _, all_arguments = parser.parse_known_args()
  double_dash_index = all_arguments.index('--')
  script_args = all_arguments[double_dash_index + 1: ]

  # add parser rules
 # add parser rules
  parser.add_argument('-hei', '--height', help="Final Height Dimension")
  parser.add_argument('-in', '--inm', help="Original Model")
  parser.add_argument('-out', '--outm', help="Rescaled output file")
  parsed_script_args, _ = parser.parse_known_args(script_args)
  return parsed_script_args

args = get_args()

height = float(args.height)
print(height)

input_model = str(args.inm)
print(input_model)

output_model = str(args.outm)
print(output_model)

print('\n Clearing blender scene (default garbage...)')
# deselect all
bpy.ops.object.select_all(action='DESELECT')

print('\n Beginning the process of import & export using Blender Python API ...')
bpy.ops.import_scene.obj(filepath=input_model)
print('\n Obj file imported successfully ...')

### just imported obj

print('\n Starting Resize...')
print('\n Z Dimension of the object is')

for o in bpy.data.objects:
    if o.type == 'MESH':
        z=o.dimensions.z

#x= bpy.data.objects[0].dimensions.x
#y=bpy.data.objects[0].dimensions.y
#z=bpy.data.objects[0].dimensions.z

# Resize the object

newscale=1
print(z)

if z != 0 :
  newscale= height/z

bpy.ops.transform.resize(value=(newscale,newscale,newscale))

print('\n new scale is',newscale ,'\n')

#bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')

bpy.ops.export_scene.obj(filepath=output_model)

print('\n Ending Resize...')


"""
gradient descent 연습
"""
import matplotlib.pyplot as plt
from scratch08.ex01 import difference_quotient, tangent, move

def g(x):
    """y = (1/3)x**3 - x"""
    return x ** 3 / 3 - x

if __name__ == '__main__':
    # ex01에서 작성한 함수를 이용, 함수 g(x)의 그래프를 그림
    # 극값(local 최소/최대)를 경사 하강법으로 찾음
    xs = [x / 10 for x in range(-30, 31)]
    ys = [g(x) for x in xs]

    plt.plot(xs, ys)
    plt.axhline(y=0, color='0.3')
    plt.axvline(x=0, color='0.3')
    plt.axvline(x=-1, color='0.75')
    plt.axvline(x=1, color='0.75')
    plt.ylim(bottom=-2, top=2)

    x_init = 1.9
    tolerance = 0.00001
    count = 0
    while True:
        count += 1
        gradient = difference_quotient(g, x_init, 0.0001)
        x_next = move(x_init, gradient, -0.1)
        print(f'{count} x: {x_next}')
        # ys_next = [tangent(x, gradient, x_next, g(x_next)) for x in xs]
        # plt.plot(xs, ys_next)
        if abs(x_init - x_next) < tolerance:
            break
        else:
            x_init = x_next

    x_init = -1.9
    count = 0
    while True:
        count += 1
        gradient = difference_quotient(g, x_init, 0.0001)
        x_next = move(x_init, gradient, 0.1)
        print(f'{count} x: {x_next}')
        # ys_next = [tangent(x, gradient, x_next, g(x_next)) for x in xs]
        # plt.plot(xs, ys_next)
        if abs(x_init - x_next) < tolerance:
            break
        else:
            x_init = x_next

    plt.show()