from cvxpy import *
from cvxpy.tests.base_test import BaseTest

class TestSolvers(BaseTest):
    """ Unit tests for solver specific behavior. """
    def setUp(self):
        self.a = Variable(name='a')
        self.b = Variable(name='b')
        self.c = Variable(name='c')

        self.x = Variable(2, name='x')
        self.y = Variable(3, name='y')
        self.z = Variable(2, name='z')

        self.A = Variable(2,2,name='A')
        self.B = Variable(2,2,name='B')
        self.C = Variable(3,2,name='C')

    def test_solver_errors(self):
        """Tests that solver errors throw an exception.
        """
        # For some reason CVXOPT can't handle this problem.
        expr = 500*self.a + square(self.a)
        prob = Problem(Minimize(expr))

        with self.assertRaises(Exception) as cm:
            prob.solve(solver=CVXOPT)
        self.assertEqual(str(cm.exception),
            "Solver 'CVXOPT' failed. Try another solver.")

    def test_ecos_options(self):
        """Test that all the ECOS solver options work.
        """
        # Test ecos
        # feastol, abstol, reltol, feastol_inacc, abstol_inacc, and reltol_inacc for tolerance values
        # max_iters for the maximum number of iterations,
        EPS = 1e-4
        prob = Problem(Minimize(norm(self.x, 1)), [self.x == 0])
        for i in range(2):
            prob.solve(solver=ECOS, feastol=EPS, abstol=EPS, reltol=EPS,
                       feastol_inacc=EPS, abstol_inacc=EPS, reltol_inacc=EPS,
                       max_iters=20, verbose=True, warm_start=True)
        self.assertItemsAlmostEqual(self.x.value, [0, 0])

    def test_ecos_bb_options(self):
        """Test that all the ECOS BB solver options work.
        """
        # 'mi_maxiter'
        # maximum number of branch and bound iterations (default: 1000)
        # 'mi_abs_eps'
        # absolute tolerance between upper and lower bounds (default: 1e-6)
        # 'mi_rel_eps'
        EPS = 1e-4
        prob = Problem(Minimize(norm(self.x, 1)), [self.x == Bool(2)])
        for i in range(2):
            prob.solve(solver=ECOS_BB, mi_max_iters=100, mi_abs_eps=1e-6,
            mi_rel_eps=1e-5, verbose=True, warm_start=True)
        self.assertItemsAlmostEqual(self.x.value, [0, 0])

    def test_scs_options(self):
        """Test that all the SCS solver options work.
        """
        # Test SCS
        # MAX_ITERS, EPS, ALPHA, UNDET_TOL, VERBOSE, and NORMALIZE.
        # If opts is missing, then the algorithm uses default settings.
        # USE_INDIRECT = True
        EPS = 1e-4
        prob = Problem(Minimize(norm(self.x, 1)), [self.x == 0])
        for i in range(2):
            prob.solve(solver=SCS, max_iters=50, eps=EPS, alpha=EPS,
                       verbose=True, normalize=True, use_indirect=False)
        self.assertItemsAlmostEqual(self.x.value, [0, 0])

    def test_cvxopt_options(self):
        """Test that all the CVXOPT solver options work.
        """
        # TODO race condition when changing these values.
        # 'maxiters'
        # maximum number of iterations (default: 100).
        # 'abstol'
        # absolute accuracy (default: 1e-7).
        # 'reltol'
        # relative accuracy (default: 1e-6).
        # 'feastol'
        # tolerance for feasibility conditions (default: 1e-7).
        # 'refinement'
        # number of iterative refinement steps when solving KKT equations (default: 0 if the problem has no second-order cone or matrix inequality constraints; 1 otherwise).
        EPS = 1e-7
        prob = Problem(Minimize(norm(self.x, 1)), [self.x == 0])
        for i in range(2):
            prob.solve(solver=CVXOPT, feastol=EPS, abstol=EPS, reltol=EPS,
                       max_iters=20, verbose=True, kktsolver="chol",
                       refinement=2, warm_start=True)
        self.assertItemsAlmostEqual(self.x.value, [0, 0])

    def test_cvxopt_glpk(self):
        """Test a basic LP with GLPK.
        """
        # Either the problem is solved or GLPK is not installed.
        if GLPK in installed_solvers():
            prob = Problem(Minimize(norm(self.x, 1)), [self.x == 0])
            prob.solve(solver = GLPK)
            self.assertItemsAlmostEqual(self.x.value, [0, 0])

            # Example from http://cvxopt.org/userguide/coneprog.html?highlight=solvers.lp#cvxopt.solvers.lp
            objective = Minimize(-4 * self.x[0] - 5 * self.x[1])
            constraints = [ 2 * self.x[0] + self.x[1] <= 3,
                            self.x[0] + 2 * self.x[1] <= 3,
                            self.x[0] >= 0,
                            self.x[1] >= 0]
            prob = Problem(objective, constraints)
            prob.solve(solver = GLPK)
            self.assertItemsAlmostEqual(self.x.value, [1, 1])
        else:
            with self.assertRaises(Exception) as cm:
                prob = Problem(Minimize(norm(self.x, 1)), [self.x == 0])
                prob.solve(solver = GLPK)
            self.assertEqual(str(cm.exception), "The solver %s is not installed." % GLPK)

    def test_installed_solvers(self):
        """Test the list of installed solvers.
        """
        from cvxpy.problems.solvers.utilities import SOLVERS
        prob = Problem(Minimize(norm(self.x, 1)), [self.x == 0])
        for solver in SOLVERS.keys():
            if solver in installed_solvers():
                prob.solve(solver=solver)
                self.assertItemsAlmostEqual(self.x.value, [0, 0])
            else:
                with self.assertRaises(Exception) as cm:
                    prob.solve(solver = solver)
                self.assertEqual(str(cm.exception), "The solver %s is not installed." % solver)


import pandas as pd
import numpy as np
# import seaborn as sb
import matplotlib.pyplot as plt

import statsmodels.formula.api as sm
from sklearn.model_selection import train_test_split # train and test
from sklearn import metrics
from sklearn.metrics import classification_report

#Importing Data
claimants1 = pd.read_csv("C:/Datasets_BA/Logistic regression/claimants.csv",sep=",")

#removing CASENUM
claimants1 = claimants1.drop('CASENUM', axis = 1)
claimants1.head(11)
claimants1.isna().sum()

# Imputating the missing values
########## Median Imputation ############
claimants1.fillna(claimants1.median(), inplace=True)
claimants1.isna().sum()

### Splitting the data into train and test data
# from sklearn.model_selection import train_test_split
train_data, test_data = train_test_split(claimants1, test_size = 0.3) # 30% test data

# Model building
# import statsmodels.formula.api as sm
logit_model = sm.logit('ATTORNEY ~ CLMAGE + LOSS + CLMINSUR + CLMSEX + SEATBELT', data = train_data).fit()

#summary
logit_model.summary2() # for AIC
logit_model.summary()

#prediction
train_pred = logit_model.predict(train_data.iloc[ :, 1: ])

# Creating new column
# filling all the cells with zeroes
train_data["train_pred"] = np.zeros(938)

# taking threshold value as 0.5 and above the prob value will be treated as correct value
train_data.loc[train_pred > 0.5, "train_pred"] = 1

# classification report
classification = classification_report(train_data["train_pred"], train_data["ATTORNEY"])
classification

# confusion matrix
confusion_matrx = pd.crosstab(train_data.train_pred, train_data['ATTORNEY'])
confusion_matrx

accuracy_train = (308 + 358)/(938)
print(accuracy_train)

#ROC CURVE AND AUC
fpr, tpr, threshold = metrics.roc_curve(train_data["ATTORNEY"], train_pred)

#PLOT OF ROC
plt.plot(fpr, tpr);plt.xlabel("False positive rate");plt.ylabel("True positive rate")

roc_auc = metrics.auc(fpr, tpr)  #AUC = 0.76

# Prediction on Test data set
test_pred = logit_model.predict(test_data)

# Creating new column for storing predicted class of Attorney
# filling all the cells with zeroes
test_data["test_pred"] = np.zeros(402)

# taking threshold value as 0.5 and above the prob value will be treated as correct value
test_data.loc[test_pred > 0.5, "test_pred"] = 1

# confusion matrix
confusion_matrix = pd.crosstab(test_data.test_pred, test_data['ATTORNEY'])

confusion_matrix
accuracy_test = (124 + 158)/(402)
accuracy_test

# Based on ROC curv we can say that cut-off value should be 0.60, We can select it and check the acccuracy again.


import discord

from redbot.core import commands, checks
from redbot.core.utils.menus import menu, DEFAULT_CONTROLS

from .core import Core

class Space(Core):
    """Show pics of space."""

    @commands.group()
    @checks.mod_or_permissions(manage_channels=True)
    async def spaceset(self, ctx: commands.Context):
        """Group commands for Space cog settings."""

    @spaceset.command()
    async def autoapod(self, ctx: commands.Context, channel: discord.TextChannel = None):
        """
        Choose if you want to automatically receive \"Astronomy Picture of the Day\" every day.

        Set to actual channel by default. You can also use `[p]spaceset autoapod <channel_name>` if you want to receive APOD in others channels.
        Use the same command to disable it.
        """
        channel = ctx.channel if not channel else channel
        auto_apod = await self.config.channel(channel).auto_apod()
        await self.config.channel(channel).auto_apod.set(not auto_apod)
        msg = (
            "I will now automatically send Astronomy Picture of the Day every day in this channel."
            if not auto_apod
            else "No longer sending Astronomy Picture of the Day every day in this channel."
        )
        await channel.send(msg)
        if not auto_apod:
            data = await self.get_data("https://api.martinebot.com/images/apod")
            apod_text = await self.apod_text(data, channel)
            await self.maybe_send_embed(channel, apod_text)
            await self.config.channel(channel).last_apod_sent.set(data["date"])
        await ctx.tick()

    @commands.command()
    @commands.bot_has_permissions(embed_links=True)
    async def apod(self, ctx: commands.Context):
        """Astronomy Picture of the Day."""
        async with ctx.typing():
            apod_text = await self.apod_text(
                await self.get_data("https://api.martinebot.com/images/apod"),
                ctx,
            )
        return await self.maybe_send_embed(ctx, apod_text)

    @commands.command()
    @commands.bot_has_permissions(embed_links=True)
    async def spacepic(self, ctx: commands.Context, *, query: str):
        """
        Lookup pictures from space!
        Note - Some pictures are from presentations and other educational talks
        """
        async with ctx.typing():
            query = self.escape_query("".join(query))
            space_data = await self.get_space_pic_data(ctx, query)
            if space_data is None:
                await ctx.send(f"Looks like you got lost in space looking for `{query}`")
                return
            if space_data is False:
                return
            if query.lower() == "star wars":
                await ctx.send(self.star_wars_gifs())
                return

            pages = []
            total_pages = len(space_data)  # Get total page count
            for c, i in enumerate(space_data, 1):  # Done this so I could get page count `c`
                space_data_clean = i.replace(" ", "%20")
                embed = discord.Embed(
                    title="Results from space",
                    description=f"Query was `{query}`",
                    color=await ctx.embed_color(),
                )
                embed.set_image(url=space_data_clean)
                embed.set_footer(text=f"Page {c}/{total_pages}")
                # Set a footer to let the user
                # know what page they are in
                pages.append(embed)
                # Added this embed to embed list that the menu will use
        return await menu(ctx, pages, DEFAULT_CONTROLS)

    @commands.command()
    @commands.bot_has_permissions(embed_links=True)
    async def isslocation(self, ctx: commands.Context):
        """Show the Current location of the ISS."""
        async with ctx.typing():
            data = await self.get_data("http://api.open-notify.org/iss-now.json")
            if not data:
                await ctx.send("I can't get the data from the API. Try again later.")
                return

            embed = discord.Embed(
                title="Current location of the ISS",
                description="Latitude and longitude of the ISS",
                color=await ctx.embed_color(),
            )
            embed.add_field(name="Latitude", value=data["iss_position"]["latitude"], inline=True)
            embed.add_field(name="Longitude", value=data["iss_position"]["longitude"], inline=True)
            embed.set_thumbnail(url="https://photos.kstj.us/GrumpyMeanThrasher.jpg")
        return await ctx.send(embed=embed)

    @commands.command()
    @commands.bot_has_permissions(embed_links=True)
    async def astronauts(self, ctx: commands.Context):
        """Show who is currently in space."""
        async with ctx.typing():
            data = await self.get_data("http://api.open-notify.org/astros.json")
            if not data:
                await ctx.send("I can't get the data from the API. Try again later.")
                return

            astrosnauts = []
            for astros in data["people"]:
                astrosnauts.append(astros["name"])

            embed = discord.Embed(title="Who's in space?", color=await ctx.embed_color())
            embed.add_field(name="Current Astronauts in space", value="\n".join(astrosnauts))
        return await ctx.send(embed=embed)


