import ast
from typing import Any, Dict, Tuple

from py2many.ast_helpers import get_id

class DeclarationExtractor(ast.NodeVisitor):
    def __init__(self, transpiler):
        self.transpiler = transpiler
        # maps name -> (type, default_value)
        self.annotated_members: Dict[str, Tuple[str, Any]] = {}
        self.class_assignments = {}
        self.member_assignments = {}
        self.typed_function_args = {}

    def _maybe_rename_key(self, key):
        if key in self.transpiler._keywords:
            return key + "_"
        else:
            return key

    def get_declarations(self):
        # strip out default values for backward compat with callers
        typed_members = {k: v[0] for k, v in self.annotated_members.items()}
        for member, var in self.member_assignments.items():
            if member in self.annotated_members:
                continue

            if var in self.typed_function_args:
                typed_members[member] = self.typed_function_args[var]

        for member, value in self.member_assignments.items():
            if member not in typed_members:
                typed_members[member] = self.transpiler._typename_from_annotation(value)

        typed_members = {self._maybe_rename_key(k): v for k, v in typed_members.items()}
        return typed_members

    def get_declarations_with_defaults(self):
        typed_members = self.annotated_members
        for member, var in self.member_assignments.items():
            if member in self.annotated_members:
                continue

            if var in self.typed_function_args:
                typed_members[member] = (self.typed_function_args[var], None)

        for member, value in self.member_assignments.items():
            if member not in typed_members:
                typed_members[member] = (
                    self.transpiler._typename_from_annotation(value),
                    None,
                )

        return typed_members

    def visit_ClassDef(self, node: ast.ClassDef):
        decorators = [get_id(d) for d in node.decorator_list]
        if len(node.decorator_list) > 0 and "dataclass" in decorators:
            node.is_dataclass = True
            dataclass_members = []
            for child in node.body:
                if isinstance(child, ast.AnnAssign):
                    self.visit_AnnAssign(child, dataclass=True)
                    dataclass_members.append(child)
            for m in dataclass_members:
                node.body.remove(m)
        else:
            node.is_dataclass = False
            self.generic_visit(node)

    def visit_AsyncFunctionDef(self, node):
        self.visit_FunctionDef(node)

    def visit_FunctionDef(self, node):
        types, names = self.transpiler.visit(node.args)

        for i in range(len(names)):
            typename = types[i]
            if typename and typename != "T":
                if names[i] not in self.typed_function_args:
                    self.typed_function_args[names[i]] = typename

        self.generic_visit(node)

    def visit_AnnAssign(self, node, dataclass=False):
        target = node.target
        target_id = get_id(target)
        if target_id is None:
            return

        # Preserve string based types (Forward refs) instead of converting them
        # to default type
        type_str = None
        if isinstance(node.annotation, ast.Constant):
            type_str = node.annotation.value
        if type_str is None:
            type_str = self.transpiler._typename_from_annotation(node)
        if target_id not in self.annotated_members:
            self.annotated_members[target_id] = (type_str, node.value)

        if not self.is_member(target):
            node.class_assignment = True
            if target not in self.class_assignments:
                self.class_assignments[target] = node.value

        if dataclass:
            type_str = self.transpiler._typename_from_annotation(node)
            if target_id not in self.annotated_members:
                self.annotated_members[target_id] = (type_str, node.value)

    def visit_Assign(self, node):
        target = node.targets[0]
        if self.is_member(target):
            if target.attr not in self.member_assignments:
                self.member_assignments[target.attr] = node.value
        else:
            node.class_assignment = True
            target = get_id(target)
            if target not in self.class_assignments:
                self.class_assignments[target] = node.value

    def is_member(self, node):
        if hasattr(node, "value"):
            if self.transpiler.visit(node.value) == "self":
                return True
        return False


def find_strongest_eggs(*args):
    sequence, num = args[0], args[1]
    sub_lists = [sequence[i::num] for i in range(num)]
    strongest_eggs = []

    for ll in sub_lists:
        middle = int(len(ll) / 2)
        first_half = ll[:middle]
        second_half = ll[middle + 1:]

        if ll[middle - 1] < ll[middle] > ll[middle + 1]:
            if [True for i, j in zip(first_half, second_half) if i < j]:
                strongest_eggs.append(ll[middle])
    return strongest_eggs

# Second Way:
# def find_strongest_eggs(eggs, sub_list_count):
#     best_eggs = []
#
#     for i in range(sub_list_count):
#         current = [eggs[idx] for idx in range(i, len(eggs), sub_list_count)]
#         mid_element = current[len(current) // 2]
#         left_element = current[len(current) // 2 - 1]
#         right_element = current[len(current) // 2 + 1]
#         if left_element < mid_element > right_element > left_element:
#             best_eggs.append(mid_element)
#
#     return best_eggs

test = ([-1, 7, 3, 15, 2, 12], 2)
print(find_strongest_eggs(*test))

test = ([-1, 0, 2, 5, 2, 3], 2)
print(find_strongest_eggs(*test))

test = ([51, 21, 83, 52, 55], 1)
print(find_strongest_eggs(*test))

Python Advanced/Exams/Python Advanced Retake Exam - 08 April 2020/03. Find the Eggs.py


# encoding=utf-8
import os

from win32com import client as wc

def doc2docxFun(path):
    w = wc.gencache.EnsureDispatch("Word.Application")
    # doc = w.Documents.Open(r"D:/data/测试.doc")  # 读取指定路径的doc
    # doc.SaveAs2(r"D:/data/测试.docx", 12)
    doc = w.Documents.Open(r"" + path + "")  # 读取指定路径的doc
    doc.SaveAs2(r"" + path + "x", 12)

path = "D:/data/"  # 需处理文件夹路径
files = []
for file in os.listdir(path):
    if file.endswith(".doc"):  # 排除文件夹内的其它干扰文件，只获取word文件
        files.append(path + file)
        doc2docxFun(path + file)
# doc2docxFun(path)


