import tensorflow as tf
from datetime import datetime
import pytz
from src import utils
import numpy as np
import matplotlib.pyplot as plt
import io

class Time2Vec(tf.keras.layers.Layer):
    def __init__(self, output_dims, name="time2vec"):
        super(Time2Vec, self).__init__(name=name)
        self.output_dims = output_dims

    def build(self, input_shape):
        w_init = tf.random_normal_initializer()
        b_init = tf.zeros_initializer()
        # i=0
        self.w0 = tf.Variable(initial_value=w_init(shape=(input_shape[-1], 1),dtype=tf.float32), name="Time2Vec_w0", trainable=True)
        self.b0 = tf.Variable(initial_value=b_init(shape=(1),dtype=tf.float32), name="Time2Vec_b0", trainable=True)
        # i!=0
        self.wi = tf.Variable(initial_value=w_init(shape=(input_shape[-1], self.output_dims-1),dtype=tf.float32), name="Time2Vec_wi", trainable=True)
        self.bi = tf.Variable(initial_value=b_init(shape=(self.output_dims-1),dtype=tf.float32), name="Time2Vec_bi", trainable=True)

    def call(self, input_tensor):
        v0 = tf.linalg.matmul(input_tensor, self.w0) + self.b0
        v1 = tf.math.sign(tf.linalg.matmul(input_tensor, self.wi) + self.bi)
        return tf.concat([v0, v1], axis=-1)

class MultiHeadAttention(tf.keras.layers.Layer):
    def __init__(self, d_model, num_heads, name="multi_head_attention"):
        super(MultiHeadAttention, self).__init__(name=name)
        self.num_heads = num_heads
        self.d_model = d_model
        # 정확히 분배되는지 확인
        assert d_model % self.num_heads == 0

        self.depth = d_model // self.num_heads
        self.query_dense = tf.keras.layers.Dense(units=d_model)
        self.key_dense = tf.keras.layers.Dense(units=d_model)
        self.value_dense = tf.keras.layers.Dense(units=d_model)

        self.dense = tf.keras.layers.Dense(units=d_model)

    def split_heads(self, inputs, batch_size):
        inputs = tf.reshape(inputs, shape=(batch_size, -1, self.num_heads, self.depth))
        return tf.transpose(inputs, perm=[0, 2, 1, 3])

    def call(self, inputs):
        query, key, value = inputs['query'], inputs['key'], inputs['value']
        batch_size = tf.shape(query)[0]

        query = self.query_dense(query)
        key = self.key_dense(key)
        value = self.value_dense(value)

        query = self.split_heads(query, batch_size)
        key = self.split_heads(key, batch_size)
        value = self.split_heads(value, batch_size)

        scaled_attention, _ = scaled_dot_product_attention(query, key, value)
        scaled_attention = tf.transpose(scaled_attention, perm=[0, 2, 1, 3])
        concat_attention = tf.reshape(scaled_attention, (batch_size, -1, self.d_model))

        outputs = self.dense(concat_attention)
        return outputs

def scaled_dot_product_attention(query, key, value):
    # Get Q * K
    matmul_qk = tf.linalg.matmul(query, key, transpose_b=True)
    # For Scaling
    depth = tf.cast(tf.shape(key)[-1], tf.float32)
    logits = matmul_qk / tf.math.sqrt(depth)
    # Get Attention Weights
    attention_weights = tf.nn.softmax(logits, axis=-1)
    outputs = tf.linalg.matmul(attention_weights, value)
    return outputs, attention_weights

class auto_module(tf.keras.layers.Layer):
    def __init__(self, time_size, hidden_size, dropout, recurrent_dropout, name="auto_module"):
        super(auto_module, self).__init__(name=name)
        self.time_size = time_size
        self.decoder_first_state_dense = tf.keras.layers.Dense(hidden_size, activation='tanh', name="Decoding_first_state_Dense")
        self.decoder_output_mu_dense = tf.keras.layers.Dense(1, activation="sigmoid", name="Decoding_mu_Output")
        self.decode_cell = tf.keras.layers.SimpleRNNCell(hidden_size, dropout=dropout, recurrent_dropout=recurrent_dropout, name="Decoding_RNN_Cell")

    def call(self, input_tensor):
        out_collect = []
        h_state = self.decoder_first_state_dense(input_tensor)
        for i in range(self.time_size):
            # Get output
            x_out = self.decoder_output_mu_dense(h_state)
            # Next Cell
            rnn_out, h_state = self.decode_cell(inputs=x_out, states=h_state)
            # Collect
            out_collect.append(x_out)
        x_out = self.decoder_output_mu_dense(h_state)
        out_collect.append(x_out)
        # Stack
        out_collect = tf.stack(out_collect[1:])
        out_collect = tf.transpose(out_collect, [1, 0, 2])
        return out_collect

def attention_module(time_len, dims, num_heads, dropout, name="Attention"):
    inputs = tf.keras.Input(shape=(time_len,dims), name="inputs")
    attention = MultiHeadAttention(dims, num_heads, name="attention")({'query': inputs, 'key': inputs, 'value': inputs})
    attention = tf.keras.layers.Dropout(rate=dropout)(attention)
    attention = tf.keras.layers.LayerNormalization(epsilon=1e-6)(inputs + attention)
    return tf.keras.Model(inputs=inputs, outputs=attention, name=name)

def encoder(time_size, dims, hidden_size, num_heads, latent_length, dropout, recurrent_dropout, name="Encoder"):
    inputs = tf.keras.Input(shape=(time_size,dims), name="inputs")
    # Init
    encode_cell = tf.keras.layers.SimpleRNNCell(hidden_size, dropout=dropout, recurrent_dropout=recurrent_dropout, name="Ecoding_RNN_Cell")
    encode_rnn = tf.keras.layers.RNN(encode_cell, return_state=True, name="RNN_Wrapper")
    # Attention
    attention = attention_module(time_len=time_size, dims=dims, num_heads=num_heads, dropout=dropout)(inputs)
    # LSTM
    x, last_states = encode_rnn(attention)
    mu = tf.keras.layers.Dense(latent_length, name="Encoding_MU_Dense")(last_states)
    return tf.keras.Model(inputs=inputs, outputs=mu, name=name)

def decoder(latent_length, time_size, hidden_size, dropout, recurrent_dropout, name="Decoder"):
    inputs = tf.keras.Input(shape=(latent_length), name="inputs")
    mu = auto_module(time_size=time_size, hidden_size=hidden_size, dropout=dropout, recurrent_dropout=recurrent_dropout)(inputs)
    return tf.keras.Model(inputs=inputs, outputs=mu, name=name)

def ae(time_size, d_model, compress_dims, num_heads, enc_hidden_size, latent_length, dec_hidden_size, dropout, recurrent_dropout, reparam=True, name="VAE"):
    inputs = tf.keras.Input(shape=(time_size,1), name="inputs")
    # Embedding
    embeddings = Time2Vec(output_dims=d_model)(inputs)
    # Compress
    compress = tf.keras.layers.Conv1D(filters=compress_dims, kernel_size=5, strides=2)(embeddings) # batch, (T-(kernel_size-1))/2, compress_dims
    compress = tf.keras.layers.Conv1D(filters=compress_dims, kernel_size=4)(compress) # batch, T-(kernel_size-1), compress_dims
    compress = tf.keras.layers.Conv1D(filters=compress_dims, kernel_size=4)(compress)
    compress = tf.keras.layers.ReLU()(compress)
    compress = tf.keras.layers.Conv1D(filters=compress_dims, kernel_size=5, strides=2)(compress)
    compress = tf.keras.layers.Conv1D(filters=compress_dims, kernel_size=4)(compress)
    compress = tf.keras.layers.Conv1D(filters=compress_dims, kernel_size=4)(compress)
    compress = tf.keras.layers.ReLU()(compress) # batch, compressT, compress_dims # batch, 38, compress_dims
    # Encoder Part
    mu_enc = encoder(time_size=compress.shape[1], dims=d_model, hidden_size=enc_hidden_size,\
    num_heads=num_heads, latent_length=latent_length, dropout=dropout, recurrent_dropout=recurrent_dropout)(compress)
    # Decoder
    mu_dec = decoder(latent_length=latent_length, time_size=time_size,\
    hidden_size=dec_hidden_size, dropout=dropout, recurrent_dropout=recurrent_dropout)(mu_enc)
    return tf.keras.Model(inputs=inputs, outputs=[mu_dec, mu_enc], name=name)

############################################################################################################################
# Train Part
############################################################################################################################
# Cal ELBO Loss
def elbo_loss(model, inputs, beta):
    # From model
    mu_dec, mu_enc = model(inputs)
    # Squeeze Dimension
    inputs = tf.squeeze(inputs, axis=-1)
    mu_dec = tf.squeeze(mu_dec, axis=-1)
    #sigma_dec = tf.squeeze(sigma_dec, axis=-1)
    # Latent loss: -KL[q(z|x)|p(z)]
    # KL_divergence = 0.5 * tf.reduce_sum(tf.math.square(mu_enc) + tf.math.square(sigma_enc) - tf.math.log(1e-8 + tf.math.square(sigma_enc)) - 1, 1)
    # KL_divergence = tf.reduce_mean(KL_divergence)
    # Reconstruction Loss: log(p(x|z))
    marginal_likelihood = tf.reduce_sum(tf.math.square(inputs-mu_dec), 1)
    marginal_likelihood = -tf.reduce_mean(marginal_likelihood)
    # Reconstruction Loss: log(p(x|z)) - 2
    # marginal_likelihood = tf.reduce_sum(inputs * tf.math.log(mu_dec) + (1 - inputs) * tf.math.log(1 - mu_dec), 1)
    # marginal_likelihood = tf.reduce_mean(marginal_likelihood)
    # Reconstruction Loss: log(p(x|z)) - 3
    # marginal_likelihood = tf.reduce_sum(0.5*tf.math.log(tf.math.square(sigma_dec))+0.5*tf.math.square(inputs-mu_dec)/tf.math.square(sigma_dec), 1)
    # marginal_likelihood = -tf.reduce_mean(marginal_likelihood)
    # Cal ELBO
    # ELBO = 10*marginal_likelihood - (beta*KL_divergence)
    # For MSE
    MSE = tf.math.reduce_mean(tf.math.square(mu_dec-inputs))
    #print("ELBO : {} Marginal : {} KLD : {}".format(-ELBO.numpy(), -marginal_likelihood.numpy(), KL_divergence.numpy()))
    return -marginal_likelihood, MSE

# Gradient
def grad(model, inputs, beta, reparam=True):
    with tf.GradientTape() as tape:
        reconstruct_er, mse = elbo_loss(model, inputs, beta)
    return reconstruct_er, mse, tape.gradient(reconstruct_er, model.trainable_variables)