from indexes.single_indexes.hnsw_hnswlib import HnswHnswlib
from indexes.testers.TimeStats import BuildTimeStats, QueryTimeStats
from indexes.utils.dataset import BasicDataset
from indexes.utils.distance_function import l2distance
import Index

from sklearn.cluster import KMeans
from overrides import overrides
from typing import List, Tuple

from time import time

class KMeansIndex(Index.Index):
    def __init__(self, name, max_elements, dimensions, metric='l2', distance_function=None, num_threads=-1,
                 num_partitions=4, num_partitions_to_search=2, ef_construction=1000, ef=1000, m=64):
        super().__init__(name, max_elements, dimensions, metric, distance_function, num_threads)
        self.num_partitions = num_partitions
        self.num_partitions_to_search = num_partitions_to_search
        self.ef_construction = ef_construction
        self.ef = ef
        self.m = m
        self.single_partitions_size = 0
        self.mapping = None
        self.centers = None

    def partition(self, dataset):
        data = dataset.get_data()
        k_means = KMeans(n_clusters=self.num_partitions, random_state=0)
        k_means.fit(data)
        labels = k_means.labels_
        self.centers = k_means.cluster_centers_
        self.mapping = dict([(i, []) for i in range(self.num_partitions)])
        p_indexes = [[] for _ in range(self.num_partitions)]
        for i in range(labels.shape[0]):
            p_indexes[labels[i]].append(i)
            self.mapping[labels[i]].append(i)

        partitions = [data[p_indexes[idx]] for idx in range(self.num_partitions)]

        return partitions

    @overrides
    def build(self, dataset) -> BuildTimeStats:
        partition_start_time = time()
        partitions = self.partition(dataset)
        elapsed_partition_time = time() - partition_start_time

        build_start_time = time()
        datasets = [BasicDataset(f'partition{idx}', '') for idx in range(self.num_partitions)]
        for idx, dataset in enumerate(datasets):
            dataset.load_dataset_from_numpy(partitions[idx])
        self.index = [HnswHnswlib('hnsw_hnswlib', datasets[idx].get_size(), datasets[idx].get_dimensions(), self.metric,
                                  self.distance_function, self.num_threads, self.ef_construction, self.ef, self.m) for
                      idx in range(self.num_partitions)]
        for idx, index in enumerate(self.index):
            index.build(datasets[idx])
        elapsed_build_time = time() - build_start_time
        return BuildTimeStats(elapsed_partition_time, elapsed_build_time)

    @overrides
    def search(self, query, k=5) -> Tuple[List[List[Tuple[float, int]]], QueryTimeStats, float]:
        avg_ind = self.num_partitions_to_search
        query_start_time = time()
        index_list = [
            list(sorted([(l2distance(q, self.centers[i]), i) for i in range(len(self.index))], key=lambda x: x[0]))[
            :self.num_partitions_to_search] for q in query]
        results = [[self.index[idx].search([query[q_id]], k)[0] for _, idx in id_list] for q_id, id_list in
                   enumerate(index_list)]
        elapsed_query_time = time() - query_start_time

        merge_start_time = time()
        # Fix indexes

        results = [[[(t[0], self.mapping[index_list[q_id][ind_id][1]][t[1]]) for t in index[0]] for ind_id, index in enumerate(res)]
                   for q_id, res in enumerate(results)]

        result = [list(sorted([t for index in res for t in index], key=lambda x: x[0]))[:k] for res in results]

        elapsed_merge_time = time() - merge_start_time
        return result, QueryTimeStats(elapsed_query_time, elapsed_merge_time, len(query)), avg_ind


#!/usr/bin/env python3

"""parser: SignWriting string parse functions

Define various regular expressions and use them to validate
SignWriting strings.

"""

import re

SYMBOL_BLOCK = 'S[123][0-9a-f]{2}[0-5][0-9a-f]'
COORD_BLOCK = 'n?[0-9]+xn?[0-9]+'
POS_COORD_BLOCK = '[0-9]+x[0-9]+'
re_word = (
    '(A(' + SYMBOL_BLOCK + ')+)?'
    '[BLMR](' + SYMBOL_BLOCK + COORD_BLOCK + ')*')
re_pword = (
    '(A(' + SYMBOL_BLOCK + ')+)?'
    '[BLMR](' + SYMBOL_BLOCK + POS_COORD_BLOCK +
    'x' + COORD_BLOCK + ')*')
re_panelword = (
    '[BLMR](' + POS_COORD_BLOCK + ')'
    '(' + SYMBOL_BLOCK + COORD_BLOCK + ')*')
re_lword = (
    '(A(' + SYMBOL_BLOCK + ')+)?' + re_panelword)
re_punc = 'S38[7-9ab][0-5][0-9a-f]'
re_ppunc = re_punc + POS_COORD_BLOCK
re_lpunc = re_punc + COORD_BLOCK

COORDINATES = re.compile(COORD_BLOCK,
                         flags=re.IGNORECASE)
SYM_WITH_COORD = re.compile(SYMBOL_BLOCK + COORD_BLOCK,
                            flags=re.IGNORECASE)
PREFIX = re.compile('A((' + SYMBOL_BLOCK + ')+)',
                    flags=re.IGNORECASE)
RAW_TOKEN = re.compile("(" + re_word + '|' + re_punc + ")",
                       flags=re.IGNORECASE)
EXPANDED_TOKEN = re.compile('(' + re_pword + '|' + re_ppunc + ')',
                            flags=re.IGNORECASE)
LAYOUT_TOKEN = re.compile('(' + re_lword + '|' + re_lpunc + ')',
                          flags=re.IGNORECASE)
PANEL_TOKEN = re.compile(
    'D' + POS_COORD_BLOCK + '(_' + re_panelword + ')*',
    flags=re.IGNORECASE)

# Pattern matching on Kartesian SignWriting strings

def is_raw(text):
    """Test whether text is a raw SignWriting string.

    Returns True if `text` is raw Kartesian SignWriting, that is,
    without symbol sizes or preprocessed information, False otherwise.

    This function tests according to pattern-matching with a regex, so
    it can only be a necessary, not a sufficient condition. For
    example, is_raw('BS3ff5f') will be True, even though the symbol
    slot S3ff5f is not assigned.

    >>> all([is_raw('B'), is_raw('L'), is_raw('M'), is_raw('R')])
    True

    >>> is_raw('BS10000n10xn10')
    True
    >>> is_raw('LS10000n10xn10')
    True
    >>> is_raw('MS10000n10xn10')
    True
    >>> is_raw('RS10000n10xn10')
    True

    >>> is_raw('AS10000BS10000n10xn10')
    True
    >>> is_raw('AS10000LS10000n10xn10')
    True
    >>> is_raw('AS10000MS10000n10xn10')
    True
    >>> is_raw('AS10000RS10000n10xn10')
    True

    >>> is_raw('AS10000BS1000010x10xn10xn10')
    False
    >>> is_raw('AS10000LS1000010x10xn10xn10')
    False
    >>> is_raw('AS10000MS1000010x10xn10xn10')
    False
    >>> is_raw('AS10000RS1000010x10xn10xn10')
    False

    @param `text` str
    @return boolean

    """
    return all([RAW_TOKEN.fullmatch(token) for token in text.split()])

def is_expanded(text):
    """Test if text is Kartesian SignWriting with symbol sizes.

    Returns True if `text` is Kartesian SignWriting with symbol sizes
    specified.

    This function tests according to pattern-matching with a regex, so
    it can only be a necessary, not a sufficient condition. For
    example, is_expanded('BS3ff5f1x1') will be True, even though the
    symbol slot S3ff5f is not assigned.

    >>> all([is_expanded('B'), is_expanded('L'),
    ... is_expanded('M'), is_expanded('R')])
    True

    >>> is_expanded('BS1000010x10xn10xn10')
    True
    >>> is_expanded('LS1000010x10xn10xn10')
    True
    >>> is_expanded('MS1000010x10xn10xn10')
    True
    >>> is_expanded('RS1000010x10xn10xn10')
    True

    >>> is_expanded('AS10000BS1000010x10xn10xn10')
    True
    >>> is_expanded('AS10000LS1000010x10xn10xn10')
    True
    >>> is_expanded('AS10000MS1000010x10xn10xn10')
    True
    >>> is_expanded('AS10000RS1000010x10xn10xn10')
    True

    >>> is_expanded('BS10000n10xn10')
    False
    >>> is_expanded('LS10000n10xn10')
    False
    >>> is_expanded('MS10000n10xn10')
    False
    >>> is_expanded('RS10000n10xn10')
    False

    """
    return all([EXPANDED_TOKEN.fullmatch(token) for token in text.split()])

def is_layouted(text):
    """Test if text is Kartesian SignWriting with layout data.

    Returns True if `text` is Kartesian SignWriting without symbol
    sizes specified, but with layout data from pre-processing.

    This function tests according to pattern-matching with a regex, so
    it can only be a necessary, not a sufficient condition. For
    example, is_raw(BS3ff5f1x1) will be True, even though the symbol
    slot S3ff5f is not assigned.

    >>> all([is_layouted('B10x10'), is_layouted('L3x4'),
    ... is_layouted('M3x2'), is_layouted('R8x23')])
    True

    >>> is_layouted('B10x10S10000n10xn10')
    True
    >>> is_layouted('L10x10S10000n10xn10')
    True
    >>> is_layouted('M10x10S10000n10xn10')
    True
    >>> is_layouted('R10x10S10000n10xn10')
    True

    """
    return all([LAYOUT_TOKEN.fullmatch(token)
                for token in text.split()])

def is_panel(text):
    """Test if text is a Kartesian SignWriting panel string.

    Returns True if `text` is Kartesian SignWriting without symbol
    sizes specified, but with layout data from pre-processing.

    This function tests according to pattern-matching with a regex, so
    it can only be a necessary, not a sufficient condition. For
    example, is_raw(BS3ff5f1x1) will be True, even though the symbol
    slot S3ff5f is not assigned.
    """
    return all([PANEL_TOKEN.fullmatch(token) for token in text.split()])

def all_symbols(sw_string):
    """List all symbols referenced in sw_string

    List all symbols that are referenced in the body of the Kartesian
    SignWriting string `sw_string`, that is, all symbols outside the
    `AS00000` prefix, or equivalently, all symbols with defined
    coordinates.

    >>> all_symbols('BS10000n10xn10')
    ['S10000']

    >>> all_symbols('LS10000n10xn10')
    ['S10000']

    >>> all_symbols('MS10000n10xn10')
    ['S10000']

    >>> all_symbols('RS10000n10xn10')
    ['S10000']

    >>> all_symbols('AS10000BS10000n10xn10S1035f10x10')
    ['S10000', 'S1035f']

    >>> all_symbols('AS10000LS10000n10xn10S1035f10x10')
    ['S10000', 'S1035f']

    >>> all_symbols('AS10000MS10000n10xn10S1035f10x10')
    ['S10000', 'S1035f']

    >>> all_symbols('AS10000RS10000n10xn10S1035f10x10')
    ['S10000', 'S1035f']

    """
    symbols = []
    for group in SYM_WITH_COORD.findall(sw_string):
        symbols.append(group[:6])
    return symbols

