import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject, Gio
from gui_functions import Function, Cal_Date
import shutil
from datetime import date, datetime, timedelta
from SQL import Queries, Store
#from GUI_Admin import Main

class Widget:
    def __init__(self, store_func, parent, queries, **setup):
        self.builder = Gtk.Builder()
        self.builder.add_from_file(setup["glade_file"])
        self.builder.connect_signals(self)
        self.widget = self.builder.get_object(setup["widget_id"])
        self.scroll = self.builder.get_object(setup["widget_scroll_id"])
        if setup["widget_calander_id"] != None:
            self.calander = self.builder.get_object(setup["widget_calander_id"])
        else:
            self.calander = None
        self.parent = parent
        self.queries = queries

        self.current_items = None
        self.current_filter = None
        self.file = None
        if setup["file_chooser"] != None:
            self.file_chooser = self.builder.get_object(setup["file_chooser"])
        else:
            self.file_chooser = None
        self.query = setup["timer_query"]

        self.store = setup["store_setup"] #Gtk.ListStore(str)
        self.columns = setup["column_numbers"]
        self.column_headings = setup["column_headings"]
        self.entries = setup["entries"]

        self.filter = self.store.filter_new()
        self.filter.set_visible_func(self.filter_func)
        self.filter_view = Gtk.TreeModel.sort_new_with_model(self.filter)
        self.treeview = Gtk.TreeView.new_with_model(self.filter_view)
        self.tree_selection = self.treeview.get_selection()
        self.tree_selection.connect("changed", self.onSelectionChanged)
        self.scroll.add(self.treeview)

        for i, column_title in enumerate(self.column_headings):
            renderer = Gtk.CellRendererText()
            self.column = Gtk.TreeViewColumn(column_title, renderer, text=i)
            self.column.set_sort_column_id(i)
            self.treeview.append_column(self.column)

        self.widget.show_all()
        self.store_func = store_func
        self.timer()

    def timer(self):
        GObject.timeout_add(1000, self.timer_func)

    def timer_func(self):
        s = self.store
        new_items = self.store_func.get(self.query)
        comparison = self.store_func.compare(self.current_items, new_items)
        if comparison == False:
            x = self.store_func.build(s, new_items)
        self.current_items = new_items

        return True

    def filter_func(self, model, iter, data):
        if self.current_filter is None or self.current_filter == "":
            return True
        elif self.current_filter in model[iter][self.current_filter_column]:
            return model[iter][self.current_filter_column]

    def onSelectionChanged(self, tree_selection):
        (model, pathlist) = tree_selection.get_selected_rows()
        for path in pathlist :
            tree_iter = model.get_iter(path)
            c = self.columns
            self.row = []
            for i in c:
                value = model.get_value(tree_iter,c[i])
                self.row.append(str(value))
            print(self.row)
            Function.set_entries(self, self.entries, self.row)

            if self.calander != None:
                for j in range(len(self.column_headings)):
                    if self.column_headings[j].endswith("Expiry") == True:
                        date_to_set = self.row[j]
                        Cal_Date.set_date(self,  calander_object=self.calander, date=date_to_set)
                    elif self.column_headings[j].endswith("Date") == True:
                        date_to_set = self.row[j]
                        Cal_Date.set_date(self,  calander_object=self.calander, date=date_to_set)

            if self.file_chooser != None:
                for k in range(len(self.column_headings)):
                    if self.column_headings[k].endswith("Certificate") == True:
                        f = Gio.File.new_for_path(self.row[k])
                        self.file_chooser.set_file(f)

                    elif self.column_headings[k].endswith("File") == True:
                        f = Gio.File.new_for_path(self.row[k])
                        self.file_chooser.set_file(f)

    def confirm_init(self):
        self.builder.add_from_file("Glade/confirm.glade")
        self.builder.connect_signals(self)
        self.confirm = self.builder.get_object("confirm")
        self.log = False
        self.msg_label = self.builder.get_object("title")
        self.confirm.set_transient_for(self.parent)
        self.f_labels = ["f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11"]
        self.v_labels = ["v11", "v10", "v9", "v8", "v7", "v6", "v5", "v4", "v3", "v2", "v1"]

    def insert(self, query, values, log_query, log_values):
        self.confirm_init()
        self.q = query
        self.v = values
        self.lq = log_query
        self.lv = log_values
        table = "equipment"
        self.msg = ("You are about to add the following {} to the database".format(table))
        self.heading_labels = self.column_headings
        self.label_values = list(values)[1:]
        self.show_message()

    def log_insert(self, log_query, log_values):
        self.confirm_init()
        self.lq = log_query
        self.lv = log_values
        table = "logbook"
        self.msg = ("You are about to add the following {} to the database".format(table))
        self.heading_labels = self.column_headings
        self.label_values = list(log_values)[1:]
        self.log = True
        self.show_message()

    def update(self, query, values, log_query, log_values):
        self.confirm_init()
        columns = list(self.column_headings)[1:]
        current_values = self.row[1:]
        new_values = list(values)[1:-1]
        self.q = query
        self.v = values
        self.lq = log_query
        self.lv = log_values
        self.heading_labels = []
        self.label_values = []
        self.msg = ("You are about to update the following fields with: ")
        for i in range(len(new_values)):
            if new_values[i] != current_values[i]:
                self.heading_labels.append(columns[i])
                self.label_values.append(new_values[i])

        self.show_message()

    def show_message(self):
        self.msg_label.set_label(self.msg)
        for i in range(len(self.heading_labels)):
            field_label = self.builder.get_object(self.f_labels[i])
            value_label = self.builder.get_object(self.v_labels[i])
            field_label.set_label(self.heading_labels[i])
            value_label.set_label(str(self.label_values[i]))
        self.confirm.show()

    def on_confirm_button_clicked(self, confirm_button):
        if self.log == False:
            self.queries.query(self.q, self.v)
            self.queries.log_query(self.lq, self.lv)
            self.confirm.destroy()
        elif self.log == True:
            self.queries.log_query(self.lq, self.lv)
            self.confirm.destroy()

    def on_confirm_cancel_button_clicked(self, confirm_cancel_button):
        self.confirm.destroy()

    def on_confirm_delete_event(self, *args):
        self.confirm.destroy()

#Do Remove/Update and Completions
class EquipAdd(Widget):
    def __init__(self, queries, store_func, parent):
        self.entries = {"equipment_add_entry_eal" : 0, "equipment_add_entry_type" : 1, "equipment_add_entry_manufacturer" : 2, "equipment_add_entry_model" : 3, "equipment_add_entry_pressure" : 4, "equipment_add_entry_serial" : 5}
        self.queries = queries

        setup = {"glade_file" : "Glade/equipment_add.glade",
                 "widget_id" :  "equipment_add_page",
                 "widget_scroll_id" : "equipment_add_scroll_window",
                 "widget_calander_id" : None,
                 "timer_query" : queries.equipment["select"],
                 "store_setup" : Gtk.ListStore(str, str, str, str, int, str),
                 "column_numbers" : (0, 1, 2, 3, 4, 5),
                 "column_headings" : ["EAL Number", "Equipment Type", "Manufacturer", "Model", "Pressure", "Serial Number"],
                 "entries" : self.entries,
                 "file_chooser" : None}

        Widget.__init__(self, store_func, parent, queries, **setup)

        Function.entry_completion(self, self.store, "equipment_add_entry_eal", 0)
        Function.entry_completion(self, self.store, "equipment_add_entry_type", 1)
        Function.entry_completion(self, self.store, "equipment_add_entry_manufacturer", 2)
        Function.entry_completion(self, self.store, "equipment_add_entry_model", 3)
        #Function.entry_completion(self, self.store, "equipment_add_entry_pressure", 4)
        #Function.entry_completion(self, self.store, "equipment_add_entry_serial", 5)

    def on_equipment_add_button_add_clicked(self, equipment_add_button_add):
        entries = ["equipment_add_entry_eal", "equipment_add_entry_type", "equipment_add_entry_manufacturer", "equipment_add_entry_model", "equipment_add_entry_pressure", "equipment_add_entry_serial"]
        text = Function.get_entries(self, entries)
        now = datetime.now()
        for item in self.current_items:
            row = list(item)
            if row[0] == text[0]:
                match = True
                break
            else:
                match = False

        if match == True:
            query = self.queries.equipment["update"]
            utext = text[1:]
            utext.append(text[0])
            values = (now, utext[0], utext[1], utext[2], utext[3], utext[4], utext[5])
            location = 'Westcott'
            procedure = 'N/A'
            message = text[0] + ' updated field'
            log_query = self.queries.logbook["insert"]
            log_values = (now, text[0], now, location, procedure, message)
            self.update(query, values, log_query, log_values)
        elif match == False:
            values = (now, text[0], text[1], text[2], text[3], text[4], text[5])
            location = 'Westcott'
            procedure = 'N/A'
            message = text[0] + ' added to equipment store'
            log_query = self.queries.logbook["insert"]
            log_values = (now, text[0], now, location, procedure, message)
            query = self.queries.equipment["insert"]
            self.insert(query, values, log_query, log_values)

        Function.clear_entries(self, entries)

    def on_equipment_add_button_clear_clicked(self, equipment_add_button_clear):
        self.tree_selection.unselect_all()
        entries = self.entries
        Function.clear_entries(self, entries)
        self.current_filter = None

    def on_equipment_add_entry_eal_changed(self, entry):
        self.tree_selection.unselect_all()
        search = entry.get_text()
        self.current_filter = search.upper()
        self.current_filter_column = 0
        self.filter.refilter()

    def on_equipment_add_entry_type_changed(self, entry):
        self.tree_selection.unselect_all()
        search = entry.get_text()
        self.current_filter = search
        self.current_filter_column = 1
        self.filter.refilter()

    def on_equipment_add_entry_manufacturer_changed(self, entry):
        self.tree_selection.unselect_all()
        search = entry.get_text()

    def on_equipment_add_entry_model_changed(self, entry):
        self.tree_selection.unselect_all()
        search = entry.get_text()

    def on_equipment_add_page_delete_event(self, *args):
        Gtk.main_quit(*args)

