#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Commands, largely through subprocess.

Attributes:
  LOGGER_NAME (str): default logging.Logger name.
  STRINGS (Dict[str, Dict[str, str]]): Strings for logging.
"""
from __future__ import absolute_import, division, print_function, \
                       unicode_literals
from contextlib import contextmanager
from copy import deepcopy
import logging
import multiprocessing
import os
import six
import pprint
from scriptharness.errorlists import ErrorList
from scriptharness.exceptions import ScriptHarnessError, \
    ScriptHarnessException, ScriptHarnessFatal, ScriptHarnessTimeout
from scriptharness.log import OutputParser
import scriptharness.process
import scriptharness.status
from scriptharness.unicode import to_unicode
import subprocess
import tempfile

# Constants {{{1
LOGGER_NAME = "scriptharness.commands"
STRINGS = {
    "check_output": {
        "pre_msg":
            "Running subprocess.check_output() with %(args)s %(kwargs)s",
    },
    "command": {
        "cwd_doesn't_exist":
            "Can't run command %(command)s in non-existent directory %(cwd)s!",
        "start_with_cwd": "Running command: %(command)s in %(cwd)s",
        "start_without_cwd": "Running command: %(command)s",
        "copy_paste": "Copy/paste: %(command)s",
        "output_timeout":
            "Command %(command)s timed out after %(output_timeout)d "
            "seconds without output.",
        "timeout":
            "Command %(command)s timed out after %(run_time)d seconds.",
        "error": "Command %(command)s failed.",
        "env": "Using env: %(env)s",
        "kill_hung_process": "Killing process that's still here",
    },
    "output": {
        "cwd_doesn't_exist":
            "Can't get output from command %(command)s in non-existent "
            "directory %(cwd)s!",
        "start_with_cwd": "Getting output from command: %(command)s in "
                          "%(cwd)s",
        "start_without_cwd": "Getting output from command: %(command)s",
        "copy_paste": "Copy/paste: %(command)s",
        "output_timeout":
            "Command %(command)s timed out after %(output_timeout)d "
            "seconds without output.",
        "timeout":
            "Command %(command)s timed out after %(run_time)d seconds.",
        "error": "Command %(command)s failed.",
        "env": "Using env: %(env)s",
        "kill_hung_process": "Killing process that's still here",
        "temp_files": "Temporary files: stdout %(stdout)s; stderr %(stderr)s",
    },
}

# Helper functions {{{1
def check_output(command, logger_name="scriptharness.commands.check_output",
                 level=logging.INFO, log_output=True, **kwargs):
    """Wrap subprocess.check_output with logging

    Args:
      command (str or List[str]): The command to run.
      logger_name (Optional[str]): the logger name to log with.

      level (Optional[int]): the logging level to log with.  Defaults to
        logging.INFO

      log_output (Optional[bool]): When true, log the output of the command.
        Defaults to True.

      **kwargs: sent to `subprocess.check_output()`
    """
    logger = logging.getLogger(logger_name)
    logger.log(level, STRINGS['check_output']['pre_msg'],
               {'args': (), 'kwargs': kwargs})
    output = subprocess.check_output(command, **kwargs)
    if log_output:
        logger = logging.getLogger(logger_name)
        logger.info("Output:")
        for line in output.splitlines():
            logger.log(level, " %s", line)
    return output

def detect_errors(command):
    """Very basic detect_errors_cb for Command.

    This looks in the command.history for return_value.  If this is set
    to 0 or other null value other than None, the command is successful.
    Otherwise it's unsuccessful.

    Args:
      command (Command): instance of `Command` class
    """
    status = scriptharness.status.SUCCESS
    return_value = command.history.get('return_value')
    if return_value is None or return_value:
        status = scriptharness.status.ERROR
    return status

def detect_parsed_errors(command):
    """Very basic detect_errors_cb for ParsedCommand.

    This looks in the command.history for num_errors.  If this is set
    to 0, the command is successful.  Otherwise it's unsuccessful.

    Args:
      command (Command): instance of `Command` class
    """
    status = scriptharness.status.SUCCESS
    if command.parser.history.get('num_errors'):
        status = scriptharness.status.ERROR
    return status

# Command {{{1
class Command(object):
    """Basic command: run and log output.  Stdout and stderr are interleaved
    depending on the timing of the message.  Because we're logging output,
    we're expecting text/non-binary output only.  For binary output, use the
    scriptharness.commands.Output object.

    Attributes:
      command (List[str] or str): The command to send to subprocess.Popen

      logger (logging.Logger): logger to log with.

      detect_error_cb (Callable[[Any], scriptharness.status]): this function
        determines whether the command was successful.

      history (Dict[str, Any]): This dictionary holds the timestamps and status of
        the command.

      kwargs (Dict[Any, Any]): These kwargs will be passed to subprocess.Popen, except
        for the optional 'output_timeout' and 'timeout', which are processed by
        Command.  `output_timeout` is how long a command can run without
        outputting anything to the screen/log.  `timeout` is how long the
        command can run, total.

      strings (Dict[str, str]): Strings to log.
    """
    def __init__(self, command, logger=None, detect_error_cb=None, **kwargs):
        self.command = command
        self.logger = logger or logging.getLogger(LOGGER_NAME)
        self.detect_error_cb = detect_error_cb or detect_errors
        self.history = {}
        self.kwargs = kwargs or {}
        self.strings = deepcopy(STRINGS['command'])

    def log_env(self, env):
        """Log environment variables.  Here for subclassing.

        Args:
          env (Dict[str, str]): the environment we'll be passing to subprocess.Popen.
        """
        env = self.fix_env(env)
        self.logger.info(self.strings['env'], {'env': pprint.pformat(env)})

    @staticmethod
    def fix_env(env):
        """Windows environments are fiddly.

        Args:
          env (Dict[str, str]): the environment we'll be passing to subprocess.Popen.

        Returns:
          Dict[bytes, bytes]: copy of the env key and values but as byte strings
        """
        if os.name == 'nt':
            env.setdefault("SystemRoot", os.environ["SystemRoot"])
            if six.PY2:
                new_env = {}
                # Win Py2 unhappy with unicode env vars
                for key, value in env.items():
                    if isinstance(key, six.text_type):
                        key = six.binary_type(key)
                    if isinstance(value, six.text_type):
                        value = six.binary_type(value)
                    new_env[key] = value
                env = new_env
        return env

    def log_start(self):
        """Log the start of the command, also checking for the existence of
        cwd if defined.

        Raises:
          scriptharness.exceptions.ScriptHarnessException: if cwd is defined
            and doesn't exist.
        """
        if 'cwd' in self.kwargs:
            if not os.path.isdir(self.kwargs['cwd']):
                raise ScriptHarnessException(
                    self.strings["cwd_doesn't_exist"] %
                    {'cwd': self.kwargs['cwd'], 'command': self.command}
                )
            self.logger.info(
                self.strings["start_with_cwd"],
                {'cwd': self.kwargs['cwd'], 'command': self.command}
            )
        else:
            self.logger.info(
                self.strings["start_without_cwd"], {'command': self.command}
            )
        if isinstance(self.command, (list, tuple)):
            self.logger.info(
                self.strings["copy_paste"],
                {'command': subprocess.list2cmdline(self.command)}
            )
        if 'env' in self.kwargs:
            # https://mail.python.org/pipermail/python-dev/2011-December/114740.html
            self.log_env(self.kwargs['env'])

    def add_line(self, line):
        """Log the output.  Here for subclassing.

        Args:
          line (str): a line of output
        """
        self.logger.info(" %s", to_unicode(line.rstrip()))

    def finish_process(self):
        """Here for subclassing.
        """
        if self.history['status'] != scriptharness.status.SUCCESS:
            raise ScriptHarnessError(
                self.strings["error"] % {'command': self.command, }
            )

    def run(self):
        """Run the command.

        Raises:
          scriptharness.exceptions.ScriptHarnessError on error
        """
        if 'env' in self.kwargs:
            self.kwargs['env'] = self.fix_env(self.kwargs['env'])
        self.log_start()
        output_timeout = self.kwargs.get('output_timeout', None)
        if 'output_timeout' in self.kwargs:
            del self.kwargs['output_timeout']
        max_timeout = self.kwargs.get('timeout', None)
        if 'timeout' in self.kwargs:
            del self.kwargs['timeout']
        if isinstance(self.command, (list, tuple)):
            self.kwargs.setdefault('shell', False)
        else:
            self.kwargs.setdefault('shell', True)
        queue = multiprocessing.Queue()  # pylint: disable=no-member
        runner = multiprocessing.Process(  # pylint: disable=not-callable
            target=scriptharness.process.command_subprocess,
            args=(queue, self.command),
            kwargs=self.kwargs,
        )
        runner.start()
        self.history['return_value'] = scriptharness.process.watch_command(
            self.logger, queue, runner, self.add_line,
            output_timeout=output_timeout, max_timeout=max_timeout
        )
        self.history['status'] = self.detect_error_cb(self)
        self.finish_process()
        return self.history['status']

# ParsedCommand {{{1
class ParsedCommand(Command):
    """Parse each line of output for errors.

    This class could have easily subclassed both OutputParser and Command;
    that may have been slightly cleaner.  However, people have subclassed
    OutputParser in mozharness for various purposes; keeping the two objects
    separate may encourage that behavior.
    """
    def __init__(self, command, error_list=None, parser=None, **kwargs):
        if not parser:
            if not isinstance(error_list, ErrorList):
                raise ScriptHarnessException(
                    "error_list must be an ErrorList!",
                    error_list
                )
            parser = OutputParser(error_list)
        self.parser = parser
        kwargs.setdefault("detect_error_cb", detect_parsed_errors)
        Command.__init__(self, command, **kwargs)

    def add_line(self, line):
        """Send the line to the parser.

        Args:
          line (str): a line of output
        """
        self.parser.add_line(line)

# Output {{{1
class Output(Command):
    """Run the command and capture stdout and stderr to separate files.
    The output can be binary or text.

    Attributes:
      strings (Dict[str, str]): Strings to log.
      stdout (NamedTemporaryFile): file to log stdout to

      stderr (NamedTemporaryFile): file to log stderr to

      + all of the attributes in scriptharness.commands.Command
    """
    def __init__(self, *args, **kwargs):
        super(Output, self).__init__(*args, **kwargs)
        self.strings = deepcopy(STRINGS['output'])
        keywargs = {'delete': False}
        if six.PY2:
            keywargs['bufsize'] = 0
        else:
            keywargs['buffering'] = 0
        self.stdout = tempfile.NamedTemporaryFile(**keywargs)
        self.stderr = tempfile.NamedTemporaryFile(**keywargs)
        self.logger.debug(
            self.strings['temp_files'], {
                'stdout': self.stdout,
                'stderr': self.stderr,
            },
        )

    def finish_process(self):
        """Close the filehandles.
        """
        self.stderr.close()
        self.stdout.close()
        super(Output, self).finish_process()

    def run(self):
        """Output.run()
        """
        if 'env' in self.kwargs:
            self.kwargs['env'] = self.fix_env(self.kwargs['env'])
        self.log_start()
        output_timeout = self.kwargs.get('output_timeout', None)
        if 'output_timeout' in self.kwargs:
            del self.kwargs['output_timeout']
        max_timeout = self.kwargs.get('timeout', None)
        if 'timeout' in self.kwargs:
            del self.kwargs['timeout']
        if isinstance(self.command, (list, tuple)):
            self.kwargs.setdefault('shell', False)
        else:
            self.kwargs.setdefault('shell', True)
        self.kwargs['stdout'] = self.stdout.file
        self.kwargs['stderr'] = self.stderr.file
        try:
            process = subprocess.Popen(self.command, **self.kwargs)
        except OSError as exc_info:
            raise ScriptHarnessError(
                "Can't run command!", self.command, exc_info
            )
        self.history['return_value'] = scriptharness.process.watch_output(
            self.logger, process, self.stdout, self.stderr,
            output_timeout=output_timeout, max_timeout=max_timeout
        )
        self.history['status'] = self.detect_error_cb(self)
        self.finish_process()
        return self.history['status']

    def get_output(self, handle_name="stdout", text=True):
        """Get output from file.  This reads the output into memory, so
        this is not appropriate for large amounts of output.

        Args:
          handle_name (Optional["stdout" or "stderr"]): the handle to read
            from.  Defaults to "stdout"

          text (Optional[bool]): whether the output is text.  If so, run
            output through to_unicode() and rstrip().  Defaults to True.
        """
        if handle_name not in ("stdout", "stderr"):
            raise ScriptHarnessException("Bad handle for get_output: %s" %
                                         handle_name)
        handle = getattr(self, handle_name)
        with open(handle.name) as filehandle:
            contents = filehandle.read()
        if text:
            contents = to_unicode(contents).rstrip()
        return contents

    def cleanup(self):
        """Best effort cleanup of stdout and stderr temp files.
        """
        for handle in self.stdout, self.stderr:
            try:
                handle.close()
                os.remove(handle.name)
            except Exception:  # pylint: disable=broad-except
                # Broad exception especially for windows nosetests
                pass

# run {{{1
def run(command, cmd_class=Command, halt_on_failure=False, *args, **kwargs):
    """Shortcut for running a Command.

    Not entirely sure if this should also catch ScriptHarnessFatal, as those
    are explicitly trying to kill the script.

    Args:
      command (List[str] or str): Command line to run.

      cmd_class (Optional[Command subclass]): the class to instantiate.
        Defaults to scriptharness.commands.Command.

      halt_on_failure (Optional[bool]): raise ScriptHarnessFatal on error
        if True.  Default: False

      **kwargs: kwargs for subprocess.Popen.

    Returns:
      int: command exit code

    Raises:
      scriptharness.exceptions.ScriptHarnessFatal: on fatal error
    """
    message = ""
    try:
        cmd = cmd_class(command, *args, **kwargs)
        cmd.run()
        return cmd
    except ScriptHarnessError as exc_info:
        message = "error: %s" % exc_info
        status = scriptharness.status.ERROR
    except ScriptHarnessTimeout as exc_info:
        message = "timeout: %s" % exc_info
        status = scriptharness.status.TIMEOUT
    if halt_on_failure and message:
        raise ScriptHarnessFatal("Fatal %s" % message)
    else:
        cmd.history.setdefault('status', status)
        return cmd

# parse {{{1
def parse(command, **kwargs):
    """Shortcut for running a ParsedCommand.

    Not entirely sure if this should also catch ScriptHarnessFatal, as those
    are explicitly trying to kill the script.

    Args:
      command (List[str] or str): Command line to run.

      **kwargs: kwargs for run/ParsedCommand.

    Returns:
      int: command exit code

    Raises:
      scriptharness.exceptions.ScriptHarnessFatal: on fatal error
    """
    return run(command, cmd_class=ParsedCommand, **kwargs)

# get_output {{{1
@contextmanager
def get_output(command, halt_on_failure=False, **kwargs):
    """Run command and yield the Output cmd object.
    The stdout and stderr file paths can be retrieved through cmd.stdout and
    cmd.stderr, respectively.

    The output is not logged, and is written as byte data, so this can work
    for both binary or text.  If text, get_text_output is preferred for full
    logging, unless the output is either sensitive in nature or so verbose
    that logging it would be more harmful than useful.  Also, if text,
    most likely the consumer will want to pass the output through
    scriptharness.unicode.to_unicode().

    Args:
      command (List[str] or str): the command to use in subprocess.Popen

      halt_on_failure (Optional[bool]): raise ScriptHarnessFatal on error
        if True.  Default: False

      **kwargs: kwargs to send to scriptharness.commands.Output

    Yields:
      cmd (scriptharness.commands.Output)

    Raises:
      scriptharness.exceptions.ScriptHarnessFatal: when halt_on_failure is
        True and we hit an error or timeout.
    """
    cmd = Output(command, **kwargs)
    status = scriptharness.status.SUCCESS
    message = None
    try:
        cmd.run()
    except ScriptHarnessError as exc_info:
        message = "error: %s" % exc_info
        status = scriptharness.status.ERROR
    except ScriptHarnessTimeout as exc_info:
        message = "timeout: %s" % exc_info
        status = scriptharness.status.TIMEOUT
    if halt_on_failure and message:
        raise ScriptHarnessFatal("Fatal %s" % message)
    else:
        cmd.history.setdefault("status", status)
    try:
        yield cmd
    finally:
        cmd.cleanup()

# get_text_output {{{1
def get_text_output(command, level=logging.INFO, **kwargs):
    """Run command and return the raw stdout from that command.
    Because we log the output, we're assuming the output is text.

    Args:
      command (List[str] or str): command for subprocess.Popen

      level (int): logging level

      **kwargs: kwargs to send to scriptharness.commands.Output

    Returns:
      output (str): the stdout from the command.
    """
    cmd = Output(command, **kwargs)
    with get_output(command, **kwargs) as cmd:
        output = cmd.get_output()
        cmd.logger.log(level, "Got output:")
        for line in output.splitlines():
            cmd.logger.log(level, " {}".format(line.rstrip()))
    return output


import numpy as np
import matplotlib.pyplot as plt
import control as ctl

##Parameters
g = 9.81
L = 1.0
m = 5.0
#Roots of Zeros
z1 = -10
z2 = -4
#(s + o+wj) * (s + o-wj)
#(s^2 + (o+wj)*s + (o-wj)*s + (o+wj)*(o-wj))
alfa = -(z1+z2)
beta = z1*z2
print(alfa,beta)

def Controller(k):
    global alfa,beta
    N = [k,k*alfa,k*beta]
    D = [1,0]
    C = ctl.tf(N,D)
    zeros = np.roots(N)
    poles = np.roots(D)
    return C,zeros,poles

##DEFINE THE PLANT
G = ctl.tf([1/(m*L**2)],[1,0,-g/L])

##PLOT POLES AND ZEROS OF PLANT AND CONTROLLER
open_poles = ctl.pole(G)
open_zeros = ctl.zero(G)
plt.plot(np.real(open_poles),np.imag(open_poles),'gx',label='Plant Open Loop Poles',markersize=15)
plt.plot(np.real(open_zeros),np.imag(open_zeros),'go',label='Plant Zeros',markersize=10)
C,zeros,poles = Controller(1)
plt.plot(np.real(zeros),np.imag(zeros),'ro',label='Control Zeros',markersize=10)
plt.plot(np.real(poles),np.imag(poles),'rx',label='Control Poles',markersize=15)

###LOOP ON K TO MAKE LOCUS
k_vec = np.linspace(0,1000,1000)
for k in k_vec:
    #print(k)
    C,zeros,poles = Controller(k)
    GCL = C*G/(1+C*G)
    poles = ctl.pole(GCL)
    plt.plot(np.real(poles),np.imag(poles),'b*')
plt.legend()
plt.grid()
plt.show()


class Solution(object):
    def threeSumSmaller(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        if not nums: 0
        res = 0
        nums = sorted(nums)
        for i in range(len(nums) - 2):
            start, end = i + 1, len(nums) - 1
            while start < end:
                if nums[i] + nums[start] + nums[end] < target:
                    res += end - start
                    start += 1
                else:
                    end -= 1
        return res


import investpy as ip
from pytz import country_names
import streamlit as st
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import plotly.graph_objects as go

# Função para consultar as Ações
@st.cache
def consultar_acao(stock, country, from_date, to_date, interval):
    df = ip.get_stock_historical_data(stock=stock, country=country, from_date=from_date, to_date=to_date, interval=interval)
    return df.head()

def format_date(dt, format='%d/%m/%Y'):
    return dt.strftime(format)

def plotCandleStick(df, acao='ticket'):
    tracel = {
        'x':df.index,
        'open':df.Open,
        'close':df.Close,
        'high':df.High,
        'low':df.Low,
        'type': 'candlestick',
        'name':acao,
        'showlegend':False

    }
    data = [tracel]
    layout = go.Layout()
    fig = go.Figure(data=data, layout=layout)

    return fig

# Captando as ações
pais_br = ['Brasil', 'Estados Unidos']
paises = ['brazil', 'united states']
intervalo = ['Daily', 'Weekly', 'Mounthy']
intervalo_br = ['Dia', 'Semana', 'Mês']
titulo = st.header('Gráfio de açoes')

# Consulta(query) das Açoes
dt_inicio = datetime.today() - timedelta(days=30)
dt_fim = datetime.today()

selecao_pais = st.sidebar.selectbox('Selecione o pais:', pais_br)
if selecao_pais == 'Brasil':
    selecao_pais = paises[0]
else:
    selecao_pais = paises[1]

acoes = ip.get_stocks_list(country=selecao_pais)

selecao_acoes = st.sidebar.selectbox('Escolha uma ação', acoes)
from_date = st.sidebar.date_input('De:',dt_inicio)
to_date = st.sidebar.date_input('De:', dt_fim)

seleca_intervalo = st.sidebar.selectbox('Selecione o Intervalo', intervalo_br)
if seleca_intervalo == 'Dia':
    seleca_intervalo = intervalo[0]
elif seleca_intervalo == 'Semana':
    seleca_intervalo = intervalo[1]
else:
    seleca_intervalo = intervalo[2]

carregar_dados = st.sidebar.checkbox('Carregar Dados')

format_date(from_date)
format_date(to_date)

grafico_candle = st.empty()
grafico_line = st.empty()

if from_date > to_date:
    st.sidebar.error('Data de inicio maior do que a data final')
else:
    df = consultar_acao(selecao_acoes, selecao_pais, format_date(dt_inicio), format_date(dt_fim), seleca_intervalo)
    try:
        fig = plotCandleStick(df)
        grafico_candle = st.plotly_chart(fig)
        grafico_line = st.line_chart(df.Close)

        if carregar_dados:
            st.subheader('Dados')
            dados = st.dataframe(df)
    except Exception as e:
        st.error(e)


#import phonenumbers
import re
from django import template
from django.template.defaultfilters import stringfilter

register = template.Library()

@register.filter
@stringfilter
def phonenumber(value):
    usa_phone = re.compile('^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$')
    int_phone = re.compile('^\+(?:[0-9] ?){6,14}[0-9]$')
    string = usa_phone.search(value)
    if string:
        tuple = string.groups()
        return '('+tuple[0]+') '+tuple[1]+'-'+tuple[2]
    else:
        return value

"""
The complex way for internation phone numbers
    number = phonenumbers.parse(value,'US')
    return phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.NATIONAL)