def train(model, train_set, epochs, batch_size, beta_cycle, beta_rate, learning_rate, summary_dir, add_name, cp_dir, sample_data_set):
    train_loss_results = []
    train_metric_results = []
    # Set Optimizer
    optimizer = tf.keras.optimizers.Adam(learning_rate= learning_rate)
    # For File Save Name
    KST = pytz.timezone('Asia/Seoul')
    log_file_name = datetime.now(KST).strftime("%Y%m%d_%H_%M_%S")+add_name
    if len(summary_dir) != 0 :
        writer = tf.summary.create_file_writer(summary_dir+"/"+log_file_name)
        tmp_sample = tensorset_forsee(arr=sample_data_set, shape=(-1, sample_data_set.shape[1], 1))
    # Train Loop
    for ep_ in range(epochs):
        #epoch_elbo_avg = tf.keras.metrics.Mean()
        epoch_mse_avg = tf.keras.metrics.Mean()
        epoch_reconstruct_avg = tf.keras.metrics.Mean()
        #epoch_kld_avg = tf.keras.metrics.Mean()
        # Data Resampling
        train_dataset = tensorset(arr=train_set, shape=(-1, train_set.shape[1], 1), batch_size=batch_size)
        # Cal Beta
        beta = cal_beta_basic(ep_, beta_cycle) * beta_rate
        # In Batch
        for x in train_dataset:
            # Get Grad
            reconstruct_er, mse, grads = grad(model, x, beta)
            # Apply Gradient
            optimizer.apply_gradients(zip(grads, model.trainable_variables))
            # For Monitoring
            #epoch_elbo_avg(elbo)
            epoch_reconstruct_avg(reconstruct_er)
            #epoch_kld_avg(kld)
            epoch_mse_avg(mse)
        train_loss_results.append(epoch_reconstruct_avg.result())
        train_metric_results.append(epoch_mse_avg.result())

        # Printing Model result
        if ep_ % 1 == 0:
            print("EPOCH : {:05d} | Reconstruct : {:.6f} | MSE : {:.6f} | Beta : {} | TrainSet Size : {}".format(\
            ep_, epoch_reconstruct_avg.result(), epoch_mse_avg.result(), beta, train_set.shape))
        # Save Model
        if len(cp_dir) != 0:
            if ep_ % 3 == 0:
                model.save_weights(cp_dir+"/"+log_file_name+"/save")
        if len(summary_dir) != 0 :
            sample_output, _ = model(tmp_sample)
            figure = image_grid(sample_output[:25].numpy())
            with writer.as_default():
                #tf.summary.scalar("ELBO Loss", epoch_elbo_avg.result(), step=ep_)
                tf.summary.scalar("Reconstruct Loss", epoch_reconstruct_avg.result(), step=ep_)
                #tf.summary.scalar("KLD Loss", epoch_kld_avg.result(), step=ep_)
                tf.summary.scalar("MSE", epoch_mse_avg.result(), step=ep_)
                tf.summary.image("Sample image from decoder", plot_to_image(figure), step=ep_)
            writer.flush()
    return train_loss_results

# Return Tensor dataset
def tensorset(arr, shape, batch_size, drop_remainder=True):
    # type casting & reshaping
    data = arr.astype(np.float32)
    data = np.reshape(data, shape)
    # make to tensor
    ds = tf.data.Dataset.from_tensor_slices(data).shuffle(buffer_size=data.shape[0]*3)
    ds = ds.batch(batch_size, drop_remainder=drop_remainder)
    return ds

# Return Tensor dataset - Non shuffle
def tensorset_forsee(arr, shape):
    # type casting & reshaping
    data = arr.astype(np.float32)
    data = np.reshape(data, shape)
    # make to tensor
    data = tf.convert_to_tensor(data, dtype=tf.float32)
    return data

# For KLD Rate
def cal_beta_basic(ep_, cycle):
    if cycle == 0:
        return 1
    while ep_>cycle:
        ep_ -= cycle
    beta = ep_*2 / cycle
    if beta >= 1:
        beta = 1
    return beta

def plot_to_image(figure):
    """Converts the matplotlib plot specified by 'figure' to a PNG image and
    returns it. The supplied figure is closed and inaccessible after this call."""
    # Save the plot to a PNG in memory.
    buf = io.BytesIO()
    plt.savefig(buf, format='png')
    # Closing the figure prevents it from being displayed directly inside
    # the notebook.
    plt.close(figure)
    buf.seek(0)
    # Convert PNG buffer to TF image
    image = tf.image.decode_png(buf.getvalue(), channels=4)
    # Add the batch dimension
    image = tf.expand_dims(image, 0)
    return image

def image_grid(sample_data):
    """Return a 5x5 grid of the MNIST images as a matplotlib figure."""
    # Create a figure to contain the plot.
    figure = plt.figure(figsize=(10,10))
    for i, sam_ in enumerate(sample_data):
        sam_ = sam_.reshape(-1)
        # Start next subplot.
        plt.subplot(5, 5, i + 1, title="Index : {}".format(i))
        plt.plot(np.arange(len(sam_)), sam_)
    return figure


from django.db import models
from django.contrib.auth.models import User

GENDER_MALE= 'Male'
GENDER_FEMALE= 'Female'
GENDER_OTHERS= 'Others'
GENDER_CHOICE=(
    (GENDER_MALE,'Male'),
    (GENDER_FEMALE, 'Female'),
    (GENDER_OTHERS, 'Others'),

)
STATUS_PENDING = 'Pending'
STATUS_REJECTED = 'Rejected'
STATUS_ACCEPTED = 'Accepted'
STATUS_CHOICE = (
    (STATUS_PENDING,'Pending'),
    (STATUS_REJECTED, 'Rejected'),
    (STATUS_ACCEPTED, 'Accepted'),
)
# Create your models here.
class Candidate(models.Model):
    name =  models.CharField(max_length= 100)
    age =  models.IntegerField()
    gender =  models.CharField(max_length= 20, choices= GENDER_CHOICE, default= GENDER_FEMALE)
    mobile =  models.CharField(max_length= 10)
    city = models.CharField(max_length= 100)
    exp_salary = models.IntegerField()
    relocate = models.BooleanField(default=False)
    c_username = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Username")
    resume = models.FileField(default = None, upload_to=None, max_length=100)
    def __str__(self):
        return self.name


import torch.nn as nn
import torch
import torch.nn.functional as F

class SiMSE(nn.Module):

	def __init__(self):
		super().__init__()

	def forward(self, shared, private):

		n = torch.numel(shared)
		loss = torch.cdist(shared, private, p=2).mean()
		loss = loss / n
		return loss

class diffLoss(nn.Module):

	def __init__(self):

		super().__init__()

	def forward(self, shared, private):
		batch_size = shared.size(0)
		shared = shared.view(batch_size, -1)
		private = private.view(batch_size, -1)

		shared_l2_norm = torch.norm(shared, p=2, dim=1, keepdim=True).detach()
		shared_l2 = shared.div(shared_l2_norm.expand_as(shared) + 1e-6)

		private_l2_norm = torch.norm(private, p=2, dim=1, keepdim=True).detach()
		private_l2 = private.div(private_l2_norm.expand_as(private) + 1e-6)

		diff_loss = torch.mean((private_l2.t().mm(shared_l2)).pow(2))

		# bs = shared.size(0)
		# shared = shared - shared.mean(dim=0)
		# private = private - private.mean(dim=0)
		# shared = F.normalize(shared, dim=1, p=2)
		# private = F.normalize(private, dim=1, p=2)
		# loss = private.t().mm(shared).pow(2).sum().pow(0.5)
		return diff_loss

class DSNLoss(nn.Module):

	def __init__(self, alpha=0.01, beta=0.05, gamma=0.3):

		super().__init__()
		self.diff_loss = diffLoss()
		self.mseloss = nn.MSELoss(reduction='mean')
		self.ceLoss = nn.CrossEntropyLoss(reduction='mean')
		self.simse = SiMSE()
		self.alpha = alpha
		self.beta = beta
		self.gamma = gamma

	def forward(self, pred_dom,  private, share, recon, label, class_label=None, pred_cls=None, mode='src'):
		bs = share.size(0)
		differnce = self.diff_loss(share, private)
		recon_loss = self.mseloss(recon, label) - self.simse(recon, label)
		domain_label = torch.ones(bs).long().cuda() if mode=='src' else torch.zeros(bs).long().cuda()
		domain_loss = self.ceLoss(pred_dom, domain_label)

		recon_loss = recon_loss * 0 if torch.isnan(recon_loss) else recon_loss
		differnce = differnce * 0 if torch.isnan(differnce) else differnce
		domain_loss = domain_loss * 0 if torch.isnan(domain_loss) else domain_loss
		if mode == 'src':
			task_loss = self.ceLoss(pred_cls, class_label)
			task_loss = task_loss * 0 if torch.isnan(task_loss) else task_loss
			return task_loss, self.alpha * recon_loss, self.beta * differnce, self.gamma * domain_loss
		return self.alpha * recon_loss, self.beta * differnce, self.gamma * domain_loss


import argparse
import re
from collections import defaultdict
import itertools as it
import math
from hashlib import md5
from advent_of_code import lib
from copy import deepcopy
import pdb

parser = argparse.ArgumentParser()
parser.add_argument("input")
parser.add_argument("part", type=int)
args = parser.parse_args()

f = open(args.input, "r")
lines = [line for line in f.read().splitlines() if line.strip()]

inp = lines[0]

last = defaultdict(list)
keys = []
for i in it.count(0):
    if args.part == 1:
        h = lib.hmd5(inp, i)
    elif args.part == 2:
        h = inp + str(i)
        for _ in range(2017):
            h = lib.hmd5(h)
    for j in range(4, len(h)):
        if h[j] == h[j-1] and h[j] == h[j-2] and h[j] == h[j-3] and h[j] == h[j-4]:
            cp = deepcopy(last[h[j]])
            for pos in last[h[j]]:
                if i - pos > 1000:
                    cp.remove(pos)
                elif pos not in keys:
                    keys.append(pos)
                    cp.remove(pos)
#                    print(len(keys))
                    if len(keys) > 72:
#                        print(sorted(keys))
                        print(sorted(keys)[63])
                        exit(0)
            last[h[j]] = cp
    for j in range(2, len(h)):
        if h[j] == h[j-1] and h[j] == h[j-2]:
            last[h[j]].append(i)
            break


#!/usr/bin/env python3
import subprocess
import time
import signal
import sys
import json
import requests
from colorama import Fore, Style
from tqdm import tqdm

def start_ngrok(port):
    global ngrok_process
    print(f"{Fore.GREEN}Démarrage du tunnel ngrok sur le port {port}...{Style.RESET_ALL}")
    ngrok_process = subprocess.Popen(["ngrok", "http", str(port)], stdout=subprocess.PIPE)

    # Wait a bit for ngrok to initialize and get the public URL
    for _ in tqdm(range(10)):
        time.sleep(1)

    response = requests.get("http://localhost:4040/api/tunnels")
    ngrok_data = json.loads(response.text)
    ngrok_url = ngrok_data['tunnels'][0]['public_url']

    # Check if ngrok initialized properly
    if not ngrok_url:
        print(f"{Fore.RED}Erreur : ngrok n'a pas pu initialiser le tunnel.{Style.RESET_ALL}")
    else:
        print(f"{Fore.BLUE}Lien de partage : {ngrok_url}/{Style.RESET_ALL}")

def cleanup(signum, frame):
    print(f"{Fore.YELLOW}Arrêt du serveur HTTP et de ngrok...{Style.RESET_ALL}")
    if http_server_process:
        http_server_process.terminate()
    if ngrok_process:
        ngrok_process.terminate()
    sys.exit(0)

# Register the cleanup function for Ctrl+C
signal.signal(signal.SIGINT, cleanup)
signal.signal(signal.SIGTERM, cleanup)

# Initialize subprocess objects
http_server_process = None
ngrok_process = None

# Ask user for the type of sharing
choice = input(f"{Fore.MAGENTA}Quel type de partage souhaitez-vous ?\n1) Partage de fichiers\n2) Partage d'application web\nChoix: {Style.RESET_ALL}")
if choice not in ['1', '2']:
    print(f"{Fore.RED}Choix invalide.{Style.RESET_ALL}")
    sys.exit(1)