class EquipCal(Widget):
    def __init__(self, queries, store_func, parent, com_store):

        self.queries = queries
        self.type = "External"
        self.entries = {"equipment_calibration_entry_eal" : 0, "equipment_calibration_entry_company" : 1}

        setup = {"glade_file" : "Glade/equipment_calibration.glade",
                 "widget_id" :  "equipment_calibration_page",
                 "widget_scroll_id" : "equipment_calibration_scroll_window",
                 "widget_calander_id" : "equipment_calibration_calendar_date",
                 "timer_query" : queries.calibration["select"],
                 "store_setup" : Gtk.ListStore(str, str, str, str, str, str, str),
                 "column_numbers" : (0,1,2,3,4,5,6),
                 "column_headings" : ["EAL Number", "Calibration Company", "Calibration Type", "Calibration Date", "Calibration Recall", "Calibration Expiry", "Calibration Certificate"],
                 "entries" : self.entries,
                 "file_chooser" : "equipment_calibration_file_certificate"}

        Widget.__init__(self, store_func, parent, queries, **setup)

        Function.entry_completion(self, com_store, "equipment_calibration_entry_eal", 0)

    def on_equipment_calibration_radio_external_toggled(self, equipment_calibration_radio_external):
        self.type = "External"

    def on_equipment_calibration_radio_internal_toggled(self, equipment_calibration_radio_internal):
        self.type = "Internal"

    def on_equipment_calibration_button_enter_clicked(self, equipment_calibration_button_enter):
        entries = ["equipment_calibration_entry_eal", "equipment_calibration_entry_company"]
        text = Function.get_entries(self, entries)
        print(text)
        calibration_type = self.type
        if (calibration_type == "External"):
            length = 12
        elif (calibration_type == "Internal"):
            length = 6
        else:
            length = 12

        calibration_date = Cal_Date.date(self, "equipment_calibration_calendar_date")
        calibration_expiry = Cal_Date.expiry(self, calibration_date, length)
        calibration_recall = Cal_Date.recall(self, calibration_expiry)
        calibration_certificate = ''

        if self.file != None:
            file_name = 'Calibration_Certificate_' + str(calibration_date)
            file_settings = {"dep":"Equipment", "sub":"Calibration", "eal_ref":text[0]}
            calibration_certificate = Function.file_path2(self, self.file, file_name, file_settings)
            shutil.copy(self.file, calibration_certificate)
            self.file_chooser.unselect_all()
        else:
            calibration_certificate = "Not Uploaded"

        now = datetime.now()
        location = Function.get_entry(self, "equipment_calibration_entry_location")

        for item in self.current_items:
            row = list(item)
            if row[0] == text[0]:
                match = True
                break
            else:
                match = False

        if match == True:
            query = self.queries.calibration["update"]
            utext = text[1:]
            utext.append(text[0])
            values = (now, utext[0], calibration_type, calibration_date, calibration_recall, calibration_expiry, calibration_certificate, utext[1])
            procedure = 'N/A'
            message = text[0] + ' updated field'
            log_query = self.queries.logbook["insert"]
            log_values = (now, text[0], now, location, procedure, message)
            self.update(query, values, log_query, log_values)

        elif match == False:
            message = "Calibration certificate added."
            procedure = "N/A"
            values = (now, text[0], text[1], calibration_type, calibration_date, calibration_recall, calibration_expiry, calibration_certificate)
            log_values = (now, text[0], now, location, procedure, message)
            query = self.queries.calibration["insert"]
            log_query = self.queries.logbook["insert"]
            self.insert(query, values, log_query, log_values)

        Function.clear_entries(self, entries)

    def on_equipment_calibration_button_clear_clicked(self, equipment_calibration_button_clear):
        self.tree_selection.unselect_all()
        self.file_chooser.unselect_all()
        entries = self.entries
        Function.clear_entries(self, entries)
        self.current_filter = None
        print ("Clear")

    def on_equipment_calibration_file_certificate_file_set(self, equipment_calibration_file_certificate):
        self.file_chooser = equipment_calibration_file_certificate
        self.file = self.file_chooser.get_filename()

    def on_equipment_calibration_entry_eal_changed(self, equipment_calibration_entry_eal):
        search = equipment_calibration_entry_eal.get_text()
        self.current_filter = search.upper()
        self.current_filter_column = 0
        self.filter.refilter()

    def on_equipment_calibration_page_delete_event(self, *args):
        Gtk.main_quit(*args)

class EquipProof(Widget):
    def __init__(self, queries, store_func, parent, com_store, proc_store):
        self.queries = queries
        self.entries = {"equipment_proof_entry_eal" : 0, "equipment_proof_entry_bar" : 1, "equipment_proof_entry_duration" : 2, "equipment_proof_entry_pt" : 3, "equipment_proof_entry_procedure" : 4, "equipment_proof_entry_location" : 8}
        self.result = "Pass"

        setup = {"glade_file" : "Glade/equipment_proof.glade",
                 "widget_id" :  "equipment_proof_page",
                 "widget_scroll_id" : "equipment_proof_scroll_window",
                 "widget_calander_id" : "equipment_proof_calendar_date",
                 "timer_query" : queries.proof["select"],
                 "store_setup" : Gtk.ListStore(str, int, int, str, str, str, str, str, str, str, str),
                 "column_numbers" : (0,1,2,3,4,5,6,7,8,9,10),
                 "column_headings" : ["EAL Number", "Test Pressure", "Test Duration", "Transducer Number", "Procedure", "Proof Date", "Proof Recall", "Proof Expiry", "Test Location", "Result", "Proof Certificate"],
                 "entries" : self.entries,
                 "file_chooser" : "equipment_proof_file_certificate"}

        Widget.__init__(self, store_func, parent, queries, **setup)

        Function.entry_completion(self, com_store, "equipment_proof_entry_eal", 0)
        Function.entry_completion(self, com_store, "equipment_proof_entry_pt", 0)
        Function.entry_completion(self, proc_store, "equipment_proof_entry_procedure", 2)

    def on_equipment_proof_radio_pass_toggled(self, equipment_proof_radio_pass):
        self.result = "Pass"

    def on_equipment_proof_radio_fail_toggled(self, equipment_proof_radio_fail):
        self.result = "Fail"

    def on_equipment_proof_button_enter_clicked(self, equipment_proof_button_enter):
        entries = ["equipment_proof_entry_eal", "equipment_proof_entry_bar", "equipment_proof_entry_duration", "equipment_proof_entry_pt", "equipment_proof_entry_procedure", "equipment_proof_entry_location"]
        text = Function.get_entries(self, entries)
        proof_date = Cal_Date.date(self, "equipment_proof_calendar_date")
        proof_expiry = Cal_Date.expiry(self, proof_date, 12)
        proof_recall = Cal_Date.recall(self, proof_expiry)

        proof_certificate = ''
        if self.file != None:
            file_name = 'Proof_Certificate_' + str(proof_date)
            file_settings = {"dep":"Equipment", "sub":"Proof", "eal_ref":text[0]}
            proof_certificate = Function.file_path2(self, self.file, file_name, file_settings)
            shutil.copy(self.file, proof_certificate)
            self.file_chooser.unselect_all()
        else:
            proof_certificate = "Not Uploaded"

        now = datetime.now()

        for item in self.current_items:
            row = list(item)
            if row[0] == text[0]:
                match = True
                break
            else:
                match = False

        if match == True:
            query = self.queries.proof["update"]
            utext = text[1:]
            utext.append(text[0])
            values = (now, utext[0], utext[1], utext[2], utext[3], proof_date, proof_recall, proof_expiry, utext[4], self.result, proof_certificate, utext[5])
            procedure = 'N/A'
            message = text[0] + ' updated field'
            log_query = self.queries.logbook["insert"]
            log_values = (now, text[0], now, text[5], text[4], message)
            self.update(query, values, log_query, log_values)

        elif match == False:
            proof_message = "Proof certificate added."
            values = (now, text[0], text[1], text[2], text[3], text[4], proof_date, proof_recall, proof_expiry, text[5], self.result, proof_certificate)
            log_values = (now, text[0], now, text[5], text[4], proof_message)

            query = self.queries.proof["insert"]
            log_query = self.queries.logbook["insert"]
            self.insert(query, values, log_query, log_values)

        Function.clear_entries(self, entries)
        print ("Add")

    def on_equipment_proof_button_clear_clicked(self, equipment_proof_button_clear):
        self.tree_selection.unselect_all()
        self.file_chooser.unselect_all()
        entries = self.entries
        Function.clear_entries(self, entries)
        self.current_filter = None

    def on_equipment_proof_file_certificate_file_set(self, equipment_proof_file_certificate):
        self.file_chooser = equipment_proof_file_certificate
        self.file = self.file_chooser.get_filename()

    def on_equipment_proof_entry_eal_changed(self, equipment_proof_entry_eal):
        search = equipment_proof_entry_eal.get_text()
        self.current_filter = search.upper()
        self.current_filter_column = 0
        self.filter.refilter()

    def on_equipment_proof_page_delete_event(self, *args):
        Gtk.main_quit(*args)

class EquipClean(Widget):
    def __init__(self, queries, store_func, parent, com_store, proc_store):
        self.queries = queries
        self.entries = {"equipment_cleanliness_entry_eal" : 0, "equipment_cleanliness_entry_pco" : 1, "equipment_cleanliness_entry_dew" : 2, "equipment_cleanliness_entry_procedure" : 3, "equipment_cleanliness_entry_location" : 7}
        self.result = "Pass"

        setup = {"glade_file" : "Glade/equipment_cleanliness.glade",
                 "widget_id" :  "equipment_cleanliness_page",
                 "widget_scroll_id" : "equipment_cleanliness_scroll_window",
                 "widget_calander_id" : "equipment_cleanliness_calendar_date",
                 "timer_query" : queries.cleanliness["select"],
                 "store_setup" : Gtk.ListStore(str, str, str, str, str, str, str, str, str, str),
                 "column_numbers" : (0,1,2,3,4,5,6,7,8,9),
                 "column_headings" : ["EAL Number", "Particle Counter Number", "Dew Point Meter", "Procedure", "Cleanliness & Dryness Date", "Cleanliness & Dryness Recall", "Cleanliness & Dryness Expiry", "Test Location", "Result", "Proof Certificate"],
                 "entries" : self.entries,
                 "file_chooser" : "equipment_cleanliness_file_certificate"}

        Widget.__init__(self, store_func, parent, queries, **setup)

        Function.entry_completion(self, com_store, "equipment_cleanliness_entry_eal", 0)
        Function.entry_completion(self, com_store, "equipment_cleanliness_entry_pco", 0)
        Function.entry_completion(self, com_store, "equipment_cleanliness_entry_dew", 0)
        Function.entry_completion(self, proc_store, "equipment_cleanliness_entry_procedure", 2)

    def on_equipment_cleanliness_radio_pass_toggled(self, equipment_cleanliness_radio_pass):
        self.result = "Pass"

    def on_equipment_cleanliness_radio_fail_toggled(self, equipment_cleanliness_radio_fail):
        self.result = "Fail"

    def on_equipment_cleanliness_button_enter_clicked(self, equipment_cleanliness_button_enter):
        entries = ["equipment_cleanliness_entry_eal", "equipment_cleanliness_entry_pco", "equipment_cleanliness_entry_dew", "equipment_cleanliness_entry_procedure", "equipment_cleanliness_entry_location"]
        text = Function.get_entries(self, entries)
        clean_date = Cal_Date.date(self, "equipment_cleanliness_calendar_date")
        clean_expiry = Cal_Date.expiry(self, clean_date, 12)
        clean_recall = Cal_Date.recall(self, clean_expiry)

        clean_certificate = ''
        if self.file != None:
            file_name = 'Cleanliness_&_Dryness_Certificate_' + str(clean_date)
            file_settings = {"dep":"Equipment", "sub":"Cleanliness_&_Dryness", "eal_ref":text[0]}
            clean_certificate = Function.file_path2(self, self.file, file_name, file_settings)
            shutil.copy(self.file, clean_certificate)
            self.file_chooser.unselect_all()
        else:
            clean_certificate = "Not Uploaded"

        now = datetime.now()
        for item in self.current_items:
            row = list(item)
            if row[0] == text[0]:
                match = True
                break
            else:
                match = False

        if match == True:
            query = self.queries.cleanliness["update"]
            utext = text[1:]
            utext.append(text[0])
            values = (now, utext[0], utext[1], utext[2], clean_date, clean_recall, clean_expiry, utext[3], self.result, clean_certificate, utext[4])
            procedure = 'N/A'
            message = text[0] + ' updated field'
            log_query = self.queries.logbook["insert"]
            log_values = (now, text[0], now, text[4], text[3], message)
            self.update(query, values, log_query, log_values)

        elif match == False:
            message = "Cleanliness & Dryness certificate added."

            values = (now, text[0], text[1], text[2], text[3], clean_date, clean_recall, clean_expiry, text[4], self.result, clean_certificate)

            log_values = (now, text[0], now, text[4], text[3], message)
            query = self.queries.cleanliness["insert"]

            log_query = self.queries.logbook["insert"]
            self.insert(query, values, log_query, log_values)

        Function.clear_entries(self, entries)

    def on_equipment_cleanliness_button_clear_clicked(self, equipment_cleanliness_button_clear):
        self.tree_selection.unselect_all()
        self.file_chooser.unselect_all()
        entries = self.entries
        Function.clear_entries(self, entries)
        self.current_filter = None
        print ("Clear")

    def on_equipment_cleanliness_file_certificate_file_set(self, equipment_cleanliness_file_certificate):
        self.file_chooser = equipment_cleanliness_file_certificate
        self.file = self.file_chooser.get_filename()

    def on_equipment_cleanliness_entry_eal_changed(self, equipment_cleanliness_entry_eal):
        search = equipment_cleanliness_entry_eal.get_text()
        self.current_filter = search.upper()
        self.current_filter_column = 0
        self.filter.refilter()

    def on_equipment_cleanliness_page_delete_event(self, *args):
        Gtk.main_quit(*args)

