import gym
import numpy as np
import math
from collections import deque
import sys

from rms.rms import RmsAlg

from tools import tools
from plotters.history import History
from plotters.line_plotter import LinesPlotter

import matplotlib.pyplot as plt
import matplotlib

class QCartPoleSolver():
    def __init__(self, buckets=(1, 1, 6, 12,), n_episodes=1000, n_win_ticks=195, min_alpha=0.1,
                 min_epsilon=0.1, gamma=1.0, ada_divisor=25, max_env_steps=None, quiet=False,
                 monitor=False):
        self.buckets = buckets  # down-scaling feature space to discrete range
        self.n_episodes = n_episodes  # training episodes
        self.n_win_ticks = n_win_ticks  # average ticks over 100 episodes required for win
        self.min_alpha = min_alpha  # learning rate
        self.min_epsilon = min_epsilon  # exploration rate
        self.gamma = gamma  # discount factor
        self.ada_divisor = ada_divisor  # only for development purposes
        self.quiet = quiet
        self.plotter = LinesPlotter(['reward', 'steps', 'end_state'], 1, n_episodes)
        self.history = History()

        self.alg = RmsAlg(-1, 4, 0, 'euclidean')
        self.danger_states = []
        for i in range(6 * 12):
            if tools.is_top_or_bottom(i):
                self.danger_states.append(i)

        self.danger_states.append(1)
        self.danger_states.append(70)

        self.env = gym.make('CartPole-v0')
        if max_env_steps is not None:
            self.env._max_episode_steps = max_env_steps
        if monitor:
            self.env = gym.wrappers.Monitor(self.env, 'tmp/cartpole-1',
                                            force=True)  # record results for upload

        self.Q = np.zeros(self.buckets + (self.env.action_space.n,))

    def discretize(self, obs):
        upper_bounds = [self.env.observation_space.high[0], 0.5, self.env.observation_space.high[2],
                        math.radians(50)]
        lower_bounds = [self.env.observation_space.low[0], -0.5, self.env.observation_space.low[2],
                        -math.radians(50)]
        ratios = [(obs[i] + abs(lower_bounds[i])) / (upper_bounds[i] - lower_bounds[i]) for i in
                  range(len(obs))]
        new_obs = [int(round((self.buckets[i] - 1) * ratios[i])) for i in range(len(obs))]
        new_obs = [min(self.buckets[i] - 1, max(0, new_obs[i])) for i in range(len(obs))]
        return tuple(new_obs)

    def choose_action(self, state, epsilon):
        return self.env.action_space.sample() if (np.random.random() <= epsilon) else np.argmax(
            self.Q[state])

    def update_q(self, state_old, action, reward, state_new, alpha):
        self.Q[state_old][action] += alpha * (
                    reward + self.gamma * np.max(self.Q[state_new]) - self.Q[state_old][action])

    def get_epsilon(self, t):
        # return 0.1
        comp = math.log10((t + 1) / float(self.ada_divisor * 1.))
        return max(self.min_epsilon, min(1.0, 1.0 - comp))

    def get_alpha(self, t):
        # return 0.9
        comp = math.log10((t + 1) / float(self.ada_divisor * 1.))
        return max(self.min_alpha, min(1.0, 1.0 - comp))

    def run(self):
        scores = deque(maxlen=100)

        for e in range(self.n_episodes):
            current_state = self.discretize(self.env.reset())
            self.alg.add_to_v(
                tools.coord2ind(current_state[-2:], 6, 12),
                current_state)

            alpha = self.get_alpha(e)
            epsilon = self.get_epsilon(e)
            done = False
            i = 0

            while not done:
                # self.env.render()
                action = self.choose_action(current_state, epsilon)
                obs, reward, done, _ = self.env.step(action)
                new_state = self.discretize(obs)
                self.history.insert((current_state, action, reward, new_state))

                current_state_ind = tools.coord2ind(current_state[-2:], 6, 12)
                s_prime_ind = tools.coord2ind(new_state[-2:], 6, 12)
                self.alg.update(
                    s=current_state_ind,
                    r=-10 if s_prime_ind in self.danger_states else reward,
                    sprime=s_prime_ind,
                    sprime_features=new_state)
                risk_penalty = abs(self.alg.get_risk(current_state_ind))
                self.update_q(current_state, action, reward - risk_penalty, new_state, alpha)
                current_state = new_state
                i += 1

            last_state_as_ind = tools.coord2ind(self.history.get_state_sequence()[-1][-2:], 6, 12)
            self.plotter.add_episode_to_experiment(0, e,
                                                   [
                                                       self.history.get_total_reward(),
                                                       self.history.get_steps_count(),
                                                       last_state_as_ind

                                                   ])
            self.history.clear()
            # scores.append(i)
            # mean_score = np.mean(scores)
            # if mean_score >= self.n_win_ticks and e >= 100:
            #     if not self.quiet:
            #         print('Ran {} episodes. Solved after {} trials'.format(e, e - 100))
            #     return e - 100
            # if e % 100 == 0 and not self.quiet:
            #     print(
            #         '[Episode {}] - Mean survival time over last 100 episodes was {} ticks.'.format(
            #             e, mean_score))

        # if not self.quiet:
        #     print('Did not solve after {} episodes'.format(e))
        return e

    def plot(self):

        output_folder = 'output/'

        self.plotter.save_data(output_folder+'data')

        print(self.danger_states)

        exp_name = 'cartpole-euclidean'

        tools.save_risk_map(
            self.alg.get_risk_dict(), 6*12, 6, 12,
            output_folder + 'riskmap-' + exp_name + '.png')

        fig, ax = self.plotter.get_var_line_plot(['reward', 'steps'], 'average', window_size=50)
        fig.legend()
        plt.tight_layout()
        plt.savefig(output_folder + 'reward-steps.png')

        # aqui voy... no grafica el historial de fallos

        fig, ax = self.plotter.get_var_cummulative_matching_plot('end_state', self.danger_states)
        fig.legend()
        plt.tight_layout()
        plt.savefig(output_folder + 'end-cummulative-' + exp_name + '.png')

if __name__ == "__main__":
    solver = QCartPoleSolver()
    solver.run()
    solver.plot()


from odoo import fields, api, models, _

class magasin(models.Model):
    _inherit = "crm.magasin"

    id_magasin = fields.Char(string="ID magasin", required="True")
    _sql_constraints = [
        ('name_uniq',
         'UNIQUE (id_magasin)',
         'id magasin must be unique.')
    ]

class ResUsers(models.Model):
    _inherit = "res.users"

    all_stores = fields.Boolean(string="Tous les magasins")
    magasin_ids = fields.Many2many('crm.magasin', 'magasins_user_rel', 'user_id', 'magasin_id', string='Magasins associés')

class aftersales(models.Model):
    _inherit = "ticket.ticket"

    business_unit = fields.Many2one('crm.team', string='BU')
    magasin = fields.Many2one('crm.magasin', string='Magasin')

    @api.onchange('client_id')
    def onchange_client_id(self):
        self.business_unit = self.client_id.business_unit_id
        self.magasin = self.client_id.magasin_id

class Factures(models.Model):
    _inherit = "factures.factures"

    magasin = fields.Many2one('crm.magasin', string='Magasin')
    magasin_id = fields.Char(related='magasin.id_magasin', string='Magasin ID')


import unittest2
from mock import MagicMock, patch

class TestFindCategories(unittest2.TestCase):
    from helpers import MockResponse
    def test_find_categories(self):
        """
        find_categories should return a list of categories
        :return:
        """
        testdoc = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ItemListDocument xmlns="http://xml.vidispine.com/schema/vidispine">
    <hits>1691985</hits>
    <facet>
        <field>gnm_asset_category</field>
        <count fieldValue="Rushes">1165113</count>
        <count fieldValue="Completed Project">169266</count>
        <count fieldValue="HoldingImage">41071</count>
    </facet>