# Ask user for the port number
port = input(f"{Fore.CYAN}Entrez le numéro du port sur lequel démarrer le service (par exemple, 8080 ou 3000): {Style.RESET_ALL}")

# Start the appropriate service based on the user choice
if choice == '1':
    print(f"{Fore.GREEN}Démarrage du serveur HTTP sur le port {port}...{Style.RESET_ALL}")
    http_server_process = subprocess.Popen(["python3", "-m", "http.server", port])
    start_ngrok(port)

elif choice == '2':
    print(f"{Fore.GREEN}Assurez-vous que votre application web est en cours d'exécution sur le port {port}...{Style.RESET_ALL}")
    start_ngrok(port)

# Wait for user to stop the HTTP server and ngrok
input(f"{Fore.YELLOW}Appuyez sur [Enter] ou Ctrl+C pour arrêter le serveur et ngrok...{Style.RESET_ALL}")
cleanup(None, None)


# Welcome to
# __________         __    __  .__                               __
# \______   \_____ _/  |__/  |_|  |   ____   ______ ____ _____  |  | __ ____
#  |    |  _/\__  \\   __\   __\  | _/ __ \ /  ___//    \\__  \ |  |/ // __ \
#  |    |   \ / __ \|  |  |  | |  |_\  ___/ \___ \|   |  \/ __ \|    <\  ___/
#  |________/(______/__|  |__| |____/\_____>______>___|__(______/__|__\\_____>
#
# This file can be a nice home for your Battlesnake logic and helper functions.
#
# To get you started we've included code to prevent your Battlesnake from moving backwards.
# For more info see docs.battlesnake.com

import random
import typing

# info is called when you create your Battlesnake on play.battlesnake.com
# and controls your Battlesnake's appearance
# TIP: If you open your Battlesnake URL in a browser you should see this data
def info() -> typing.Dict:
    print("INFO")

    return {
        "apiversion": "1",
        "author": "Nagini",  # TODO: Your Battlesnake Username
        "color": "#736CCB",  # TODO: Choose color
        "head": "beluga",  # TODO: Choose head
        "tail": "curled",  # TODO: Choose tail
    }

# start is called when your Battlesnake begins a game
def start(game_state: typing.Dict):
    print("GAME START")

# end is called when your Battlesnake finishes a game
def end(game_state: typing.Dict):
    print("GAME OVER\n")

# Calculating Manhattan Distance between 2 points
def manhattan_distance(point1, point2):
    return sum(abs(value1 - value2) for value1, value2 in zip(point1, point2))

# Find the neighboring coordinate

def is_snake_neighbor(youSnake, min_food, opponentsNotYou):
    if (manhattan_distance(youSnake['head'].values(), min_food.values()) == 1):
        food_pointX, food_pointY = min_food.values()
        neighbor_coordinate = [(food_pointX-1, food_pointY), (food_pointX+1, food_pointY),
                               (food_pointX, food_pointY-1), (food_pointX, food_pointY+1)]
        for opponent in opponentsNotYou:
            if tuple(opponent["head"].values()) in neighbor_coordinate and opponent["length"] >= youSnake['length']:
                return True
    return False

# If your neignbor snake is 2 manhattan distance away from you, be cautious

def is_snake_too_close(youSnake, safe_move, opponentsNotYou):
    for opponent in opponentsNotYou:
        if manhattan_distance(youSnake['head'].values(), opponent["head"].values()) == 2:
            if (opponent["length"] >= youSnake['length']):
                if safe_move == "left":
                    return (youSnake['head']['x'] - opponent["head"]['x'] > 0)
                elif safe_move == "down":
                    return (youSnake['head']['y'] - opponent["head"]['y'] > 0)
                elif safe_move == "right":
                    return (youSnake['head']['x'] - opponent["head"]['x'] < 0)
                else:
                    return (youSnake['head']['y'] - opponent["head"]['y'] < 0)
            else:
                if safe_move == "left":
                    if (youSnake['head']['x'] - opponent["head"]['x'] > 0):
                        return "left"
                elif safe_move == "down":
                    if (youSnake['head']['y'] - opponent["head"]['y'] > 0):
                        return "down"
                elif safe_move == "right":
                    if (youSnake['head']['x'] - opponent["head"]['x'] < 0):
                        return "right"
                else:
                    if (youSnake['head']['y'] - opponent["head"]['y'] < 0):
                        return "up"
    return False

# if there is only 2 snakes on board now, you may want to attack this snake

def is_last_2_snakes(youSnake, safe_move, opponentsNotYou):
    if (youSnake["health"] >= 40):
        if (len(opponentsNotYou) == 1) and (opponentsNotYou[0]["length"] < youSnake['length']):
            if safe_move == "left":
                if (youSnake['head']['x'] > opponentsNotYou[0]['head']['x']):
                    return True
            elif safe_move == "down":
                if (youSnake['head']['y'] > opponentsNotYou[0]['head']['y']):
                    return True
            elif safe_move == "right":
                if (youSnake['head']['x'] < opponentsNotYou[0]['head']['x']):
                    return True
            else:
                if (youSnake['head']['y'] < opponentsNotYou[0]['head']['y']):
                    return True
    return False

# move is called on every turn and returns your next move
# Valid moves are "up", "down", "left", or "right"
# See https://docs.battlesnake.com/api/example-move for available data

def move(game_state: typing.Dict) -> typing.Dict:

    is_move_safe = {
        "up": True,
        "down": True,
        "left": True,
        "right": True
    }

    # We've included code to prevent your Battlesnake from moving backwards
    my_head = game_state["you"]["body"][0]  # Coordinates of your head
    my_neck = game_state["you"]["body"][1]  # Coordinates of your "neck"

    if my_neck["x"] < my_head["x"]:  # Neck is left of head, don't move left
        is_move_safe["left"] = False

    elif my_neck["x"] > my_head["x"]:  # Neck is right of head, don't move right
        is_move_safe["right"] = False

    elif my_neck["y"] < my_head["y"]:  # Neck is below head, don't move down
        is_move_safe["down"] = False

    elif my_neck["y"] > my_head["y"]:  # Neck is above head, don't move up
        is_move_safe["up"] = False

    # TODO: Step 1 - Prevent your Battlesnake from moving out of bounds
    board_width = game_state['board']['width']
    board_height = game_state['board']['height']
    if my_head["x"] == board_width-1:
        is_move_safe["right"] = False
    elif my_head["x"] == 0:
        is_move_safe["left"] = False
    if my_head["y"] == board_height-1:
        is_move_safe["up"] = False
    elif my_head["y"] == 0:
        is_move_safe["down"] = False
    # TODO: Step 2 - Prevent your Battlesnake from colliding with itself
    youSnake = game_state['you']
    my_body = youSnake['body']
    # print(my_body)
    # print(is_move_safe)
    # print(game_state)

    # print(my_body)

    if (is_move_safe["left"] and {"x": my_head["x"]-1, "y": my_head["y"]} in my_body[1:]):
        is_move_safe["left"] = False
    if (is_move_safe["right"] and {"x": my_head["x"]+1, "y": my_head["y"]} in my_body[1:]):
        is_move_safe["right"] = False
    if (is_move_safe["up"] and {"x": my_head["x"], "y": my_head["y"]+1} in my_body[1:]):
        is_move_safe["up"] = False
    if (is_move_safe["down"] and {"x": my_head["x"], "y": my_head["y"]-1} in my_body[1:]):
        is_move_safe["down"] = False
    # print(is_move_safe)

    # TODO: Step 3 - Prevent your Battlesnake from colliding with other Battlesnakes
    opponents = game_state['board']['snakes']
    opponentsNotYou = [
        opponent for opponent in opponents if opponent['id'] != youSnake['id']]
    opponentsNotYouBody = [opponent['body'] for opponent in opponentsNotYou]
    opponentsNotYouBody = [
        item for sublist in opponentsNotYouBody for item in sublist]

    if (is_move_safe["left"]):
        if ({"x": my_head["x"]-1, "y": my_head["y"]} in opponentsNotYouBody):
            is_move_safe["left"] = False
        else:
            result_is_snake_too_close = is_snake_too_close(
                youSnake, "left", opponentsNotYou)
            if isinstance(result_is_snake_too_close, int):
                if result_is_snake_too_close:
                    is_move_safe["left"] = False
            else:
                return {"move": "left"}
    if (is_move_safe["right"]):
        if ({"x": my_head["x"]+1, "y": my_head["y"]} in opponentsNotYouBody):
            is_move_safe["right"] = False
        else:
            result_is_snake_too_close = is_snake_too_close(
                youSnake, "right", opponentsNotYou)
            if isinstance(result_is_snake_too_close, int):
                if result_is_snake_too_close:
                    is_move_safe["right"] = False
            else:
                return {"move": "right"}
    if (is_move_safe["up"]):
        if ({"x": my_head["x"], "y": my_head["y"]+1} in opponentsNotYouBody):
            is_move_safe["up"] = False
        else:
            result_is_snake_too_close = is_snake_too_close(
                youSnake, "up", opponentsNotYou)
            if isinstance(result_is_snake_too_close, int):
                if result_is_snake_too_close:
                    is_move_safe["up"] = False
            else:
                return {"move": "up"}
    if (is_move_safe["down"]):
        if ({"x": my_head["x"], "y": my_head["y"]-1} in opponentsNotYouBody):
            is_move_safe["down"] = False
        else:
            result_is_snake_too_close = is_snake_too_close(
                youSnake, "down", opponentsNotYou)
            if isinstance(result_is_snake_too_close, int):
                if result_is_snake_too_close:
                    is_move_safe["down"] = False
            else:
                return {"move": "down"}

    # Are there any safe moves left?
    safe_moves = []
    for move, isSafe in is_move_safe.items():
        if isSafe:
            safe_moves.append(move)

    if len(safe_moves) == 0:
        print(
            f"MOVE {game_state['turn']}: No safe moves detected! Moving down")
        return {"move": "down"}

    # Choose a random move from the safe ones
    next_move = random.choice(safe_moves)

    # TODO: Step 3.1: find the longest path from a cell
    board = [opponent['body'] for opponent in opponents]
    board = [tuple(item.values) for sublist in board for item in sublist]
    # Create a map table and fill cells that has snakes are 1, cells without are 0
    occupacied_board = [[1 if (i, j) in board else 0 for j in range(
        board_height)]for i in range(board_width)]
    # Create a lookup table and fill all entries in it as -1
    dp = [[-1 for j in range(board_height)]for i in range(board_width)]

    def findLongestFromACell(i, j, dp):
        # Base case
        if (i < 0 or i >= board_width or j < 0 or j >= board_height):
            return 0

        # If this subproblem is already solved
        if (dp[i][j] != -1):
            return dp[i][j]

        # To store the path lengths in all the four directions
        x, y, z, w = -1, -1, -1, -1

        # Since all numbers are unique and in range from 1 to n * n,
        # there is atmost one possible direction from any cell
        if (j < board_height-1 and occupacied_board[i][j+1] == 0):
            occupacied_board[i][j] = 1
            x = 1 + findLongestFromACell(i, j + 1, dp)

        if (j > 0 and occupacied_board[i][j-1] == 0):
            occupacied_board[i][j-1] = 1
            y = 1 + findLongestFromACell(i, j-1, dp)

        if (i > 0 and occupacied_board[i-1][j] == 0):
            occupacied_board[i-1][j] = 1
            z = 1 + findLongestFromACell(i-1, j, dp)

        if (i < board_width-1 and occupacied_board[i + 1][j] == 0):
            occupacied_board[i + 1][j] = 1
            w = 1 + findLongestFromACell(i + 1, j, dp)

        # If none of the adjacent fours is one greater we will take 1
        # otherwise we will pick maximum from all the four directions
        dp[i][j] = max(x, max(y, max(z, max(w, 1))))
        return dp[i][j]

    def whichDirectionLongest(i, j, dp, direction):
        left_longest = (findLongestFromACell(i-1, j, dp), "left")
        right_longest = (findLongestFromACell(i+1, j, dp), "right")
        up_longest = (findLongestFromACell(i, j+1, dp), "up")
        down_longest = (findLongestFromACell(i, j-1, dp), "down")

        longest_direction = ""
        longest_length = 0
        for length, direction_long in [left_longest, right_longest, up_longest, down_longest]:
            if length > longest_length:
                longest_length = length
                longest_direction = direction_long
        if direction == longest_direction:
            return True
        return False

    # TODO: Step 4 - Move towards food instead of random, to regain health and survive longer
    food = game_state['board']['food']
    min_distance = board_width + board_height
    min_food = {'x': 0, 'y': 0}
    for food_coordinate in food:
        to_distance = manhattan_distance(
            my_head.values(), food_coordinate.values())
        if to_distance < min_distance:
            min_distance = to_distance
            min_food = food_coordinate

    which_turn = game_state['turn']

    better_moves = []
    if ("left" in safe_moves):
        if my_head['x'] > min_food['x']:
            better_moves.append("left")
        if whichDirectionLongest(my_head['x']-1, my_head['y'], dp, "left"):
            return {"move": "left"}
    if ("right" in safe_moves):
        if my_head['x'] < min_food['x']:
            better_moves.append("right")
        if whichDirectionLongest(my_head['x']+1, my_head['y'], dp, "right"):
            return {"move": "right"}
    if ("up" in safe_moves):
        if my_head['y'] < min_food['y']:
            better_moves.append("up")
        if whichDirectionLongest(my_head['x'], my_head['y'] + 1, dp, "up"):
            return {"move": "up"}
    if ("down" in safe_moves):
        if my_head['y'] > min_food['y']:
            better_moves.append("down")
        if whichDirectionLongest(my_head['x'], my_head['y']-1, dp, "down"):
            return {"move": "down"}

    if len(better_moves) != 0:
        # dont do this when there is a head to head collision and you know you will lose, more to come
        if len(set(better_moves)) == 1:
            if not is_snake_neighbor(youSnake, min_food, opponentsNotYou):
                next_move = better_moves[0]
            else:
                safe_moves.remove(better_moves[0])
                next_move = random.choice(safe_moves)
        else:
            next_move = random.choice(better_moves)

    print(f"MOVE {game_state['turn']}: {next_move}")
    return {"move": next_move}

