import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.nn.parallel
from torch.nn.utils import clip_grad_norm_
import torch.optim
from torch.utils.data import DataLoader
import numpy as np
import datetime
import time
import os
import math

from ops.models import TSN
from ops.dataset import TSNDataSet
from ops.transforms import *
from ops.utils import *
import cl_methods.cl_utils as cl_utils
import cl_methods.distillation as cl_dist
import cl_methods.classifer as classifier
from cl_methods import tcd
import copy

def _train(args, train_loader, model, criterion, optimizer, epoch, age, lambda_0=[0.5,0.5], model_old=None, importance_list=None):
    batch_time = AverageMeter()
    data_time = AverageMeter()
    losses = AverageMeter()

    losses_ce = AverageMeter()
    losses_kd_logit = AverageMeter()
    losses_att = AverageMeter()
    losses_div = AverageMeter()

    top1 = AverageMeter()

    loss = torch.tensor(0.).cuda()
    loss_kd_logit = torch.tensor(0.).cuda()
    loss_att = torch.tensor(0.).cuda()
    loss_div = torch.tensor(0.).cuda()

    if args.no_partialbn:
        model.module.partialBN(False)
    else:
        model.module.partialBN(True)

    # switch to train mode
    model.train()

    if model_old:
        model_old.eval()

    end = time.time()
    for i, (input, target, _) in enumerate(train_loader):
        # measure data loading time
        data_time.update(time.time() - end)

        input = input.cuda()
        target = target.cuda()

        # compute output
        outputs = model(input=input,t_div=args.t_div)
        preds = outputs['preds']
        feat = outputs['feat']
        int_features = outputs['int_features']

        if args.loss_type == 'bce':
            target_ = cl_utils.convert_to_one_hot(target, preds.size(1))
        else:
            target_ = target

        if age > 0:
            if args.cl_type == 'DIST':
                with torch.no_grad():
                    outputs_old = model_old(input=input)
                    preds_old = outputs_old['preds']
                    feat_old = outputs_old['feat']
                    int_features_old = outputs_old['int_features']

                old_size = preds_old.size(1)
                preds_base = torch.sigmoid(preds_old)

                if args.fc == 'lsc':
                    loss_ce = cl_dist.nca_loss(preds, target_)
                else:
                    loss_ce = criterion(preds, target_)

                loss_kd_logit = cl_dist.lf_dist_tcd(feat,feat_old,factor=importance_list[-1] if importance_list else None)
                loss_att = cl_dist.feat_dist(int_features,int_features_old,args,factor=importance_list[:-1] if importance_list else None)
                loss = lambda_0[0] * loss_ce + lambda_0[1] * loss_kd_logit + args.lambda_1 * loss_att

                #del preds_old, feat_old, int_features_old
                #del feat, int_features
            else:
                loss_ce = criterion(preds, target_)
                loss = loss_ce
        else:
            if args.fc == 'lsc':
                loss_ce = cl_dist.nca_loss(preds, target_)
            else:
                loss_ce = criterion(preds, target_)
            loss = loss_ce

        if args.t_div:
            loss_div = outputs['t_div'].sum()/input.size(0)
            loss = loss + args.lambda_2 * loss_div

        # compute gradient and do SGD step
        optimizer.zero_grad()
        loss.backward()

        if args.clip_gradient is not None:
            total_norm = clip_grad_norm_(model.parameters(), args.clip_gradient)

        optimizer.step()

        # measure accuracy and record loss
        prec1 = accuracy(preds.data, target, topk=(1,))
        losses.update(loss.item(), input.size(0))
        losses_ce.update(loss_ce.item(), input.size(0))
        losses_kd_logit.update(loss_kd_logit.item(),input.size(0))
        losses_att.update(loss_att.item(), input.size(0))
        losses_div.update(loss_div.item(),input.size(0))
        top1.update(prec1[0].item(), input.size(0))

        #del preds

        # measure elapsed time
        batch_time.update(time.time() - end)
        end = time.time()

        #printGPUInfo()

        if i % args.print_freq == 0:
            print(datetime.datetime.now())
            output = ('Epoch: [{0}][{1}/{2}], lr: {lr:.5f}\t'
                      'Time {batch_time.val:.3f} ({batch_time.avg:.3f})\t'
                      'Data {data_time.val:.3f} ({data_time.avg:.3f})\t'
                      'Loss {loss.val:.4f} ({loss.avg:.4f})\t'
                      'Loss CE {loss_ce.val:.4f} ({loss_ce.avg:.4f})\t'
                      'Loss KD (Logit) {loss_kd_logit.val:.4f} ({loss_kd_logit.avg:.4f})\t'
                      'Loss KD (Feature) {loss_att.val:.4f} ({loss_att.avg:.4f})\t'
                      'Loss DIV {loss_div.val:.4f} ({loss_div.avg:.4f})\t'
                      'Prec@1 {top1.val:.3f} ({top1.avg:.3f})'.format(
                epoch, i, len(train_loader), batch_time=batch_time,
                data_time=data_time, loss=losses, loss_ce=losses_ce, loss_kd_logit=losses_kd_logit,
                loss_att=losses_att, loss_div=losses_div,
                top1=top1, lr=optimizer.param_groups[-1]['lr'] * 0.1))
            print(output)
        #torch.cuda.empty_cache()

def _validate(args, val_loader, model, criterion, age):
    batch_time = AverageMeter()
    top1 = AverageMeter()

    # switch to evaluate mode
    model.eval()

    end = time.time()
    with torch.no_grad():
        for i, (input, target, _) in enumerate(val_loader):
            input = input.cuda()
            target = target.cuda()

            # compute output
            outputs = model(input=input)
            output = outputs['preds']

            target_one_hot = cl_utils.convert_to_one_hot(target, output.size(1))

            # measure accuracy and record loss
            prec1 = accuracy(output.data, target, topk=(1,))

            top1.update(prec1[0].item(), input.size(0))

            # measure elapsed time
            batch_time.update(time.time() - end)
            end = time.time()

            if i % args.print_freq == 0:
                output = ('Test: [{0}/{1}]\t'
                          'Time {batch_time.val:.3f} ({batch_time.avg:.3f})\t'
                          'Prec@1 {top1.val:.3f} ({top1.avg:.3f})'.format(
                    i, len(val_loader), batch_time=batch_time,
                    top1=top1))

    output = ('Testing Results: Prec@1 {top1.avg:.3f} '
              .format(top1=top1))
    print(output)

    return top1.avg

def train_task(args, age, current_task, current_head, class_indexer, model_old=None, prefix=None):
    if age == 1 and args.dataset=='hmdb51' and args.fc=='cc':
        args.lr = args.lr * 0.1
    hook = False
    if age > 0 and args.cl_type=='DIST':
        hook = True
    if age > 0 and args.exemplar:
        exemplar_dict = load_exemplars(args)
        exemplar_list = exemplar_dict[age-1]
        exemplar_per_class = len(exemplar_list[0])

    else:
        exemplar_dict = {}
        exemplar_list = None
        exemplar_per_class = 0

    if age > 0 and args.use_importance:
        importance_dict = load_importance(args)
        importance_temp = importance_dict[age-1]
        importance_list = []
        for i in importance_temp:
            importance_list.append(i)
    else:
        importance_dict = {}
        importance_list = None

    # Construct TSM Models
    model = TSN(args, num_class=current_head if age==0 else current_head-len(current_task), #modality='RGB',
            fc_lr5=not (args.tune_from and args.dataset in args.tune_from),
            apply_hooks=hook, age=age, training=True,
            cur_task_size=len(current_task))#,exemplar_segments=args.exemplar_segments)

    scale_size = model.scale_size
    input_size = model.input_size

    normalize = GroupNormalize(model.input_mean, model.input_std)
    train_augmentation = model.get_augmentation(flip=False if 'something' in args.dataset or 'jester' in args.dataset else True)
    transform_rgb = torchvision.transforms.Compose([
                       train_augmentation,
                       Stack(roll=(args.arch in ['BNInception', 'InceptionV3'])),
                       ToTorchFormatTensor(div=(args.arch not in ['BNInception', 'InceptionV3'])),
                       normalize,
                   ])
    lambda_0 = 0.0

    if age > 0:
        print("Load the Previous Model")
        ckpt_path = os.path.join(args.root_model, args.dataset, str(args.init_task), str(args.nb_class), '{:03d}'.format(args.exp), 'task_{:03d}.pth.tar'.format(age-1))

        print(ckpt_path)
        sd = torch.load(ckpt_path)
        sd = sd['state_dict']
        state_dict = dict()
        for k, v in sd.items():
            state_dict[k[7:]] = v

        model.load_state_dict(state_dict)

        # Prepare Old Model to Distill
        if args.cl_type == 'DIST' or args.cl_type == 'REG':
            print("Copy the old Model")
            model_old = copy.deepcopy(model)
            model_old.eval()
            lambda_0 = cl_utils.set_lambda_0(len(current_task),current_head-len(current_task),args)
            print('lambda_0  : {}'.format(lambda_0))

        # Increment the classifier
        print("Increment the Model")
        model.increment_head(current_head,age)
    print(model.new_fc)
    #print(args.train_list)
    #print(prefix)
    # Construct DataLoader
    train_dataset = TSNDataSet(args.root_path, args.train_list, current_task, class_indexer, num_segments=args.num_segments,
                new_length=1, modality='RGB',image_tmpl=prefix, transform=transform_rgb, dense_sample=args.dense_sample,
                exemplar_list=exemplar_list, is_entire=(args.store_frames=='entire'), #nb_val=args.nb_val,
                exemplar_per_class=exemplar_per_class, current_head=current_head,
                diverse_rate=args.diverse_rate, cl_method=args.cl_method, age=age)

    train_loader = DataLoader(train_dataset, batch_size=args.train_batch_size,
                            shuffle=True, num_workers=args.workers,
                            pin_memory=True, drop_last=True)

    print("DataLoader Constructed : Train {}".format(len(train_loader)))

    policies = model.get_optim_policies()

    # Wrap the model with DataParallel module
    model = torch.nn.DataParallel(model, device_ids=args.gpus).cuda()
    if model_old:
        model_old = torch.nn.DataParallel(model_old, device_ids=args.gpus).cuda()

    optimizer = torch.optim.SGD(policies,
                                args.lr,
                                momentum=args.momentum,
                                weight_decay=args.weight_decay)
    if args.loss_type == 'nll':
        criterion = nn.CrossEntropyLoss().cuda()
    elif args.loss_type == 'bce':
        criterion = nn.BCEWithLogitsLoss().cuda()

    print("Optimizer Constructed")

    if age > 0 and args.fc in ['cc','lsc']:
        transform_ex = torchvision.transforms.Compose([
                                                GroupScale(scale_size),
                                                GroupCenterCrop(input_size),
                                                Stack(roll=(args.arch in ['BNInception', 'InceptionV3'])),
                                                ToTorchFormatTensor(div=(args.arch not in ['BNInception', 'InceptionV3'])),
                                                normalize,
                                                ])

        dataset_for_embedding = TSNDataSet(args.root_path, args.train_list, current_task, class_indexer,
                                num_segments=args.num_segments, random_shift=False, new_length=1,
                                modality='RGB', image_tmpl=prefix, transform=transform_ex,
                                dense_sample=args.dense_sample)

        loader_for_embedding = DataLoader(dataset_for_embedding, batch_size=args.train_batch_size,
                            shuffle=False, num_workers=args.workers,
                            pin_memory=True, drop_last=False)

        cl_utils.init_cosine_classifier(model,current_task,class_indexer,loader_for_embedding,args)

    best_prec1 = 0
    best_epoch = 0
    # Train the model for the current task
    for epoch in range(args.start_epoch, args.epochs):
        _adjust_learning_rate(args, optimizer, epoch, args.lr_type, args.lr_steps)
        print("Learning rate adjusted")

        _train(args, train_loader, model, criterion, optimizer, epoch, age,
                lambda_0=lambda_0, model_old=model_old, importance_list=importance_list)
        if (epoch + 1) % args.eval_freq == 0 or epoch == args.epochs - 1:
            if args.fc in ['cc','lsc']:
                print('Sigma : {}, Eta : {}'.format(model.module.new_fc.sigma, model.module.new_fc.eta))

            state = {'epoch': epoch + 1,
                'arch': args.arch,
                'state_dict': model.state_dict(),
                'optimizer': optimizer.state_dict(),
                'best_prec1': best_prec1,}
            save_checkpoint(args, age, state)

    if args.use_importance:
        tcd.update_importance(args,model,train_loader,criterion)
        save_importance(args,age,model,importance_dict)

    torch.cuda.empty_cache()
    del model