class EquipSearch(Widget):
    def __init__(self, queries, store_func, parent):
        self.queries = queries
        self.entries = {"equipment_search_entry_search" : 0}

        setup = {"glade_file" : "Glade/equipment_search.glade",
                 "widget_id" :  "equipment_search_page",
                 "widget_scroll_id" : "equipment_search_scroll_window",
                 "widget_calander_id" : None,
                 "timer_query" : queries.overview["select"],
                 "store_setup" : Gtk.ListStore(str, str, str, str, str, str, str),
                 "column_numbers" : (0,1,2,3,4,5,6),
                 "column_headings" : ["EAL Number", "Equipment Type", "Serial Number", "Calibration Expiry", "Proof Expiry", "Cleanliness Expiry", "Current Location"],
                 "entries" : self.entries,
                 "file_chooser" : None}

        Widget.__init__(self, store_func, parent, queries, **setup)

    def on_equipment_search_entry_search_changed(self, equipment_search_entry_search):
        search = equipment_search_entry_search.get_text()
        self.current_filter = search.upper()
        self.current_filter_column = 0
        self.filter.refilter()

    def on_equipment_search_button_export_clicked(self, equipment_search_button_export):
        with open('overview.csv', 'w', newline='') as f:
            writer = csv.writer(f)
            rows = self.current_items
            for row in rows:
                writer.writerow(row)

    def on_equipment_search_page_delete_event(self, *args):
        Gtk.main_quit(*args)

class Log(Widget):
    def __init__(self, queries, store_func, parent, com_store, proc_store):
        self.queries = queries
        self.entries = {"equipment_log_entry_eal" : 0, "equipment_log_entry_from" : 2, "equipment_log_entry_procedure" : 3, "equipment_log_entry_message" : 4}

        setup = {"glade_file" : "Glade/equipment_log.glade",
                 "widget_id" :  "equipment_log_page",
                 "widget_scroll_id" : "equipment_log_scroll_window",
                 "widget_calander_id" : "equipment_log_calendar_date",
                 "timer_query" : queries.logbook["select"],
                 "store_setup" : Gtk.ListStore(str, str, str, str, str),
                 "column_numbers" : (0,1,2,3,4),
                 "column_headings" : ["EAL Number", "Log Date", "Location", "Documents", "Message"],
                 "entries" : self.entries,
                 "file_chooser" : None}

        Widget.__init__(self, store_func, parent, queries, **setup)

        Function.entry_completion(self, com_store, "equipment_log_entry_eal", 0)
        Function.entry_completion(self, proc_store, "equipment_log_entry_procedure", 2)

    def on_equipment_log_button_enter_clicked(self, equipment_log_button_enter):
        entries = ["equipment_log_entry_eal", "equipment_log_entry_from", "equipment_log_entry_procedure", "equipment_log_entry_message"]
        text = Function.get_entries(self, entries)
        log_date = Cal_Date.date(self, "equipment_log_calendar_date")
        now = datetime.now()
        log_values = (now, text[0], log_date, text[1], text[2], text[3])
        log_query = self.queries.logbook["insert"]
        self.log_insert(log_query, log_values)

        Function.clear_entries(self, entries)

    def on_equipment_log_button_clear_clicked(self, equipment_log_button_clear):
        self.tree_selection.unselect_all()
        entries = self.entries
        Function.clear_entries(self, entries)
        self.current_filter = None

    def on_equipment_log_entry_eal_changed(self, entry):
        search = entry.get_text()
        self.current_filter = search.upper()
        self.current_filter_column = 0
        self.filter.refilter()

    def on_equipment_log_page_delete_event(self, *args):
        Gtk.main_quit(*args)

class DocAdd(Widget):
    def __init__(self, queries, store_func, parent):
        self.queries = queries
        self.entries = {"documents_add_entry_for" : 0, "documents_add_entry_ref" : 1, "documents_add_entry_name" : 2, "documents_add_entry_issue" : 3, "documents_add_entry_reason" : 4}

        setup = {"glade_file" : "Glade/documents.glade",
                 "widget_id" :  "documents_add_page",
                 "widget_scroll_id" : "documents_add_scroll_window",
                 "widget_calander_id" : "documents_add_calendar_date",
                 "timer_query" : queries.documents["select"],
                 "store_setup" : Gtk.ListStore(str, str, str, int, str, str, str),
                 "column_numbers" : (0,1,2,3,4,5,6),
                 "column_headings" : ["Client", "Reference", "Name", "Issue", "Reason for Issue", "Date", "File"],
                 "entries" : self.entries,
                 "file_chooser" : "documents_add_file_path"}

        Widget.__init__(self, store_func, parent, queries, **setup)

        Function.entry_completion(self, self.store, "documents_add_entry_for", 0)
        Function.entry_completion(self, self.store, "documents_add_entry_ref", 1)
        Function.entry_completion(self, self.store, "documents_add_entry_name", 2)

    def on_documents_add_button_enter_clicked(self, documents_add_button_enter):
        entries = ["documents_add_entry_for", "documents_add_entry_ref", "documents_add_entry_name", "documents_add_entry_issue", "documents_add_entry_reason"]
        text = Function.get_entries(self, entries)
        date = Cal_Date.date(self, "documents_add_calendar_date")

        doc = ''
        if self.file != None:
            file_name = text[2]
            file_settings = {"dep":"Procedures", "sub":text[0], "eal_ref":None}
            doc = Function.file_path2(self, self.file, file_name, file_settings)
            shutil.copy(self.file, doc)
            self.file_chooser.unselect_all()
        else:
            doc = "Not Uploaded"

        now = datetime.now()
        for item in self.current_items:
            row = list(item)
            if row[1] == text[1]:
                match = True
                break
            else:
                match = False

        if match == True:
            query = self.queries.documents["update"]
            values = (now, text[0], text[2], text[3], text[4], date, doc, text[1])
            procedure = 'N/A'
            message = text[1] + ' updated field'
            log_query = self.queries.logbook["insert"]
            log_values = (now, text[0], now, text[4], text[3], message)
            self.update(query, values, log_query, log_values)

        elif match == False:
            query = self.queries.documents["insert"]
            values = (now, text[0], text[1], text[2], text[3], text[4], date, doc)
            log_query = self.queries.logbook["insert"]
            log_values = (now, text[1], date, "N/A", text[2], text[4])
            self.insert(query, values, log_query, log_values)
        Function.clear_entries(self, entries)

    def on_documents_add_button_clear_clicked(self, documents_add_button_clear):
        self.tree_selection.unselect_all()
        self.file_chooser.unselect_all()
        entries = self.entries
        Function.clear_entries(self, entries)
        self.current_filter = None

    def on_documents_add_file_path_file_set(self, documents_add_file_path):
        self.file_chooser = documents_add_file_path
        self.file = self.file_chooser.get_filename()

    def on_documents_add_entry_ref_changed(self, entry):
        search = entry.get_text()
        self.current_filter = search.upper()
        self.current_filter_column = 1
        self.filter.refilter()

    def on_documents_add_entry_for_changed(self, entry):
        search = entry.get_text()
        self.current_filter = search.upper()
        self.current_filter_column = 0
        self.filter.refilter()

    def on_documents_add_entry_name_changed(self, entry):
        search = entry.get_text()
        self.current_filter = search.upper()
        self.current_filter_column = 2
        self.filter.refilter()

        on_documents_add_entry_name_changed

    def on_documents_add_page_delete_event(self, *args):
        Gtk.main_quit(*args)


import sys
from collections import defaultdict
input = sys.stdin.readline

n = int(input())
participants = defaultdict(int)

for _ in range(n):
    name = input().rstrip()
    participants[name] += 1

for _ in range(n-1):
    name = input().rstrip()
    participants[name] -= 1

for key, value in participants.items():
    if value >= 1:
        print(key)


import numpy as np
import os
import ray
import time
from graphpas.search_space import search_space_node_classification, gnn_architecture_flow
from graphpas.graphpas_search import utils
from graphpas.estimation import val_data_etimatamtion
from data_utils.util_cite_network import CiteNetwork
from parallel_config import ParallelConfig, ray_gpu_num