"""Change product table name

Revision ID: 35ce34d4e586
Revises: b8824e08d502
Create Date: 2021-12-22 09:27:33.697689

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = '35ce34d4e586'
down_revision = 'b8824e08d502'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('product',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('name', sa.String(), nullable=False),
    sa.Column('brand_id', sa.Integer(), nullable=True),
    sa.Column('category_id', sa.Integer(), nullable=True),
    sa.Column('attribute_id', sa.Integer(), nullable=True),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
    sa.ForeignKeyConstraint(['attribute_id'], ['attribute.id'], ),
    sa.ForeignKeyConstraint(['brand_id'], ['brand.id'], ),
    sa.ForeignKeyConstraint(['category_id'], ['category.id'], ),
    sa.PrimaryKeyConstraint('id')
    )
    op.drop_table('type_screen')
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('type_screen',
    sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
    sa.Column('name', sa.VARCHAR(), autoincrement=False, nullable=False),
    sa.Column('brand_id', sa.INTEGER(), autoincrement=False, nullable=True),
    sa.Column('category_id', sa.INTEGER(), autoincrement=False, nullable=True),
    sa.Column('attribute_id', sa.INTEGER(), autoincrement=False, nullable=True),
    sa.Column('created_at', postgresql.TIMESTAMP(), server_default=sa.text('now()'), autoincrement=False, nullable=True),
    sa.ForeignKeyConstraint(['attribute_id'], ['attribute.id'], name='type_screen_attribute_id_fkey'),
    sa.ForeignKeyConstraint(['brand_id'], ['brand.id'], name='type_screen_brand_id_fkey'),
    sa.ForeignKeyConstraint(['category_id'], ['category.id'], name='type_screen_category_id_fkey'),
    sa.PrimaryKeyConstraint('id', name='type_screen_pkey')
    )
    op.drop_table('product')
    # ### end Alembic commands ###


import pandas as pd
import geopandas as gpd
import osmnx as ox
import networkx as nx
from shapely.geometry import Point, LineString, Polygon
from config import cluster_time, dist, bike_speed, walk_speed
from mapHelpers import js_var, file_copy
import pygeos
import os
import matplotlib
from random import randint

def make_iso_polys(G, subgraph, edge_buff=25, node_buff=50, infill = False):
    isochrone_polys = []
    node_points = [Point((data["x"], data["y"])) for node, data in subgraph.nodes(data=True)]
    nodes_gdf = gpd.GeoDataFrame({"id": list(subgraph.nodes)}, geometry=node_points)
    nodes_gdf = nodes_gdf.set_index("id")

    nodes_gdf = nodes_gdf.set_crs(epsg = 4326)

    edge_lines = []
    for n_fr, n_to in subgraph.edges():
        f = nodes_gdf.loc[n_fr].geometry
        t = nodes_gdf.loc[n_to].geometry
        edge_lookup = G.get_edge_data(n_fr, n_to)[0].get("geometry", LineString([f, t]))
        edge_lines.append(edge_lookup)

    edge_gdf = gpd.GeoDataFrame({'geometry' : edge_lines}, geometry = 'geometry')
    edge_gdf = edge_gdf.set_crs(epsg = 4326)

    nodes_gdf = ox.project_gdf(nodes_gdf)
    edge_gdf = ox.project_gdf(edge_gdf)

    n = nodes_gdf.buffer(node_buff).geometry
    e = edge_gdf.buffer(edge_buff).geometry

    all_gs = list(n) + list(e)
    un = gpd.GeoSeries(all_gs).unary_union

    # if infill == True:
    un = Polygon(un.exterior)

    new_iso = gpd.GeoDataFrame({'geometry' : [un]}, geometry = 'geometry', crs = n.crs)
    new_iso.to_crs(epsg = 4326, inplace = True)

    return new_iso

def nodes_polys(G, node, destinations, radius, name, idx, brew_nodes, gdf_list):
    node_subgraph = nx.ego_graph(G, node, radius=radius, distance="length")
    graph_nodes = [str(node) for node in node_subgraph.nodes()]
    # graph_brews = list(set(brew_nodes) & set(graph_nodes))
    # destinations.loc[idx, name] = ','.join(graph_brews)
    gdf_list.append(make_iso_polys(G, node_subgraph))

def assign_cluster_id(join_gdf, id_name, destinations, color_ramp):
    join_gdf.reset_index(inplace = True)
    join_gdf.rename(columns = {'index' : id_name}, inplace = True)

    dest_project = ox.projection.project_gdf(destinations)
    join_gdf = ox.projection.project_gdf(join_gdf)

    dest_project = dest_project.sjoin_nearest(join_gdf, max_distance = 25)
    dest_project = dest_project[['node', id_name]].copy()

    mode_destinations = destinations.merge(dest_project, on = 'node', how = 'left')

    color_map = {}

    for idx in mode_destinations[id_name].unique():
        # normid =  idx / mode_destinations[id_name].max()
        cmap = matplotlib.cm.get_cmap(color_ramp)
        val = randint(0, 100) / 100
        hex = matplotlib.colors.rgb2hex(cmap(val))
        color_map[idx] = hex

    mode_destinations['color'] = mode_destinations[id_name].map(color_map)

    return mode_destinations

def popup_maker(gdf, name_field = 'Name', website_field = 'Website'):
    noweb = '{0}'
    web = '{0}'
    gdf['popup'] = gdf.apply(lambda r: web.format(r[name_field], r[website_field])\
                            if pd.notnull(r[website_field])\
                            else noweb.format(r[name_field]), axis = 1)

def cluster_creation(G, destinations, walk = True, bike = False, folder = None, walk_G = None, bike_G = None):
    xlist = destinations.geometry.x.to_list()
    ylist = destinations.geometry.y.to_list()
    nodelist = ox.nearest_nodes(G, X = xlist, Y = ylist)

    destinations['node'] = nodelist

    bike_dist = (bike_speed * 1000 * cluster_time / 60)
    walk_dist = (walk_speed * 1000 * cluster_time / 60)
    brew_nodes = destinations.node.to_list()
    brew_nodes = [str(node) for node in brew_nodes]

    walk_gdfs = []
    bike_gdfs = []

    for idx, val in destinations.iterrows():
        node = destinations.loc[idx, 'node']
        if walk:
            if walk_G:
                nodes_polys(walk_G, node, destinations, walk_dist, 'walk_nodes', idx, brew_nodes, walk_gdfs)
            else:
                nodes_polys(G, node, destinations, walk_dist, 'walk_nodes', idx, brew_nodes, walk_gdfs)

        if bike:
            if bike_G:
                nodes_polys(bike_G, node, destinations, bike_dist, 'bike_nodes', idx, brew_nodes, bike_gdfs)
            else:
                nodes_polys(G, node, destinations, bike_dist, 'bike_nodes', idx, brew_nodes, bike_gdfs)

    if walk:
        walk_gdf = pd.concat(walk_gdfs)
        walk_gdf = walk_gdf.dissolve().explode(ignore_index = True, index_parts = False)
        walk_mode = assign_cluster_id(walk_gdf, 'walk_id', destinations, 'nipy_spectral')
        popup_maker(walk_mode)

        if folder:
            walk_mode.to_file(os.path.join(folder, 'walk_region.js'), driver = 'GeoJSON')
            walk_gdf.to_file(os.path.join(folder, 'walk_clusters.js'), driver = 'GeoJSON')

    if bike:
        bike_gdf = pd.concat(bike_gdfs)
        bike_gdf = bike_gdf.dissolve().explode(ignore_index = True, index_parts = False)
        bike_mode = assign_cluster_id(walk_gdf, 'bike_id', destinations)
        popup_maker(bike_mode)

        if folder:
            bike_mode.to_file(os.path.join(folder, 'bike_region.js'), driver = 'GeoJSON')
            bike_gdf.to_file(os.path.join(folder, 'bike_clusters.js'), driver = 'GeoJSON')

    if walk and bike:
        return walk_mode, bike_mode
    elif walk:
        return walk_mode
    else:
        return bike_mode

def region_map(out_folder, start_point = None, out_name='region', type = 'walk'):
    brew_file = f"{type}_region.js"
    cluster_file = f"{type}_clusters.js"

    if start_point:
        lat, long = start_point
    else:
        gdf = gpd.read_file(os.path.join(out_folder, brew_file), driver = 'GeoJSON')
        ct = gdf.dissolve().centroid
        long, lat = ct.x.values[0], ct.y.values[0]

    js_var(os.path.join(out_folder, brew_file), 'brews')
    js_var(os.path.join(out_folder, cluster_file), 'clusters')
    file_copy('Templates', out_folder, ['geolet.js', 'map.css'])

    with open('Templates/region_map_template.html', 'r', encoding='utf-8') as file:
        data = file.readlines()

    data[8] = '		\n'.format(brew_file)
    data[9] = '		\n'.format(cluster_file)
    data[15] = '			var startLoc = [{0}, {1}]\n'.format(lat, long)

    map_path = '{0}/{1}.html'.format(out_folder, out_name)
    with open(map_path, 'w', encoding='utf-8') as file:
        file.writelines(data)

if __name__ == "__main__":
    G = ox.io.load_graphml('GraphML/denver_region_walk.graphml')
    ng = ox.graph_to_gdfs(G, edges = False)
    bl = ng.total_bounds
    bbox = (bl[0], bl[1], bl[2], bl[3])
    ds = gpd.read_file('Breweries/DenverBreweries', bbox = bbox)

    cluster_creation(G, ds, walk = True, bike = False, folder = 'RegionMap')
    region_map('RegionMap/')


from uplogic.events import send
from uplogic.nodes import ULActionNode
from uplogic.nodes import ULOutSocket

class ULDispatchEvent(ULActionNode):
    def __init__(self):
        ULActionNode.__init__(self)
        self.condition = None
        self.subject = None
        self.body = None
        self.target = None
        self.old_subject = None
        self.done = None
        self.OUT = ULOutSocket(self, self.get_done)

    def get_done(self):
        return self.done

    def evaluate(self):
        self.done = False
        if not self.get_input(self.condition):
            return
        subject = self.get_input(self.subject)
        body = self.get_input(self.body)
        target = self.get_input(self.target)
        send(subject, body, target)
        self.done = True


from flask import Blueprint, render_template, request, flash, redirect, session,g,jsonify
from flask.helpers import url_for
from .models import Customer, Order, Admin,Role,Driver,Truck,Checkpoint
from . import db
import json
from .auth import gen, getIdentity
from .helperFunc import *
from .camera import VideoCamera
from sqlalchemy.sql import func
import gc

def verifyUser(User):
    """
    Funtion to verify already authenticated user for its role
    Input - User Title (Admin,Customer,Driver)
    Function - First checks if user is authenticated, then checks that the right user is authenticated or not
                For example, user logged in as driver cannot access admin dashboard, or logged in as customer
                cannot access the admin dashboard
    Output - If the correct user is accessing the page, return true
    """
    if g.user:
        if User == "Admin":
            if session['role'] == 1:
                return True
        elif User == "Customer":
            if session['role'] == 2:
                return True
        elif User == "Driver":
            if session['role'] == 3:
                return True

views = Blueprint('views',__name__)

@views.route('/')
@views.route('/home')
def HomePage():

    if g.user:
        if session['role'] == 2:
            flash('You need to logout to visit the home page!',category='error')
            return redirect(url_for('views.userDashboard'))
        elif session['role'] == 1:
            flash('You need to logout to visit the home page!',category='error')
            return redirect(url_for('views.adminDashboard'))
        elif session['role'] == 3:
            flash('You need to logout to visit the home page!',category='error')
            return redirect(url_for('views.driverDashboard'))
    else:
        return render_template('home.html')

@views.route('/userDashboard')
def userDashboard():
    if g.user:
        cust = Customer.query.filter_by(email=session['email']).first()
        if cust:
            return render_template('userDashboard.html',customer=cust)
        elif session['role'] == 1:
            flash("You are an admin, not a customer!",category='error')
            return redirect(url_for('views.adminDashboard'))
        else:
            flash("You are a driver, not a customer!",category='error')
            return redirect(url_for('views.driverDashboard'))
    else:
        flash("Please login first as a customer",category='error')
        return redirect(url_for('auth.login'))

@views.route('/adminDashboard')
def adminDashboard():
    if g.user:
        if session['idmatch'] == True:
            admin = Admin.query.filter_by(email=session['email']).first()
            if admin:
                return render_template('adminDashboard.html')
            elif session['role'] == 2:
                flash("You are a customer, not an admin!",category='error')
                return redirect(url_for('views.userDashboard'))
            else:
                flash("You are a driver, not an admin!",category='error')
                return redirect(url_for('views.driverDashboard'))
        else:
            flash("Please confirm your identity!",category="error")
            return redirect(url_for('auth.faceRecognition'))
    else:
        flash("Please login first as an admin",category='error')
        return redirect(url_for('auth.login'))

@views.route('/driverDashboard')
def driverDashboard():
    if g.user:
        if session['idmatch'] == True:
            driver = Driver.query.filter_by(email=session['email']).first()
            if driver:
                return render_template('driverDashboard.html',driver=driver)
            elif session['role'] == 2:
                flash("You are a customer, not a driver!",category='error')
                return redirect(url_for('views.userDashboard'))
            else:
                flash("You are an admin, not a driver!",category='error')
                return redirect(url_for('views.adminDashboard'))
        else:
            flash("Please confirm your identity!",category="error")
            return redirect(url_for('auth.faceRecognition'))
    else:
        flash("Please login first as a driver",category='error')
        return redirect(url_for('auth.login'))

@views.route('/waitingLobby')
def waitingLobby():
    return render_template('waitingLobby.html')

@views.route('/driverApplications',methods=['GET','POST'])
def driverApplications():
    con = verifyUser("Admin")
    #Only admins can access this page
    if con:
        drivers = Driver.query.filter_by(status=0).all()
        return render_template('driverApplications.html',drivers=drivers)
    else:
        flash("Not an Admin!",category="error")
        return redirect(url_for('auth.logout'))

@views.route('reject-driver',methods = ['POST'])
def reject_driver():
    driver = json.loads(request.data)
    driverId = driver['driverId']
    driver = Driver.query.get(driverId)
    if driver:
        driver.status = 2
        db.session.commit()
    del driver
    del driverId
    gc.collect()
    return jsonify({})

@views.route('accept-driver',methods = ['POST'])
def accept_driver():
    driver = json.loads(request.data)
    driverId = driver['driverId']
    driver = Driver.query.get(driverId)
    if driver:
        driver.status = 1
        db.session.commit()
    del driver
    del driverId
    gc.collect()
    return jsonify({})

@views.route('/fireDriver',methods=['GET','POST'])
def fireDriver():
    con = verifyUser("Admin")
    if con:
        drivers = Driver.query.limit(10).all()
        return render_template('fireDriver.html',drivers=drivers)
    else:
        flash("Not an Admin!",category="error")
        return redirect(url_for('auth.logout'))

@views.route('fire-driver',methods = ['POST'])
def fire_driver():
    driver = json.loads(request.data)
    driverId = driver['driverId']
    driver = Driver.query.get(driverId)
    if driver:
        db.session.delete(driver)
        db.session.commit()
    del driver
    del driverId
    gc.collect()
    return jsonify({})

@views.route('/manageTrucks',methods=['GET','POST'])
def manageTrucks():
    con = verifyUser("Admin")
    if con:
        trucks = Truck.query.limit(30).all()
        driver = Driver.query.limit(30).all()
        if request.method == "POST":
            truckNo = request.form.get("truckNo")
            driverId = request.form.get('driverId')
            truck = Truck.query.filter_by(truckNumber = truckNo).first()
            driver = Driver.query.filter_by(id = driverId).first()
            if truck:
                flash("Truck already exists!",category='error')
            elif len(truckNo) < 6:
                flash("Invalid Truck Number. It should be greater than 6 characters!",category="error")
            elif driver:
                newTruck = Truck(truckNumber = truckNo)
                db.session.add(newTruck)
                db.session.commit()
                truck = Truck.query.filter_by(truckNumber = truckNo).first()
                driver.truckNumber = truck.id
                db.session.commit()
                flash("New Truck added!",category='success')
                del truckNo, driverId,truck,driver,newTruck
                gc.collect()
                return redirect(url_for('views.manageTrucks'))
            else:
                flash("Driver does not exist!",category='error')
        return render_template('manageTrucks.html',trucks=trucks,driver=driver)
    else:
        flash("Not an Admin!",category="error")
        return redirect(url_for('auth.logout'))

@views.route('delete-truck',methods = ['POST'])
def delete_truck():
    truck = json.loads(request.data)
    truckId = truck['truckId']
    truck = Truck.query.get(truckId)
    if truck:
        db.session.delete(truck)
        db.session.commit()
    del truck,truckId,truck
    gc.collect()
    return jsonify({})

@views.route('delete-checkpoint',methods = ['POST'])
def delete_checkpoint():
    checkpoint = json.loads(request.data)
    checkpointId = checkpoint['checkpointId']
    checkpoint = Checkpoint.query.get(checkpointId)
    if checkpoint:
        db.session.delete(checkpoint)
        db.session.commit()
    return jsonify({})

@views.route('/driverLocation',methods=['GET','POST'])
def driverLocation():
    con = verifyUser("Admin")
    if con:
        drivers = Driver.query.filter_by(status=1).all()
        checkp = Checkpoint.query.limit(10).all()
        if request.method == "POST":
            checkpoint = request.form.get("checkpoint")
            check = Checkpoint.query.filter_by(location=checkpoint).first()
            if check:
                flash("Checkpoint already exists!",category='error')
            elif len(checkpoint) < 4:
                flash("Checkpoint name must be greater than 4 characters!",category='error')
            else:
                newCheckpoint = Checkpoint(location = checkpoint)
                db.session.add(newCheckpoint)
                db.session.commit()
                flash("Checkpoint added successfully!",category='success')
                del drivers,checkp,checkpoint,check
                gc.collect()
                return redirect(url_for('views.driverLocation'))

        return render_template('driverLocation.html',drivers=drivers,checkpoints = checkp)
    else:
        flash("Not an Admin!",category="error")
        return redirect(url_for('auth.logout'))

@views.route("/manageOrder",methods = ['GET','POST'])
def manageOrder():
    con = verifyUser("Admin")
    if con:
        orders = Order.query.limit(30).all()
        truck = Truck.query.limit(30).all()
        driver = Driver.query.limit(30).all()
        cust = Customer.query.limit(30).all()
        checkpoint = Checkpoint.query.limit(10).all()
        if request.method == "POST":
            details = request.form.get("details")
            truckId = request.form.get("truckId")
            customerId = request.form.get("customerId")
            origin = request.form.get("origin")
            final = request.form.get("final")
            if (origin == "Banglore" or origin == "Mumbai" or origin == "Delhi") and (final == "Banglore" or final == "Mumbai" or final == "Delhi"):
                driverID = Driver.query.filter_by(truckNumber = truckId).first()
                newOrder = Order(customerId = customerId,details=details,truckNumber=truckId,origin=origin,finalStation=final,driverId=driverID.id)
                db.session.add(newOrder)
                db.session.commit()
                flash("Order created successfully!",category="success")
                del details,truckId,customerId,origin,final
                gc.collect()
                return redirect(url_for('views.manageOrder'))
            else:
                flash("Select the correct origin and final station!",category='error')
        return render_template('manageOrder.html',orders=orders,trucks=truck,checkp = checkpoint,cust=cust,driver=driver)
    else:
        flash("Not an Admin!",category="error")
        return redirect(url_for('auth.logout'))

@views.route('delete-order',methods = ['POST'])
def delete_order():
    order = json.loads(request.data)
    orderId = order['orderId']
    order = Order.query.get(orderId)
    if order:
        db.session.delete(order)
        db.session.commit()
    del order,orderId
    gc.collect()
    return jsonify({})

@views.route('/pendingOrder',methods = ['GET','POST'])
def pendingOrder():
    con = verifyUser("Driver")
    if con:
        #Check if driver has already started a previous journey before logging out
        order = Order.query.filter_by(driverId=session["user"]).all()
        if order:
            for o in order:
                if o.status == "Enroute":
                    flash("Please continue with the previous journey!",category='error')
                    return redirect(url_for('views.dFaceRecognition'))
        else:
            order = Order.query.filter_by(driverId=session["user"]).all()
        return render_template('pendingOrder.html',orders=order)
    else:
        flash("Not a Driver!",category="error")
        return redirect(url_for('auth.logout'))

@views.route('start-journey',methods = ['POST'])
def start_journey():
    order = json.loads(request.data)
    orderId = order['orderId']
    order = Order.query.get(orderId)
    if order:
        #Store oder info in session variable
        session['porder'] = order.id
    del order,orderId
    gc.collect()
    return jsonify({})

@views.route('/dFaceRecognition',methods=['GET','POST'])
def dFaceRecognition():
    #Function to begin journey by recognizing the face
    con = verifyUser("Driver")
    if con:
        if request.method == 'POST':
            identity = getIdentity(VideoCamera(),"toMatch")
            identityEnc = encFromByte(identity)
            driver = Driver.query.filter_by(email=session['email']).first()
            dbIdentity = encFromByte(driver.identity)
            result = is_match(dbIdentity,identityEnc)
            if result:
                flash('Identity confirmed! Happy Journey!',category="success")
                order = Order.query.filter_by(id = session['porder']).first()
                cp = Checkpoint.query.filter_by(location = order.origin).first()
                order.status = "Enroute"
                order.checkPoint = cp.id
                db.session.commit()
                #Store delivery stations in session variables
                session['begin'] = order.origin
                session['final'] = order.finalStation
                del identity,identityEnc,driver,dbIdentity,result
                gc.collect()
                return redirect(url_for('views.journey'))
            else:
                flash("Identity not matched! Please retry",category='error')

        return render_template('dFaceRecognition.html',Type = "begin")
    else:
        flash("Not a Driver!",category="error")
        return redirect(url_for('auth.logout'))

@views.route('/eFaceRecognition',methods=['GET','POST'])
def eFaceRecognition():
    #Function to end journey by recognizing the face
    con = verifyUser("Driver")
    if con:
        if request.method == 'POST':
            identity = getIdentity(VideoCamera(),"toMatch")
            identityEnc = encFromByte(identity)
            driver = Driver.query.filter_by(email=session['email']).first()
            dbIdentity = encFromByte(driver.identity)
            result = is_match(dbIdentity,identityEnc)
            if result:
                flash('Identity confirmed! Order delivered successfully!',category="success")
                order = Order.query.filter_by(id = session['porder']).first()
                order.status = "Delivered"
                order.dateDelivered = func.now()
                cp = Checkpoint.query.filter_by(location = session['final']).first()
                order.checkPoint = cp.id
                db.session.commit()
                #Pop session variables since order is delivered
                session["porder"] = ""
                session['begin'] = ""
                session.pop('final',None)
                del identity,identityEnc,driver,dbIdentity,result
                gc.collect()
                return redirect(url_for('views.driverDashboard'))
            else:
                flash("Identity not matched! Please retry",category='error')

        return render_template('dFaceRecognition.html',Type = "end")
    else:
        flash("Not a Driver!",category="error")
        return redirect(url_for('auth.logout'))

@views.route('/journey',methods = ['GET','POST'])
def journey():
    con = verifyUser("Driver")
    if con:
        img = "static/images/" + session['begin'][0] + "2" + session['final'][0] + ".png"
        if request.method == "POST":
            return redirect(url_for('views.eFaceRecognition'))
        return render_template('journey.html',img=img)
    else:
        flash("Not a Driver!",category="error")
        return redirect(url_for('auth.logout'))

@views.route('/completedOrder',methods = ['GET','POST'])
def completedOrder():
    con = verifyUser("Driver")
    if con:
        currentDriver = Driver.query.filter_by(email = session['email']).first()
        order = Order.query.filter_by(truckNumber = currentDriver.truckNumber).all()
        return render_template('completedOrder.html',orders=order)
    else:
        flash("Not a Driver!",category="error")
        return redirect(url_for('auth.logout'))

@views.route("/userOrder",methods = ['GET','POST'])
def userOrder():
    con = verifyUser("Customer")
    if con:
        cust = Customer.query.filter_by(email = session['email']).first()
        if cust:
            order = Order.query.filter_by(customerId = cust.id).all()
            return render_template('userOrder.html',orders=order)
    else:
        flash("Not a Customer!",category="error")
        return redirect(url_for('auth.logout'))

@views.route('track-order',methods = ['POST'])
def track_order():
    order = json.loads(request.data)
    orderId = order['orderId']
    order = Order.query.get(orderId)
    if order:
        session['porder'] = order.id
    del order,orderId
    gc.collect()
    return jsonify({})

@views.route('/trackOrder')
def trackOrder():
    con = verifyUser("Customer")
    if con:
        order = Order.query.filter_by(id = session['porder']).first()
        checkpoint = Checkpoint.query.filter_by(id = order.checkPoint).first()
        return render_template('trackOrder.html',order=order,cp = checkpoint)
    else:
        flash("Not a Customer!",category="error")
        return redirect(url_for('auth.logout'))

@views.route('/knowMore')
def knowMore():
    return render_template('knowMore.html')


n = int(input())
size = dict()
for i in range(n):
    size[i] = list(map(int, input().split()))
dp = [[0 for _ in range(n)] for _ in range(n)]
INF = 2**31-1

for diagonal in range(1, n):
    for row in range(n-diagonal):
        col = row+diagonal
        if diagonal == 1:
            dp[row][col] = size[row][0] * size[row][1] * size[col][1]
        else:
            dp[row][col] = INF
            for calculated in range(row, col):
                dp[row][col] = min(dp[row][col], dp[row][calculated]+dp[calculated+1][col]+size[row][0]*size[calculated][1]*size[col][1])

print(dp[0][-1])


'''
Server script
Get signal message from traiding view and save the message
'''
import logging
import os
import csv
from logging.handlers import RotatingFileHandler
from flask import Flask, request, jsonify
import bot_module  # 수정된 모듈 이름으로 import

app = Flask(__name__)

# Set Logger
logger = logging.getLogger("webhook_logger")
logger.setLevel(logging.INFO)

# Log Handler : Record log
handler = RotatingFileHandler('webhook.log', maxBytes=10000, backupCount=5)
logger.addHandler(handler)

# Error logging
@app.errorhandler(Exception)
def handle_exception(e):
    logger.error("An error occurred: %s", str(e))
    # print error info
    return "An error occurred", 500

# Take webhook(Traidingview) message
received_data = None

@app.route('/webhook', methods=['POST'])
def webhook():
    global received_data

    if request.is_json:
        received_data = request.json
    else:
        received_data = request.data.decode()  # Converting to String

    # Save message in csv
    with open('Webhook_Message.csv', 'w', newline='') as csvfile:
        csvwriter = csv.writer(csvfile)
        csvwriter.writerow([received_data])

    logger.info("Received webhook data: %s", received_data)  # Record log
    print(received_data)

    return jsonify({"status": "success"}), 200

# Get API : Return from another script
@app.route('/get-latest-data', methods=['GET'])
def get_latest_data():
    try:
        current_data = received_data
        if current_data is not None:
            return jsonify(current_data)
        else:
            return jsonify({"message": "No data available"}), 200
    except Exception as e:
        logger.error(f"An error occurred: {e}", exc_info=True)
        return jsonify({"error": "An unexpected error occurred"}), 500

# Add URL router
@app.route('/')
def index():
    return "Hello, World!"

# Handling website's favicon.ico
@app.route('/favicon.ico')
def favicon():
    return app.send_static_file('favicon.ico')

if __name__ == '__main__':
    # Initialization Webhook_Message.csv
    with open('Webhook_Message.csv', 'w', newline='') as csvfile:
        pass  # Save only new messages

    app.run(host='0.0.0.0', port=10080)


import asyncio
import json
import os
from typing import Dict, List, Tuple

import toml

from homework10.scalper import Scalper

class Worker:
    def __init__(self, number_of_elements: int):
        """
        Create class for collecting and filtering data about companies

        :param number_of_elements: Number of companies which information save
                                   to results
        :type number_of_elements: int
        """
        current_path = os.path.abspath(os.getcwd())
        current_path = os.path.join(current_path, 'homework10')
        info_file = os.path.join(current_path, 'links.toml')
        with open(info_file, 'r') as fi:
            info = toml.load(fi)
        # Filenames to save data
        self._files = {'price': os.path.join(current_path, 'price.json'),
                       'pe': os.path.join(current_path, 'pe.json'),
                       'growth': os.path.join(current_path, 'growth.json'),
                       'profit': os.path.join(current_path, 'profit.json')}

        self._scalper = Scalper(info)
        self._number_of_elements = number_of_elements

    async def _get_info(self) -> Tuple[float, List[Dict]]:
        """
        Collect _companies data from web

        :return: Current USD course, List with information about all companies
        :rtype: Tuple[float, List[Dict]]
        """
        number_of_threads = 15
        sem = asyncio.Semaphore(number_of_threads)
        async with sem:
            usd_course = await self._scalper.scalp_usd_course()
            companies_list = await self._scalper.scalp()
        await self._scalper.close_session()

        return usd_course, companies_list

    def _sort_elements(
            self, companies_info: List[Dict], key: str,
            coef: float = 1.0, reverse: bool = False
    ) -> List[Dict]:
        """
        Sort parsed data by some key and take only defined number of elements

        :param companies_info: List with collected information about all
                               companies
        :type companies_info: List[Dict]
        :param key: Dictionary key to sort values
        :type key: str
        :param coef: Optional parameter to modify selected data
        :type coef: float
        :param reverse: Flag to select order of sorting
        :type reverse: bool
        :return: List of dictionary with company code, name and selected
                 parameter
        :rtype: List
        """
        elements = [item for item in companies_info if item[key]]
        elements = sorted(elements, key=lambda x: x[key], reverse=reverse)

        data = []
        for i in range(self._number_of_elements):
            tmp_dict = elements[i]
            new_dict = {'name': tmp_dict['name'],
                        'code': tmp_dict['code'],
                        key: tmp_dict[key]*coef}
            data.append(new_dict)

        return data

    def _write_to_file(self, data: List[Dict], category: str):
        """
        Save data to corresponding file

        :param data: List with data
        :type data: List[Dict]
        :param category: Category of the data
        :type category: str
        """
        with open(self._files[category], 'w') as fi:
            json.dump(data, fi)

    def _save_data(
            self, companies_info: List[Dict], key: str,
            coef: float = 1.0, reverse: bool = False
    ) -> None:
        """
        Save specified data category to related file

        :param companies_info: List with collected information about all
                               companies
        :type companies_info: List[Dict]
        :param key: Data category
        :type key: str
        :param coef: Coefficient to convert data
        :type coef: float
        :param reverse: Flag to sort data in increasing or decreasing order
        type reverse: bool
        """
        data = self._sort_elements(companies_info, key, coef, reverse)
        self._write_to_file(data, key)

    def get_result(self):
        """Collect companies data and save it to the files"""
        loop = asyncio.get_event_loop()
        usd_course, companies_info = loop.run_until_complete(self._get_info())
        self._save_data(companies_info, 'price', usd_course, reverse=True)
        self._save_data(companies_info, 'pe')
        self._save_data(companies_info, 'growth', reverse=True)
        self._save_data(companies_info, 'profit', reverse=True)

if __name__ == '__main__':
    worker = Worker(number_of_elements=10)
    worker.get_result()


# -*- coding: utf-8 -*-
"""
Created on Tue Mar 16 20:18:52 2021

