# -*- coding: utf-8 -*-
#
'''
I/O for Gmsh's msh format, cf.
<http://geuz.org/gmsh/doc/texinfo/gmsh.html#File-formats>.

.. moduleauthor:: Nico Schlömer <nico.schloemer@gmail.com>
'''
from itertools import islice
import numpy

def read(filename):
    '''Reads a Gmsh msh file.
    '''
    with open(filename) as f:
        points, cells = read_buffer(f)

    return points, cells, {}, {}, {}

def read_buffer(f):
    # The format is specified at
    # <http://geuz.org/gmsh/doc/texinfo/gmsh.html#MSH-ASCII-file-format>.
    while True:
        try:
            line = next(islice(f, 1))
        except StopIteration:
            break
        assert(line[0] == '$')
        environ = line[1:].strip()
        if environ == 'MeshFormat':
            line = next(islice(f, 1))
            # 2.2 0 8
            line = next(islice(f, 1))
            assert(line.strip() == '$EndMeshFormat')
        elif environ == 'Nodes':
            # The first line is the number of nodes
            line = next(islice(f, 1))
            num_nodes = int(line)
            points = numpy.empty((num_nodes, 3))
            for k, line in enumerate(islice(f, num_nodes)):
                # Throw away the index immediately
                points[k, :] = numpy.array(line.split(), dtype=float)[1:]
            line = next(islice(f, 1))
            assert(line.strip() == '$EndNodes')
        elif environ == 'Elements':
            # The first line is the number of elements
            line = next(islice(f, 1))
            num_cells = int(line)
            cells = {}
            gmsh_to_meshio_type = {
                    15: ('vertex', 1),
                    1: ('line', 2),
                    2: ('triangle', 3),
                    3: ('quad', 4),
                    4: ('tetra', 4),
                    5: ('hexahedron', 8),
                    6: ('wedge', 6)
                    }
            for k, line in enumerate(islice(f, num_cells)):
                # Throw away the index immediately;
                data = numpy.array(line.split(), dtype=int)
                t = gmsh_to_meshio_type[data[1]]
                # Subtract one to account for the fact that python indices
                # are 0-based.
                if t[0] in cells:
                    cells[t[0]].append(data[-t[1]:] - 1)
                else:
                    cells[t[0]] = [data[-t[1]:] - 1]

            line = next(islice(f, 1))
            assert(line.strip() == '$EndElements')
        elif environ == 'PhysicalNames':
            line = next(islice(f, 1))
            num_phys_names = int(line)
            for k, line in enumerate(islice(f, num_phys_names)):
                pass
            line = next(islice(f, 1))
            assert(line.strip() == '$EndPhysicalNames')
        else:
            raise RuntimeError('Unknown environment \'%s\'.' % environ)

    for key in cells:
        cells[key] = numpy.vstack(cells[key])

    return points, cells

def write(
        filename,
        points,
        cells,
        point_data=None,
        cell_data=None,
        field_data=None
        ):
    '''Writes msh files, cf.
    http://geuz.org/gmsh/doc/texinfo/gmsh.html#MSH-ASCII-file-format
    '''
    if point_data is None:
        point_data = {}
    if cell_data is None:
        cell_data = {}
    if field_data is None:
        field_data = {}

    with open(filename, 'w') as fh:
        fh.write('$MeshFormat\n2 0 8\n$EndMeshFormat\n')

        # Write nodes
        fh.write('$Nodes\n')
        fh.write('%d\n' % len(points))
        for k, x in enumerate(points):
            fh.write('%d %f %f %f\n' % (k+1, x[0], x[1], x[2]))
        fh.write('$EndNodes\n')

        # Translate meshio types to gmsh codes
        # http://geuz.org/gmsh/doc/texinfo/gmsh.html#MSH-ASCII-file-format
        meshio_to_gmsh_type = {
                'vertex': 15,
                'line': 1,
                'triangle': 2,
                'quad': 3,
                'tetra': 4,
                'hexahedron': 5,
                'wedge': 6,
                }
        fh.write('$Elements\n')
        num_cells = 0
        for key, data in cells.iteritems():
            num_cells += data.shape[0]
        fh.write('%d\n' % num_cells)
        num_cells = 0
        for key, data in cells.iteritems():
            n = data.shape[1]
            form = '%d ' + '%d' % meshio_to_gmsh_type[key] + ' 0 ' + \
                ' '.join(n * ['%d']) + '\n'
            for k, c in enumerate(data):
                fh.write(form % ((num_cells+k+1,) + tuple(c + 1)))
            num_cells += data.shape[0]
        fh.write('$EndElements')

    return


# uncompyle6 version 3.7.4
# Python bytecode 3.4 (3310)
# Decompiled from: Python 3.6.9 (default, Apr 18 2020, 01:56:04)
# [GCC 8.4.0]
# Embedded file name: build/bdist.macosx-10.10-x86_64/egg/dhcpkit/tests/ipv6/messages/test_client_server_message.py
# Compiled at: 2017-06-23 17:22:45
# Size of source mod 2**32: 3991 bytes
"""
Test the ClientServerMessage implementation
"""
import unittest
from dhcpkit.ipv6.duids import EnterpriseDUID
from dhcpkit.ipv6.messages import ClientServerMessage, SolicitMessage
from dhcpkit.ipv6.options import ClientIdOption, ElapsedTimeOption, IANAOption, IATAOption, UnknownOption
from dhcpkit.tests.ipv6.messages import test_message
from dhcpkit.tests.ipv6.messages.test_unknown_message import unknown_packet

class ClientServerMessageTestCase(test_message.MessageTestCase):

    def setUp(self):
        self.packet_fixture = bytes.fromhex('0158595a00010015000200009d10444843504b6974556e697454657374000800020000')
        self.message_fixture = SolicitMessage(transaction_id=b'XYZ', options=[
         ClientIdOption(duid=EnterpriseDUID(enterprise_number=40208, identifier=b'DHCPKitUnitTest')),
         ElapsedTimeOption(elapsed_time=0)])
        self.parse_packet()

    def parse_packet(self):
        super().parse_packet()
        self.assertIsInstance(self.message, ClientServerMessage)

    def test_validate_transaction_id(self):
        self.message.transaction_id = b'AB'
        with self.assertRaisesRegex(ValueError, '3 bytes'):
            self.message.validate()
        self.message.transaction_id = b'ABCD'
        with self.assertRaisesRegex(ValueError, '3 bytes'):
            self.message.validate()
        self.message.transaction_id = 'ABC'
        with self.assertRaisesRegex(ValueError, '3 bytes'):
            self.message.validate()

    def test_validate_IAID_uniqueness(self):
        self.message.options.append(IANAOption(iaid=b'test'))
        self.message.validate()
        self.message.options.append(IATAOption(iaid=b'test'))
        self.message.validate()
        self.message.options.append(IATAOption(iaid=b'test'))
        with self.assertRaisesRegex(ValueError, 'not unique'):
            self.message.validate()

    def test_get_options_of_type(self):
        found_options = self.message.get_options_of_type(ClientIdOption)
        self.assertEqual(len(found_options), 1)
        self.assertIsInstance(found_options[0], ClientIdOption)
        found_options = self.message.get_options_of_type(UnknownOption)
        self.assertEqual(len(found_options), 0)

    def test_get_option_of_type(self):
        found_option = self.message.get_option_of_type(ClientIdOption)
        self.assertIsInstance(found_option, ClientIdOption)
        found_option = self.message.get_option_of_type(UnknownOption)
        self.assertIsNone(found_option)

    def test_load_from_wrong_buffer(self):
        message = self.message_class()
        with self.assertRaisesRegex(ValueError, 'buffer does not contain'):
            message.load_from(unknown_packet)

if __name__ == '__main__':
    unittest.main()


# Data
import pandas as pd
import numpy as np
import datetime
import math
from urllib.request import urlopen
import json
import requests
import urllib.request
import urllib.parse
import time
import io
from bs4 import BeautifulSoup
# Graphing
import plotly.graph_objects as go
import plotly.express as px
# Dash
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Output, Input
# Navbar
from navbar import Navbar

## Import necessary components
from sklearn.decomposition import PCA
import plotly.express as px
import plotly.graph_objects as go
import plotly.figure_factory as ff
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np

import openpyxl

from sklearn.cluster import KMeans
from sklearn.cluster import AgglomerativeClustering

from scipy.stats import zscore

#from app import create_time_series2, create_bar_series2
#from homepage import create_bar_series, create_time_series, create_prob_series

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.UNITED])

app.config.suppress_callback_exceptions = True

server = app.server

##################################
#####   DATA    ##################
##################################
# With this:

## Import previously imputed.xlsx dataset
df=pd.read_excel('https://renkulab.io/gitlab/jeffrey.post/ssa_hiv_ml/-/raw/master/data/new/imputation_output/imputed.xlsx?inline=false', engine='openpyxl', index_col=0).set_index(['Country', 'Survey'])

# Create dictionary for sliding window
# Create groups that include 5 years of surveys, so 2002 will be [2000,20004], 2003 = [2001,2005] and so on..
# First surveys are 2000, so the first group is 2002 = [2000,2004]
# Last survey is 2018, so the last group is 2016 = [2014, 2018]
min_year = 2002
max_year = 2016
G={}
for start_year in range(min_year, max_year+1):
    #G[start_year]=df.loc[(df.index.get_level_values('Survey') >= start_year-2) & (df.index.get_level_values('Survey') < start_year+3)]
    # The line below removes duplicate country entries in the 5year groups, so say 2015 has Senegal four times, for 2017, 2016, 2015 and 2014, this only keeps Senegal 2017 which limits one countries bias
    G[start_year]=df.loc[(df.index.get_level_values('Survey') >= start_year-2) & (df.index.get_level_values('Survey') < start_year+3)].reset_index().drop_duplicates(subset='Country').set_index(['Country','Survey'])

## Create PCA

n=2
#n=3

pca = PCA(n_components = n)

# Use zscore normalization or not?
# Yes then use_zscore = True else False
use_zscore = False
#use_zscore = True

# Use this variable to select if you run PCA on last group of countries G[2016] or on all countries
#use_all = True
use_all = False

# Fit model with data from the last group
if use_all == False:
    if use_zscore == False:
        X2D_G4 = pca.fit(G[max_year].drop(columns=['iso','cow','GY']))
    elif use_zscore == True:
        X2D_G4 = pca.fit(G[max_year].drop(columns=['iso','cow','GY']).apply(zscore))
if use_all == True:
    if use_zscore == False:
        X2D_G4 = pca.fit(df.drop(columns=['iso','cow','GY']))
    elif use_zscore == True:
        X2D_G4 = pca.fit(df.drop(columns=['iso','cow','GY']).apply(zscore))

# Create a similar dict but composed of the PCs
PCG={}

if n == 2:
    components = ['PC-1', 'PC-2']
elif n == 3:
    components = ['PC-1', 'PC-2', 'PC-3']

for start_year in range(min_year,max_year+1):
    if use_zscore == False:
        PCG[start_year]=pd.DataFrame(pca.transform(G[start_year].drop(columns=['iso','cow','GY'])), columns=components, index=G[start_year].index)
    elif use_zscore == True:
        PCG[start_year]=pd.DataFrame(pca.transform(G[start_year].drop(columns=['iso','cow','GY']).apply(zscore)), columns=components, index=G[start_year].index)

#PCG[start_year]=pd.DataFrame(pca.transform(G[start_year].drop(columns=['iso','cow','GY'])), columns=components, index=G[start_year].index)
#PCG_norm[start_year]=pd.DataFrame(pca_norm.transform(G[start_year].drop(columns=['iso','cow','GY']).apply(zscore)), columns=components, index=G[start_year].index)
#PCG[start_year]=pd.DataFrame(pca_norm.transform(G[start_year].drop(columns=['iso','cow','GY']).apply(zscore)), columns=components, index=G[start_year].index)