@ray.remote(num_gpus=ray_gpu_num)
class ParallelOperator(object):

    def __init__(self, data, s_parameter, searcher_name, g_parameter):
        self.data = data
        self.search_parameter = s_parameter
        self.searcher_name = searcher_name
        self.gnn_parameter = g_parameter

    @ray.method(num_returns=2)
    def random_initialize_population(self):

        print(35*"=", "initializing population  based on random", 35*"=")

        gnn_architecture_list = []
        gnn_architecture_embedding_list = []
        while len(gnn_architecture_list) < self.search_parameter["single_searcher_initial_num"]:
            gnn_architecture_embedding = utils.random_generate_gnn_architecture_embedding()
            gnn_architecture = utils.gnn_architecture_embedding_decoder(gnn_architecture_embedding)
            gnn_architecture_embedding_list.append(gnn_architecture_embedding)
            gnn_architecture_list.append(gnn_architecture)
        val_acc_list = self.fitness_computation(gnn_architecture_list)

        path = os.path.split(os.path.realpath(__file__))[0][:-24] + "data_save/graphpas_data_save"
        if not os.path.exists(path):
            os.makedirs(path)
        utils.experiment_initial_data_save(path,
                                           self.searcher_name + "_initialization.txt",
                                           gnn_architecture_list,
                                           val_acc_list)

        return gnn_architecture_embedding_list, val_acc_list

    @ray.method(num_returns=1)
    def fitness_computation(self, gnn_architecture_list):
        acc_list = []
        for gnn_architecture in gnn_architecture_list:
            val_acc = val_data_etimatamtion(gnn_architecture,
                                            self.data,
                                            self.gnn_parameter,
                                            self.search_parameter)
            acc_list.append(val_acc)
            print("gnn_architecture: ", gnn_architecture)
            print("gnn_val_acc: ", val_acc)
        return acc_list

class EvolutionSearch(object):

    def __init__(self, searcher_name, sharing_num, mutation_num):
        self.search_name = searcher_name
        self.sharing_num = sharing_num
        self.mutation_num = mutation_num

    def search(self,
               history_pop,
               sharing_population,
               sharing_accuracy,
               mutation_selection_probability):

        print(35*"=", "search", 35*"=")
        print("sharing population:\n", sharing_population)
        print("sharing accuracy:\n", sharing_accuracy)
        print("[sharing population accuracy] Mean/Median/Best:\n",
                np.mean(sharing_accuracy),
                np.median(sharing_accuracy),
                np.max(sharing_accuracy))

        parents = self.selection(sharing_population, sharing_accuracy)
        print(self.search_name + "selected parents:\n", parents)

        children = self.mutation(parents, mutation_selection_probability, history_pop)
        print(self.search_name+"mutated children:\n", children)

        history_pop = history_pop + children

        return children, history_pop

    def selection(self,
                  population,
                  accuracies):
        print(35*"=", self.search_name + " wheel select strategy", 35*"=")
        fitness = np.array(accuracies)
        fitness_probility = fitness / sum(fitness)
        fitness_probility = fitness_probility.tolist()
        index_list = [index for index in range(len(fitness))]
        parents = []
        parent_index = np.random.choice(index_list, self.sharing_num, replace=False, p=fitness_probility)
        for index in parent_index:
            parents.append(population[index].copy())
        return parents

    def mutation(self,
                 parents,
                 mutation_selection_probability,
                 history_pop):

        print(35 * "=", self.search_name + " mutate", 35 * "=")
        for index in range(len(parents)):

            while parents[index] in history_pop:
                position_to_mutate_list = np.random.choice([gene for gene in range(len(parents[index]))],
                                                           self.mutation_num,
                                                           replace=False,
                                                           p=mutation_selection_probability)

                for mutation_index in position_to_mutate_list:
                    mutation_space = search_space_node_classification[gnn_architecture_flow[mutation_index]]
                    parents[index][mutation_index] = np.random.randint(0, len(mutation_space))
        return parents

    def updating(self,
                 sharing_children,
                 sharing_children_val_acc_list,
                 sharing_population,
                 sharing_acc
                 ):

        print(35*"=", "update", 35*"=")
        print("sharing_acc before update:\n", sharing_acc)

        _, top_acc = utils.top_population_select(sharing_population,
                                                 sharing_acc,
                                                 top_k=self.sharing_num)
        avg_accuracy = np.mean(top_acc)

        index = 0
        for acc in sharing_children_val_acc_list:
            if acc > avg_accuracy:
                sharing_acc.append(acc)
                sharing_population.append(sharing_children[index])
                index += 1
            else:
                index += 1
        print("sharing_acc after update:\n", sharing_acc)
        return sharing_population, sharing_acc

class Search(object):

    def __init__(self, data, s_parameter, g_parameter):

        self.data = data
        self.search_parameter = s_parameter
        self.gnn_parameter = g_parameter

    def search_operator(self):

        paralleloperator_list = []
        for searcher_name in self.search_parameter["searcher_name"]:
            paralleloperator = ParallelOperator.remote(self.data,
                                                       self.search_parameter,
                                                       searcher_name,
                                                       self.gnn_parameter)
            paralleloperator_list.append(paralleloperator)

        print(35 * "=", "initial based on random", 35 * "=")

        time_initial = time.time()
        task = []
        for index in range(len(self.search_parameter["searcher_name"])):
            initial_pop_list, val_acc_list = paralleloperator_list[index].random_initialize_population.remote()
            task.append(initial_pop_list)
            task.append(val_acc_list)
        result = ray.get(task)
        time_initial = time.time() - time_initial

        path = os.path.split(os.path.realpath(__file__))[0][:-24] + "data_save/graphpas_time_save"
        if not os.path.exists(path):
            os.makedirs(path)
        utils.experiment_time_save_initial(path, self.data.data_name + "_initial_time.txt", time_initial)

        total_initial_pop_list = []
        for pop in result[::2]:
            total_initial_pop_list = total_initial_pop_list + pop
        total_val_acc_list = []
        for acc in result[1::2]:
            total_val_acc_list = total_val_acc_list + acc

        history_pop = []
        history_acc = []
        index = 0
        for gnn in total_initial_pop_list:
            if gnn not in history_pop:
                history_pop.append(gnn)
                history_acc.append(total_val_acc_list[index])
                index += 1
            else:
                index += 1

        searcher_list = []
        for index in range(len(self.search_parameter["searcher_name"])):
            searcher = EvolutionSearch(searcher_name=self.search_parameter["searcher_name"][index],
                                       sharing_num=self.search_parameter["sharing_num"],
                                       mutation_num=self.search_parameter["mutation_num"][index])
            searcher_list.append(searcher)

        print(35 * "=", "sharing_population select", 35 * "=")
        sharing_population, sharing_accuracy = utils.top_population_select(history_pop,
                                                                           history_acc,
                                                                           top_k=self.search_parameter["sharing_num"])
        sharing_population_temp = sharing_population.copy()
        mutation_selection_probability = utils.mutation_selection_probability(sharing_population_temp, gnn_architecture_flow)
        print(35 * "=", "mutate select probability", 35 * "=")
        print(mutation_selection_probability)
        print(35 * "=", "search", 35 * "=")

        time_search_list = []
        epoch = []

        for i in range(self.search_parameter["search_epoch"]):
            time_search = time.time()
            sharing_children = []
            sharing_children_embedding = []

            for searcher in searcher_list:
                children, history_pop = searcher.search(history_pop,
                                                        sharing_population,
                                                        sharing_accuracy,
                                                        mutation_selection_probability)
                sharing_children.append(children)
                sharing_children_embedding = sharing_children_embedding + children

            sharing_children_architecture = []
            for children_list in sharing_children:
                children_gnn_architecture_list = []
                for gnn_architecture_embedding in children_list:
                    gnn_architecture = utils.gnn_architecture_embedding_decoder(gnn_architecture_embedding)
                    children_gnn_architecture_list.append(gnn_architecture)
                sharing_children_architecture.append(children_gnn_architecture_list)
            print("sharing_children_architecture:\n", sharing_children_architecture)

            task = []
            for gnn_architecture_list, paralleloperator in zip(sharing_children_architecture, paralleloperator_list):
                children_val_acc = paralleloperator.fitness_computation.remote(gnn_architecture_list)
                task.append(children_val_acc)
            result = ray.get(task)
            sharing_children_val_acc_list = []
            for acc in result:
                sharing_children_val_acc_list = sharing_children_val_acc_list + acc

            history_acc = history_acc + sharing_children_val_acc_list

            sharing_population, sharing_accuracy = searcher_list[0].updating(sharing_children_embedding,
                                                                             sharing_children_val_acc_list,
                                                                             sharing_population,
                                                                             sharing_accuracy)

            sharing_population_temp = sharing_population.copy()
            mutation_selection_probability = utils.mutation_selection_probability(sharing_population_temp, gnn_architecture_flow)
            time_search_list.append(time.time()-time_search)
            epoch.append(i+1)

            path = os.path.split(os.path.realpath(__file__))[0][:-24] + "data_save/graphpas_data_save"
            utils.experiment_graphpas_data_save(path,
                                                self.data.data_name + "_search_epoch_" + str(i+1) + ".txt",
                                                sharing_population,
                                                sharing_accuracy)

        index = sharing_accuracy.index(max(sharing_accuracy))
        best_val_architecture = sharing_population[index]
        best_val_architecture = utils.gnn_architecture_embedding_decoder(best_val_architecture)
        best_acc = max(sharing_accuracy)
        print("Best architecture:\n", best_val_architecture)
        print("Best val_acc:\n", best_acc)

        path = os.path.split(os.path.realpath(__file__))[0][:-24] + "data_save/graphpas_time_save"
        utils.experiment_time_save(path,
                                   self.data.data_name + "_search_time.txt",
                                   epoch,
                                   time_search_list)

if __name__=="__main__":
    ParallelConfig(False)

    graph = CiteNetwork("cora")

    search_parameter = {"searcher_name": ["ev1", "ev2"],
                        "mutation_num": [1, 2],
                        "single_searcher_initial_num": 5,
                        "sharing_num": 5,
                        "search_epoch": 2,
                        "es_mode": "transductive",
                        "ensemble": False,
                        "ensemble_num": 5}

    gnn_parameter = {"drop_out": 0.5,
                     "learning_rate": 0.05,
                     "learning_rate_decay": 0.0005,
                     "train_epoch": 5,
                     "model_select": "min_loss",
                     "retrain_epoch": 5,
                     "early_stop": False,
                     "early_stop_mode": "val_acc",
                     "early_stop_patience": 10}

    graphpas_instance = Search(graph, search_parameter, gnn_parameter)
    graphpas_instance.search_operator()


from queue import PriorityQueue

import torch
from loguru import logger
from torch import nn
from torch.nn.utils import weight_norm
from torch.nn.utils.rnn import pack_padded_sequence

class FullyConnectedLayer(torch.nn.Module):
    def __init__(self,
                 in_dim,
                 out_dim,
                 do_batch_norm=False,
                 do_weight_norm=False,
                 dropout=None,
                 activation=None):
        super().__init__()
        self.linear = nn.Linear(in_dim, out_dim)
        if do_batch_norm and do_weight_norm:
            logger.warning(
                "batch norm and weight norm enabled at the same time!")
        if do_weight_norm:
            logger.info("weight norm enabled.")
            self.linear = weight_norm(self.linear)
        if dropout:
            self.dropout = nn.Dropout(dropout)
        else:
            self.dropout = None
        if do_batch_norm:
            logger.info("batch norm enabled.")
            self.bn = nn.BatchNorm1d(out_dim)
        else:
            self.bn = None
        if not activation:
            logger.warning("no activation function!")
        self.activation = activation

    def forward(self, input):
        out = self.linear(input)
        if self.bn:
            out = self.bn(out)
        if self.activation:
            out = self.activation(out)
        if self.dropout:
            out = self.dropout(out)
        return out