def prefix_symbols(sw_string):
    """ List all symbols referenced in the prefix.

    >>> prefix_symbols(
    ... 'M18x33S1870an11x15S18701n18xn10S205008xn4S2e7340xn32')
    []

    >>> prefix_symbols('AS1870aS18701S2e734M18x33S1870an11x15'
    ... 'S18701n18xn10S205008xn4S2e7340xn32')
    ['S1870a', 'S18701', 'S2e734']
    """
    match = PREFIX.match(sw_string)
    if not match:
        return []
    return re.findall(SYMBOL_BLOCK, match.group(0), flags=re.IGNORECASE)

# Define symbol types

symbol_ranges = {
    'iswa': (0x100, 0x38b),
    'writing': (0x100, 0x37e),
    'hand': (0x100, 0x204),
    'movement': (0x205, 0x2f6),
    'dynamics': (0x2f7, 0x2fe),
    'head': (0x2ff, 0x36c),
    'trunk': (0x36d, 0x375),
    'limb': (0x376, 0x37e),
    'location': (0x37f, 0x386),
    'punctuation': (0x387, 0x38b)}

def symbol_id(symbol):
    """This basic shape's integer ID.

    A helper function for looking up symbol types. Following the `S`,
    the first three symbols are the hexadecimal number of the symbol
    (up to rotation or similar variation).

    >>> symbol_id('S10350') == 0x103
    True
    >>> symbol_id('2a6') == 0x2a6
    True

    """
    if symbol.startswith('S'):
        return int(symbol[1:4], 16)
    else:
        return int(symbol[:3], 16)

def is_type(symbol, type):
    """Check whether a symbol is of a given type.

    The symbol can be given as ISWA identifier with or without `S`, or
    as the corresponding integer id of the basic shape.

    >>> is_type('S32a00', 'head')
    True
    >>> is_type(0x389, 'punctuation')
    True
    >>> is_type('1da51', 'hand')
    True

    """
    try:
        symbol = symbol_id(symbol)
    except AttributeError:
        pass
    try:
        return (
            symbol_ranges[type][0] <= symbol <= symbol_ranges[type][1])
    except KeyError:
        raise ValueError('No symbol type {:}.'.format(type))

def symbol_type(symbol):
    """Return the type of the symbol.

    >>> symbol_type(0x100)
    'hand'
    >>> symbol_type('S38b00')
    'punctuation'
    >>> symbol_type('S37e00')
    'limb'

    """

    try:
        symbol = symbol_id(symbol)
    except AttributeError:
        pass
    for type, (lower, upper) in symbol_ranges.items():
        if type == 'iswa' or type == 'writing':
            # Not a fundamental type
            continue
        if lower <= symbol <= upper:
            return type
    raise ValueError('Not a valid symbol: {:}'.format(symbol))

def swnumber(string):
    """Convert a KSW number string into an integer.

    A KSW number string is a string of the format 'n?[0-9]+'. The 'n'
    indicates 'negative' numbers.

    >>> swnumber('0092')
    92
    >>> swnumber('200')
    200
    >>> swnumber('n34')
    -34
    >>> swnumber('-34')
    Traceback (most recent call last):
    [...]
    ValueError: Not a valid KSW number string: -34

    """
    if not re.fullmatch('n?[0-9]+', string):
        raise ValueError('Not a valid KSW number string: {:}'.format(
            string))
    if string.startswith('n'):
        return -int(string[1:])
    else:
        return int(string)

def coordinates(sw_substring):
    """Convert a KSW coordinate string into a pair of integers.

    A KSW coordinate string, used for Cartesian coordinates as well as
    dimensions, is a string of the format 'n?[0-9]+xn?[0-9]+' and
    corresponds in an obvious manner to a pair of signed integers.

    >>> coordinates('0092x0108')
    (92, 108)
    >>> coordinates('n15x20')
    (-15, 20)
    >>> coordinates('1x2x3')
    Traceback (most recent call last):
    [...]
    ValueError: Not a valid KSW coordinates string: 1x2x3

    """
    if not COORDINATES.fullmatch(sw_substring):
        raise ValueError(
            'Not a valid KSW coordinates string: {:}'.format(
                sw_substring))
    first, last = sw_substring.split('x')
    return swnumber(first), swnumber(last)

def parse(layout_string):
    """Parse a layout string to array of symbols with placement.

    >>> parse('M18x33S1870an11x15S18701n18xn10S205008xn4S2e7340xn32')
    [('M', (18, 33)), ('S1870a', (-11, 15)), ('S18701', (-18, -10)), ('S20500', (8, -4)), ('S2e734', (0, -32))]

    >>> parse('MS1870an11x15S18701n18xn10S205008xn4S2e7340xn32')
    [('M', (8, 15)), ('S1870a', (-11, 15)), ('S18701', (-18, -10)), ('S20500', (8, -4)), ('S2e734', (0, -32))]

    >>> parse('S38800n36xn4')
    [('B', (36, 4)), ('S38800', (-36, -4))]

    >>> parse('')
    [('M', (0, 0))]
    """
    if not layout_string:
        return [('M', (0, 0))]

    seq = 'A' + ''.join(prefix_symbols(layout_string))
    sw_string = layout_string.replace(seq, '')

    match = re.fullmatch(
        '((' + re_punc + ')(' + COORD_BLOCK + '))|'
        '([BLMR](' + POS_COORD_BLOCK + ')?)'
        '((' + SYMBOL_BLOCK + COORD_BLOCK + ')*)',
        sw_string)

    if not match:
        raise ValueError(
            'String {:} contained unrecognized elements'.format(
                sw_string))

    if match.group(1):
        # This is a punctuation character
        punct = match.group(2)
        coord = coordinates(match.group(3))
        return [
            ('B', (-coord[0], -coord[1])),
            (punct, coord)]
    else:
        # This is some other character

        cluster = []
        max_x = max_y = float('-inf')
        for symbol in re.findall(
                SYMBOL_BLOCK + COORD_BLOCK,
                match.group(6)):
            coord = coordinates(symbol[6:])
            max_x = max(max_x, coord[0])
            max_y = max(max_y, coord[1])
            cluster.append(
                (symbol[:6], coord))
        cluster.insert(
            0, (match.group(4)[0],
                coordinates(match.group(5)) if match.group(5) else (max_x, max_y)))
        return cluster

def min_coordinates(cluster, min_is_zero=True):
    x_min = 0 if min_is_zero else float('inf')
    y_min = 0 if min_is_zero else float('inf')
    for i, (sym, (x, y)) in enumerate(cluster):
        if i == 0:
            continue
        x_min = min(x_min, x)
        y_min = min(y_min, y)
    return x_min, y_min


from .bot import Bot
from ..direction import Direction
from ..tile import Booth
from .algs import BFS

class RealisticBot(Bot):
    """
    RealisticBot aims for the smaller companies because it has the best
    chance of getting a job from a smaller company. It will not visit the
    same company twice, because there is no point in handing a resume out
    twice so it will mark the companies it has visited. It uses a bfs to
    search for the closest small company and move towards that direction.
    It should find a company and retrieve the path.
    """
    def __init__(self, board, loc, speed, id):
        super().__init__(board, loc, speed, id)
        self.queue = []
        self.to_visit = "S"
        self.visited = set()

    def update_to_visit(self):
        if self.to_visit == "S":
            self.to_visit = "M"
        elif self.to_visit == "M":
            self.to_visit = "L"
        else:
            self.to_visit = "S"

    def compute_step(self):
        if not self.is_in_line():
            src = self.loc
            self.queue = BFS(self.board, src,
                             lambda tile: \
                             self.board.booths.get(tile.get_booth()) and \
                             self.board.booths.get(tile.get_booth()).get_size() == self.to_visit \
                             and tile.get_booth() not in self.visited)
            while self.queue is None:
                self.update_to_visit()
                self.visited = set()
                self.queue = BFS(self.board, src,
                                 lambda tile: \
                                 self.board.booths.get(tile.get_booth()) and \
                                 self.board.booths.get(tile.get_booth()).get_size() == self.to_visit \
                                 and tile.get_booth() not in self.visited)
            self.queue = BFS(self.board, src, lambda tile: tile.get_line() == self.board.get(self.queue[-1]).get_booth())

        if self.queue:
            if self.loc == self.queue[0]:
                self.queue.pop(0)
            if self.queue:
                first_tile = self.queue[0]
                self.new_direction = Direction.get_dir(self.loc, first_tile)
            else:
                self.new_direction = Direction.ENTER
                self.visited.add(self.board.get(self.loc).get_line())


class Solution:
    def count(self, nums: list[int]) -> tuple[int, int]:
        prev = None
        cnt = 0
        maxCnt, totCnt = -inf, 0
        for x in chain(nums, [0]):
            if x == prev:
                cnt += 1
            else:
                if cnt > 0:
                    maxCnt = max(maxCnt, cnt)
                    totCnt += cnt
                cnt = 1
                prev = x
        return maxCnt, totCnt

    def canDivideIntoSubsequences(self, nums: List[int], K: int) -> bool:
        maxCnt, totCnt = self.count(nums)
        return (totCnt - maxCnt) // maxCnt >= (K-1)


# Largely stolen from https://github.com/jmoiron/humanize (MIT)

from datetime import datetime, timedelta

def _ngettext(message, plural, num):
    return message if num == 1 else plural

def _now():
    return datetime.now()

def abs_timedelta(delta):
    """Returns an "absolute" value for a timedelta, always representing a
    time distance."""
    if delta.days < 0:
        now = _now()
        return now - (now + delta)
    return delta

def date_and_delta(value):
    """Turn a value into a date and a timedelta which represents how long ago
    it was.  If that's not possible, return (None, value)."""
    now = _now()
    if isinstance(value, datetime):
        date = value
        delta = now - value
    elif isinstance(value, timedelta):
        date = now - value
        delta = value
    else:
        try:
            value = int(value)
            delta = timedelta(seconds=value)
            date = now - delta
        except (ValueError, TypeError):
            return (None, value)
    return date, abs_timedelta(delta)