# Calculate loadings if you want
loadings=pd.DataFrame(pca.components_.T*np.sqrt(pca.explained_variance_), columns=components, index=G[min_year].drop(columns=['iso','cow','GY']).columns)

def minmax(X):
    return (X - X.min()) / (X.max() - X.min())

norm_loadings = minmax(loadings)
#norm_loadings_true = minmax(loadings_True)

fake = loadings.copy()
fake.iloc[:,:] = 0
blabliblou = fake.append(np.abs(loadings))

# Plot loadings
#fig = px.scatter(norm_loadings.reset_index(), x='PC-1', y='PC-2', color='index', text='index')
fig = px.line(blabliblou.reset_index(), x='PC-1', y='PC-2', color='index', text='index')
fig.update_traces(textposition='top center')
#fig = px.scatter(norm_loadings, x='PC-1', y='PC-2',hover_name=loadings.index)
fig.update_layout(height=800)

# Get HIV incidence and prevalence into usable format from Aziza's original dataset

HIV_incidence_path = 'data/original_aziza/HIVIncidence_per1000_15_49.csv'
#HIV_incidence_path = '../../data/new/New HIV infections_HIV incidence per 1000 population - Adults (15-49)_Population All adults (15-49).csv'

HIV_prevalence_path = 'data/original_aziza/HIVPrevalence_15_49.csv'
#HIV_prevalence_path = '../../data/new/People living with HIV_HIV Prevalence - Adults (15-49)_Population Adults (15-49).csv'

def read_HIV(path):
    tmp = pd.read_csv(path)
    tmp = tmp.set_index('Country').filter(regex='[0-9][0-9][0-9][0-9]$',axis=1)
    return tmp.rename(index={'Congo, Rep.': 'Congo', 'Congo, Dem. Rep.':'Congo Democratic Republic'})
#    return tmp.rename(index={'Democratic Republic of the Congo':'Congo Democratic Republic'})

HIV = read_HIV(HIV_incidence_path)
HIV_prev = read_HIV(HIV_prevalence_path)

def addHIV(X, incprev):
    tmp=[]
    if incprev == 'incidence':
        HIV = read_HIV(HIV_incidence_path)
    elif incprev == 'prevalence':
        HIV = read_HIV(HIV_prevalence_path)
    for i in range(len(X)):
        year=X.reset_index().Survey[i]
        if (year > 2017):
            year=2017
        tmp.append(HIV.loc[X.reset_index().Country[i],str(year)])
    return pd.Series(tmp).astype(float)

for start_year in range(min_year,max_year+1):
    PCG[start_year]['HIV.incidence']=addHIV(PCG[start_year], 'incidence').values

for start_year in range(min_year,max_year+1):
    PCG[start_year]['HIV.prevalence']=addHIV(PCG[start_year], 'prevalence').values

# Number of clusters we want is 3 (from inertia basically)
k=3

kmeans = KMeans(n_clusters=k, random_state=0)

ccenters={}
clabels={}

start_year=2002

# Use n to use n PCs
# Here we only want 2D clustering
#kmeans.fit(PCG[start_year].iloc[:,:2])
kmeans.fit(PCG[start_year].iloc[:,:n])

for start_year in range(min_year,max_year+1):
    #print(start_year)
    # The line below allows us to initiliaze the cluster from the previous centroids - this avoid the jump at year 2009
    kmeans = KMeans(n_clusters=k, random_state=0, init=kmeans.cluster_centers_)
    #kmeans.fit(PCG[start_year].iloc[:,:n])
    kmeans.fit(PCG[start_year].iloc[:,:n])
    #print(kmeans.cluster_centers_)

    # Sort clusters by their sum of PC-1 and PC-2
    #idx = np.argsort(kmeans.cluster_centers_.sum(axis=1))

    # It's easier to sort by PC-1 instead since that is more of mark of clusters:
    idx = np.argsort(kmeans.cluster_centers_[:,0])
    lut = np.zeros_like(idx)
    lut[idx] = np.arange(k)

    #print(lut[idx])
    #print(lut)
    #print(kmeans.labels_)
    #print(lut[kmeans.labels_])

    #print([kmeans.cluster_centers_[i] for i in idx])
    ccenters[start_year]=[kmeans.cluster_centers_[i] for i in idx]
    PCG[start_year]['Cluster']=lut[kmeans.labels_]

for start_year in range(min_year,max_year+1):
    PCG[start_year]['gy']=start_year

centroids={}
for start_year in reversed(range(min_year,max_year+1)):
    if n==2:
        centroids[start_year]=pd.DataFrame([['Centroid_0', start_year, ccenters[start_year][0][0], ccenters[start_year][0][1], 10, 10, 0, start_year],['Centroid_1', start_year, ccenters[start_year][1][0], ccenters[start_year][1][1], 10, 10, 1, start_year],['Centroid_2', start_year, ccenters[start_year][2][0], ccenters[start_year][2][1], 10, 10, 2, start_year]], columns=['Country', 'Survey', 'PC-1', 'PC-2', 'HIV.incidence', 'HIV.prevalence', 'Cluster', 'gy']).set_index(['Country','Survey'])
    elif n==3:
        centroids[start_year]=pd.DataFrame([['Centroid_0', start_year, ccenters[start_year][0][0], ccenters[start_year][0][1], ccenters[start_year][0][2], 10, 10, 0, start_year],['Centroid_1', start_year, ccenters[start_year][1][0], ccenters[start_year][1][1], ccenters[start_year][1][2], 10, 10, 1, start_year],['Centroid_2', start_year, ccenters[start_year][2][0], ccenters[start_year][2][1], ccenters[start_year][2][2], 10, 10, 2, start_year]], columns=['Country', 'Survey', 'PC-1', 'PC-2', 'PC-3', 'HIV.incidence', 'HIV.prevalence', 'Cluster', 'gy']).set_index(['Country','Survey'])

# Same but using different cluster number for centroids than actual clusters they represent (in order to change symbol)
#centroids={}
#for start_year in reversed(range(min_year,max_year+1)):#
    #if n==2:
#        centroids[start_year]=pd.DataFrame([['Centroid_0', start_year, ccenters[start_year][0][0], ccenters[start_year][0][1], 10, 10, 3, start_year],['Centroid_1', start_year, ccenters[start_year][1][0], ccenters[start_year][1][1], 10, 10, 4, start_year],['Centroid_2', start_year, ccenters[start_year][2][0], ccenters[start_year][2][1], 10, 10, 5, start_year]], columns=['Country', 'Survey', 'PC-1', 'PC-2', 'HIV.incidence', 'HIV.prevalence', 'Cluster', 'gy']).set_index(['Country','Survey'])
#    elif n==3:
#        centroids[start_year]=pd.DataFrame([['Centroid_0', start_year, ccenters[start_year][0][0], ccenters[start_year][0][1], ccenters[start_year][0][2], 10, 10, 0, start_year],['Centroid_1', start_year, ccenters[start_year][1][0], ccenters[start_year][1][1], ccenters[start_year][1][2], 10, 10, 1, start_year],['Centroid_2', start_year, ccenters[start_year][2][0], ccenters[start_year][2][1], ccenters[start_year][2][2], 10, 10, 2, start_year]], columns=['Country', 'Survey', 'PC-1', 'PC-2', 'PC-3', 'HIV.incidence', 'HIV.prevalence', 'Cluster', 'gy']).set_index(['Country','Survey'])

#pd.concat([PCG[2000], PCG[2001]])
data_sy_list = []
for i, start_year in enumerate(PCG):
    data_sy = PCG[start_year]
    data_sy_list.append(data_sy)
final_data_sy = pd.concat(data_sy_list)

#pd.concat([PCG[2000], PCG[2001]])
data_centroids_list = []
for i, start_year in enumerate(centroids):
    data_centroids = centroids[start_year]
    data_centroids_list.append(data_centroids)
final_data_centroids = pd.concat(data_centroids_list)

#final_data_centroids['Centroid'] = 0
#final_data_sy['Centroid'] = 1

tmp=pd.concat([final_data_sy, final_data_centroids])
tmp['Cluster']=tmp['Cluster'].astype(str)

## 3. Animation 2002-2016 - PCA 2D or 3D space and HIV boxplots

size='HIV.incidence'

# diff = 10%
diff = 1.1

map=px.scatter(
    #px.scatter_3d(
    tmp.reset_index().drop_duplicates(subset=['Country', 'gy']),
    #final_data_sy.reset_index().drop_duplicates(subset=['Country', 'gy']),
    x="PC-1",
    y="PC-2",
    #z="PC-3",
    animation_frame="gy",
    hover_name="Country",
    size=size,
    color="Cluster",
    #symbol="Centroid",
    category_orders={'Cluster':['0','1','2', '4', '5']},
    color_discrete_sequence=['#890000','#2a6b28','#4f5a90', '#000000', '#000000' , '#000000'],
    text="Country",
    size_max=40,
    range_x=[tmp['PC-1'].min()*diff,tmp['PC-1'].max()*diff],
    range_y=[tmp['PC-2'].min()*diff,tmp['PC-2'].max()*diff],
    #range_z=[tmp['PC-3'].min()-diff,tmp['PC-3'].max()+diff],
)

map.update_layout(title="Evolution of countries on 2D PCA Space<br>Size represents {}".format(size), height=800)

#fig.write_html('all_pca_2D.html', auto_open=True)

variable='HIV.incidence'

figbox = px.box(
    final_data_sy.reset_index(),
    x="Cluster",
    y=variable,
    points='all',
    #notched=True,
    animation_frame="gy",
    hover_name='Country',
    color='Cluster',
    category_orders={'Cluster':[0,1,2]},
    color_discrete_sequence=['#890000','#2a6b28','#4f5a90'],
    hover_data=['Survey'], range_y=[0,tmp[variable].max()+5]
)
#figbox.update_traces(quartilemethod="inclusive")
figbox.update_layout(title="Evolution of {} by cluster".format(variable), height=800)

#fig.write_html('HIV2015.html', auto_open=True)

##################################
##################################

nav = Navbar()

header_FR = html.Div(
    [
        dbc.Row(
            dbc.Col(
                html.H2(
                    'COVID-19 in France',
                    style= {
                        'textAlign': 'center',
                        "background": "lightblue"
                    }
                )
            )
        )
    ]
)

div_figbox = html.Div(
    [
        dbc.Row(
            dbc.Col(
                dcc.Graph(
                    id='figbox',
                    figure=figbox,
                    #clickData={'points': [{'location': '01'}]}
                )
            )
        )
    ]
)

div_map = html.Div(
    [
        dbc.Row(
            dbc.Col(
                dcc.Graph(
                    id='map',
                    figure=map,
                    #clickData={'points': [{'location': '01'}]}
                )
            )
        )
    ]
)

div_fig = html.Div(
    [
        dbc.Row(
            dbc.Col(
                dcc.Graph(
                    id='fig',
                    figure=fig,
                    #clickData={'points': [{'location': '01'}]}
                )
            )
        )
    ]
)

def App():
    layoutapp = html.Div([
        nav,
        header_FR,
        div_fig
    ])
    return layoutapp

def Homepage():
    layouthp = html.Div([
        nav,
        header_FR,
        div_map,
        div_figbox
    ])
    return layouthp

app.layout = html.Div([
    dcc.Location(id = 'url', refresh = True),
    html.Div(id = 'page-content')
])