"""


from sklearn.linear_model import LogisticRegression
from sklearn import neighbors
import numpy as np
from data import make_dataset, L

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable

from utils import make_knn, knn_loss

# ====================== DATA HOLDER WITH PORPORTIONAL SAMPLING =============
class DataHolder:
  def __init__(self, X, Y, weights):
    self.X = np.array(X)
    self.Y = np.array(Y)
    weights = np.array(weights)
    weights = weights / np.sum(weights) # normalized weights D: :D :D
    self.weights = weights

  # return the unweighted dataset, uniform weighted
  def get_all_set(self):
    return self.X, self.Y

  # return the entire dataset, properly weighted by duplications
  def get_all_set_weighted(self):
    min_prob = np.min(self.weights)
    multiple = (1 / min_prob)
    repeats = (multiple * self.weights).astype(int)
    retX = np.repeat(self.X, repeats, axis=0)
    retY = np.repeat(self.Y, repeats, axis=0)
    return retX, retY

  # return a sample of dataset smapled from the weight distribution
  def get_sample(self, n):
    sample_idx = np.random.choice(range(len(self.weights)),
                                     size=n,
                                     p=self.weights)
    return self.X[sample_idx, :], self.Y[sample_idx]

# ===================== FC NN CLASSIFIER =====================
def to_torch(x, dtype, req = False):
  tor_type = torch.cuda.LongTensor if dtype == "int" else torch.cuda.FloatTensor
  x = Variable(torch.from_numpy(x).type(tor_type), requires_grad = req)
  return x

class FCNet(nn.Module):

  def __init__(self):
    super(FCNet, self).__init__()
    self.name = "FCNet"
    self.fc = nn.Linear(L * 2, 16)
    self.pred = nn.Linear(16, 2)
    self.opt = torch.optim.Adam(self.parameters(), lr=0.001)

  def predict(self, x):
    x = F.relu(self.fc(x))
    x = F.log_softmax(self.pred(x), dim=1)
    return x

  def learn(self, train_corpus):

    losses = []
    while True:
      X_sub, Y_sub = train_corpus.get_sample(40)
      # convert to proper torch forms
      X_sub = to_torch(X_sub, "float")
      Y_sub = to_torch(Y_sub, "int")

      # optimize
      self.opt.zero_grad()
      output = self.predict(X_sub)
      loss = F.nll_loss(output, Y_sub)
      losses.append( loss.data.cpu().numpy() )
      # terminate if no improvement
      if loss < 1e-3 or min(losses) < min(losses[-1000:]):
        break
      loss.backward()
      self.opt.step()

  def evaluate(self, test_corpus):
    test_data, test_label = test_corpus
    test_data = to_torch(test_data, "float")
    label_pred = np.argmax(self.predict(test_data).data.cpu().numpy(), axis=1)
    return np.sum(label_pred == test_label) / len(test_label)

# ========================= LOGISTIC REGRESSION CLASSIFIER ========================
class LRegr:

  def __init__(self):
    self.name = "LRegr"

  def learn(self, train_corpus):
    train_data, train_label = train_corpus.get_all_set_weighted()
    logisticRegr = LogisticRegression(solver='sag')
    logisticRegr.fit(train_data, train_label)
    self.logisticRegr = logisticRegr

  def evaluate(self, test_corpus):
    test_data, test_label = test_corpus
    label_pred = self.logisticRegr.predict(test_data)
    return np.sum(label_pred == test_label) / len(test_label)

# ========================= KNN CLASSIFIER ========================
class KNN:

  def __init__(self):
    self.name = "KNN"

  def learn(self, train_corpus):
    train_data, train_label = train_corpus.get_all_set()
    self.knn = make_knn(train_data, train_label)

  def evaluate(self, test_corpus):
    test_data, test_label = test_corpus
    return 1.0 - (knn_loss(self.knn, test_data, test_label) / len(test_label))


import cv2 as cv
import numpy as np
import time
import os
import HandTrackingModule as htm

brushThickness = 25
eraserThickness = 100

folderPath = "/home/meghal/Personal/Konverge_AI/Training/Advance Computer Visions/AI Virtual Painter/Header"
myList = os.listdir(folderPath)
myList.sort()
print(myList)
overlayList = []

for imPath in myList:
    image = cv.imread(f"{folderPath}/{imPath}")
    overlayList.append(image)

#overlayList.sort()
print(len(overlayList))
header = overlayList[0]
drawColor = (255, 0, 255)

cap = cv.VideoCapture(0)
cap.set(3, 640)
cap.set(4, 480)

detector = htm.handDetector(detectionCon=0,maxHands=1)
xp, yp = 0, 0
vidCanvas = np.zeros((480, 640, 3), np.uint8)

while True:

    # 1. Import image
    success, vid = cap.read()
    vid = cv.flip(vid, 1)
    #print(vid.shape)

    # 2. Find Hand Landmarks
    vid = detector.findHands(vid)
    lmList = detector.findPosition(vid, draw=False)

    if len(lmList) != 0:
        print(lmList)
        # tip of index and middle fingers
        x1, y1 = lmList[8][1:]
        x2, y2 = lmList[12][1:]

        # 3. Check which fingers are up
        fingers = detector.fingersUp()
        # print(fingers)

        # 4. If Selection Mode – Two finger are up
        if fingers[1] and fingers[2]:
            # xp, yp = 0, 0
            #cv.rectangle(vid, (x1, y1-25), (x2, y2+25), (255, 0, 255), cv.FILLED)
            print("Selection Mode")

            # Checking for the click
            if y1 < 100:
                if 50 < x1 < 150:
                    header = overlayList[0]
                    drawColor = (255, 0, 255)
                elif 150 < x1 < 200:
                    header = overlayList[1]
                    drawColor = (255, 0, 0)
                elif 240 < x1 < 390:
                    header = overlayList[2]
                    drawColor = (0, 255, 0)
                elif 490 < x1 < 640:
                    header = overlayList[3]
                    drawColor = (0, 0, 0)
                cv.rectangle(vid, (x1, y1 - 25), (x2, y2 + 25), drawColor, cv.FILLED)

        # 5. If Drawing Mode – Index finger is up
        if fingers[1] and fingers[2] == False:
            cv.circle(vid, (x1, y1), 15, drawColor, cv.FILLED)
            print("Drawing Mode")

            if xp == 0 and yp == 0:
                xp, yp = x1, y1

            #cv.line(vid, (xp, yp), (x1, y1), drawColor, brushThickness)

            if drawColor == (0, 0, 0):
                cv.line(vid, (xp, yp), (x1, y1), drawColor, eraserThickness)
                cv.line(vidCanvas, (xp, yp), (x1, y1), drawColor, eraserThickness)
            else:
                cv.line(vid, (xp, yp), (x1, y1), drawColor, brushThickness)
                cv.line(vidCanvas, (xp, yp), (x1, y1), drawColor, brushThickness)

            xp, yp = x1, y1

            # # Clear Canvas when all fingers are up
            # if all (x >= 1 for x in fingers):
            # vidCanvas = np.zeros((720, 1280, 3), np.uint8)

    vidGray = cv.cvtColor(vidCanvas, cv.COLOR_BGR2GRAY)
    _, vidInv = cv.threshold(vidGray, 50, 255, cv.THRESH_BINARY_INV)
    vidInv = cv.cvtColor(vidInv,cv.COLOR_GRAY2BGR)
    vid = cv.bitwise_and(vid,vidInv)
    vid = cv.bitwise_or(vid,vidCanvas)

    # Setting the header image
    vid[0:100, 0:640] = header
    #vid = cv.addWeighted(vid,0.5,vidCanvas,0.5,0)
    cv.imshow("Video", vid)
    #cv.imshow("Video Canvas", vidCanvas)
    #print(vidCanvas.shape)
    # cv.imshow("Video Inv", vidInv)
    # print(vidInv.shape)
    cv.waitKey(1)


def gcd(a,b):
    if a < b:
        a,b = b,a
    a = a%b
    return gcd(b,a) if a!= 0 else b

# def prime_list(a):
#     for i in range(2,a):
#         if a < i**2:
#             break
#         if a%i == 0:
#             yield i
#             if i != a//i:
#                 yield a//i
#     yield a

def main():
    n = int(input())
    A = list(map(int,input().split()))
    counter = [0 for i in range(int(1e6+1))]

    setwise = A[0]
    for a in A:
        counter[a] += 1
        setwise = gcd(a,setwise)

    for i in range(2,len(counter)):
        if 1 < sum(counter[i::i]):
            if setwise == 1:
                print("setwise coprime")
            else:
                print("not coprime")
            return
        else:
            print("pairwise coprime")
            return

    # prime = [True for i in range(int(1e6+2))]
    # setwise = A[0]
    # pairwise = True
    # prime_set = set()
    # for a in A:
    #     if pairwise:
    #         for p in prime_list(a):
    #             if p not in prime_set:
    #                 prime_set.add(p)
    #             else:
    #                 pairwise = False

        #     if pairwise and prime[p] == True:
        #         prime[p] = False
        #         index = p
        #         while index < len(prime):
        #             prime[index] = False
        #             index += p
        #     else:
        #         pairwise = False
        #         break

        # setwise = gcd(setwise,a)

    # pairwise = True
    # setwise = A[0]
    # for a in A[1:]:
    #     if pairwise and gcd(A[0],a) != 1:
    #         pairwise = False

    #     setwise = gcd(setwise,a)
    # if pairwise:
    #     print("pairwise coprime")
    # elif setwise == 1:
    #     print("setwise coprime")
    # else:
    #     print("not coprime")
    # return

if __name__ == "__main__":
    main()


import socket
import struct
import binascii

import re

# Global variables
#host = "localhost"
addr = socket.gethostbyname(socket.gethostname())
porting = 0
buff_size = 65565

# Getting protocol function
def getProtocol(protocolNr):
    protocolFile = open('Protocol.txt', 'r')
    protocolData = protocolFile.read()
    protocol = re.findall(r'\n' + str(protocolNr) + ' (?:.)+\n', protocolData)
    if protocol:
        protocol = protocol[0]
        protocol = protocol.replace('\n', '')
        protocol = protocol.replace(str(protocolNr), '')
        protocol = protocol.lstrip()
        return protocol
    else:
        return "No such protocol was found"

#sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.htons(0x0800))
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)

sock.bind((addr, porting))
sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
sock.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
print("RAW Socket is ready")

# It works forever
counter = 0
while True:
    print('Inside the loop')
    packet = sock.recvfrom(buff_size)
    print(packet[0])

    # It seems, that AF_INET does not handle Ethernet
    """
    # Processing ethernet
    ethernet_header = packet[0][0:14]                                # Get Ethernet Header
    eth_header = struct.unpack("!6s6s2s", ethernet_header)
    print(eth_header)
    print(
          "Destination MAC:" + binascii.hexlify(eth_header[0]).decode()
          + " Source MAC:" + binascii.hexlify(eth_header[1]).decode()
          + " Type:" + binascii.hexlify(eth_header[2]).decode()
    )
    """

    # Processing IP
    unpackedDataIP = struct.unpack("!BBHHHBBH4s4s", packet[0][:20])   # Get IP Header
    print(unpackedDataIP)
    versionIP = unpackedDataIP[0] >> 4
    print(f"Version:\t\t {versionIP}")
    totalLengthIP = unpackedDataIP[2]
    print(f"Length:\t\t\t {totalLengthIP}")
    protocolFromIP = getProtocol(unpackedDataIP[6])
    print(f"Protocol:\t\t {protocolFromIP}")

    # Increase counter and check if we have to exit
    counter += 1
    if counter == 10:
        break

# Disable promiscuous mode
sock.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)


from pathlib import Path
import numpy as np
from datasets.arrow_dataset import Batch
import os
import json
import torch

from mlpipeline.datasets.nlp import RuREBus
from mlpipeline.datasets.nlp.units import Entity
from mlpipeline.models.nlp.ner import BertForNER, ConvLSTM, ConvSRU, ConvSRUpp
from mlpipeline.processors.nlp.collators import MaxLenSplitCollator, PaddingCollator
from mlpipeline.processors.nlp.labelizers import BILOULabelizer
from mlpipeline.processors.nlp.prediction_postprocessors import Viterbi

def main():
    home_dir = Path(os.getenv('HOME'))
    rurebus_path = home_dir / 'datasets' / 'RuREBus' / 'Preprocessed'
    hf_bert_path = home_dir / 'models' / 'DeepPavlov-rubert-base-cased'

    scratch_dir = Path(os.getenv('SCRATCH_DIR'))
    datasets_dir = scratch_dir / 'datasets'
    models_dir = scratch_dir / 'models'
    models = [
        (BertForNER(bert_name_or_path=hf_bert_path,
                    n_ent_types=8,
                    n_classes=5,
                    n_head_layers=2,
                    dropout=0.1),
         [('rurebus/v0.0.2_2layers_dce0.9/checkpoints/BertForNER_epoch=14_f1-macro=0.56576/model.pt',
           'rurebus/BertForNER_ner_preds')]),
        (ConvLSTM(n_ent_types=8,
                  n_classes=5,
                  cnn_layers=2,
                  cnn_kernels=[1, 3, 5],
                  rnn_layers=4,
                  hid_size=768 // 2,
                  head_layers=2,
                  dropout=0.1),
         [('rurebus/v1.0.0/checkpoints/ConvLSTM_epoch=100_f1-macro=0.41578/model.pt',
           'rurebus/ConvLSTM_ner_preds'),
          ('distil/v0.0.1/checkpoints/ConvLSTM_epoch=19_f1-macro=0.57962/model.pt',
           'rurebus/ConvLSTM_dist_preds'),
          ('fine_tuning_ditil_rurebus/v1.0.0/checkpoints/ConvLSTM_epoch=40_f1-macro=0.54448/model.pt',
           'rurebus/ConvLSTM_dist_ner_preds')]),
        (ConvSRU(n_ent_types=8,
                 n_classes=5,
                 cnn_layers=2,
                 cnn_kernels=[1, 3, 5],
                 rnn_layers=4,
                 hid_size=768 // 2,
                 head_layers=2,
                 dropout=0.1),
         [('rurebus/v1.0.0/checkpoints/ConvSRU_epoch=86_f1-macro=0.43208/model.pt',
           'rurebus/ConvSRU_ner_preds'),
          ('distil/v0.0.1/checkpoints/ConvSRU_epoch=14_f1-macro=0.56631/model.pt',
           'rurebus/ConvSRU_dist_preds'),
          ('fine_tuning_ditil_rurebus/v1.0.0/checkpoints/ConvSRU_epoch=40_f1-macro=0.53861/model.pt',
           'rurebus/ConvSRU_dist_ner_preds')]),
        (ConvSRUpp(n_ent_types=8,
                   n_classes=5,
                   cnn_layers=2,
                   cnn_kernels=[1, 3, 5],
                   rnn_layers=4,
                   hid_size=768 // 2,
                   head_layers=2,
                   dropout=0.1),
         [('rurebus/v1.0.0/checkpoints/ConvSRUpp_epoch=100_f1-macro=0.42305/model.pt',
           'rurebus/ConvSRUpp_ner_preds'),
          ('distil/v0.0.1/checkpoints/ConvSRUpp_epoch=16_f1-macro=0.5802/model.pt',
           'rurebus/ConvSRUpp_dist_preds'),
          ('fine_tuning_ditil_rurebus/v1.0.0/checkpoints/ConvSRUpp_epoch=40_f1-macro=0.53547/model.pt',
           'rurebus/ConvSRUpp_dist_ner_preds')])
    ]

    device = 'cuda' if torch.cuda.is_available() else 'cpu'

    rurebus = RuREBus.load(rurebus_path)['test']

    collator = MaxLenSplitCollator(
        collate_columns=['tokens', 'spans', 'tokens_ids', 'attention_mask', 'token_type_ids'],
        pk_columns=['doc_id', 'start'],
        unite_columns=['logits'],
        max_len=128
    )

    padder = PaddingCollator(pad_value=0,
                             padding_type='longest',
                             collate_columns=['tokens_ids', 'attention_mask'])

    viterbi = Viterbi(logits_column='logits',
                      word_tokens_indices_column='word_tokens_indices',
                      out_predicted_labels_ids_column='predicted_labels_ids',
                      first_subword_transition_probs=BILOULabelizer.first_subword_transition_probs,
                      middle_subword_transition_probs=BILOULabelizer.middle_subword_transition_probs,
                      last_subword_transition_probs=BILOULabelizer.last_subword_transition_probs,
                      word_transition_probs=BILOULabelizer.word_transition_probs,
                      initial_state=0,
                      pad_label_id=0)

    labelizer = BILOULabelizer(text_column='text',
                               tokens_column='tokens',
                               tokens_spans_column='spans',
                               entities_column='entities',
                               out_labels_column='labels',
                               out_labels_ids_column='labels_ids',
                               predicted_labels_ids_column='predicted_labels_ids',
                               out_predicted_entities_column='predicted_entities',
                               entity_types=rurebus.entity_types,
                               entities_deserialize_fn=Entity.from_brat,
                               entities_serialize_fn=Entity.to_brat)

    def predict_logits_map_fn(model):
        def f(batch: Batch):
            lengths = [len(ex) for ex in batch['tokens_ids']]
            batch = padder.collate(batch)
            with torch.no_grad():
                output = model(tokens_ids=batch['tokens_ids'].to(device),
                               attention_mask=batch['attention_mask'].to(device))
            logits = [out[:lengths[i]] for i, out in enumerate(output)]
            return {'logits': logits}
        return f

    for model, paths in models:
        model.to(device)
        for model_path, output_path in paths:
            model.load(models_dir / model.name / model_path)
            ds = rurebus
            if isinstance(model, BertForNER):
                ds = collator.preprocess(ds)
            ds = ds.map(predict_logits_map_fn(model), batched=True, batch_size=128)
            if isinstance(model, BertForNER):
                ds = collator.postprocess(ds)
            ds = viterbi.postprocess(ds)
            ds = labelizer.postprocess(ds)
            ds.save(datasets_dir / output_path)

if __name__ == '__main__':
    main()


from sklearn.metrics import roc_auc_score, precision_recall_fscore_support, accuracy_score
import numpy as np
from  EERNNDataProcessor import EERNNDataProcessor
import tensorflow as tf
import os

# 模型定义部分
class EERNN(tf.keras.Model):
    def __init__(self,  embedding_matrix, onehot_matrix):
        super(EERNN, self).__init__()
        self.lstm = tf.keras.layers.LSTM(name="lstm", units=LSTM_UNITS, return_sequences=True, return_state=False,
            kernel_initializer=tf.keras.initializers.RandomUniform(minval=-0.1549193338, maxval=0.1549193338))

        self.dropout = tf.keras.layers.Dropout(0.1)

        self.dense1 = tf.keras.layers.Dense(name='dense1', units=50, activation=tf.keras.activations.relu,
            kernel_initializer=tf.keras.initializers.RandomUniform(minval=-0.1732050808, maxval=0.1732050808))

        self.dense2 = tf.keras.layers.Dense(name='dense2', units=1,
            kernel_initializer=tf.keras.initializers.RandomUniform(minval=-0.3429971703,maxval=0.3429971703))

        self.sotfmax = tf.keras.layers.Softmax()

        self.embedding = tf.keras.layers.Embedding(input_dim=5111, output_dim=EMBEDDING_DIM, name="embedding", weights=[embedding_matrix], trainable=False)

        self.embedding2 = tf.keras.layers.Embedding(input_dim=2, output_dim=4*LSTM_UNITS, name="embedding2", weights=[onehot_matrix], trainable=False)

        self.bi_lstm = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(name="bi_lstm", units=LSTM_UNITS, return_sequences=True, return_state=False,
            kernel_initializer=tf.keras.initializers.RandomUniform(minval=-0.2, maxval=0.2),
            kernel_regularizer=tf.keras.regularizers.l2(0.00004)))

    def call_encode(self, pid2seq):
        # 将题目文本进行嵌入
        # pid2seq :[483, 100]
        # x: [483, 100, 50]
        x = self.embedding(pid2seq)
        if pid2seq.shape[0]<2000:
            x = self.bi_lstm(x)
        else:
            x1 = self.bi_lstm(x[0:2000, :, :])
            x2 = self.bi_lstm(x[2000:4000, :, :])
            x3 = self.bi_lstm(x[4000: ,:, :])
            x = tf.concat([x1, x2, x3], axis=0)
        x = tf.math.reduce_max(x, axis=1)
        sim = self.cosine_distance(x)
        return x, sim

    def cosine_distance(self, inputs):
        num_vec = inputs.shape[0]
        x = tf.expand_dims(inputs, axis=1)
        x = tf.tile(x, [1, num_vec, 1])
        y = tf.expand_dims(inputs, axis=0)
        y = tf.tile(y, [num_vec, 1, 1])
        sim = -1 * tf.keras.losses.cosine_similarity(x, y)
        return sim

    def cal_hatt(self, ht, pro_id_ont_hot, X, cos_X, trimatrix):
        # 每一行为一个题目与其他题目向量的余弦值
        a = tf.matmul(pro_id_ont_hot, cos_X)
        aj = tf.expand_dims(a, -1)
        hj = tf.expand_dims(ht, 2)
        hidden = tf.multiply(aj, hj)
        ajhj = tf.tensordot(hidden, trimatrix, [[1],[0]])
        ajhj = tf.transpose(ajhj, [0, 3, 1, 2])
        x1 = tf.expand_dims(X, 0)
        x1 = tf.expand_dims(x1, 0)
        XX = tf.tile(x1, multiples=[BATCH_SIZE, pro_id_ont_hot.shape[1], 1, 1])
        hatt = tf.concat([ajhj , XX], -1)
        return hatt

    def call(self, data, num_pro, X, cos_X, trimatrix):
        pro_id, label = data
        pro_id_one_hot = tf.one_hot(pro_id, num_pro)
        label_embedding = self.embedding2(label)
        # [batch, 题目序列， 题目词向量表达]
        t_X = tf.matmul(pro_id_one_hot, X)
        t_X = tf.tile(t_X, [1, 1, 2])
        # [batch, 题目序列， 题目词向量与0,1拼接]
        xt = tf.multiply(t_X, label_embedding)
        ht = self.lstm(xt)
        hatt= self.cal_hatt(ht, pro_id_one_hot, X, cos_X, trimatrix)
        r = self.dense1(hatt)
        prediction = self.dense2(r)
        return prediction

# 损失函数
def entroy_loss(prediction, data):
    target_id, target_correctness = data

    # 真实值
    target_correctness = target_correctness[:, 1:]
    flat_target_correctness = tf.reshape(target_correctness, [-1])
    flat_target_correctness = tf.cast(flat_target_correctness, dtype=tf.float32)

    # 预测值
    target_id = target_id[:, 1:]
    num_pro = prediction.shape[-2]

    # 计算偏移量
    flat_bias_target_id = num_pro * tf.range(BATCH_SIZE * target_id.shape[-1])
    # 获取预测数据所在ID
    flat_target_id = tf.reshape(target_id, [-1]) + flat_bias_target_id
    prediction = prediction[:, :-1, :, :]
    flat_logits = tf.reshape(prediction, [-1])
    flat_target_logits = tf.gather(flat_logits, flat_target_id)

    loss = tf.reduce_sum(tf.nn.sigmoid_cross_entropy_with_logits(labels=flat_target_correctness, logits=flat_target_logits))
    return loss

def train(DataName,TmpDir):
    trimatrix = np.tri(MAXLEN, MAXLEN, 0).T
    trimatrix = tf.cast(trimatrix, tf.float32)
    # 定义数据处理器
    data_processor = EERNNDataProcessor([15,1000000,0.06,1],[10,1000000,0.02,1],['2005-01-01 23:47:31','2019-01-02 11:21:49'],True,DataName,TmpDir)
    # 获取处理好的数据
    pid2seq, embedding_matrix, dataset, onehot_matrix = data_processor.LoadEERNNData(BATCH_SIZE, PREFETCH_SIZE, SHUFFLE_BUFFER_SIZE, LSTM_UNITS,100)
    # 定义模型
    model = EERNN(embedding_matrix, onehot_matrix)
    # 周期数
    epochs = 10
    # 学习率
    lr = 0.01
    # 学习率衰减率
    lr_decay = 0.92
    print("Start training...")
    for epoch in range(epochs):
        optimizer = tf.keras.optimizers.Adam(lr * lr_decay ** epoch)
        # 打乱数据集
        dataset.shuffle(BUFFER_SIZE)
        for batch, data in enumerate(dataset):
            loss = 0
            with tf.GradientTape() as tape:
                # pid2seq　保存了每道题目对应的词语ID　[pro_num, word_num]
                X,cos_X =  model.call_encode(pid2seq)
                # X 记录了每道题目对应的hatten
                # cos_X 记录了每道题目对应的hatten之间的cosine
                # 计算预测值
                prediction = model(data, pid2seq.shape[0], X, cos_X, trimatrix)
                # 计算损失值
                loss += entroy_loss(prediction, data)
            grad = tape.gradient(loss, model.trainable_variables)
            optimizer.apply_gradients(zip(grad, model.trainable_variables))
            # 打印该批次损失
            batch_loss = (loss / BATCH_SIZE)
            if batch%100 == 0:
                print("Epoch {} Batch {} Loss {:.4f}".format(epoch + 1, batch, batch_loss.numpy()))

if __name__=='__main__':
    NUM_WORDS = 5000
    BUFFER_SIZE = 12
    BATCH_SIZE = 8
    EMBEDDING_DIM = 50
    LSTM_UNITS = 50
    PREFETCH_SIZE = 128
    SHUFFLE_BUFFER_SIZE = 5120
    MAXLEN = 100
    data_name = 'hdu'
    tmp_dir = './data/'
    train(data_name, tmp_dir)


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

from math import prod

def parse_hex(hex_code):
    hex_code = [f"{int(i, 16):04b}" for i in list(hex_code)]
    bit_code = "".join(hex_code)
    return(bit_code)

def gt(l):
    return(int(l[0]>l[1]))

def lt(l):
    return(int(l[0]<l[1]))

def eq(l):
    return(int(l[0]==l[1]))

def parse_packet(packet, offset=0):
    #print(packet)
    packet = packet[offset:]
    parsed = {}
    parsed["version"] = int(packet[0:3], 2)
    parsed["id"] = type_ids[int(packet[3:6], 2)]
    if parsed["id"] == "lit":
        payload = []
        for p in [packet[6:][x:x+5] for x in range(0, len(packet[6:]), 5)]:
            payload.append(p)
            if p[0] == "0":
                break
        parsed["payload"] = [list(p)[1:] for p in payload if list(p)[0] == "1"]
        parsed["payload"].append(list(payload[len(parsed["payload"])][1:]))
        parsed["payload"] = "".join(["".join(p) for p in parsed["payload"]])
        parsed["payload"] = int(parsed["payload"], 2)
        parsed["len_of_package"] = 6 + (len(payload)*5)
    else:
        parsed["length_type"] = int(packet[6])
        if parsed["length_type"] == 0:
            parsed["sub_len"] = int("".join(packet[7:22]), 2)
            parsed["len_of_package"] = 22
            parsed["length_type"] = "len"
        else:
            parsed["sub_len"] = int("".join(packet[7:18]), 2)
            parsed["len_of_package"] = 18
            parsed["length_type"] = "count"
    return(parsed)

def solve_code(bit_code, offset=0):
    p = parse_packet(bit_code, offset)
    if p["id"] == "lit":
        return(p["payload"], offset+p["len_of_package"])

    results = []
    initial_offset = offset
    end = -1

    if p["length_type"] == "len":
        total_len = p["sub_len"]
        offset += p["len_of_package"]
        while total_len > 0:
            expr_res, end = solve_code(bit_code, offset)
            results.append(expr_res)
            total_len -= end - offset
            offset = end
    else:
        total_count = p["sub_len"]
        offset += p["len_of_package"]

        for _ in range(total_count):
            expr_res, end = solve_code(bit_code, offset)
            results.append(expr_res)
            offset = end

    return(p["id"](results), end)

type_ids = {
    0:sum,
    1:prod,
    2:min,
    3:max,
    4:"lit",
    5:gt,
    6:lt,
    7:eq
}

# read puzzle input
with open("input.txt") as f:
   puzzle_input = f.read()

bit_code = parse_hex(puzzle_input)
print(solve_code(bit_code)[0])


#### 재귀함수 방법 ####
nIteration = int(input())

def solution(n):
    if n == 0:
        return 2
    if n > 0:
        return (2*solution(n-1)-1)

print(solution(nIteration)**2)

#### DP TABLE ####  < 이게 더 오래걸림.

dpTable = [-1] * 15
dpTable[0] = 2

for i in range(1, 15):
    dpTable[i] = 2 * dpTable[i-1] -1

print(dpTable[nIteration]**2)


#input_below

#12
#insert 0 5
#insert 1 10
#insert 0 6
#print
#remove 6
#append 9
#append 1
#sort
#print
#pop
#reverse
#print

#output

#[6, 5, 10]
#[1, 5, 9, 10]
#[9, 5, 1]

if __name__ == '__main__':
    N = int(input())
mylist=[]
for _ in range(N):
    args=input().split(" ") #even if you do not give " " in split it will use " " by default
    print(args)
    print(type(args))
    if args[0]=="insert":
        mylist.insert(int(args[1]),int(args[2]))
    elif args[0]=="remove":
        mylist.remove(int(args[1]))
    elif args[0]=="reverse":
        mylist.reverse()
    elif args[0]=="sort":
        mylist.sort()
    elif args[0]=='append':
        mylist.append(int(args[1]))
    elif args[0]=="print":
        print(mylist)
    elif args[0]=="pop":
        mylist.pop()


import os

import pandas as pd

import dash
import dash_table
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.express as px
import plotly.graph_objects as go
#from plotly.subplots import make_subplots
# trying to get row layout simple
import dash_bootstrap_components as dbc

from statList import statList # dictionary mapping human readable to columns
 							# column = statList[human]['yStat']

'''
for k,v in statList.items():
	print(k, '\t', v['yStat'])
'''

# see: https://community.plotly.com/t/deploying-multi-page-app-to-heroku-not-deploying-as-set-up/7877/2
from app import app
from app import server # needed for heroku
# import all pages in the app
#from apps import global_situation, singapore, home
from pages import mynavbar, uploadpage
#from mynavbar import myNavBar
#from uploadPage import uploadPageLayout

def loadCsv():
	path = 'data/Superior vs Inferior database_13_Feb_master.csv'
	df = pd.read_csv(path, header=0)
	return df

def getMean(dfMaster, groupByList, theStat):
	"""
	for one column (like spikeFreq_hz) get stats like count, mean, std, ...
	"""
	aggList = ['count', 'mean', 'std', 'sem', 'median']

	dfMean = dfMaster.groupby(groupByList, as_index=False)[theStat].agg(aggList)
	dfMean = dfMean.reset_index()
	dfMean.insert(1, 'stat', theStat) # column 1, in place
	return dfMean

def makeDropdown(id, itemList, defaultItem):
	"""
	defaultItem: Needs to be in itemList
	"""
	ret = dcc.Dropdown(
		id=id,
		options=[{'label': i, 'value': i} for i in itemList],
		value=defaultItem,
		)
	#
	return ret

def makeCheckList(id, itemList, defaultItem):
	options = [{'label': x, 'value': x} for x in itemList]
	ret = dcc.Checklist(
		id=id,
		options=options,
		value=[itemList[0]],
		#labelStyle={'display': 'inline-block'}
		labelStyle={"margin-right": "15px"}, # adds space between options list
		inputStyle={"margin-right": "5px"}, # adds space between check and its label
	), # Checklist
	return ret

def makeRadio(id, itemList, defaultItem):
	options = [{'label': x, 'value': x} for x in itemList]
	ret = dcc.RadioItems(
		id=id,
		options=options,
		value=itemList[0],
		labelStyle={"margin-right": "15px"}, # adds space between options list
		inputStyle={"margin-right": "5px"}, # adds space between check and its label
	)
	return ret

def makeTable(id, df, height=200, row_selectable='single', defaultRow=0):
	"""
	defaultRow: row index selected on __init__
	"""
	ret = dash_table.DataTable(
		id=id,
		columns=[{"name": i, "id": i} for i in df.columns],
		data=df.to_dict('records'),
		row_selectable=row_selectable,
		fixed_rows={'headers': True}, # on scroll, keep headers at top
		selected_rows = [defaultRow], # default selected row
		style_header={
			'backgroundColor': 'rgb(200, 200, 255)',
			'fontWeight': 'bold',
		},
		style_cell={
			'textAlign': 'left',
			'fontSize':11, 'font-family':'sans-serif',
			#'backgroundColor': 'rgb(30, 30, 30)',# dark theme
			#'color': 'white' # dark theme
			},
		style_data_conditional=[
			{
			'if': {'row_index': 'odd'},
			#'backgroundColor': 'rgb(50, 50, 50)' # dark theme
			'backgroundColor': 'rgb(200, 200, 200)' # light theme
			}
		],
		style_table={
			'height': height, # hard coding height
			#'overflowY': 'scroll',
			'overflowX': 'auto',
			'overflowY': 'auto',
			#'width': width
		}
	)
	return ret

def plotStripPlot(df, groupBy, yStatCol, doMeanSem=True):
	dfMaster = df
	fig = px.strip(dfMaster,
					x=groupBy, color=groupBy,
					y=yStatCol,
					stripmode='overlay',
					hover_data=dfMaster.columns)
	#
	return fig

def plotHistogram(df, groupBy, yStatCol, doCumulative=False, doBoxPlotInset=False):
	"""
	global:
		dfMaster
	"""
	dfMaster = df
	if doCumulative:
		#show_hist = False
		histnorm = 'probability density' #probability'
	else:
		#show_hist = True
		histnorm = None

	if doBoxPlotInset:
		marginal = 'box' # ['box', 'violin', 'rug']
	else:
		marginal = None
	fig = px.histogram(
		dfMaster, x=yStatCol, color=groupBy,
		#histfunc=histfunc,
		cumulative=doCumulative,
		histnorm=histnorm,
		#show_hist=show_hist,
		marginal=marginal,
		hover_data=dfMaster.columns)
	return fig

def plotScatter(df, xStatCol, yStatCol, groupBy, colorBy, plotRaw=True, plotMean=False):
	"""
	groupBy: for example 'Region'
	"""
	colors = px.colors.qualitative.Dark24
	dfMaster = df
	ret = []

	if plotRaw:
		# todo: if groupBy is None then no grouping, use very row in dfMaster
		groups = dfMaster[groupBy].unique()
		print('	plotScatter() groupBy:', groupBy, 'num:', len(groups))
		for idx, group in enumerate(groups):
			#print('	plotScatter() group:', group)
			color = colors[idx] # global
			dfGroup = dfMaster[ dfMaster[groupBy]==group ]
			xRaw = dfGroup[xStatCol].tolist()
			yRaw = dfGroup[yStatCol].tolist()
			rawScatter = go.Scatter(x=xRaw, y=yRaw,
							# for legend, str() needed because 'File Number' column is numpy.int64
							name=str(group),
							mode='markers',
							marker=dict(
								color=color,
								size=5,
								line=dict(
									color='Gray',
									width=0
								)
							),
							showlegend=True
							)
			#
			ret.append(rawScatter)

	if plotMean:
		#xMeanDf = getMean(dfMaster, groupByList, xStatCol)
		#yMeanDf = getMean(dfMaster, groupByList, yStatCol)
		xMeanDf = getMean(dfMaster, groupBy, xStatCol)
		yMeanDf = getMean(dfMaster, groupBy, yStatCol)
		xMean = xMeanDf['mean'].tolist()
		yMean = yMeanDf['mean'].tolist()
		xSem = xMeanDf['sem'].tolist()
		ySem = yMeanDf['sem'].tolist()
		# plot mean as different colors, this does not work ???
		# color of mean, tricky
		meanColor = xMeanDf[groupBy].tolist()
		meanColorList = [colors[idx] for idx, x in enumerate(meanColor)]

		meanScatter = go.Scatter(x=xMean, y=yMean,
						mode='markers',
						error_x=dict(
							type='data', # value of error bar given in data coordinates
							array=xSem,
							visible=True),
						error_y=dict(
							type='data', # value of error bar given in data coordinates
							array=ySem,
							visible=True),
						marker=dict(
							#color='Black',
							color=meanColorList,
							size=10,
							line=dict(
								color='Gray',
								width=1
							)
						),
						showlegend=False
						)
		#
		#fig.add_trace(meanScatter)
		ret.append(meanScatter)
	#
	return ret

##
## start main
##
def dashMain():

	# todo: allow to load any csv
	dfMaster = loadCsv()

	# get columns to make a stat table (list of columns)
	statsDf = pd.DataFrame(columns=['idx', 'stat'])
	statsDf['idx'] = [i for i in range(len(statList.keys()))]
	statsDf['stat'] = [x for x in statList.keys()]

	plotTypeList = ['Scatter', 'Histogram', 'Histogram + Box Plot', 'Cumulative Histogram', 'Strip Plot']

	# todo: add this as param to __init__
	# todo: implement 'None', in particular in getMean()
	groupByList = ['File Number', 'analysisname', 'Region', 'Sex', 'Condition']
	colorByList = ['None', 'analysisname', 'Region', 'Sex', 'Condition']

	# todo: add as a parameter to __init__
	defaultDict = {
		'plotType': 'Scatter',
		'groupBy': 'Region',
		'colorBy': 'Region',
		'xDefaultRow': 2, # todo: need to grab this index from preferred stat in statList
		'yDefaultRow': 0,
	}

	# initial tables
	xStat = 'thresholdVal'
	yStat = 'spikeFreq_hz'
	xMeanDf = getMean(dfMaster, groupByList, xStat)
	yMeanDf = getMean(dfMaster, groupByList, yStat)

	# todo: add same colors to all plots
	#colors = px.colors.qualitative.Dark24
	#print('  colors:', colors)

	#
	# moved to app.py
	'''
	myStyles = 'assets/myStyle.css'
	# this is crap, no layout
	#external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
	# can't use dark themes
	external_stylesheets = [dbc.themes.BOOTSTRAP, myStyles]
	app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
	server = app.server
	'''

	# a control panel div with dropdowns, checkbox, and radio
	tmpControlDiv = html.Div(
		[
			dbc.Row(
				[
					dbc.Col(
						html.Label('Plot Type')
						, width="auto"
					),
					dbc.Col(
						makeDropdown('plot-type-dropdown', plotTypeList, defaultDict['plotType'])
						#, width=3
					),
				],
				#],no_gutters=True,
			), # row
			dbc.Row(
				[
					dbc.Col(
						html.Label('Group By')
						, width="auto"
					),
					dbc.Col(
						makeDropdown('group-by-dropdown', groupByList, defaultDict['groupBy'])
						#, width=3
					),
				],
				#],no_gutters=True,
			), # row
			dbc.Row(
				[
					dbc.Col(
						html.Label('Color By')
						, width="auto"
					),
					dbc.Col(
						makeDropdown('color-by-dropdown', colorByList, defaultDict['colorBy'])
						#, width=3
					),
				],
				#],no_gutters=True,
			), # row
			dbc.Label(''),
			dbc.Row(
				[
					dbc.Col(
						html.Label('Plot Data')
						, width="auto"
					),
					dbc.Col(
						makeCheckList('plot-options-check-list', ['Raw', 'Mean'], 'Raw')
						#, width=3
					),
				],
				#],no_gutters=True,
			), # row
			dbc.Label(''),
			dbc.Row(
				[
					dbc.Col(
						html.Label('Update Plot')
						, width="auto"
					),
					dbc.Col(
						makeRadio('update-plot-radio', ['Left', 'Right'], 'Left')
						#, width=3
					),
				],
				#],no_gutters=True,
			), # row

		], className = 'container', style={'font-size': '12px'})
		#, style={'fontColor': 'blue'})
		#]) # outerdiv

	##
	##
	boxBorder = "0px black solid"
	tmpOneRow2 = html.Div( # outer div
		[
			dbc.Row(
				[
					dbc.Col(
						html.Div([
							html.Label('Parameters'),
							tmpControlDiv
						]
						#,style={'font-size': '11px'}
						) # div
						,width=4,style={"border":boxBorder}
					),
					dbc.Col(
						html.Div([
							html.Label('X-Stat'),
							makeTable('x-stat-table', statsDf, height=180, defaultRow=defaultDict['xDefaultRow'])
						]) # div
						,width=4,style={"border":boxBorder}
					), # col
					dbc.Col(
						html.Div([
							html.Label('Y-Stat'),
							makeTable('y-stat-table', statsDf, height=180, defaultRow=defaultDict['yDefaultRow'])
						]) # div
						,width=4,style={"border":boxBorder}
					), # col
					#dbc.Col(
					#	html.Div([
					#		#html.Label('Color By'),
					#		dcc.Graph(id="scatter-plot")
					#	])
					#	,width=6,style={"border":boxBorder}), # col
				],
				#],no_gutters=True,
			), # row
			dbc.Row(
				[
					dbc.Col(
						html.Div([
							#html.Label('Color By'),
							dcc.Graph(id="scatter-plot-left")
						])
						,width=6,style={"border":boxBorder}), # col
					dbc.Col(
						html.Div([
							#html.Label('Color By'),
							dcc.Graph(id="scatter-plot-right")
						])
						,width=6,style={"border":boxBorder}), # col
				],
			), # row
		], className = 'container') # outerdiv

	tmpOneRow3 = html.Div( # outer div
		[
			dbc.Row(
				[
					dbc.Col(
						html.Div([
							html.Label('X Group By'),
							#makeTable('x-mean-table', xMeanDf, height=300, row_selectable=None),
							makeTable('x-mean-table', xMeanDf, height=300, row_selectable='multi'),
						])
						,width=6,style={"border":boxBorder}), # col
					dbc.Col(
						html.Div([
							html.Label('Y Group By'),
							makeTable('y-mean-table', yMeanDf, height=300, row_selectable=None),
						]) # div
						,width=6,style={"border":boxBorder}), # col
				],
			), # row
		], className = 'container') # outerdiv

	indexLayout = html.Div([
		tmpOneRow2, # controls and x/y stat tables
		tmpOneRow3, # plots
	])

	app.layout = html.Div([
		# i don't understand this. This is hidden but allows
		# callback to go to a different page?
		#dcc.Location(id='url', refresh=False),
		dcc.Location(id='url'),

		mynavbar.myNavBar,
		#tmpOneRow, # controls
		#tmpControlDiv, # single div for all controls v2

		# was this
		#tmpOneRow2, # controls and x/y stat tables
		#tmpOneRow3, # plots

		html.Div(id='page-content'), # working on two page app

	]) #, style={'columnCount': 3})

	#
	# callbacks
	#

	@app.callback(dash.dependencies.Output("page-content", "children"),
				  [dash.dependencies.Input('url', 'pathname')])
	def displayPageCallback(pathname):
		print('displayPageCallback() pathname:', pathname)
		if pathname == "/":
			return indexLayout
		elif pathname == '/uploadPage':
			return uploadpage.uploadPageLayout
		else:
			# If the user tries to reach a different page, return a 404 message
			return dbc.Jumbotron(
				[
					html.H1("404: Not found", className="text-danger"),
					html.Hr(),
					html.P(f"The pathname {pathname} was not recognised..."),
				]
			)

	@app.callback(
		[
			Output("scatter-plot-left", "figure"),
			Output("scatter-plot-right", "figure"),
			Output("x-mean-table", "data"),
			Output("y-mean-table", "data"),
		],
		[
			Input('plot-type-dropdown', 'value'),
			Input('x-stat-table', 'selected_rows'),
			Input('y-stat-table', 'selected_rows'),
			Input('group-by-dropdown', 'value'),
			Input('color-by-dropdown', 'value'),
			Input('plot-options-check-list', 'value'), # (raw, mean)
			State('update-plot-radio', 'value'), # (left, right)
		]
		)
	def f(plotType, xRow, yRow, groupBy, colorBy, plotOptions, plotLeftRight):
		"""
		Parameters:
			plotType:
			xRow,yRow: [list]
			groupBy:
			plotOptions: List of options that are checked, like
					['plot raw', 'plot mean']
			plotLeftRight: plot to either the left or right plot
		"""
		print('=== f()')

		print('  plotType:', plotType)
		print('  xRow:', xRow)
		print('  yRow:', yRow)
		print('  groupBy:', groupBy)
		print('  colorBy:', colorBy)
		print('  plotOptions:', plotOptions)
		print('  plotLeftRight:', plotLeftRight)

		print('  1) defaultDict:', defaultDict)
		defaultDict['xDefaultRow'] = xRow[0]
		defaultDict['yDefaultRow'] = yRow[0]
		print('  2) defaultDict:', defaultDict)

		# use context ctx to determine who triggered callback
		ctx = dash.callback_context
		if not ctx.triggered:
			idTriggered = 'No clicks yet'
		else:
			idTriggered = ctx.triggered[0]['prop_id'].split('.')[0]
		print('  idTriggered:', idTriggered)

		# x
		if xRow is None:
			xRow = 0
		else:
			xRow = xRow[0]
		xStat = statsDf.iloc[xRow]['stat']
		print('  x-stat-table Input:', xStat)
		# y
		if yRow is None:
			yRow = 0
		else:
			yRow = yRow[0]
		yStat = statsDf.iloc[yRow]['stat']
		print('  y-stat-table Input:', yStat)

		# convertt human to actual column
		xStatCol = statList[xStat]['yStat']
		yStatCol = statList[yStat]['yStat']

		# todo: append xMeanDf/yMeanDf to tables
		'''
		xMeanDf = getMean(dfMaster, groupByList, xStatCol)
		yMeanDf = getMean(dfMaster, groupByList, yStatCol)
		xMean = xMeanDf['mean'].tolist()
		yMean = yMeanDf['mean'].tolist()
		xSem = xMeanDf['sem'].tolist()
		ySem = yMeanDf['sem'].tolist()

		# plot mean as different colors, this does not work ???
		# color of mean, tricky
		meanColor = xMeanDf[groupBy].tolist()
		meanColorList = [colors[idx] for idx, x in enumerate(meanColor)]
		'''

		fig = go.Figure()

		#plotRaw = plotOptions is not None and 'plot raw' in plotOptions
		#plotMean = plotOptions is not None and 'plot mean' in plotOptions
		plotRaw = plotOptions is not None and 'Raw' in plotOptions
		plotMean = plotOptions is not None and 'Mean' in plotOptions

		#plotType = 'Histogram + Boxplot'
		xAxisTitle = ''
		yAxisTitle = ''
		if plotType == 'Scatter':
			rawScatterList = plotScatter(dfMaster, xStatCol, yStatCol, groupBy, colorBy, plotRaw=plotRaw, plotMean=plotMean)
			# rawScatterList is a list of [scatter, mean)
			for rawScatter in rawScatterList:
				fig.add_trace(rawScatter)
			xAxisTitle = xStat
			yAxisTitle = yStat
		elif plotType in ['Histogram', 'Histogram + Box Plot', 'Cumulative Histogram']:
			doBoxPlotInset = plotType == 'Histogram + Box Plot'
			doCumulative = plotType == 'Cumulative Histogram'
			fig = plotHistogram(dfMaster, groupBy, yStatCol, doCumulative=doCumulative, doBoxPlotInset=doBoxPlotInset)
			#fig.add_trace(rawScatter)
			xAxisTitle = yStat
			yAxisTitle = 'Count'
		elif plotType == 'Strip Plot':
			doMeanSem = True
			fig = plotStripPlot(dfMaster, groupBy, yStatCol, doMeanSem=doMeanSem)
			# gives error
			#fig.update_layout(traceorder='normal')
			xAxisTitle = groupBy
			yAxisTitle = yStat

		fig.update_layout(
			#title="Plot Title",
			xaxis_title=xAxisTitle,
			yaxis_title=yAxisTitle,
			legend_title=groupBy,
			font=dict(
				family="Arial",
				size=12,
				color="Black"
			),
			margin=dict(l=20, r=20, t=20, b=20),
		)

		#
		# use dash.no_update to update left/right and keep other the same
		# this works, but started using State for update-plot-radio
		#if idTriggered == 'update-plot-radio':
		#	# don't update plot when use just click on plot radio left/right
		#	print('  user selected left/right -->> no update')
		#	return dash.no_update, dash.no_update, dash.no_update, dash.no_update
		if plotLeftRight == 'Left':
			#
			return fig, dash.no_update, xMeanDf.to_dict('records'), yMeanDf.to_dict('records')
		elif plotLeftRight == 'Right':
			#
			return dash.no_update, fig, xMeanDf.to_dict('records'), yMeanDf.to_dict('records')
	#
	#
	#return app, server

'''
# grab hover from one plot and show in other plot
@app.callback([Output('local and imported', 'figure'),
			   Output('dorms', 'figure')],
			  [Input('graph_by_period', 'hoverData')])

def update_breakdown(hoverData):
	day = hoverData['points'][0]['x']
	dff = df[df['Date'] == day]
'''

# "server" needs to be global for heroku
#app, server = dashMain()
dashMain()

if __name__ == '__main__':
	# causing heroku to crash
	#app = dashMain()
	# procfile for Heroku is: web: gunicorn app:server
	# expects app.py to have global variable "server"
	#app, server = dashMain()
	#dashMain()
	app.run_server(debug=True)


import audioio
import time
import board
import neopixel
from digitalio import DigitalInOut, Direction, Pull
import digitalio
import busio
import digitalio
import adafruit_lis3dh

# enable the speaker
speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
speaker_enable.direction = digitalio.Direction.OUTPUT
speaker_enable.value = True
a = audioio.AudioOut(board.A0)

#Set up pixels
pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, auto_write=False)

##Button Presses
buttonA = DigitalInOut(board.BUTTON_A)
buttonA.direction = Direction.INPUT
buttonA.pull = Pull.DOWN
buttonB = DigitalInOut(board.BUTTON_B)
buttonB.direction = Direction.INPUT
buttonB.pull = Pull.DOWN

brightness = 10

##Accelerometer is hooked up to SDA/SCL which is I2C or just some kind of protocol
i2c = busio.I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA)
_int1 = digitalio.DigitalInOut(board.ACCELEROMETER_INTERRUPT)
lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, address=0x19, int1=_int1)
lis3dh.range = adafruit_lis3dh.RANGE_8_G

def check_brightness():
    global brightness
    if brightness > 255:
        brightness = 0
    if brightness < 0:
        brightness = 255
    print(brightness)

def change_brightness(increment):
    global brightness
    brightness+=increment
    check_brightness()

def PLAY_SOUND():
    print("Playing Sound")
    f = open("Pikachu.wav", "rb")
    wav = audioio.WaveFile(f)
    a.play(wav)
    # You can now do all sorts of stuff here while the audio plays
    # such as move servos, motors, read sensors...
    # Or wait for the audio to finish playing:
    # Light_Show()
    # While the music is playing run the light show
    while a.playing:
        pass
    f.close()
    return

##Take a bunch of average readings
avg = 0
N = 100
for i in range(0,N):
    x,y,z = lis3dh.acceleration
    norm2 = x*x + y*y + z*z
    avg+=norm2
avg/=(N+1)

while True:
    if buttonA.value:
        change_brightness(10)
    if buttonB.value:
        change_brightness(-10)
    ###Top Row is red and bottom row is white
    pixels.fill((brightness,brightness,brightness))
    for i in range(0,5):
        pixels[i] = (brightness,0,0)
    pixels.show()
    time.sleep(0.1)
    x,y,z = lis3dh.acceleration
    norm2 = x*x + y*y + z*z
    if abs(norm2 - avg) > 100:
        PLAY_SOUND()
    #print((norm2-avg,))


import argparse

# Showing both short and long argument options

def get_args():
    """"""
    parser = argparse.ArgumentParser(
        description="A simple argument parser",
        epilog="This is where you might put example usage"
    )

    # required argument
    parser.add_argument('-x', '--execute', action="store", required=True,
                        help='Help text for option X')
    # optional arguments
    parser.add_argument('-y', '--message1', help='Help text for option Y', default=False)
    parser.add_argument('-z', '--message2', help='Help text for option Z', type=int)

    print(parser.parse_args())

if __name__ == '__main__':
    get_args()

'''
$ arg_demo_3.py
usage: arg_demo_3.py [-h] -x EXECUTE [-y MESSAGE1] [-z MESSAGE2]
arg_demo_3.py: error: the following arguments are required: -x/--execute
$ arg_demo_3.py --execute something
Namespace(execute='something', message1=False, message2=None)
$ arg_demo_3.py --execute something --message1 text1 --message2 text2
usage: arg_demo_3.py [-h] -x EXECUTE [-y MESSAGE1] [-z MESSAGE2]
arg_demo_3.py: error: argument -z/--message2: invalid int value: 'text2'
$ arg_demo_3.py --execute something --message1 text1 --message2 100
Namespace(execute='something', message1='text1', message2=100)
'''


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
import numpy as np
import math
import tensorflow as tf
import gensim.models.keyedvectors as word2vec
from pathlib import Path
from nni_child_model.data.ptb import *

global only_sentence, use_embed_layer, phrase_min_length, slot_num
only_sentence = False
phrase_min_length=0
embed_dim = 300
slot_num = 1

def set_random_seed(seed):
  print("-" * 80)
  print("set random seed for data reading: {}".format(seed))
  np.random.seed(seed)

def sst_load_trees(filename):
  trees = read_trees(filename)
  return trees

def sst_get_id_input(content, word_id_dict, max_input_length):
  words = content.split(' ')
  sentence = []
  field = []
  index, f_index = 0, 1
  for i in range(0, max(max_input_length, len(words))):
    if len(words) <= index:
      id = word_id_dict["<pad>"]
    else:
      word = words[index].strip()
      if word in word_id_dict:
        id = word_id_dict[word]
      else:
        id = word_id_dict["<unknown>"]
    if index < max_input_length:
      sentence.append(id)
      if len(words) <= index:
        field.append(0)
      else:
        field.append(f_index)
    index += 1
    if "<sep>" in word_id_dict and id == word_id_dict["<sep>"]:
      f_index += 1
  return sentence, field

def sst_get_phrases(trees, sample_ratio=1.0,
                    is_binary=False, only_sentence=False):
  all_phrases = []
  for tree in trees:
    if only_sentence == True:
      sentence = get_sentence_by_tree(tree)
      label = int(tree.label)
      pair = (sentence, label)
      all_phrases.append(pair)
    else:
      phrases = get_phrases_by_tree(tree)
      sentence = get_sentence_by_tree(tree)
      pair = (sentence, int(tree.label))
      all_phrases.append(pair)
      all_phrases.extend(phrases)
  np.random.shuffle(all_phrases)
  result_phrases = []
  for pair in all_phrases:
    if is_binary:
      phrase = pair[0]
      label = pair[1]
      if label <= 1:
        pair = (phrase, 0)
      elif label >= 3:
        pair = (phrase, 1)
      else:
        continue
    if sample_ratio == 1.0:
      result_phrases.append(pair)
    else:
      rand_portion = np.random.random()
      if rand_portion < sample_ratio:
        result_phrases.append(pair)
  return result_phrases

def get_phrases_by_tree(tree):
  phrases = []
  if tree == None:
    return phrases
  if tree.is_leaf():
    pair = (tree.word, int(tree.label))
    phrases.append(pair)
    return phrases
  left_child_phrases = get_phrases_by_tree(tree.subtrees[0])
  right_child_phrases = get_phrases_by_tree(tree.subtrees[1])
  phrases.extend(left_child_phrases)
  phrases.extend(right_child_phrases)
  sentence = get_sentence_by_tree(tree)
  pair = (sentence, int(tree.label))
  phrases.append(pair)
  return phrases

def get_sentence_by_tree(tree):
  sentence = ""
  if tree == None:
    return sentence
  if tree.is_leaf():
    return tree.word
  left_sentence = get_sentence_by_tree(tree.subtrees[0])
  right_sentence = get_sentence_by_tree(tree.subtrees[1])
  sentence = left_sentence + " " + right_sentence
  return sentence.strip()

def get_word_id_dict(word_num_dict, word_id_dict, min_count):
  for word in word_num_dict:
    count = word_num_dict[word]
    if count >= min_count:
      index = len(word_id_dict)
      if word not in word_id_dict:
        word_id_dict[word] = index
  return word_id_dict

def load_word_num_dict(phrases, word_num_dict):
  for (sentence, label) in phrases:
    words = sentence.split(' ')
    for cur_word in words:
      word = cur_word.strip()
      if word not in word_num_dict:
        word_num_dict[word] = 1
      else:
        count = word_num_dict[word]
        word_num_dict[word] += 1
  return word_num_dict

def init_trainable_embedding(embedding, word_id_dict,
                word_embed_model, unknown_word_embed):
  embed_dim = unknown_word_embed.shape[0]
  embedding[0] = np.zeros(embed_dim)
  embedding[1] = unknown_word_embed
  for word in word_id_dict:
    id = word_id_dict[word]
    if id == 0 or id == 1:
      continue
    if word in word_embed_model:
      embedding[id] = word_embed_model[word]
    else:
      embedding[id] = np.random.rand(embed_dim) / 2.0 - 0.25
  print("init embedding: {0}".format(embedding))
  return embedding

def sst_get_trainable_data(phrases, word_id_dict,
                           split_label, max_input_length, is_binary):
  doc, bow_doc, labels, datasets = [], [], [], []

  for (phrase, label) in phrases:
    if len(phrase.split(' ')) < phrase_min_length:
      continue
    phrase_input, field_input = sst_get_id_input(phrase,
                                                 word_id_dict,
                                                 max_input_length)
    doc.append(phrase_input)
    bow_doc.append(field_input)
    labels.append(int(label))
    datasets.append("sst")
  labels = np.array(labels, dtype=np.int32)
  datasets = np.array(datasets, dtype=np.str)
  if split_label == 1:
    split_label_str = "train"
  elif split_label == 2:
    split_label_str = "test"
  else:
    split_label_str = "valid"
  doc = np.reshape(doc, [-1, max_input_length])  #(N, len)
  doc = doc.astype(np.int32)
  bow_doc = np.reshape(bow_doc, [-1, max_input_length])
  bow_doc = bow_doc.astype(np.int32)
  print(split_label_str, doc.shape, labels.shape, datasets.shape)
  print(doc)
  return doc, bow_doc, labels, datasets

def load_glove_model(filename):
  embedding_dict = {}
  with open(filename) as f:
    for line in f:
      vocab_word, vec = line.strip().split(' ', 1)
      embed_vector = list(map(float, vec.split()))
      embedding_dict[vocab_word] = embed_vector
  return embedding_dict

def load_embedding(embedding_model):
  word_embed_model = {}

  if embedding_model == "word2vec" or embedding_model == "all":
    embedding_data_path = '/data/yujwang/word2vec-GoogleNews-vectors'
    embedding_data_file = os.path.join(embedding_data_path,'GoogleNews-vectors-negative300.bin')
    word_embed_model["word2vec"] = word2vec.KeyedVectors.load_word2vec_format(embedding_data_file, binary=True)

  if embedding_model == "glove" or embedding_model == "all":
    embedding_data_path = '/data/yujwang'
    embedding_data_file = os.path.join(embedding_data_path, 'glove.840B.300d.txt')
    word_embed_model["glove"] = load_glove_model(embedding_data_file)

  unknown_word_embed = np.random.rand(embed_dim)    #create random vector in [0, 1)
  unknown_word_embed = (unknown_word_embed - 0.5) / 2.0
  return word_embed_model, unknown_word_embed

def read_data_sst(word_id_dict, word_num_dict, data_path, max_input_length,
                  embedding_model, min_count, train_ratio, valid_ratio,
                  is_binary=False, is_valid=False, cache={}):
  """Reads SST format data. Always returns NHWC format

  Returns:
    sentences: np tensor of size [N, H, W, C=1]
    labels: np tensor of size [N]
  """

  doc, labels, datasets = {}, {}, {}

  if len(cache) == 0:
    print("-" * 80)
    print("Reading SST data")

    train_file_name = os.path.join(data_path, 'train.txt')
    valid_file_name = os.path.join(data_path, 'dev.txt')
    test_file_name = os.path.join(data_path, 'test.txt')

    train_trees = sst_load_trees(train_file_name)
    train_phrases = sst_get_phrases(train_trees,
                                    train_ratio,
                                    is_binary,
                                    only_sentence)
    print("finish load train_phrases")
    valid_trees = sst_load_trees(valid_file_name)
    valid_phrases = sst_get_phrases(valid_trees,
                                    valid_ratio,
                                    is_binary,
                                    only_sentence or is_valid)
    if is_valid == False:
      train_phrases = train_phrases + valid_phrases
      valid_phrases = None
    test_trees = sst_load_trees(test_file_name)
    test_phrases = sst_get_phrases(test_trees,
                                   1.0,
                                   is_binary,
                                   only_sentence=True)
    print("finish load test_phrases")

    cache["train"] = train_phrases
    cache["valid"] = valid_phrases
    cache["test"] = test_phrases
  else:
    train_phrases = cache["train"]
    valid_phrases = cache["valid"]
    test_phrases = cache["test"]

  #get word_id_dict
  word_id_dict["<pad>"] = 0
  word_id_dict["<unknown>"] = 1
  load_word_num_dict(train_phrases, word_num_dict)
  print("finish load train words: {0}".format(len(word_num_dict)))
  if valid_phrases != None:
    load_word_num_dict(valid_phrases, word_num_dict)
  load_word_num_dict(test_phrases, word_num_dict)
  print("finish load test words: {0}".format(len(word_num_dict)))
  word_id_dict = get_word_id_dict(word_num_dict, word_id_dict, min_count)
  print("after trim words: {0}".format(len(word_id_dict)))

  if embedding_model != "none":
    word_embed_model, unknown_word_embed = load_embedding(embedding_model)
    embedding = {}
    for model_name in word_embed_model:
      embedding[model_name] = np.random.random(
              [len(word_id_dict), embed_dim]).astype(np.float32) / 2.0 - 0.25
      embedding[model_name] = init_trainable_embedding(embedding[model_name],
              word_id_dict, word_embed_model[model_name],
              unknown_word_embed)
    embedding["none"] = np.random.random(
            [len(word_id_dict), embed_dim]).astype(np.float32) / 2.0 - 0.25
    embedding["none"][0] = np.zeros([embed_dim])
    embedding["field"] = np.random.random(
            [slot_num + 1, embed_dim]).astype(np.float32) / 2.0 - 0.25
    embedding["field"][0] = np.zeros([embed_dim])

  else:
    embedding = {}
    embedding["none"] = np.random.random(
      [len(word_id_dict), embed_dim]).astype(np.float32) / 2.0 - 0.25
    embedding["none"][0] = np.zeros([embed_dim])
    embedding["field"] = np.random.random(
      [slot_num + 1, embed_dim]).astype(np.float32) / 2.0 - 0.25
    embedding["field"][0] = np.zeros([embed_dim])

  print("finish initialize word embedding")

  doc["train"], doc["train_bow_ids"], labels["train"], datasets["train"] \
          = sst_get_trainable_data(train_phrases, word_id_dict,
                   1, max_input_length, is_binary)
  doc["test"], doc["test_bow_ids"], labels["test"], datasets["test"] \
          = sst_get_trainable_data(test_phrases, word_id_dict,
                  2, max_input_length, is_binary)
  if is_valid == True:
    doc["valid"], doc["valid_bow_ids"], labels["valid"], datasets["valid"]\
            = sst_get_trainable_data(valid_phrases, word_id_dict,
                     3, max_input_length, is_binary)
  else:
    doc["valid"], doc["valid_bow_ids"], labels["valid"], datasets["valid"]\
            = None, None, None, None

  return doc, labels, datasets, embedding


from typing import Iterator, List, Union, Tuple, Any
from datetime import datetime
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split

from tensorflow import keras
import tensorflow_addons as tfa
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import layers, models, Model
from tensorflow.python.keras.callbacks import TensorBoard, EarlyStopping, ModelCheckpoint
from tensorflow.keras.losses import MeanAbsoluteError, MeanAbsolutePercentageError
from tensorflow.keras.models import Sequential
from tensorflow.keras.applications import EfficientNetB0
from tensorflow.keras.utils import plot_model
from tensorflow.keras.callbacks import History

# the next 3 lines of code are for my machine and setup due to https://github.com/tensorflow/tensorflow/issues/43174
import tensorflow as tf

physical_devices = tf.config.list_physical_devices("GPU")
tf.config.experimental.set_memory_growth(physical_devices[0], True)

def visualize_augmentations(data_generator: ImageDataGenerator, df: pd.DataFrame):
    """Visualizes the keras augmentations with matplotlib in 3x3 grid. This function is part of create_generators() and
    can be accessed from there.

    Parameters
    ----------
    data_generator : Iterator
        The keras data generator of your training data.
    df : pd.DataFrame
        The Pandas DataFrame containing your training data.
    """
    # super hacky way of creating a small dataframe with one image
    series = df.iloc[2]

    df_augmentation_visualization = pd.concat([series, series], axis=1).transpose()

    iterator_visualizations = data_generator.flow_from_dataframe(  # type: ignore
        dataframe=df_augmentation_visualization,
        x_col="image_location",
        y_col="price",
        class_mode="raw",
        target_size=(224, 224),  # size of the image
        batch_size=1,  # use only one image for visualization
    )

    for i in range(9):
        ax = plt.subplot(3, 3, i + 1)  # create a 3x3 grid
        batch = next(iterator_visualizations)  # get the next image of the generator (always the same image)
        img = batch[0]  # type: ignore
        img = img[0, :, :, :]  # remove one dimension for plotting without issues
        plt.imshow(img)
    plt.show()
    plt.close()

def get_mean_baseline(train: pd.DataFrame, val: pd.DataFrame) -> float:
    """Calculates the mean MAE and MAPE baselines by taking the mean values of the training data as prediction for the
    validation target feature.

    Parameters
    ----------
    train : pd.DataFrame
        Pandas DataFrame containing your training data.
    val : pd.DataFrame
        Pandas DataFrame containing your validation data.

    Returns
    -------
    float
        MAPE value.
    """
    y_hat = train["price"].mean()
    val["y_hat"] = y_hat
    mae = MeanAbsoluteError()
    mae = mae(val["price"], val["y_hat"]).numpy()  # type: ignore
    mape = MeanAbsolutePercentageError()
    mape = mape(val["price"], val["y_hat"]).numpy()  # type: ignore

    print(mae)
    print("mean baseline MAPE: ", mape)

    return mape

def split_data(df: pd.DataFrame) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
    """Accepts a Pandas DataFrame and splits it into training, testing and validation data. Returns DataFrames.

    Parameters
    ----------
    df : pd.DataFrame
        Your Pandas DataFrame containing all your data.

    Returns
    -------
    Union[pd.DataFrame, pd.DataFrame, pd.DataFrame]
        [description]
    """
    train, val = train_test_split(df, test_size=0.2, random_state=1)  # split the data with a validation size o 20%
    train, test = train_test_split(
        train, test_size=0.125, random_state=1
    )  # split the data with an overall  test size of 10%

    print("shape train: ", train.shape)  # type: ignore
    print("shape val: ", val.shape)  # type: ignore
    print("shape test: ", test.shape)  # type: ignore

    print("Descriptive statistics of train:")
    print(train.describe())  # type: ignore
    return train, val, test  # type: ignore

def create_generators(
    df: pd.DataFrame, train: pd.DataFrame, val: pd.DataFrame, test: pd.DataFrame, plot_augmentations: Any
) -> Tuple[Iterator, Iterator, Iterator]:
    """Accepts four Pandas DataFrames: all your data, the training, validation and test DataFrames. Creates and returns
    keras ImageDataGenerators. Within this function you can also visualize the augmentations of the ImageDataGenerators.

    Parameters
    ----------
    df : pd.DataFrame
        Your Pandas DataFrame containing all your data.
    train : pd.DataFrame
        Your Pandas DataFrame containing your training data.
    val : pd.DataFrame
        Your Pandas DataFrame containing your validation data.
    test : pd.DataFrame
        Your Pandas DataFrame containing your testing data.

    Returns
    -------
    Tuple[Iterator, Iterator, Iterator]
        keras ImageDataGenerators used for training, validating and testing of your models.
    """
    train_generator = ImageDataGenerator(
        rescale=1.0 / 255,
        rotation_range=5,
        width_shift_range=0.1,
        height_shift_range=0.1,
        brightness_range=(0.75, 1),
        shear_range=0.1,
        zoom_range=[0.75, 1],
        horizontal_flip=True,
        validation_split=0.2,
    )  # create an ImageDataGenerator with multiple image augmentations
    validation_generator = ImageDataGenerator(
        rescale=1.0 / 255
    )  # except for rescaling, no augmentations are needed for validation and testing generators
    test_generator = ImageDataGenerator(rescale=1.0 / 255)
    # visualize image augmentations
    if plot_augmentations == True:
        visualize_augmentations(train_generator, df)

    train_generator = train_generator.flow_from_dataframe(
        dataframe=train,
        x_col="image_location",  # this is where your image data is stored
        y_col="price",  # this is your target feature
        class_mode="raw",  # use "raw" for regressions
        target_size=(224, 224),
        batch_size=32,  # increase or decrease to fit your GPU
    )

    validation_generator = validation_generator.flow_from_dataframe(
        dataframe=val, x_col="image_location", y_col="price", class_mode="raw", target_size=(224, 224), batch_size=128,
    )
    test_generator = test_generator.flow_from_dataframe(
        dataframe=test, x_col="image_location", y_col="price", class_mode="raw", target_size=(224, 224), batch_size=128,
    )
    return train_generator, validation_generator, test_generator

def get_callbacks(model_name: str) -> List[Union[TensorBoard, EarlyStopping, ModelCheckpoint]]:
    """Accepts the model name as a string and returns multiple callbacks for training the keras model.

    Parameters
    ----------
    model_name : str
        The name of the model as a string.

    Returns
    -------
    List[Union[TensorBoard, EarlyStopping, ModelCheckpoint]]
        A list of multiple keras callbacks.
    """
    logdir = (
        "logs/scalars/" + model_name + "_" + datetime.now().strftime("%Y%m%d-%H%M%S")
    )  # create a folder for each model.
    tensorboard_callback = TensorBoard(log_dir=logdir)
    # use tensorboard --logdir logs/scalars in your command line to startup tensorboard with the correct logs

    early_stopping_callback = EarlyStopping(
        monitor="val_mean_absolute_percentage_error",
        min_delta=1,  # model should improve by at least 1%
        patience=10,  # amount of epochs  with improvements worse than 1% until the model stops
        verbose=2,
        mode="min",
        restore_best_weights=True,  # restore the best model with the lowest validation error
    )

    model_checkpoint_callback = ModelCheckpoint(
        "./data/models/" + model_name + ".h5",
        monitor="val_mean_absolute_percentage_error",
        verbose=0,
        save_best_only=True,  # save the best model
        mode="min",
        save_freq="epoch",  # save every epoch
    )  # saving eff_net takes quite a bit of time
    return [tensorboard_callback, early_stopping_callback, model_checkpoint_callback]

def small_cnn() -> Sequential:
    """A very small custom convolutional neural network with image input dimensions of 224x224x3.

    Returns
    -------
    Sequential
        The keras Sequential model.
    """
    model = models.Sequential()
    model.add(layers.Conv2D(32, (3, 3), activation="relu", input_shape=(224, 224, 3)))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(64, (3, 3), activation="relu"))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(64, (3, 3), activation="relu"))

    model.add(layers.Flatten())
    model.add(layers.Dense(64, activation="relu"))
    model.add(layers.Dense(1))

    return model

def run_model(
    model_name: str,
    model_function: Model,
    lr: float,
    train_generator: Iterator,
    validation_generator: Iterator,
    test_generator: Iterator,
) -> History:
    """This function runs a keras model with the Ranger optimizer and multiple callbacks. The model is evaluated within
    training through the validation generator and afterwards one final time on the test generator.

    Parameters
    ----------
    model_name : str
        The name of the model as a string.
    model_function : Model
        Keras model function like small_cnn()  or adapt_efficient_net().
    lr : float
        Learning rate.
    train_generator : Iterator
        keras ImageDataGenerators for the training data.
    validation_generator : Iterator
        keras ImageDataGenerators for the validation data.
    test_generator : Iterator
        keras ImageDataGenerators for the test data.

    Returns
    -------
    History
        The history of the keras model as a History object. To access it as a Dict, use history.history. For an example
        see plot_results().
    """

    callbacks = get_callbacks(model_name)
    model = model_function
    model.summary()
    plot_model(model, to_file=model_name + ".png", show_shapes=True)

    radam = tfa.optimizers.RectifiedAdam(learning_rate=lr)
    ranger = tfa.optimizers.Lookahead(radam, sync_period=6, slow_step_size=0.5)
    optimizer = ranger

    model.compile(
        optimizer=optimizer, loss="mean_absolute_error", metrics=[MeanAbsoluteError(), MeanAbsolutePercentageError()]
    )
    history = model.fit(
        train_generator,
        epochs=100,
        validation_data=validation_generator,
        callbacks=callbacks,
        workers=6,  # adjust this according to the number of CPU cores of your machine
    )

    model.evaluate(
        test_generator, callbacks=callbacks,
    )
    return history  # type: ignore

def adapt_efficient_net() -> Model:
    """This code uses adapts the most up-to-date version of EfficientNet with NoisyStudent weights to a regression
    problem. Most of this code is adapted from the official keras documentation.

    Returns
    -------
    Model
        The keras model.
    """
    inputs = layers.Input(
        shape=(224, 224, 3)
    )  # input shapes of the images should always be 224x224x3 with EfficientNetB0
    # use the downloaded and converted newest EfficientNet wheights
    model = EfficientNetB0(include_top=False, input_tensor=inputs, weights="efficientnetb0_notop.h5")
    # Freeze the pretrained weights
    model.trainable = False

    # Rebuild top
    x = layers.GlobalAveragePooling2D(name="avg_pool")(model.output)
    x = layers.BatchNormalization()(x)
    top_dropout_rate = 0.4
    x = layers.Dropout(top_dropout_rate, name="top_dropout")(x)
    outputs = layers.Dense(1, name="pred")(x)

    # Compile
    model = keras.Model(inputs, outputs, name="EfficientNet")

    return model

def plot_results(model_history_small_cnn: History, model_history_eff_net: History, mean_baseline: float):
    """This function uses seaborn with matplotlib to plot the trainig and validation losses of both input models in an
    sns.relplot(). The mean baseline is plotted as a horizontal red dotted line.

    Parameters
    ----------
    model_history_small_cnn : History
        keras History object of the model.fit() method.
    model_history_eff_net : History
        keras History object of the model.fit() method.
    mean_baseline : float
        Result of the get_mean_baseline() function.
    """

    # create a dictionary for each model history and loss type
    dict1 = {
        "MAPE": model_history_small_cnn.history["mean_absolute_percentage_error"],
        "type": "training",
        "model": "small_cnn",
    }
    dict2 = {
        "MAPE": model_history_small_cnn.history["val_mean_absolute_percentage_error"],
        "type": "validation",
        "model": "small_cnn",
    }
    dict3 = {
        "MAPE": model_history_eff_net.history["mean_absolute_percentage_error"],
        "type": "training",
        "model": "eff_net",
    }
    dict4 = {
        "MAPE": model_history_eff_net.history["val_mean_absolute_percentage_error"],
        "type": "validation",
        "model": "eff_net",
    }

    # convert the dicts to pd.Series and concat them to a pd.DataFrame in the long format
    s1 = pd.DataFrame(dict1)
    s2 = pd.DataFrame(dict2)
    s3 = pd.DataFrame(dict3)
    s4 = pd.DataFrame(dict4)
    df = pd.concat([s1, s2, s3, s4], axis=0).reset_index()
    grid = sns.relplot(data=df, x=df["index"], y="MAPE", hue="model", col="type", kind="line", legend=False)
    grid.set(ylim=(20, 100))  # set the y-axis limit
    for ax in grid.axes.flat:
        ax.axhline(
            y=mean_baseline, color="lightcoral", linestyle="dashed"
        )  # add a mean baseline horizontal bar to each plot
        ax.set(xlabel="Epoch")
    labels = ["small_cnn", "eff_net", "mean_baseline"]  # custom labels for the plot

    plt.legend(labels=labels)
    plt.savefig("training_validation.png")
    plt.show()

def run(small_sample=False):
    """Run all the code of this file.

    Parameters
    ----------
    small_sample : bool, optional
        If you just want to check if the code is working, set small_sample to True, by default False
    """

    df = pd.read_pickle("./data/df.pkl")
    df["image_location"] = (
        "./data/processed_images/" + df["zpid"] + ".png"
    )  # add the correct path for the image locations.
    if small_sample == True:
        df = df.iloc[0:1000]  # set small_sampe to True if you want to check if your code works without long waiting
    train, val, test = split_data(df)  # split your data
    mean_baseline = get_mean_baseline(train, val)
    train_generator, validation_generator, test_generator = create_generators(
        df=df, train=train, val=val, test=test, plot_augmentations=True
    )

    small_cnn_history = run_model(
        model_name="small_cnn",
        model_function=small_cnn(),
        lr=0.001,
        train_generator=train_generator,
        validation_generator=validation_generator,
        test_generator=test_generator,
    )

    eff_net_history = run_model(
        model_name="eff_net",
        model_function=adapt_efficient_net(),
        lr=0.5,
        train_generator=train_generator,
        validation_generator=validation_generator,
        test_generator=test_generator,
    )

    plot_results(small_cnn_history, eff_net_history, mean_baseline)

if __name__ == "__main__":
    run(small_sample=False)