@author: guang
"""
import GPy
import numpy as np
import os
import time
from utilities import *
import matplotlib.pyplot as plt
import pandas as pd
import scipy
from scipy import stats, signal
from scipy.optimize import minimize_scalar
from scipy import optimize
from scipy.spatial.distance import pdist, cdist, squareform
from pathlib import Path

class Spectrum():
    def __init__(self):
        self.pathbase = Path(os.getcwd())

    def CheckSpecExist(self, disp = True):
        if not os.path.exists(self.pathbase/'..'/'spectrum'):
            os.makedirs(self.pathbase/'..'/'spectrum')
        spectrumList = os.listdir(self.pathbase/'..'/'spectrum')
        if len(spectrumList) == 0:
            return False
        else:
            if disp == True:
                print('Existed spectra:')
                print(spectrumList)
            return True

    def GenOneSpectrum(self, velocityShift,SNR = None, Vmag = 9., exposureTime = 900.):
        R, telescopeArea, effWavelSpectrograph, samplingResolution, throughputInterpolator, lambdaMin, lambdaMax = getSpectrograph("Marvel")

        # Choose the stellar parameters. Cf Data/ folder to see what choice there is.

        Teff = 5700          # Effective temperature  [K]
        logg = 4.5           # logarithm of the gravity
        vsini = 2            # A measure for the stellar rotation, determines the width of the spectral lines
        vmicro = 1           # Micro-turbulent velocity, affects the depth of your spectral lines
        FeH = 0.0            # Metallicity: how much metals in the stellar atmosphere. Determines the depth of the spectral lines
        Vmag = Vmag  ##11    # Magnitude of the star (i.e. its brightness)

        exposureTime = exposureTime## 25*60

        # Load and process the stellar spectrum

        ## generate spetrum if you want a S/N ratio throughout the spectrum that is wavelength dependent
        if SNR is None:
            # This is for 1 telescope only. Use 4*telescopeArea instead of telescopeArea if the spectrum for 4 telescopes is needed.
            spectrum = loadSpectrum2(Teff, logg, vmicro, FeH, vsini, R, effWavelSpectrograph, samplingResolution, velocityShift)
            spectrum = electronFlux(spectrum, telescopeArea, throughputInterpolator, lambdaMin, lambdaMax, exposureTime, Vmag,
                                    includePoissonNoise=True, normalizeSpectrum=True)
        else:
            R = 100000
            spectrum = loadSpectrum2(Teff, logg, vmicro, FeH, vsini, R, effWavelSpectrograph, samplingResolution, velocityShift)
            SNratio = SNR
            spectrum= normalizedSpectrumxWithFixedSN(spectrum, lambdaMin, lambdaMax, SNratio)
            print('Generating spectrum with constant SNR {}'.format(SNR))

        return spectrum

    def GetOrderIndex(self, spectrum):
        # Split spectrum to orders via trough of original signal
        miniInd = signal.argrelextrema(spectrum['NelectronsCont'].ravel(), np.less, order = 10)
        # remove the first split threshold point, since first order only contains few points
        miniInd = miniInd[0].tolist()[1:]

        return miniInd

    def GenSpectrum(self,velocity, SNR = None, Vmag = 9., exposureTime = 900., overwrite=False):
        def ApplyGen(velocity, SNR ,Vmag, exposureTime):
            assert len(velocity.shape) == 1, 'Please input one-dim list or array'
            for i in range(len(velocity)):
                spectrum = self.GenOneSpectrum(round(velocity[i],2), SNR, Vmag, exposureTime)
                filename = 'Spectrum' + str(int(i/10)) + str(int(i%10)) + '_' + str(round(velocity[i],2)) + '.csv'
                spectrum.to_csv(self.pathbase/'..'/'spectrum'/filename,index=False)

        flag = self.CheckSpecExist(disp = False)
        if flag == False:
            ApplyGen(velocity, SNR, Vmag, exposureTime)
        else:
            if overwrite == True:
                import shutil
                print('Overwritting existing spectra!!!')
                shutil.rmtree(self.pathbase/'..'/'spectrum')
                os.makedirs(self.pathbase/'..'/'spectrum')
                ApplyGen(velocity,SNR ,Vmag, exposureTime)
            else:
                print('Spectra exist, No need to generate.')

        velocity = [round(v,2) for v in velocity]
        RVTrue = pd.DataFrame({'RVTrue':velocity})
        RVTrue.to_csv(self.pathbase/'RVTrue.txt',index=False)

    def CutGenedSpectrum(self, lowerWavl, upperWavl):
        print('This will overwrite original spetrum files!!')
        spectrumList = os.listdir(self.pathbase/'..'/'spectrum')
        spectrumList = [item for item in spectrumList if item.startswith('Spectrum')]
        for spectrum in spectrumList:
            df = pd.read_csv(self.pathbase/'..'/'spectrum'/spectrum)
            subSpec = df.loc[(df["wavel"] > lowerWavl) & (df["wavel"] < upperWavl)]
            subSpec.to_csv(self.pathbase/'..'/'spectrum'/spectrum,index=False)

    def orderToSuborder(self,spectrum,nSplit):
        pointsPerOrder = int(np.ceil(len(spectrum)/nSplit))
        suborder = []
        for i in range(nSplit-1):
            suborder.append(spectrum.iloc[pointsPerOrder*i:pointsPerOrder*(1+i)])
        # for last sub-order, select obs to the end in case obs lost because of ceiling
        i = i+1
        suborder.append(spectrum.iloc[pointsPerOrder*i:])
        return suborder

    def spectrumToSuborder(self, spectrum, nPointSuborder,uniform=False):
        if uniform == False:
            miniInd = self.GetOrderIndex(spectrum)
        else:
            # manually create uniform spilt, each order contains 3 suborders
            intervel = nPointSuborder*3
            splitPoint = intervel
            miniInd = []
            while(splitPoint<=len(spectrum)):
                miniInd.append(splitPoint)
                splitPoint+=intervel
        spectrumByOrders = np.split(spectrum, miniInd, axis=0)
        nSplit = [round(len(i)/nPointSuborder) for i in spectrumByOrders]
        assert len(spectrumByOrders) == len(nSplit)
        suborders = []
        for i in range(len(nSplit)):
            if nSplit[i] == 0:
                suborders.append([spectrumByOrders[i]])
            else:
                suborders.append(self.orderToSuborder(spectrumByOrders[i],nSplit[i]))
        return suborders,nSplit

    def subSpectrum(self, spectrum, lowerWavl, upperWavl):
        subSpec = spectrum.loc[(spectrum["wavel"] > lowerWavl) & (spectrum["wavel"] < upperWavl)]
        return subSpec

    def plotSpectrum(self,spectrum,normalization = True):
        miniInd = signal.argrelextrema(spectrum['NelectronsCont'].ravel(), np.less, order = 10)
        fig, ax = plt.subplots(figsize=(18,9))
        X = spectrum['wavel']
        if normalization == True:
            Y = spectrum['NelectronsLine']
            Ylabel = "Flux [e-/exposure]"
        else:
            Y = spectrum['NelectronsCont']
            Ylabel = "Flux [original]"
        ax.plot(X, Y, c="steelblue")
        ax.set_xlabel("Wavelength [nm]")
        ax.set_ylabel(Ylabel)
        ax.grid(True, color='gainsboro', linestyle='-', linewidth=0.5)
        if normalization == False and len(miniInd[0])!=0:
            Xminimum = spectrum["wavel"].iloc[miniInd]
            Yminimum = spectrum["NelectronsCont"].iloc[miniInd]
            ax.plot(Xminimum, Yminimum, "or")
        plt.show()

class GPR():
    def __init__(self, h = 0.5, rho = 0.02):
        self.c = 299792458
        self.h = h
        self.rho = rho

    def regression(self,spectrum, holdPara = True):
        noPoints = len(spectrum)
        kernelMatern = GPy.kern.Matern52(input_dim=1,variance = self.h**2, lengthscale = self.rho)
        # Define data for regression
        X = spectrum["wavel"].ravel().reshape(noPoints,-1)
        Y = spectrum["NelectronsLine"].ravel().reshape(noPoints,-1)

        # poisson_likelihood = GPy.likelihoods.Poisson()
        # laplace_inf = GPy.inference.latent_function_inference.Laplace()
        # m = GPy.core.GP(X=X, Y=Y, likelihood=poisson_likelihood, inference_method=laplace_inf, kernel=kernelMatern)
        m = GPy.models.GPRegression(X,Y,kernelMatern)
        # fix length scale and variance, leave noise variance unconstrianed
        m.Mat52.variance = self.h**2
        m.Mat52.lengthscale = self.rho
        if holdPara == True:
            m.Mat52.variance.constrain_fixed()
            m.Mat52.lengthscale.constrain_fixed()
        m.optimize()
        return m

    def plotGP(self,m,GPwavelInterval=0.002):
        X = m.X
        Y = m.Y
        Xnew = np.arange(X[0],X[-1], step=GPwavelInterval)
        Xnew = Xnew.reshape(len(Xnew),-1)
        mpred = m.predict(Xnew)
        mMean = mpred[0]
        mCI = m.predict_quantiles(Xnew,quantiles=(2.5, 97.5))

        fig0, ax0 = plt.subplots(figsize=(18,9))
        ax0.plot(X, Y, "bo",label='Observation')
        ax0.set_xlabel("Wavelength [nm]")
        ax0.set_ylabel("Normalized flux")
        ax0.grid(True, color='gainsboro', linestyle='-', linewidth=0.5)
        # add posterior predictive mean curve
        ax0.plot(Xnew,mMean ,c="red",label='Posterior mean')
        ax0.fill_between(Xnew.ravel(), mCI[0].ravel(), mCI[1].ravel() , alpha=0.3,label='1.96σ error bar')
        ax0.legend()
        plt.show()

    def PredOneGP(self, suborders, wavelInterval = 0.002):
        count = 0
        timesum = 0
        dataFrame = pd.DataFrame({'wavel':[],'mean':[],'var':[],'separation':[]})
        for i in range(len(suborders)):
            for j in range(len(suborders[i])):
                # timeStart = time.perf_counter()
                count += 1
                m = self.regression(suborders[i][j])
                X = m.X
                Xnew = np.arange(X[0],X[-1], step = wavelInterval)
                wavel = Xnew.reshape(len(Xnew),-1)
                mpred = m.predict(wavel)
                mMean = mpred[0].ravel()
                mVar = mpred[1].ravel()
                separation = np.zeros(len(mMean),dtype=bool)
                # set suborder's starting index as 1
                separation[0] = 1
                tmp = pd.DataFrame({'wavel':wavel.ravel(),'mean':mMean,'var':mVar,'separation':separation})
                dataFrame = pd.concat([dataFrame, tmp], ignore_index=True)

                # timeEnd = time.perf_counter()-timeStart
                # timesum += timeEnd
        #         print('{0}:{1}'.format(count,timeEnd))
        # print('total time : {}'.format(timesum))
        return dataFrame

    def kernel_Mat52(self, x1, x2):
        tau = np.sqrt(5*(np.subtract.outer(x1,x2)**2))
        kout = self.h**2*(1 + tau/self.rho + tau**2/(3*self.rho**2))*np.exp(-tau/self.rho)
        return kout

    # Gradiant calculation: dK/dv
    # input X is the wavelength without considering v
    def kernel_Mat52_grad(self,X,v):

        def tau_grad2(v,lam1,lam2):
            c = self.c
            term1 = -2*c/(c+v)**2
            term2 = 0.5*((c-v)/(c+v))**(-0.5)
            return np.sqrt(5*np.subtract.outer(lam1 , lam2)**2)*term2*term1

        def tau_grad3(v,lam1,lam2):
            c = self.c
            term1 = np.sqrt((1 - v/c)/(1 + v/c))
            term2 = np.sign(np.subtract.outer(lam1*term1,lam2))
            term3 = -2*c/(c+v)**2
            term4 = 0.5*((c-v)/(c+v))**(-0.5)
            out1 = np.sqrt(5)*lam1*term3*term4
            out2 = np.tile(out1, (len(out1),1))
            return out2*term2

        length = len(X)
        matrix1 = tau_grad2(v,X,X)
        matrix2 = tau_grad3(v,X,X)
        matrix3 = -matrix2
        matrix4 = np.zeros([length,length])
        matrixUpper = np.concatenate((matrix1, matrix2),axis=1)
        matrixLower = np.concatenate((matrix3, matrix4),axis=1)
        return np.concatenate((matrixUpper, matrixLower))

    # Save L matrix from cholesky decomposition, using var estimation from first spectrum
    def SaveLmatrix(self,wavel1, Y12, var1, vs):
        # startTime = time.clock()
        length = len(wavel1)
        Ls = []
        for v in vs:
            wavel2 = wavel1/np.sqrt((1 + v/self.c)/(1 - v/self.c))
            X12 = np.concatenate((wavel2,wavel1))

            # varMatrix = np.diag(np.concatenate((np.ones(length)*var1,np.ones(length)*var2)))
            varMatrix = np.diag(np.concatenate((var1,var1)))
            K12 = self.kernel_Mat52(X12,X12)
            K12 += varMatrix
            # scipy package solution
            ## NOTE: smalle value multiplied to I changed from 1e-10 to 1e-8, due to matrix not positive definite
            ## problem encountered in 22nd April 2021.
            Y12  = Y12[:, np.newaxis]
            L = scipy.linalg.cholesky(K12 + (1e-6*np.identity(2*length)),lower=True)
            Ls.append(L)
        return np.array(Ls).astype(np.float32) # to minimize the storage requirements

    # Log likelihood with Cholosky decompostion
    def logLik_Chol(self,wavel1, wavel2, Y12, var1, var2, v, evalGradiant = False):
        # startTime = time.clock()
        length = len(wavel1)
        wavel1 = wavel2/np.sqrt((1 + v/self.c)/(1 - v/self.c))
        X12 = np.concatenate((wavel1,wavel2))

        # varMatrix = np.diag(np.concatenate((np.ones(length)*var1,np.ones(length)*var2)))
        varMatrix = np.diag(np.concatenate((var1,var2)))
        K12 = self.kernel_Mat52(X12,X12)
        K12 += varMatrix
        # scipy package solution
        ## NOTE: smalle value multiplied to I changed from 1e-10 to 1e-8, due to matrix not positive definite
        ## problem encountered in 22nd April 2021.
        Y12  = Y12[:, np.newaxis]
        L = scipy.linalg.cholesky(K12 + (1e-6*np.identity(2*length)),lower=True)
        alpha = scipy.linalg.cho_solve((L,True),Y12)
        loglik = -0.5 * np.einsum("ik,ik->k", Y12, alpha)
        loglik -= np.log(np.diag(L)).sum()
        loglik -= length * np.log(2 * np.pi)
        # # numpy package solution
        # L = np.linalg.cholesky(K12 + (1e-6*np.identity(2*length)))
        # alpha = np.linalg.solve(L.T,np.linalg.solve(L,Y12))
        # loglik = -0.5*(Y12.T @ alpha) - np.log(L.diagonal()).sum() - length*np.log(2*np.pi)

        negLogLik = - loglik
        # print((time.clock() - startTime))

        # Evaluate gradient
        if evalGradiant == True:
            K_gradient = self.kernel_Mat52_grad(wavel2,v)
            tmp = np.einsum("ik,jk->ijk", alpha, alpha)  # k: output-dimension
            tmp -= scipy.linalg.cho_solve((L, True), np.eye(2*length))[:, :, np.newaxis]
            # tmp -= np.linalg.solve(L.T,np.linalg.solve(L,np.eye(2*length)))[:, :, np.newaxis]
            # Compute "0.5 * trace(tmp.dot(K_gradient))" without
            # constructing the full matrix tmp.dot(K_gradient) since only
            # its diagonal is required
            log_likelihood_gradient = 0.5 * np.einsum("ijl,jik->kl", tmp, K_gradient[:,:,np.newaxis])
            return negLogLik.item(), log_likelihood_gradient.sum(-1)
        else:
            return negLogLik.item()

    def optimizeRV(self, GPFitted1, GPFitted2, loglik_nearMax = False, deltaV = 1):
        len1 = len(GPFitted1)
        len2 = len(GPFitted2)
        if len1 != len2:
            assert abs(len1-len2)<5
            print("WARNING: Unequal suborder length, removing the difference")
            if len1 > len2:
                GPFitted1 = GPFitted1.iloc[:len2]
            else:
                GPFitted2 = GPFitted2.iloc[:len1]
        Y12 = np.concatenate((GPFitted1['mean'].to_numpy(),GPFitted2['mean'].to_numpy()))
        # startTime = time.clock()
        objFun = lambda v:self.logLik_Chol(GPFitted1['wavel'].to_numpy(), GPFitted2['wavel'].to_numpy(),
                                           Y12, GPFitted1['var'].to_numpy(), GPFitted2['var'].to_numpy(), v)
        # step_count = opt.minimize(objFun, [v]).numpy()
        # result = v.numpy()
        result = minimize_scalar(objFun,method='brent',tol=1e-3)
        # result = scipy.optimize.minimize(objFun, x0=-20, method="L-BFGS-B", options={'ftol': 1e-15, 'gtol': 1e-15, 'eps': 1e-15})
        # result = scipy.optimize.minimize(objFun, 500, method="Powell", options={'disp': True,'ftol':1e-5,'xtol': 1e-5})
        # result = optimize.dual_annealing(objFun,bounds = list(zip([-10000], [10000])))

        ### Following eq.11 in Zechmeister1,2017: error estimation under porabolic approximation
        if loglik_nearMax == True:
            maxmum = result.x
            neglog_max = result.fun
            neglog_maxN = objFun(maxmum - deltaV)
            neglog_maxP = objFun(maxmum + deltaV)
            uncertainty = 2*deltaV**2/(neglog_maxN - 2*neglog_max + neglog_maxP)
            return  maxmum,uncertainty
        else:
            return result.x

    def optimizeRVQA(self, GPFitted1, GPFitted2, loglik_nearMax = False):
        len1 = len(GPFitted1)
        len2 = len(GPFitted2)
        if len1 != len2:
            assert abs(len1-len2)<5
            print("WARNING: Unequal suborder length, removing the difference")
            if len1 > len2:
                GPFitted1 = GPFitted1.iloc[:len2]
            else:
                GPFitted2 = GPFitted2.iloc[:len1]
        Y12 = np.concatenate((GPFitted1['mean'].to_numpy(),GPFitted2['mean'].to_numpy()))
        objFun = lambda v:self.logLik_Chol(GPFitted1['wavel'].to_numpy(), GPFitted2['wavel'].to_numpy(),
                                           Y12, GPFitted1['var'].to_numpy(), GPFitted2['var'].to_numpy(), v)
        # Polyfit with order 2 of 3 points
        Xt = np.array([-50,0,50])
        Yt1 = objFun(Xt[0]);Yt2 = objFun(Xt[1]);Yt3 = objFun(Xt[2]);
        Yt = np.array([Yt1,Yt2,Yt3])
        coefs = np.polyfit(Xt, Yt, 2)
        rv = -coefs[1]/(coefs[0]*2)
        var = 1/coefs[0]
        if loglik_nearMax==True:
            return rv,var
        else:
            return rv

    def optimizeRVQA_Lsaved(self, GPFitted1, GPFitted2, Ls, loglik_nearMax = False):
        length = len(GPFitted1)
        Y12 = np.concatenate((GPFitted1['mean'].to_numpy(),GPFitted2['mean'].to_numpy()))
        Y12  = Y12[:, np.newaxis]
        Yt = np.empty(3,dtype=np.float64)
        for i, L in enumerate(Ls):
            alpha = scipy.linalg.cho_solve((L,True),Y12)
            loglik = -0.5 * np.einsum("ik,ik->k", Y12, alpha)
            loglik -= np.log(np.diag(L)).sum()
            loglik -= length * np.log(2 * np.pi)
            Yt[i] = - loglik
        Xt = np.array([-50,0,50])
        coefs = np.polyfit(Xt, Yt, 2)
        rv = -coefs[1]/(coefs[0]*2)
        var = 1/coefs[0]
        if loglik_nearMax==True:
            return rv,var
        else:
            return rv


import yaml

class GetConf():

    def __init__(self, file):
        self.file = file

    def get(self):
        with open(self.file, 'r') as self.stream:
            try:
                self.conf_yaml = yaml.full_load(self.stream)
            except yaml.YAMLError as err:
                print('ERR: [GetConf:get]', err)
                return False
            else:
                return self.conf_yaml


def sortInDictionary(L):
    """
    a function that gets a list and return a dictionary ordered by types that counting all types in the list
    :param L: our list
    :return:the dictionary we got
    """
    dic = dict.fromkeys({'list', 'int', 'float', 'str', 'tuple'})
    count = 0
    for i in range(len(L)):
        string = str(type(L[i]))
        string1 = string[8:len(string) - 2]
        if dic[string1] is None:
            count = 0
        else:
            count = dic[string1]
        dic[string1] = count + 1
    return dic

# תוכנית ראשית
def main():
    L = [1, 2, 'a', (11, 2, 'b'), [22, 'c'], (33,), ['d'], 'e']
    x = sortInDictionary(L)
    for keys, values in x.items():
        if values is None:
            print(keys + ":", 0)
        else:
            print(keys + ":", values)

if __name__ == '__main__':
    main()


# -*- coding: utf-8 -*-

"""