def naturaldelta(value, months=True):
    """Given a timedelta or a number of seconds, return a natural
    representation of the amount of time elapsed.  This is similar to
    ``naturaltime``, but does not add tense to the result.  If ``months``
    is True, then a number of months (based on 30.5 days) will be used
    for fuzziness between years."""
    date, delta = date_and_delta(value)
    if date is None:
        return value

    use_months = months

    seconds = abs(delta.seconds)
    days = abs(delta.days)
    years = days // 365
    days = days % 365
    months = int(days // 30.5)

    if not years and days < 1:
        if seconds < 60:
            return "a moment"
        elif 60 <= seconds < 120:
            return "a minute"
        elif 120 <= seconds < 3600:
            minutes = seconds // 60
            return _ngettext("%d minute", "%d minutes", minutes) % minutes
        elif 3600 <= seconds < 3600 * 2:
            return "an hour"
        elif 3600 < seconds:
            hours = seconds // 3600
            return _ngettext("%d hour", "%d hours", hours) % hours
    elif years == 0:
        if days == 1:
            return "a day"
        if not use_months:
            return _ngettext("%d day", "%d days", days) % days
        else:
            if not months:
                return _ngettext("%d day", "%d days", days) % days
            elif months == 1:
                return "a month"
            else:
                return _ngettext("%d month", "%d months", months) % months
    elif years == 1:
        if not months and not days:
            return "a year"
        elif not months:
            return _ngettext("1 year, %d day", "1 year, %d days", days) % days
        elif use_months:
            if months == 1:
                return "1 year, 1 month"
            else:
                return (
                    _ngettext("1 year, %d month", "1 year, %d months", months)
                    % months
                )
        else:
            return _ngettext("1 year, %d day", "1 year, %d days", days) % days
    else:
        return _ngettext("%d year", "%d years", years) % years

def naturaltime(value, future=False, months=True):
    """Given a datetime or a number of seconds, return a natural representation
    of that time in a resolution that makes sense.  This is more or less
    compatible with Django's ``naturaltime`` filter.  ``future`` is ignored for
    datetimes, where the tense is always figured out based on the current time.
    If an integer is passed, the return value will be past tense by default,
    unless ``future`` is set to True."""
    now = _now()
    date, delta = date_and_delta(value)
    if date is None:
        return value
    # determine tense by value only if datetime/timedelta were passed
    if isinstance(value, (datetime, timedelta)):
        future = date > now

    ago = "%s from now" if future else "%s ago"
    delta = naturaldelta(delta, months)

    if delta == "a moment":
        return "now"

    return ago % delta

suffixes = ("kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")

def naturalsize(value, format="%.1f"):
    """Format a number of byteslike a human readable filesize (eg. 10 kB) """

    base = 1024
    bytes = float(value)

    if bytes == 1:
        return "1 Byte"
    elif bytes < base:
        return "%d Bytes" % bytes

    for i, s in enumerate(suffixes):
        unit = base ** (i + 2)
        if bytes < unit:
            return (format + " %s") % ((base * bytes / unit), s)
    return (format + " %s") % ((base * bytes / unit), s)


import urllib.parse

from flask import request

from sqlalchemy import select

from FashionCampus.database import session
from FashionCampus.common import get_image_url
from FashionCampus.model import Product, ProductImage

from FashionCampus.api.blueprints import home

@home.route('/home/banner', methods = ['GET'])
def home_get_banner():
    db = session()

    products = db.execute(select(
        Product.id,
        Product.name,
        ProductImage.path.label('image_path')
    ).join(Product.images.and_(ProductImage.order == 1), isouter = True).where(Product.is_deleted == False).order_by(Product.created_at.desc()).limit(5)).fetchall()

    return {
        'data': [
            {
                'id': str(p.id),
                'image': get_image_url(p.image_path),
                'title': p.name
            } for p in products
        ]
    }, 200


import copy
import cv2
import glob
import os
import pathlib
import sys
import time
import xml
import xml.etree.ElementTree as ET

from . import utils
from .. import procs

# Add import path for submodules
currentdir = pathlib.Path(__file__).resolve().parent
sys.path.append(str(currentdir) + "/../../submodules/separate_pages_ssd")
sys.path.append(str(currentdir) + "/../../submodules/ndl_layout")
sys.path.append(str(currentdir) + "/../../submodules/deskew_HT")
sys.path.append(str(currentdir) + "/../../submodules/text_recognition_lightning")
sys.path.append(str(currentdir) + "/../../submodules/reading_order")

# supported image type list
supported_img_ext = ['.jpg', '.jpeg', '.jp2']

class OcrInferrer:
    """
    推論実行時の関数や推論の設定値を保持します。

    Attributes
    ----------
    full_proc_list : list
        全推論処理のリストです。
    proc_list : list
        本実行処理における推論処理のリストです。
    cfg : dict
        本実行処理における設定情報です。
    """

    def __init__(self, cfg):
        """
        Parameters
        ----------
        cfg : dict
            本実行処理における設定情報です。
        """
        # inference process class list in order
        self.full_proc_list = [
            procs.PageSeparation,           # 0: ノド元分割               出力：（画像：あり、XML：なし、TXT：なし）
            procs.PageDeskewProcess,        # 1: 傾き補正                 出力：（画像：あり、XML：なし、TXT：なし）
            procs.LayoutExtractionProcess,  # 2: レイアウト抽出           出力：（画像：あり、XML：あり、TXT：なし）
            procs.LineOcrProcess,           # 3: 文字認識(OCR)            出力：（画像：あり、XML：あり、TXT：あり）
        ]
        self.proc_list = self._create_proc_list(cfg)
        self.cfg = cfg
        self.total_time_statistics = []
        self.proc_time_statistics = {}
        for proc in self.proc_list:
            self.proc_time_statistics[proc.proc_name] = []
        self.xml_template = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>\n<OCRDATASET></OCRDATASET>'

    def run(self):
        """
        self.cfgに保存された設定に基づいた推論処理を実行します。
        """
        if len(self.cfg['input_dirs']) == 0:
            print('[ERROR] Input directory list is empty', file=sys.stderr)
            return

        # input dir loop
        for input_dir in self.cfg['input_dirs']:
            if self.cfg['input_structure'] in ['t']:
                single_outputdir_data_list = self._get_single_dir_data_from_tosho_data(input_dir)
            else:
                single_outputdir_data_list = self._get_single_dir_data(input_dir)

            if single_outputdir_data_list is None:
                print('[ERROR] Input data list is empty', file=sys.stderr)
                continue
            print(single_outputdir_data_list)
            # do infer with input data for single output data dir
            for single_outputdir_data in single_outputdir_data_list:
                if single_outputdir_data is None:
                    continue
                if self.cfg['ruby_only']:
                    pred_list = self._infer_ruby_only(single_outputdir_data)
                else:
                    pred_list = self._infer(single_outputdir_data)

                # save inferenced xml in xml directory
                if (self.cfg['save_xml'] or self.cfg['partial_infer']) and (self.cfg['proc_range']['end'] > 1):
                    self._save_pred_xml(single_outputdir_data['output_dir'], [single_data['xml'] for single_data in pred_list], self.cfg['line_order'])
        if len(self.total_time_statistics) == 0:
            print('================== NO VALID INFERENCE ==================')
        else:
            print('================== PROCESSING TIME ==================')
            for proc_name, proc_time_list in self.proc_time_statistics.items():
                proc_averaege = sum(proc_time_list) / len(proc_time_list)
                print(f'Average processing time ({proc_name})'.ljust(45, ' ') + f': {proc_averaege:8.4f} sec / image file ')
            total_average = sum(self.total_time_statistics) / len(self.total_time_statistics)
            print(f'Average processing time (total)'.ljust(45, ' ') + f': {total_average:8.4f} sec / image file ')
        return

    def _infer_ruby_only(self, single_outputdir_data):
        """
        self.cfgに保存された設定に基づき、XML一つ分のデータに対するルビ推定処理を実行します。

        Parameters
        ----------
        single_outputdir_data : dict
            XML一つ分のデータ（基本的に1書籍分を想定）の入力データ情報。
            入力となるXMLデータを含みます。

        Returns
        -------
        pred_list : list
            1ページ分の推論結果を要素に持つ推論結果のリスト。
            各結果は辞書型で保持されています。
        """
        # single_outputdir_data dictionary include [key, value] pairs as below
        # [key, value]: ['img', None], ['xml', xml_tree]
        pred_list = []
        pred_xml_dict_for_dump = {}

        for page_idx, page_xml in enumerate(single_outputdir_data['xml'].findall('PAGE')):
            single_image_file_data = self._get_single_image_file_data(page_idx, single_outputdir_data)
            if single_image_file_data is None:
                print('[ERROR] Failed to get single page input data.')
                continue

            print('######## START PAGE INFERENCE PROCESS ########')
            start_page = time.time()

            for proc in self.proc_list:
                start_proc = time.time()
                single_page_output = []
                for idx, single_data_input in enumerate(single_image_file_data):
                    single_data_output = proc.do(idx, single_data_input)
                    single_page_output.extend(single_data_output)

                single_image_file_data = single_page_output
                self.proc_time_statistics[proc.proc_name].append(time.time() - start_proc)

            single_image_file_output = single_image_file_data
            self.total_time_statistics.append(time.time() - start_page)

            # save inferenced result text for this page
            sum_main_txt = ''
            sum_cap_txt = ''
            sum_ruby_txt = ''

            # check if xml output for this image is vertical text
            vertical_text_page = 0
            for single_data_output in single_image_file_output:
                if self._is_vertical_text_xml(single_data_output['xml']):
                    vertical_text_page += 1

            # reverse order of page if all pages are vertical text
            single_image_file_output_for_txt = single_image_file_output
            if vertical_text_page >= len(single_image_file_output):
                single_image_file_output_for_txt = list(reversed(single_image_file_output))

            for single_data_output in single_image_file_output_for_txt:
                main_txt, cap_txt = self._create_result_txt(single_data_output['xml'])
                sum_main_txt += main_txt + '\n'
                sum_cap_txt += sum_cap_txt + '\n'
                sum_ruby_txt += single_data_output['ruby_txt'] + '\n'

                self._save_pred_txt(sum_main_txt, sum_cap_txt, sum_ruby_txt, page_xml.attrib['IMAGENAME'], single_outputdir_data['output_dir'])

            # add inference result for single image file data to pred_list, including XML data
            pred_list.extend(single_image_file_output)
            print('########  END PAGE INFERENCE PROCESS  ########')

        return pred_list

    def _infer(self, single_outputdir_data):
        """
        self.cfgに保存された設定に基づき、XML一つ分のデータに対する推論処理を実行します。

        Parameters
        ----------
        single_outputdir_data : dict
            XML一つ分のデータ（基本的に1書籍分を想定）の入力データ情報。
            画像ファイルパスのリスト、それらに対応するXMLデータを含みます。

        Returns
        -------
        pred_list : list
            1ページ分の推論結果を要素に持つ推論結果のリスト。
            各結果は辞書型で保持されています。
        """
        # single_outputdir_data dictionary include [key, value] pairs as below
        # (xml is not always included)
        #   [key, value]: ['img', numpy.ndarray], ['xml', xml_tree]
        pred_list = []
        pred_xml_dict_for_dump = {}
        if self.cfg['dump']:
            dump_dir = os.path.join(single_outputdir_data['output_dir'], 'dump')
            os.makedirs(dump_dir, exist_ok=True)

            for proc in self.proc_list:
                pred_xml_dict_for_dump[proc.proc_name] = []
                proc_dump_dir = os.path.join(dump_dir, proc.proc_name)
                os.makedirs(proc_dump_dir, exist_ok=True)

        for img_path in single_outputdir_data['img_list']:
            single_image_file_data = self._get_single_image_file_data(img_path, single_outputdir_data)
            output_dir = single_outputdir_data['output_dir']
            if single_image_file_data is None:
                print('[ERROR] Failed to get single page input data for image:{0}'.format(img_path), file=sys.stderr)
                continue

            print('######## START PAGE INFERENCE PROCESS ########')
            start_page = time.time()

            for proc in self.proc_list:
                start_proc = time.time()
                single_page_output = []
                for idx, single_data_input in enumerate(single_image_file_data):
                    single_data_output = proc.do(idx, single_data_input)
                    single_page_output.extend(single_data_output)
                # save inference result data to dump
                if self.cfg['dump'] and 'xml' in single_image_file_data[0].keys():
                    pred_xml_dict_for_dump[proc.proc_name].append(single_image_file_data[0]['xml'])

                single_image_file_data = single_page_output
                self.proc_time_statistics[proc.proc_name].append(time.time() - start_proc)

            single_image_file_output = single_image_file_data
            self.total_time_statistics.append(time.time() - start_page)

            if self.cfg['save_image'] or self.cfg['partial_infer']:
                # save inferenced result drawn image in pred_img directory
                for single_data_output in single_image_file_output:
                    # save input image while partial inference
                    if self.cfg['partial_infer']:
                        img_output_dir = os.path.join(output_dir, 'img')
                        self._save_image(single_data_output['img'], single_data_output['img_file_name'], img_output_dir)

                    pred_img = self._create_result_image(single_data_output, self.proc_list[-1].proc_name)
                    img_output_dir = os.path.join(output_dir, 'pred_img')
                    self._save_image(pred_img, single_data_output['img_file_name'], img_output_dir)

            # save inferenced result text for this page
            if self.cfg['proc_range']['end'] > 2:
                sum_main_txt = ''
                sum_cap_txt = ''
                sum_ruby_txt = None
                if self.cfg['ruby_read']:
                    sum_ruby_txt = ''

                # check if xml output for this image is vertical text
                vertical_text_page = 0
                for single_data_output in single_image_file_output:
                    if self._is_vertical_text_xml(single_data_output['xml']):
                        vertical_text_page += 1

                # reverse order of page if it's vertical text
                single_image_file_output_for_txt = single_image_file_output
                if vertical_text_page >= len(single_image_file_output):
                    single_image_file_output_for_txt = list(reversed(single_image_file_output))

                for single_data_output in single_image_file_output_for_txt:
                    main_txt, cap_txt = self._create_result_txt(single_data_output['xml'])
                    sum_main_txt += main_txt + '\n'
                    sum_cap_txt += sum_cap_txt + '\n'
                    if self.cfg['ruby_read']:
                        sum_ruby_txt += single_data_output['ruby_txt'] + '\n'

                self._save_pred_txt(sum_main_txt, sum_cap_txt, sum_ruby_txt, os.path.basename(img_path), single_outputdir_data['output_dir'])

            # add inference result for single image file data to pred_list, including XML data
            pred_list.extend(single_image_file_output)
            print('########  END PAGE INFERENCE PROCESS  ########')

        return pred_list

    def _get_single_dir_data(self, input_dir):
        """
        XML一つ分の入力データに関する情報を整理して取得します。

        Parameters
        ----------
        input_dir : str
            XML一つ分の入力データが保存されているディレクトリパスです。

        Returns
        -------
        # Fixme
        single_dir_data : dict
            XML一つ分のデータ（基本的に1PID分を想定）の入力データ情報です。
            画像ファイルパスのリスト、それらに対応するXMLデータを含みます。
        """
        single_dir_data = {'input_dir': os.path.abspath(input_dir)}
        single_dir_data['img_list'] = []

        # get img list of input directory
        if not self.cfg['ruby_only']:
            if self.cfg['input_structure'] in ['w']:
                for ext in supported_img_ext:
                    single_dir_data['img_list'].extend(sorted(glob.glob(os.path.join(input_dir, '*{0}'.format(ext)))))
            elif self.cfg['input_structure'] in ['f']:
                stem, ext = os.path.splitext(os.path.basename(input_dir))
                if ext in supported_img_ext:
                    single_dir_data['img_list'] = [input_dir]
                else:
                    print('[ERROR] This file is not supported type : {0}'.format(input_dir), file=sys.stderr)
            elif not os.path.isdir(os.path.join(input_dir, 'img')):
                print('[ERROR] Input img diretctory not found in {}'.format(input_dir), file=sys.stderr)
                return None
            else:
                for ext in supported_img_ext:
                    single_dir_data['img_list'].extend(sorted(glob.glob(os.path.join(input_dir, 'img/*{0}'.format(ext)))))

        # check xml file number and load xml data if needed
        if (self.cfg['proc_range']['start'] > 2) or self.cfg['ruby_only']:
            if self.cfg['input_structure'] in ['f']:
                print('[ERROR] Single image file input mode does not support partial inference wich need xml file input.', file=sys.stderr)
                return None
            input_xml = None
            xml_file_list = glob.glob(os.path.join(input_dir, 'xml/*.xml'))
            if len(xml_file_list) > 1:
                print('[ERROR] Input xml file must be only one, but there is {0} xml files in {1}.'.format(
                    len(xml_file_list), os.path.join(self.cfg['input_root'], 'xml')), file=sys.stderr)
                return None
            elif len(xml_file_list) == 0:
                print('[ERROR] There is no input xml files in {0}.'.format(os.path.join(input_dir, 'xml')), file=sys.stderr)
                return None
            else:
                input_xml = xml_file_list[0]
            try:
                single_dir_data['xml'] = ET.parse(input_xml)
            except xml.etree.ElementTree.ParseError as err:
                print("[ERROR] XML parse error : {0}".format(input_xml), file=sys.stderr)
                return None

        # prepare output dir for inferensce result with this input dir
        if self.cfg['input_structure'] in ['f']:
            stem, ext = os.path.splitext(os.path.basename(input_dir))
            output_dir = os.path.join(self.cfg['output_root'], stem)
        elif self.cfg['input_structure'] in ['i', 's']:
            dir_name = os.path.basename(input_dir)
            output_dir = os.path.join(self.cfg['output_root'], dir_name)
        elif self.cfg['input_structure'] in ['w']:
            input_dir_names = input_dir.split('/')
            dir_name = input_dir_names[-3][0] + input_dir_names[-2] + input_dir_names[-1]
            output_dir = os.path.join(self.cfg['output_root'], dir_name)
        else:
            print('[ERROR] Unexpected input directory structure type: {}.'.format(self.cfg['input_structure']), file=sys.stderr)
            return None

        # output directory existence check
        output_dir = utils.mkdir_with_duplication_check(output_dir)
        single_dir_data['output_dir'] = output_dir

        return [single_dir_data]

    def _get_single_dir_data_from_tosho_data(self, input_dir):
        """
        XML一つ分の入力データに関する情報を整理して取得します。

        Parameters
        ----------
        input_dir : str
            tosho data形式のセクションごとのディレクトリパスです。

        Returns
        -------
        single_dir_data_list : list
            XML一つ分のデータ（基本的に1PID分を想定）の入力データ情報のリストです。
            1つの要素に画像ファイルパスのリスト、それらに対応するXMLデータを含みます。
        """

        if self.cfg['ruby_only']:
            print("[ERROR] tosho_data input mode doesn't support ruby_only mode.", file=sys.stderr)
            return None

        single_dir_data_list = []

        # get img list of input directory
        tmp_img_list = sorted(glob.glob(os.path.join(input_dir, '*.jp2')))
        tmp_img_list.extend(sorted(glob.glob(os.path.join(input_dir, '*.jpg'))))

        pid_list = []
        for img in tmp_img_list:
            pid = os.path.basename(img).split('_')[0]
            if pid not in pid_list:
                pid_list.append(pid)

        for pid in pid_list:
            single_dir_data = {'input_dir': os.path.abspath(input_dir),
                               'img_list': [img for img in tmp_img_list if os.path.basename(img).startswith(pid)]}

            # prepare output dir for inferensce result with this input dir
            output_dir = os.path.join(self.cfg['output_root'], pid)

            # output directory existance check
            os.makedirs(output_dir, exist_ok=True)
            single_dir_data['output_dir'] = output_dir
            single_dir_data_list.append(single_dir_data)

        return single_dir_data_list

    def _get_single_image_file_data(self, img_path, single_dir_data):
        """
        1ページ分の入力データに関する情報を整理して取得します。

        Parameters
        ----------
        img_path : str
            入力画像データのパスです。
        single_dir_data : dict
            1書籍分の入力データに関する情報を保持する辞書型データです。
            xmlファイルへのパス、結果を出力するディレクトリのパスなどを含みます。

        Returns
        -------
        single_image_file_data : dict
            1ページ分のデータの入力データ情報です。
            画像ファイルのパスとnumpy.ndarray形式の画像データ、その画像に対応するXMLデータを含みます。
        """
        single_image_file_data = [{
            'img_path': img_path,
            'img_file_name': os.path.basename(img_path) if isinstance(img_path, str) else None,
            'output_dir': single_dir_data['output_dir']
        }]

        full_xml = None
        if 'xml' in single_dir_data.keys():
            full_xml = single_dir_data['xml']

        # get img data for single page
        if isinstance(img_path, str):
            orig_img = cv2.imread(img_path)
            if orig_img is None:
                print('[ERROR] Image read error : {0}'.format(img_path), file=sys.stderr)
                return None
            single_image_file_data[0]['img'] = orig_img

        # return if this proc needs only img data for input
        if full_xml is None:
            return single_image_file_data

        if self.cfg['ruby_only']:
            tmp_idx = 0
            for page in full_xml.getroot().iter('PAGE'):
                if tmp_idx == img_path:
                    node = ET.fromstring(self.xml_template)
                    node.append(page)
                    tree = ET.ElementTree(node)
                    single_image_file_data[0]['xml'] = tree
                    break
                tmp_idx += 1
            return single_image_file_data

        # get xml data for single page
        image_name = os.path.basename(img_path)
        for page in full_xml.getroot().iter('PAGE'):
            if page.attrib['IMAGENAME'] == image_name:
                node = ET.fromstring(self.xml_template)
                node.append(page)
                tree = ET.ElementTree(node)
                single_image_file_data[0]['xml'] = tree
                break

        if 'xml' not in single_image_file_data[0].keys():
            print('[ERROR] Input PAGE data for page {} not found in XML data.'.format(img_path), file=sys.stderr)
            return None

        return single_image_file_data

    def _create_proc_list(self, cfg):
        """
        推論の設定情報に基づき、実行する推論処理のリストを作成します。

        Parameters
        ----------
        cfg : dict
            推論実行時の設定情報を保存した辞書型データ。
        """
        if cfg['ruby_only']:
            return [procs.RubyReadingProcess(cfg, 'ex2')]

        proc_list = []
        for i in range(cfg['proc_range']['start'], cfg['proc_range']['end'] + 1):
            proc_list.append(self.full_proc_list[i](cfg, i))
        if cfg['line_order']:
            if cfg['proc_range']['end'] <= 2:
                print('[WARNING] LineOrderProcess will be skipped(this process needs LineOcrProcess output).')
            else:
                proc_list.append(procs.LineOrderProcess(cfg, 'ex1'))
        if cfg['ruby_read']:
            if cfg['proc_range']['end'] <= 2 or not cfg['line_order']:
                print('[WARNING] RubyReadingProcess will be skipped(this process needs LineOrderProcess output).')
            else:
                proc_list.append(procs.RubyReadingProcess(cfg, 'ex2'))
        if cfg['line_attribute']['add_title_author']:
            if cfg['proc_range']['end'] <= 2:
                print('[WARNING] LineAttributeProcess will be skipped(this process needs LineOcrProcess output).')
            else:
                proc_list.append(procs.LineAttributeProcess(cfg, 'ex3'))

        return proc_list

    def _save_pred_xml(self, output_dir, pred_list, sorted):
        """
        推論結果のXMLデータをまとめたXMLファイルを生成して保存します。

        Parameters
        ----------
        output_dir : str
            推論結果を保存するディレクトリのパスです。
        pred_list : list
            1ページ分の推論結果を要素に持つ推論結果のリスト。
            各結果は辞書型で保持されています。
        sorted : bool
            読み順認識が実行されたかどうかのフラグ。
        """
        xml_dir = os.path.join(output_dir, 'xml')
        os.makedirs(xml_dir, exist_ok=True)

        # basically, output_dir is supposed to be PID, so it used as xml filename
        if sorted:
            xml_path = os.path.join(xml_dir, '{}.sorted.xml'.format(os.path.basename(output_dir)))
        else:
            xml_path = os.path.join(xml_dir, '{}.xml'.format(os.path.basename(output_dir)))
        pred_xml = self._parse_pred_list_to_save(pred_list)
        utils.save_xml(pred_xml, xml_path)
        return

    def _save_image(self, pred_img, orig_img_name, img_output_dir, id=''):
        """
        指定されたディレクトリに画像データを保存します。
        画像データは入力に使用したものと推論結果を重畳したものの２種類が想定されています。

        Parameters
        ----------
        pred_img : numpy.ndarray
            保存する画像データ。
        orig_img_name : str
            もともとの入力画像のファイル名。
            基本的にはこのファイル名と同名で保存します。
        img_output_dir : str
            画像ファイルの保存先のディレクトリパス。
        id : str
            もともとの入力画像のファイル名に追加する処理結果ごとのidです。
            一つの入力画像から複数の画像データが出力される処理がある場合に必要になります。
        """
        os.makedirs(img_output_dir, exist_ok=True)
        stem, ext = os.path.splitext(orig_img_name)
        orig_img_name = stem + '.jpg'

        if id != '':
            stem, ext = os.path.splitext(orig_img_name)
            orig_img_name = stem + '_' + id + ext

        img_path = os.path.join(img_output_dir, orig_img_name)
        try:
            cv2.imwrite(img_path, pred_img)
        except OSError as err:
            print("[ERROR] Image save error: {0}".format(err), file=sys.stderr)
            raise OSError

        return

    def _save_pred_txt(self, main_txt, cap_txt, ruby_txt, orig_img_name, output_dir):
        """
        指定されたディレクトリに推論結果のテキストデータを保存します。

        Parameters
        ----------
        main_txt : str
            本文＋キャプションの推論結果のテキストデータです
        cap_txt : str
            キャプションのみの推論結果のテキストデータです
        ruby_txt : str
            ルビのみの推論結果のテキストデータです
        orig_img_name : str
            もともとの入力画像ファイル名。
            基本的にはこのファイル名と同名で保存します。
        img_output_dir : str
            画像ファイルの保存先のディレクトリパス。
        """
        txt_dir = os.path.join(output_dir, 'txt')
        os.makedirs(txt_dir, exist_ok=True)

        stem, _ = os.path.splitext(orig_img_name)
        txt_path = os.path.join(txt_dir, stem + '_cap.txt')
        try:
            with open(txt_path, 'w') as f:
                f.write(cap_txt)
        except OSError as err:
            print("[ERROR] Caption text save error: {0}".format(err), file=sys.stderr)
            raise OSError

        stem, _ = os.path.splitext(orig_img_name)
        txt_path = os.path.join(txt_dir, stem + '_main.txt')
        try:
            with open(txt_path, 'w') as f:
                f.write(main_txt)
        except OSError as err:
            print("[ERROR] Main text save error: {0}".format(err), file=sys.stderr)
            raise OSError

        if ruby_txt is not None:
            stem, _ = os.path.splitext(orig_img_name)
            txt_path = os.path.join(txt_dir, stem + '_ruby.txt')
            try:
                with open(txt_path, 'w') as f:
                    f.write(ruby_txt)
            except OSError as err:
                print("[ERROR] Ruby text save error: {0}".format(err), file=sys.stderr)
                raise OSError

        return

    def _parse_pred_list_to_save(self, pred_list):
        """
        推論結果のXMLを要素に持つリストから、ファイルに保存するための一つのXMLデータを生成します。

        Parameters
        ----------
        pred_list : list
            推論結果のXMLを要素に持つリスト。
        """
        ET.register_namespace('', 'NDLOCRDATASET')
        node = ET.fromstring(self.xml_template)
        for single_xml_tree in pred_list:
            root = single_xml_tree.getroot()
            for element in root:
                node.append(element)

        tree = ET.ElementTree(node)
        return tree

    def _create_result_image(self, result, proc_name):
        """
        推論結果を入力画像に重畳した画像データを生成します。

        Parameters
        ----------
        result : dict
            1ページ分の推論結果を持つ辞書型データ。
        proc_name : str
            重畳を行う結果を出力した推論処理の名前。
        """
        if 'dump_img' in result.keys():
            dump_img = copy.deepcopy(result['dump_img'])
        else:
            dump_img = copy.deepcopy(result['img'])
        if 'xml' in result.keys() and result['xml'] is not None:
            # draw inference result on input image
            cv2.putText(dump_img, proc_name, (0, 50),
                        cv2.FONT_HERSHEY_PLAIN, 4, (0, 0, 0), 5, cv2.LINE_AA)
            pass
        else:
            cv2.putText(dump_img, proc_name, (0, 50),
                        cv2.FONT_HERSHEY_PLAIN, 4, (0, 0, 0), 5, cv2.LINE_AA)
        return dump_img

    def _create_result_txt(self, xml_data):
        """
        推論結果のxmlデータからテキストデータを生成します。

        Parameters
        ----------
        xml_data :
            1ページ分の推論結果を持つxmlデータ。
        """
        main_txt = ''
        cap_txt = ''
        for page_xml in xml_data.iter('PAGE'):
            for line_xml in page_xml.iter('LINE'):
                main_txt += line_xml.attrib['STRING']
                main_txt += '\n'
                if line_xml.attrib['TYPE'] == 'キャプション':
                    cap_txt += line_xml.attrib['STRING']
                    cap_txt += '\n'

        return main_txt, cap_txt

    def _is_vertical_text_xml(self, xml_data):
        """
        与えられたxmlデータが縦書きテキストかどうか判定します

        Parameters
        ----------
        xml_data :
            1ページ分の推論結果を持つxmlデータ。
        """
        all_line_num = 0
        vertical_line_num = 0
        for page_xml in xml_data.iter('PAGE'):
            for line_xml in page_xml.iter('LINE'):
                w = int(line_xml.attrib['WIDTH'])
                h = int(line_xml.attrib['HEIGHT'])
                if w < h:
                    vertical_line_num += 1
                all_line_num += 1
        return (all_line_num / 2) < vertical_line_num


pkgname = "weechat"
pkgver = "4.0.5"
pkgrel = 0
build_style = "cmake"
configure_args = [
    # no guile available
    "-DENABLE_GUILE=False",
    # no php available
    "-DENABLE_PHP=False",
    # no v8 available
    "-DENABLE_JAVASCRIPT=False",
    # no, aspell available
    "-DENABLE_ENCHANT=True",
    # missing dependencies
    "-DENABLE_TESTS=False",
    "-DENABLE_MAN=False",
    "-DENABLE_DOC=False",
]
hostmakedepends = ["cmake", "ninja", "pkgconf"]
makedepends = [
    # core deps
    "libgcrypt-devel",
    "gnutls-devel",
    "zstd-devel",
    "libcurl-devel",
    "ncurses-devel",
    # perl plugin
    "perl",
    # lua plugin
    "lua5.4-devel",
    # pyhton plugin
    "python-devel",
    # relay plugin
    "zlib-devel",
    # ruby plugin
    "ruby-devel",
    # spell plugin
    "enchant-devel",
    # tcl plugin
    "tcl-devel",
]
pkgdesc = "Extensible chat client"
maintainer = "eater <=@eater.me>"
license = "GPL-3.0-or-later"
url = "https://weechat.org"
source = f"https://weechat.org/files/src/weechat-{pkgver}.tar.gz"
sha256 = "4564caf767ccac6c9ed51ac12bade83bd040f42931dd76a81f82a9e3ba0ee57c"

@subpackage("weechat-devel")
def _devel(self):
    return self.default_devel()

def _plugin(name):
    @subpackage(f"weechat-{name}")
    def _plg(self):
        self.pkgdesc = f"{pkgdesc} ({name.capitalize()} plugin)"
        self.depends = [f"{pkgname}={pkgver}-r{pkgrel}"]

        return [f"usr/lib/weechat/plugins/{name}.so"]

for _p in ["lua", "python", "ruby", "tcl", "perl"]:
    _plugin(_p)


import copy

class Arguments:
    def __init__(self):
        self.batch_size = 64
        self.test_batch_size = 64
        self.local_epochs = 2
        self.lr = 0.0005
        self.save_model = True
        self.global_round = 200
        # 'cifar10'   'mnist'
        self.dataset_name = 'cifar10'
        if self.dataset_name == 'mnist':
            self.deep_model_layer_name = 'fc4.weight'
            self.model_name = "mnist"
        else:
            self.deep_model_layer_name = 'fc3.weight'  # 'fc3.weight'
            self.model_name = "NewCifar10"
        self.dataset_labels_number = 10
        self.worker_num = 100
        self.test_worker_num = 200
        self.worker_train = 10
        self.cluster_worker_train = 2

        self.MaxProcessNumber = 3

        self.optim = 'Adam' # 'SGD', 'Adam'

        # 每个本地客户端分配的数据数量
        self.local_data_size = 0.4
        self.rot_local_data_size = 200
        self.data_classes_dict = {'cifar10': 10, 'mnist': 10}
        self.data_classes = self.data_classes_dict[self.dataset_name]
        # 每个本地客户端分配的数据标签类别占比
        self.local_data_classes = 0.4
        # 数据分布
        self.dataset_labels_num = 10
        self.data_info = {'data_labels': [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]],
                          # [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]
                          # [[0, 1, 2, 3, 4], [1, 2, 3], [5, 6, 7, 8, 9], [6, 7, 8], [0, 4, 5, 9]]
                          # [[0, 1, 2, 3], [2, 3, 4, 5], [4, 5, 6, 7], [6, 7, 8, 9], [0, 1, 8, 9]]
                          'data_rot': [0, 1, 2, 3],
                          'divide_type': 'labels'
                          }# 'rot'

        self.cluster_number = len(self.data_info["data_labels"]) if self.data_info["divide_type"]=="labels" else len(self.data_info["data_rot"])
        self.cuda = True
        self.save_path = ""
        if len(self.data_info) > 0:
            self.save_path = self.get_file_name() + '_cluster_self_data' + str(self.worker_train)+"_"+str(self.cluster_worker_train)
        else:
            self.save_path = self.get_file_name() + '_cluster_' + str(self.worker_train) + "_" + str(self.cluster_worker_train)
        self.Arg_string = ''
        self.kMeansArgs = KMeansArgs()

    def get_file_name(self):
        return str(self.local_data_size)+'_'+str(self.local_data_classes) + '_' + self.dataset_name

    def list_all_member(self):
        text = ''
        for name, value in vars(self).items():
            text += str(name) + ":  " + str(value) + '\n'

        return text

    def to_string(self, text=''):
        self.Arg_string = '实验描述：\n' + text + '\n' + '**************************\n' + self.list_all_member()

    def save_dict(self):
        str_dict = {'algorithm_name': "", 'acc': 0, 'loss': 0, 'traffic': 0,'final_cluster_number': 0,'extra_param':"",
            'batch_size': self.batch_size, 'local_epoch': self.local_epochs, 'lr': self.lr,
                    'global_round': self.global_round, 'dataset': self.dataset_name, 'model': self.model_name,
                    'worker_num': self.worker_num, 'worker_train': self.worker_train,
                    'deep_model_name': self.deep_model_layer_name, 'optim': self.optim,
                    'data_type': self.data_info["divide_type"],
                    'data_info': self.data_info["data_labels"] if self.data_info["divide_type"] == "labels" else
                    self.data_info["data_rot"],
                    'acc_list': [],
                    'loss_list': []}
        return str_dict

    def quant_save_dict(self):
        str_dict = {
            "algorithm_name": "",
            'acc': 0,
            'loss': 0,
            "acc_list":[],
            "loss_list":[],
            'data_info': self.data_info["data_labels"] if self.data_info["divide_type"] == "labels" else self.data_info["data_rot"],
            'dataset': self.dataset_name,
            'model': self.model_name,
            'batch_size': self.batch_size,
            'local_epoch': self.local_epochs,
            'lr': self.lr,
            'optim': self.optim,
        }
        return str_dict