@app.callback(Output('page-content', 'children'),
            [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/':
        return App()
    else:
        return Homepage()

if __name__ == '__main__':
    app.run_server(debug=True)


import warnings
from scipy import stats

import numpy as np

def get_stars(a, b):
    p = stats.ttest_rel(a, b).pvalue
    if p <= 0.001:
        return '***'
    elif p <= 0.01:
        return '**'
    elif p <= 0.05:
        return '*'
    else:
        return ''

def get_head_tail_split_8020(item_pop):
    """
    Get the index of the short head limit (80% of ratings)
    :param item_pop:
    :return:
    """
    eighty_percent = sum(np.array(item_pop)) * 0.8
    for i, cnt in enumerate(np.array(item_pop)):
        eighty_percent -= cnt
        if eighty_percent <= 0:
            return i

def get_head_tail_split(item_pop, num_items):
    """
    Get the index of the top-20% rated items in the training set
    :param item_pop:
    :return:
    """
    threshold = 0.2
    return int(num_items * threshold)

def catalog_coverage(predicted, catalog, k):
    """
    Computes the catalog coverage for k lists of recommendations
    Parameters
    ----------
    predicted : a list of predictions
        Ordered predictions
        example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
    catalog: list
        A list of all unique items in the training data
        example: ['A', 'B', 'C', 'X', 'Y', Z]
    k: integer
        The number of observed recommendation lists
        which randomly choosed in our offline setup
    Returns
    ----------
    catalog_coverage:
        Number of Recommended Items
    percentage_catalog_coverage:
        The catalog coverage of the recommendations as a percent
        rounded to 2 decimal places
    ----------
    """
    predicted_flattened = [p for sublist in predicted for p in sublist]
    L_predictions = len(set(predicted_flattened))
    catalog_coverage = round(L_predictions / (len(catalog) * 1.0) * 100, 2)
    return L_predictions, catalog_coverage

def compute_gini(x, w=None):
    x = np.asarray(x)
    if w is not None:
        w = np.asarray(w)
        sorted_indices = np.argsort(x)
        sorted_x = x[sorted_indices]
        sorted_w = w[sorted_indices]
        cumw = np.cumsum(sorted_w, dtype=float)
        cumxw = np.cumsum(sorted_x * sorted_w, dtype=float)
        return (np.sum(cumxw[1:] * cumw[:-1] - cumxw[:-1] * cumw[1:]) /
                (cumxw[-1] * cumw[-1]))
    else:
        sorted_x = np.sort(x)
        n = len(x)
        cumx = np.cumsum(sorted_x, dtype=float)
        return (n + 1 - 2 * np.sum(cumx) / cumx[-1]) / n

def _ark(actual, predicted, k=10):
    """
    Computes the average recall at k.
    Parameters
    ----------
    actual : list
        A list of actual items to be predicted
    predicted : list
        An ordered list of predicted items
    k : int, default = 10
        Number of predictions to consider
    Returns:
    -------
    score : int
        The average recall at k.
    """
    if len(predicted) > k:
        predicted = predicted[:k]

    score = 0.0
    num_hits = 0.0

    for i, p in enumerate(predicted):
        if p in actual and p not in predicted[:i]:
            num_hits += 1.0
            score += num_hits / (i + 1.0)

    if not actual:
        return 0.0

    return score / len(actual)

def mark(actual, predicted, k=10):
    """
    Computes the mean average recall at k.
    Parameters
    ----------
    actual : a list of test predictions
        Actual items to be predicted
        example: [['A', 'B', 'X'], ['A', 'B', 'Y']]
    predicted : a list of predictions
        Ordered predictions
        example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
    Returns:
    -------
        mark: int
            The mean average recall at k (mar@k)
    """
    return np.mean([_ark(a, p, k) for a, p in zip(actual, predicted)])

def novelty(predicted, pop, u, n):
    """
    Computes the novelty for a list of recommendations
    Parameters
    ----------
    predicted : a list of predictions
        Ordered predictions
        example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
    pop: dictionary
        A dictionary of all items alongside of its occurrences counter in the training data
        example: {1198: 893, 1270: 876, 593: 876, 2762: 867}
    u: integer
        The number of users in the training data
    n: integer
        The length of recommended lists per user
    Returns
    ----------
    novelty:
        The novelty of the recommendations in system level
    mean_self_information:
        The novelty of the recommendations in recommended top-N list level
    ----------
    Metric Defintion:
    Zhou, T., Kuscsik, Z., Liu, J. G., Medo, M., Wakeling, J. R., & Zhang, Y. C. (2010).
    Solving the apparent diversity-accuracy dilemma of recommender systems.
    Proceedings of the National Academy of Sciences, 107(10), 4511-4515.
    """
    mean_self_information = []
    k = 0
    for sublist in predicted:
        self_information = 0
        k += 1
        for i in sublist:
            if pop[i] != 0:
                self_information += np.sum(-np.log2(pop[i] / u))
        mean_self_information.append(self_information / n)
    novelty = sum(mean_self_information) / k
    return novelty, mean_self_information

def recommender_precision(predicted, actual):
    """
    Computes the precision of each user's list of recommendations, and averages precision over all users.
    ----------
    actual : a list of test predictions
        Actual items to be predicted
        example: [['A', 'B', 'X'], ['A', 'B', 'Y']]
    predicted : a list of predictions
        Ordered predictions
        example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
    Returns:
    -------
        precision: int
    """

    def calc_precision(predicted, actual):
        prec = [value for value in predicted if value in actual]
        prec = np.round(float(len(prec)) / float(len(predicted)), 4)
        return prec

    precision = np.mean(list(map(calc_precision, predicted, actual)))
    return precision, list(map(calc_precision, predicted, actual))

def recommender_recall(predicted, actual):
    """
    Computes the recall of each user's list of recommendations, and averages precision over all users.
    ----------
    actual : a list of test predictions
        Actual items to be predicted
        example: [['A', 'B', 'X'], ['A', 'B', 'Y']]
    predicted : a list of predictions
        Ordered predictions
        example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
    Returns:
    -------
        recall: int
    """

    def calc_recall(predicted, actual):
        reca = [value for value in predicted if value in actual]
        reca = np.round(float(len(reca)) / float(len(actual)), 4)
        return reca

    recall = np.mean(list(map(calc_recall, predicted, actual)))
    return recall, list(map(calc_recall, predicted, actual))

def average_recommendation_popularity(predicted, pop):
    """
        Computes the average popularity of the recommended items in each list
        ----------
        predicted : a list of predictions
            Ordered predictions
            example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
        pop: dictionary
            A dictionary of all items alongside of its occurrences counter in the training data
            example: {1198: 893, 1270: 876, 593: 876, 2762: 867}
        Returns:
        -------
            arp: Average Recommendation Popularity (ARP)
        -------
        Metric Definition:
            Himan Abdollahpouri, Robin Burke, Bamshad Mobasher
            Managing Popularity Bias in Recommender Systems with Personalized Re-Ranking. FLAIRS Conference 2019
        """

    arp = []
    for L_u in predicted:
        phi_u = 0
        for i in L_u:
            phi_u += pop[i]
        arp.append(phi_u / len(L_u))
    mean_arp = sum(arp) / len(predicted)  # len(predicted)  is the number of users in the test set.

    return mean_arp, arp

def average_percentage_of_long_tail_items(predicted, long_tail_items):
    """
        Computes  the average percentage of long tail items in the recommended lists
        ----------
        predicted : a list of predictions
            Ordered predictions
            example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
        long_tail_items: list
            A dictionary of all items alongside of its occurrences counter in the training data
            example: ['X', 'Y']
        Returns:
        -------
            aplt: Average Percentage of Long Tail Items (APLT)
        -------
        Metric Definition:
            Himan Abdollahpouri, Robin Burke, Bamshad Mobasher
            Managing Popularity Bias in Recommender Systems with Personalized Re-Ranking. FLAIRS Conference 2019
        """

    aplt = []
    for L_u in predicted:
        long_tail_items_in_u = len(list(set(L_u) & set(long_tail_items)))
        aplt.append(long_tail_items_in_u / len(L_u))
    mean_aplt = sum(aplt) / len(predicted)  # len(predicted)  is the number of users in the test set.

    return mean_aplt, aplt

def average_coverage_of_long_tail_items(predicted, long_tail_items):
    """
        Evaluate how much exposure long-tail items get in the entire recommendation
        ----------
        predicted : a list of predictions
            Ordered predictions
            example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
        long_tail_items: list
            A dictionary of all items alongside of its occurrences counter in the training data
            example: ['X', 'Y']
        Returns:
        -------
            aclt: Average Coverage of Long Tail items (ACLT)
        -------
        Metric Definition:
            Himan Abdollahpouri, Robin Burke, Bamshad Mobasher
            Managing Popularity Bias in Recommender Systems with Personalized Re-Ranking. FLAIRS Conference 2019
        """

    aclt = []
    for L_u in predicted:
        long_tail_items_in_u = len(list(set(L_u) & set(long_tail_items)))
        aclt.append(long_tail_items_in_u)
    mean_aclt = sum(aclt) / len(predicted)  # len(predicted)  is the number of users in the test set.

    return mean_aclt, aclt

def ranking_based_statistical_parity(list_of_predictions, list_of_training, head_tail_items, long_tail_items):
    """
        Evaluate how much exposure long-tail items get in the entire recommendation
        ----------
        list_of_predictions : a list of predictions
            Ordered predictions
            example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
        list_of_training : a list of predictions
            Ordered predictions
            example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
        long_tail_items: list
            A dictionary of all items alongside of its occurrences counter in the training data
            example: ['X', 'Y']
        Returns:
        -------
            rsp: Ranking-based Statistical Parity (RSP)
        -------
        Metric Definition:
            Ziwei Zhu, Jianling Wang, James Caverlee
            Measuring and Mitigating Item Under-Recommendation Bias in Personalized Ranking Systems. SIGIR 2020
        """
    n = [[], []]
    numerators = [0, 0]
    for L_u in list_of_predictions:
        long_tail_items_in_u = len(list(set(L_u) & set(long_tail_items)))
        short_tail_items_in_u = len(list(set(L_u) & set(head_tail_items)))
        numerators[0] += short_tail_items_in_u
        n[0].append(short_tail_items_in_u)
        numerators[1] += long_tail_items_in_u
        n[1].append(long_tail_items_in_u)

    d = [[], []]
    denominators = [0, 0]
    for T_u in list_of_training:
        long_tail_items_in_u = len(list(set(T_u) | set(long_tail_items)))
        short_tail_items_in_u = len(list(set(T_u) | set(head_tail_items)))
        denominators[0] += short_tail_items_in_u
        d[0].append(short_tail_items_in_u)
        denominators[1] += long_tail_items_in_u
        d[1].append(long_tail_items_in_u)

    ps = [nn / dd for nn, dd in zip(numerators, denominators)]

    ps_by_u = [[], []]
    for i, (nn, dd) in enumerate(zip(n, d)):
        for nnn, ddd in zip(nn, dd):
            ps_by_u[i].append(nnn / ddd)

    rsp = np.std(ps) / np.mean(ps)

    return ps[0], ps[1], rsp, ps_by_u[0], ps_by_u[1], np.std(ps_by_u, axis=0) / np.mean(ps_by_u, axis=0)

def ranking_based_equal_opportunity(list_of_predictions, list_of_test, head_tail_items, long_tail_items):
    """
        Evaluate the probability of being ranked in top-𝑘 given the ground-truth that the user likes the item
        ----------
        list_of_predictions : a list of predictions
            Ordered predictions
            example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
        list_of_training : a list of predictions
            Ordered predictions
            example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
        list_of_test : a list of predictions
            Ordered predictions
            example: [['X', 'Y', 'Z'], ['X', 'Y', 'Z']]
        long_tail_items: list
            A dictionary of all items alongside of its occurrences counter in the training data
            example: ['X', 'Y']
        Returns:
        -------
            reo: Ranking-based Equal Opportunity (REO)
        -------
        Metric Definition:
            Ziwei Zhu, Jianling Wang, James Caverlee
            Measuring and Mitigating Item Under-Recommendation Bias in Personalized Ranking Systems. SIGIR 2020
        """
    n = [[], []]
    numerators = [0, 0]  # counts how many items in test set from group-a are ranked in top-𝑘 for user u
    for index, L_u in enumerate(list_of_predictions):
        short_tail_items_in_u = len(list(set(L_u) & set(head_tail_items) & set(list_of_test[index])))
        numerators[0] += short_tail_items_in_u
        n[0].append(short_tail_items_in_u)

        long_tail_items_in_u = len(list(set(L_u) & set(long_tail_items) & set(list_of_test[index])))
        numerators[1] += long_tail_items_in_u
        n[1].append(long_tail_items_in_u)

    d = [[], []]
    denominators = [0, 0]  # counts the total number of items from group-a in test set for user u.
    for index, T_u in enumerate(list_of_test):
        short_tail_items_in_u = len(list(set(T_u) & set(head_tail_items)))
        denominators[0] += short_tail_items_in_u
        d[0].append(short_tail_items_in_u)

        long_tail_items_in_u = len(list(set(T_u) & set(long_tail_items)))
        denominators[1] += long_tail_items_in_u
        d[1].append(long_tail_items_in_u)

    ps = [n / d for n, d in zip(numerators, denominators)]

    ps_by_u = [[], []]
    for i, (nn, dd) in enumerate(zip(n, d)):
        for nnn, ddd in zip(nn, dd):
            ps_by_u[i].append(0 if nnn == 0 else nnn / ddd)

    reo = np.std(ps) / np.mean(ps)

    return ps[0], ps[1], reo, ps_by_u[0], ps_by_u[1], np.std(ps_by_u, axis=0) / np.mean(ps_by_u, axis=0)

def _warn_for_empty_labels():
    """Helper for missing ground truth sets"""
    warnings.warn("Empty ground truth set! Check input data")
    return 0.

def _mean_ranking_metric(predictions, labels, metric):
    """Helper function for precision_at_k and mean_average_precision"""
    ndcg_by_user = [
        metric(np.asarray(prd), np.asarray(labels[i]))
        for i, prd in enumerate(predictions)  # lazy eval if generator
    ]
    return np.mean(ndcg_by_user), ndcg_by_user

def _require_positive_k(k):
    """Helper function to avoid copy/pasted code for validating K"""
    if k <= 0:
        raise ValueError("ranking position k should be positive")

def ndcg_at(predictions, labels, k=10, assume_unique=True):
    """Compute the normalized discounted cumulative gain at K.
    Compute the average NDCG value of all the queries, truncated at ranking
    position k. The discounted cumulative gain at position k is computed as:
        sum,,i=1,,^k^ (2^{relevance of ''i''th item}^ - 1) / log(i + 1)
    and the NDCG is obtained by dividing the DCG value on the ground truth set.
    In the current implementation, the relevance value is binary.
    If a query has an empty ground truth set, zero will be used as
    NDCG together with a warning.
    Parameters
    ----------
    predictions : array-like, shape=(n_predictions,)
        The prediction array. The items that were predicted, in descending
        order of relevance.
    labels : array-like, shape=(n_ratings,)
        The labels (positively-rated items).
    k : int, optional (default=10)
        The rank at which to measure the NDCG.
    assume_unique : bool, optional (default=True)
        Whether to assume the items in the labels and predictions are each
        unique. That is, the same item is not predicted multiple times or
        rated multiple times.
    Examples
    --------
    >>> # predictions for 3 users
    >>> preds = [[1, 6, 2, 7, 8, 3, 9, 10, 4, 5],
    ...          [4, 1, 5, 6, 2, 7, 3, 8, 9, 10],
    ...          [1, 2, 3, 4, 5]]
    >>> # labels for the 3 users
    >>> labels = [[1, 2, 3, 4, 5], [1, 2, 3], []]
    >>> ndcg_at(preds, labels, 3)
    0.3333333432674408
    >>> ndcg_at(preds, labels, 10)
    0.48791273434956867
    References
    ----------
    .. [1] K. Jarvelin and J. Kekalainen, "IR evaluation methods for
           retrieving highly relevant documents."
    """
    # validate K
    _require_positive_k(k)

    def _inner_ndcg(pred, lab):
        if lab.shape[0]:
            # if we do NOT assume uniqueness, the set is a bit different here
            if not assume_unique:
                lab = np.unique(lab)

            n_lab = lab.shape[0]
            n_pred = pred.shape[0]
            n = min(max(n_pred, n_lab), k)  # min(min(p, l), k)?

            # similar to mean_avg_prcsn, we need an arange, but this time +2
            # since python is zero-indexed, and the denom typically needs +1.
            # Also need the log base2...
            arange = np.arange(n, dtype=np.float32)  # length n

            # since we are only interested in the arange up to n_pred, truncate
            # if necessary
            arange = arange[:n_pred]
            denom = np.log2(arange + 2.)  # length n
            gains = 1. / denom  # length n

            # compute the gains where the prediction is present in the labels
            dcg_mask = np.in1d(pred[:n], lab, assume_unique=assume_unique)
            dcg = gains[dcg_mask].sum()

            # the max DCG is sum of gains where the index < the label set size
            max_dcg = gains[arange < n_lab].sum()
            return dcg / max_dcg

        else:
            return _warn_for_empty_labels()

    return _mean_ranking_metric(predictions, labels, _inner_ndcg)


import os
import json
import pickle
import datetime
import tkinter as tk
from tkinter import (
    ttk,
    OptionMenu,
    StringVar,
    messagebox
)

class Component(object):
    def __init__(self, serial_number=None, component_type='Winglet Strut', size_fit='A320 Series', status='Manufactured-Unfinished'):
        """Constructor"""
        self._serial_number = serial_number         # 1 to 99
        # Winglet Dtrut, Door handle, Rudder Pin
        self._component_type = component_type
        # A320 Series, A380 Series, 10x75, 12x100, 16x150
        self._size_fit = size_fit
        self._status = status                       # Polish, Paint

    # get_serial_number() function is accessible to class Batch
    def get_serial_number(self):
        return self._serial_number

    # set_serial_number is accessible outside the class
    def set_serial_number(self, serial_number):
        self._serial_number = serial_number

class Batch(Component):
    def __init__(self, batch_number, serial_number, location="Not Allocated"):
        """Constructor"""
        super(Batch, self).__init__(serial_number)
        self._date_manufacture = datetime.datetime.today().strftime('%Y%m%d')
        self._batch_create = datetime.datetime.today().strftime('%H%M')
        self._batch_number = batch_number
        self._location = location

    def create_sn_component(self, component_type, size_fit):
        sn = []
        x = 1

        sn_component = int(self.get_serial_number())
        while x <= sn_component:
            sn.append({
                "sn_component": self.create_batch_number() + '-' + self.add_zero(x),
                'type_components': component_type,
                'size_fitment_comps': size_fit,
                'status': self._status
            })
            x += 1
        return sn

    def create_batch_number(self):
        batch_num = int(self._batch_number)

        return self._date_manufacture + self.add_zero(batch_num)

    # I have used a static method because I don't need  the self to be passed as the first argument
    @staticmethod
    def add_zero(arg):
        x = 1
        batch = None
        while x <= arg:
            if x < 10:
                batch = '000' + str(x)
            elif 10 <= x < 100:
                batch = '00' + str(x)
            elif 100 <= x < 1000:
                batch = '0' + str(x)
            else:
                batch = str(x)

            x += 1

        return batch

class App(tk.Frame):
    # Initialize Method
    def __init__(self, master):
        """Constructor"""
        tk.Frame.__init__(self, master)
        # Set the Font and color of Nee Batch Frame
        s = ttk.Style()
        s.configure('Blue.TLabelframe.Label', font=('courier', 13, 'bold'))
        s.configure('Blue.TLabelframe.Label', foreground='#374e9b')
        # get screen width and height
        self.master.geometry('800x820')
        # Add a tittle on window
        self.master.title("PPEC - Inventory System")

        # Create instance for menu frame, this is the Menu Frame in the Main Window
        self._menu_frame = ttk.LabelFrame(
            self.master, text=' Menu ', style="Blue.TLabelframe")
        # Create instance for menu frame, this is the New Batch Frame in the Main Window
        self._create_batch_frame = ttk.LabelFrame(
            self.master, text=' Create New Batch ', style="Blue.TLabelframe")
        self._list_batch_frame = ttk.LabelFrame(
            self.master, text=' List All Batches ', style="Blue.TLabelframe")
        self._detail_batch_frame = ttk.LabelFrame(
            self.master, text=' View Details Batch ', style="Blue.TLabelframe")
        self._detail_comp_frame = ttk.LabelFrame(
            self.master, text=' View Details Component ', style="Blue.TLabelframe")
        self._show_details_frame = ttk.LabelFrame(
            self.master, text=' Batch Details', style="Blue.TLabelframe")

        # Initialize path and filename of json file
        self.path = '../Data'
        self.filename = 'BatchIndex'
        self.file_path_name_w = './' + self.path + '/' + self.filename + '.json'

        # Dictionary for dropdown components type
        self.choices_comp = {'Door handle': ['A320 Series', 'A380 Series'],
                             'Rudder Pin': ['A320 Series', 'A380 Series','10x75', '12x100', '16x150'],
                             'Winglet Strut': ['A320 Series', 'A380 Series']
                            }

        # Place Dropdown into the container element create a new status
        self.choices_status = {'Paint': ['AJ74','AB76', 'BT98', 'DF56', 'BE43'],
                                'Polished': ['No Code']
                            }

        # Create a Tkinter variable for dropdown
        self.tk_var = StringVar(self)
        self.entry_type_comp = StringVar(self)
        self.entry_size_fitment = StringVar(self)
        # Create a Tkinter variable for input
        self.entry_batch_no = StringVar(self)
        self.entry_components = StringVar(self)

        # Call methods
        self.create_menu()
        self._inventory = self.create_json_file()
        self.create_batch_pkl_file()
        self.create_comp_pkl_file()

    # Create json file and save all batch created
    def create_json_file(self):
        # Input the try except in a while loop, because try to see if file exist if not exist give an error that is catch by except,
        # the exception take the data and save into file and create, and start the loop again, this time check that file exist so open the file
        while True:
            try:
                fh = open(self.file_path_name_w, 'rb+')
                data_file = json.load(fh)
                return data_file
                break
            except FileNotFoundError:
                data = {'Batch': []}
                self.save_data(data)
                continue

    def save_data(self, datafile):
        # Write Data
        with open(self.file_path_name_w, 'w+') as fp:
            fp.write(json.dumps(datafile, indent=2, sort_keys=False))
        fp.close()

    # Create batch pickle file from json file
    def create_batch_pkl_file(self):
        # list to collect data from json file  and save into pickle file
        with open('../Data/BatchIndex.json') as json_file:
            # load the json file to check data saved inside
            data = json.load(json_file)
            component = []
            comps = []

            # Check json file inside the Batch List all Ojects and save each object in a single pickle file with value of key:number
            for batch_obj in data['Batch']:
                number = batch_obj['number']
                qty_comp = batch_obj['quantity_comp']
                manufacture_date = batch_obj['manufacture_date']
                location = batch_obj['location']
                component = batch_obj['component']

            for comp_obj in component:
                sn_component = comp_obj['sn_component']
                type_components = comp_obj['type_components']
                size_fitment_comps = comp_obj['size_fitment_comps']
                status = comp_obj['status']

                comps.append([sn_component,type_components,size_fitment_comps,status])

                self.file_path_name_pkl_w = './' + self.path + '/' + batch_obj['number'] + '.pkl'

                batch = [number, qty_comp, manufacture_date, location, comps]
                batch_dict = { batch[0]: batch }
                self.save_batch_pkl_data(batch_dict)

    def save_batch_pkl_data(self, pkl_batch_file):
        # Write Data
        with open(self.file_path_name_pkl_w, 'wb') as fhp:
            pickle.dump(pkl_batch_file, fhp)
        fhp.close()

    # Create components pickle file from json file
    def create_comp_pkl_file(self):
         # list to collect data from json file  and save into pickle file
        with open('../Data/BatchIndex.json') as json_file:
            # load the json file to check data saved inside
            data = json.load(json_file)

            # Check json file inside the Batch List all Ojects and save each object in a single pickle file with value of key:number
            for batch_obj in data['Batch']:

                for comp_obj in batch_obj['component']:
                    sn_component = comp_obj['sn_component']
                    type_components = comp_obj['type_components']
                    size_fitment_comps = comp_obj['size_fitment_comps']
                    manufacture_date = batch_obj['manufacture_date']
                    status = comp_obj['status']
                    number = batch_obj['number']
                    location = batch_obj['location']

                    self.file_path_name_comp_pkl_w = './' + self.path + '/' + comp_obj['sn_component'] + '.pkl'

                    # batch = [sn_component, type_components, size_fitment_comps, manufacture_date, status, number]
                    # data[batch_obj['sn_component'][comp_obj]] = batch
                    comp = [sn_component, type_components, size_fitment_comps, manufacture_date, status, location, number]
                    comp_dict = { comp[0]: comp }
                    self.save_comp_pkl_data(comp_dict)

    def save_comp_pkl_data(self, pkl_comp_file):
        # Write Data
        with open(self.file_path_name_comp_pkl_w, 'wb') as fhcp:
            pickle.dump(pkl_comp_file, fhcp)
        fhcp.close()

    # this method manage the choice you make on the dropdown options menu, display in the frame below the menu the choice you made
    def change_dropdown(self, *args):
        option = self.tk_var.get()
        # set a dictionary with coice for menu
        choice_dict = {
            '1': self.create_new_batch,
            '2': self.list_all_batches,
            '3': self.view_details_batch,
            '4': self.view_details_comp,
            '5': self.close_app
        }
        # call the methods that user choose from the dropdown menu
        choice_dict.get(option, self.create_menu)()

    """ this method manage the choice you do for the component, for one type component you choose,
        display the size/fit for the this specific component """
    def search_product_options(self, *args):
        comp_types = self.choices_comp[self.entry_type_comp.get()]
        self.entry_size_fitment.set(comp_types[0])

        menu = self.optionmenu_size_fitment['menu']
        menu.delete(0, 'end')

        for comp_type in comp_types:
            menu.add_command(label=comp_type, command=lambda c_type=comp_type: self.entry_size_fitment.set(c_type))

    # Check if number of batch exist
    def check_batch_number_exist(self):
        entry_batch_no = self.entry_batch_no.get()
        # Check if the bacth insert is a number
        if self.isNumber(entry_batch_no):
            new_batch = Batch(entry_batch_no, None)
            batch_num = new_batch.create_batch_number()

            try:
                data = self.create_json_file()
                temp_list = []
                # Access data
                for dict_obj in data['Batch']:
                    temp_list.append(dict_obj['number'])

                if batch_num in temp_list:
                    messagebox.showinfo('Oooops!!', 'The batch number ' + batch_num + ' already exist')
                else:
                    self.show_msg_before_save()
            except (ValueError, KeyError, TypeError):
                messagebox.showerror('Comp Json Error', 'Is not a number, enter a valid number.')
        else:
            messagebox.showerror('Warning', 'Is not a number, enter a valid number.')

    # Check the input is a number
    def isNumber(self, value):
        try:
            val = int(value) # check if the parameter passed is numeric
            return True # if so return True
        except (TypeError, ValueError): # if the params is not numeric the exception is a TypeError or ValueError
            return False # return False

    # This method create a menu with a dropdown to choice options
    def create_menu(self):
        # Create a container to hold all label for menu
        self._menu_frame.grid(column=0, row=8, padx=10,
                              pady=10, ipadx=40, sticky=tk.W)

        # Dictionary with options
        choices = {'1', '2', '3', '4', '5'}
        # set the default label in the dropdown option
        self.tk_var.set('Options')

        # Create the Dropdown Menu Option
        OptionMenu(self._menu_frame, self.tk_var, *sorted(choices)).grid(column=1, row=5, ipadx=5)

        # Place labels into the container element menu_frame
        ttk.Label(self._menu_frame, text="1. Create a New Batch").grid(
            column=0, row=0, sticky=tk.W)
        ttk.Label(self._menu_frame, text="2. List All Batches").grid(
            column=0, row=1, sticky=tk.W)
        ttk.Label(self._menu_frame, text="3. View details of a Batch").grid(
            column=0, row=2, sticky=tk.W)
        ttk.Label(self._menu_frame, text="4. View Details of Components").grid(
            column=0, row=3, sticky=tk.W)
        ttk.Label(self._menu_frame, text="5. Quit").grid(
            column=0, row=4, sticky=tk.W)
        ttk.Label(self._menu_frame, text="Choose the option:").grid(
            column=0, row=5, ipady=10, sticky=tk.W)

        # link function to change dropdown and pass the choice as an argument
        self.tk_var.trace('w', self.change_dropdown)

        for child in self._menu_frame.winfo_children():
            child.grid_configure(padx=10, pady=4)

    # This method create a frame with all input to create a new batch
    def create_new_batch(self):
        self._show_details_frame.grid_remove()
        self._list_batch_frame.grid_remove()
        self._detail_batch_frame.grid_remove()
        self._detail_comp_frame.grid_remove()

        # Create a new Object from Batch class
        new_batch = Batch(batch_number='0', serial_number='0')
        # remove the button for exit to application
        self._show_details_frame.grid_remove()
        # Create a container to hold all label for menu
        self._create_batch_frame.grid(
            column=0, row=10, padx=10, pady=10, ipadx=40, sticky=(tk.N, tk.W, tk.E, tk.S))
        # Place labels into the container element create new batch
        ttk.Label(self._create_batch_frame, text="Batch number:").grid(
            column=0, row=0, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._create_batch_frame, text="{}".format(new_batch._date_manufacture)).grid(
            column=1, row=0, padx=0, pady=10, sticky=tk.W)
        ttk.Label(self._create_batch_frame, text="How many components\n in this Batch (1 to 9999):").grid(
            column=0, row=1, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._create_batch_frame, text="Select component type:").grid(
            column=0, row=2, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._create_batch_frame, text="Select Size/Fitment type:").grid(
            column=0, row=3, padx=10, pady=10, sticky=tk.W)
        # Place Entry into the container element create new batch
        ttk.Entry(self._create_batch_frame, textvariable=self.entry_batch_no).grid(
            column=1, row=0, padx=52, pady=10)
        ttk.Entry(self._create_batch_frame, textvariable=self.entry_components).grid(
            column=1, row=1)
        # Place Dropdown into the container element create a new batch
        self.entry_type_comp.trace('w', self.search_product_options)

        self.optionmenu_type_comp = OptionMenu(self._create_batch_frame, self.entry_type_comp, *sorted(self.choices_comp.keys()))
        self.optionmenu_size_fitment = OptionMenu(self._create_batch_frame, self.entry_size_fitment, '')

        self.entry_type_comp.set('Door handle')

        self.optionmenu_type_comp.grid(column=1, row=2, padx=20, pady=10, ipadx=5)
        self.optionmenu_size_fitment.grid(column=1, row=3, padx=20, pady=10, ipadx=5)

        # Place Buttons into the container element create new batch and call the methods check_batch_number_exist
        ttk.Button(self._create_batch_frame, text="Create Batch", command=self.check_batch_number_exist).grid(
            column=0, row=4, padx=10, pady=10, sticky=tk.W)

    # Show the message on separated windows of the batch created.
    def show_msg_before_save(self):
        entry_batch_no = self.entry_batch_no.get()
        entry_no_comps = self.entry_components.get()
        entry_type_comps = self.entry_type_comp.get()
        entry_size_fit = self.entry_size_fitment.get()
        # Call Date Class
        new_batch = Batch(entry_batch_no, entry_no_comps)
        sn_comps = new_batch.create_sn_component(entry_type_comps, entry_size_fit)
        batch_num = new_batch.create_batch_number()
        # Save in a variable the value return from Batch Object
        date_manufacture = new_batch._date_manufacture
        # Setting up the message box
        show_msg_saving = messagebox.askyesno(
            'Warning!',
            'This batch No {}\ncreated at {}\ncontains {} {} {}\n\n\tis this correct!'.format(
                batch_num, date_manufacture, len(sn_comps), entry_size_fit, entry_type_comps, _icon='warning')
        )
        # If click "yes" the details insert is saved on BatchIndex.json file
        if show_msg_saving:
            # Setting up the messagebox for show batch detail
            show_msg_details = messagebox.askyesno(
                'Batch Created',
                'Batch and Component records created at {} on {}\n\nShow Batch details?'.format(
                    new_batch._batch_create, date_manufacture, _icon='info')
            )
            # If click "Yes" The batch details are displayed
            if show_msg_details:
                self.show_details_batch()
            # Call the method that Save the detail on json file
            self.save_batch_to_json_file(self._inventory)
            self.create_batch_pkl_file()
            self.create_comp_pkl_file()

    # Show the details of the batch created
    def show_details_batch(self):
        print('New Batch Details Method Called')
        entry_batch_no = self.entry_batch_no.get()
        entry_no_comps = self.entry_components.get()
        entry_type_comps = self.entry_type_comp.get()
        entry_size_fit = self.entry_size_fitment.get()
        # Call Date Class
        new_batch = Batch(entry_batch_no, entry_no_comps)
        sn_comps = new_batch.create_sn_component(entry_type_comps,entry_size_fit)
        batch_num = new_batch.create_batch_number()
        comp_location = new_batch._location

        sn = []
        comps = []
        for item in sn_comps:
            sn.append(item['sn_component'] )
            comps.append(item['sn_component'] + ' ' + item['status'])

        comps = "\n\t".join(comps)

        # Save in a variable the value return from Batch Object
        date_manufacture = new_batch._date_manufacture
        # remove the button for exit to application
        self._create_batch_frame.grid_remove()
        # Create a container to hold all label for menu
        self._show_details_frame.grid(column=0, row=10, padx=10, pady=10, ipadx=40, sticky=(tk.N, tk.W, tk.E, tk.S))
        # Place labels into the container element create new batch
        ttk.Label(self._show_details_frame, text="Batch number:\t{}".format(batch_num)).grid(
            column=0, row=0, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._show_details_frame, text="Manufacture Date:\t{}".format(date_manufacture)).grid(
            column=0, row=1, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._show_details_frame, text="Component type:\t{}".format(entry_type_comps)).grid(
            column=0, row=2, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._show_details_frame, text="Component Size/Fitment type: {}".format(entry_size_fit)).grid(
            column=0, row=3, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._show_details_frame, text="SerialNumbers: {}".format(sn)).grid(
            column=0, row=4, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._show_details_frame, text="Component Status: [\n\t{}\n\t]".format(comps)).grid(
            column=0, row=5, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._show_details_frame, text="Component Location: {}".format(comp_location)).grid(
            column=0, row=6, padx=10, pady=10, sticky=tk.W)

    # This method show all batches
    def list_all_batches(self):
        self._show_details_frame.grid_remove()
        self._create_batch_frame.grid_remove()
        self._detail_batch_frame.grid_remove()
        self._detail_comp_frame.grid_remove()

        # Open file json for retrieving all batch saved
        fh = open(self.file_path_name_w, 'r')
        data_file = json.load(fh)
        fh.close()

        # Loop for display all list Batches
        r = 1
        for list_batch in data_file['Batch']:
            batch_number = list_batch['number']
            quantity_comp = list_batch['quantity_comp']
            for comp in list_batch['component']:
                type_components = comp['type_components']
                size_fitment_comps = comp['size_fitment_comps']

            # Place labels into the container element create row for each batch
            ttk.Label(self._list_batch_frame, text=batch_number).grid(column=0, row=r, padx=10, pady=10, sticky=tk.W)
            ttk.Label(self._list_batch_frame, text=type_components).grid(column=1, row=r, padx=10, pady=10, sticky=tk.W)
            ttk.Label(self._list_batch_frame, text=size_fitment_comps).grid(column=2, row=r, padx=10, pady=10, sticky=tk.W)
            ttk.Label(self._list_batch_frame, text=quantity_comp).grid(column=3, row=r, padx=10, pady=10, sticky=tk.W)

            r += 1

        # Create a container to hold all label for menu
        self._list_batch_frame.grid(column=0, row=10, padx=10, pady=10, ipadx=40, sticky=(tk.N, tk.W, tk.E, tk.S))
        # Place labels into the container element create new batch
        ttk.Label(self._list_batch_frame, text="Batch number").grid(column=0, row=0, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._list_batch_frame, text="Type").grid(column=1, row=0, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._list_batch_frame, text="Size/Fitment").grid(column=2, row=0, padx=10, pady=10, sticky=tk.W)
        ttk.Label(self._list_batch_frame, text="Quantity Made").grid(column=3, row=0, padx=10, pady=10, sticky=tk.W)

    # Show detail of the batch
    def view_details_batch(self):
        self._show_details_frame.grid_remove()
        self._create_batch_frame.grid_remove()
        self._detail_comp_frame.grid_remove()
        self._list_batch_frame.grid_remove()

        # Create a container to hold all label for menu
        self._detail_batch_frame.grid(
            column=0, row=10, padx=10, pady=10, ipadx=40, sticky=(tk.N, tk.W, tk.E, tk.S))
        # Place labels into the container element create new batch
        ttk.Label(self._detail_batch_frame, text="Batch number:").grid(
            column=0, row=0, padx=10, pady=10, sticky=tk.W)
        # Place Entry into the container element create new batch
        ttk.Entry(self._detail_batch_frame, textvariable=self.entry_batch_no).grid(
            column=1, row=0, padx=52, pady=10)
        # Place Buttons into the container element create new batch
        ttk.Button(self._detail_batch_frame, text="Show Details", command=lambda : self.check_batch_exist(self.entry_batch_no.get())).grid(
            column=0, row=9, padx=10, pady=10, sticky=tk.W)

    # Check if batch exist, receive parameter from view_details_batch()
    def check_batch_exist(self, code):
        # Check if the bacth insert is a number
        if self.isNumber(code):

            if os.path.exists('../Data/' + code + '.pkl'):
                fhb = open('../Data/' + code + '.pkl', 'rb+')
                data = pickle.load(fhb)
                comps = []
                compStatus = []

                if code in data.keys():
                    # if the code is correct and exist execute the statement
                    batchDetail = data[code]  # pass to variable the element value to collect the right elements from the same list
                    ttk.Label(self._detail_batch_frame, text="Batch Number:\t{}".format(batchDetail[0])).grid(column=0, row=1, padx=10, pady=10, sticky=tk.W)
                    ttk.Label(self._detail_batch_frame, text="Manufacture date:\t{}".format(batchDetail[2])).grid(column=0, row=3, padx=10, pady=10, sticky=tk.W)
                    ttk.Label(self._detail_batch_frame, text="Type:\t{}".format(batchDetail[4][0][1])).grid(column=0, row=4, padx=10, pady=10, sticky=tk.W)
                    ttk.Label(self._detail_batch_frame, text="Size/Fit:\t{}".format(batchDetail[4][0][2])).grid(column=0, row=5, padx=10, pady=10, sticky=tk.W)
                    ttk.Label(self._detail_batch_frame, text="Number Components in Batch:\t{}".format(batchDetail[1])).grid(column=0, row=6, padx=10, pady=10, sticky=tk.W)
                    n_comps = int(batchDetail[1])
                    i = 0
                    for i in range(n_comps):
                        comps.append(batchDetail[4][i][0])
                        compStatus.append(batchDetail[4][i][0] + ' ' + batchDetail[4][i][3])

                    ttk.Label(self._detail_batch_frame, text="SN Component:\t{}".format(comps)).grid(column=0, row=7, padx=10, pady=10, sticky=tk.W)
                    ttk.Label(self._detail_batch_frame, text="Component Status: [\n\t{}\n\t]".format("\n\t".join(compStatus))).grid(column=0, row=8, padx=10, pady=10, sticky=tk.W)

                return True

            else:
                messagebox.showwarning('Warning','Batch not found')
                return False
        else:
            messagebox.showerror('Warning', 'Is not a number, enter a valid number.')

    # Show detail of components
    def view_details_comp(self):
        self._show_details_frame.grid_remove()
        self._create_batch_frame.grid_remove()
        self._detail_batch_frame.grid_remove()
        self._list_batch_frame.grid_remove()

        # Create a container to hold all label for menu
        self._detail_comp_frame.grid(
            column=0, row=10, padx=10, pady=10, ipadx=40, sticky=(tk.N, tk.W, tk.E, tk.S))
        # Place labels into the container element create new batch
        ttk.Label(self._detail_comp_frame, text="Component SN:").grid(
            column=0, row=0, padx=10, pady=10, sticky=tk.W)
        # Place Entry into the container element create new batch
        ttk.Entry(self._detail_comp_frame, textvariable=self.entry_components).grid(
            column=1, row=0, padx=52, pady=10)
        # Place Buttons into the container element create new batch
        ttk.Button(self._detail_comp_frame, text="Show Details", command=lambda : self.check_comp_exist(self.entry_components.get())).grid(
            column=0, row=7, padx=10, pady=10, sticky=tk.W)

    # Check if component exist by receiving parameter from view_details_comp()
    def check_comp_exist(self, code):
        # Check if the bacth insert is a number
        #if self.isNumber(code):

        if os.path.exists('../Data/' + code + '.pkl'):
            fhb = open('../Data/' + code + '.pkl', 'rb+')
            data = pickle.load(fhb)

            if code in data.keys():
                # if the code is correct and exist execute the statement
                compDetail = data[code]  # pass to variable the element value to collect the right elements from the same list
                ttk.Label(self._detail_comp_frame, text="Component Detail for:\t{}".format(compDetail[0])).grid(column=0, row=1, padx=10, pady=10, sticky=tk.W)
                ttk.Label(self._detail_comp_frame, text="Type:\t{}".format(compDetail[1])).grid(column=0, row=2, padx=10, pady=10, sticky=tk.W)
                ttk.Label(self._detail_comp_frame, text="Size/Fit:\t{}".format(compDetail[2])).grid(column=0, row=3, padx=10, pady=10, sticky=tk.W)
                ttk.Label(self._detail_comp_frame, text="Date of Manufacture:\t{}".format(compDetail[3])).grid(column=0, row=4, padx=10, pady=10, sticky=tk.W)
                ttk.Label(self._detail_comp_frame, text="Current Status:\t{}".format(compDetail[4])).grid(column=0, row=5, padx=10, pady=10, sticky=tk.W)
                ttk.Label(self._detail_comp_frame, text="Part of Batch:\t{}".format(compDetail[6])).grid(column=0, row=6, padx=10, pady=10, sticky=tk.W)

            return True

        else:
            messagebox.showwarning('Warning','Component not found')
            return False
        #else:
            #messagebox.showerror('Warning', 'Is not a number, enter a valid number.')

    """ The method save_batch_to_json_file() is called when you click "yes" on the message box that appear
        when click "Create batch" button and save all data in BatchIndex.json file.
    """
    def save_batch_to_json_file(self, inventory):
        entry_batch_no = self.entry_batch_no.get()
        entry_no_comps = self.entry_components.get()
        entry_type_comps = self.entry_type_comp.get()
        entry_size_fit = self.entry_size_fitment.get()
        # Call Date Class
        new_batch = Batch(entry_batch_no, entry_no_comps)
        sn_comps = new_batch.create_sn_component(entry_type_comps,entry_size_fit)
        batch_num = new_batch.create_batch_number()
        manufacture_date = new_batch._date_manufacture
        # Dictionary to collect data and save into json file
        a_dict = {}
        #data = self.create_json_file()
        temp_list = []
        for dic_obj in inventory["Batch"]:
            temp_list.append(dic_obj)
        qty_comp = entry_no_comps
        temp_list.append(
            {'number': batch_num,
            'quantity_comp': qty_comp,
            'location': new_batch._location,
            'manufacture_date': manufacture_date,
            'component': sn_comps
            })
        inventory["Batch"] = temp_list
        a_dict["Batch"] = inventory["Batch"]
        self.save_data(a_dict)
        # Clear the entry one the file is created to set with empty string
        self.entry_batch_no.set('')
        self.entry_components.set('')

    # Method that close Application
    def close_app(self):
        # Below line is just for testing if everything work
        msgbox_exit = messagebox.askyesno(
            'Exit Program', 'Are you sure want to EXIT!', icon='warning')
        if msgbox_exit:
            # Below line is just for testing if everything work
            print('Close App method Called')
            self.quit()
        else:
            # Below line is just for testing if everything work
            print('Return to menu')

# ====================
# Start GUI
# ====================
if __name__ == "__main__":
    _frame = tk.Tk()
    app = App(_frame)
    app.mainloop()


def subsetA(arr):
    results = []
    arr.sort()
    arr_len = len(arr)
    result_sum = 0
    arr_sum = sum(arr)
    # 大きい数字から合計して探索を行う
    for index in range(arr_len - 1, -1, -1):
        results.append(arr[index])
        result_sum += arr[index]
        arr_sum -= arr[index]
        if result_sum > arr_sum:
            break
    results.sort()
    return results

if __name__ == '__main__':
    n = int(input())
    arr = []
    for i in range(n):
        arr.append(int(input()))
    results = subsetA(arr)
    for result in results:
        print(result)


##Solution to Project Euler problem 15
##Author: Andy Shu Xin
##License: CC0. All rights waived.

from __future__ import print_function

BORDER = 20

def getRoutes(coordinate, M):
    if coordinate in M:
        return M[coordinate]
    else:
        res =  getRoutes((coordinate[0] + 1, coordinate[1]), M) + \
               getRoutes((coordinate[0], coordinate[1] + 1), M)
        M[coordinate] = res
        return res

def main():
    M = {}
    for i in range(0, BORDER+1):
        M[BORDER,i] = 1
        M[i,BORDER] = 1
    M[BORDER+1, BORDER+1] = 0
    return getRoutes((0,0), M)

if __name__ == '__main__':
    #import cProfile
    #cProfile.run('main()')
    print(main())


#!/usr/bin/python3
"""This module contains the square
"""
from models.rectangle import Rectangle

class Square(Rectangle):
    """Class square
    Args:
        Rectangle (class): Sub class which is now also a super class
    """
    def __init__(self, size, x=0, y=0, id=None):
        """Initializer/Constructor
        Args:
            size (int): Size of a side
            x (int, optional): X. Defaults to 0.
            y (int, optional): Y. Defaults to 0.
            id (int): ID. Defaults to None.
        """
        super().__init__(size, size, x, y, id)

    def __str__(self):
        """Prints pretty
        Returns:
            str: Pretty format
        """
        return "[Square] ({}) {}/{} - {}"\
            .format(self.id, self.x, self.y, self.width)

    @property
    def size(self):
        """Getter for size
        Returns:
            int: size
        """
        return self.width

    @size.setter
    def size(self, val):
        """setter for size
        Args:
            val (int): Size
        """
        self.width = val
        self.height = val

    def update(self, *args, **kwargs):
        """Updates stuff
        """
        if args:
            count = 0
            for val in args:
                if count is 0:
                    self.id = val
                    count += 1
                elif count is 1:
                    self.width = val
                    self.height = val
                    count += 2
                elif count is 3:
                    self.x = val
                    count += 1
                elif count is 4:
                    self.y = val
                    count += 1
        else:
            if "id" in kwargs:
                self.id = kwargs["id"]
            if "size" in kwargs:
                self.width = kwargs["size"]
                self.height = kwargs["size"]
            if "x" in kwargs:
                self.x = kwargs["x"]
            if "y" in kwargs:
                self.y = kwargs["y"]

    def to_dictionary(self):
        """Returns a dictionary representation of itself
        Returns:
            dict: the representation of the object
        """
        return {"id": self.id, "size": self.width,
                "x": self.x, "y": self.y}


"""
        _________________

        Game's parameters
        _________________
"""

import pygame
from pygame import *
from pygame.locals import *
import time
import random

# Game PARAMETERS
TICK_LIMIT = 30

# Display
SPRITE_SIZE = 30
SPRITE_HEIGHT = 22
SPRITE_WIDTH = 19
WINDOW_SIZE = (SPRITE_WIDTH * SPRITE_SIZE, SPRITE_HEIGHT * SPRITE_SIZE)
WINDOW_TITLE = "AIPAC-MAN"

ICON = "resources/pacman_right.png"

# Import resources
root = "resources/"
LEVEL_MAP = root+"map.txt"
HOME_SCREEN = root+"home.jpeg"
#HOME_SCREEN = root+"home2.png"
BACKGROUND_IMG = root+"pacman_up.png"
WALL_IMG = root+"wall.png"
WAY_IMG = root+"bck.jpg"
POINT_IMG = root+"point.png"

# Pacman direction images
PACMAN_UP = root+"pacman_up.png"
PACMAN_RIGHT = root+"pacman_right.png"
PACMAN_DOWN = root+"pacman_down.png"
PACMAN_LEFT = root+"pacman_left.png"

# Ghost color images
GHOST_RED = root+"ghost_red.png"
GHOST_YELLOW = root+"ghost_yellow.png"
GHOST_GREEN = root+"ghost_green.jpg"


from bs4 import BeautifulSoup
import scrapy

class HnSpider(scrapy.Spider):
    name = "hacker-news"
    allowed_domains = ["news.ycombinator.com"]
    start_urls = [f'https://news.ycombinator.com/news?p={i}' for i in range(1,16)]

    def parse(self, response):
        soup = BeautifulSoup(response.text, 'html.parser')
        links = soup.findAll('tr', class_='athing')

        for link in links:
        	yield {
        		'id': link['id'],
        		'title': link.find_all('td')[2].a.text,
        		"url": link.find_all('td')[2].a['href'],
        		"rank": int(link.td.span.text.replace('.', ''))
        	}


# -*- coding: utf-8 -*-
"""
Created on Wed Jul 31 13:45:42 2019

@author: Narink
"""

import matplotlib.pyplot as plt
import numpy as np

plt.plot()
plt.xlabel('x label')
plt.ylabel('y label')
plt.title('title')
plt.suptitle('super title')

x=np.linspace(0,2,100)
print(x)
print(type(x))

y=(0.5*x)+1.7
y2=x**2 # x*x
print(y)

plt.plot(x,y,color='red',linestyle='--',label='linear')
plt.plot(x,y2,color='green',label='exponential',marker='x')
plt.legend()

plt.xlim(right=2.5)
plt.ylim(top=4.5)
plt.fill_between(x,y,y2,color='pink')


## Script to rescale images and to create data sets X, y and LabelToNumer for genera and species classification

import pyexiv2
import sys
import os
import magic
import re
import cv2
import numpy as np

## lists are yspecies and ygenus from plot_inventory_exif.py
genera = ['Leptophryne', 'Microhyla', 'Fejervarya', 'Polypedates', 'Limnonectes', 'Chalcorana', 'Rhacophorus',
          'Nyctixalus', 'Amnirana', 'Phrynoidis', 'Odorrana', 'Ingerophrynus', 'Sumaterana', 'Pelophryne', 'Pulchrana',
          'Occidozyga', 'Hylarana', 'Leptobrachium', 'Megophrys', 'Huia', 'Philautus', 'Ansonia']
species = ['borbonica', 'heymonsi', 'achatina', 'limnocharis', 'leucomystax', 'otilophus', 'macrotis', 'paramacrodon',
           'sisikdagu', 'blythii', 'hikidai', 'kuhlii', 'macrodon', 'chalconota', 'rufipes', 'prominanus',
           'cyanopunctatus', 'catamitus', 'margaritifer', 'poecilonotus', 'pictum', 'nicobariensis', 'asper',
           'juxtasper', 'hosii', 'parvus', 'dabulescens', 'crassiovis', 'montana', 'signata', 'debussyi', 'rawa',
           'glandulosa', 'picturata', 'sumatrana', 'erythraea', 'hasseltii', 'nasuta', 'masonii']

## Function to rescale the images from rectangular to squared images with given edge lenght.
## Longer edge of original edge is resized to given edge length without distortion.
## Black borders are added to shorter edge to get squared format
def pad(image, length):
    ## get length and width of given image
    origlength, origwidth = image.shape[:2]
    ## if image is portrait format set length to given length without distortion
    if origlength > origwidth:
        ratio = length / float(origlength)
        resizedwidth = int(origwidth * ratio)
        dimensions = (resizedwidth, length)
        resized = cv2.resize(image, dimensions, interpolation=cv2.INTER_CUBIC)
        ## calculate size of borders to get squared image and add black border
        left = int((length - resizedwidth) / 2)
        right = left
        top = 0
        bottom = 0
        resized = cv2.copyMakeBorder(resized, top, bottom, left, right, cv2.BORDER_CONSTANT, 0)

    else:
        ## if image is landscape format set width to given length without distortion
        ratio = length / float(origwidth)
        resizedlength = int(origlength * ratio)
        dimensions = (length, resizedlength)
        resized = cv2.resize(image, dimensions, interpolation = cv2.INTER_CUBIC)
        ## calculate size of borders to get squared image and add black borders
        left = 0
        right = 0
        top = int((length - resizedlength) / 2)
        bottom = top
        resized = cv2.copyMakeBorder(resized, top, bottom, left, right, cv2.BORDER_CONSTANT, 0)
    ## return squared image with borders
    return resized

def rescale(X, y, labeltonumber, absolutimpath, label, length, resize):
    ## Use two approaches to get squared images:
    ## function pad: set long side of image to square length and add black or random noise to borders
    ## function resize: resize the image without caring about distortions
    ## size must be 299,299,3 for Xception
    origimage = cv2.imread(absolutimpath)
    if resize == 'distort':
        smallimage = cv2.resize(origimage, (length, length), interpolation=cv2.INTER_CUBIC)
    elif resize == 'pad':
        smallimage = pad(origimage, length)
    ## append all resized images in array and label numbers in other array at same index
    X.append(smallimage)
    y.append(labeltonumber.index(label))
    return X, y

## rescale images to squared images and create numpy arrays X, y and labeltonumber
def prepare_images(directory, resize, length, mode):
    labeltonumber = list()
    X = list()
    y = list()
    ## walk directories to find all images
    for root, dirs, files in os.walk(directory):
        for name in files:
            if name.endswith((".JPG", ".jpg")):
                ## get absolutepath because of git annex
                absolutimpath = os.path.realpath(os.path.join(root, name))
                if not os.path.exists(absolutimpath):
                    # print('path %s is a broken symlink' % name)
                    pass
                elif not magic.from_file(absolutimpath).startswith("JPEG image data"):
                    pass
                else:
                    ## read metadata from exif tags of images
                    metadata = pyexiv2.ImageMetadata(absolutimpath)
                    metadata.read()
                    tag = metadata['Exif.Photo.UserComment']
                    genus_species = tag.value
                    genus_species = genus_species.strip()
                    match = re.search(r'(\w+)\s(\w+)', genus_species)
                    genus = match.group(1)
                    genus = genus.strip()
                    ## if given mode is genus create dictionary with all genera as keys and numbers 1-n as value
                    if mode == 'genus':
                        label = genus
                        if label not in genera:
                            pass
                        else:
                            if label not in labeltonumber:
                                labeltonumber.append(label)
                            X, y = rescale(X, y, labeltonumber, absolutimpath, label, length, resize)

                        ## make sure genus sp. are not included in species dict
                    ## if given mode is species create dictionary with all species as keys and numbers 1-n as value
                    elif mode == 'species':
                        label = genus_species
                        ## do not use images were species is unknown
                        if match.group(2) in species:
                            if label not in labeltonumber:
                                labeltonumber.append(label)
                            X, y = rescale(X, y, labeltonumber, absolutimpath, label, length, resize)
                    else:
                        ## print error if mode is neither species or genus
                        sys.stderr.write(
                            'Usage: inventory_exif.py <path to directory containing .jpg files>, <pad> or <distort>,'
                            ' <length of resized image in pixel>, <width of resized image in pixel>, <genus> or <species>\n')

    ## create numpy array from each image in array of images
    X = np.array(X)
    y = np.array(y)
    labeltonumber = np.array(labeltonumber)
    # plt.imshow(X[1])
    # plt.show()
    print(len(X))
    print(len(y))
    ## return array of numpy array images and corresponding array of label numbers
    return X, y, labeltonumber

if len(sys.argv) != 5:
    sys.stderr.write(
        'Usage: xylabel_to_number.py <path to directory containing .jpg files>, <pad> or <distort>,'
        ' <edge length of resized image in pixel>, <genus> or <species>\n')
    sys.exit(1)
else:
    directory = sys.argv[1]
    resize = sys.argv[2]
    mode = sys.argv[4]
    length = int(sys.argv[3])

X, y, labeltonumber = prepare_images(directory, resize, length, mode)
print(X)
print(y)
print(labeltonumber)
## compress data and safe in npz file
np.savez_compressed('data_{}_{}'.format(mode, resize), X = X, y = y, labeltonumber = labeltonumber)


import os
import json
import pytest
import logging
import inspect

import asv

from collections import OrderedDict, defaultdict

from datetime import datetime
from pytest_benchmark.fixture import BenchmarkFixture
from pytest_benchmark.utils import NameWrapper

logger = logging.getLogger(__name__)

primary_stat_key = 'mean'

def pytest_bench_machine_to_asv(root, *, node, machine, system, release, cpu,
                                **kw):
    'Pytest-benchmark machine infomation to asv'
    asv_defaults = asv.machine.Machine.get_defaults()
    return dict(arch=machine,
                cpu=cpu['brand'],
                machine=node,
                os='{} {}'.format(system, release),
                ram=asv.util.human_file_size(asv_defaults['ram']),
                version=1,
                )

def get_bench_name(fullname, name):
    if name in asv_metadata:
        return name

    name, _, param_string = name.partition('[')
    return name

def single_asv_bench_result(*, start_dt, end_dt, fullname, options, stats,
                            extra_info, params, name, **kwargs):
    'Single benchmark result -> asv format'
    # non-parameterized version
    return dict(
        started_at=asv.util.datetime_to_js_timestamp(start_dt),
        ended_at=asv.util.datetime_to_js_timestamp(end_dt),
        results=dict(stats=dict(min=stats['min'],
                                max=stats['max'],
                                mean=stats['mean'],
                                std=stats['stddev'],
                                n=stats['iterations'],
                                ),
                     result=stats[primary_stat_key]
                     ),
    )

def asv_bench_result(name, md_list):
    'Single normal or parameterized benchmark result -> asv format'
    if not md_list:
        return dict(results=None)

    md0 = md_list[0]
    if len(md_list) == 1:
        return single_asv_bench_result(start_dt=md0['start_dt'],
                                       end_dt=md0['end_dt'],
                                       **md0['pytest_result'])
    else:
        # parameterized version - need to group params
        pytest_results = [md.get('pytest_result', {}) for md in md_list]
        param_names = md0['param_names']
        params = md0['all_params']

        def get_stat_key(key):
            return [res['stats'][key]
                    if res and 'stats' in res
                    else None
                    for res in pytest_results]

        return dict(
            param_names=param_names,
            params=params,
            result=get_stat_key(primary_stat_key),
            number=get_stat_key('iterations'),
        )

def match_asv_metadata(root):
    'Match global asv metadata with json-output pytest metadata'
    for bench in root['benchmarks']:
        bench_name, fullname = bench['name'], bench['fullname']
        name = get_bench_name(fullname, bench_name)
        for md in asv_metadata[name]:
            if md.get('_pytest_name') == bench_name:
                md.pop('_pytest_name')
                md['pytest_result'] = bench
                break

def pytest_bench_results_to_asv():
    'All benchmark results -> asv format'
    benches = defaultdict(lambda: {})

    # ensure at least 'results' key is available, even if all tests are parametrized
    benches['results']

    for name, md_list in asv_metadata.items():
        info = asv_bench_result(name, md_list)
        if 'params' in info:
            # parameterized ones have a dictionary of their own
            benches['results'][name] = info
        else:
            # ... whereas others are just part of general 'results'/etc dicts
            # and keyed by name
            benches['results'][name] = info.pop('results')
            for key, value in info.items():
                benches[key][name] = value
    return benches

def asv_bench_outline(name, md_list):
    'pytest benchmark outline -> asv'
    if not md_list:
        return {}

    md = md_list[0]
    return dict(
        code=md['code'],
        # goal_time=2.0,
        name=name,
        number=0,
        param_names=md['param_names'],
        params=md['all_params'],
        pretty_name=name,
        repeat=1,
        # timeout=60.0,
        type='time',
        unit='seconds',
    )

def pytest_bench_outline_to_asv():
    'All benchmark outlines -> asv format'
    outlined = {name: asv_bench_outline(name, md_list)
                for name, md_list in asv_metadata.items()
                }
    outlined.update(version=1)
    return outlined

def pytest_bench_to_asv(root):
    'pytest-benchmark info to asv'
    commit_info = root['commit_info']

    # TODO git timestamp formatting...
    commit_dt = datetime.strptime(commit_info['time'][:-6],
                                  "%Y-%m-%dT%H:%M:%S")

    machine_info = pytest_bench_machine_to_asv(root, **root['machine_info'])

    # copy over the machine info for the params
    params = dict(machine_info)
    python_version = root['machine_info']['python_version']
    params['python'] = python_version
    # but remove version as it's for the top-level
    del params['version']

    bench_results = dict(
        commit_hash=commit_info['id'],
        date=asv.util.datetime_to_js_timestamp(commit_dt),
        python=python_version,
        params=params,  # TODO
        profiles={},  # TODO
        requirements={},  # TODO
        env_name=os.environ.get('ASV_ENV_NAME', 'conda-py3.5'),  # TODO
        version=1,
    )

    # match asv metadata with pytest results
    match_asv_metadata(root)

    bench_results.update(**pytest_bench_results_to_asv())
    bench_outline = pytest_bench_outline_to_asv()

    return dict(machine_info=machine_info,
                bench_outline=bench_outline,
                bench_results=bench_results)

def save_asv_results(asv_path, *, machine_info, bench_outline, bench_results):
    results_top = os.path.join(asv_path, 'results')
    logger.debug('Saving results to %s', results_top)
    os.makedirs(results_top, exist_ok=True)

    machine_top = os.path.join(results_top, machine_info['machine'])
    machine_path = os.path.join(machine_top, 'machine.json')
    logger.debug('Saving machine info to %s', machine_path)
    os.makedirs(machine_top, exist_ok=True)

    with open(os.path.join(results_top, 'benchmarks.json'), 'wt') as f:
        json.dump(bench_outline, f, sort_keys=True, indent=4)

    with open(machine_path, 'wt') as f:
        json.dump(machine_info, f, sort_keys=True, indent=4)

    results_fn = '{}-{}.json'.format(bench_results['commit_hash'][:8],
                                     bench_results['env_name'],
                                     )
    bench_path = os.path.join(machine_top, results_fn)
    logger.debug('Saving benchmark results to %s', bench_path)

    with open(bench_path, 'wt') as f:
        json.dump(bench_results, f, sort_keys=True, indent=4)

def find_asv_root(path, *, asv_conf_filename='asv.conf.json',
                  asv_subdir='.asv'):
    test_path = os.path.join(path, asv_conf_filename)
    if os.path.exists(test_path):
        return os.path.join(path, asv_subdir)

    parent = os.path.join(*os.path.split(path)[:-1])
    if not parent:
        raise RuntimeError('Unable to find asv root path')

    return find_asv_root(parent)

@pytest.hookimpl(trylast=True, hookwrapper=True)
def pytest_benchmark_update_json(config, benchmarks, output_json):
    yield

    try:
        results = pytest_bench_to_asv(output_json)
        asv_path = find_asv_root('.')

        logger.info('Saving asv-style JSON to %s', asv_path)
        save_asv_results(asv_path, **results)
    except Exception:
        logger.exception('Failed to update pytest benchmark json; '
                         'asv results not saved')

def get_all_params_from_marked_test(node_or_func):
    'Returns (all_param_names, all_param_values)'
    # TODO: important - verify ordering of kwargs
    decorated_test = getattr(node_or_func, 'obj', node_or_func)

    arg_names = []
    arg_values = []
    kwarg_names = []
    kwarg_values = []
    for pinfo in decorated_test.pytestmark:
        if pinfo.name != 'parametrize':
            continue
        _arg_names, _arg_values = pinfo.args[::2], pinfo.args[1::2]
        _kwarg_names = list(sorted(pinfo.kwargs.keys()))
        _kwarg_values = [pinfo.kwargs[key] for key in _kwarg_names]
        arg_names += _arg_names
        arg_values += _arg_values
        kwarg_names += _kwarg_names
        kwarg_values += _kwarg_values

    return (list(arg_names) + kwarg_names,
            [[repr(arg) for arg in arg_list]
             for arg_list in list(arg_values) + kwarg_values]
            )

asv_metadata = {}

class AsvBenchmarkFixture(BenchmarkFixture):
    def __init__(self, *, node, **kwargs):
        self.node = node
        super().__init__(node=node, **kwargs)

    def generate_asv_metadata(self, function_to_benchmark, start_dt, end_dt):
        'Generate metadata for asv from pytest_benchmark information'
        callspec = self.node.callspec
        params = OrderedDict(
            (arg, callspec.params[arg])
            for arg in callspec.metafunc.fixturenames
            if arg in callspec.params
        )

        code = ''.join(inspect.getsourcelines(function_to_benchmark)[0])

        if params:
            name, _, param_string = self.name.partition('[')
            param_string = param_string.rstrip(']')
        else:
            name, param_string = self.name, ''

        return dict(start_dt=start_dt,
                    end_dt=end_dt,
                    code=code,
                    params=params,
                    name=name,
                    param_string=param_string,
                    )

    def __call__(self, function_to_benchmark, *args, **kwargs):
        start_dt = datetime.now()
        try:
            ret = super().__call__(function_to_benchmark, *args, **kwargs)
        finally:
            end_dt = datetime.now()

            md = self.generate_asv_metadata(function_to_benchmark, start_dt,
                                            end_dt)
            name = md['name']
            if name not in asv_metadata:
                asv_metadata[name] = []

            param_names, param_values = get_all_params_from_marked_test(self.node)
            md['param_names'] = param_names
            md['all_params'] = param_values

            md['_pytest_name'] = self.node.name
            logger.debug('md generated: name=%s md=%s', name, md)
            asv_metadata[name].append(md)

        return ret

@pytest.fixture(scope="function")
def asv_bench(request):
    bs = request.config._benchmarksession

    if bs.skip:
        pytest.skip("[asv] Benchmarks are skipped (--benchmark-skip was "
                    "used).")
    else:
        node = request.node
        marker = node.get_closest_marker("benchmark")
        options = marker.kwargs if marker else {}
        if "timer" in options:
            options["timer"] = NameWrapper(options["timer"])

        # use our subclass here to customize any pytest_benchmark behavior
        logger.debug('Added fixture instance for %s', node.name)

        fixture = AsvBenchmarkFixture(
            node=node,
            add_stats=bs.benchmarks.append,
            logger=bs.logger,
            warner=request.node.warn,
            disabled=bs.disabled,
            **dict(bs.options, **options)
        )
        request.addfinalizer(fixture._cleanup)
        return fixture

def get_conftest_globals():
    'Globals to be in conftest for this shim to work'
    return dict(pytest_benchmark_update_json=pytest_benchmark_update_json,
                benchmark=asv_bench,
                )


"""
 Import datetime
b) Create a class with the following attributes:
name
last name
surname
address
age
telephone
email
Create a method that based on today’s time can return the person’s age.
  For instance, if this person was born in (1992, 3, 12) and I use this method, I should get 28 as a result
"""

from datetime import date

class Person:
    def __init__(self, fname, lname, address, bday, tel, email):
        self.first_name = fname
        self.last_name = lname
        self.address = address
        self.birthday = date(bday[0], bday[1], bday[2])
        self.tel = tel
        self.email = email

    def getAge(self):
        age = date.today() - self.birthday
        return age.days // 365

p1 = Person("fname", "lname", "123 street", (1992, 3, 12), "555", "email@email")
print(p1.birthday, p1.getAge())


# -*- coding: utf-8 -*-
# @Time : 2020/5/24
# @Author : J
# @File : 图像上的算术运算.py
# @Software: PyCharm

import cv2 as cv
import numpy as np
img1 = cv.imread("../image2.jpg")
img2 = cv.imread("../image3.jpg")
dst = cv.addWeighted(img1,0.5,img2,0.5,0)
cv.namedWindow('dst',cv.WINDOW_NORMAL)
cv.imshow("dst",dst)
cv.waitKey(0)
cv.destroyAllWindows()

img1 = cv.imread('../image2.jpg')
img2 = cv.imread('../image3.png')
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
# 现在创建logo的掩码，并同时创建其相反掩码
img2gray = cv.cvtColor(img2,cv.COLOR_BGR2GRAY)
ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)
#src:灰度图  thresh阈值 maxval：最大值  type：阈值类型
# 第一个参数ret 为True 或者False,代表有没有读取到图片 mask：二值化的图像
# 将灰度图img2gray中灰度值小于10的点置0，灰度值大于175的点置255

mask_inv = cv.bitwise_not(mask)
# # 现在将ROI中logo的区域涂黑
img1_bg = cv.bitwise_and(roi,roi,mask = mask_inv)
# 仅从logo图像中提取logo区域
img2_fg = cv.bitwise_and(img2,img2,mask = mask)
# 将logo放入ROI并修改主图像
dst = cv.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst

cv.namedWindow('dst',cv.WINDOW_NORMAL)
cv.imshow('dst',img1)
cv.waitKey(0)
cv.destroyAllWindows()