@author: Everaldo Gomes
@email: everaldo.gomes@pucpr.br

Início da Implementação: 20/09/2015 - 13h22

"""

import unittest
from fila import Fila
#from teste_lista import TestLista
from random import randint
from sys import maxsize, getrecursionlimit, setrecursionlimit
from collections import deque

setrecursionlimit(maxsize)

class TesteFila(unittest.TestCase):

    def setUp(self):
        """Esse método é invocado antes de cada Teste. Prepara o ambiente"""
        self.MAX_VALUE = 10000
        self.fila_vazia = Fila()
        self.x = randint(0, maxsize)
        self.fila_um = Fila()
        self.fila_um.enqueue(self.x)
        self.max = randint(100, 500)
        self.fila = Fila()
        self.fila.enqueue(self.x)
        self.fila_limite = Fila(self.max)
        self.python_deque = deque()
        for i in range(0, self.max):
            element = randint(0, self.MAX_VALUE)
            self.python_deque.append(element)
            self.fila_limite.enqueue(element)

    def test_construtor(self):
        """O construtor deve receber um valor max ou None"""
        self.assertIsInstance(self.fila_um, Fila)
        self.assertIsInstance(self.fila_vazia, Fila)
        self.assertIsInstance(self.fila, Fila)
        self.assertIsInstance(self.fila_limite, Fila)

    def test_bool_false(self):
        """Uma Fila Vazia retorna False"""
        self.assertFalse(bool(self.fila_vazia))
        self.assertFalse(self.fila_vazia)
        self.assertFalse(self.fila_vazia.__bool__())

    def test_bool_true(self):
        """Uma Fila com 1 elemento  retorna True"""
        self.assertTrue(bool(self.fila_um))
        self.assertTrue(self.fila_um)
        self.assertTrue(self.fila_um.__bool__())

    def test_empty_queue(self):
        """Uma Fila Vazia retorna True para is_empty"""
        self.assertTrue(self.fila_vazia.is_empty())

    def test_not_empty_queue(self):
        """Uma Fila Não Vazia retorna False para is_empty"""
        self.assertFalse(self.fila_um.is_empty())

    def test_len_empty_queue(self):
        """Uma Fila Vazia tem tamanho 0"""
        self.assertEqual(len(self.fila_vazia), 0)

    def test_len_one_element_queue(self):
        """Uma Fila com 1 elemento tem tamanho 1"""
        self.assertEqual(len(self.fila_um), 1)

    #Este Teste só funciona quando enqueue tiver sido implementado
    def test_len_arbitrary_size_queue(self):
        """Uma Fila com n elementos tem tamanho n"""
        self.assertEqual(len(self.fila_limite), self.max)

    def test_first_empty_queue(self):
        """Uma Fila vazia retorna uma Exceção quando first é invocado"""
        with self.assertRaises(Exception):
            self.fila_vazia.first()

    def test_first_one_element_queue(self):
        """Uma Fila com 1 elemento retorna o elemento com first"""
        self.assertEqual(self.fila_um.first(), self.x)

    def test_first_n_elements_queue(self):
        """Uma Fila com n elementos retorna o primeiro a ter sido inserido com first"""
        self.assertEqual(self.fila_limite.first(), self.python_deque.popleft())

    def test_first_doesnt_change_queue_len(self):
        """O método first é idempotente e não altera o tamanho da fila"""
        size = len(self.fila_limite)
        self.assertEqual(len(self.fila_limite), size)
        self.fila_limite.first()
        self.fila_limite.first()
        self.fila_limite.first()
        self.fila_limite.first()
        self.fila_limite.first()
        self.assertEqual(len(self.fila_limite), size)

    def test_last_empty_queue(self):
        """Uma Fila vazia retorna uma Exceção quando last é invocado"""
        with self.assertRaises(Exception):
            self.fila_vazia.last()

    def test_last_one_element_queue(self):
        """Uma Fila com 1 elemento retorna o elemento com last"""
        self.assertEqual(self.fila_um.last(), self.x)

    def test_last_n_elements_queue(self):
        """Uma Fila com n elementos retorna o último a ter sido inserido com last"""
        self.assertEqual(self.fila_limite.last(), self.python_deque.pop())

    def test_last_doesnt_change_queue_len(self):
        """O método last é idempotente e não altera o tamanho da fila"""
        size = len(self.fila_limite)
        self.assertEqual(len(self.fila_limite), size)
        self.fila_limite.last()
        self.fila_limite.last()
        self.fila_limite.last()
        self.fila_limite.last()
        self.fila_limite.last()
        self.assertEqual(len(self.fila_limite), size)

    def test__eq__empty_queues(self):
        """Duas filas vazias são iguais"""
        self.assertEqual(Fila(), Fila())
        #o argumento é a capacidade da fila
        self.assertEqual(Fila(5), Fila(10))

    def test__eq__n_elements_queues(self):
        """Duas filas com os mesmos elementos são iguais"""
        x = randint(100, 500)
        fila1 = Fila()
        fila2 = Fila()
        for i in range(0, x):
            element = randint(0, self.MAX_VALUE)
            fila1.enqueue(element)
            fila2.enqueue(element)
            self.assertEqual(fila1, fila2)
        self.assertEqual(fila1, fila2)

    def test_str_empty_queue(self):
        """Uma fila vazia deve ser representada pela string []"""
        self.assertEqual(str(self.fila_vazia), "[]")

    def test_str_one_element_queue(self):
        """Uma fila com somente um elemento x deve ser representada por [x]"""
        self.assertEqual(str(self.fila_um), "[" + str(self.x) + "]")

    def test_str_n_elements_queue(self):
        """Uma fila com n elementos imprime todos os elementos"""
        """Nossa implementação insere no começo e retira no final,
        mas também é possível inserir no final e retirar no começo"""
        fila = Fila()
        fila.enqueue(1)
        fila.enqueue(2)
        fila.enqueue(3)
        fila.enqueue(4)
        self.assertEqual(str(fila), "[4, 3, 2, 1]")

    def test_clear_remove_all_elements(self):
        """clear remove todos os elementos da fila"""
        self.assertEqual(len(self.fila_vazia), 0)
        self.assertNotEqual(len(self.fila_um), 0)
        self.assertNotEqual(len(self.fila_limite), 0)

        self.fila_vazia.clear()
        self.fila_um.clear()
        self.fila_limite.clear()

        self.assertEqual(len(self.fila_vazia), 0)
        self.assertEqual(len(self.fila_um), 0)
        self.assertEqual(len(self.fila_limite), 0)

    def test_enqueue(self):
        """enqueue aumenta o tamanho da fila em 1"""
        element = randint(0, self.MAX_VALUE)
        self.assertEqual(len(self.fila_vazia), 0)
        self.assertEqual(len(self.fila_um), 1)
        self.fila_vazia.enqueue(element)
        self.fila_um.enqueue(element)
        self.assertEqual(len(self.fila_vazia), 1)
        self.assertEqual(len(self.fila_um), 2)

    def test_enqueue_full_queue(self):
        """enqueue numa lista cheia gera um erro"""
        with self.assertRaises(Exception):
            element = randint(0, self.MAX_VALUE)
            self.fila_limite.enqueue(element)

    def test_dequeue(self):
        """dequeue diminui o tamanho da fila em 1"""
        self.assertEqual(len(self.fila_um), 1)
        self.fila_um.dequeue()
        self.assertEqual(len(self.fila_um), 0)
        self.assertEqual(self.fila_um, Fila())

        size = len(self.fila_limite)
        self.fila_limite.dequeue()
        self.assertEqual(len(self.fila_limite), size - 1)

    def test_dequeue_empty_queue(self):
        """dequeue numa lista vazia gera um erro"""
        with self.assertRaises(Exception):
            self.fila_vazia.dequeue()

    def test_enqueue_dequeue_1(self):
        """teste de integração pipeline de filas"""
        fila1 = Fila()
        fila2 = Fila()
        fila3 = Fila()
        fila4 = Fila()
        for i in range(0, self.max):
            fila1.enqueue(i)
            fila2.enqueue(fila1.dequeue())
            fila3.enqueue(fila2.dequeue())
            fila4.enqueue(fila3.dequeue())
            self.assertEqual(i, fila4.dequeue())

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