def _adjust_learning_rate(args, optimizer, epoch, lr_type, lr_steps):
    """Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""
    if lr_type == 'step':
        decay = 0.1 ** (sum(epoch >= np.array(lr_steps)))
        lr = args.lr * decay
        decay = args.weight_decay
    elif lr_type == 'cos':
        import math
        lr = 0.5 * args.lr * (1 + math.cos(math.pi * epoch / args.epochs))
        decay = args.weight_decay
    else:
        raise NotImplementedError
    for param_group in optimizer.param_groups:
        param_group['lr'] = lr * param_group['lr_mult']
        param_group['weight_decay'] = decay * param_group['decay_mult']


import tkinter as tk
from tkinter.font import Font
from utils import utils
from PIL import ImageTk, Image
from lolwidgets.runepage import RuneSheet
from lolwidgets.championcard import ChampionFrame
from lolwidgets.abilities import AbilitiesTable
from lolwidgets.items import ItemBuildFrame
from lolwidgets.skinchooser import SkinChooser
from lolwidgets.utils import *

class Build(tk.Frame):
	def __init__(self, parent, vertical_space: int = 20, horizontal_space: float = 20, ability_cell_size: int = 40, champion_frame_size: int = 110, item_size: float = 64, control_bar_font_size: int = 16, *args, **kwargs) -> None:
		tk.Frame.__init__(self, parent, *args, **kwargs)
		self.champion = None
		self.backend = self.winfo_toplevel().backend
		self.spacing = Spacing(vertical=vertical_space, horizontal=horizontal_space)

		self.rune_sheet = RuneSheet(self, self.backend.get_runes(), vertical_space=15)
		self.abilities = AbilitiesTable(self, cell_size=int((self.rune_sheet.width - ability_cell_size) / 19), border_size=2)
		self.width = int(self.rune_sheet.width + self.abilities.width + self.spacing.horizontal * 3)
		self.champion_frame = ChampionFrame(self, width=self.width, size=champion_frame_size, backend=self.backend, background=self['bg'])
		self.data = ControlFrame(self, lane_navigation=self.backend.navigation_icons['lane_navigation'], width=self.rune_sheet.width, font_size=control_bar_font_size, func=self.select_lane, background=self['bg'])

		self.starting_items = ItemBuildFrame(self, title='Starting Items', width=self.rune_sheet.width, height=item_size, title_width=150, background=self['bg'])
		self.full_build = ItemBuildFrame(self, title='Full Build', width=self.rune_sheet.width, height=item_size, title_width=150, background=self['bg'])

		self.height = int(self.champion_frame.height + self.data.height + self.rune_sheet.height + vertical_space)
		self.skins = SkinChooser(self, width=self.abilities.width, height=self.height - self.champion_frame.height - self.abilities.height - self.starting_items.height - self.full_build.height - 5 * self.spacing.vertical)
		self.previous_selected = ''

	def set_champion(self, champion) -> None:
		self.champion = champion
		self.data.set_lanes(champion['build'].keys())
		self.champion_frame.set_champion(champion['name'], champion['image'])
		self.abilities.set_abilities(champion['abilities'])
		self.select_lane(champion['default_lane'])
		self.skins.set_skins(self.backend.get_skins())

	def select_lane(self, lane: str) -> None:
		if self.champion is None:
			return
		self.rune_sheet.select_runes(*self.champion['build'][lane][0]['runes'])
		self.champion_frame.set_spells(self.champion['build'][lane][0]['spells'])
		self.abilities.set_ability_order(self.champion['build'][lane][0]['ability_order'])
		self.starting_items.set_items(self.champion['build'][lane][0]['items'][0])
		self.full_build.set_items(self.champion['build'][lane][0]['items'][1])
		self.data.set_values(self.champion['build'][lane][0]['wr'], self.champion['build'][lane][0]['br'], self.champion['build'][lane][0]['pr'])
		self.data.select_lane(lane)
		self.previous_selected = lane

		self.backend.set_everything(self.champion['build'][lane][1])

	def place(self, x=0, y=0) -> None:
		super().place(x=x, y=y, height=self.height, width=self.width)
		y = 0
		self.champion_frame.place(x=0, y=0)
		y += self.champion_frame.height
		self.data.place(x=self.spacing.horizontal, y=y)
		y += self.data.height
		self.rune_sheet.place(x=self.spacing.horizontal, y=y)
		x = self.spacing.horizontal * 2 + self.rune_sheet.width
		y = self.champion_frame.height + self.spacing.vertical
		self.abilities.place(x=x, y=y)
		y += self.abilities.height + self.spacing.vertical
		self.starting_items.place(x=x, y=y)
		y += self.starting_items.height + self.spacing.vertical
		self.full_build.place(x=x, y=y)
		y += self.full_build.height + self.spacing.vertical
		self.skins.place(x=x, y=y)

	def place_forget(self) -> None:
		super().place_forget()
		self.rune_sheet.place_forget()
		self.champion_frame.place_forget()
		self.abilities.place_forget()
		self.starting_items.place_forget()
		self.full_build.place_forget()
		self.data.place_forget()

	def select_skin(self, skinid):
		self.skins.select_skin(skinid)

class ControlFrame(tk.Frame):
	def __init__(self, parent, lane_navigation, width: float, font_size: int, horizontal_spacing: float = 20, func: callable = lambda *args: None, *args, **kwargs) -> None:
		tk.Frame.__init__(self, parent, *args, **kwargs)
		self.horizontal_spacing = horizontal_spacing
		self.font = Font(size=font_size)
		self.height = self.font.metrics('linespace') * 2
		self.width = width

		self.pick_rate = tk.Label(self, text='PR:', font=self.font, background=self['bg'], foreground='white', anchor='w')
		self.pick_rate_value = tk.Label(self, text='100%', font=self.font, background=self['bg'], foreground='white', anchor='w')
		self.win_rate = tk.Label(self, text='WR:', font=self.font, background=self['bg'], foreground='white', anchor='w')
		self.win_rate_value = tk.Label(self, text='100%', font=self.font, background=self['bg'], foreground='white', anchor='w')
		self.ban_rate = tk.Label(self, text='BR:', font=self.font, background=self['bg'], foreground='white', anchor='w')
		self.ban_rate_value = tk.Label(self, text='100%', font=self.font, background=self['bg'], foreground='white', anchor='w')
		self.lane_images = [ImageTk.PhotoImage(Image.open('images/Top.png').resize((self.height, self.height)))]
		self.laneFrame = LaneFrame(self, lane_navigation=lane_navigation, height=self.height, background=self['bg'], func=func)

	def select_lane(self, lane):
		self.laneFrame.select_lane(lane)

	def set_values(self, win_rate, ban_rate, play_rate):
		self.win_rate_value['text'] = f'{win_rate:.2f}%'
		self.ban_rate_value['text'] = f'{ban_rate:.2f}%'
		self.pick_rate_value['text'] = f'{play_rate:.2f}%'

	def set_lanes(self, lane_list):
		self.laneFrame.set_active_buttons(lane_list)

	def place(self, x=0, y=0) -> None:
		super().place(x=x, y=y, height=self.height, width=self.width)

		x = 0
		self.pick_rate.place(x=x, y=0, height=self.height, width=self.font.measure(self.pick_rate['text']) + self.horizontal_spacing // 4)
		x += self.font.measure(self.pick_rate['text']) + self.horizontal_spacing // 2
		self.pick_rate_value.place(x=x, y=0, height=self.height, width=self.font.measure(self.pick_rate_value['text']) + self.horizontal_spacing)

		x += self.font.measure(self.pick_rate_value['text']) + self.horizontal_spacing
		self.win_rate.place(x=x, y=0, height=self.height, width=self.font.measure(self.win_rate['text']) + self.horizontal_spacing // 4)
		x += self.font.measure(self.win_rate['text']) + self.horizontal_spacing // 4
		self.win_rate_value.place(x=x, y=0, height=self.height, width=self.font.measure(self.win_rate_value['text']) + self.horizontal_spacing)

		x += self.font.measure(self.win_rate_value['text']) + self.horizontal_spacing
		self.ban_rate.place(x=x, y=0, height=self.height, width=self.font.measure(self.ban_rate['text']) + self.horizontal_spacing // 4)
		x += self.font.measure(self.ban_rate['text']) + self.horizontal_spacing // 4
		self.ban_rate_value.place(x=x, y=0, height=self.height, width=self.font.measure(self.ban_rate_value['text']) + self.horizontal_spacing)

		x = self.width - self.laneFrame.width
		self.laneFrame.place(x=x, y=0)

	def place_forget(self) -> None:
		super().place_forget()
		self.pick_rate.place_forget()
		self.pick_rate_value.place_forget()
		self.win_rate.place_forget()
		self.win_rate_value.place_forget()
		self.ban_rate.place_forget()
		self.ban_rate_value.place_forget()
		self.laneFrame.place_forget()

class LaneFrame(tk.Frame):
	def __init__(self, parent, lane_navigation, height: float, horizontal_spacing=5, func: callable = lambda *args: None, *args, **kwargs) -> None:
		tk.Frame.__init__(self, parent, *args, **kwargs)
		self.lane_func = func
		self.height = height
		self.width = 0
		self.horizontal_spacing = horizontal_spacing
		self.button_list = [LaneButton(self, lane=lane, active_icon=lane_navigation[lane]['enabled'], inactive_icon=lane_navigation[lane]['disabled'], size=int(self.height), borderwidth=0, background=self['bg'], activebackground=self['bg'], func=self.toggle_lane) for lane in utils.lanes if lane in lane_navigation]
		self.active_buttons = []
		self.previous_selected = -1

	def select_lane(self, lane):
		if self.previous_selected != -1:
			self.button_list[self.previous_selected].set_active(False)
			self.button_list[self.previous_selected]['bg'] = self['bg']
		self.button_list[utils.lane_indexes[lane]].set_active(True)
		self.button_list[utils.lane_indexes[lane]]['bg'] = utils.widget_color
		self.previous_selected = utils.lane_indexes[lane]

	def toggle_lane(self, lane):
		if self.previous_selected == utils.lane_indexes[lane]:
			return
		self.lane_func(lane)

	def set_active_buttons(self, lanes):
		self.active_buttons = []
		for lane in lanes:
			self.active_buttons.append(utils.lane_indexes[lane])
		self.active_buttons.sort()
		self.width = (self.height + self.horizontal_spacing) * len(self.active_buttons) - self.horizontal_spacing

	def place(self, x: float = 0, y: float = 0) -> None:
		super().place(x=x, y=y, width=(self.height + self.horizontal_spacing) * len(self.active_buttons), height=self.height)
		x = 0
		for i in self.active_buttons:
			self.button_list[i].place(x=x, y=0, height=self.height, width=self.height)
			x += self.height + self.horizontal_spacing

class LaneButton(tk.Button):
	def __init__(self, parent, active_icon, inactive_icon, size: int, lane: str, func: callable = lambda *args: None, *args, **kwargs):
		tk.Button.__init__(self, parent, *args, **kwargs)
		self.size = size
		self.lane = lane
		self.is_active = False
		self.active_image = ImageTk.PhotoImage(Image.open(active_icon).resize((size, size)))
		self.inactive_image = ImageTk.PhotoImage(Image.open(inactive_icon).resize((size, size)))
		self.size = size
		self.func = func
		self['image'] = self.inactive_image
		self['command'] = self.callback

	def set_active(self, status: bool) -> None:
		self.is_active = status
		if status:
			self['image'] = self.active_image
		else:
			self['image'] = self.inactive_image

	def callback(self):
		self.func(self.lane)


#!/usr/bin/env python

import os
import io
import json

from flask import Flask, jsonify
from flask_restful import Resource, Api, request
from flask import send_file, make_response
from flask_cors import CORS

app = Flask(__name__)
api = Api(app)
CORS(app)

image_directory = '/media/anders/Media/Pictures/Post processed/'
small_thumbnail_directory = '/media/anders/Media/Pictures/Post processed/thumbnails/small/'
big_thumbnail_directory = '/media/anders/Media/Pictures/Post processed/thumbnails/big/'
image_data_filepath = 'image_info.json'

thumbnails = {} # {name : binary_data}
                # thumbnails are saved to memory as they are small and need to be accessed often.
                # Note: Raw images are not loaded to memory.

image_info = {} # {image_name : int(nbr of likes)}

@app.route('/images/<string:image_name>')
def get_image(image_name):
    image_binary = thumbnails[image_name]
    return make_image_response(image_binary, image_name)

@app.route('/images/raw/<string:image_name>')
def get_raw_image(image_name):
    return send_file(image_directory + image_name)

# Returns the filenames in the default original image directory
# sorted by rating on client side
@app.route('/images/filenames.json')
def get_filenames():
    return jsonify(image_info)

def make_image_response(image_binary, image_name):
    response = make_response(image_binary)
    response.headers.set('Content-Type', 'image/jpeg')
    response.headers.set(
        'Content-Disposition', '', filename='%s.jpg' % image_name) # '' argument represent "not as attachment"
    return response

def read_images(directory_list):
    img_dict = {}
    for directory in directory_list:
        filenames = read_filenames(directory)
        for filename in filenames:
            print('READING FILE: ' + str(filename))
            img_dict[filename] = open(directory + filename, "rb").read()
    return img_dict

def read_image_info(directory):
    image_info = load_image_info()
    for filename in os.listdir(directory):
        if filename not in image_info.keys():
            if filename.endswith('.png') or filename.endswith('.jpg'):
                image_info[filename] = 0
    return image_info

def read_filenames(directory):
    filenames = []
    for filename in os.listdir(directory):
        if filename.endswith('.png') or filename.endswith('.jpg'):
            filenames.append(filename)
    return filenames

def save_image_data(image_info):
    with open(image_data_filepath, 'w') as outfile:
        json.dump(image_info, outfile)

def load_image_info():
    try:
        with open(image_data_filepath) as file:
            return json.load(file)
    except IOError:
        print ("File does not exist:", image_data_filepath)
        return {}

class ImageRating(Resource):
    def get(self, image_name):
        if image_name in image_info:
            return image_info[image_name]
        return 0

    def put(self, image_name):
        put_data =  int(request.form['data'])
        if image_name in image_info.keys():
            image_info[image_name] += put_data
        elif put_data > 0:
            image_info[image_name] = put_data
        save_image_data(image_info) #TODO: optimize save to file to happen less
        return image_info[image_name]

api.add_resource(ImageRating, '/ratings/<string:image_name>')

if __name__ == '__main__':
    # ORDER IMPORTANT
    image_info = read_image_info(image_directory)
    thumbnails = read_images([small_thumbnail_directory, big_thumbnail_directory])
    app.run(debug=False)


import typer
from farcaster.client import Warpcast
from farcaster.models import ApiCast, ApiUser
from typing import Optional, Set
from rich import print
from rich.panel import Panel
from rich.padding import Padding
from rich.progress import Progress, SpinnerColumn, TextColumn

cast_link_prefix = "farcaster://casts/"
user_link_prefix = "farcaster://profiles/"

def main(mnemonic: str, watch_all: bool = False, skip_existing: bool = False):
    with Progress(
        SpinnerColumn(),
        TextColumn("[progress.description]{task.description}"),
        transient=True,
    ) as progress:
        progress.add_task(description="Logging in...", total=None)
        progress.add_task(description="Reticulating splines...", total=None)

        client = Warpcast(mnemonic=mnemonic)

        following: Set[int] = set()
        if not watch_all:
            following_users = client.get_all_following().users
            following = set([user.fid for user in following_users])
    print("Ready!")
    with Progress(
        SpinnerColumn(),
        TextColumn("[progress.description]{task.description}"),
        transient=True,
    ) as progress:
        progress.add_task(description="Listening for new casts...", total=None)
        for cast in client.stream_casts(skip_existing=skip_existing):
            if cast:
                if not watch_all:
                    if cast.author.fid not in following:
                        continue
                if cast.text.startswith("recast:farcaster://casts/"):
                    recaster = cast.author
                    cast_hash = cast.text.lstrip("recast:farcaster://casts/")
                    cast = client.get_cast(cast_hash).cast
                else:
                    recaster = None
                print_cast(cast, recaster)

def print_cast(cast: ApiCast, recaster: Optional[ApiUser] = None) -> None:
    if recaster:
        print(
            f"🔁 [red bold link={user_link_prefix + str(recaster.fid)}]{recaster.username}[/red bold link] recasted:"
        )
    parent = ""
    if cast.parent_hash:
        parent = f" replying to [purple link={cast_link_prefix + str(cast.parent_hash)}](parent)[/purple link]"

    print(
        Padding(
            f"[green bold link={user_link_prefix + str(cast.author.fid)}]{cast.author.username}[/green bold link]{parent} | [purple link={cast_link_prefix + str(cast.hash)}](cast)[/purple link]",
            (0, 1),
        )
    )
    print(Panel(cast.text))
    print()

def start():
    typer.run(main)


import collections
import json
from json.decoder import JSONDecodeError
from data.offer_reply import ReplyStatus, OfferReply
from static_info import DEFAULT_FILENAME

class JsonDatabase:
    """
    бд в которй хранятся все данные о заявках в формате json
    """

    def __init__(self, filename=DEFAULT_FILENAME):
        self.__filename = filename
        self.__data = collections.defaultdict(list)
        self.reply_to_approve_queue = []

        with open(self.__filename, 'r') as json_file:
            try:
                self.__data.update(json.load(json_file))
            except JSONDecodeError:
                pass

        self.__clear_data_from_deleted()
        self.__fill_reply_queue_from_bd(self.reply_to_approve_queue)

    def get_reply(self, reply_address: OfferReply.Address):
        try:
            reply_data = self.__data[str(reply_address.chat_id)][reply_address.user_reply_ind]
            return OfferReply.from_bd_row(**reply_data, row_ind=reply_address.user_reply_ind)
        except:
            return None

    def get_replies(self, chat_id):
        if str(chat_id) not in self.__data:
            return []
        return self.__data[str(chat_id)]

    def write_reply(self, reply: OfferReply):
        if reply.__user_reply_ind is None:
            reply.__user_reply_ind = self.__add(reply.__chat_id, reply.__status, reply.__credit_ind, reply.__data)
        else:
            self.__update(reply.__chat_id, reply.__status, reply.__credit_ind, reply.__user_reply_ind, reply.__data)

    def __update(self, chat_id, status: ReplyStatus, credit_ind: int, credit_number: int, data):
        self.__data[str(chat_id)][credit_number] = \
            {"credit_data": data, "credit_ind": credit_ind, "status": status,
             "chat_id": chat_id}

    def __add(self, chat_id, status: ReplyStatus, credit_ind: int, data):
        self.__data[str(chat_id)].append(
            {"credit_data": data, "credit_ind": credit_ind, "status": status,
             "chat_id": chat_id})
        return len(self.__data[str(chat_id)]) - 1

    def flush(self):
        with open(self.__filename, 'w+') as outfile:
            json.dump(self.__data, outfile)

    def __fill_reply_queue_from_bd(self, queue: list):
        for chat_id, replies in self.__data.items():
            for ind, reply_data in enumerate(replies):
                if reply_data["status"] == ReplyStatus.Pending:
                    cr = OfferReply.from_bd_row(**reply_data, row_ind=ind)
                    queue.append(cr.get_address())

    def __clear_data_from_deleted(self):
        new_data = collections.defaultdict(list)
        for chat_id, replies in self.__data.items():
            new_data[chat_id] = [reply_data for reply_data in replies if reply_data["status"] != ReplyStatus.Removed]
        self.__data = new_data

    def filter_reply_queue(self):
        self.reply_to_approve_queue = [addr for addr in self.reply_to_approve_queue if
                                       not (self.get_reply(addr).is_deleted() or self.get_reply(addr).is_cancelled())]

    def get_approved_replies(self):
        ret_replies = []
        for chat_id, replies in self.__data.items():
            for ind, reply_data in enumerate(replies):
                if reply_data["status"] == ReplyStatus.Approved:
                    cr = OfferReply.from_bd_row(**reply_data, row_ind=ind)
                    ret_replies.append(cr.get_address())
        return ret_replies

    def get_rejected_replies(self):
        ret_replies = []
        for chat_id, replies in self.__data.items():
            for ind, reply_data in enumerate(replies):
                if reply_data["status"] == ReplyStatus.Rejected:
                    cr = OfferReply.from_bd_row(**reply_data, row_ind=ind)
                    ret_replies.append(cr.get_address())
        return ret_replies

    def get_cancelled_replies(self):
        ret_replies = []
        for chat_id, replies in self.__data.items():
            for ind, reply_data in enumerate(replies):
                if reply_data["status"] == ReplyStatus.Cancelled:
                    cr = OfferReply.from_bd_row(**reply_data, row_ind=ind)
                    ret_replies.append(cr.get_address())
        return ret_replies


import cv2
import numpy as np
import time
from VehicleCounter import VideoPreprocessor, VehicleCounter
import yaml

def read_configs(filename):
    with open(filename, 'r') as stream:
        configs = yaml.load(stream, Loader = yaml.FullLoader)
    return configs

if __name__ == '__main__':
    configs = read_configs('configs.yaml')
    vidcap = cv2.VideoCapture(configs['video_input'])

    #Get video frame data
    width  = int(vidcap.get(3))
    height = int(vidcap.get(4))
    original_fps = vidcap.get(cv2.CAP_PROP_FPS)

    output_filename = "outputs/" + configs['video_input'].split('.')[0] + "_" + str(int(time.time())) + ".mp4"
    fourcc = cv2.VideoWriter_fourcc(*'MP4V')
    writer = cv2.VideoWriter(output_filename, fourcc, original_fps, (width,height))

    count_frame = 0
    vid_proprocessor = VideoPreprocessor(height, width, configs["stabilizerPercentageCropFromTop"], np.array(configs["roiPolyPoints"]))
    vehicle_counter = VehicleCounter(configs['yoloModelName'],
                                       configs['yoloSize'],
                                       configs['trackerModel_filename'],
                                       configs['tracker_max_cosine_distance'],
                                       configs['tracker_maxAge'],
                                       np.array(configs['exit_lines']))

    with open('model_data/names.txt', 'r') as f:
        classes = f.read().splitlines()

    while True:
        t1 = time.time()

        ret, frame = vidcap.read()
        #Break loop when video ends
        if ret != True:
            print("BREAK")
            cv2.destroyAllWindows()
            break

        ## Stabilize frame
        inv_transformation, transformation_mat, processed_frame, original_frame = vid_proprocessor.preprocess_img(frame, width, height)
        classIds, boxes, trackIds, exit_records, unsure_records = vehicle_counter.trackSouthwardVehicles(processed_frame,
                                                                                confThreshold = configs["confThreshold"],
                                                                                nmsThreshold = configs["nmsThreshold"])

        for (classId, box, trackId) in zip(classIds, boxes, trackIds):
            #Transform to original
            top_left = (box[0], box[1])
            bottom_right = (box[0] + box[2], box[1] + box[3])
            top_left = VideoPreprocessor.transform2OriginalCoord(top_left, transformation_mat)
            bottom_right = VideoPreprocessor.transform2OriginalCoord(bottom_right, transformation_mat)

            if trackId in exit_records:
                color = (0, 255 , 0)
            elif trackId in unsure_records:
                color = (0, 0, 255)
            else:
                color = (0, 255, 255)

            cv2.rectangle(original_frame, (bottom_right[0], bottom_right[1]),(top_left[0], top_left[1]),
                  color=color, thickness=2)
            text =  str(trackId) + " " + classes[classId]
            cv2.putText(original_frame, text, (top_left[0], top_left[1] - 5), cv2.FONT_HERSHEY_SIMPLEX, 1,
                color=color, thickness=2)

        vehicles_exited_text = "Vehicles Exited (South): " + str(len(exit_records))
        cv2.rectangle(original_frame, (93, 45),(970, 117),
                  color=(0,0,0), thickness=-1)
        cv2.putText(original_frame, vehicles_exited_text, (100, 100), cv2.FONT_HERSHEY_SIMPLEX, 2,
            color=(0, 0, 255), thickness=3)

        writer.write(frame)
        original_frame = cv2.resize(original_frame, (1920//2, 1080//2))

        cv2.imshow("output", original_frame)
        key = cv2.waitKey(1)
        if ret != True or key==27:
            print("BREAK")
            cv2.destroyAllWindows()
            break

        #previous_frame = frame
        print(1/(time.time()-t1))
        count_frame+=1

    writer.release()


# Combining all the ML elements into a pipeline

from sklearn.tree import DecisionTreeRegressor # Select a model (right now the model doesn't matter)
from sklearn.model_selection import train_test_split # Train-test split
from sklearn.model_selection import KFold # K-fold Cross validation
import sklearn.preprocessing as pp
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
import sklearn.metrics as m
from sklearn.model_selection import cross_validate

# Data management
import pandas as pd

# Data
from gapminder import gapminder as gap

# Let's predict life expectancy given GDP and population
y = gap['lifeExp'] # Clarify outcome
X = gap[['gdpPercap','pop']] # Clarify predictors

# %% -----------------------------------------

# split data
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.25, random_state=123)

# %% -----------------------------------------

# Combine preprocessing and model together so all steps are run at once
pipe = Pipeline([('scaler', pp.StandardScaler()), ('dtree', DecisionTreeRegressor())])

# Now we can run everything in one pass
pipe.fit(X_train,y_train)

# Make our prediction
y_hat = pipe.predict(X_train)

# See how we did.
m.mean_squared_error(y_train,y_hat)
m.r2_score(y_train,y_hat)

# How well do we do out of sample?
y_hat = pipe.predict(X_test)
m.mean_squared_error(y_test,y_hat)
m.r2_score(y_test,y_hat)

# Not so great. Over fit.

# %% -----------------------------------------

# Fold Cross validation into this process (to estimate the test error using the training data)

kf = KFold(n_splits=5) # Set the number of folds
k_splits = kf.split(X_train) # Create the split generator
scores = [] # Empty list to retain scores

# Loop through the splits, refit the model, and store performance
for train_ind, val_ind in k_splits:

    # Fit Model on the training slits
    pipe.fit(X_train.iloc[train_ind,:],y_train.iloc[train_ind])

    # Predict using the validation splits
    yhat = pipe.predict(X_train.iloc[val_ind,:])

    # Calculate performance scores
    mse = m.mean_squared_error(y_train.iloc[val_ind],yhat)
    r2 = m.r2_score(y_train.iloc[val_ind],yhat)

    # save
    scores.append((mse,r2))

# Convert into DF
dat_scores = pd.DataFrame(scores,columns=["mse","r2"])

# Estimate of test performance
dat_scores.mean(axis=0)

# %% -----------------------------------------

# Is there a quicker way to do this??? Yes!

scores_we_care_about = {"r2":"r2",'mse':'neg_mean_squared_error'}
# List of all the relevant keys: m.SCORERS.keys()

# Use the cross_validation method to validate.
scores = cross_validate(pipe,X=X_train,y=y_train,
                        scoring=scores_we_care_about,
                        cv=5)

# Predicted fit on the test data test error
scores['test_r2'].mean()
-1*scores['test_mse'].mean()

# ISSUE: Note there is one issue with the above. If we want to compare the performance
# of different models (which we often want to do), then we need to ensure that
# the splits for each fold are the same across models (else the difference
# in performance between two models might just be statistical fluke given
# how the data was scrambled).

# How do we get around this? Use the KFold generator to generate consistent folds
# that we can use again and again

# By seeding the random state, we can ensure the same folds are generated each time.
gen_folds = KFold(n_splits=5,random_state=111,shuffle=True)

scores = cross_validate(pipe,X=X_train,y=y_train,
                        scoring=scores_we_care_about,
                        cv=gen_folds) # Just drop the generator in for the cv arg

# %% -----------------------------------------

# Can we do better by adding in country information?

y = gap['lifeExp'] # Clarify outcome
X = gap[['country','gdpPercap','pop']] # Clarify predictors

# split data
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.25, random_state=123)

# Different preprocessing transformations given different variable types.
numeric_transformer = Pipeline(steps=[('scaler', pp.StandardScaler())])
categorical_transformer = Pipeline(steps=[('onehot', pp.OneHotEncoder())])

# Combine the different preprocessing instruction, mapping them to specific variables
preprocessor = ColumnTransformer(
    transformers=[('num', numeric_transformer, ['pop','gdpPercap']),
                  ('cat', categorical_transformer, ['country'])]
    )

# Now put it all together into a single pipeline
pipe2 = Pipeline([("preproces",preprocessor), ('dtree', DecisionTreeRegressor())])

# Use the cross_validation method to validate.
scores2 = cross_validate(pipe2,X=X_train,y=y_train,
                        scoring=scores_we_care_about,
                        cv=gen_folds)

# Predicted fit on the test data test error. Country info adds a lot!
scores2['test_r2'].mean()
-1*scores2['test_mse'].mean()


from os import environ
from  random import randint
from  time import sleep
import logging as logger
from flask import Flask, jsonify
from flask_cors import CORS
from collections import defaultdict
import json

app = Flask(__name__)
CORS(app)
logger.debug("App starting")

@app.route("/")
def hello():
    return "
Congratulations!
 Your server is running."

@app.route('/get_raw', methods=['GET'])
def get_data():
    logger.debug("GET method returning data")
    with open("data/covariates.json") as json_file:
        raw = json.load(json_file)
        #if randint(0,99) == 1:
        #    sleep(200000)
        return jsonify(raw), 200

@app.route('/get_counts', methods=['GET'])
def get_count():
    logger.debug("GET method returning data")
    with open("data/covariates.json") as json_file:
        raw = json.load(json_file)
        drugs = raw['Drug']
        res = defaultdict(list)
        for key, val in sorted(drugs.items()):
            res[val].append(key)
        raw = list()
        for key, val in res.items():
            drug_count = dict()
            drug_count["Drug"] = key
            drug_count['Count'] = len(val)
            raw.append(drug_count)
        if randint(0,99) == 1:
            sleep(200000)
        return jsonify(raw), 200

if __name__ == "__main__":
    app.run(host="0.0.0.0",
            port=environ['TX_SERVER_PORT'])


import config
import tweepy
from janome.tokenizer import Tokenizer
from wordcloud import WordCloud

font_pass = "/System/Library/Fonts/ヒラギノ角ゴシック W1.ttc"

def api():
    auth = tweepy.OAuth1UserHandler(
        config.api_key,
        config.api_secret,
        config.consumer_key,
        config.consumer_secret
    )
    return tweepy.API(auth, wait_on_rate_limit=True, timeout=120)

class TLDesigner:
    def __init__(self):
        self.tweet_id = None
        self.text = ''
        self.tweet_timelines = []
        self.API = api()

    def find_tweet(self):
        f = open("tweet_id.txt", "r")
        self.tweet_id = f.readline()

    def get_tweet(self):
        tweet_timelines = self.API.home_timeline(since_id=self.tweet_id, )
        for tt in tweet_timelines:
            if "https" not in tt.text and "RT" not in tt.text and "@" not in tt.text:
                self.tweet_timelines.append(tt.text)

    def filter_tweet(self):
        t = Tokenizer()
        for tt in self.tweet_timelines:
            tts = [token.surface for token in t.tokenize(tt) if token.part_of_speech.startswith('名詞')]
            for ts in tts:
                if len(ts) != 1:
                    self.text += " " + ts
            print(self.text)

    def generation_image(self, txt):
        wc = WordCloud(font_path=font_pass).generate(txt)
        wc.to_file("word_cloud_result.png")
        self.API.update_status_with_media(status='image tweet from python', filename='word_cloud_result.png')

    def store_tweet(self):
        ts = self.API.home_timeline(count=1)
        tweet_id = ts[0].id
        f = open("tweet_id.txt", "w")
        f.write(str(tweet_id))
        f.close()

    def main(self):
        self.find_tweet()
        self.get_tweet()
        self.filter_tweet()
        self.generation_image(self.text)
        self.store_tweet()

test = TLDesigner()
test.main()


import os
import glob
import math
import sys
from io import BytesIO
import threading
from boto3.session import Session
import numpy as np
from mlchain import logger
from mlchain.config import object_storage_config
from mlchain.base.exceptions import MlChainError
from .base import MLStorage

cv2 = None

def import_cv2():
    if cv2 is None:
        import cv2 as cv
        return cv
    return cv2

class ProgressPercentage:
    def __init__(self, filename, filesize):
        self._filename = filename
        self._size = filesize
        self._seen_so_far = 0
        self._lock = threading.Lock()

    def __call__(self, bytes_amount):
        def convertSize(size):
            if (size == 0):
                return '0B'
            size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
            i_name = int(math.floor(math.log(size, 1024)))
            chunk = math.pow(1024, i_name)
            size = round(size / chunk, 2)
            return '%.2f %s' % (size, size_name[i_name])

        # To simplify, assume this is hooked up to a single filename
        with self._lock:
            self._seen_so_far += bytes_amount
            percentage = (self._seen_so_far / self._size) * 100
            sys.stdout.write(
                "\r%s  %s / %s  (%.2f%%)        " % (self._filename, convertSize(self._seen_so_far),
                                                     convertSize(self._size), percentage))
            sys.stdout.flush()

class ObjectStorage(MLStorage):
    def __init__(self, bucket=None, client=None, url=None,
                 access_key=None, secret_key=None, provider=None, ping=False):
        MLStorage.__init__(self)
        self.bucket = bucket or object_storage_config.BUCKET
        self._client = client
        self.url = url or object_storage_config.URL
        self.access_key = access_key or object_storage_config.ACCESS_KEY
        self.secret_key = secret_key or object_storage_config.SECRET_KEY
        self.provider = provider or object_storage_config.PROVIDER or 's3'
        if ping:
            try:
                self.client.list_buckets()
            except Exception:
                MlChainError("Can't connect to Object Storage", code="S000", status_code=500)
        if self.bucket:
            try:
                self.client.create_bucket(Bucket=self.bucket)
            except Exception:
                pass

    @property
    def client(self):
        if self._client is None:
            session = Session(
                aws_access_key_id=self.access_key,
                aws_secret_access_key=self.secret_key)
            self._client = session.client(self.provider, endpoint_url=self.url)
        return self._client

    def download_file(self, key, local_path, bucket_name=None, use_basename=False):
        """
        Download a file from S3.
        Args:
            key: `str`. S3 key that will point to the file.
            local_path: `str`. the path to download to.
            bucket_name: `str`. Name of the bucket in which to store the file.
            use_basename: `bool`. whether or not to use the basename of the key.
        """
        if not bucket_name:
            bucket_name = self.bucket
        if bucket_name is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        local_path = os.path.abspath(local_path)
        if use_basename:
            local_path = os.path.join(local_path, os.path.basename(key))
        dir_name = os.path.dirname(local_path)
        if not os.path.exists(dir_name):
            os.makedirs(dir_name)
        try:
            content_length = self.client.head_object(Bucket=bucket_name, Key=key)["ContentLength"]
            progress = ProgressPercentage(key, content_length)
            self.client.download_file(bucket_name, key, local_path, Callback=progress)
            return True
        except Exception as ex:
            logger.error(str(ex))
            raise MlChainError(str(ex), code="S001", status_code=500)

    def download_bytes(self, key, bucket_name=None, use_basename=True):
        """
        Download a file from S3.
        Args:
            key: `str`. S3 key that will point to the file.
            local_path: `str`. the path to download to.
            bucket_name: `str`. Name of the bucket in which to store the file.
            use_basename: `bool`. whether or not to use the basename of the key.
        """
        if not bucket_name:
            bucket_name = self.bucket
        if bucket_name is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        try:
            buffer = BytesIO()
            self.client.download_fileobj(bucket_name, key, buffer)
            return buffer.getvalue()
        except Exception as ex:
            logger.error(str(ex))
            raise MlChainError(str(ex), code="S002", status_code=500)

    def download_cv2(self, key, bucket_name=None):
        """
        Download a file from S3.
        Args:
            key: `str`. S3 key that will point to the file.
            local_path: `str`. the path to download to.
            bucket_name: `str`. Name of the bucket in which to store the file.
            use_basename: `bool`. whether or not to use the basename of the key.
        """
        if not bucket_name:
            bucket_name = self.bucket
        if bucket_name is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        try:
            buffer = BytesIO()
            self.client.download_fileobj(bucket_name, key, buffer)
            cv2 = import_cv2()
            return cv2.imdecode(
                np.asarray(bytearray(buffer.getvalue()), dtype="uint8"),
                cv2.IMREAD_COLOR)
        except Exception as ex:
            logger.error(str(ex))
            raise MlChainError(str(ex), code="S003", status_code=500)

    def download_dir(self, prefix, dir_path, bucket_name=None):
        bucket_name = bucket_name or self.bucket
        if bucket_name is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        if prefix.endswith('/'):
            prefix = prefix[:-1]
        if len(prefix) > 0:
            prefix = '{0}/'.format(prefix)
        try:
            results = self.list(bucket_name=bucket_name, prefix=prefix)
            for file in results['keys']:
                self.download_file(prefix + file, os.path.join(dir_path, file),
                                   bucket_name=bucket_name)
            for dir in results['prefixes']:
                self.download_dir(prefix + dir, os.path.join(dir_path, dir),
                                  bucket_name=bucket_name)
        except Exception as ex:
            logger.error(str(ex))
            raise MlChainError(str(ex), code="S004", status_code=500)

    def upload_file(self, filename,
                    key,
                    bucket_name=None,
                    overwrite=False,
                    encrypt=False,
                    acl=None,
                    use_basename=False):
        """
        Uploads a local file to S3.
        Args:
            filename: `str`. name of the file to upload.
            key: `str`. S3 key that will point to the file.
            bucket_name: `str`. Name of the bucket in which to store the file.
            overwrite: `bool`. A flag to decide whether or not to overwrite the key
                if it already exists. If replace is False and the key exists, an
                error will be raised.
            encrypt: `bool`. If True, the file will be encrypted on the server-side
                by S3 and will be stored in an encrypted form while at rest in S3.
            acl: `str`. ACL to use for uploading, e.g. "public-read".
            use_basename: `bool`. whether or not to use the basename of the filename.
        """
        if not bucket_name:
            bucket_name = self.bucket
        if bucket_name is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        if use_basename:
            key = os.path.join(key, os.path.basename(filename))
        try:
            self.client.upload_file(filename, bucket_name, key)
        except Exception as ex:
            logger.error(str(ex))
            raise MlChainError(str(ex), code="S005", status_code=500)

    def upload_bytes(self, bytes_data,
                     key,
                     bucket_name=None,
                     overwrite=False,
                     encrypt=False,
                     acl=None):
        """
        Uploads bytes to S3
        This is provided as a convenience to drop a string in S3. It uses the
        boto infrastructure to ship a file to s3.
        Args:
            bytes_data: `bytes`. bytes to set as content for the key.
            key: `str`. S3 key that will point to the file.
            bucket_name: `str`. Name of the bucket in which to store the file.
            overwrite: `bool`. A flag to decide whether or not to overwrite the key
                if it already exists.
            encrypt: `bool`. If True, the file will be encrypted on the server-side
                by S3 and will be stored in an encrypted form while at rest in S3.
            acl: `str`. ACL to use for uploading, e.g. "public-read".
        """
        if not bucket_name:
            bucket_name = self.bucket
        if bucket_name is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        filelike_buffer = BytesIO(bytes_data)
        try:
            self.client.upload_fileobj(filelike_buffer, bucket_name, key)
        except Exception as ex:
            logger.info(str(ex))
            raise MlChainError(str(ex), code="S006", status_code=500)

    def upload_cv2(self, img,
                   key,
                   bucket_name=None,
                   overwrite=False,
                   quality=95,
                   img_fmt='.jpg',
                   acl=None):
        """
        Uploads bytes to S3
        This is provided as a convenience to drop a string in S3. It uses the
        boto infrastructure to ship a file to s3.
        Args:
            bytes_data: `bytes`. bytes to set as content for the key.
            key: `str`. S3 key that will point to the file.
            bucket_name: `str`. Name of the bucket in which to store the file.
            overwrite: `bool`. A flag to decide whether or not to overwrite the key
                if it already exists.
            encrypt: `bool`. If True, the file will be encrypted on the server-side
                by S3 and will be stored in an encrypted form while at rest in S3.
            acl: `str`. ACL to use for uploading, e.g. "public-read".
        """
        if not bucket_name:
            bucket_name = self.bucket
        if bucket_name is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        try:
            jpg_formats = ['.JPG', '.JPEG']
            png_formats = ['.PNG']
            encode_params = None
            img_fmt = '.{0}'.format(img_fmt.strip('.')).upper()
            cv2 = import_cv2()
            if img_fmt in jpg_formats:
                encode_params = [cv2.IMWRITE_JPEG_QUALITY, quality]
            elif img_fmt in png_formats:
                encode_params = [cv2.IMWRITE_PNG_COMPRESSION, quality]
            ret, buf = cv2.imencode(img_fmt, img, encode_params)

            filelike_buffer = BytesIO(buf.tostring())

            self.client.upload_fileobj(filelike_buffer, bucket_name, key)
        except Exception as ex:
            logger.info(str(ex))
            raise MlChainError(str(ex), code="S007", status_code=500)

    def upload_dir(self, dir_path, prefix, bucket_name=None):
        bucket_name = bucket_name or self.bucket
        if bucket_name is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        try:
            for file in glob.glob(os.path.join(dir_path, '*'), recursive=True):
                file_name = file[len(dir_path):].replace('\\', '/')
                if file_name.startswith('/'):
                    file_name = file_name[1:]
                key = os.path.join(prefix, file_name).replace('\\', '/')
                if os.path.isfile(file):
                    self.upload_file(file, key, bucket_name)
                else:
                    self.upload_dir(file, key, bucket_name)
        except Exception as ex:
            logger.info(str(ex))
            raise MlChainError(str(ex), code="S008", status_code=500)

    def list(self,
             bucket_name=None,
             prefix='',
             delimiter='/',
             page_size=None,
             max_items=None,
             keys=True,
             prefixes=True):
        """
        Lists prefixes and contents in a bucket under prefix.
        Args:
            bucket_name: `str`. the name of the bucket
            prefix: `str`. a key prefix
            delimiter: `str`. the delimiter marks key hierarchy.
            page_size: `str`. pagination size
            max_items: `int`. maximum items to return
            keys: `bool`. if it should include keys
            prefixes: `boll`. if it should include prefixes
        """
        if not bucket_name:
            bucket_name = self.bucket
        if bucket_name is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        config = {
            'PageSize': page_size,
            'MaxItems': max_items,
        }
        try:
            paginator = self.client.get_paginator('list_objects_v2')

            response = paginator.paginate(Bucket=bucket_name,
                                          Prefix=prefix,
                                          Delimiter=delimiter,
                                          PaginationConfig=config)

            def get_keys(contents):
                list_keys = []
                for cont in contents:
                    list_keys.append(cont['Key'][len(prefix):])

                return list_keys

            def get_prefixes(page_prefixes):
                list_prefixes = []
                for pref in page_prefixes:
                    list_prefixes.append(pref['Prefix'][len(prefix): -1])
                return list_prefixes

            results = {
                'keys': [],
                'prefixes': []
            }
            for page in response:
                if prefixes:
                    results['prefixes'] += get_prefixes(page.get('CommonPrefixes', []))
                if keys:
                    results['keys'] += get_keys(page.get('Contents', []))

            return results
        except Exception as ex:
            logger.info(str(ex))
            raise MlChainError(str(ex), code="S009", status_code=500)

    def listdir(self, path, bucket=None):
        bucket = bucket or self.bucket
        if bucket is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        try:
            results = self.list(bucket_name=bucket, prefix=path)
            return {'files': results['keys'], 'dirs': results['prefixes']}
        except Exception as ex:
            logger.info(str(ex))
            raise MlChainError(str(ex), code="S010", status_code=500)

    def delete(self, path, bucket=None):
        bucket = bucket or self.bucket
        if bucket is None:
            raise MlChainError("bucket can't be None", code="S000", status_code=500)
        try:
            self.client.remove_object(bucket, path)
        except Exception as ex:
            logger.info(str(ex))
            raise MlChainError(str(ex), code="S011", status_code=500)


from setuptools import setup, find_packages
import os

tests_require = ['zope.testing', 'Products.PloneTestCase']

version = '0.2.0'

setup(name='collective.powertoken.workflow',
      version=version,
      description="Workflow add-ons for collective.powertoken support for Plone",
      long_description=open("README.txt").read() + "\n" +
                       open(os.path.join("docs", "HISTORY.txt")).read(),
      # Get more strings from
      # http://pypi.python.org/pypi?:action=list_classifiers
      classifiers=[
        "Framework :: Plone",
        "Framework :: Plone :: 3.3",
        "Framework :: Plone :: 4.0",
        "Framework :: Plone :: 4.1",
        "Framework :: Zope2",
        "Framework :: Zope3",
        "Development Status :: 4 - Beta",
        "Intended Audience :: Developers",
        "Programming Language :: Python",
        ],
      keywords='plone security token plonegov workflow',
      author='RedTurtle Technology',
      author_email='sviluppoplone@redturtle.it',
      url='http://plone.org/products/collective.powertoken.core',
      license='GPL',
      packages=find_packages(exclude=['ez_setup']),
      namespace_packages=['collective', 'collective.powertoken'],
      include_package_data=True,
      zip_safe=False,
      install_requires=[
          'setuptools',
          'collective.powertoken.core>=0.3.0',
      ],
      tests_require=tests_require,
      extras_require=dict(tests=tests_require),
      entry_points="""
      [z3c.autoinclude.plugin]
      target = plone
      """,
      )


import pygame
pygame.init()

# Constants
BG_COLOR = 'black'
FONT_COLOR = 'white'
FONT_SIZE = 20
TOPLEFT = (10,30)
FONT = None  # None for pygame default font
ANTIALIAS = True

# This method converts list of strings to a multi-line overlay,
# with rect at position topleft = (x,y) = TOPLEFT
# Must input as a list of strings even if single line

def debug(multistring_list, x=TOPLEFT[0], y=TOPLEFT[1], font_size=FONT_SIZE):
    f = pygame.font.Font(FONT, font_size)
    display_surf = pygame.display.get_surface()
    line_height = pygame.font.Font.get_linesize(f)

    for index, line in enumerate(multistring_list):
        debug_surf = f.render(str(line), ANTIALIAS, FONT_COLOR)
        position = (x, y + index*line_height)
        debug_rect = debug_surf.get_rect(topleft=position)
        pygame.draw.rect(display_surf, BG_COLOR, debug_rect)
        display_surf.blit(debug_surf, debug_rect)


import chardet
import os
import math
from pathlib import Path
import nltk
nltk.download('stopwords')
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from collections import Counter

# Detect the encoding of a file
def find_encoding(fname):
    try:
        with open(fname, 'rb') as f:
            result = chardet.detect(f.read())
            charenc = result['encoding']
            return charenc
    except Exception:
        return 'utf-8'

# Data pre-processing: stopwords removal and removal of any leading numbers from the string
def preprocess(document_text):
    stopwords_set = set(stopwords.words('english'))
    terms = [term.lower() for term in document_text.strip().split()[1:] if term.lower() not in stopwords_set]
    return terms

# Read the input file, preprocess the data, build the vocabulary, and construct the inverted index.
def load_data():
    vocab = Counter()
    documents = []
    inverted_index = {}

    directory = Path('Qdatalc/')
    file_names = [
        directory / 'indexlc.txt',
        directory / 'Qindexlc.txt',
    ]

    data_directory = directory / 'data'
    file_names.extend(data_directory.rglob('*'))

    for filename in file_names:
        my_encoding = find_encoding(filename)

        with open(filename, 'r', encoding=my_encoding) as f:
            lines = f.readlines()

        for index, line in enumerate(lines):
            tokens = preprocess(line)
            documents.append(tokens)
            for token in tokens:
                vocab[token] += 1
                inverted_index.setdefault(token, []).append(index)

    vocab = dict(sorted(vocab.items(), key=lambda item: item[1], reverse=True))
    save_data(vocab, documents, inverted_index)

# Save the vocabulary, IDF values, documents, and inverted index into separate text files
def save_data(vocab, documents, inverted_index):
    output_dir = Path('tf-idf_lc')
    output_dir.mkdir(exist_ok=True)

    # Save the vocab in a text file
    with open(output_dir / 'vocab_lc.txt', 'w', encoding=find_encoding('tf-idf_lc/vocab_lc.txt')) as f:
        f.write('\n'.join(vocab.keys()))

    # Save the idf values in a text file
    with open(output_dir / 'idf-values_lc.txt', 'w', encoding=find_encoding('tf-idf_lc/idf-values_lc.txt')) as f:
        f.write('\n'.join(str(vocab[key]) for key in vocab.keys()))

    # Save the documents in a text file
    with open(output_dir / 'documents_lc.txt', 'w', encoding=find_encoding('tf-idf_lc/documents_lc.txt')) as f:
        f.write('\n'.join(' '.join(document) for document in documents))

    # Save the inverted index in a text file
    with open(output_dir / 'inverted-index_lc.txt', 'w', encoding=find_encoding('tf-idf_lc/inverted-index_lc.txt')) as f:
        for key, value in inverted_index.items():
            f.write(f"{key}\n")
            f.write(' '.join(str(doc_id) for doc_id in value))
            f.write('\n')

# Load the vocabulary and IDF values from the text files
def load_vocab():
    vocab = {}
    with open('tf-idf_lc/vocab_lc.txt', 'r', encoding='utf-8') as f:
        vocab_terms = f.readlines()
    with open('tf-idf_lc/idf-values_lc.txt', 'r', encoding='utf-8') as f:
        idf_values = f.readlines()

    for (term, idf_value) in zip(vocab_terms, idf_values):
        vocab[term.strip()] = int(idf_value.strip())
    return vocab

# Load the preprocessed documents from the text file
def load_documents():
    with open('tf-idf_lc/documents_lc.txt', 'r', encoding='utf-8') as f:
        documents = [document.strip().split() for document in f.readlines()]
    return documents

# Load the inverted index from a text file
def load_inverted_index():
    inverted_index = {}
    with open('tf-idf_lc/inverted-index_lc.txt', 'r', encoding='utf-8') as f:
        inverted_index_terms = f.readlines()

    for row_num in range(0, len(inverted_index_terms), 2):
        term = inverted_index_terms[row_num].strip()
        documents = inverted_index_terms[row_num + 1].strip().split()
        inverted_index[term] = documents
    return inverted_index

# Calculate term frequency
def get_tf_dictionary(term):
    tf_values = {}
    if term in inverted_index:
        for document in inverted_index[term]:
            if document not in tf_values:
                tf_values[document] = 1
            else:
                tf_values[document] += 1

    for document in tf_values:
        tf_values[document] /= len(documents[int(document)])

    return tf_values

# Calculate inverse document frequency
def get_idf_value(term):
    return math.log(len(documents) / vocab_idf_values[term])

# Extract heading part
def fetch_text_by_index(file_path, index):
    if index is None:
        return None  # Return None if line number is None

    with open(file_path, 'r', encoding=find_encoding(file_path)) as file:
        lines = file.readlines()
        line = lines[index]
        parts = line.strip().split('.', 1)
        return parts[1].strip()

# Extract URL of the corresponding heading
def fetch_data_by_line(file_path, line_number):
    with open(file_path, 'r', encoding=find_encoding(file_path)) as file:
        lines = file.readlines()
        return lines[line_number].strip()

# Calculate the relevance scores for the given query terms and retrieve the matching documents
def calculate_sorted_order_of_documents(query_terms):
    potential_documents = {}
    for term in query_terms:
        if term in vocab_idf_values and vocab_idf_values[term] != 0:
            tf_values_by_document = get_tf_dictionary(term)
            idf_value = get_idf_value(term)
            for document in tf_values_by_document:
                if document not in potential_documents:
                    potential_documents[document] = tf_values_by_document[document] * idf_value
                potential_documents[document] += tf_values_by_document[document] * idf_value

    if not potential_documents:
        return []
    else:
        for document in potential_documents:
            potential_documents[document] /= len(query_terms)

        potential_documents = dict(sorted(potential_documents.items(), key=lambda item: item[1], reverse=True))

        sorted_documents = []

        heading = 'Qdatalc/indexlc.txt'
        link = 'Qdatalc/Qindexlc.txt'

        for doc_index in potential_documents:
            index=int(doc_index)-1
            heading_text = fetch_text_by_index(heading, index)
            if heading_text is None:
                continue
            url_text = fetch_data_by_line(link, index)
            sorted_documents.append((doc_index, heading_text, url_text))

        return sorted_documents

# Load the data if not already loaded
def load_and_process_data():
    if not os.path.exists('tf-idf_lc/vocab_lc.txt') or not os.path.exists('tf-idf_lc/idf-values_lc.txt') or not os.path.exists(
            'tf-idf_lc/documents_lc.txt') or not os.path.exists('tf-idf_lc/inverted-index_lc.txt'):
        load_data()
    vocab_idf_values = load_vocab()
    documents = load_documents()
    inverted_index = load_inverted_index()
    return vocab_idf_values, documents, inverted_index

vocab_idf_values, documents, inverted_index = load_and_process_data()


# from __future__ import absolute_import
# from __future__ import print_function
import os
import sys
import gym
import subprocess
from gym import spaces, logger
import numpy as np
import time

# we need to import python modules from the $SUMO_HOME/tools directory
if 'SUMO_HOME' in os.environ:
    tools = os.path.join(os.environ['SUMO_HOME'], 'tools')
    sys.path.append(tools)
else:
    sys.exit("please declare environment variable 'SUMO_HOME'")
from sumolib import checkBinary
# import traci

controlled_lights = [{'name': 'gneJ14', 'curr_phase': 0, 'num_phases': 6}]
uncontrolled_lights = [{'name': 'nw', 'curr_phase': 0, 'num_phases': 4},
                       {'name': 'se', 'curr_phase': 0, 'num_phases': 4},
                       {'name': 'sw', 'curr_phase': 0, 'num_phases': 4}]
important_roads = ['gneE16', 'gneE59', 'gneE13']
load_options = ["-c", "PoundSign/PoundSign.sumocfg", "-t", "--remote-port", "1337"]

class SumoEnv(gym.Env):
    def __init__(self, steps_per_episode, render):
        super(SumoEnv, self).__init__()
        # self.scenario_name = scenario_name
        self.steps_per_episode = steps_per_episode
        self.is_done = False
        self.current_step = 0

        self.reward_range = (-float('inf'), float('inf'))  # HARDCODE
        self.action_space = spaces.Discrete(5)  # HARDCODE
        self.observation_space = spaces.Box(low=0, high=float('inf'), shape=np.array([6]), dtype=np.float32)  # HARDCODE

        # Start sumo simulation
        self.noguiBinary = checkBinary('sumo')
        self.guiBinary = checkBinary('sumo-gui')
        self.current_binary = self.guiBinary if render else self.noguiBinary
        self.sumobin = subprocess.Popen([self.current_binary] + load_options)
        time.sleep(1)  # Make sure that the binary opens before moving on TODO: Find a better way to wait for the binary to open

        # TODO: Start traci client
        self.sumo = subprocess.Popen(['./sim_interface'], stdin=subprocess.PIPE, text=True, universal_newlines=True, stdout=subprocess.PIPE) # , stdout=subprocess.PIPE
        self._send_command('connect')
        assert(self.sumo.stdout.readline().strip() == '1')
        print('Connected')

    def reset(self):
        print('reset')
        # self._send_command('load')
        self.current_step = 0
        self.is_done = False

        for i in range(10):
            print('hi')
            self._send_command('step')
            print(self.sumo.stdout.readline().strip())
            time.sleep(1)

        return self._next_observation()

    def _send_command(self, command):
        self.sumo.stdin.write(command + '\n')
        self.sumo.stdin.flush()

    def _next_observation(self):
        obs = []
        # TODO: Get Data
        # wait_counts, road_counts = self._get_road_waiting_vehicle_count()
        # HARDCODE
        # for lane in important_roads:
        #     obs.append(road_counts[lane])
        #     obs.append(wait_counts[lane])

        return np.array(obs)

    def step(self, action):

        self._take_action(action)

        self._send_command('step')

        self.current_step += 1

        obs = self._next_observation()
        reward = self._get_reward()

        if self.is_done:
            logger.warn("You are calling 'step()' even though this environment has already returned done = True. "
                        "You should always call 'reset()' once you receive 'done = True' "
                        "-- any further steps are undefined behavior.")
            reward = 0.0

        if self.current_step + 1 == self.steps_per_episode:
            self.is_done = True

        return obs, reward, self.is_done, {}

    def _get_reward(self):
        # TODO: Get data
        # road_waiting_vehicles_dict, _ = self._get_road_waiting_vehicle_count()
        reward = 0.0

        # for (road_id, num_vehicles) in road_waiting_vehicles_dict.items():
        #     if road_id in important_roads:
        #         reward -= num_vehicles

        return reward

    def _take_action(self, action):
        if action != controlled_lights[0]['curr_phase']:
            controlled_lights[0]['curr_phase'] = action
            # TODO: Change tl phase in sumo
            # self._set_tl_phase(controlled_lights[0]['name'], action)

    # def _get_road_waiting_vehicle_count():
    #     wait_counts = {'gneE16': 0, 'gneE59': 0, 'gneE13': 0}
    #     road_counts = {'gneE16': 0, 'gneE59': 0, 'gneE13': 0}
    #     vehicles = traci.vehicle.getIDList()
    #     for v in vehicles:
    #         road = traci.vehicle.getRoadID(v)
    #         if road in wait_counts.keys():
    #             if traci.vehicle.getWaitingTime(v) > 0:
    #                 wait_counts[road] += 1
    #             road_counts[road] += 1
    #     return wait_counts, road_counts

    # def _set_tl_phase(intersection_id, phase_id):
    #     traci.trafficlight.setPhase(intersection_id, phase_id)

    def render(self, mode='human'):
        self.current_binary = self.guiBinary


bl_info = {
    "name" : "EPIC GS data Processor",
    "author" : "David C. King",
    "version" : (2, 79, 0),
    "location" : "View3D > Tools > Create",
    "description" : "Process EPIC.GS data files into full animations: 1 object per cell",
    "tracker_url" : "https://github.com/meekrob/c-blenderi/issues",
    "warning" : "",
    "wiki_url" : "https://github.com/meekrob/c-blenderi/wiki",
    "category" : "3D View"
}

import bpy
from bpy.props import StringProperty
from bpy.props import CollectionProperty
import sys

from mathutils import Vector

from epic_gs_data_addon import trace_lineage

def find_cell_or_parent(cellname):
    while bpy.data.objects.find(cellname) < 0:
        cellname = cellname[:-1]
        if not cellname:
            return -1

    return bpy.data.objects.find(cellname)

# mball elements #######
##object as returned by mball.elements.new:
##------------------------
##e.g.
#mball= bpy.data.metaballs.new("name")
#el = mball.elements.new()

def mball_el_translate_x(el, x):
    mball_translate(el,Vector((x,0,0)))

def mball_el_translate_y(el, y):
    mball_translate(el,Vector((0,y,0)))

def mball_el_translate_z(el, z):
    mball_translate(el,Vector((0,0,z)))

def mball_el_translate(el, vec):
    el.co = el.co + vec

# mball elements #######

def swap_obj_locations(obj1, obj2):
    loc = obj1.location.copy()
    obj1.location = obj2.location
    obj2.location = loc

def set_active_object(obj, context=bpy.context):
    context.scene.objects.active = obj

def select_only_and_make_active(obj,  context=bpy.context):
    set_active_object(obj, context)
    select_only(obj)

def select_by_prefix(prefix):
    for obj in bpy.context.scene.objects:
        if obj.name.startswith(prefix): obj.select = True

def assign_material_to_selected(material):
    assign_material_to_objects(material, bpy.context.selected_objects)

def assign_material_to_objects(material, objects):
    for obj in objects:
        obj.active_material = material

def assign_parent_to_selected(parent):
    assign_parent_to_objects(parent, bpy.context.selected_objects)

def assign_parent_to_objects(parent, objects):
    for obj in objects:
        obj.parent = parent

def scale_value(inval):
    MINV = 20000
    MAXV = 90000
    margin = MAXV - MINV
    percent_max = (inval - MINV) / margin
    return percent_max

def select_only(obj):
    bpy.ops.object.select_all(action='DESELECT')
    obj.select = True
    return obj

def dup_obj_return_new(obj):
    select_only(obj)
    bpy.ops.object.duplicate() # the duplicate becomes the only selected object
    new_obj = bpy.context.selected_objects[0]
    return new_obj

DIVISIONS_ONLY = True

class OBJECT_OT_epic(bpy.types.Operator):
    """Epic processing button"""
    bl_label = "Process file"
    bl_idname = "object.epic"
    bl_options = {'REGISTER'}

    run_this_shit = False

    def execute(self, context):
        if context.scene.render.engine != 'CYCLES':
            context.scene.render.engine = 'CYCLES'

        if context.scene.epic_gs_filename == '':
            self.report({'ERROR_INVALID_INPUT'}, "Need to specify a file")
            return {'CANCELLED'}

        self.report(
            {'INFO'},
            """Processing context.scene.epic_gs_filename: %s,\n context.scene.embryo_parent: %s,\n context.scene.default_cell_template: %s,\n context.scene.default_cell_material: %s""" %
            (context.scene.epic_gs_filename, context.scene.embryo_parent, context.scene.default_cell_template, context.scene.default_cell_material)
        )
        infilename = context.scene.epic_gs_filename
        # key the cell divisions only
        key_divisions_only = context.scene.key_divisions_only

        # set up the scene
        if not context.scene.default_cell_template:
            # add an object
            bpy.ops.mesh.primitive_uv_sphere_add(size=1, view_align=False, enter_editmode=False, location=(0, 0, 0), layers=layers_tuple())
            context.scene.default_cell_template = context.object

        cell_template = bpy.data.objects.get( context.scene.default_cell_template.name )

        if context.scene.E_cell_template:
            e_cell_template = bpy.data.objects.get( context.scene.E_cell_template.name )
        else:
            e_cell_template = cell_template

        if context.scene.MS_cell_template:
            ms_cell_template = bpy.data.objects.get( context.scene.MS_cell_template.name )
        else:
            ms_cell_template = cell_template

        if context.scene.P_cell_template:
            p_cell_template = bpy.data.objects.get( context.scene.P_cell_template.name )
        else:
            p_cell_template = p_cell_template

        # process data
        bpy.context.scene.frame_start = 1
        bpy.context.scene.frame_end = 2000
        min_time, max_time, big_data = trace_lineage.load_gs_epic_file(infilename)
        for celltype in trace_lineage.ALL_END_PNTS:
            current_cell_type_char = ''
            cell_type_char = celltype[0]
            print("Doing", celltype, file=sys.stderr)
            print("==============", file=sys.stderr)
            ### E cells
            if celltype.startswith('E'):
                new_cell = dup_obj_return_new(e_cell_template)
                new_mat = bpy.context.scene.e_cell_material
            ### MS cells
            elif celltype.startswith('MS'):
                new_cell = dup_obj_return_new(ms_cell_template)
                new_mat = bpy.context.scene.ms_cell_material
            ### P --> Z cells
            elif celltype.startswith('P') or celltype.startswith('Z'):
                new_cell = dup_obj_return_new(p_cell_template)
                new_mat = bpy.context.scene.p_cell_material
            else:
                new_cell = dup_obj_return_new(cell_template)
                new_mat = bpy.context.scene.default_cell_material

            new_cell.name = celltype
            new_cell.parent = context.scene.embryo_parent
            new_cell.active_material = new_mat
            do_thing(new_cell, celltype, min_time, max_time, big_data, key_divisions_only)

        # set active object to parent
        if context.scene.embryo_parent:
           set_active_object( context.scene.embryo_parent, context )
           select_only( context.scene.embryo_parent )

        return {'FINISHED'}
import time
NTICKS = 4

def do_thing(object, end_cell, min_time, max_time, big_data, key_divisions_only = True):
    last_cell = ''
    timer = time.time()
    for timepnt, row, found_cell in trace_lineage.search_gs_epic_file([end_cell], min_time, max_time, big_data):
        frame = timepnt *12
        print("%s: at cell division" % end_cell, str(timepnt) + ",", last_cell, "==>", found_cell, "in %.4f seconds" % (time.time() - timer), file=sys.stderr)

        synchronize = False
        if frame % 512 == 0:
            synchronize = True
        if timepnt == max_time:
            synchronize = True

        # cell divisions determined by "found_cell" being different from the last iteration, since it traverses a lineage tree in the search
        in_a_cell_division = False
        if found_cell != last_cell:
            print("%s: =========== AT CELL DIVISION ===========" % end_cell, file=sys.stderr)
            ticker = NTICKS
            timer = time.time()
            in_a_cell_division = True

        # always insert keyframes at synchronization points
        if synchronize:
            print("%s: =========== key_divisions_only %s, in_a_cell_division %s. SYNCHRONIZING ==========="
                        % (end_cell, key_divisions_only, in_a_cell_division),
                        file=sys.stderr
            )
            pass
        # skip intermediate keyframes
        elif key_divisions_only and not in_a_cell_division:
            print("%s: =========== key_divisions_only %s, in_a_cell_division %s. continuing ==========="
                        % (end_cell, key_divisions_only, in_a_cell_division),
                        file=sys.stderr
            )
            continue

        last_cell = found_cell

        if not row: continue

        bpy.context.scene.frame_current = frame
        object.location = (row['x']/100,row['y']/100,row['z']/10)
        size = row['size']/200
        object.scale = (size,size,size)
        object.keyframe_insert('scale')
        object.keyframe_insert('location')
        # do something with the material
        curMat = object.active_material
        #if 'ecdf' in row:
        if False:
            if False:
                curMat.node_tree.nodes['ColorRamp'].inputs[0].default_value = row['ecdf']
            else:
                curMat.node_tree.nodes['ColorRamp'].inputs[0].default_value = scale_value(row['value'])
            curMat.node_tree.nodes['ColorRamp'].inputs[0].keyframe_insert("default_value", frame = frame )

class OBJECT_OT_custompath(bpy.types.Operator):
    #bl_label = "Select epic.gs data file"
    bl_label = "Process EPIC.GS file"
    bl_idname = "object.custom_path"
    __doc__ = ""

    bl_options = {'REGISTER'}

    filename_ext = "*.csv"
    filter_glob = StringProperty(
        name = "Filename",
        description = "File to Process",
        default=filename_ext, options={'HIDDEN'}
    )

    filepath = StringProperty(
        name="File Path",
        description="Filepath used for importing txt files",
        maxlen= 1024,
        default= "")

    def execute(self, context):
        print("FILEPATH %s"%self.properties.filepath)#display the file name and current path
        context.scene.epic_gs_filename = self.properties.filepath
        return {'FINISHED'}

    def invoke(self, context, event):
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}

class file_processing_panel(bpy.types.Panel):
    """File processing panel"""
    bl_label = "Epic.gs.data processer"
    bl_idname = "OBJECT_PT_file_process"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_category = "Create"
    bl_context = "objectmode"

    def draw(self, context):
        #obj = bpy.context.scene.objects.get("embryo_parent")
        scene = bpy.context.scene

        layout = self.layout
        row = layout.row()
        row.label(text="Open and process an epic.gs.data file:")
        row = layout.row(align=True)
        row.prop( context.scene, "epic_gs_filename", text="")
        p = row.operator( OBJECT_OT_custompath.bl_idname, text="", icon = "FILESEL")
        p.filepath = context.scene.epic_gs_filename

        row = layout.row()
        row.label(text="Setup:")

        row = layout.row()
        row.label(text="Smooth animation")
        row.prop(bpy.context.scene, "key_divisions_only", text="")

        # empty parent for everything
        row = layout.row()
        row.label(text="Embryo parent")
        row.prop_search(bpy.context.scene, "embryo_parent", bpy.context.scene, "objects", text="")

        # cell type object templates
        row = layout.row()
        row.label(text="Object template for cell types:")

        # default
        row = layout.row()
        split = row.split()
        col = split.column()
        col.label(text="Mesh template")
        col.prop_search(bpy.context.scene, "default_cell_template", bpy.context.scene, "objects", text="")
        col = split.column()
        col.label(text="Material template")
        col.prop_search(scene, "default_cell_material", bpy.data, "materials", text="")

        # E cell row
        row = layout.row()
        split = row.split()
        col = split.column()
        col.label(text="E cell:")
        col.prop(bpy.context.scene, "E_cell_template", text="")
        col = split.column()
        col.label(text="E cell material")
        col.prop_search(scene, "e_cell_material", bpy.data, "materials", text="")

        # MS cell row
        row = layout.row()
        split = row.split()
        col = split.column()
        col.label(text="MS cell:")
        col.prop_search(bpy.context.scene, "MS_cell_template", bpy.context.scene, "objects", text="")
        col = split.column()
        col.label(text="MS cell material")
        col.prop_search(scene, "ms_cell_material", bpy.data, "materials", text="")

        # P/Z cell row
        row = layout.row()
        split = row.split()
        col = split.column()
        col.label(text="P/Z cells:")
        col.prop_search(bpy.context.scene, "P_cell_template", bpy.context.scene, "objects", text="")
        col = split.column()
        col.label(text="P/Z cell material")
        col.prop_search(scene, "p_cell_material", bpy.data, "materials", text="")

        # Functions
        row = layout.row()
        row.label(text="Operations:")
        row = layout.row()
        p = row.operator(OBJECT_OT_epic.bl_idname)

def process_epic_gs_button(self, context):
    self.layout.operator('file.select_all_toggle',
        OBJECT_OT_custompath.bl_idname,
        icon = "FILESEL"
    )

def layers_tuple(selected=0):
    layer_list = [False] * 20
    layer_list[0] = True
    return tuple(layer_list)

# registration
def register():
    print("-register-", file=sys.stderr)

    """
    # While trying to activate as an add-on
    # AttributeError: '_RestrictContext' object has no attribute 'scene'
    if bpy.context.scene.objects.find("embryo_parent") < 0:
        bpy.ops.object.empty_add(
            type='PLAIN_AXES',
            view_align=False,
            location=(0, 0, 0),
            layers=layers_tuple()
        )
        bpy.context.object.name = "embryo_parent"
    """
    bpy.types.Scene.key_divisions_only = bpy.props.BoolProperty(
        name = "Key Divisions Only",
        default = True,
        description = "Only insert keyframes at divisions (smoother animation)"
    )

    bpy.types.Scene.epic_gs_filename = bpy.props.StringProperty(
        name = "Epic filename",
        default = "",
        description = "Epic gs name"
    )

    bpy.types.Scene.embryo_parent = bpy.props.PointerProperty(
        type=bpy.types.Object,
        name = "Embryo object parent",
        description = "All added objects are parented to this object",
        poll = empty_check_function
    )

    bpy.types.Scene.default_cell_template = bpy.props.PointerProperty(
        type=bpy.types.Object,
        name = "Default object to use for all cells",
        description = "This object will be cloned to produce any cells",
        poll = mesh_check_function
    )

    bpy.types.Scene.C_cell_template = bpy.props.PointerProperty(
        type=bpy.types.Object,
        name = "C Cell Object template",
        description = "This object will be cloned to produce all of the C cells in the data file",
        poll = mesh_check_function

    )
    bpy.types.Scene.D_cell_template = bpy.props.PointerProperty(
        type=bpy.types.Object,
        name = "D Cell Object template",
        description = "This object will be cloned to produce all of the D cells in the data file",
        poll = mesh_check_function

    )
    bpy.types.Scene.E_cell_template = bpy.props.PointerProperty(
        type=bpy.types.Object,
        name = "E Cell Object template",
        description = "This object will be cloned to produce all of the E cells in the data file",
        poll = mesh_check_function
    )
    bpy.types.Scene.MS_cell_template = bpy.props.PointerProperty(
        type=bpy.types.Object,
        name = "MS Cell Object template",
        description = "This object will be cloned to produce all of the MS cells in the data file",
        poll = mesh_check_function
    )
    bpy.types.Scene.P_cell_template = bpy.props.PointerProperty(
        type=bpy.types.Object,
        name = "P-->Z Cell Object template",
        description = "This object will be cloned to produce all of the P and Z cells in the data file",
        poll = mesh_check_function

    )
    bpy.types.Scene.default_cell_material = bpy.props.PointerProperty(
        type=bpy.types.Material,
        name = "Default cell material",
        description = "This material will be assigned to all cells",
        poll = material_check_function
    )

    bpy.types.Scene.e_cell_material = bpy.props.PointerProperty(
        type=bpy.types.Material,
        name = "E cell material",
        description = "This material will be assigned to all E cells",
        poll = material_check_function
    )

    bpy.types.Scene.ms_cell_material = bpy.props.PointerProperty(
        type=bpy.types.Material,
        name = "E cell material",
        description = "This material will be assigned to all E cells",
        poll = material_check_function
    )

    bpy.types.Scene.p_cell_material = bpy.props.PointerProperty(
        type=bpy.types.Material,
        name = "P/Z cell material",
        description = "This material will be assigned to all P and Z cells",
        poll = material_check_function
    )

    bpy.utils.register_module(__name__)
    #bpy.utils.register_class(OBJECT_OT_epic)
    #bpy.utils.register_class(OBJECT_OT_custompath)
    #bpy.utils.register_class(file_processing_panel)
    bpy.types.INFO_MT_mesh_add.append(process_epic_gs_button)

def mesh_check_function(self, obj):
    return obj.type == 'MESH'

def empty_check_function(self, obj):
    return obj.type == 'EMPTY'

def material_check_function(self, obj):
    return obj.type in ['SURFACE', 'WIRE', 'VOLUME', 'HALO'] # possible "material" types

def unregister():
    bpy.utils.unregister_module(__name__)
    #bpy.utils.unregister_class(OBJECT_OT_epic)
    #bpy.utils.unregister_class(OBJECT_OT_custompath)
    #bpy.utils.unregister_class(file_processing_panel)
    bpy.types.INFO_MT_mesh_add.remove(process_epic_gs_button)

    del bpy.types.Scene.key_divisions_only

    del bpy.types.Scene.epic_gs_filename
    del bpy.types.Scene.embryo_parent

    del bpy.types.Scene.default_cell_template
    del bpy.types.Scene.default_cell_material

    del bpy.types.Scene.C_cell_template
    del bpy.types.Scene.D_cell_template

    del bpy.types.Scene.E_cell_template
    del bpy.types.Scene.e_cell_material

    del bpy.types.Scene.MS_cell_template
    del bpy.types.Scene.ms_cell_material

    del bpy.types.Scene.P_cell_template
    del bpy.types.Scene.p_cell_material

if __name__ == "__main__":
    register()


import sys
from collections import deque
from itertools import permutations

dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]

def bfs(start, end):
    targetX, targetY = end
    visited = [[0 for _ in range(W)] for _ in range(H)]

    q = deque()
    q.append((start, 0))

    while q:
        (x, y), depth = q.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if nx < 0 or nx >= H or ny < 0 or ny >= W:
                continue
            if room[nx][ny] == "x":
                continue
            if visited[nx][ny] == 1:
                continue
            if nx == targetX and ny == targetY:
                return depth + 1
            visited[nx][ny] = 1
            q.append(((nx,ny), depth+1))

    return -1

while True:
    W, H = map(int, sys.stdin.readline().split())

    if W == 0 and H == 0:
        break

    room = [list(input()) for _ in range(H)]
    dirties = []

    for i in range(H):
        for j in range(W):
            if room[i][j] == 'o':
                robot = (i,j)
            if room[i][j] == '*':
                dirties.append((i,j))

    numVertex = len(dirties) + 1
    adjArr = [[0 for _ in range(numVertex)] for _ in range(numVertex)]
    flag = False

    for i in range(len(dirties)):
        for j in range(i+1, len(dirties) + 1):
            if i == 0:
                dist = bfs(robot, dirties[j-1])
            else:
                dist = bfs(dirties[i-1], dirties[j-1])

            if dist == -1:
                flag = True
                break

            adjArr[i][j] = dist
            adjArr[j][i] = dist

    if flag:
        print(-1)
        break

    comb = list(permutations([i+1 for i in range(len(dirties))], len(dirties)))

    answer = float('inf')
    for i in range(len(comb)):
        path = comb[i]
        sum = 0
        start = 0
        for j in range(len(path)):
            sum += adjArr[start][path[j]]
            start = path[j]
        answer = min(answer, sum)
    print(answer)


import requests
import json
import time
import urllib.request
from PIL import Image
import datetime
def todayAt (hr, minutes=0, sec=0, micros=0):
    now_time = datetime.datetime.now()
    return now_time.replace(hour=hr, minute=minutes, second=sec, microsecond=micros)
while datetime.datetime.now() < todayAt (16,10):
    r = requests.get('https://dog.ceo/api/breeds/image/random')
    if r.status_code == 200:
        try:
            pretty_json =json.dumps(r.json(),indent=2)
        except:
            print("not a json")
            exit()
        print(f'Pretty: {pretty_json}')
    else:
        print(f"error {r.status_code}")
    msg= r.json()
    urllib.request.urlretrieve(
      msg['message'],
       "gfg.png")
    """img = Image.open("gfg.png")
    img.show()
    img.close()"""
    with Image.open('gfg.png') as test_image:
        test_image.show()
        time.sleep(3)