# Start server when `python main.py` is run
if __name__ == "__main__":
    from server import run_server

    run_server({
        "info": info,
        "start": start,
        "move": move,
        "end": end
    })


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""

@author: eman-saeed
"""

import numpy as np
import matplotlib.pyplot as plt

#python image library.
"""
PIL is a library that used for transformation of image
    into an array  that numpy can understand.
"""
from PIL import Image
"""
-> support the path of the image.
"""
pic = Image.open('English Lab Puppy (1)_0.png')
pic.show()
type(pic)
pic_arr = np.asarray(pic)
print(pic_arr.shape)
#showing image by using matplotlib library by converting the pixels to an image.
#plt.imshow(pic_arr)
pic_red = pic_arr.copy()
#plt.imshow(pic_red)

"""to show the image with the red color we select a specific channel to show."""
#R G B
pic_red2 = pic_red[:,:,0]
"""
- cmap -> color map we choose color gray .
- RED Channel Values 0-255:
    0 -> No Color Value(pure black).
    255-> Full Color.
"""
plt.imshow(pic_red[:,:,1],cmap ='gray')

#Check for the blue
plt.imshow(pic_red[:,:,2 ],cmap ='gray')
#Check for the green channel
pic_red [:,:,1] = 0
pic_red [:,:,2]  = 0
plt.imshow(pic_red)
print(pic_red.shape)

pic_red[:,:,1].shape


import logging

from .models import LogApiRequestsModel

logger = logging.getLogger(__name__)

class LogApiRequestsMiddleware:
    """
    Writes API request history to DB
    """
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        if 'api' in request.path:
            LogApiRequestsModel.objects.create(user=request.user.username, url=request.path)
            logger.debug(f'MIDDLEWARE REQUEST ADDED LOG {request.user.username}, {request.path}')
        return response


# 例題3-3
import numpy as np
import scipy.stats as st
import matplotlib.pyplot as plt
# データ
S2 = 4.0
n = 7
m = 4
alpha = 0.01

# グラフ
gxmin,gxmax = (0.01, 25)
gymin,gymax = (0.0, 0.7)

# 確率密度関数
t = np.arange(gxmin,gxmax,0.01)
rv = st.f(dfn=m-1,dfd=n-1)
f = rv.pdf(t)
#　確率変数値
t1 = rv.isf(alpha)
print('t1=',t1)
# 分散
T = ((m*(n-1))/(n*(m-1)))*10
print('T=',T)

fig = plt.figure(figsize=(6,4))
plt.plot(t,f)
plt.autoscale(tight=True)
plt.xlabel('z')
plt.ylabel('f(z)')
plt.vlines(t1,gymin,gymax,linestyles='--',colors='r')
plt.vlines(T,gymin,gymax,linestyles='--',colors='g')
plt.show()


from django.shortcuts import render, HttpResponseRedirect, redirect
from .models import Todo, Date
from django.urls import reverse
from .forms import TodoForm
from django.utils import timezone
from django.contrib.auth.decorators import login_required
# Create your views here.

@login_required
def index(request):
    author = request.user
    dates = Date.objects.filter(author = author).exclude(strdate = timezone.now().strftime("%Y-%m-%d"))
    dates = dates.order_by('-strdate')

    return render(
        request,
        'todo/index.html',
        {
            'dates' : dates,
        }
    )

@login_required
def todo_list(request, date):
    author = request.user
    todos = Todo.objects.filter(author = author).filter(completed = False).filter(str_date = date)
    todosc = Todo.objects.filter(author = author).filter(completed = True).filter(str_date = date)

    return render(
        request,
        'todo/todo_list.html',
        {
            'todos' : todos,
            'todosc' : todosc
        }
    )

@login_required
def todo_today(request):
    author = request.user
    dates = Date.objects.filter(author = author).filter(strdate = timezone.now().strftime("%Y-%m-%d"))

    if(len(dates) == 0):
        new_date = Date()
        new_date.author = request.user
        new_date.save()

    todos = Todo.objects.filter(author = author).filter(completed = False).filter(str_date = timezone.now().strftime("%Y-%m-%d"))
    todosc = Todo.objects.filter(author = author).filter(completed = True).filter(str_date = timezone.now().strftime("%Y-%m-%d"))

    return render(
        request,
        'todo/todo_today.html',
        {
            'todos' : todos,
            'todosc' : todosc
        }
    )

@login_required
def todo_detail(request, pk):
    todo = Todo.objects.get(id=pk)

    return render(request, 'todo/todo_detail.html', {'todo' : todo})

@login_required
def todo_delete(request, pk):
    todo = Todo.objects.get(id=pk)

    todo.delete()

    previous_page = request.META.get('HTTP_REFERER')
    return HttpResponseRedirect(previous_page)

@login_required
def todo_post(request):
    if request.method == "POST":
        form = TodoForm(request.POST)
        if form.is_valid():
            todo = form.save(commit=False)
            todo.author = request.user
            todo.save()
            return redirect('/todo/today')
    else:
        form = TodoForm()

    return render(request, 'todo/todo_post.html', {'form': form})

@login_required
def todo_edit(request, pk):
    todo = Todo.objects.get(id=pk)
    if request.method == "POST":
        form = TodoForm(request.POST, instance=todo)
        if form.is_valid():
            todo = form.save(commit=False)
            todo.save()
            return redirect('/todo/today')
    else:
        form = TodoForm(instance=todo)

    return render(request, 'todo/todo_post.html', {'form': form})

@login_required
def todo_done(request, pk):
    todo = Todo.objects.get(id=pk)
    if(todo.completed == False) :
        todo.completed = True
    else :
        todo.completed = False

    todo.save()

    previous_page = request.META.get('HTTP_REFERER')
    return HttpResponseRedirect(previous_page)


from collections.abc import Callable

def mutate(par: list, p: int, d: float) -> list:
    newpar = par.copy()
    newpar[p - 1] += d
    return newpar

def hj(f: Callable[[list[float]], float], parv: list[float], maxiter: int, startstep: float, endstep: float) -> list[float]:
    p = len(parv)
    currentstep = startstep
    iter = 0
    par = parv.copy()
    while iter < maxiter:
        fold = f(par)
        fnow = fold
        for currentp in range(1, p + 1):
            mutateleft = mutate(par, currentp, -currentstep)
            fleft = f(mutateleft)
            mutateright = mutate(par, currentp, currentstep)
            fright = f(mutateright)
            if fleft < fold:
                par = mutateleft
                fnow = fleft
            elif fright < fold:
                par = mutateright
                fnow = fright

        if fold <= fnow:
            currentstep = currentstep / 2.0

        if currentstep < endstep:
            break

        iter += 1

    return par


import pandas as pd
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import LabelEncoder
from xgboost import XGBClassifier
from sklearn.metrics import classification_report, accuracy_score
import pickle

# Load the data
data = pd.read_csv("crop_data.csv")

# Encode crop names as numeric labels
le = LabelEncoder()
data["Crop"] = le.fit_transform(data["Crop"])

# Split the data into features (X) and target (y)
X = data.drop("Crop", axis=1)
y = data["Crop"]

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Set up the hyperparameter grid
param_grid = {
    "learning_rate": [0.05, 0.1, 0.15],
    "max_depth": [3, 4, 5],
    "n_estimators": [50, 100, 200],
    "reg_lambda": [0.1, 0.5, 1],
    "subsample": [0.5, 0.7, 0.9],
}

# Train an XGBoost Classifier with grid search
clf = XGBClassifier(objective="multi:softmax")
grid_search = GridSearchCV(
    clf, param_grid=param_grid, cv=3, n_jobs=-1, verbose=2, scoring="accuracy"
)
grid_search.fit(X_train, y_train)

# Print the best hyperparameters and score
print("Best hyperparameters:", grid_search.best_params_)
print("Best accuracy score:", grid_search.best_score_)

# Save the trained model
clf = grid_search.best_estimator_
with open("xgboost_classifier.pkl", "wb") as f:
    pickle.dump(clf, f)

# Make predictions on the test set
y_pred = clf.predict(X_test)

# Decode numeric labels back to crop names
y_test = le.inverse_transform(y_test)
y_pred = le.inverse_transform(y_pred)

# Evaluate the model
print("Classification report:")
print(classification_report(y_test, y_pred))

# Calculate the accuracy of the model
accuracy = accuracy_score(y_test, y_pred)
print("Overall classification accuracy:", accuracy)


import tempfile
import os
import numpy
import mathutil
import shelve
import argparse
import glob
import subprocess
import exifread
from enum import Enum
import datetime
import os.path
import inspect
import sys
import itertools
import nptime
from nptime import nptime
try:
    import cv2
    #from cv2 import waitKey
except ImportError:
  pass

import PIL  # image text
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw

#from tkinter._fix import ver

from collections import OrderedDict
import mathutil

def crop(image,top=0,bottom=0,left=0,right=0):
    if bottom==0: bottom=image.shape[0]
    else: bottom=-bottom
    if right==0: right=image.shape[1]
    else: right=-right

    return image[top:bottom,left:right]

def str_to_class(str):
    return getattr(sys.modules[__name__], str)

def neighborhood(iterable):
    iterator = iter(iterable)
    prev = None
    item = next(iterator)  # throws StopIteration if empty.
    for nextone in iterator:
        yield (prev,item,nextone)
        prev = item
        item = nextone
    yield (prev,item,None)

def defname():
    try:
        return inspect.stack()[1][3]
    except:
        pass

class SliceType(Enum):
    day = 1
    hour = 2
    dayhour = 3
    concat = 4

    @staticmethod
    def fromStr(name):
        return getattr( SliceType, name )

    @staticmethod
    def names():
        return list(map(lambda x: x.name, list(SliceType)))
    #names = staticmethod(names_static)

class TLMovieMaker:
    tlMovies = []
    movieFolder = "."
    speedup = 60
    leastImages = 1
    moviesRelPath = ""
    fileGlob = ""
    fileList = []
    tlFiles = []
    motion=False
    dayStartTime = datetime.time(8)
    dayEndTime = datetime.time(15)
    daySliceLength = None
    verbose=False
    cache=True
    suffix=""
    fpsMax = None

    def __init__ (self):
        pass

    def __str__(self):
        return "{}: Movies:{}  SpeedUp:{} DaySliceLength:{} file_list:{} motion:{}".format(type(self).__name__,len(self.tlMovies),self.speedup,self.daySliceLength,len(self.fileList),self.motion)

    def ls(self):
        s = ""
        for m in self.tlMovies:
            s = s & m.ls()
        return s

    def makeTLFiles(self):
        self.tlFiles=[]
        print (os.getcwd())
        d = shelve.open("tlmm-cache",writeback=True)
        nErrors =0
        if self.verbose: print("Reading dates of {} files...".format(len(self.fileList)))
        globStr = ','.join(self.fileGlob)

        # try to find a cached version of file dates
        if self.cache and self.fileGlob!="" and globStr in d:
            print ("Found cache for {}: {} files".format(globStr,len(d[globStr])))
            self.tlFiles = d[globStr]
        else:
            for fn in self.fileList:
                try:
                    #dname, bname = os.path.split(fn)
                    f = open(fn,'rb')
                    tags = exifread.process_file(f,details=False)
                    f.close()
                    datetimeTakenExifStr = tags["EXIF DateTimeOriginal"]
                    datetimeTakenExif = datetime.datetime.strptime(str(datetimeTakenExifStr), r'%Y:%m:%d %H:%M:%S')
                    #dateExifIso = dateExif.isoformat()
                    #print (os.path.basename(fn) + " date = " + str(exifDate) + " diso = " + diso)
                    #tlf = TLFile(fn,datetimeTakenExif,tags)
                    tlf = TLFile(fn,datetimeTakenExif)
                    self.tlFiles.append(tlf)
                except  Exception as e:
                    nErrors += 1
                    #print ("Error getting date for %s: %s"%(fn,e))
            # write to cache (
            if globStr!="" and globStr not in d:
                d[globStr] = self.tlFiles

        d.close()
        if self.verbose:
            print("Got {} timelapse images from {} files with {} errors".format(len(self.tlFiles),len(self.fileList),nErrors))
        if nErrors: print ("No dates available for {} of {}. Ignoring them.".format(nErrors,len(self.fileList)))
        return self.tlFiles.sort()

    def senseMotion(self):
        if self.verbose: print("Sensing motion in {} movies".format(len(self.tlMovies)))
        for tlm in self.tlMovies:
            tlm.sense_motion()

    def fileListFromGlob(self, fileGlob):
        self.fileList = []
        self.fileGlob = fileGlob
        for fg in fileGlob:
            if (self.verbose): print ("Globbing {}.".format(fg))
            self.fileList.extend(glob.glob(fg))
        self.fileList.sort()
        if (self.verbose): print ("Processing %d files"%(len(self.fileList)))

    def loadMovies(self):
        del(self.tlMovies[:])
        self.makeTLFiles()

    def saveMovies(self):
        for m in self.tlMovies:
            m.verbose = self.verbose # do earlier
            m.write()

class TLMovieMakerConcat(TLMovieMaker):
    def loadMovies(self):
        TLMovieMaker.loadMovies(self)
        self.tlMovies.append(TLMovie(self.tlFiles,self.moviesRelPath,self.speedup,self.leastImages,self.motion,self.suffix))

class TLMovieMakerHour(TLMovieMaker):
    pass
#    def loadMovies(self):
#       TLMovieMaker.loadMovies(self)

# Make one movie per day
#
class TLMovieMakerDay(TLMovieMaker):
    def __str__(self):
        return "{}: Movies:{}  SpeedUp:{} file_list:{} range={} to {} day_slice_length:{} leastImages:{} motion:{}".format(type(self).__name__,len(self.tlMovies),self.speedup,len(self.fileList),self.dayStartTime,self.dayEndTime,self.daySliceLength,self.leastImages,self.motion)

    def ls(self):
        s=""
        for m in self.tlMovies:
            s += m.ls()
        return s

    def loadMovies(self):
        TLMovieMaker.loadMovies(self)
        groupedByDayTLFiles = self.groupByDay(self.tlFiles)
        for day in groupedByDayTLFiles:
            dayFilesFiltered = self.filterByHour(groupedByDayTLFiles[day], self.dayStartTime, self.dayEndTime,self.verbose)
            if self.verbose: print("Loading movie for {} with {} filtered files from {} total files ".format(day,len(dayFilesFiltered),len(groupedByDayTLFiles[day])))
            self.tlMovies.append(TLMovie(dayFilesFiltered,self.moviesRelPath,self.speedup,self.leastImages,self.motion,fpsMax=self.fpsMax,verbose=self.verbose))

        #pprint(groupedTLFiles)
    @staticmethod
    def filterByHour(localTLFiles,localStartTime=None,localEndTime=None,verbose=False):
        retval = localTLFiles
        #if verbose: print("Filtering from {} to {}".format(localStartTime,localEndTime))
        #if verbose: print("Starting with {} files".format(len(retval)))
        if localStartTime is not None:
            retval = list(filter(lambda x: x.datetimeTaken.time()>=localStartTime, retval))

        #if verbose: print("After start with {} files".format(len(retval)))

        if localEndTime is not None:
            #print(localEndTime)
            for i in retval:
                retval = list(filter(lambda x: x.datetimeTaken.time()<=localEndTime, retval ))
        #if verbose: print("After end {} files".format(len(retval))  )

        return retval

    @staticmethod
    def groupByDay(localTLFiles):
        groupedTLFiles = OrderedDict()
        for day, dayFiles in itertools.groupby(localTLFiles,lambda x: x.datetimeTaken.date()):
           # print ("Day {}".format(day))
            groupedTLFiles[day] = []
            for tlf in sorted(dayFiles):
                groupedTLFiles[day].append(tlf)
            #    print ("\t{}".format(tlf.filename))
            #groupedTLFiles = sorted(groupedTLFiles)
        return groupedTLFiles

class TLMovieMakerDayhour(TLMovieMakerDay):
    def loadMovies(self):
        slicedTLFiles = []
        TLMovieMaker.loadMovies(self)

        groupedByDay = self.groupByDay(self.tlFiles)
    #    dailyTimeDelta = (datetime.datetime.combine(datetime.date.today(),self.day_end_time) - (datetime.date.today() + self.day_slice_length)) / (len(groupedByDay)-1)
        # work out minutesPerDay to be continuous
        if self.daySliceLength == None:
            self.daySliceLength = (nptime.nptime.from_time(self.dayEndTime) - nptime.nptime.from_time(self.dayStartTime))   / len(groupedByDay)
            if self.verbose: print ("Autoset dayslicelength to {}".format(self.daySliceLength))

        dailyTimeDelta = nptime.from_time(self.dayEndTime) - nptime.from_time(self.dayStartTime)
        dailyTimeDelta = dailyTimeDelta - self.daySliceLength
        dailyTimeDelta /= len(groupedByDay)-1
        #print(dailyTimeDelta)
        startDateTime = nptime.from_time(self.dayStartTime)
        #        sortedGroupByDay = sorted(groupedByDay.items(), key=lambda (k,v): k)

        for day in sorted(groupedByDay.keys()):
            #dayTLFiles =  self.tl_files[day]
            #endTime = startTime + self.day_slice_length
            endDateTime = startDateTime + self.daySliceLength
            dayTLFiles = self.filterByHour(groupedByDay[day],startDateTime,endDateTime)
            if (self.verbose):
                print ("Day {}: {} to {} ({}/{} files)".format(day,startDateTime,endDateTime,len(dayTLFiles),len(groupedByDay[day])))

            slicedTLFiles.extend(list(dayTLFiles))
            #self.tlMovies.append(TLMovie(dayTLFiles,self.moviesRelPath,self.speedup))
            #self.tlMovies
            startDateTime += dailyTimeDelta
        slicedTLFiles.sort()
        if self.verbose:
            pass
            #[print(tlf) for tlf in slicedTLFiles]
            #input("Please Enter to continue")
        self.tlMovies.append(TLMovie(slicedTLFiles,self.moviesRelPath,self.speedup,self.leastImages))
        print ("Warning: calcGaps not run __LINE__")
        #self.calcGaps()

class TLMovie:
    tlFiles  = []
    disjointThreshold = datetime.timedelta(hours=1)       # minutes. Gaps greater than this are considered disjoint
    bitrate="2000k" # str for ffmpeg
    movieDir = ""
    speedup = 0
    leastImages = 100
    customMovieFilename = ""
    verbose = False
    motion=False
    motionTimeDeltaMax =  datetime.timedelta(hours=1)   # if longer than this, cannot really compute motion
    fpsMax = None # if unset, use all frames; if set, select frames to achieve this fps

    def __init__(self,tlFiles, movieDir=".",speedup=None,leastImages=None,motion=None,suffix="",fpsMax=None,verbose=None):
        self.tlFiles = tlFiles
        if movieDir: self.movieDir = movieDir
        if speedup: self.speedup = speedup
        if leastImages is not None: self.leastImages = leastImages
        if motion: self.motion = motion
        if verbose: self.verbose = verbose
        self.suffix = suffix
        self.calcGaps()
        if fpsMax and self.fpsVideo()>fpsMax:
            if verbose: print ("Set fpsMax to %f" % fpsMax)
            self.fpsMax= fpsMax
            self.selectTLFilesToSuitMaxFPS()

    def __str__(self):
        return  "TLMovie: filename={} speedup={} fpsVideo={:.1f} br={} djt={} frames={} spfReal={:.1f} leastImages={} motion:{} ".format(self.movieFilename(),self.speedup,self.fpsVideo(),self.bitrate,self.disjointThreshold,len(self.tlFiles),self.spfReal(),self.leastImages,self.motion)

    def ls(self):
        s = ""
        for tlf in self.tlFiles:
            s += str(tlf) + "\n"
        return s

    # Uses self.TLFiles as a source of images to construct a NEW self.TLFiles with just enough images to achieve videoFPS
    def selectTLFilesToSuitMaxFPS(self):
        if (self.verbose):
            print("selectTLFilesToSuitMaxFPS: realStart: %s realEnd: %s" % (self.firstDateTime(), self.lastDateTime()))
        frameTime = self.firstDateTime()
        spfVideoToSet = 1 / self.fpsMax
        spfRealToSet = spfVideoToSet * self.speedup
        newTLFiles = []
        # Run through real time, stepping per-frame-to-be and find the nearest frame in time to use
        while frameTime < self.lastDateTime():
            frameTime += datetime.timedelta(seconds=spfRealToSet)
            tlf = min(self.tlFiles, key=lambda x: abs(x.datetimeTaken - frameTime))
            tlf.durationReal = datetime.timedelta(seconds=spfRealToSet)
            if (self.verbose):
                pass
                #print ("frameTime %s" % frameTime)
                #print ("found %s at %s" % (tlf,tlf.datetimeTaken))
            newTLFiles.append(tlf)
        self.tlFiles = newTLFiles
        if (self.verbose):
            dv = self.durationVideo()
            print("selectTLFilesToSuitMaxFPS: maxFps=%f fps= %f duration = %s newTLFiles = %d" % (self.fpsMax,self.fpsVideo(),self.lastDateTime() - self.firstDateTime(),len(newTLFiles)))

    def calcGaps(self):

        for prev,item,nextitem in neighborhood(self.tlFiles):
            if prev is not None:
                item.durationReal = item.datetimeTaken - prev.datetimeTaken

            if prev is None or item.durationReal > self.disjointThreshold:
                # if there is a massive disjoint in the images' datetakens, skip this in the video (ie. set durationReal from BIG to a small value)
                item.durationReal = datetime.timedelta(milliseconds=100) #(seconds=666)
                item.isFirst=True

    # Since frames' time may be disjoint, add the gaps between all frames; this ignores disjoint frames (see "calcgaps")
    def durationReal(self):
        dr=datetime.timedelta()
        for tlf in self.tlFiles:
            dr += tlf.durationReal
        return dr

    def firstDateTime(self):
        return self.tlFiles[0].datetimeTaken

    def lastDateTime(self):
        return self.tlFiles[-1].datetimeTaken

    def durationVideo(self):
        return self.durationReal() / self.speedup

    def fpsVideo(self):
        if len(self.tlFiles)==0: return 0
        if  self.durationVideo().total_seconds()==0 :return 0
        return len(self.tlFiles) / self.durationVideo().total_seconds()

    def addTLFiles(self, tlfiles):
        # concat list
        self.tlFiles.append(tlfiles)
        pass

    def fpsReal(self):
        if len(self.tlFiles)==0: return 0
        if  self.durationReal().total_seconds()==0 :return 0
        return len(self.tlFiles) / self.durationReal().total_seconds()

    def spfReal(self):
        if self.fpsReal()==0: return 0
        return 1 / self.fpsReal()
    #
    # Compare image before to present image and mark if present one is quite diff-erent
    #
    #
    def senseMotion(self):
        print ("Sensing motion for m:{}".format(self))
        # expect smaller gaps because the motion senser will cut-up the video into sensed fragments.
        # set the disjoint threshold low, so that the video run with out long pauses between fragments
        self.disjointThreshold = datetime.timedelta(minutes=1)

        #self.verbose = True
        for prev,item,nextitem in neighborhood(self.tlFiles):
            if (self.verbose):
                print("Sensing motion for TLFile: %s with prev=%s next=%s" % (item, prev, nextitem))
            if prev is not None:
                if item.durationReal < self.motionTimeDeltaMax:
                    item.sense_motion(prev)
                else:
                    pass
                    # mark as "keep" as it is the start of new item period
        #if self.verbose:
            # show the plots of motion
        cv2.destroyAllWindows()

        motionList = list(tlf.motion for tlf in self.tlFiles)
        percentile95 = numpy.percentile(motionList,99)
        if self.verbose: print ("Motion 95 percentile = %f" % percentile95)
        motionList95=[]
        for m in motionList:
            if m > percentile95:
                #print ("Truncating {} to {}".format(m,percentile95))
                m = percentile95
            motionList95.append(m)
            #  SMOOTH
        fpm = self.fpsReal()*60
        fts = int(fpm * 10)+1 # avoid zero
        #print ("fpm={} fts={}".format(fpm,fts))
        showMotionPlots = False
        if showMotionPlots:
            mathutil.plot1d([motionList95,mathutil.smoothList(motionList,motionList95,degree=fts),mathutil.smoothListGaussian(motionList95,degree=fts),mathutil.smoothListTriangle(motionList95,degree=fts),mathutil.smoothListTriangle(motionList95,degree=fts)])
        # Set back smoothes values to tl_files
        motionTotal =0
        motionThreshold = 0.00015
        for i,motion in enumerate(mathutil.smoothListGaussian(motionList95,degree=fts)):
                self.tlFiles[i].motion = motion
        preMotionFilterNFiles = len(self.tlFiles)
        # THRESHOLD
        filterMotionImages= True
        if (filterMotionImages):
            self.tlFiles = [item for item in self.tlFiles if item.motion >= motionThreshold]
            self.calcGaps()

        addMotionText=True
        if (addMotionText):
            for tlf in self.tlFiles:
                if tlf.motion >= motionThreshold:
                    tlf.addText("MOTION DETECTED")

        print ("Detected smoothed motion in {} of {}".format(len(self.tlFiles),preMotionFilterNFiles ))

    def write(self):
        if len(self.tlFiles)<self.leastImages:
            if self.verbose: print ("Skipping {} as only got {} images".format(self.movieBasename(),len(self.tlFiles)))
            return False

        self.writeImageList()

        if self.verbose:
            print ("TLMovie.write(): writing {} images to {} durationReal = {}s (={}) durationVideo= {}s (={}) ".format(len(self.tlFiles),self.moviePathname(),self.durationReal().total_seconds(),self.durationReal(),self.durationVideo().total_seconds(),self.durationVideo()))
            print("TLMovie.write(): self = {}".format(self))
            print("TLMovie.write(): abspath = %s" % os.path.abspath(self.moviePathname()))
        logFile = open(self.logFilename(),"w")
        #p = subprocess.Popen(["ffmpeg.exe","-y","-f","concat","-i",self.listFilename(),"-b:v",str(self.bitrate),"-r",str(self.fpsVideo),self.moviePathname()],stdout=logFile,stderr=logFile)
        #textcmd =  ''' drawtext=x=(w-text_w)/2: y=(h-text_h-line_h)/2:fontcolor=white:fontfile=/Windows/Fonts/arial.ttf:text=************ MOTION ***************'''

        r = subprocess.call(["ffmpeg.exe","-y","-f","concat","-i",self.listFilename(),"-b:v",str(self.bitrate),"-r",str(self.fpsVideo()),self.moviePathname()],stdout=logFile,stderr=logFile)
        logFile.close()
        #(stdoutdata, stderrdata) = p.communicate()
        #if (p.returncode == 0):
        if r == 0:
            if self.verbose: print("Wrote {} images to {}".format(len(self.tlFiles),self.moviePathname()))
            return True
        else:
            print("*** FAILED on writing {} images to {}. Logged to {}".format(len(self.tlFiles),self.moviePathname(),self.logFilename()))
            print(open(self.logFilename()).read())
        return False

    def writeImageList(self):
        f = open(self.listFilename(),'w')
        for tlf in self.tlFiles:
            f.write("file '" + tlf.filename + "'\n")
            f.write("duration " + str(tlf.durationReal / self.speedup) + "\n")
        f.close()
    def logFilename(self):
        return os.path.join(self.movieDir,"tlmm.log")

    def listFilename(self):
        return os.path.join(self.movieDir,self.movieBasename() + ".list")

    def movieFilename(self):
        return self.movieBasename() + ".avi"

    def moviePathname(self):
        return os.path.join(self.movieDir,self.movieFilename())

    def movieBasename(self):
        bn = self.customMovieFilename
        if bn=="":
            if len(self.tlFiles)>0:
                bn = str(self.tlFiles[0].datetimeTaken.date())+"_to_" +str(self.tlFiles[-1].datetimeTaken.date())
            bn += "-" + self.suffix

        return bn

class TLFile:
    durationReal = datetime.timedelta()
    filename=""
    datetimeTaken=None
    tags=[]
    isFirst=False   # of a sequence
    isLast=False    # of a sequence - there will be gap after (or end)
    motion = 0      # 0 to 1
    def __repr__(self):
        return '{}\t\t{}\t\t{}\t{}'.format(self.datetimeTaken,self.durationReal,self.filename,self.isFirst if self.isFirst else "    ")

    def __str__(self):
        return '{}\t\t{}\t\t{}\t{}'.format(self.datetimeTaken,self.durationReal,self.filename,self.isFirst if self.isFirst else "    ")
    def __init__(self,filename,datetimeTaken,tags=None):
        self.filename = filename
        self.datetimeTaken = datetimeTaken
        self.tags = tags
    def __gt__(self, o2):
        return self.datetimeTaken > o2.datetimeTaken
    def __eq__(self, o2):
        return self.datetimeTaken == o2.datetimeTaken
        pass
    def __add__(self, other):
        return self.durationReal + other.durationReal
    def senseMotion(self,prevTLF):
        testimg = cv2.imread(self.filename, 0)
        selfImg = cv2.blur(crop(cv2.imread(self.filename,0),bottom=50),(5,5))
        prevImg = cv2.blur(crop(cv2.imread(prevTLF.filename,0),bottom=50),(5,5))
        diffImg  =cv2.blur(crop( cv2.absdiff(selfImg,prevImg) ,bottom=50),(5,5))
        retval,diffImg = cv2.threshold(diffImg, thresh=64,maxval=10,type=cv2.THRESH_TOZERO)
        maxDiff = selfImg.size * 255
        diffPC = cv2.sumElems(diffImg)[0] / maxDiff
        cv2.putText(selfImg,"Mottion={:.2%}".format(diffPC),(10,500), cv2.FONT_HERSHEY_PLAIN, 1,(255,255,255),2,cv2.LINE_AA)
        if diffPC>0.0005:
            cv2.putText(selfImg,"Motion!",(10,400), cv2.FONT_HERSHEY_PLAIN, 3,(255,255,255),3,cv2.LINE_AA)
        self.motion = diffPC
        if False:
            cv2.imshow('self',selfImg)
            cv2.imshow('prev',prevImg)
            cv2.imshow('diff',diffImg )
        #if cv2.waitKey() == ord('q'):
        #    sys.exit()
    def addText(self,s):
        #
        # WILL WRITE OVER THE FILES!
        #

        font = ImageFont.truetype("/Windows/Fonts/arial.ttf",25)
        img=Image.open(self.filename)
        # THIS CAUSES A WARNING "UNCLOSED FILE"
        draw = ImageDraw.Draw(img)
        draw.text((0, 0),s,(255,255,0),font=font)
        #draw = ImageDraw.Draw(img)
        #draw = ImageDraw.Draw(img)
        self.filename = os.path.join(tempfile.gettempdir(),os.path.basename(self.filename))
        img.save(self.filename)
        img.close()

if __name__ == "__main__":
    parser = argparse.ArgumentParser("Make timelapse movies")
    parser.add_argument("file_glob",nargs='+')
    parser.add_argument("--verbose",action='store_true',default=False)
    parser.add_argument("--dryrun",action='store_true',default=False)
    parser.add_argument("--moviesRelPath", default="", type=str)
    parser.add_argument("--nocache",action='store_true',default=False)
    parser.add_argument("--slicetype",choices=SliceType.names(),default="day")
    parser.add_argument("--speedup",default=300,type=int)
    parser.add_argument("--leastimages",default=100,type=int)
    parser.add_argument("--fpsmax", default=None, type=int)
    parser.add_argument("--daystarttime",default="0:00",type=str)
    parser.add_argument("--dayendtime",default="23:59",type=str)
    parser.add_argument("--minutesperday",default=None,type=int,help="For hour or dayhour slice types, minutes to show per day")
    parser.add_argument("--motion",action='store_true',default=False,help="Filter to include only motiony images")
    parser.add_argument("--suffix",default="",type=str)

    args = (parser.parse_args())

    mm = str_to_class("TLMovieMaker" + args.slicetype.title())()
    mm.moviesRelPath = args.moviesRelPath
    mm.suffix = args.suffix
    mm.verbose = args.verbose
    mm.files_from_glob(args.fileGlob)
    mm.speedup = args.speedup
    mm.dayStartTime = datetime.datetime.strptime(args.daystarttime,"%H:%M").time()
    mm.dayEndTime = datetime.datetime.strptime(args.dayendtime,"%H:%M").time()
    mm.leastImages = args.leastimages
    mm.motion = args.motion
    if args.minutesperday:
        mm.daySliceLength = datetime.timedelta(minutes=args.minutesperday)
    mm.cache = not args.nocache
    mm.fpsMax  = args.fpsmax

    if mm.verbose:
        pass
        print("Loading movies using: {} ...".format(mm))
    mm.loadMovies()

    if mm.motion:
        mm.sense_motion()
    if mm.verbose:
        print("Loaded movies {}".format(mm))
    #    [print(m) for m in  mm.tlMovies]
    if not args.dryrun:
        if mm.verbose: print("Saving movies...")
        mm.saveMovies()


# N개의 수가 주어지고 : 1 <= N <= 1,000,000
# N개의 수 각 항을 자기보다 작은 수의 개수로 변환

from collections import defaultdict as dd
import sys
input = sys.stdin.readline

t = int(input())
d = dd(int)
li = list(map(int,input().split()))
order = -1
acc = 0
_li = li.copy()
_li.sort(key=lambda x : x)
for i in range(t):
    if i > 0 and _li[i] == _li[i-1]:
        d[_li[i]] = order
    else:
        order += 1
        d[_li[i]] = order
for i in li:
    print(d[i], end=' ')


import json
import boto3
import os

dynamodb=boto3.client('dynamodb')

def handler(event, context):
    connectionId=event['requestContext']['connectionId']

    dynamodb.delete_item(
        TableName=os.environ.get('TABLE_NAME'),
        Key={'socketId':{'S':connectionId}}
    )
    return {}


import json
import uuid
import sqlite3
import sys
from typing import List, Optional

from goet.lib.converter.converter import converter
from goet.lib.frame.frame import Frame
from goet.tracer.base import BaseTracer

CURR_FRAME_ID: int = 0
PREV_FRAME_IDS: List[Optional[int]] = [None]

class SqlTracer(BaseTracer):
    """SqlTracer is used to record Python runtime.

    >>> with SqlTracer.trace_manager() as t:
    ...     fn()
    """

    def __init__(self, connection: sqlite3.Connection):
        self.connection = connection
        self.cursor = connection.cursor()
        self.run_id = str(uuid.uuid4())

    def __exit__(self, *exc):
        sys.settrace(None)
        val = super().__exit__(*exc)
        self.connection.commit()
        return val

    def dispatch_call(self, frame):
        PREV_FRAME_IDS.append(CURR_FRAME_ID)

    def dispatch_line(self, sysframe):
        with self.pause_tracing():
            global CURR_FRAME_ID
            CURR_FRAME_ID += 1

            frame = Frame.from_sysframe(sysframe, CURR_FRAME_ID, PREV_FRAME_IDS[-1])

            sql = f"""
            INSERT INTO frames (run_id, f_id, f_back_id, f_filename, f_funcname, f_lineno, f_locals)
            VALUES (?, ?, ?, ?, ?, ?, ?)
            """
            args = (
                self.run_id,
                frame.f_id,
                frame.f_back_id,
                frame.f_filename,
                frame.f_funcname,
                frame.f_lineno,
                json.dumps(converter.unstructure(frame.f_locals)),
            )
            self.cursor.execute(sql, args)

            sys.settrace(self.tracefunc)

    def dispatch_return(self, frame):
        PREV_FRAME_IDS.pop()

    def dispatch_exception(self, frame):
        pass

    def dispatch_opcode(self, frame):
        pass


from django.db import models
from voyage.models import Voyage
# Create your models here.
class Excursion(models.Model):
    nom=models.CharField(max_length=100,null=True)
    photoexcursion = models.ImageField(upload_to='pics',default=False)
    optionnelle=models.BooleanField(default=False)
    voyage = models.ManyToManyField(Voyage)
    date_creation=models.DateTimeField(auto_now_add=True,null=True)

    def __str__(self):
        return self.nom


from tensorflow.python.keras.saving import save

import h5py
import json
import inspect

from deepposekit.models.layers.util import ImageNormalization
from deepposekit.models.layers.convolutional import (
    UpSampling2D,
    SubPixelDownscaling,
    SubPixelUpscaling,
)
from deepposekit.models.layers.deeplabcut import ImageNetPreprocess

from deepposekit.io import TrainingGenerator
from deepposekit.models.LEAP import LEAP
from deepposekit.models.StackedDenseNet import StackedDenseNet
from deepposekit.models.StackedHourglass import StackedHourglass
from deepposekit.models.DeepLabCut import DeepLabCut

MODELS = {
    "LEAP": LEAP,
    "StackedDenseNet": StackedDenseNet,
    "StackedHourglass": StackedHourglass,
    "DeepLabCut": DeepLabCut,
}

CUSTOM_LAYERS = {
    "ImageNormalization": ImageNormalization,
    "UpSampling2D": UpSampling2D,
    "SubPixelDownscaling": SubPixelDownscaling,
    "SubPixelUpscaling": SubPixelUpscaling,
    "ImageNetPreprocess": ImageNetPreprocess,
}

def load_model(path, generator=None, augmenter=None, custom_objects=None, compile=True):
    """
    Load the model

    Example
    -------
    model = load_model('model.h5', augmenter)

    """
    if custom_objects:
        if isinstance(custom_objects, dict):
            base_objects = CUSTOM_LAYERS
            custom_objects = dict(
                list(base_objects.items()) + list(custom_objects.items())
            )
    else:
        custom_objects = CUSTOM_LAYERS

    if isinstance(path, str):
        if path.endswith(".h5") or path.endswith(".hdf5"):
            filepath = path
        else:
            raise ValueError("file must be .h5 file")
    else:
        raise TypeError("file must be type `str`")

    train_model = save.load_model(filepath, custom_objects=custom_objects, compile=compile)

    with h5py.File(filepath, "r") as h5file:
        train_generator_config = h5file.attrs.get("train_generator_config")
        if train_generator_config is None:
            raise ValueError("No data generator found in config file")
        train_generator_config = json.loads(train_generator_config.decode("utf-8"))[
            "config"
        ]

        model_config = h5file.attrs.get("pose_model_config")
        if model_config is None:
            raise ValueError("No pose model found in config file")
        model_name = json.loads(model_config.decode("utf-8"))["class_name"]
        model_config = json.loads(model_config.decode("utf-8"))["config"]

    if generator is not None:
        signature = inspect.signature(TrainingGenerator.__init__)
        keys = [key for key in signature.parameters.keys()]
        keys.remove("self")
        keys.remove("augmenter")
        keys.remove("generator")
        kwargs = {key: train_generator_config[key] for key in keys}
        kwargs["augmenter"] = augmenter
        kwargs["generator"] = generator
        train_generator = TrainingGenerator(**kwargs)
    else:
        train_generator = None

    Model = MODELS[model_name]
    signature = inspect.signature(Model.__init__)
    keys = [key for key in signature.parameters.keys()]
    keys.remove("self")
    keys.remove("train_generator")
    if "kwargs" in keys:
        keys.remove("kwargs")
    kwargs = {key: model_config[key] for key in keys}
    kwargs["train_generator"] = train_generator

    # Pass to skip initialization and manually intialize
    kwargs["skip_init"] = True

    model = Model(**kwargs)
    model.train_model = train_model
    model.__init_train_model__()
    model.__init_input__(model_config["image_shape"])

    kwargs = {}
    kwargs["output_shape"] = model_config["output_shape"]
    kwargs["keypoints_shape"] = model_config["keypoints_shape"]
    kwargs["downsample_factor"] = model_config["downsample_factor"]
    kwargs["output_sigma"] = model_config["output_sigma"]
    model.__init_predict_model__(**kwargs)

    return model


from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
from PyQt5 import QtWidgets as qtw

# ################################
# SEE COMMENTS AT END OF THIS FILE
# ################################
from io import StringIO

from gui.qualityTabGui import Ui_Form
#
from psSettings import PSSettings

from picamera import PiCamera
from time import sleep
import sys
import datetime
import json
import psFunctions
import subprocess

class QualityTab(qtw.QWidget):

    def __init__(self, camvals, camera):
        super().__init__()
        self.comboItemsAdded = False
        # camvals = None means we are running the code as stand alone
        # so we need to load the settings file
        if camvals == None:
            with open("settings.json", "r") as settings:
                self.camvals = json.load(settings)
        else:
            self.camvals = camvals
        self.camera = camera
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        # add combo box items
        self.soundDevs = self.getSoundDevs(self)
        self.comboItemsAdded = self.addItemsToCombos(self)

        self.applySettings()
        print(self.soundDevs)
        if len(self.soundDevs) == 0:
            self.setActiveStates()

    def setActiveStates(self):
        self.ui.audioBitRate.setEnabled(False)
        self.ui.audioSampleRate.setEnabled(False)
        self.ui.audioFileFormat.setEnabled(False)
        self.ui.soundDevices.setEnabled(False)
        self.ui.audioActive.setEnabled(False)
        self.ui.mux.setEnabled(False)

    def getSoundDevs(*args):
        # initialise the list of sound devices
        soundDevs=list()
        #get the operating system to run the command "arecord -D"
        # this returns a list of sound devices capable of recording to the
        # object soundevs.stdout
        # stdout is the standard output from the program. I.e. the list
        # of sound devices that would be printed tp the screen if you ran
        # arecord -D from the command line in the usual way
        soundevs = subprocess.run(["arecord", "-L"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, \
            check=True, text=True)

        # we convert the returned object to a StringIO type object
        # which we can then parse as if it were a file
        buffer = StringIO(soundevs.stdout)
        # rest of code as before, but now we have gathered the data dynamically
        for line in buffer:
            if line.startswith('hw:CARD='):
                line=line.replace('hw:CARD=','')
                ix=line.find(',')
                devname=(line[0:ix])
                endix=(len(line)-1)
                startix=line.rfind('=')+1
                devnum=(line[startix:endix])
                dev=('hw:'+devname+','+devnum)
                soundDevs.append(dev)
        # return a list of hardware record devices
        return soundDevs

    def addItemsToCombos(*args):
        args[0].ui.audioBitRate.addItems(["8", "16", "24", "48"])
        args[0].ui.audioSampleRate.addItems(["44100", "48000"])
        args[0].ui.audioFileFormat.addItems(["wav", "aiff", "bollo"])
        args[0].ui.videoBitRate.addItems(["0", "2000000", "4000000","8000000", "17000000"])
        args[0].ui.videoQuality.addItems(["10", "20", "25", "30", "35", "40"])
        args[0].ui.videoProfile.addItems(["baseline", "main", "extended", "high", "constrained"])
        args[0].ui.videoLevel.addItems(["4","4.1", "4.2"])
        args[0].ui.iso.addItems(["0", "100", "200", "320", "400", "500", "640", "800"])
        args[0].ui.soundDevices.addItems(args[0].soundDevs)
        return True

    def applySettings(self):
        if self.comboItemsAdded == True:
            #for each key in the settings dictionery
            self.ui.audioBitRate.setCurrentText(str(self.camvals["audioBitRate"]))
            self.ui.audioSampleRate.setCurrentText(str(self.camvals["audioSampleRate"]))
            self.ui.audioFileFormat.setCurrentText(str(self.camvals["audioFileFormat"]))
            self.ui.videoBitRate.setCurrentText(str(self.camvals["videoBitRate"]))
            self.ui.videoQuality.setCurrentText(str(self.camvals["videoQuality"]))
            self.ui.soundDevices.setCurrentText(str(self.camvals["soundDevices"]))
            if self.camvals["mux"] == "true":
                state = True
            else:
                state = False
            self.ui.mux.setChecked(state)
            if self.camvals["audioActive"] == "true":
                state = True
            else:
                state = False
            self.ui.audioActive.setChecked(state)
            self.ui.videoProfile.setCurrentText(str(self.camvals["videoProfile"]))
            self.ui.videoLevel.setCurrentText(str(self.camvals["videoLevel"]))
            self.ui.iso.setCurrentText(str(self.camvals["iso"]))

    def setCamValFromCombo(self, str):
        if self.comboItemsAdded == True:
            self.camvals[self.sender().objectName()] = str
            #setattr(self.camera,self.sender().objectName(),str)

    def setIso(self,str):
        if self.comboItemsAdded == True:
            self.camvals["iso"] = int(str)
            self.camera.iso = int(str)

    def doMux(self, state):
        if state == True:
            self.camvals["mux"] = "true"
        else:
            self.camvals["mux"] = "false"

    def isAudioActive(self, state):
        if state == True:
            self.camvals["audioActive"] = "true"
        else:
            self.camvals["audioActive"] = "false"

#######################################################################################
    #                           END OF CLASS
#######################################################################################
if __name__ == "__main__":
    import sys
    # instiantiate an app object from the QApplication class
    app = qtw.QApplication(sys.argv)
    # get the settings
    camera = PiCamera()
        # pass the main window and camera objects to a settings object
    # settings = CameraSettings(camera)
    # instantiate an object containing the logic code
    qualityTab = QualityTab(None)
    qualityTab.show()
    sys.exit(app.exec_())

"""
https://en.wikipedia.org/wiki/Advanced_Video_Coding#Levels