class ObjectClassifier(torch.nn.Module):
    def __init__(self,
                 feature_dim,
                 att_dim,
                 linear_dims,
                 num_of_classes,
                 dropout=0.5):
        super().__init__()
        self.fc_att0 = FullyConnectedLayer(feature_dim[1],
                                           att_dim,
                                           do_weight_norm=True,
                                           dropout=dropout,
                                           activation=nn.ReLU())
        self.fc_att1 = FullyConnectedLayer(att_dim,
                                           1,
                                           do_weight_norm=True,
                                           activation=nn.Softmax(dim=1))
        self.fc_pred_first = FullyConnectedLayer(feature_dim[1],
                                                 linear_dims[0],
                                                 do_batch_norm=True,
                                                 activation=nn.ReLU())
        self.fc_pred_last = FullyConnectedLayer(linear_dims[-1],
                                                num_of_classes)
        self.fc_pred_middle = nn.ModuleList()
        for i in range(len(linear_dims) - 1):
            self.fc_pred_middle.append(
                FullyConnectedLayer(linear_dims[i],
                                    linear_dims[i + 1],
                                    do_batch_norm=True,
                                    activation=nn.ReLU()))

    def forward(self, inputs):
        image_features, = inputs
        att_0 = self.fc_att0(image_features)
        alphas = self.fc_att1(att_0)
        reduced_features = torch.sum(alphas * image_features, dim=1)
        h = self.fc_pred_first(reduced_features)
        for layer in self.fc_pred_middle:
            h = layer(h)
        h = self.fc_pred_last(h)
        return h

class LanguageModel(torch.nn.Module):
    def __init__(self,
                 vocal_size,
                 embed_dim,
                 hidden_dim,
                 feature_dim,
                 img_embed_dim,
                 att_dim,
                 device,
                 dropout=0.5):
        super().__init__()
        self.embedding = nn.Embedding(vocal_size,
                                      embed_dim,
                                      padding_idx=0,
                                      max_norm=1.)

        self.hidden_dim = hidden_dim
        self.fc_att_embed = FullyConnectedLayer(feature_dim[1],
                                                img_embed_dim,
                                                do_weight_norm=True,
                                                activation=nn.ReLU())
        self.lstm_att = nn.LSTMCell(hidden_dim + img_embed_dim + embed_dim,
                                    hidden_dim)

        self.fc_att_hidden = FullyConnectedLayer(
            hidden_dim,
            att_dim,
            do_weight_norm=True,
        )
        self.fc_att_image = FullyConnectedLayer(
            feature_dim[1],
            att_dim,
            do_weight_norm=True,
        )
        self.relu = nn.ReLU()
        self.dropout = nn.Dropout(dropout)
        self.fc_lang_embed = FullyConnectedLayer(feature_dim[1],
                                                 img_embed_dim,
                                                 do_weight_norm=True,
                                                 activation=nn.ReLU())
        self.fc_att_out = FullyConnectedLayer(att_dim,
                                              1,
                                              do_weight_norm=True,
                                              activation=nn.Softmax(dim=1))

        self.lstm_lang = nn.LSTMCell(hidden_dim + img_embed_dim, hidden_dim)
        self.fc_pred1 = FullyConnectedLayer(
            hidden_dim,
            vocal_size,
            do_weight_norm=True,
        )

        self.device = device

    def step(self, image_features, prev_pred, att_h0, att_c0, lang_h0,
             lang_c0):
        mean_features = torch.mean(image_features, dim=1)
        input_embed = self.embedding(prev_pred)
        mean_features_embed = self.fc_att_embed(mean_features)
        att_input = torch.cat([lang_h0, mean_features_embed, input_embed],
                              dim=1)

        att_h1, att_c1 = self.lstm_att(att_input, (att_h0, att_c0))

        att_h = self.fc_att_hidden(self.dropout(att_h1)).unsqueeze(1)
        att_v = self.fc_att_image(image_features)
        att_in = self.dropout(self.relu(att_h + att_v))
        alphas = self.fc_att_out(att_in)
        reduced_features = torch.sum(alphas * image_features, dim=1)
        reduced_features_embed = self.fc_lang_embed(reduced_features)

        lang_input = torch.cat([reduced_features_embed, att_h1], dim=1)
        lang_h1, lang_c1 = self.lstm_lang(lang_input, (lang_h0, lang_c0))

        pred = self.fc_pred1(self.dropout(lang_h1))

        return pred, att_h1, att_c1, lang_h1, lang_c1

    def init_hidden(self, batch_size):
        att_h0 = torch.zeros(batch_size, self.hidden_dim, device=self.device)
        att_c0 = torch.zeros(batch_size, self.hidden_dim, device=self.device)
        lang_h0 = torch.zeros(batch_size, self.hidden_dim, device=self.device)
        lang_c0 = torch.zeros(batch_size, self.hidden_dim, device=self.device)

        return att_h0, att_c0, lang_h0, lang_c0

    def forward(self, inputs):
        image_features, seq, seq_length = inputs
        seq_length += 1  # won't input <end>
        seq_length = seq_length.cpu().to(torch.int64)
        packed_seq = pack_padded_sequence(seq,
                                          seq_length,
                                          batch_first=True,
                                          enforce_sorted=False)
        batchs = torch.split(packed_seq.data, packed_seq.batch_sizes.tolist())
        sorted_features = image_features[packed_seq.sorted_indices]
        att_h, att_c, lang_h, lang_c = self.init_hidden(len(seq))
        preds = []
        for batch in batchs:
            batch_size = len(batch)
            batch_features = sorted_features[:batch_size]
            batch_att_h0 = att_h[:batch_size]
            batch_att_c0 = att_c[:batch_size]
            batch_lang_h0 = lang_h[:batch_size]
            batch_lang_c0 = lang_c[:batch_size]
            pred, att_h1, att_c1, lang_h1, lang_c1 = self.step(
                batch_features, batch, batch_att_h0, batch_att_c0,
                batch_lang_h0, batch_lang_c0)
            preds.append(pred)
            att_h = att_h1
            att_c = att_c1
            lang_h = lang_h1
            lang_c = lang_c1
        return torch.cat(preds)

    def decode(self, inputs, end, beam=1):
        # in forward(), inputs are in batches, seq is the gold label
        # in decode(), batch size is always 1, seq is the guiding sequence.
        # for lstm-left, guiding sequence is the guiding object, and asumed
        # sequence, in reverse order.
        # for lstm-right, guiding sequence is the output of lstm-left, in
        # reverse order.
        image_features, seq, seq_length = inputs
        seq_length += 1
        att_h, att_c, lang_h, lang_c = self.init_hidden(1)
        # use log softmax, so that we can add the scores (instead of multiply)
        softmax = nn.LogSoftmax(dim=0)
        top_k = PriorityQueue()
        ended = 0
        guiding_length = seq_length[0]

        # prepare model states with input sequence
        for i in range(guiding_length - 1):
            pred, att_h, att_c, lang_h, lang_c = self.step(
                image_features, seq[0, i].view(-1), att_h, att_c, lang_h,
                lang_c)

        # start actual decoding (no guidng sequence left)
        pred, att_h, att_c, lang_h, lang_c = self.step(
            image_features, seq[0, guiding_length - 1].view(-1), att_h, att_c,
            lang_h, lang_c)
        pred = pred.view(-1)
        pred = softmax(pred)
        top_k_pred = torch.argsort(pred, descending=True)[:beam]
        for candidate in top_k_pred:
            # negate the score, because priority queue is in ascending order
            top_k.put((-pred[candidate], [candidate]))

        decoded_length = 0
        while decoded_length < 50:
            new_top_k = PriorityQueue()
            ended = 0
            for _ in range(beam):
                score, pred_seq = top_k.get()
                if pred_seq[-1] == end:
                    new_top_k.put((score, pred_seq))
                    ended += 1
                    continue
                pred, att_h, att_c, lang_h, lang_c = self.step(
                    image_features, pred_seq[-1].view(-1), att_h, att_c,
                    lang_h, lang_c)
                pred = pred.view(-1)
                pred = softmax(pred)
                top_k_pred = torch.argsort(pred, descending=True)[:beam]
                for candidate in top_k_pred:
                    new_top_k.put(
                        (-pred[candidate] + score, pred_seq + [candidate]))
            top_k = new_top_k
            decoded_length += 1
            if ended == beam:
                break
        top_results = []
        for _ in range(beam):
            score, final_pred_seq = top_k.get()
            top_results.append(
                (score.item(), [x.item() for x in final_pred_seq]))
        return top_results


from rest_framework import serializers
from apps.phones.models import Phone

class PhoneSerializer(serializers.ModelSerializer):

    class Meta:
        model = Phone
        read_only_fields = (
            "id",
            "created_at"
        )
        fields = (
            "id",
            "created_at",
            "name",
            "brand",
            "os",
            "description",
            "color",
            "screen",
            "processor",
            "ram",
            "camera",
            "price",
            "offerPrice",
            "hasOffer",
            "image",
        )

    #This function returns media images
    def get_photo_url(self, obj):
        request = self.context.get('request')
        photo_url = obj.fingerprint.url
        return request.build_absolute_uri(photo_url)


import numpy as np
import pandas as pd
from math import *
import matplotlib.pyplot as plt

'''
Convert user input string to an executable function.
CAUTION eval() converts user input into executable code.
'''
def get_differential():
    expression = input('Enter the differential equation using Python math syntax in terms of x and y\ndy/dx = ')
    diff = lambda x,y: eval(expression)
    return diff

'''
Run eulers method to approximate the solution.

Parameters:
    equation: differential
    stop: the desired guess
    init_x: initial x
    init_y: initial y
    h: step interval
'''
def euler_method(equation, stop,init_x, init_y, h):
    #list to return with cord_y being the guesses at cord_x
    cord_x = []
    cord_y = []
    y_curr = init_y
    x_curr = init_x
    h_curr = h

    while ( not compare_floats(x_curr, stop + h)):
        try:
            cord_x.append(x_curr)
            cord_y.append(y_curr)
            y_prev = equation(x_curr, y_curr)
            y_curr = y_curr + h * y_prev
            x_curr = init_x + h_curr
        except ZeroDivisionError:
            pass
        finally:
            if(abs(x_curr) > abs(stop + h)):
                raise ValueError('The step is too large.')
            h_curr += h

    return (cord_x,cord_y)

def compare_floats(f1,f2):
    return abs(f1 - f2) <= 0.000001

def main():
    #user input
    equation = get_differential()
    stop = float(input('approximate unil x_n = '))
    init_x = float(input('initial condition x_0 = '))
    init_y = float(input('f(x_0) = '))
    h = float(input('h = '))

    cord_x, cord_y = euler_method(equation, stop,init_x, init_y, h)
    df = pd.DataFrame({'x ' : cord_x, '\u2248y(x) ' : cord_y}) #dataframes are easy to print and graph
    df.index += 1 #for printing
    with pd.option_context('display.max_rows', None, 'display.max_columns', 3):
        print(df)

    '''plot the approximate solution curve'''
    df.plot(x = 'x ', y= '\u2248y(x) ')
    plt.show()