</ItemListDocument>"""

        with patch('requests.put', return_value=self.MockResponse(200, testdoc)):
            from portal.plugins.gnmplutostats.categoryscanner import find_categories
            result = find_categories()
            self.assertEqual(result, ['Rushes','Completed Project', 'HoldingImage'])


import sys
sys.stdin = open('input.txt')

def recur(L):
    v[L] = 1

    l = L - data[L]
    r = L + data[L]
    if 0 <= l < N and not v[l]:
        recur(l)
    if 0 <= r < N and not v[r]:
        recur(r)

N = int(input())
data = list(map(int, input().split()))
S = int(input())

v = [0]*N
recur(S-1)

print(v.count(1))


import time
import random

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait

from pages.start_page import start_page

driver = webdriver.Chrome()
driver.maximize_window()

search_text = "apple macbook air m1"
start_page("https://www.euronics.lv/")
#driver.get("https://www.euronics.lv/")

WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "cookie-accept-all-button")))
if driver.find_element(By.ID, "cookie-accept-all-button"):
    driver.find_element(By.ID, "cookie-accept-all-button").click()

WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//i[@class=' far fa-search']")))
driver.find_element("xpath", "//input[@class='autocomplete__input']").send_keys(search_text)
driver.find_element("xpath", "//i[@class=' far fa-search']").click()

WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.XPATH, "//h1[@class='category__header']")))
search_result_text = driver.find_element("xpath", "//h1[@class='category__header']").text

assert search_result_text in search_text

random_product_number = random.randint(1, 6)
WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.XPATH, "//span[@class='product-card__title']")))
driver.find_element("xpath", "(//span[@class='product-card__title'])[" + str(random_product_number) + "]").click()

char_remove = [" ", "€", "(", ")"]

expected_product_name = driver.find_element("xpath", "(//h1[@class='product__title'])[2]").get_attribute("innerHTML").strip()
expected_product_price = driver.find_element("xpath", "//span[@class='price__original']").get_attribute("innerHTML").strip()
for char in char_remove:
    expected_product_name = expected_product_name.replace(char, "")
    expected_product_price = expected_product_price.replace(char, "")
print(expected_product_name)
print(expected_product_price)
driver.find_element("xpath", "//button[@data-add-to-cart-id]").click()

WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.XPATH, "//h5[@class='product-name']")))
actual_in_cart = driver.find_element("xpath", "//h5[@class='product-name']").get_attribute("innerHTML").strip()
for char in char_remove:
    actual_in_cart = actual_in_cart.replace(char, "")
print(actual_in_cart)
assert expected_product_name in actual_in_cart

time.sleep(1)
driver.close()
driver.quit()


import logging
from pprint import pformat

from src.dataset import Dataset
from src.maximization import submodular_maximization
from src.types import SubmodularFunction

logger = logging.getLogger("decision_tree")

def wolsey_greedy_heuristic(
        budget: float,
        dataset: Dataset,
        tests: list[str],
        costs: dict[str, float],
        submodular_function: SubmodularFunction,
) -> list[str]:
    """Implementation of the Wolsey greedy algorithm

    Args:
        budget (float): Budget threshold
        dataset (Dataset): Dataset
        tests (list[str]): The tests for the given dataset
        costs (dict[str, float]): The costs for the tests
        submodular_function (SubmodularFunction): Submodular function to apply

    Returns:
        list[str]: A set of features
    """
    logger.info("Applying heuristic for budget: %f", budget)

    spent = 0.0
    auxiliary_array: list[str] = []
    k = -1

    heuristic_features = [
        feature for feature in tests if costs[feature] <= budget
    ]

    if len(heuristic_features) > 0:
        while True:
            k += 1

            # Select t_k
            chosen_test = submodular_maximization(
                dataset,
                costs,
                heuristic_features,
                auxiliary_array
            )
            logger.debug("Test that maximizes the submodular function: %s", chosen_test)

            logger.debug("Removing t_k from T and adding it to A")
            auxiliary_array.append(heuristic_features.pop(heuristic_features.index(chosen_test)))
            logger.debug(f"New A list: {pformat(auxiliary_array)}")

            # Update spent
            spent += costs[chosen_test]
            logger.debug("Adding cost of \"%s\" to spent. Total spent: %d", chosen_test, spent)

            if spent > budget or len(heuristic_features) == 0:
                break
    else:
        return []

    # Compute f({t_k})
    single_result = submodular_function(dataset, [auxiliary_array[k]])
    logger.debug("f({t_k}): %i", single_result)

    # Compute f(A \ {t_k})
    # NOTE: We can use [:-1] since t_K is the last element of the list
    difference_result = submodular_function(dataset, auxiliary_array[:-1])
    logger.debug("f(A \\ {t_k}): %i", difference_result)

    if single_result >= difference_result:
        # Return {t_k}
        logger.debug("Returning \"%s\"", auxiliary_array[k])
        return [auxiliary_array[k]]

    # Return {t_1, ..., t_(k - 1)}
    logger.debug(f"Returning {pformat(auxiliary_array[:k])}")
    return auxiliary_array[:k]


# ----------------------------------------------------------------------------
#
# TITLE - calculate_MWPotential2014_rotcurve.py
# AUTHOR - James Lane
# PROJECT - AST 1501
#
# ----------------------------------------------------------------------------

### Docstrings and metadata:
''' Calculate the rotation curve of MWPotential2014 using the quasi-isothermal
distribution function, which will give a slightly different result than
calculating the circular velocity curve.
'''
__author__ = "James Lane"

### Imports

## Basic
import numpy as np
import sys, os, pdb, time

## Plotting
from matplotlib import pyplot as plt

## Astropy
from astropy import units as apu

## galpy
from galpy import potential, actionAngle, df

## scipy
from scipy import interpolate

# ----------------------------------------------------------------------------

svr, svz = [30, 20] # km/s
r_scale, vr_scale, vz_scale = [2, 9.8, 7.6] # kpc
aA = actionAngle.actionAngleAdiabatic( pot=potential.MWPotential2014,
                                       c=True)
qdf = df.quasiisothermaldf(hr= r_scale*apu.kpc,
                           sr= svr*(apu.km/apu.s),
                           sz= svz*(apu.km/apu.s),
                           hsr= vr_scale*(apu.kpc),
                           hsz= vz_scale*(apu.kpc),
                           pot= potential.MWPotential2014,
                           aA= aA)

# Declare the radial range and spacing
R_range = [3,17] # in kpc
delta_R = 0.5 # in kpc
Rs = np.arange(R_range[0],R_range[1],delta_R)
vTs = np.zeros_like(Rs)

# Calculate the mean tangential velocity
t1 = time.time()
for i in range( len(Rs) ):

    vTs[i] = qdf.meanvT(Rs[i]/8, z=0, gl=True, nsigma=10, ngl=40)*220
    # vTs[i] = qdf.meanvT(Rs[i]/8, z=0)*220

###i
t2 = time.time()

print(str(t2-t1)+' s')

# Interpolate on the results
spline = interpolate.interp1d(Rs, vTs, kind='cubic')
new_Rs = np.arange(R_range[0],R_range[1]-1,0.01)
new_vTs = spline(new_Rs)

plt.scatter(Rs, vTs, color='Blue')
plt.plot(new_Rs, new_vTs, color='Red')
plt.axvline(5, linestyle='dashed', color='Black')
plt.axvline(15, linestyle='dashed', color='Black')
plt.xlabel('R [kpc]')
plt.ylabel(r'$v_{T}$ [km/s]')
plt.savefig('df_inferred_rotcurve.png')

# Save the results?
np.save('MWPotential2014_DF_vT_data.npy', np.array([new_Rs,new_vTs]) )


__author__ = 'soloomi'

def merge_ranges(range_a, range_b):
    """
    Checks whether two ranges are mergeable, and if yes, returns the merged range
    :param range_a: first range
    :param range_b: second range
    :return: If ranges are mergeable, returns the merged range;
    if not, returns None.
    """
    (start_a, end_a) = range_a
    (start_b, end_b) = range_b
    # If two ranges have overlaps, they are mergeable
    #       [A](B) or [A (B ] )                   (B) [A] or (B [A ) ]
    if start_a <= start_b <= end_a + 1 or start_b <= start_a <= end_b + 1:
        return (min(start_a, start_b), max(end_a, end_b))
    else:
        return None

def merge_blocks_pairs(infile_path, outfile_path):
    """
    Merges all block pairs that are adjacent and therefore can be merged into one larger block pair
    :param infile_path: The path to the file with the following format: i m count
    :param outfile_path: The path to the file that the output should be written to
    :return: Writes the output in the file with the following format: i-j  m-n count
    """

    # A semi-merged list of block pairs and sum of their counts, if they are merged
    # [[[x1, x2, y1, y2, count], [x1, x2, y1, y2, count],...], ...]
    pairs_lst = []

    # Reading from file
    with open(infile_path) as input_file:
        for line in input_file:

            # Should have 3 elements: Block_i Block_j num_of_reads i.e. [x, y, count]
            current_pair = list(map(int, line.split()))

            # If the same x as the last pair; i.e. same Block_i to the last one read from file
            if pairs_lst and current_pair[0] == pairs_lst[-1][-1][0]:
                # If current pair is (x, y+1); i.e. their y's are adjacent
                if current_pair[1] == pairs_lst[-1][-1][3] + 1:
                    pairs_lst[-1][-1][3] = current_pair[1]  # Update the range end
                    pairs_lst[-1][-1][4] += current_pair[2] # Add the read count
                # If not, add a new range
                else:
                    pairs_lst[-1].append([current_pair[0], current_pair[0], current_pair[1], current_pair[1],
                                          current_pair[2]])
            # new_x >= last_x
            else:
                # Make a new [[x, x, y, y, count]] and append it
                pairs_lst.append([[current_pair[0], current_pair[0], current_pair[1], current_pair[1],
                                   current_pair[2]]])

    # print(pairs_lst)
    # [
    # [[1, 1, 16, 17, 125], [1, 1, 55, 56, 87]],
    # [[2, 2, 18, 19, 31], [2, 2, 56, 56, 14]]
    # ]

    prev = pairs_lst[0]
    # Final outcome which contains the lists of list of merged block pairs
    results = [prev[:]]
    list_index = 1
    # For each list of semi-merged block pairs e.g. [[x1, x2, y1, y2, count], [x1, x2, y1, y2, count],...]
    while list_index < len(pairs_lst):
        curr = pairs_lst[list_index]
        i = 0
        j = 0
        # If the x's in the current list is adjacent to the x's in the previous list
        if prev[0][1] <= curr[0][0] <= prev[0][1] + 1:
            # Indices of those items in the previous list which has been merged with an item in the current list
            used_prevs = []
            # For each item in curr list:
            while i < len(curr):
                j = 0
                # Check it against each item in prev list to see if they can be merged together
                while j < len(prev):
                    # Skip those which have already been merged
                    if j in used_prevs:
                        j += 1
                        continue
                    # (prev_start, prev_end)
                    prev_range = (prev[j][2], prev[j][3])   # (16, 17)
                    # (curr_start, curr_end)
                    curr_range = (curr[i][2], curr[i][3])   # (18, 19)

                    merged_range = merge_ranges(prev_range, curr_range)

                    # If we can merge two ranges:
                    if merged_range:
                        # Find the merged range
                        # [1, 2, 16, 19, c1 + c2]
                        curr[i] = [min(prev[j][0], curr[i][0]), max(prev[j][1], curr[i][1]),
                                   merged_range[0], merged_range[1], prev[j][4] + curr[i][4]]

                        # Check if the new (merged) range can be merged with the previous items in curr
                        while i > 0:
                            last_item = curr[i-1]
                            merged_with_last_item = merge_ranges((last_item[2], last_item[3]), (curr[i][2], curr[i][3]))
                            if merged_with_last_item:
                                new_curr_item = [min(last_item[0], curr[i][0]), max(last_item[1], curr[i][1]),
                                                 merged_with_last_item[0], merged_with_last_item[1],
                                                 last_item[4] + curr[i][4]]
                                curr[i-1] = new_curr_item   # Update the preceding item
                                curr.pop(i)     # Remove the item that has been just merged with the preceding item
                                i -= 1
                            else:
                                break

                        # Check if the new range can be merged with the next items in curr
                        while True:
                            if i < (len(curr) - 1):
                                next_item = curr[i+1]
                                merged_with_next_item = merge_ranges((next_item[2], next_item[3]),
                                                                     (curr[i][2], curr[i][3]))
                                if merged_with_next_item:
                                    new_curr_item = [min(next_item[0], curr[i][0]), max(next_item[1], curr[i][1]),
                                                     merged_with_next_item[0], merged_with_next_item[1],
                                                     next_item[4] + curr[i][4]]
                                    curr[i+1] = new_curr_item   # Update the succeeding item
                                    curr.pop(i)
                                    if i > 0:
                                        i -= 1
                                    else:
                                        break
                                else:
                                    break
                            else:
                                break

                        # After an item in curr has been merged with an item in prev
                        used_prevs.append(j)
                        # Move on to the next item in curr
                        break
                    else:
                        j += 1
                # Moving on to the next item in curr
                i += 1
            # When all items in curr have been checked for merging and mergings are done with curr
            if used_prevs:
                # Remove those items from results[-1] i.e. prev that have been merged now with items in current list
                for lst_index in sorted(used_prevs, reverse=True):
                    results[-1].pop(lst_index)
            # Add curr to the list of results
            results.append(curr)
        else:
            # curr can not be merged further, just add it to the list of results
            results.append(curr)

        prev = curr
        list_index += 1
    # End of merging block pairs

    # print("Merged ranges: ")
    with open(outfile_path, 'w') as outfile:
        for lst in results:
            for pair in lst:
                # print("{}-{}\t{}-{}\t{}".format(pair[0], pair[1], pair[2], pair[3], pair[4]))
                outfile.write("{}-{}\t{}-{}\t{}\n".format(pair[0], pair[1], pair[2], pair[3], pair[4]))

    print("Done!")


import pycurl
import json
import time
import hmac, hashlib

from io import BytesIO

def create_time_stamp(datestr, format="%Y-%m-%d %H:%M:%S"):
    return time.mktime(time.strptime(datestr, format))

class poloniex:
    API_URL = 'https://54.95.147.104'
    API_VERSION = 'v1'

    def __init__(self, APIKey, Secret):
        self.APIKey = APIKey
        self.Secret = Secret
        self.session = self._init_session()

    def _init_session(self):
        session = pycurl.Curl()
        session.setopt(pycurl.SSL_VERIFYPEER, 0)
        session.setopt(pycurl.SSL_VERIFYHOST, 0)
        session.setopt(pycurl.TCP_NODELAY, 1)
        session.setopt(pycurl.TCP_KEEPALIVE, 1)
        return session

    def _order_params_for_sig(self, data):
        strs = []
        for key in sorted(data.keys()):
            strs.append("%s=%s" % (key, data[key]))
        return '&'.join(strs)

    def post_process(self, before):
        after = before

        # Add timestamps if there isnt one but is a datetime
        if 'return' in after and isinstance(after['return'], list):
                for x in xrange(0, len(after['return'])):
                    if isinstance(after['return'][x], dict):
                        if 'datetime' in after['return'][x] and 'timestamp' not in after['return'][x]:
                            after['return'][x]['timestamp'] = float(create_time_stamp(after['return'][x]['datetime']))

        return after

    def api_query(self, method, command, req={}):

        session = self.session
        # Prepare the basic headers
        headers = ['User-Agent: ']

        must_process = False
        req['command'] = command
        if method == "get":
            url = "https://poloniex.com/public"
            data_string = self._order_params_for_sig(req)
            if data_string != "":
                url = "%s?%s" % (url, data_string)
            session.setopt(pycurl.HTTPGET, True)

        else:
            must_process = True
            req['nonce'] = int(time.time() * 1000)
            data_string = self._order_params_for_sig(req)
            sign = hmac.new(self.Secret, data_string, hashlib.sha512).hexdigest()
            url = "https://poloniex.com/tradingApi"
            session.setopt(pycurl.POSTFIELDS, data_string)
            session.setopt(pycurl.POST, True)
            headers.append('Sign: %s' % sign)
            headers.append('Key: %s' % self.APIKey)

        # Apply the settings
        buff = BytesIO()
        session.setopt(pycurl.HTTPHEADER, headers)
        session.setopt(pycurl.URL, url)
        session.setopt(pycurl.WRITEDATA, buff)
        session.perform()

        # Handle the response
        json_ret = json.loads(buff.getvalue())
        if must_process:
            return self.post_process(json_ret)
        return json_ret

    def return_ticker(self):
        return self.api_query(
            "get",
            "returnTicker"
        )

    def return_24volume(self):
        return self.api_query(
            "get",
            "return24Volume"
        )

    def return_order_book(self, currency_pair, depth=1):
        return self.api_query(
            "get",
            "returnOrderBook",
            {
                'currency_pair': currency_pair,
                'depth': '%d' % depth
            }
        )

    def return_market_trade_history(self, currency_pair):
        return self.api_query(
            "get",
            "returnTradeHistory",
            {
                'currency_pair': currency_pair
            }
        )

    def return_chart_data(self, currency_pair, start, end):
        return self.api_query(
            "get",
            "returnChartData",
            {
                'currency_pair': currency_pair,
                'start': start,
                'end': end
            }
        )

    def return_currencies(self):
        return self.api_query("get", "returnCurrencies")

    def return_loan_orders(self):
        return self.api_query("get", "returnLoadOrders")

    # Returns all of your balances.
    # Outputs:
    # {"BTC":"0.59098578","LTC":"3.31117268", ... }
    def return_balances(self):
        return self.api_query(
            'post',
            'returnBalances'
        )

    # Returns your open orders for a given market, specified by the "currency_pair" POST parameter, e.g. "BTC_XCP"
    # Inputs:
    # currency_pair  The currency pair e.g. "BTC_XCP"
    # Outputs:
    # order_number   The order number
    # type          sell or buy
    # rate          Price the order is selling or buying at
    # Amount        Quantity of order
    # total         Total value of order (price * quantity)
    def return_open_orders(self, currency_pair):
        return self.api_query(
            'post',
            'returnOpenOrders',
            {
                "currency_pair": currency_pair
            }
        )

    # Returns your trade history for a given market, specified by the "currency_pair" POST parameter
    # Inputs:
    # currency_pair  The currency pair e.g. "BTC_XCP"
    # Outputs:
    # date          Date in the form: "2014-02-19 03:44:59"
    # rate          Price the order is selling or buying at
    # amount        Quantity of order
    # total         Total value of order (price * quantity)
    # type          sell or buy
    def return_trade_history(self, currency_pair):
        return self.api_query(
            'post',
            'returnTradeHistory',
            {
                "currency_pair": currency_pair
            }
        )

    # Places a buy order in a given market. Required POST parameters are "currency_pair", "rate", and "amount". If successful, the method will return the order number.
    # Inputs:
    # currency_pair  The currency pair
    # rate          price the order is buying at
    # amount        Amount of coins to buy
    # Outputs:
    # order_number   The order number
    def buy(self, currency_pair, rate, amount):
        return self.api_query(
            'post',
            'buy',
            {
                "currency_pair": currency_pair,
                "rate": rate,
                "amount": amount
            }
        )

    # Places a sell order in a given market. Required POST parameters are "currency_pair", "rate", and "amount". If successful, the method will return the order number.
    # Inputs:
    # currency_pair  The currency pair
    # rate          price the order is selling at
    # amount        Amount of coins to sell
    # Outputs:
    # order_number   The order number
    def sell(self, currency_pair, rate, amount):
        return self.api_query(
            'post',
            'sell',
            {
                "currency_pair": currency_pair,
                "rate": rate,
                "amount": amount
            }
        )

    # Cancels an order you have placed in a given market. Required POST parameters are "currency_pair" and "order_number".
    # Inputs:
    # currency_pair  The currency pair
    # order_number   The order number to cancel
    # Outputs:
    # succes        1 or 0
    def cancel(self, currency_pair, order_number):
        return self.api_query(
            'post',
            'cancelOrder',
            {
                "currency_pair": currency_pair,
                "order_number": order_number
            }
        )

    # Immediately places a withdrawal for a given currency, with no email confirmation. In order to use this method, the withdrawal privilege must be enabled for your API key. Required POST parameters are "currency", "amount", and "address". Sample output: {"response":"Withdrew 2398 NXT."}
    # Inputs:
    # currency      The currency to withdraw
    # amount        The amount of this coin to withdraw
    # address       The withdrawal address
    # Outputs:
    # response      Text containing message about the withdrawal
    def withdraw(self, currency, amount, address):
        return self.api_query(
            'post',
            'withdraw',
            {
                "currency": currency,
                "amount": amount,
                "address": address
            }
        )


import random
import numpy as np
import tensorflow as tf
import utils

class GraphEmbedding(tf.keras.models.Model):

    def __init__(self, num_graphs, num_features):
        super(GraphEmbedding, self).__init__()
        self.num_graphs = num_graphs
        self.num_features = num_features
        self.embeds = [
            self.add_weight(name=('graph_embed_%d'%i), shape=[self.num_features], initializer='zeros')
            for i in range(self.num_graphs)]

    def get_numpy(self):
        return np.array([embed.numpy() for embed in self.embeds])

    def dump_to_csv(self, csv_file, _):
        with open(csv_file, 'w') as f:
            for embed in self.embeds:
                f.write('\t'.join(map(str, embed.numpy().tolist()))+'\n')

    def get_embeddings_from_indices(self, _, indices):
        return self.get_weights_from_indices(indices)

    def get_weights_from_indices(self, indices):
        return [self.embeds[index] for index in indices]

    def call(self, indices):
        return tf.stack(self.get_weights_from_indices(indices))

def get_dense_batch(wl_embedder, graph_inputs, k):
    vocab_size = wl_embedder.vocab_size()
    graph_indexes = random.sample(list(range(len(graph_inputs[0]))), k+1)
    graph_lengths = [int(graph_inputs[0][index].shape[0])*vocab_size for index in graph_indexes]
    nodes_tensor = []
    labels = []
    for i, index in enumerate(graph_indexes):
        node_embeds = wl_embedder(utils.dispatch(graph_inputs, index))
        before, now, after = sum(graph_lengths[:i]), graph_lengths[i], sum(graph_lengths[i+1:])
        graph_indicator = before*[0.] + now*[1.] + after*[0.]
        labels.append(graph_indicator)
        nodes_tensor += node_embeds
    nodes_tensor = tf.concat(nodes_tensor, axis=0)
    labels = tf.constant(labels, dtype=tf.float32)
    return nodes_tensor, graph_indexes, labels

def get_updated_metric(metric, labels, similarity, _):
    labels = tf.reshape(labels, [-1])
    similarity = tf.nn.sigmoid(tf.reshape(similarity, [-1]))
    metric.update_state(labels, similarity)
    return metric.result().numpy()

def train_epoch(wl_embedder, graph_embedder,
                graph_inputs,
                k, num_batchs, lbda, lr):
    optimizer_G = tf.keras.optimizers.Adam(lr)
    optimizer_WL = tf.keras.optimizers.Adam(lr)
    progbar = tf.keras.utils.Progbar(num_batchs)
    metric = tf.keras.metrics.BinaryAccuracy()
    for step in range(num_batchs):
        with tf.GradientTape() as tape:
            nodes_tensor, graph_indexes, labels = get_dense_batch(
                wl_embedder, graph_inputs, k)
            graph_embeds = graph_embedder.get_embeddings_from_indices(graph_inputs, graph_indexes)
            graph_embeds = tf.stack(graph_embeds)
            similarity = tf.einsum('if,jf->ij', graph_embeds, nodes_tensor)
            loss = tf.nn.weighted_cross_entropy_with_logits(labels, similarity, lbda*float(k))
        g_weights = graph_embedder.get_weights_from_indices(graph_indexes)
        wl_weights = wl_embedder.trainable_variables
        dG, dWL = tape.gradient(loss, [g_weights, wl_weights])
        optimizer_G.apply_gradients(zip(dG, g_weights))
        optimizer_WL.apply_gradients(zip(dWL, wl_weights))
        acc = get_updated_metric(metric, labels, similarity, k)
        progbar.update(step+1, [('loss', float(loss.numpy().mean())), ('acc', acc)])


import dataclasses
import importlib
import json
import re

import aws_cdk as cdk

from infra.stacks.lambda_stack import LambdaStack

with open("cdk.json", "r") as json_file:
    context = json.load(json_file)["context"]
    arns = context["dev"]["arns"]

services = LambdaStack(
    cdk.App(),
    "Dev",
    arns,
    alarms=False,
).services

functions = services.aws_lambda.functions
api_endpoints = services.api_gateway.endpoints

endpoints = []

for function in functions:
    function_name = function["name"]
    if function_name in api_endpoints:
        endpoint = api_endpoints[function_name]["endpoint"]
        method = api_endpoints[function_name]["method"]
        merged_obj = {
            "file_path": function["file_path"],
            "name": function_name,
            "description": function["description"],
            "endpoint": endpoint,
            "method": method,
        }
        endpoints.append(merged_obj)

def extract_path_parameters(endpoint):
    pattern = r"\{(.*?)\}"
    matches = re.findall(pattern, endpoint)
    return matches

schemas = []
paths = {endpoint["endpoint"]: {} for endpoint in endpoints}
for endpoint in endpoints:
    file_path = (
        endpoint["file_path"]
        .replace(".", "/")[2:]
        .replace("/", ".")
        .replace(".lambda_handler", "")
    )
    function_file = importlib.import_module(file_path)

    if "{" in endpoint["endpoint"] and "}" in endpoint["endpoint"]:
        try:
            path = function_file.Path
        except AttributeError:
            raise Exception(f"Path is missing on {file_path.replace('.', '/')}")

        if not dataclasses.is_dataclass(path):
            raise Exception(f"Path is not a dataclass on {file_path.replace('.', '/')}")

        paths = extract_path_parameters(endpoint["endpoint"])
        typed_args = list(path.__dataclass_fields__.keys())
        for path in paths:
            if path not in typed_args:
                raise Exception(
                    f"Path parameter {path} is missing in Path on {file_path.replace('.', '/')}"
                )

    try:
        input_ = function_file.Input
    except AttributeError:
        raise Exception(f"Input is missing on {file_path.replace('.', '/')}")

    try:
        output = function_file.Output
    except AttributeError:
        raise Exception(f"Output is missing on {file_path.replace('.', '/')}")

    if not dataclasses.is_dataclass(input_):
        raise Exception(f"Input is not a dataclass on {file_path.replace('.', '/')}")

    if not dataclasses.is_dataclass(output):
        raise Exception(f"Output is not a dataclass on {file_path.replace('.', '/')}")


from utils import *

def augment(line):
    return_list = list(map(float, line.rstrip("\n").split(",")))
    output = return_list.pop()
    inputs = return_list
    average = sum(inputs) / len(inputs)
    variance = sum([(i-average)**2 for i in inputs]) / len(inputs)
    inputs = [i/variance for i in inputs]

    return ','.join(map(str, inputs+[output])) + "\n"

def main():
    for name in sorted(os.listdir(PRE)):
        with open(PRE+name, "r") as file:
            data = [line for line in file]
        data.pop(0)
        try:
            data = [augment(line) for line in data]
        except ZeroDivisionError:
            print(name)
        with open(AUG+name, "w") as file:
            file.write(','.join([f"{i}_augmented" for i in range(LEN, 0, -1)] + ["target"]) + '\n')
            file.writelines(data)

if __name__ == "__main__":
    main()


#!/usr/bin/env python3

import subprocess
import sys
import os
import argparse
import yaml
import asyncio
import shutil
import re
from typing import List, Dict, Any, Optional

REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

class col:
    HEADER = "\033[95m"
    BLUE = "\033[94m"
    GREEN = "\033[92m"
    YELLOW = "\033[93m"
    RED = "\033[91m"
    RESET = "\033[0m"
    BOLD = "\033[1m"
    UNDERLINE = "\033[4m"

def color(the_color: str, text: str) -> str:
    return col.BOLD + the_color + str(text) + col.RESET

def cprint(the_color: str, text: str) -> None:
    if hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
        print(color(the_color, text))
    else:
        print(text)

def git(args: List[str]) -> List[str]:
    p = subprocess.run(
        ["git"] + args,
        cwd=REPO_ROOT,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        check=True,
    )
    lines = p.stdout.decode().strip().split("\n")
    return [line.strip() for line in lines]

def find_changed_files() -> List[str]:
    untracked = []

    for line in git(["status", "--porcelain"]):
        # Untracked files start with ??, so grab all of those
        if line.startswith("?? "):
            untracked.append(line.replace("?? ", ""))

    # Modified, unstaged
    modified = git(["diff", "--name-only"])

    # Modified, staged
    cached = git(["diff", "--cached", "--name-only"])

    # Committed
    merge_base = git(["merge-base", "origin/master", "HEAD"])[0]
    diff_with_origin = git(["diff", "--name-only", merge_base, "HEAD"])

    # De-duplicate
    all_files = set(untracked + cached + modified + diff_with_origin)
    return [x.strip() for x in all_files if x.strip() != ""]

async def run_step(step: Dict[str, Any], job_name: str, files: Optional[List[str]], quiet: bool) -> bool:
    env = os.environ.copy()
    env["GITHUB_WORKSPACE"] = "/tmp"
    if files is None:
        env["LOCAL_FILES"] = ""
    else:
        env["LOCAL_FILES"] = " ".join(files)
    script = step["run"]

    PASS = color(col.GREEN, '\N{check mark}')
    FAIL = color(col.RED, 'x')

    if quiet:
        # TODO: Either lint that GHA scripts only use 'set -eux' or make this more
        # resilient
        script = script.replace("set -eux", "set -eu")
        script = re.sub(r"^time ", "", script, flags=re.MULTILINE)
    name = f'{job_name}: {step["name"]}'

    def header(passed: bool) -> None:
        icon = PASS if passed else FAIL
        print(f"{icon} {color(col.BLUE, name)}")

    try:
        proc = await asyncio.create_subprocess_shell(
            script,
            shell=True,
            cwd=REPO_ROOT,
            env=env,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            executable=shutil.which("bash"),
        )

        stdout_bytes, stderr_bytes = await proc.communicate()

        header(passed=proc.returncode == 0)
    except Exception as e:
        header(passed=False)
        print(e)
        return False

    stdout = stdout_bytes.decode().strip()
    stderr = stderr_bytes.decode().strip()

    if stderr != "":
        print(stderr)
    if stdout != "":
        print(stdout)

    return proc.returncode == 0

async def run_steps(steps: List[Dict[str, Any]], job_name: str, files: Optional[List[str]], quiet: bool) -> None:
    coros = [run_step(step, job_name, files, quiet) for step in steps]
    await asyncio.gather(*coros)

def grab_specific_steps(steps_to_grab: List[str], job: Dict[str, Any]) -> List[Dict[str, Any]]:
    relevant_steps = []
    for step in steps_to_grab:
        for actual_step in job["steps"]:
            if actual_step["name"].lower().strip() == step.lower().strip():
                relevant_steps.append(actual_step)
                break

    if len(relevant_steps) != len(steps_to_grab):
        raise RuntimeError("Missing steps")

    return relevant_steps

def grab_all_steps_after(last_step: str, job: Dict[str, Any]) -> List[Dict[str, Any]]:
    relevant_steps = []

    found = False
    for step in job["steps"]:
        if found:
            relevant_steps.append(step)
        if step["name"].lower().strip() == last_step.lower().strip():
            found = True

    return relevant_steps

def main() -> None:
    parser = argparse.ArgumentParser(
        description="Pull shell scripts out of GitHub actions and run them"
    )
    parser.add_argument("--file", help="YAML file with actions", required=True)
    parser.add_argument("--file-filter", help="only pass through files with this extension", default='')
    parser.add_argument("--changed-only", help="only run on changed files", action='store_true', default=False)
    parser.add_argument("--job", help="job name", required=True)
    parser.add_argument("--no-quiet", help="output commands", action='store_true', default=False)
    parser.add_argument("--step", action="append", help="steps to run (in order)")
    parser.add_argument(
        "--all-steps-after", help="include every step after this one (non inclusive)"
    )
    args = parser.parse_args()

    relevant_files = None
    quiet = not args.no_quiet

    if args.changed_only:
        changed_files: Optional[List[str]] = None
        try:
            changed_files = find_changed_files()
        except Exception:
            # If the git commands failed for some reason, bail out and use the whole list
            print(
                "Could not query git for changed files, falling back to testing all files instead",
                file=sys.stderr
            )
        if changed_files is not None:
            relevant_files = []
            for f in changed_files:
                for file_filter in args.file_filter:
                    if f.endswith(file_filter):
                        relevant_files.append(f)
                        break

    if args.step is None and args.all_steps_after is None:
        raise RuntimeError("1+ --steps or --all-steps-after must be provided")

    if args.step is not None and args.all_steps_after is not None:
        raise RuntimeError("Only one of --step and --all-steps-after can be used")

    action = yaml.safe_load(open(args.file, "r"))
    if "jobs" not in action:
        raise RuntimeError(f"top level key 'jobs' not found in {args.file}")
    jobs = action["jobs"]

    if args.job not in jobs:
        raise RuntimeError(f"job '{args.job}' not found in {args.file}")

    job = jobs[args.job]

    if args.step is not None:
        relevant_steps = grab_specific_steps(args.step, job)
    else:
        relevant_steps = grab_all_steps_after(args.all_steps_after, job)

    if sys.version_info > (3, 7):
        loop = asyncio.get_event_loop()
        loop.run_until_complete(run_steps(relevant_steps, args.job, relevant_files, quiet))
    else:
        raise RuntimeError("Only Python >3.7 is supported")

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        pass


from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import ListView, DetailView, CreateView
from .models import Products

class ShowByCategory(ListView):
    model = Products
    template_name = 'Products/show_by_category.html'
    context_object_name = 'products'
    allow_empty = False

    def get_queryset(self):
        return Products.objects.filter(category__slug=self.kwargs['slug'], is_published=True).select_related('category')

class ShowProduct(DetailView):
    model = Products
    template_name = 'Products/show_product.html'
    context_object_name = 'product'

    def get_queryset(self):
        return Products.objects.filter(slug=self.kwargs['slug'])

def show_product(request, slug):
    pr = Products.objects.filter(slug=slug)
    return render(request, 'Products/show_product.html', {'products': pr})


import pygame
from environment import screenWidth, screenHeight
from environment import snakeSize, snakeInitialVelocity, snakeVelocityIncrement

class Snake(pygame.sprite.Sprite):
    size = snakeSize
    initialVelocity = snakeInitialVelocity

    def __init__(self):
        super().__init__()
        self.x = screenWidth / 2
        self.y = screenHeight / 2

        self.head = [self.x, self.y]
        self.list = []
        self.length = 1

        self.velocityX = 0
        self.velocityY = 0

    def handleDirection(self, eventKey: int):
        if eventKey == pygame.K_UP:
            self.velocityX = 0
            self.velocityY = -Snake.initialVelocity
        elif eventKey == pygame.K_RIGHT:
            self.velocityX = Snake.initialVelocity
            self.velocityY = 0
        elif eventKey == pygame.K_DOWN:
            self.velocityX = 0
            self.velocityY = Snake.initialVelocity
        elif eventKey == pygame.K_LEFT:
            self.velocityX = -Snake.initialVelocity
            self.velocityY = 0

    def slither(self):
        self.x += self.velocityX
        self.y += self.velocityY

        self.head = [self.x, self.y]
        self.list.append(self.head)

        if len(self.list) > self.length:
            self.list.pop(0)

    def handleFoodEaten(self, increment: int = 7):
        self.length += increment
        Snake.initialVelocity += snakeVelocityIncrement


# Tim Momose, October 2014

# ----------------------------------------------------------------------
#  Imports
# ----------------------------------------------------------------------
import scipy
import numpy as np
from copy import deepcopy
# SUAVE Imports
from SUAVE.Core import Data, Data_Exception, Data_Warning
#from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Drag.parasite_drag_aircraft import parasite_drag_aircraft
# SUAVE-AVL Imports
from .Data.Inputs   import Inputs
from .Data.Wing     import Wing, Section, Control_Surface
from .Data.Body     import Body
from .Data.Aircraft import Aircraft
from .Data.Cases    import Run_Case
from .Data.Configuration import Configuration

def create_avl_datastructure(geometry,conditions):

	avl_aircraft      = translate_avl_geometry(geometry)
	avl_configuration = translate_avl_configuration(geometry,conditions)
	avl_cases         = translate_avl_cases(conditions,settings.run_cases)
	#avl_cases         = setup_test_cases(conditions)

	# pack results in a new AVL inputs structure
	avl_inputs = Inputs()
	avl_inputs.aircraft      = avl_aircraft
	avl_inputs.configuration = avl_configuration
	avl_inputs.cases         = avl_cases
	return avl_inputs

def translate_avl_geometry(geometry):

	aircraft = Aircraft()
	aircraft.tag = geometry.tag

	# FOR NOW, ASSUMING THAT CONTROL SURFACES ARE NOT ALIGNED WITH WING SECTIONS (IN THIS CASE, ROOT AND TIP SECTIONS)
	for wing in geometry.wings:
		w = translate_avl_wing(wing)
		aircraft.append_wing(w)

	for body in geometry.fuselages:
		b = translate_avl_body(body)
		aircraft.append_body(b)

	return aircraft

def translate_avl_wing(suave_wing):

	w = Wing()
	w.tag       = suave_wing.tag
	w.symmetric = suave_wing.symmetric
	w.vertical  = suave_wing.vertical
	w.sweep     = suave_wing.sweep
	w.dihedral  = suave_wing.dihedral
	w = populate_wing_sections(w,suave_wing)

	return w

def translate_avl_body(suave_body):

	b = Body()
	b.tag       = suave_body.tag
	b.symmetric = True #body.symmetric
	b.lengths.total = suave_body.lengths.total
	b.lengths.nose  = suave_body.lengths.nose
	b.lengths.tail  = suave_body.lengths.tail
	b.widths.maximum = suave_body.width
	b.heights.maximum = suave_body.heights.maximum
	b = populate_body_sections(b,suave_body)

	return b

def populate_wing_sections(avl_wing,suave_wing):
	symm     = avl_wing.symmetric
	sweep    = avl_wing.sweep
	dihedral = avl_wing.dihedral
	span     = suave_wing.spans.projected
	semispan = suave_wing.spans.projected * 0.5 * (2 - symm)
	origin   = suave_wing.origin
	root_section = Section()
	root_section.tag    = 'root_section'
	root_section.origin = origin
	root_section.chord  = suave_wing.chords.root
	root_section.twist  = suave_wing.twists.root

	tip_section = Section()
	tip_section.tag  = 'tip_section'
	tip_section.chord = suave_wing.chords.tip
	tip_section.twist = suave_wing.twists.tip
	tip_section.origin = [origin[0]+semispan*np.tan(sweep),origin[1]+semispan,origin[2]+semispan*np.tan(dihedral)]

	if avl_wing.vertical:
		temp = tip_section.origin[2]
		tip_section.origin[2] = tip_section.origin[1]
		tip_section.origin[1] = temp

	avl_wing.append_section(root_section)
	avl_wing.append_section(tip_section)

	if suave_wing.control_surfaces:
		for ctrl in suave_wing.control_surfaces:
			num = 1
			for section in ctrl.sections:
				semispan_fraction = (span/semispan) * section.origins.span_fraction
				s = Section()
				s.chord  = scipy.interp(semispan_fraction,[0.,1.],[root_section.chord,tip_section.chord])
				s.tag    = '{0}_section{1}'.format(ctrl.tag,num)
				s.origin = section.origins.dimensional
				s.origin[0] = s.origin[0] - s.chord*section.origins.chord_fraction
				s.twist  = scipy.interp(semispan_fraction,[0.,1.],[root_section.twist,tip_section.twist])
				c = Control_Surface()
				c.tag     = ctrl.tag
				c.x_hinge = 1. - section.chord_fraction
				c.sign_duplicate = ctrl.deflection_symmetry

				s.append_control_surface(c)
				avl_wing.append_section(s)
				num += 1

	return avl_wing

def populate_body_sections(avl_body,suave_body):

	symm = avl_body.symmetric
	semispan_h = avl_body.widths.maximum * 0.5 * (2 - symm)
	semispan_v = avl_body.heights.maximum * 0.5
	origin = suave_body.origin
	root_section = Section()
	root_section.tag    = 'center_horizontal_section'
	root_section.origin = origin
	root_section.chord  = avl_body.lengths.total

	tip_section = Section()
	tip_section.tag  = 'outer_horizontal_section'
	nl = avl_body.lengths.nose
	tl = avl_body.lengths.tail
	tip_section.origin = [origin[0]+nl,origin[1]+semispan_h,origin[2]]
	tip_section.chord = root_section.chord - nl - tl

	avl_body.append_section(root_section,'horizontal')
	avl_body.append_section(tip_section,'horizontal')
	tip_sectionv1 = deepcopy(tip_section)
	tip_sectionv1.origin[1] = origin[1]
	tip_sectionv1.origin[2] = origin[2] - semispan_v
	tip_sectionv1.tag       = 'lower_vertical_section'
	avl_body.append_section(tip_sectionv1,'vertical')
	avl_body.append_section(root_section,'vertical')
	tip_sectionv2 = deepcopy(tip_section)
	tip_sectionv2.origin[1] = origin[1]
	tip_sectionv2.origin[2] = origin[2] + semispan_v
	tip_sectionv2.tag       = 'upper_vertical_section'
	avl_body.append_section(tip_sectionv2,'vertical')

	return avl_body

def translate_avl_configuration(geometry,conditions):

	config = Configuration()
	config.reference_values.sref = geometry.reference_area
	config.reference_values.bref = geometry.wings['Main Wing'].spans.projected
	config.reference_values.cref = geometry.wings['Main Wing'].chords.mean_aerodynamic
	config.reference_values.cg_coords = geometry.mass_properties.center_of_gravity

	#config.parasite_drag = 0.0177#parasite_drag_aircraft(conditions,configuration,geometry)

	config.mass_properties.mass = geometry.mass_properties.max_takeoff ###
	moment_tensor = geometry.mass_properties.moments_of_inertia.tensor
	config.mass_properties.inertial.Ixx = moment_tensor[0][0]
	config.mass_properties.inertial.Iyy = moment_tensor[1][1]
	config.mass_properties.inertial.Izz = moment_tensor[2][2]
	config.mass_properties.inertial.Ixy = moment_tensor[0][1]
	config.mass_properties.inertial.Iyz = moment_tensor[1][2]
	config.mass_properties.inertial.Izx = moment_tensor[2][0]

	#No Iysym, Izsym assumed for now

	return config

def translate_avl_cases(conditions,suave_cases):

	runcases = Run_Case.Container()

	for case in suave_cases:
		kase = Run_Case()
		kase.tag = case.tag
		kase.conditions.mach  = case.conditions.freestream.mach
		kase.conditions.v_inf = case.conditions.freestream.velocity
		kase.conditions.rho   = case.conditions.freestream.density
		kase.conditions.g     = case.conditions.freestream.gravitational_acceleration
		kase.angles.alpha     = case.conditions.aerodynamics.angle_of_attack
		kase.angles.beta      = case.conditions.aerodynamics.side_slip_angle
		kase.parasite_drag    = case.conditions.aerodynamics.parasite_drag

		for deflect in case.conditions.stability_and_control.control_surface_deflections:
			kase.append_control_deflection(deflect.tag,deflect.magnitude)

		runcases.append_case(case)

	return runcases

def setup_test_cases(conditions):

	runcases = Run_Case.Container()

	alphas = [-10,-5,-2,0,2,5,10,20]
	mach   = conditions.freestream.mach
	v_inf  = conditions.freestream.velocity
	rho    = conditions.density
	g      = conditions.g
	for alpha in alphas:
		case = Run_Case()
		case.tag = 'Alpha={}'.format(alpha)
		case.conditions.mach  = mach
		case.conditions.v_inf = v_inf
		case.conditions.rho   = rho
		case.conditions.gravitation_acc = g
		case.angles.alpha     = alpha
		runcases.append_case(case)

	return runcases


from collections import OrderedDict
import yaml

def get_configs(dataset):
    data = yaml.load(open('dataset_cfg.yaml'))
    return data[dataset]

def accuracy(output, target, topk=(1,)):
    """Computes the precision@k for the specified values of k"""
    maxk = max(topk)
    batch_size = target.size(0)
    _, pred = output.topk(maxk, 1, True, True)
    pred = pred.t()
    correct = pred.eq(target.view(1, -1).expand_as(pred))

    res = []
    for k in topk:
        correct_k = correct[:k].view(-1).float().sum(0)
        res.append(correct_k.mul_(100.0 / batch_size))
    return res

class AverageMeter(object):
    """Computes and stores the average and current value"""

    def __init__(self):
        self.reset()

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=0):
        self.val = val
        self.sum += val * n
        self.count += n
        self.avg = self.sum / (.0001 + self.count)

    def __str__(self):
        """String representation for logging
        """
        # for values that should be recorded exactly e.g. iteration number
        if self.count == 0:
            return str(self.val)
        # for stats
        return '%.4f (%.4f)' % (self.val, self.avg)

class LogCollector(object):
    """A collection of logging objects that can change from train to val"""

    def __init__(self):
        # to keep the order of logged variables deterministic
        self.meters = OrderedDict()

    def update(self, k, v, n=0):
        # create a new meter if previously not recorded
        if k not in self.meters:
            self.meters[k] = AverageMeter()
        self.meters[k].update(v, n)

    def __str__(self):
        """Concatenate the meters in one log line
        """
        s = ''
        for i, (k, v) in enumerate(iter(self.meters.items())):
            if i > 0:
                s += '  '
            s += k + ' ' + str(v)
        return s

    def tb_log(self, tb_logger, prefix='', step=None):
        """Log using tensorboard
        """
        for k,v in iter(self.meters.items()):
            tb_logger.log_value(prefix + k, v.val, step=step)


# cook your dish here
for _ in range(int(input())):
    n=int(input())
    li=list(map(int,input().split()))
    li.sort()
    x=li[1]-li[0]
    for i in range(n-1):
        if (li[i]==li[i+1]):
            print(li[i])
            break
    else:
        if x!=1:
            print(li[0])
        else:
            print(li[-1])


import sys

sys.path.append("./")
from pypde import *
from pypde.plot import *

try:
    from rbc2d_base import NavierStokesBase
    from rbc2d import NavierStokes
except:
    from .rbc2d_base import NavierStokesBase
    from .rbc2d import NavierStokes

class NavierStokesAdjoint(NavierStokesBase, Integrator):
    """
    CONFIG={
        "shape": (50,50),
        "kappa": 1.0,
        "nu": 1.0,
        "dt": 0.2,
        "ndim": 2,
        "tsave": 0.1,
        "dealias": True,
        "integrator": "eu",
        "beta": 1.0,
        "Lx": 1.0,
    }
    """

    avail_cases = ["rbc", "linear", "zero"]

    def __init__(self, case="rbc", **kwargs):

        if case not in self.avail_cases:
            raise ValueError("Specified case is not available: ", self.avail_cases)
        else:
            self.case = case

        Integrator.__init__(self)
        NavierStokesBase.__init__(self, **kwargs)

        if self.case == "rbc":
            side = "CN"
        else:
            side = "CD"

        # Initialize underlying NavierStokes Solver
        self.NS = NavierStokes(case=case, **self.CONFIG)

        # Space for Fields
        self.T = Field(
            [
                Base(self.shape[0], side, dealias=3 / 2),
                Base(self.shape[1], "CD", dealias=3 / 2),
            ]
        )
        self.U = Field(
            [
                Base(self.shape[0], "CD", dealias=3 / 2),
                Base(self.shape[1], "CD", dealias=3 / 2),
            ]
        )
        self.V = Field(
            [
                Base(self.shape[0], "CD", dealias=3 / 2),
                Base(self.shape[1], "CD", dealias=3 / 2),
            ]
        )
        self.P = Field([Base(self.shape[0], "CN"), Base(self.shape[1], "CN")])

        # Additional pressure field
        self.pres = Field([Base(self.shape[0], "CH"), Base(self.shape[1], "CH")])

        # Store list of fields for collective saving and time update
        self.field = MultiField(
            [self.T, self.U, self.V], ["temp", "ux", "uy"]
        )

        # Space for Adjoint Fields
        self.TA = Field(
            [
                Base(self.shape[0], side, dealias=3 / 2),
                Base(self.shape[1], "CD", dealias=3 / 2),
            ]
        )
        self.UA = Field(
            [
                Base(self.shape[0], "CD", dealias=3 / 2),
                Base(self.shape[1], "CD", dealias=3 / 2),
            ]
        )
        self.VA = Field(
            [
                Base(self.shape[0], "CD", dealias=3 / 2),
                Base(self.shape[1], "CD", dealias=3 / 2),
            ]
        )

        # Setup Solver solverplans
        self.setup_solver()

        # Setup Temperature field and bcs
        # self.set_temperature()
        self.Tbc = self.NS.Tbc
        self.Tbc.backward()

        # Array for rhs's
        self.rhs = np.zeros(self.shape)

        # Temperature BC in physical space
        self.deriv_field.vhat[:] = galerkin_to_cheby(self.NS.Tbc.vhat, self.NS.Tbc)
        if self.dealias:
            self.temp_bc = self.deriv_field.dealias.backward(self.deriv_field.vhat)
        else:
            self.temp_bc = self.deriv_field.backward(self.deriv_field.vhat)

    def reset_time(self):
        self.time = 0.0
        for field in self.field.fields:
            field.time = 0.0

    def set_temperature(self, amplitude=0.5):
        self.T.v = (
            amplitude * np.sin(0.5 * np.pi * self.xx) * np.cos(0.5 * np.pi * self.yy)
        )
        self.T.forward()

    def setup_solver(self):
        from pypde.templates.poisson import solverplan_poisson2d

        # Time step coefficients
        self.a = self.NS.a
        self.b = self.NS.b
        self.c = self.NS.c
        self.nstage = self.NS.nstage

        # Solver Plans
        self.solver_P = self.NS.solver_P

        # Plans to smooth fields
        self.nabla_U = solverplan_poisson2d(self.U.xs, singular=False, scale=self.scale)
        self.nabla_V = solverplan_poisson2d(self.V.xs, singular=False, scale=self.scale)
        self.nabla_T = solverplan_poisson2d(self.T.xs, singular=False, scale=self.scale)

    def save(self):
        self.T.save()
        self.P.save()
        self.U.save()
        self.V.save()

    def conv(self, field, u, deriv):
        return conv_term(
            field,
            u,
            deriv=deriv,
            deriv_field=self.deriv_field,
            dealias=self.dealias,
            scale=self.scale,
        )

    def conv_term_adj_ux(self, fieldx, fieldz, fieldT, ux, uz, temp, add_bc=None):

        conv = self.conv(fieldx, ux, deriv=(1, 0))

        conv += self.conv(fieldz, uz, deriv=(1, 0))

        conv += self.conv(fieldT, temp, deriv=(1, 0))

        conv += self.conv(fieldT, self.temp_bc, deriv=(1, 0))

        if self.dealias:
            return self.deriv_field.dealias.forward(conv)
        return self.deriv_field.forward(conv)

    def conv_term_adj_uz(self, fieldx, fieldz, fieldT, ux, uz, temp, add_bc=None):
        conv = self.conv(fieldx, ux, deriv=(0, 1))

        conv += self.conv(fieldz, uz, deriv=(0, 1))

        conv += self.conv(fieldT, temp, deriv=(0, 1))

        conv += self.conv(fieldT, self.temp_bc, deriv=(0, 1))

        if self.dealias:
            return self.deriv_field.dealias.forward(conv)
        return self.deriv_field.forward(conv)

    def update_NS(self):
        # -- Calculate Residual of Navier-Stokes
        self.NS.U.vhat[:] = self.U.vhat[:]
        self.NS.V.vhat[:] = self.V.vhat[:]
        self.NS.T.vhat[:] = self.T.vhat[:]
        self.NS.update()
        self.NS.U.vhat[:] = (self.NS.U.vhat[:] - self.U.vhat[:]) / self.dt
        self.NS.V.vhat[:] = (self.NS.V.vhat[:] - self.V.vhat[:]) / self.dt
        self.NS.T.vhat[:] = (self.NS.T.vhat[:] - self.T.vhat[:]) / self.dt

        # -- Smooth fields (nabla^2 TA = T)
        rhs = self.nabla_U.solve_rhs(galerkin_to_cheby(self.NS.U.vhat, self.NS.U))
        self.UA.vhat[:] = self.nabla_U.solve_lhs(rhs) / self.nu
        rhs = self.nabla_V.solve_rhs(galerkin_to_cheby(self.NS.V.vhat, self.NS.V))
        self.VA.vhat[:] = self.nabla_V.solve_lhs(rhs) / self.nu
        rhs = self.nabla_T.solve_rhs(galerkin_to_cheby(self.NS.T.vhat, self.NS.T))
        self.TA.vhat[:] = self.nabla_T.solve_lhs(rhs) / self.kappa

    def update_U(self, stage):
        self.rhs[:] = 0.0

        # Pressure term
        dpdx = self.grad(self.pres, deriv=(1, 0))
        self.rhs -= self.a[stage] * dpdx

        # Non-Linear Convection
        self.rhs += self.b[stage] * self.NS.conv_term(self.UA, self.ux, self.uz)
        self.rhs += self.b[stage] * self.conv_term_adj_ux(
            self.UA, self.VA, self.TA, self.ux, self.uz, self.temp
        )
        if self.c[stage] != 0:
            self.rhs += self.c[stage] * self.NS.conv_term(
                self.UA, self.ux_old, self.uz_old
            )
            self.rhs += self.c[stage] * self.conv_term_adj_ux(
                self.UA, self.VA, self.TA, self.ux_old, self.uz_old, self.temp_old
            )

        # Diffusion
        self.rhs += self.a[stage] * galerkin_to_cheby(self.NS.U.vhat, self.U)
        # self.rhs += self.a[stage] * self.nu * galerkin_to_cheby(self.NS.U.vhat, self.U)

        # Update
        self.U.vhat[:] += self.dt * cheby_to_galerkin(self.rhs, self.U)

    def update_V(self, stage):
        self.rhs[:] = 0.0

        # Pressure term
        dpdz = self.grad(self.pres, deriv=(0, 1))
        self.rhs -= self.a[stage] * dpdz

        # Non-Linear Convection
        self.rhs += self.b[stage] * self.NS.conv_term(self.VA, self.ux, self.uz)
        self.rhs += self.b[stage] * self.conv_term_adj_uz(
            self.UA, self.VA, self.TA, self.ux, self.uz, self.temp
        )
        if self.c[stage] != 0:
            self.rhs += self.c[stage] * self.NS.conv_term(
                self.VA, self.ux_old, self.uz_old
            )
            self.rhs += self.c[stage] * self.conv_term_adj_uz(
                self.UA, self.VA, self.TA, self.ux_old, self.uz_old, self.temp_old
            )

        # Diffusion
        # self.rhs += self.a[stage] * self.nu * galerkin_to_cheby(self.NS.V.vhat, self.V)
        self.rhs += self.a[stage] * galerkin_to_cheby(self.NS.V.vhat, self.V)

        # Update
        self.V.vhat[:] += self.dt * cheby_to_galerkin(self.rhs, self.V)

    def update_T(self, stage):
        self.rhs[:] = 0.0

        # Non-Linear Convection
        self.rhs += self.b[stage] * self.NS.conv_term(self.TA, self.ux, self.uz)
        if self.c[stage] != 0:
            self.rhs += self.c[stage] * self.NS.conv_term(
                self.TA, self.ux_old, self.uz_old
            )

        # Diffusion
        # self.rhs += (
        #    self.a[stage] * self.kappa * galerkin_to_cheby(self.NS.T.vhat, self.T)
        # )
        self.rhs += self.a[stage] * galerkin_to_cheby(self.NS.T.vhat, self.T)

        # Buoyancy
        self.rhs += self.a[stage] * galerkin_to_cheby(self.VA.vhat, self.VA)

        # Update
        self.T.vhat[:] += self.dt * cheby_to_galerkin(self.rhs, self.T)

    def update_P(self, div, singular=True):
        rhs = self.solver_P.solve_rhs(div)
        self.P.vhat[:] = self.solver_P.solve_lhs(rhs)
        if singular:
            self.P.vhat[0, 0] = 0

    def update_pres(self, div, stage):
        self.pres.vhat += galerkin_to_cheby(self.P.vhat, self.P) / (
            self.dt * self.a[stage]
        )

    def update_velocity(self, p, u, v, fac=1.0):

        dpdx = self.grad(p, deriv=(1, 0))
        dpdz = self.grad(p, deriv=(0, 1))

        u.vhat -= cheby_to_galerkin(dpdx * fac, u)
        v.vhat -= cheby_to_galerkin(dpdz * fac, v)

    def callback(self):
        self.eval_Nu()
        # -- Divergence
        print(
            "|div| = {:4.2e}".format(
                np.linalg.norm(self.NS.divergence_velocity(self.U, self.V))
            )
        )
        print(
            "|div residual|: {:4.2e}".format(
                np.linalg.norm(self.NS.divergence_velocity(self.NS.U, self.NS.V))
            )
        )

        # -- Norm
        print(" |U| = {:5.2e}".format(np.linalg.norm(self.NS.U.vhat)))
        print(" |V| = {:5.2e}".format(np.linalg.norm(self.NS.V.vhat)))
        print(" |T| = {:5.2e}".format(np.linalg.norm(self.NS.T.vhat)))

    def update(self):
        self.ux_old, self.uz_old, self.temp_old = 0, 0, 0
        for rk in range(self.nstage):

            # Convection velocity
            if self.dealias:
                self.ux = self.U.dealias.backward(self.U.vhat)
                self.uz = self.V.dealias.backward(self.V.vhat)
                self.temp = self.T.dealias.backward(self.T.vhat)
            else:
                self.ux = self.U.backward(self.U.vhat)
                self.uz = self.V.backward(self.V.vhat)
                self.temp = self.T.backward(self.T.vhat)

            # -- Residual NS
            self.update_NS()

            # -- Ux
            self.update_U(stage=rk)

            # -- Uz
            self.update_V(stage=rk)

            # -- Pressure
            div = self.NS.divergence_velocity(self.U, self.V)
            self.update_P(div)
            self.update_pres(div, stage=rk)

            # -- Update Velocity
            self.update_velocity(self.P, self.U, self.V)

            # -- Temp
            self.update_T(stage=rk)

            # -- Save old velocities
            self.ux_old, self.uz_old, self.temp_old = self.ux, self.uz, self.temp

if __name__ == "__main__":
    shape = (64, 64)
    Pr = 1
    Ra = 5e3

    # Pre-iterate
    NSA = NavierStokesAdjoint(
        shape=shape,
        dt=0.1,
        tsave=1.0,
        Ra=Ra,
        Pr=Pr,
        dealias=True,
        integrator="eu",
        beta=1.0,
    )

    NSA.NS.set_temperature(amplitude=0.2)
    NSA.NS.iterate(5.0)
    U = NSA.NS.U.vhat[:].copy()
    V = NSA.NS.V.vhat[:].copy()
    T = NSA.NS.T.vhat[:].copy()

    # Adjoint iteration
    NSA = NavierStokesAdjoint(
        shape=shape,
        dt=0.1,
        tsave=1.0,
        Ra=Ra,
        Pr=Pr,
        dealias=True,
        integrator="eu",
        beta=1.0,
    )

    NSA.U.vhat[:] = U
    NSA.V.vhat[:] = V
    NSA.T.vhat[:] = T

    NSA.iterate(20.0)
    NSA.plot()
    NSA.animate()

# # Animate
# for i,v in enumerate(NSA.T.V):
#         if NSA.T.V[i][0,0] < 0.1:
#             NSA.T.V[i] += NSA.NS.Tbc.v

# anim = NSA.T.animate(NSA.T.x,duration=4,wireframe=False)
# plt.show()


from pyqtgraph.parametertree import types as pTypes
from HdfDoc import HdfDoc
import GateDocView
from FileDocView import FileDocView
from MainDocView import MainDocView
from Event import Event

class CscanDocView(pTypes.GroupParameter):
    def __init__(self, gate_docview, name, hdf_doc: HdfDoc, c_scan, **opts):
        super().__init__(name=name)
        self.hdf_doc = hdf_doc
        self.c_scan = c_scan
        self.gate_docview: GateDocView.GateDocView = gate_docview
        self.file_docview: FileDocView = self.gate_docview.parent()
        self.main_docview: MainDocView = self.file_docview.parent()

        self.gate_docview.t_range_event += self.on_update_time_range
        self.gate_docview.fwf_changed_event += self.on_update_fwf
        self._mouse_row = 0
        self._mouse_col = 0
        self.cscan_changed_event = Event()

    def set_cscan(self):
        dn0, dn1 = self.gate_docview.get_dn_min_max()
        fwf_arr = self.gate_docview.get_fwf_arr()
        self.c_scan = self.hdf_doc.get_c_scan(dn0=dn0, dn1=dn1, fwf_arr=fwf_arr)
        self.cscan_changed_event(self.c_scan)

    def on_update_time_range(self):
        self.set_cscan()

    def on_update_fwf(self):
        self.set_cscan()

    def set_mouse_ij_pos(self, row, col):
        num_row, num_col = self.c_scan.shape
        if (0 <= row < num_row) and (0 <= col < num_col):
            self._mouse_row = row
            self._mouse_col = col
            pos = self.hdf_doc.get_pos(row, col)
            pos_str = '(x = %0.1f [mm], col = %0.1f = [mm]' % (pos['x'], pos['y'])
        else:
            pos_str = ''

        self.main_docview.set_status(pos_str)


"""
	This file containts several data analysis methods designed to run on a Dataset Class
	(PCA, clustering, some classification tests)

	TODO: add these to the example-scripts folder to make some preliminary analysis easier