Profiles
By far the most commonly used profile is the High Profile.

High Profile (HiP, 100)
The primary profile for broadcast and disc storage applications, particularly for high-definition television applications
(for example, this is the profile adopted by the Blu-ray Disc storage format and the DVB HDTV broadcast service).

available for us:
profile - The H.264 profile to use for encoding. Defaults to ‘high’, but can be one of
‘baseline’, ‘main’, ‘extended’, ‘high’, or ‘constrained’.

Levels
As the term is used in the standard, a "level" is a specified set of constraints that indicate a degree of required decoder
performance for a profile. For example, a level of support within a profile specifies the maximum picture resolution, frame rate,
and bit rate that a decoder may use. A decoder that conforms to a given level must be able to decode all bitstreams encoded for
that level and all lower levels.

level - The H.264 level to use for encoding. Defaults to ‘4’, but can be any H.264 level up to ‘4.2’.
                max bit rate max res/framerate
4	245,760	8,192	20,000	2,048×1,024@30.0 (4)
4.1	245,760	8,192	50,000	2,048×1,024@30.0 (4)
4.2	522,240	8,704	50,000	2,048×1,080@60.0 (4)

bitrate - The bitrate at which video will be encoded. Defaults to 17000000 (17Mbps) if not specified. The maximum value depends
on the selected H.264 level and profile.