main()


from django.urls import path

from . import views

urlpatterns = [
    path('', views.journal, name='journal'),
    path('add_entry/', views.add_entry.as_view(),name='add_entry'),
    path('search/', views.SearchView.as_view(), name='search'),
    path('search/<int:pk>/', views.FoodDetail.as_view(),name='details'),
    path('search/food_register/', views.food_register.as_view(), name='food_register'),
    path('login/', views.login_view, name='login_view'),
    path('login/authenticate/', views.authenticate_view, name='authenticate'),
    path('logout/', views.logout_view, name='logout_view'),
    path('registrate/', views.registrate_view, name='sign_up'),
    path('registrate/process_account/', views.process_account, name='process_account'),
]


#!/usr/bin/env python
#
# Author: Thamme Gowda [tg (at) isi (dot) edu]
# Created: 2019-10-25

from typing import List, Dict, Union, Optional, TypeVar, Generic, Any
import heapq

class LnNode:  # doubly linked list node data structure; used for learning BPE
    __slots__ = 'val', 'left', 'right', 'freq', 'data'

    def __init__(self, val: int, left: Optional['LnNode'] = None,
                 right: Optional['LnNode'] = None, freq: int = 1, data: Any = None):
        self.val = val
        self.left = left
        self.right = right
        self.freq = freq
        self.data = data

    def __eq__(self, other):
        # caution: these calls are recursive on left and right; cycles would cause infinite loop
        return (other.val == self.val and other.freq == self.freq and
                other.left == self.left and other.right == self.right)

    def __hash__(self):
        return id(self)  # quick and dirty hash; not sure how this mess if we use multiprocessing

    def delete(self, unlink=True):
        """
        deletes this node from the list
        :return:
        """
        x, y = self.left, self.right
        if x:  # right links : x → self → y  => x → y
            x.right = y
        if y:  # left links  : x ← self ← y  => x ← y
            y.left = x
        if unlink:
            self.left = self.right = None

    @property
    def is_unlinked(self):
        return self.right is None and self.left is None

    @classmethod
    def from_seq(cls, string: Union[str, List[int]], freq=1, data=None) -> List['LnNode']:
        """
        makes a doubly linked list from string
        :param string: input string (of integers recommended)
        :param freq: frequency of string in corpus (for scaling
        :return: List of Nodes, doubly linked to lefts and rights
        """
        nodes = [cls(ch, freq=freq, data=data) for ch in string]
        for i, n in enumerate(nodes):
            if i > 0:
                n.left = nodes[i - 1]
            if i + 1 < len(nodes):
                n.right = nodes[i + 1]
        return nodes

    def __repr__(self):
        lefts, rights = [], []

        cur = self.left
        while cur:
            lefts.append(str(cur.val))
            cur = cur.left
        cur = self.right
        while cur:
            rights.append(str(cur.val))
            cur = cur.right
        return ' '.join(reversed(lefts)) + f' *{self.val}* ' + ' '.join(rights)

T = TypeVar('T')  # T for index; Dont use I, since 'I' agree with pep008
D = TypeVar('D')  # D for data

class TrNode(Generic[T, D]):  # Trie Node or Tree Node

    __slots__ =  'idx', 'name', 'data', 'parent', 'kids'

    def __init__(self, idx: T, name: Optional[str] = None, data: Optional[D] = None,
                 parent: Optional['TrNode'] = None, kids: Dict[T, 'TrNode'] = None):
        self.idx = idx
        self.name = name
        self.data = data
        self.parent = parent
        self.kids = dict() if kids is None else kids

    def get_node(self, idxs, create_missing: bool = True) -> 'TrNode[T, D]':
        if not idxs:
            return self
        if create_missing and idxs[0] not in self.kids:  # make one
            self.kids[idxs[0]] = TrNode(idx=idxs[0], parent=self)
        return self.kids[idxs[0]].get_node(idxs=idxs[1:], create_missing=create_missing)

    @property
    def n_kids(self):
        """Number of immediate children"""
        return len(self.kids)

    @property
    def has_data(self):
        return self.data is not None

    @property
    def size(self):
        """Number of nodes in the tree at this node. Counts self and all the kids"""
        return 1 + sum(k.size for k in self.kids.values())

    @property
    def data_node_count(self):
        return (1 if self.has_data else 0) + sum(k.data_node_count for k in self.kids.values())

class MaxHeap:
    "Offers Max Heap which is a wrapper to fast min heap implementation from heapq "

    def __init__(self, items: Dict[Any, int]):
        self.min_heap = [(-val, node) for node, val in items.items()]
        heapq.heapify(self.min_heap)

    def push(self, node, val):
        """
        Adds a node to heap while maintaining heap property
        :param node: node data
        :param val: priority value
        :return:
        """
        heapq.heappush(self.min_heap, (-val, node))

    def pop(self):
        """returns the max item (task, priority)"""
        val, task = heapq.heappop(self.min_heap)
        return task, -val

    def peek(self):
        val, task = self.min_heap[0]
        return task, -val

    def __len__(self):
        return len(self.min_heap)


import sqlalchemy
import os

"""
Reset trending_page_views column for each game
"""

# Connect to Database
engine = sqlalchemy.create_engine(os.getenv('SQLALCHEMY_DATABASE_URI'))

# Prepare SQL query
sql = 'UPDATE games SET trending_page_views = 0'

# Execute query
with engine.connect() as con:
    rs = con.execute(sql)
    print("Trending views have been reset")


""" Core classes. """

from sklearn.externals.joblib import Parallel, delayed
from sklearn.model_selection import cross_val_score, cross_val_predict
from sklearn.model_selection import GridSearchCV
from sklearn.metrics.scorer import check_scoring
from sklearn.pipeline import Pipeline
from sklearn.base import TransformerMixin, BaseEstimator

from collections import OrderedDict
from itertools import product
from pandas import DataFrame
from numpy import mean, std, hstack, zeros
from time import time

import os