"""

import logging
import typing

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib import cm

log = logging.getLogger(__name__)
#pylint: disable=import-outside-toplevel #Make scikit-learn optional

def plot_subset_columns(dataset, columns, label_column_name = "Classification"):
	"""
	Quick plot of 3d plot of 3 columns of a dataframe
	"""
	fig = plt.figure(figsize = (10,10))
	ax = fig.add_subplot(1, 1, 1, projection='3d') #3d plot #pylint: disable=invalid-name
	ax.set_xlabel(columns[0], fontsize = 15) #set labels
	ax.set_ylabel(columns[1], fontsize = 15)
	ax.set_zlabel(columns[2], fontsize = 15)
	ax.set_title('Columns:' + columns[0] + " "+ columns[1] + " " + columns[2] , fontsize = 20) #set title
	classes = dataset.df[label_column_name].unique() #get all classes
	colors = cm.rainbow(np.linspace(0,1,len(classes))) #get new color for each one #type: ignore #pylint: disable=no-member
	legend = []

	for target, color in zip(classes,colors):
		kept_indices = dataset.df['Classification'] == target #Split on classification type
		ax.scatter(dataset.df.loc[kept_indices, columns[0]], #plot the columns
				dataset.df.loc[kept_indices, columns[1]],
				dataset.df.loc[kept_indices, columns[2]],
				c = color.reshape(1,-1), #Color each type according to different color wheel
				s = 50)
		legend.append(dataset.classes[int(target)])
	ax.legend(legend)
	ax.grid()
	plt.show()

def get_pca(df, components =3, scale=True ):  #pylint: disable=invalid-name
	"""
	Uses PCA to add a "PC1", "PC2", "PC3" column to the passed dataframe and returns it
	Args:
		df (pd.DataFrame): The dataframe to perform PCA on
		components (int, optional): Number of components to return. Defaults to 3.
		scale (bool, optional): Wether to scale the data before PCA. Defaults to True.
	"""
	from sklearn import (decomposition, preprocessing)
	log.info("Generating 3d PCA plot...")
	df_pca = df.copy()
	if scale: # SCikit learn automatically centers, but does not scale data (MinMaxScaler is used here)
		for col in df_pca: #go over columns, normalize them TODO: what about time? class?
			scaler = preprocessing.MinMaxScaler()
			norm_col = scaler.fit_transform(df_pca[[col]]) #Min-max normalize data (it is centered by scikit-pca)
			df_pca.loc[:, col] = norm_col

	pca = decomposition.PCA(n_components=components)

	df_pca = df_pca.dropna()  #drop NaN for PCA analysis
	princ_components = pca.fit_transform(df_pca) #Apply PCA
	principal_df = pd.DataFrame(data = princ_components, columns = ['PC1', 'PC2', 'PC3'], index=df_pca.index)

	return principal_df

def plot_pca_2d(dataset):
	"""
	Create a 2D PCA plot of the dataset
	"""
	pca_result_df  = get_pca(
		dataset.df[dataset.df.columns.difference(["Date", "Time", "Classification", "DateTime"])], components=2)
	pca_result_df = pd.concat([pca_result_df, dataset.df['Classification']]) #append classification column to PCA plot
	classes = range(int(pca_result_df['Classification'].max()) + 1) #        \
	fig = plt.figure(figsize = (10,10))
	ax = fig.add_subplot(1, 1, 1) #pylint: disable=invalid-name
	ax.set_xlabel('Principal Component 1', fontsize = 15)
	ax.set_ylabel('Principal Component 2', fontsize = 15)
	ax.set_title('2 component PCA', fontsize = 20)
	legend = []

	colors = cm.rainbow(np.linspace(0,1,len(classes))) #get color for each one #type: ignore #pylint: disable=no-member
	for target, color in zip(classes,colors):
		kept_indices = pca_result_df['Classification'] == target #Split on classification type
		ax.scatter(pca_result_df.loc[kept_indices, 'PC1'],
				pca_result_df.loc[kept_indices, 'PC2'],
				c = color.reshape(1,-1), #Color each type according to different color wheel
				s = 50)
		legend.append(dataset.classes(target))

	ax.legend(legend)
	ax.grid()
	plt.show()

def plot_pca_3d(
		dataframe : pd.DataFrame,
		plot_only_classes : typing.Optional[typing.List[str]] = None,
		dt_column = "DateTime",
		lbl_column = None,
		figurenr : int = 5,
		figsize : tuple = (15, 10)):
	"""Plots a 3D PCA splot for the provided dataframe (all columns included).
	Colors each dot according to its column

	Args:
		dataframe (pd.DataFrame): The dataframe with all data
		plot_only_classes (Typing.List[str] optional): Wether to only plot certain columns (classes), provide a
			list of string. Defaults to [].
	"""
	if plot_only_classes is None:
		plot_only_classes = []

	#Perform PCA on all passed data (except datetime/class label):
	pca_result_df = get_pca(dataframe[dataframe.columns.difference([dt_column, lbl_column])], components=3)

	classes = ["All"]
	if lbl_column:
		pca_result_df = pd.concat([pca_result_df, dataframe[lbl_column]]) #append label column to PCA plot
		classes = dataframe[lbl_column].unique()

	fig = plt.figure(figurenr)
	ax = fig.add_subplot(1, 1, 1, projection='3d') #pylint: disable=invalid-name

	fig.set_size_inches(figsize[0], figsize[1])

	ax.set_xlabel('Principal Component 1', fontsize = 15)
	ax.set_ylabel('Principal Component 2', fontsize = 15)
	ax.set_zlabel('Principal Component 3', fontsize = 15)
	ax.set_title('3 Component PCA', fontsize = 20)

	log.debug(f"Classes: {classes}")

	colors = cm.rainbow(np.linspace(0,1,len(classes))) #get color for each one #type: ignore #pylint: disable=no-member
	legend = []
	# colors = ['r', 'g', 'b']
	for target, color in zip(classes,colors):
		log.debug(f"Now processing class {target}")
		# if target == 6: #Skip jetting as this process applies to
		#     continue
		if len(plot_only_classes) > 0 and target not in plot_only_classes: #If plot
			continue

		if lbl_column is None: #If all should be added:
			kept_indices = dataframe.index
		else:
			kept_indices = dataframe[lbl_column] == target #Split on classification type
			legend.append(target)

		if len(pca_result_df.loc[kept_indices]) <= 0:
			# print("None")
			log.warning(f"No entries for class {target}")
			continue

		ax.scatter(pca_result_df.loc[kept_indices, 'PC1'],
				pca_result_df.loc[kept_indices, 'PC2'],
				pca_result_df.loc[kept_indices, 'PC3'],
				c = color.reshape(1,-1), #Color each type according to different color wheel
				s = 50)
	ax.legend(legend)
	ax.grid()
	fig.show()

def plot_df_scatter_class(
		df, #pylint: disable=invalid-name
		ax,	#pylint: disable=invalid-name
		color_column="Classification",
		legend_label_prefix = "",
		class_name_dict = None,
		plot_kwargs = None
	):
	"""
	Plot a dataframe with a classification column, color each class differently
	Args:
		df (pd.DataFrame): The dataframe to plot
		ax (matplotlib.axes.Axes): The ax to plot on
		color_column (str, optional): The column to use for coloring. Defaults to "Classification".
		legend_label_prefix (str, optional): Prefix to add to each class label in the legend. Defaults to "".
		class_name_dict (dict, optional): Dictionary to translate class labels to other labels. Defaults to {-1 : None}.
	"""
	if plot_kwargs is None:
		plot_kwargs = {}
	if class_name_dict is None:
		class_name_dict = {-1 : None}
	dims = len(df.columns) - 1 #Columns count - classification column (determines color)
	data_cols = df.columns[ df.columns != color_column]

	if len(data_cols) > 4:
		log.fatal(f"Trying to generate a plot with dims={dims} (excluding color_column), this is impossible, exiting...")
		raise ValueError(f"Trying to generate a plot with dims={dims} (excluding color_column), "
			"this is impossible, exiting...")

	# classes = range(int(df[color_column].max()) + 1)
	classes = df[color_column].unique() #get all unique classes

	colormap = cm.rainbow(np.linspace(0,1,len(classes))) #get colors #type: ignore #pylint: disable=no-member

	class_color_dict = {}

	for i, _ in enumerate(classes):
		class_color_dict[i] = colormap[i] #create color mapping of form {"class": [r,g,b,a], etc}
	colors = pd.Series(df.loc[:, color_column]).map(class_color_dict) #create color array for each entry

	if dims == 2:
		df.plot.scatter(x=data_cols[0], y=data_cols[1], c=colors, ax=ax, **plot_kwargs)
	elif dims == 3:
		for cur_class in classes:
			cur_class_df = df[df[color_column] == cur_class] #Select only
			cur_label = legend_label_prefix + str(cur_class)
			if cur_label in class_name_dict.keys(): #if label-translation
				cur_label = class_name_dict[cur_label] #type: ignore
			ax.scatter(
				cur_class_df[data_cols[0]].to_numpy(),
	      		cur_class_df[data_cols[1]].to_numpy(),
				cur_class_df[data_cols[2]].to_numpy(),
				**plot_kwargs,
				label=cur_label
			)
			ax.legend()

		ax.set_xlabel(data_cols[0], fontsize = 10) #set labels
		ax.set_ylabel(data_cols[1], fontsize = 10)
		ax.set_zlabel(data_cols[2], fontsize = 10)
	else:
		print("Dims = 1, cant plot")

	ax.grid()
	# plt.show()

def k_cluster(df, n_clusters = 4): #pylint: disable=invalid-name
	"""Cluster using k-means"""
	import sklearn.cluster
	df = df[df.columns.difference(["Date", "Time", "DateTime", "Classification"])]
	df = df.dropna() #remove nan values
	model = sklearn.cluster.KMeans(n_clusters=n_clusters).fit(df) #Train using the trainset (split[0]), without labels
	results = pd.Series(model.predict(df), name="Cluster", index=df.index) #Nearest clusters
	df['Cluster'] = results
	return df

def k_means_classification(dataset, label_column_name= "Classification", n_clusters=100, n_splits = 5):
	"""
	Do k-means clustering, then determine the label of that cluster using majority vote. We can then use this
	to classify new data points by finding the nearest cluster and using the majority vote label of that cluster.
	"""
	import sklearn
	import sklearn.cluster
	from sklearn import (model_selection)
	from sklearn.metrics import classification_report
	#Simple k-means classification using majority-vote for each cluster center, contains a test as well
	df_norm = dataset.get_df_norm()
	train_df = df_norm[df_norm.columns.difference(["Date", "Time"])] #Train on all (normalized) data except
		# date, time and label
	train_df = train_df.dropna() #remove nan values
	print("Number of detected classification labels in database: "
    	+  str(len(dataset.df[label_column_name].unique())) + "  (" + str(dataset.df[label_column_name].unique()) + ")")
	splits = model_selection.KFold(n_splits = n_splits, shuffle=False) #TODO: shuffle manually to equal-shared?
	labels_actual = np.array([])
	labels_predicted = np.array([])
	splits = splits.split(train_df) #get splits for training dataframe

	# for n_test in range(n_splits): #perform classification and evaluate for every split
	for n_test, split_indexes in enumerate(splits):
		print(" Doing K-fold test "+ str(n_test+1) + " out of "+  str(n_splits))
		# split_indexes = next(splits) #get split indexes
		split = train_df.iloc[split_indexes[0]], train_df.iloc[split_indexes[1]] #get train and testsplit

		train_split = split[0][split[0].columns.difference([label_column_name])] #get current trainsplit
		test_split = split[1][split[1].columns.difference([label_column_name])] #get current testsplit

		model = sklearn.cluster.KMeans(n_clusters=n_clusters).fit(train_split) #Train using the trainset (split[0]),
		results = pd.Series(model.predict(train_split), name="Cluster") #create a result series with the nearest cluster
		#create df that has class label+cluster for each entry, index should first be reset or join will fail:
		df_label_and_cluster = pd.concat([split[0][label_column_name].reset_index(drop=True), results], axis=1)
		cluster_label = ["UNKNOWN" for i in range(len(results.unique()))]
		#create dataframe with each center and the (majority voted) label for that center:
		df_center_labels = pd.DataFrame(columns=["Center", "Label Mode"])

		for cur_cluster in results.unique(): #Go over each mean (cluster), do majority vote to get labels per cluster
			cluster_df = df_label_and_cluster[df_label_and_cluster["Cluster"] == cur_cluster] #get all
			cluster_label = cluster_df[label_column_name].mode() #do majority vote for cluster
			cluster_row = pd.DataFrame([[cur_cluster, cluster_label.iloc[0]]], columns=["Center", "Label Mode"])
			df_center_labels = df_center_labels.append(cluster_row) #append row #type: ignore

		#----------------------Testing-----------------------
		#Get current predictions/labels in numpy array
		cur_pred = pd.DataFrame(model.predict(test_split), columns=["Center"])
		cur_pred = cur_pred.merge(df_center_labels, on=["Center"], how='left')["Label Mode"] #join to get majority-vote
		cur_pred_np = np.array(cur_pred, dtype=int)

		cur_act = split[1][label_column_name].reset_index(drop=True)
		cur_act_np = np.array(cur_act, dtype=int)

		#append to total list of actual/predictions
		labels_actual = np.append(labels_actual, cur_act_np) #create list with all actual labels
		labels_predicted = np.append(labels_predicted, cur_pred_np) #create list with all predicted labels

	labels_actual = [ dataset.classes[int(labels_actual[i])] for i in range(len(labels_actual))] #translate to int+class
	labels_predicted = [ dataset.classes[int(labels_predicted[i])] for i in range(len(labels_predicted))]

	print(classification_report(labels_actual, labels_predicted))