class KMeansArgs:
    def __init__(self):
        self.K = 5
        self.max_iter = 50
        self.local_epoch = 5

class ClientInServerData:
    def __init__(self, ID: int, ModelDict, inClusterID, Round):
        self.ClientID: int = ID
        self.InClusterID = inClusterID
        self.ModelStaticDict = ModelDict
        self.PreModelStaticDict = None
        self.DataLen = 0
        # 描述当前客户端最新的参与训练的轮次
        self.TrainRound = Round
        self.NumRounds = 0

    def set_client_info(self, ModelDict, DataSize):
        self.ModelStaticDict = copy.deepcopy(ModelDict)
        self.DataLen = DataSize

    def set_client_InClusterID(self, ClusterID):
        self.InClusterID = ClusterID


from typing import List

class Contact():

    all_contacts: List["Contact"] = []

    def __init__(self,nombre: str,email: str):

        self.nombre = nombre
        self.email = email

        Contact.all_contacts.append(self)

    def __repr__(self)->str:
             return (f"ClassName: {self.__class__.__name__}  Nombre:{self.nombre}  Email:{self.email}")

class Supplier(Contact):

    def ventas(self, venta:"Order")->None:

        print(f'La venta fue pendida al contacto supplier {self.nombre}')

c_1 = Contact("Dusty", "dusty@example.com")
c_2 = Contact("Steve", "steve@itmaybeahack.com")
c = Contact("Some Body", "somebody@example.net")
s = Supplier("Sup Plier", "supplier@example.net")
print(Contact.all_contacts)