class Pipeliner(object):
    """

    Parameters:
    -----------
    steps : list
        List of (name, transforms) tuples

    eval_cv : int, cross-validation generator or an iterable, optional
        Determines the evaluation cross-validation splitting strategy.
        Possible inputs for cv are:
            - None, to use the default 3-fold cross validation,
            - integer, to specify the number of folds in a `(Stratified)KFold`,
            - An object to be used as cross-validation generator.
            - An iterable yielding train, test splits.

        For integer/None inputs, if the estimator is a classifier and ``y`` is
        either binary or multiclass, :class:`StratifiedKFold` is used. In all
        other cases, :class:`KFold` is used.

        Refer :ref:`User Guide <cross_validation>` for the various
        cross-validation strategies that can be used here.

    grid_cv : int, cross-validation generator or an iterable, optional

    param_grid :

    banned_combos :

    Attributes:
    -----------

    Examples:
    ---------

    """
    def __init__(self, steps, eval_cv, grid_cv, param_grid=dict(),
            banned_combos=list()):
        steps = OrderedDict(steps)
        columns = list(steps)
        for column in columns:
            steps[column] = OrderedDict(steps[column])

        def accept_from_banned_combos(row_keys, banned_combo):
            if set(banned_combo) - set(row_keys) == set():
                return False
            else:
                return True

        column_keys = [list(steps[column]) for column in columns]
        plan_rows = list()
        for row_keys in product(*column_keys):
            accept = list()
            for bnnd_cmb in banned_combos:
                accept += [accept_from_banned_combos(row_keys, bnnd_cmb)]

            if all(accept):
                row_of_plan = OrderedDict()
                for column, row_key in zip(columns, row_keys):
                    row_of_plan[column] = row_key
                plan_rows.append(row_of_plan)

        self.plan_table = DataFrame().from_dict(plan_rows)[columns]
        self.named_steps = steps
        self.eval_cv = eval_cv
        self.grid_cv = grid_cv
        self.param_grid = param_grid
        self._cached_data = OrderedDict()
        self.best_params = dict()
        self.scores = dict()

    def dump(self, path_to_file):
        """
        Write a representation of a Pipeliner's class to a specified file.

        Parameters:
        -----------
        path_to_file : string
            A path to which you want to save a class.

        """
        with open(path_to_file, 'wb') as f:
            for attr in sorted(self.__dict__.keys()):
                dump(getattr(self, attr), f)

    def load(self, path_to_file):
        """
        Load a representation of a Pipeliner's class from a specified file.

        Parameters:
        -----------
        path_to_file : string
            A path from which you want to load a class.

        """
        with open(path_to_file, 'rb') as f:
            for attr in sorted(self.__dict__.keys()):
                setattr(self, attr, load(f))

    def transform_with_caching(self, data, row_keys):
        """
        Sequentially apply a list of transforms to an input data.

        Parameters:
        -----------
        data : any
            A data, to which you want to apply transformations.

        row_keys : list
            Keys of transformations.

        Returns:
        --------
        transformed_data : any
            A data transformed with all specified transformations.

        """
        columns = list(self.plan_table.columns[:len(row_keys)])

        def remove_unmatched_caching_data(row_keys):
            cached_keys = list(self._cached_data)
            unmatched_caching_keys = cached_keys.copy()
            for row_key, cached_key in zip(row_keys, cached_keys):
                if not row_key == cached_key:
                    break
                unmatched_caching_keys.remove(row_key)

            for unmatched_caching_key in unmatched_caching_keys:
                del self._cached_data[unmatched_caching_key]

        def transform_data_from_last_cached(row_keys, columns):
            prev_key = list(self._cached_data)[-1]
            for row_key, column in zip(row_keys, columns):
                transformer = self.named_steps[column][row_key]
                data = self._cached_data[prev_key]
                self._cached_data[row_key] = transformer.fit_transform(data)
                prev_key = row_key

        if 'init' not in self._cached_data:
            self._cached_data['init'] = data
            transform_data_from_last_cached(row_keys, columns)
        else:
            row_keys = ['init'] + row_keys
            columns = ['init'] + columns
            remove_unmatched_caching_data(row_keys)
            cached_keys = list(self._cached_data)
            cached_keys_length = len(cached_keys)
            for i in range(cached_keys_length):
                del row_keys[0]
                del columns[0]
            transform_data_from_last_cached(row_keys, columns)

        last_cached_key = list(self._cached_data)[-1]

        return self._cached_data[last_cached_key]

    def get_grid_search_results(self, X, y, row_keys, scoring):
        """
        Give results with tuned parameters of a specified pipeline using grid search.

        Parameters:
        -----------
        X : array-like, shape (n_samples, n_features)
            Training vectors, where n_samples is the number of samples and n_features is the number of features.
            For kernel=”precomputed”, the expected shape of X is (n_samples, n_samples).

        y : array-like, shape (n_samples,)
            Target values (class labels in classification, real numbers in regression)

        row_keys : list
            Keys of transformations.

        scoring : list or str
            Name of a scoring method.
            If None, the score method of the estimator is used.

        Returns:
        --------
        results : dict
            Results dictionary.
        """
        classifier_key = row_keys[-1]
        if classifier_key in self.param_grid:
            columns = list(self.plan_table.columns)[-len(row_keys):]

            steps = list()
            for row_key, column in zip(row_keys, columns):
                steps.append((row_key, self.named_steps[column][row_key]))

            param_grid = dict()
            for key, value in self.param_grid[classifier_key].items():
                param_grid['{}__{}'.format(classifier_key, key)] = value

            self.asdf = param_grid
            self.asdfasdf = self.param_grid[classifier_key]

            grid_clf = GridSearchCV(estimator=Pipeline(steps),
                                    param_grid=param_grid,
                                    scoring=scoring,
                                    n_jobs=-1,
                                    cv=self.grid_cv)
            grid_clf.fit(X, y)

            best_params = dict()
            classifier_key_len = len(classifier_key)
            for key, value in grid_clf.best_params_.items():
                key = key[classifier_key_len + 2:]
                best_params[key] = value
            param_key = ''.join(row_keys) + str(scoring)
            self.best_params[param_key] = best_params

            results = dict()
            for i, params in enumerate(grid_clf.cv_results_['params']):
                if params == grid_clf.best_params_:

                    k = 'grid_{}_mean'.format(scoring)
                    results[k] = grid_clf.cv_results_['mean_test_score'][i]

                    k = 'grid_{}_std'.format(scoring)
                    results[k] = grid_clf.cv_results_['std_test_score'][i]

                    k = 'grid_{}_best_params'.format(scoring)
                    results[k] = str(best_params)

            return results
        else:
            param_key = ''.join(row_keys) + str(scoring)
            self.best_params[param_key] = dict()
            results = dict()
            results['grid_{}_mean'.format(scoring)] = 'NaN'
            results['grid_{}_std'.format(scoring)] = 'NaN'
            results['grid_{}_best_params'.format(scoring)] = 'NaN'
            return results

    def get_scores(self, X, y, row_keys, scoring, collect_n=None):
        """

        Parameters:
        -----------

        X :

        y :

        row_keys :

        scoring :

        collect_n :

        Returns:
        --------

        """
        columns = list(self.plan_table.columns)[-len(row_keys):]
        param_key = ''.join(row_keys) + str(scoring)

        steps = list()
        for row_key, column in zip(row_keys, columns):
            steps.append((row_key, self.named_steps[column][row_key]))

        steps[-1][1].set_params(**self.best_params[param_key])

        if not collect_n:
            scores = cross_val_score(Pipeline(steps), X, y,
                                     scoring=scoring,
                                     cv=self.eval_cv,
                                     n_jobs=-1)
        else:
            init_random_state = self.eval_cv.random_state
            scores = list()
            for i in range(collect_n):
                fold_prediction = cross_val_predict(Pipeline(steps), X, y,
                                                     cv=self.eval_cv,
                                                     n_jobs=-1)
                metric = check_scoring(steps[-1][1],
                                    scoring=scoring).__dict__['_score_func']
                scores.append(metric(y, fold_prediction))
                self.eval_cv.random_state += 1

            self.eval_cv.random_state = init_random_state
        return scores

    def get_results(self, data, caching_steps=list(), scoring='accuracy',
            results_file='results.csv', logs_file='results.log', collect_n=None):
        """

        Parameters:
        -----------
        data :

        caching_steps :

        scoring :

        results_file :

        logs_file :

        collect_n :

        Returns:
        --------

        """
        if type(scoring) == str:
            scoring = [scoring]

        columns = list(self.plan_table.columns)
        without_caching = [step for step in columns
                                if step not in caching_steps]

        for metric in scoring:
            grid_steps = ['grid_{}_mean'.format(metric),
                          'grid_{}_std'.format(metric),
                          'grid_{}_best_params'.format(metric)]

            eval_steps = ['eval_{}_mean'.format(metric),
                          'eval_{}_std'.format(metric),
                          'eval_{}_scores'.format(metric)]

            columns += grid_steps + eval_steps

        results = DataFrame(columns=columns)

        try:
            os.remove(results_file)
            print('Removed previous results file -- {}.'.format(results_file))
        except:
            print('No previous results found.')
        if results_file != None:
            results.to_csv(results_file)

        columns = list(self.plan_table.columns)
        results[columns] = self.plan_table

        with open(logs_file, 'w+') as logs:
            N = len(self.plan_table.index)
            for idx in self.plan_table.index:
                print('Line: {}/{}'.format(idx + 1, N))
                logs.write('Line: {}/{}\n'.format(idx + 1, N))
                logs.write('{}\n'.format(str(self.plan_table.loc[idx])))
                row = self.plan_table.loc[idx]
                caching_keys = list(row[caching_steps].values)

                time_point = time()
                X_featured, y = self.transform_with_caching(data, caching_keys)
                spent_time = round(time() - time_point, 3)
                logs.write('Got Features: {} sec\n'.format(spent_time))

                for metric in scoring:
                    logs.write('Scoring: {}\n'.format(metric))
                    ml_keys = list(row[without_caching].values)
                    time_point = time()
                    grid_res = self.get_grid_search_results(X_featured, y,
                                                            ml_keys,
                                                            metric)
                    spent_time = round(time() - time_point, 3)
                    logs.write('Grid Search: {} sec\n'.format(spent_time))
                    logs.write('Grid Search Results: {}\n'.format(grid_res))

                    for key, value in grid_res.items():
                        results.loc[idx][key] = value

                    time_point = time()
                    scores = self.get_scores(X_featured, y,
                                             ml_keys,
                                             metric,
                                             collect_n)
                    spent_time = round(time() - time_point, 3)
                    logs.write('Got Scores: {} sec\n'.format(spent_time))

                    mean_key = 'eval_{}_mean'.format(metric)
                    scores_mean = mean(scores)
                    results.loc[idx][mean_key] = scores_mean
                    logs.write('Scores mean: {}\n'.format(scores_mean))

                    std_key = 'eval_{}_std'.format(metric)
                    scores_std = std(scores)
                    results.loc[idx][std_key] = scores_std
                    logs.write('Scores std: {}\n'.format(scores_std))

                    scores_key = 'eval_{}_scores'.format(metric)
                    results.loc[idx][scores_key] = str(scores)
                    logs.write('Scores: {}\n\n'.format(str(scores)))
                results.loc[[idx]].to_csv(results_file, header=False, mode='a+')

        return results

class Transformer(TransformerMixin, BaseEstimator):
    """

    Parameters:
    -----------
    func :

    params :

    collect :

    Attributes:
    -----------

    """
    def __init__(self, func, params=None, collect=None):
        self.func = func
        self.params = params
        self.collect = collect

    def fit(self, data):
        """

        Parameters:
        -----------
        data :

        Returns:
        --------

        """
        return self

    def transform(self, data):
        """

        Parameters:
        -----------
        data :

        Returns:
        --------
        """
        if type(data) == dict:
            data = data.copy()

        if self.params:
            self.params['data'] = data
            result = self.func(**self.params)
        else:
            result = self.func(data)

        if self.collect:
            y = result['y']
            X = result[self.collect[0]]

            for key in self.collect[1:]:
                X = hstack((X, result[key]))
            return X, y

        return result

__all__ = ['Transformer', 'Pipeliner']


from gi.repository import GLib, GObject, Gio, Gedit, Ggit

class GitAppActivatable(GObject.Object, Gedit.AppActivatable):
    app = GObject.Property(type=Gedit.App)

    __instance = None

    def __init__(self):
        super().__init__()

        Ggit.init()

        GitAppActivatable.__instance = self

    def do_activate(self):
        self.clear_repositories()

    def do_deactivate(self):
        self.__git_repos = None
        self.__workdir_repos = None

    @classmethod
    def get_instance(cls):
        return cls.__instance

    def clear_repositories(self):
        self.__git_repos = {}
        self.__workdir_repos = {}

    def get_repository(self, location, is_dir, *, allow_git_dir=False):
        # The repos are cached by the directory
        dir_location = location if is_dir else location.get_parent()
        dir_uri = dir_location.get_uri()

        # Fast Path
        try:
            return self.__workdir_repos[dir_uri]

        except KeyError:
            pass

        try:
            repo = self.__git_repos[dir_uri]

        except KeyError:
            pass

        else:
            return repo if allow_git_dir else None

        # Doing remote operations is too slow
        if not location.has_uri_scheme('file'):
            return None

        # Must check every dir, otherwise submodules will have issues
        try:
            repo_file = Ggit.Repository.discover(location)

        except GLib.Error:
            # Prevent trying to find a git repository
            # for every file in this directory
            self.__workdir_repos[dir_uri] = None
            return None

        repo_uri = repo_file.get_uri()

        # Reuse the repo if requested multiple times
        try:
            repo = self.__git_repos[repo_uri]

        except KeyError:
            repo = Ggit.Repository.open(repo_file)

            # TODO: this was around even when not used, on purpose?
            head = repo.get_head()
            commit = repo.lookup(head.get_target(), Ggit.Commit)
            tree = commit.get_tree()

            self.__git_repos[repo_uri] = repo

        # Need to keep the caches for workdir and
        # the .git dir separate to support allow_git_dir
        if dir_uri.startswith(repo_uri):
            top_uri = repo_uri
            repos = self.__git_repos

        else:
            top_uri = repo.get_workdir().get_uri()
            repos = self.__workdir_repos

        # Avoid trouble with symbolic links
        while dir_uri.startswith(top_uri):
            repos[dir_uri] = repo

            dir_location = dir_location.get_parent()
            dir_uri = dir_location.get_uri()

            # Avoid caching the repo all the
            # way up to the top dir each time
            if dir_uri in repos:
                break

        if repos is self.__git_repos:
            return repo if allow_git_dir else None

        return repo

# ex:ts=4:et:


from flask import Flask
import json

app = Flask(__name__)

@app.route("/<int:number>", methods=["GET"])
def default_range(number):
    result = []
    for n in range(1, number + 1):
        result.append(n)
    return {
        "result" : tuple(result)
    }

@app.route("/<int:number>/odd", methods=["GET"])
def odd_range(number):
    result = []
    for n in range(1, number + 1, 2):
        if(n % 2 == 1):
            result.append(n)
    return {
        "result" : tuple(result)
    }

@app.route("/<int:number>/even", methods=["GET"])
def even_range(number):
    result = []
    for n in range(2, number + 1, 2):
        result.append(n)
    return {
        "result" : tuple(result)
    }

@app.route("/<int:number>/prime", methods=["GET"])
def prime_range(number):
    result = []
    s = [True] * number

    for a in range(2, number):
        if s[a] == True:
            result.append(a)

            for b in range(2, number):
                if (a * b) >= number:
                    break
                s[a * b] = False

    return {
        "result" : tuple(result)
    }


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('logger', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='RestService',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False,
                                        auto_created=True, primary_key=True)),
                ('service_url', models.URLField(verbose_name='Service URL')),
                ('name', models.CharField(
                    max_length=50,
                    choices=[('f2dhis2', 'f2dhis2'),
                             ('generic_json', 'JSON POST'),
                             ('generic_xml', 'XML POST'),
                             ('bamboo', 'bamboo'),
                             ('textit', 'TextIt POST')])),
                ('xform', models.ForeignKey(
                    to='logger.XForm', on_delete=models.CASCADE)),
            ],
            options={
            },
            bases=(models.Model,),
        ),
        migrations.AlterUniqueTogether(
            name='restservice',
            unique_together=set([('service_url', 'xform', 'name')]),
        ),
    ]


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