Bitrate 0 indicates the encoder should not use bitrate control (the encoder is limited by the quality only).

quality - Specifies the quality that the encoder should attempt to maintain. For the 'h264' format, use values between
10 and 40 where 10 is extremely high quality, and 40 is extremely low (20-25 is usually a reasonable range for H.264 encoding).

For the mjpeg format, use JPEG quality values between 1 and 100 (where higher values are higher quality).
Quality 0 is special and seems to be a “reasonable quality” default.

END COMMENTS
"""


__author__ = 'alipirani'
import os
from config_settings import ConfigSectionMap
from sys import platform as _platform
from modules.log_modules import keep_logging
from modules.logging_subprocess import *

def vcftools_vcf2fasta_filter2(only_snp_filter2_vcf, out_path, analysis, reference, logger, Config):
    bgzip_cmd = "bgzip -f %s" % (only_snp_filter2_vcf)
    tabix_cmd = "tabix %s.gz" % (only_snp_filter2_vcf)
    vcftools_vcf2fasta_filter2_cmd = "cat %s | vcf-consensus %s.gz > %s_filter2_consensus.fa" % (reference, only_snp_filter2_vcf, only_snp_filter2_vcf)
    try:
        call(bgzip_cmd, logger)
        call(tabix_cmd, logger)
        call(vcftools_vcf2fasta_filter2_cmd, logger)
    except sp.CalledProcessError:
        keep_logging('- Error in vcftools vcf 2 fasta step. Exiting.', '- Error in vcftools vcf 2 fasta step. Exiting.', logger, 'exception')
        sys.exit(1)
    bash_script_file = "%s.sh" % (only_snp_filter2_vcf)
    f1=open(bash_script_file, 'w+')
    f1.write(vcftools_vcf2fasta_filter2_cmd)
    bash_command = "bash %s" % bash_script_file
    keep_logging(bash_command, bash_command, logger, 'debug')
    call(bash_command, logger)
    if _platform == "darwin":
        change_header_cmd = "sed -i '' 's/>.*/>%s/g' %s_filter2_consensus.fa" % (analysis, only_snp_filter2_vcf)
        call(change_header_cmd, logger)
        keep_logging(change_header_cmd, change_header_cmd, logger, 'debug')
    else:
        change_header_cmd = "sed -i 's/>.*/>%s/g' %s_filter2_consensus.fa" % (analysis, only_snp_filter2_vcf)
        call(change_header_cmd, logger)
        keep_logging(change_header_cmd, change_header_cmd, logger, 'debug')

def vcfstats(final_raw_vcf, out_path, analysis, logger, Config):
    bgzip_cmd = "bgzip -f -c %s > %s/%s_aln_mpileup_raw.vcf_5bp_indel_removed.vcf.gz" % (final_raw_vcf, out_path, analysis)
    tabix_cmd = "tabix -f %s.gz" % (final_raw_vcf)
    vcfstat_cmd = "vcf-stats %s.gz > %s/%s_vcf_stats" % (final_raw_vcf, out_path, analysis)
    try:
        call(bgzip_cmd, logger)
        call(tabix_cmd, logger)
        call(vcfstat_cmd, logger)
    except sp.CalledProcessError:
        keep_logging('- Error in vcftools vcf stats step. Exiting.', '- Error in vcftools vcf stats step. Exiting.', logger, 'exception')
        sys.exit(1)
    vcf_stats_file = "%s/%s_vcf_stats" % (out_path, analysis)
    return vcf_stats_file

def only_snp_filter2_vcf(gatk_filter2_final_vcf, out_path, analysis, reference):
    onlysnp_filter2_cmd = "vcftools --vcf %s --remove-indels --recode --recode-INFO-all --out %s/%s_filter2_onlysnp.vcf" % (gatk_filter2_final_vcf, out_path, analysis)
    keep_logging('Running Command: [%s]' % onlysnp_filter2_cmd, 'Running Command: [%s]' % onlysnp_filter2_cmd, logger, 'info')
    keep_logging(onlysnp_filter2_cmd, onlysnp_filter2_cmd, logger, 'debug')
    only_snp_filter2_vcf_file = "%s/%s_filter2_onlysnp.vcf.recode.vcf" % (out_path, analysis)
    return only_snp_filter2_vcf_file

def only_snp_filter1_vcf(gatk_filter1_final_vcf, out_path, analysis, reference):
    onlysnp_filter1_cmd = "vcftools --vcf %s --remove-indels --recode --recode-INFO-all --out %s/%s_filter1_onlysnp.vcf" % (gatk_filter1_final_vcf, out_path, analysis)
    keep_logging('Running Command: [%s]' % onlysnp_filter1_cmd, 'Running Command: [%s]' % onlysnp_filter1_cmd, logger, 'info')
    keep_logging(onlysnp_filter1_cmd, onlysnp_filter1_cmd, logger, 'debug')
    only_snp_filter1_vcf_file = "%s/%s_filter1_onlysnp.vcf.recode.vcf" % (out_path, analysis)
    return only_snp_filter1_vcf_file

def only_snp_raw_vcf(final_raw_vcf, out_path, analysis, reference):
    onlysnp_raw_cmd = "vcftools --vcf %s --remove-indels --recode --recode-INFO-all --out %s/%s_raw_onlysnp.vcf" % (final_raw_vcf, out_path, analysis)
    keep_logging(onlysnp_raw_cmd, onlysnp_raw_cmd, logger, 'debug')
    only_snp_raw_vcf_file = "%s/%s_raw_onlysnp.vcf.recode.vcf" % (out_path, analysis)
    return only_snp_raw_vcf_file

def vcftools_vcf2fasta_filter1(only_snp_filter1_vcf_file, out_path, analysis, reference):
    bgzip_cmd = "bgzip -f %s" % (only_snp_filter1_vcf_file)
    keep_logging(bgzip_cmd, bgzip_cmd, logger, 'debug')
    try:
        call(bgzip_cmd, logger)
    except sp.CalledProcessError:
        keep_logging('Error in vcf2fasta step', 'Error in vcf2fasta step', logger, 'exception')
        sys.exit(1)
    tabix_cmd = "tabix %s.gz" % (only_snp_filter1_vcf_file)
    keep_logging(tabix_cmd, tabix_cmd, logger, 'debug')
    vcftools_vcf2fasta_filter1_cmd = "cat %s | vcf-consensus %s.gz > %s/%s_filter1_consensus.fa" % (reference, only_snp_filter1_vcf_file, out_path, analysis)
    keep_logging('Running Command: [%s]' % vcftools_vcf2fasta_filter1_cmd, 'Running Command: [%s]' % vcftools_vcf2fasta_filter1_cmd, logger, 'info')
    if _platform == "darwin":
        change_header_cmd = "sed -i '' 's/>.*/>%s/g' %s/%s_filter1_consensus.fa" % (analysis, out_path, analysis)
        keep_logging(change_header_cmd, change_header_cmd, logger, 'debug')
    else:
        change_header_cmd = "sed -i 's/>.*/>%s/g' %s/%s_filter1_consensus.fa" % (analysis, out_path, analysis)
        keep_logging(change_header_cmd, change_header_cmd, logger, 'debug')