print(s.ventas('Holaperro'))


from qtc.imports import *
from qtc.data.utils import Vocab, _prepare_labels
from qtc.featurizers import SpacyFeaturizer

__all__ = ["TextClassifierData"]

class TextClassifierData(Dataset):
    """
    This class provides labels and tokenized and vectorized text
    """

    def __init__(self, texts, labels, model="en_core_web_md"):
        """
        Constructor function for TextClassifierData class
        Args:
            texts (List): List of texts in dataset
            labels (List): List of labels in dataset
            model (string): List of sPacy model to use
        Returns:
            None
        """

        self._texts = texts
        self._labels = labels

        self.featurizer = SpacyFeaturizer()

        self.vocab = Vocab(self.featurizer)

        # Prepare labels
        self._labels, _, _ = _prepare_labels(self._labels)

        # Build vocabulary
        self.vocab.build(self._texts)

        self._idx_texts = self.vocab.get_tokenized_texts()

        self.stoi = self.vocab.get_stoi()
        self.itos = self.vocab.get_itos()

    def __len__(self):
        """
        Returns the total length of the dataset
        Args:
            None
        Return:
            int: Total length of the dataset
        """

        return len(self._texts)

    def __getitem__(self, idx):
        """
        Returns an item from dataset
        Args:
            idx (int): The index of the data item in dataset
        Returns:
            dict: A dictionary with text and label
        """

        # Get text and label
        _idx_text = self._idx_texts[idx]
        _label = self._labels[idx]

        return {"idx_text": _idx_text, "label": _label}

    def get_batch(self, batch):
        """
        Collate function for PyTorch dataloaders
        This function is required to pad the sequences in batch
        Args:
            batch (dict): The dictionary of texts and labels
        Returns:
            dict: This dictionary contains vectorized text input, labels
                    and sequence lengths which are required in RNN
        """

        # Retrieve data from batch
        _idx_texts = [item["idx_text"] for item in batch]
        _labels = [item["label"] for item in batch]

        # Sort the list
        _idx_texts, _labels = map(
            list, zip(*sorted(zip(_idx_texts, _labels), reverse=True))
        )

        max_len = len(_idx_texts[0])

        # Initialize text list
        _texts = []
        _seq_lens = []

        for _idx_text in _idx_texts:

            _len = len(_idx_text)
            pad_len = max_len - _len

            if pad_len < 0:
                _idx_text = _idx_text[:max_len]
            else:
                _idx_text = np.pad(
                    _idx_text, (0, pad_len), "constant", constant_values=0
                ).tolist()

            _text = [self.itos[_idx] for _idx in _idx_text]

            _feature = self.featurizer.get_feature_vector(_text)

            _texts.append(_feature)

            _seq_lens.append(_len if _len < max_len else max_len)

        _texts = np.stack(_texts)
        _texts = torch.from_numpy(_texts)

        return {
            "texts": _texts,
            "labels": torch.tensor(_labels),
            "seq_lens": torch.tensor(_seq_lens),
        }