import click

import os
import subprocess
import getpass
import shutil
import shlex
import time
import json

def ejecutar_comando(shellcmd, verbose=True):
    p = subprocess.Popen(
        shlex.split(shellcmd),
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT
    )
    segundos_transcurridos = 0
    if verbose:
        click.echo(' ', nl=False)
    while(True):
        poll = p.poll()
        if poll == None:
            if verbose:
                click.echo('.', nl=False)
            if segundos_transcurridos > 20:
                p.kill()
                if verbose:
                    click.echo(click.style(' Falló', fg='red'))

                return -1
        else:
            if poll != 0:
                if verbose:
                    click.echo(click.style(' Falló', fg='red'))

                    print(p.stdout.read())
                return -1
            if verbose:
                click.echo(click.style(' Ok', fg='green'))

            return 0

        time.sleep(1)

        segundos_transcurridos += 1

def get_running_servers(docker_path, docker_image):
    shellcmd = '{docker_path} ps --no-trunc --format "{{{{.Names}}}}\t{{{{.Ports}}}}\t{{{{.Mounts}}}}" --filter ancestor={docker_image}'.format(
        docker_path=docker_path,
        docker_image=docker_image
    )
    p = subprocess.Popen(shlex.split(shellcmd), stdout=subprocess.PIPE)

    contenedores = p.communicate()[0].split('\n')

    container_data = {}

    for contenedor in contenedores:
        if contenedor.strip() == '':
            continue
        data = contenedor.split('\t')
        nombre = data.pop(0)
        if nombre.startswith('apds'):
            container_data[nombre] = data

    return container_data

def detener_contenedor(docker_path, nombre, verbose=True):
    shellcmd = '{docker_path} rm -f {nombre}'.format(
        docker_path=docker_path,
        nombre=nombre
    )
    ejecutar_comando(shellcmd, verbose)

def obtener_estado_contenedor(docker_path, imagen, nombre):
    '''Comprueba si un contenedor ha sido iniciado'''
    contenedores = get_running_servers(docker_path, imagen)
    ha_sido_iniciado = False
    for name in contenedores:
        if name == nombre:
            ha_sido_iniciado = True

    return ha_sido_iniciado

class Config(object):

    def __init__(self):
        cfg = self.get_conf()
        self.port = cfg['default_port']
        self.docker_path = cfg['docker_path']
        self.docker_image = cfg['docker_image']
        self.dir_maps = cfg['dir_maps']
        self.start_cmds = cfg['start_cmds']
        self.start_root_cmds = cfg['start_root_cmds']

    def get_conf(self):
        user_ini_path = os.path.expanduser('~/.config/apds.json')
        if not os.path.isfile(user_ini_path):
            cfg = self.get_default_cfg()
            with open(user_ini_path, 'w') as configfile:
                jsondata = json.dumps(cfg, sort_keys=True,
                    indent=4)
                configfile.write(jsondata)
        else:
            jsondata = open(user_ini_path).read()
            cfg = json.loads(jsondata)

        return cfg

    def get_default_cfg(self):
        cfg = {
            'default_port': '8080',
            'docker_image': 'joanrivera/apds:dev',
            'docker_path': '/usr/bin/docker',
            'dir_maps': [],
            'start_root_cmds': [],
            'start_cmds': [],
        }

        return cfg

pass_config = click.make_pass_decorator(Config, ensure=True)

@click.group()
@click.option('--port', '-p', type=click.INT,
        help='Puerto usado por el servidor')
@pass_config
def cli(config, port):
    '''Apache+PHP Development Server'''
    if port:
        config.port = port

###########
#  Start  #
###########

@click.command()
@click.option(
        '--document-root', '-d',
        type=click.Path(exists=True, file_okay=False),
        default='.',
        help='Directorio donde se encuentran los ficheros que van a ser servidos'
)
@click.option(
        '--server-droot', '-sdr',
        type=click.Path(exists=True, file_okay=False),
        default='.',
        help='Subdirectorio que va a cumplir la función de raíz del sitio web'
)
@pass_config
def start(config, document_root, server_droot):
    '''Inicia el servidor'''

    iniciado = obtener_estado_contenedor(
        config.docker_path, config.docker_image, 'apds'+str(config.port)
    )

    if iniciado:
        click.echo(click.style('Falló. ', fg='red'), nl=False)
        click.echo(
            'Ya hay un servidor ejecutándose en el puerto {}'.format(config.port)
        )
        exit(1)
    else:
        # Puede ser que hayan restos de servidores que han sido detenidos de
        # forma anormal, por lo que se intentan eliminar explícitamente
        detener_contenedor(config.docker_path, 'apds'+str(config.port), False)

    dir_maps_string = ' '.join(['-v \'{}\''.format(map) for map in config.dir_maps])
    click.echo('Iniciando servidor en puerto %s' % config.port, nl=False)
    droot_expanded = os.path.abspath(os.path.expanduser(document_root))
    shellcmd = '{docker_path} run -d -p {port}:80 -e DOCKER_USER="{username}" -e SERVER_DROOT="{server_droot}" -v {document_root}:/var/www/html {dir_maps} --name=apds{port} --hostname=apds {docker_image}'.format(
        docker_path=config.docker_path,
        port=config.port,
        dir_maps=dir_maps_string,
        document_root=droot_expanded,
        docker_image=config.docker_image,
        username=getpass.getuser(),
        server_droot=server_droot
    )
    ejecutar_comando(shellcmd)

    for cmd in config.start_cmds:
        run_in_container(config, True, cmd)

    for cmd in config.start_root_cmds:
        run_in_container(config, True, cmd)

##########
#  Stop  #
##########

@click.command()
@pass_config
def stop(config):
    '''Detiene el servidor'''
    nombre_contenedor = 'apds'+str(config.port)
    iniciado = obtener_estado_contenedor(
        config.docker_path, config.docker_image, nombre_contenedor
    )
    if not iniciado:
        click.echo(click.style('Falló. ', fg='red'), nl=False)
        click.echo(
            'No hay un servidor usando el puerto {}'.format(config.port)
        )
        exit(1)
    click.echo('Deteniendo servidor', nl=False)
    detener_contenedor(config.docker_path, nombre_contenedor)

#############
#  Restart  #
#############

@click.command()
@pass_config
def restart(config):
    '''Reinicia el servidor'''

    iniciado = obtener_estado_contenedor(
        config.docker_path, config.docker_image, 'apds'+str(config.port)
    )

    if not iniciado:
        click.echo(click.style('Falló. ', fg='red'), nl=False)
        click.echo(
            'No hay un servidor ejecutándose en el puerto {}'.format(config.port)
        )
        exit(1)

    click.echo('Reiniciando servidor', nl=False)
    shellcmd = '{docker_path} restart apds{port}'.format(
        docker_path=config.docker_path,
        port=config.port
    )
    ejecutar_comando(shellcmd)

#########
#  Run  #
#########

@click.command()
@click.option('--root', is_flag=True,
        help=u'Ejecuta los comandos como root')
@click.argument('comando', nargs=1)
@pass_config
def run(config, root, comando):
    '''Ejecuta un comando que esté disponible dentro del contenedor del servidor'''
    click.echo('Ejecutando: %s' % comando)
    run_in_container(config, root, comando)

def run_in_container(config, root, comando):
    comando='bash -c \'{}\''.format(comando)
    username = 'root'
    if not root:
        username = getpass.getuser()
    shellcmd = '{docker_path} exec -it -u={username} apds{port} {comando}'.format(
        docker_path=config.docker_path,
        port=config.port,
        comando=comando,
        username=username
    )
    subprocess.call(shlex.split(shellcmd))

##########
#  Logs  #
##########

@click.command()
@click.option('--follow', '-f', is_flag=True,
        help=u'Muestra las novedades del log según vayan apareciendo')
@click.option('--clear', is_flag=True,
        help=u'Elimina los contenidos del archivo de logs')
@click.option('--no-color', is_flag=True,
        help=u'Muestra los logs sin colores')
@pass_config
def logs(config, follow, clear, no_color):
    '''Muestra el log de errores de PHP'''
    log_path = '/var/log/apache2/error.log'
    if clear:
        comando = 'bash -c "echo \'\' > {}"'.format(log_path)
        shellcmd = '{docker_path} exec -it apds{port} {comando}'.format(
            docker_path=config.docker_path,
            port=config.port,
            comando=comando
        )
        subprocess.call(shellcmd, shell=True)
    else:
        follow = '-f' if follow == True else ''
        colorizer = 'cat' if no_color == True else 'log-colorizer'
        comando = 'bash -c "tail {} {} | {}"'.format(
            follow, log_path, colorizer
        )
        shellcmd = '{docker_path} exec -it apds{port} {comando}'.format(
            docker_path=config.docker_path,
            port=config.port,
            comando=comando
        )
        subprocess.call(shlex.split(shellcmd))

##########
#  List  #
##########

@click.command()
@pass_config
def list_servers(config):
    '''Lista los servidores en ejecución'''
    contenedores = get_running_servers(config.docker_path, config.docker_image)
    if len(contenedores) > 0:
        click.echo('{:10}{}'.format('PUERTO', 'DIRECTORIO'))
    else:
        click.echo(u'No hay servidores en ejecución')
    for nombre in contenedores.keys():
        puertos, directorios = contenedores[nombre]
        if nombre.startswith('apds'):
            puertos = puertos.split(',')
            puerto_apds = ''
            for puerto in puertos:
                puerto = puerto.strip()
                if puerto.endswith('->80/tcp'):
                    puerto = puerto.split('->80/tcp')[0]
                    puerto_apds = puerto.split(':')[1]
            click.echo('{:10}{}'.format(puerto_apds, directorios))

cli.add_command(start)
cli.add_command(stop)
cli.add_command(restart)

cli.add_command(run)
cli.add_command(logs)
cli.add_command(list_servers, 'list')


import matplotlib.pyplot as plt
import numpy as np

def f(x,y):
    # 计算高度值
    return (1 - x/2 + x**5 + y**3) * np.exp(-x**2 - y**2)

n = 256
x = np.linspace(-3,3,n)
y = np.linspace(-3,3,n)

# 绑定网格的输入值np.meshgrid()
X,Y=np.meshgrid(x,y)

# 使用plt.contourf()把对应颜色放到等高线中
plt.contourf(X,Y,f(X,Y),8,alpha=0.75,cmap=plt.cm.hot)

# 使用plt.contour()绘制等高线，分为8+2部分
C = plt.contour(X,Y,f(X,Y),8,colors='black')

# 在等高线中添加标签
plt.clabel(C,inline=True,fontsize=10)

# 隐藏x轴和y轴角标
plt.xticks(())
plt.yticks(())
plt.show()