#!/usr/bin/env python3

from pynput import keyboard as kb
import rospy
from std_msgs.msg import String

rospy.init_node("teclas")
pub = rospy.Publisher("/voice_ui", String, queue_size=10)

def callback(tecla):
    s = String()

    print("Se ha pulsado la tecla ")

    if(str(tecla) == "'r'"):
        print("R")
        s.data = "sal"

    elif(str(tecla) == "'g'"):
        print("G")
        s.data = "pimienta"

    elif(str(tecla) == "'b'"):
        print("B")
        s.data = "azúcar"

    pub.publish(s)

# Main
if __name__ == '__main__':

    print("------- Start --------")
    kb.Listener(callback).run()


import json, jsonlines
class vocab():
    def __init__(self):
        self.word2index = {}
        self.word2count = {}
        self.index2word = []
        self.n_words = 0  # Count word tokens
        self.num_start = 0
    def add_sen_to_vocab(self, sentence):  # add words of sentence to vocab
        for word in sentence:
            word = word.lower()
            if word not in self.index2word:
                self.word2index[word] = self.n_words
                self.word2count[word] = 1
                self.index2word.append(word)
                self.n_words += 1
            else:
                self.word2count[word] += 1

    def trim(self, min_count):  # trim words below a certain count threshold
        keep_words = []

        for k, v in self.word2count.items():
            if v >= min_count:
                keep_words.append(k)

        print('keep_words %s / %s = %.4f' % (
            len(keep_words), len(self.index2word), len(keep_words) / len(self.index2word)
        ))

        # Reinitialize dictionaries
        self.word2index = {'PAD':0, '<s>':1, '</s>':2, 'UNKN':3}
        self.word2count = {}
        self.index2word = ['PAD', '<s>', '</s>', 'UNKN']
        self.n_words = 4  # Count default tokens

        for word in keep_words:
            self.word2index[word] = self.n_words
            self.index2word.append(word)
            self.n_words += 1

def Data_loader(train_file, test_file, max_len, output_train, output_test):
    vo = vocab()

    train_dataset = []
    test_dataset = []
    with open(train_file) as f:
        for line in f:
            d = json.loads(line.strip())
            vo.add_sen_to_vocab(d['question']['sentence'])
            for item in d['sample']:
                vo.add_sen_to_vocab(item['sentence'])
    vo.trim(2)
    word2index = vo.word2index
    index2word = vo.index2word
    with open(train_file) as f:
        for line in f:
            d = json.loads(line.strip())
            question = ['<s>'] + d['question']['sentence'] + ['<\s>']
            new_question = []
            for word in question:
                if word in index2word:
                    new_question.append(word2index[word])
                else:
                    new_question.append(word2index['UNKN'])
            if len(new_question) < max_len:
                new_question.extend([0]*(max_len-len(new_question)))
            else:
                print(1)
            for item in d['sample']:
                answer = ['<s>'] + item['sentence'] + ['<\s>']
                new_answer = []
                for word in answer:
                    if word in index2word:
                        new_answer.append(word2index[word])
                    else:
                        new_answer.append(word2index['UNKN'])
                if len(new_answer) < max_len:
                    new_answer.extend([0] * (max_len - len(new_answer)))
                else:
                    print(0)
                temp = {}
                temp['question'] = new_question
                temp['question_edges'] = d['question']['edges']
                temp['answer'] = new_answer
                temp['answer_edges'] = item['edges']
                temp['label'] = item['label']
                train_dataset.append(temp)
    with open(test_file) as f:
        for line in f:
            d = json.loads(line.strip())
            question = ['<s>'] + d['question']['sentence'] + ['<\s>']
            new_question = []
            for word in question:
                if word in index2word:
                    new_question.append(word2index[word])
                else:
                    new_question.append(word2index['UNKN'])
            if len(new_question) < max_len:
                new_question.extend([0]*(max_len-len(new_question)))
            else:
                print(0)
            for item in d['sample']:
                answer = ['<s>'] + item['sentence'] + ['<\s>']
                new_answer = []
                for word in answer:
                    if word in index2word:
                        new_answer.append(word2index[word])
                    else:
                        new_answer.append(word2index['UNKN'])
                if len(new_answer) < max_len:
                    new_answer.extend([0] * (max_len - len(new_answer)))
                else:
                    print(0)
                temp = {}
                temp['question'] = new_question
                temp['question_edges'] = d['question']['edges']
                temp['answer'] = new_answer
                temp['answer_edges'] = item['edges']
                temp['label'] = item['label']
                temp['output_result'] = item['answer']
                test_dataset.append(temp)

    with jsonlines.open(output_train, 'w') as writer:
        writer.write_all(train_dataset)
    with jsonlines.open(output_test, 'w') as writer:
        writer.write_all(test_dataset)

def merge(file_list):
    res = []
    for file in file_list:
        with open(file) as f:
            for line in f:
                d=json.loads(line.strip())
                res.append(d)
    with jsonlines.open('all_test.json', 'w') as writer:
        writer.write_all(res)
if __name__ == '__main__':
    #file_list = ['./train1_100.json', './train101_200.json', './train201_300.json', './train301_400.json', './train401_500.json', './train501_600.json', './train601_700.json', './train701_800.json', './train801_900.json', './train901_1000.json']
    #merge(file_list)
    #test_file = ['./test1_100.json', './test101_200.json', './test168_300.json', './test301_500.json','./test501_700.json', './test701_900.json', './test901_1000.json']
    #merge(test_file)
    Data_loader('./all_train.json', './all_test.json', 256, 'output_all_train.json', 'output_all_test.json')


from __future__ import annotations

from typing import Optional
from urllib.parse import urlencode
from jupyterhub.tests.utils import async_requests, public_host
from jupyterhub.utils import url_path_join
from traitlets import Unicode, default

from jupyterhub_moss import MOSlurmSpawner

def request(
    app,
    method: str,
    path: str,
    data: Optional[dict] = None,
    cookies: Optional[dict] = None,
    **kwargs,
):
    """Send a GET or POST request on the hub

    Similar to jupyterhub.tests.utils.get_page
    """
    if data is None:
        data = {}

    base_url = url_path_join(public_host(app), app.hub.base_url)
    url = url_path_join(base_url, path)

    if method == "POST":
        if cookies is not None and "_xsrf" in cookies:
            data["_xsrf"] = cookies["_xsrf"]
        return async_requests.post(url, data=data, cookies=cookies, **kwargs)

    assert method == "GET"
    if data:  # Convert data to query string
        url += f"?{urlencode(data)}"
    return async_requests.get(url, cookies=cookies, **kwargs)

class MOSlurmSpawnerMock(MOSlurmSpawner):
    """MOSlurmSpawner with some overrides to mock some features.

    Adapted from jupyterhub.tests.mocking.MockSpawner and
    batchspawner.tests.test_spawner.BatchDummy
    """

    exec_prefix = Unicode("")
    batch_submit_cmd = Unicode("cat > /dev/null; sleep 1")
    batch_query_cmd = Unicode("echo PENDING")
    batch_cancel_cmd = Unicode("echo STOP")

    req_homedir = Unicode(help="The home directory for the user")

    @default("req_homedir")
    def _default_req_homedir(self):
        return f"/tmp/jupyterhub_moss_tests/{self.user.name}"

    def user_env(self, env):
        env["USER"] = self.user.name
        env["HOME"] = self.req_homedir
        env["SHELL"] = "/bin/bash"
        return env


from django.shortcuts import render
from django.http import HttpResponse
from orders.models import *
import csv
from django.http import HttpResponse, JsonResponse

# Create your views here.
def exportOrders(request):
    response = HttpResponse(content_type='text/csv')
    writer = csv.writer(response)
    writer.writerow(['order_number', 'user', 'address_line_1','region', 'city','order_total', 'created_at' ])

    for record in Order.objects.all().values_list('order_number', 'user', 'address_line_1', 'region', 'city',
                                                   'order_total', 'created_at'):
        record = list(record)
        writer.writerow(record)
    response['Content-Disposition'] = "attachment; filename=Orders.csv"
    return response

def exportOrderProducts(request):
    response = HttpResponse(content_type='text/csv')
    writer = csv.writer(response)
    writer.writerow(['order__order_number', 'user', 'product','variations', 'quantity', 'product_price', 'created_at' ])

    for record in OrderProduct.objects.all().values_list('order', 'user', 'product__product_name',
                                                   'variations__variation_value','quantity','product_price', 'created_at'):
        record = list(record)
        writer.writerow(record)
    response['Content-Disposition'] = "attachment; filename=OrderProducts.csv"
    return response


import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
#from collections import OrderedDict

import matplotlib.pyplot as plt
#import torch.optim as optim
import math
import random

def plot3D(imgA,imgB,l1,l2,dim,mode="max"):
    if mode == "max":
        img2D_A,_ = torch.max(imgA[0,l1,:,:,:],dim)
        img2D_B,_ = torch.max(imgB[0,l2,:,:,:],dim)
    if mode == "half":
        if dim == 0:
            img2D_A = imgA[0,l1,imgA.shape[2]//2,:,:]
            img2D_B = imgB[0,l2,imgB.shape[2]//2,:,:]
        if dim == 1:
            img2D_A = imgA[0,l1,:,imgA.shape[3]//2,:]
            img2D_B = imgB[0,l2,:,imgB.shape[3]//2,:]
        if dim == 2:
            img2D_A = imgA[0,l1,:,:,imgA.shape[4]//2]
            img2D_B = imgB[0,l2,:,:,imgB.shape[4]//2]
    imgRGB = np.zeros(tuple(img2D_A.shape)+(3,))
    imgRGB[:,:,0] = img2D_A.numpy()
    imgRGB[:,:,1] = img2D_B.numpy()
    return imgRGB

def sliceplot(imgA_,imgB,d=10):
    imgA = torch.zeros(imgB.shape)
    imgA[:imgA_.shape[0],:imgA_.shape[1],:imgA_.shape[2]] = imgA_
    print(imgA.shape)
    print(imgB.shape)
    f = plt.figure()
    #f.tight_layout()
    ax = f.gca()
    s = imgA.shape[-1]
    ns = s // d
    nr = 1
    nc = ns
    if ns>4:
        nc = 4
        nr = math.ceil(ns / 4.0)
    for a in range(1,ns-1):
        imgA_2D = imgA[:,:,a*d]
        imgB_2D = imgB[:,:,a*d]

        imgRGB = np.zeros(tuple(imgA_2D.shape)+(3,))
        imgRGB[:,:,0] = imgA_2D.numpy()
        imgRGB[:,:,1] = imgB_2D.numpy()
        ax = plt.subplot(nr,nc,a)

        ax.imshow(imgRGB)
        ax.axis('off')

def plot_patch_batch(x,index,offsets,f=None):
       if f is None:
           f = plt.figure()

       ax = f.gca()
       ax.axis('off')

       num_scales = len(x.patchlist)
       for a in range(0,num_scales):
           tensor = x.patchlist[a].tensor.cpu().numpy()
           shape = tensor.shape[2:4]
           ax = plt.subplot(2,num_scales,a+1)
           im = ax.imshow(tensor[index,0,:,:])
           ax = plt.subplot(2,num_scales,num_scales+a+1)
           x0 = offsets[a,0]
           y0 = offsets[a,0]
           x1 = x0 +  shape[0]//2**a
           y1 = y0 +  shape[1]//2**a
           im = ax.imshow(tensor[index,0,x0:x1,y0:y1])

def plot_patch(x,offsets,f=None):
       if f is None:
           f = plt.figure()

       ax = f.gca()
       ax.axis('off')
       num_scales = x.shape[1]
       shape = x.shape[2:4]
       for a in range(0,num_scales):
           #print(num_scales)
           ax = plt.subplot(2,num_scales,a+1)
           im = ax.imshow(x[0,a,:,:])
           ax = plt.subplot(2,num_scales,num_scales+a+1)
           x0 = offsets[a,0]
           y0 = offsets[a,0]
           x1 = x0 +  shape[0]//2**a
           y1 = y0 +  shape[1]//2**a
           #print([x0,y0,x1,y1])
           im = ax.imshow(x[0,a,x0:x1,y0:y1])


import numpy as np
from tqdm import tqdm
from tools import augment_cluster

class InversionAugmentor(object):
    """docstring for InversionAugmentor."""

    def __init__(self, waveforms = None, earthquake_parameters = None, new_elements=2, parameter_variation=0.2, additional_weight = False):
        super(InversionAugmentor, self).__init__()
        self.waveforms = waveforms
        self.earthquake_parameters = earthquake_parameters

        self.__check_variable_state()

        # assign data values which have default values
        self.new_elements = new_elements
        self.parameter_variation = parameter_variation
        self.additional_weight = additional_weight

        # print(f"new_elements is {new_elements}")

    def __check_variable_state(self):
        # check if values for inputs are set and set state variable accordingly
        if (self.waveforms is None) or (self.earthquake_parameters is None):
            self.all_inputs_set = False
            print("Warning: Inputs missing")
        else:
            self.all_inputs_set = True

    def __create_output_string(self):
        """ this private method creates an output string of the internal variables
        """
        try:
            waveforms_string = self.waveforms.shape
        except:
            waveforms_string = self.waveforms
        try:
            earthquake_parameters_string = self.earthquake_parameters.shape
        except:
            earthquake_parameters_string = self.earthquake_parameters
        output_string = \
        "---- Inputs ----\n" + \
        f"Waveforms = {waveforms_string}\n" + \
        f"Earthquake Parameters = {earthquake_parameters_string}\n" + \
        f"---- Augmentation Properties ----\n" + \
        f"New elements = {self.new_elements}\n" + \
        f"Parameter variation = {self.parameter_variation}\n" + \
        f"Additional weight = {self.additional_weight}"

        return output_string

    def create_new_dataset(self, waveforms = None, earthquake_parameters = None, new_elements = None, parameter_variation = None,
                            additional_weight = None):
        """ this public method creates new waveforms for augmentation. Checks if augmentation parameters
        and input variables are given and, if given, uses them instead of the properties of the instance.
        """
        # if new inputs have been given, overwrite the inputs into the instance properties
        if (waveforms is not None) or (earthquake_parameters is not None):
            self.set_input(waveforms, earthquake_parameters)
        # same for augmentation properties
        if (new_elements is not None) or (parameter_variation is not None) or (
            additional_weight is not None):
            self.set_augmentation_parameters(new_elements, parameter_variation, additional_weight)

        self.__check_variable_state()
        # initialize outputs for when function is called without parameters set
        new_earthquakes, new_waveforms = None, None

        if self.all_inputs_set:

            # the actual generation is done here
            new_earthquakes, new_waveforms = augment_cluster(
                waveforms= self.waveforms,
                earthquake_parameters =  self.earthquake_parameters,
                parameter_variation=self.parameter_variation,
                number_of_new_data= self.new_elements, clip_values=True,
                additional_weight = self.additional_weight)
        else: # create error message
            print("Error: Not all input values are set. \n"+ \
                  "Please define the inputs: waveforms and/or earthquake parameters")

        return new_earthquakes, new_waveforms

    def set_input(self, waveforms = None, earthquake_parameters = None):
        """ this public method sets the input parameters, if they have been given
        """
        if (waveforms is not None):
            self.waveforms = waveforms
        if (earthquake_parameters is not None):
            self.earthquake_parameters = earthquake_parameters

    def set_augmentation_parameters(self, new_elements = None, parameter_variation = None, additional_weight = None):
        """ this public method sets the parameters of the augmentation method
        """
        if new_elements is not None:
            self.new_elements = new_elements
        if parameter_variation is not None:
            self.parameter_variation = parameter_variation
        if additional_weight is not None:
            self.additional_weight = additional_weight

    def store_settings(self, filename, ID=None):
        """ this public method stores all the internal variables for input and
        augmentation settings in the given filename; if a ID code is given, it is
        written to the file as well
        """
        # store all settings in a plain text file,
        # store also the data and time of creation, and possibly with corresponding data
        output_string = self.__create_output_string()
        current_time = datetime.now()
        output_string += f"\n---- Time of creation ----\n{current_time}"

        if ID is not None:
            output_string = f"---- ID ----\nID ={ID}\n" + \
                output_string
        with open(filename, 'w') as f:
            f.write(output_string)

    def display_properties(self):
        """ this method displays the stored values
        """
        output_string= self.__create_output_string()
        print(output_string)


import itertools
from subprocess import call

import chainer
import chainer.functions as F
import chainer.links as L
import numpy as np
from chainer import serializers
from chainer.backends import cuda

from util import invLIDAR

class RecoNet(chainer.Chain):
    def __init__(self, n_hid1=100, n_hid2=50):
        super().__init__()
        with self.init_scope():
            self.l0 = L.Linear(None, n_hid1)
            self.l1 = L.Linear(None, n_hid2)
            self.l2 = L.Linear(None, 15)

    def __call__(self, x, test=False):
        h = F.relu(self.l0(x))
        h = F.relu(self.l1(h))
        return self.l2(h)

    def predict(self, x, test=False):
        h = F.relu(self.l0(x))
        h = F.relu(self.l1(h))
        return F.sigmoid(self.l2(h))

class ThreatEstimator:
    def __init__(self, model, filename, gpu):
        self.model = model
        serializers.load_npz(filename, self.model)
        self.gpu = gpu
        if gpu:
            self.model.to_gpu(0)
        acc_list = [-0.02, 0, 0.02]
        omega_list = [-0.15, -0.05, 0, 0.05, 0.15]
        self.action_list = list(itertools.product(
            acc_list, omega_list))

    def threat(self, obs):
        xp = cuda.get_array_module(obs)
        r = invLIDAR(obs[:, :360][0], xp)
        v_val = obs[:, 363][0]

        rx, ry = r.real, r.imag
        mask = (-0.5 < rx) & (rx < 0.7) & (-0.3 < ry) & (ry < 0.3)
        r = r[mask]
        num = len(r)

        v = xp.ones((num, 1)) * v_val
        data = xp.c_[r.real, r.imag, v].astype(np.float32)
        if self.gpu:
            data = cuda.cupy.asarray(data)

        result = self.model.predict(data).array.sum(axis=0)
        if self.gpu:
            result = cuda.cupy.asnumpy(result)
        return result


from flask import Flask,request
from sklearn.pipeline import Pipeline
import numpy as np
import joblib
import json

app = Flask(__name__)

# inisialize predected volume
predected_data = 0.0

# load pipeline
pipeline = joblib.load('transform_predict.joblib')

@app.route("/", methods=["POST", "GET"])
def home():

    global predected_data
    global pipeline

    if request.method == "POST":
        #  get data

        test_data = request.get_json()

        # data preparation
        test_data = test_data["volume"][-29:]
        test_data = np.array(test_data).reshape(-1, 1)

        # using pipeline
        transformed_data = pipeline['scaler'].transform(test_data).T
        transformed_data = np.reshape(transformed_data, (transformed_data.shape[0], 1, transformed_data.shape[1]))
        predected_data = pipeline['model'].predict(transformed_data)

        # invert predictions (output)
        predected_data = pipeline['scaler'].inverse_transform(predected_data)[0][0]

    pred_obj = {"prediction": float(predected_data)}
    json_dump = json.dumps(pred_obj)

    return json_dump

if __name__ == "__main__":
    app.run(host="0.0.0.0", port="8080", threaded=False)