# -*- coding: utf-8 -*-
"""This module contains custom widgets (composite panels) to be used in the main application frame."""

import wx
import wx.lib.scrolledpanel as scrolled
from math import ceil

import dialog

import config
import fn_path
import fn_gfx

class CompositeGallery(wx.Panel):
    """Custom widget that overlays an "add image" button on top of the WidgetGallery custom widget

        Class Variables:
            btn_size (int): Size of the "add image" button in the overlay

        Args:
            parent (ref): Reference to the parent wx.object
            root (ref): Reference to the root parts tab

        Attributes:
            parent (ref): Reference to the parent wx.object
            root (ref): Reference to the root parts tab
    """

    btn_size = 25

    def __init__(self, parent, root):
        """Constructor"""
        wx.Panel.__init__(self, parent)

        self.parent = parent
        self.root = root

        # Button overlay and binding
        self.btn_add_image = wx.BitmapButton(self,
                                             bitmap=wx.Bitmap(fn_path.concat_gui('plus.png')),
                                             size=(CompositeGallery.btn_size,) * 2)

        # Image gallery subwidget
        self.pnl_gallery = WidgetGallery(self, self.root)

        # Button overlay binding - Must be after subwidget to bind to
        self.btn_add_image.Bind(wx.EVT_BUTTON, self.pnl_gallery.evt_add_image)
        self.btn_add_image.Bind(wx.EVT_SET_FOCUS, self.evt_btn_no_focus)

        # Main sizer - do not add button so it floats
        szr_main = wx.BoxSizer(wx.VERTICAL)
        szr_main.Add(self.pnl_gallery, proportion=1, flag=wx.EXPAND)
        self.SetSizer(szr_main)

        # Bind button movement to resize
        self.Bind(wx.EVT_SIZE, self.evt_resize)

    def evt_resize(self, event):
        """Move the button overlay when resized

            Args:
                event: A resize event object passed from the resize event
        """

        # Get width and height of the resize and subtract a tuple representing the scrollbar size
        (_w, _h) = event.GetSize() - (16, 0)

        # Move the button that adds more images
        self.btn_add_image.SetPosition((_w - CompositeGallery.btn_size, _h - CompositeGallery.btn_size))

        # Refresh Layout required for unknown reasons - otherwise odd scale behaviour on pnl_gallery
        self.Layout()

    def evt_btn_no_focus(self, event):
        """Prevents focus from being called on the buttons

            Args:
                event: A focus event
        """
        pass

class WidgetGallery(scrolled.ScrolledPanel):
    """Custom scrolled widget to contain a gallery of photos associated with the part of the parent tab

        Class Variables:
            icon_gap (int): Spacing between adjacent icons in sizer
            icon_size (int): Square size intended for the icon for each image

        Args:
            parent (ref): Reference to the parent wx.object
            root (ref): Reference to the root parts tab

        Attributes:
            parent (ref): Reference to the parent wx.object
            root (ref): Reference to the root parts tab
    """

    icon_gap = 5
    icon_size = 120

    def __init__(self, parent, root):
        """Constructor"""
        super().__init__(parent, style=wx.BORDER_SIMPLE)

        # Variables
        self.parent = parent
        self.root = root

        # Load list of images from database and store the image filenames with extensions
        conn = config.sql_db.connect(config.cfg["db_location"])
        crsr = conn.cursor()
        crsr.execute("SELECT image FROM Images WHERE part_num=(?) AND part_rev=(?);",
                     (self.root.part_num, self.root.part_rev))
        self.image_list = [i[0] for i in crsr.fetchall()]
        conn.close()

        # Create list of raw images
        self.images = [fn_path.concat_img(self.root.part_num, img) for img in self.image_list]

        # Create a grid sizer to contain image icons
        self.nrows, self.ncols = 1, len(self.images)
        self.img_object_list = []
        self.sizer_grid = wx.GridSizer(rows=self.nrows + 1,
                                       cols=self.ncols,
                                       hgap=WidgetGallery.icon_gap,
                                       vgap=WidgetGallery.icon_gap)

        # Add cropped and scaled image icons to the grid sizer
        for r in range(self.nrows):
            for c in range(self.ncols):
                _n = self.ncols * r + c
                _tmp = fn_gfx.crop_square(wx.Image(self.images[_n]), WidgetGallery.icon_size)
                _temp = wx.StaticBitmap(self, bitmap=wx.Bitmap(_tmp))
                _temp.Bind(wx.EVT_LEFT_UP, self.evt_image_click)
                self.img_object_list.append(_temp)
                self.sizer_grid.Add(_temp, wx.EXPAND)

        # Main sizer
        szr_main = wx.BoxSizer(wx.VERTICAL)
        szr_main.Add(self.sizer_grid)
        self.SetSizer(szr_main)

        # Setup the scrolling style and function, wanting only vertical scroll to be available
        self.SetAutoLayout(1)
        self.SetupScrolling()
        self.ShowScrollbars(wx.SHOW_SB_NEVER, wx.SHOW_SB_ALWAYS)
        self.SetWindowStyle(wx.VSCROLL)

        # Bind button movement to resize
        self.Bind(wx.EVT_SIZE, self.evt_resize)

        # Bind layout recalculation to scrolling
        self.Bind(wx.EVT_SCROLLWIN, self.evt_scroll)

    def evt_image_click(self, event):
        """Call up the dialog for when an image is clicked

            Args:
                event: The triggering click event object
        """

        # Load the "image clicked" dialog
        _dlg = dialog.EditImage(self, self.root, self.img_object_list.index(event.GetEventObject()))
        _dlg.ShowModal()
        if _dlg: _dlg.Destroy()

    def evt_add_image(self, event):
        """Call up dialogs to add an image to the database

            Args:
                event: A button event object passed from the button click
        """

        # Open an explorer dialog to select images to import
        with wx.FileDialog(None, "Open",
                           wildcard="Images (*.png;*.jpg;*.bmp;*.gif)|*.png;*.jpg;*.jpeg;*.bmp;*.gif|"
                                    "PNG (*.png)|*.png|"
                                    "JPEG (*.jpg)|*.jpg;*.jpeg|"
                                    "BMP (*.bmp)|*.bmp|"
                                    "GIF (*.gif)|*.gif",
                           style=wx.FD_MULTIPLE | wx.FD_FILE_MUST_EXIST) as file_dialog:

            # Check if the user changed their mind about importing
            if file_dialog.ShowModal() == wx.ID_CANCEL:
                return

            # Make a list of chosen images to add to the database
            selected_files = file_dialog.GetPaths()

        # Proceed loading the file(s) chosen by the user to the "add image" dialog
        _dlg = dialog.AddImage(self, self.root, selected_files)
        _dlg.ShowModal()
        if _dlg: _dlg.Destroy()

    def evt_resize(self, event):
        """Resize the image grid

        Retrieves width and height of the grid panel and adds/removes grid columns/rows to fit panel nicely.

            Args:
                event: A resize event object passed from the resize event
        """

        # Get width and height of the resize
        (_w, _h) = event.GetSize()

        # Calculate the number of columns that fit in the scrolled panel, force a minimum of 1 columns
        _c = max((_w - WidgetGallery.icon_gap) // (WidgetGallery.icon_size + WidgetGallery.icon_gap), 1)

        # Redistribute rows and columns for the grid
        self.sizer_grid.SetCols(_c)
        self.sizer_grid.SetRows(ceil(len(self.image_list)/_c))

    def evt_scroll(self, event):
        """Adds forced recalculation of layout on scroll - as default repainting of frames does not work here

            Args:
                event: Scroll event
        """

        wx.CallAfter(self.Layout)
        event.Skip()

class CompositeNotes(wx.Panel):
    """Custom widget that overlays an "add note" button on top of the WidgetNotes custom widget as well as
    governs the column header behavior

        Class Variables:
            btn_size (int): Size of the "add image" button in the overlay
            col_min (list: int): List of minimum column widths for the column headers

        Args:
            parent (ref): Reference to the parent wx.object
            root (ref): Reference to the root parts tab

        Attributes:
            parent (ref): Reference to the parent wx.object
            root (ref): Reference to the root parts tab
    """

    btn_size = 25
    col_min = [25, 40, -1]

    def __init__(self, parent, root):
        """Constructor"""
        wx.Panel.__init__(self, parent)

        self.parent = parent
        self.root = root

        # List of text objects in the header
        self.header_list = []

        # Draw button first, as the first object drawn stays on top
        self.btn_add_note = wx.BitmapButton(self,
                                            bitmap=wx.Bitmap(fn_path.concat_gui('plus.png')),
                                            size=(CompositeNotes.btn_size,) * 2)

        # Set up sizer to contain header and scrolled notes
        self.pnl_notes = NotesScrolled(self, self.root)

        # Button overlay binding - Must be after subwidget to bind to
        self.btn_add_note.Bind(wx.EVT_BUTTON, self.pnl_notes.evt_add_note)
        self.btn_add_note.Bind(wx.EVT_SET_FOCUS, self.evt_button_no_focus)

        # Binding for clicking between notes text
        self.pnl_notes.Bind(wx.EVT_LEFT_UP, self.evt_edit_note)

        # Main Sizer
        self.szr_title = wx.BoxSizer(wx.HORIZONTAL)
        self.szr_main = wx.BoxSizer(wx.VERTICAL)
        self.szr_main.Add(self.szr_title, flag=wx.ALL | wx.EXPAND)
        self.szr_main.Add(self.pnl_notes, proportion=1, flag=wx.ALL | wx.EXPAND)

        self.header_list.append(
            wx.StaticText(self,
                          label="Date", style=wx.ALIGN_LEFT))
        self.header_list.append(
            wx.StaticText(self,
                          label="Author", style=wx.ALIGN_LEFT))
        self.header_list.append(wx.StaticText(self, label="Note", style=wx.ALIGN_LEFT))

        self.szr_title.Add(self.header_list[0])
        self.szr_title.Add(self.header_list[1])
        self.szr_title.Add(self.header_list[2], proportion=1)
        #self.szr_title.Add(self.header_list[3])

        # Refresh headers, repopulating self.sizer_title
        self.refresh_headers()

        # Set sizer and resize
        self.SetSizer(self.szr_main)
        self.Layout()

        # Bind button movement to resize
        self.Bind(wx.EVT_SIZE, self.evt_resize)

    def refresh_headers(self):
        """Refresh the column headers to reflect the column widths in the lower scrolled sizer"""

        # Append three 0s in case the notes list is empty. Only the first 3 entries are observed
        column_widths = [*self.pnl_notes.szr_grid.GetColWidths(), 0, 0, 0][:3]

        # Change the size of the first two column headers
        self.header_list[0].SetMinSize((max(column_widths[0], CompositeNotes.col_min[0]) + NotesScrolled.col_gap, -1))
        self.header_list[1].SetMinSize((max(column_widths[1], CompositeNotes.col_min[1]) + NotesScrolled.col_gap, -1))

        # Ensure headers resize properly
        self.Layout()

    def evt_edit_note(self, event):
        """Determine where in the scrolled panel was clicked and pass that to the method handling the dialog

            Args:
                event: A resize event object passed from the click event
        """

        # Mouse positions within the overall panel, corrected for scroll. The math signage is odd, but works out
        pos_panel = self.pnl_notes.ScreenToClient(wx.GetMousePosition())[1]
        pos_scroll = -self.pnl_notes.CalcScrolledPosition(0, 0)[1]

        # Call method from the panel itself to handle dialog popup
        self.pnl_notes.edit_notes((pos_panel + pos_scroll) // 20)

    def evt_resize(self, event):
        """Move the button overlay when resized

            Args:
                event: A resize event object passed from the resize event
        """

        # Get width and height of the resize and subtract a tuple representing the scrollbar size
        (_w, _h) = event.GetSize() - (16, 0)

        # Move the button that adds more images
        self.btn_add_note.SetPosition((_w - CompositeNotes.btn_size, _h - CompositeNotes.btn_size))

        # Refresh Layout required for unknown reasons - otherwise odd scale behaviour on pnl_gallery
        self.Layout()

    def evt_button_no_focus(self, event):
        """Prevents focus from being called on the buttons

            Args:
                event: A focus event
        """
        pass

class NotesScrolled(scrolled.ScrolledPanel):
    """Custom scrolled widget to contain notes associated with the part of the parent tab

        Class Variables:
            row_gap (int): Vertical spacing between rows in grid
            col_gap (int): Horizontal spacing between columns in grid

        Args:
            parent (ref): Reference to the parent wx.object
            root (ref): Reference to the root parts tab

        Attributes:
            parent (ref): Reference to the parent wx.object
            root (ref): Reference to the root parts tab
    """

    row_gap = 5
    col_gap = 15

    def __init__(self, parent, root):
        """Constructor"""
        super().__init__(parent, style=wx.ALL | wx.VSCROLL)

        self.parent = parent
        self.root = root

        # List of current notes items in widget; each entry is a list of three wx.objects
        self.notes_list = []

        # Sizer to hold notes entries - Also set as main sizer
        self.szr_grid = wx.FlexGridSizer(3, NotesScrolled.row_gap, NotesScrolled.col_gap)
        self.szr_grid.AddGrowableCol(2)
        self.szr_grid.SetFlexibleDirection(wx.HORIZONTAL)
        self.szr_grid.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_NONE)
        self.SetSizer(self.szr_grid)

        # Load notes into the provided grid sizer
        self.load_notes()

        # Setup the scrolling style and function, wanting only vertical scroll to be available
        self.SetupScrolling()
        self.ShowScrollbars(wx.SHOW_SB_NEVER, wx.SHOW_SB_ALWAYS)
        self.SetWindowStyle(wx.VSCROLL)

        # Not clear as to why this is needed, but without it the scrollbar is missing in some circumstances
        self.SetScrollbars(10, 10, 10, 10)

        # Bind layout recalculation to scrolling
        self.Bind(wx.EVT_SCROLLWIN, self.evt_scroll)

    def load_notes(self):
        """Open SQL database and load notes from table"""

        # Load notes from database
        conn = config.sql_db.connect(config.cfg["db_location"])
        crsr = conn.cursor()
        crsr.execute("SELECT date, author, note FROM Notes WHERE part_num=(?) AND part_rev=(?)",
                     (self.root.part_num, self.root.part_rev))
        _tmp_list = crsr.fetchall()
        conn.close()

        # Sort and remove non-date information from the datetime string
        if _tmp_list:
            _tmp_list = [(a[0][:10],)+a[1:] for a in sorted(_tmp_list, key=lambda x: x[0])]

        # Add the notes to the grid
        for i, note_args in enumerate(_tmp_list):
            self.add_note(*note_args, i)

    def evt_add_note(self, event):
        """Event to trigger the addition of entries to the notes widget

            Args:
                event: A button event object passed from the button click
        """

        _dlg = dialog.AddNote(self, self.root)
        _dlg.ShowModal()
        if _dlg: _dlg.Destroy()

    def add_note(self, timestamp, user, note, id_set=0):
        """Add an entry to the notes widget

            Args:
                self: A reference to the parent wx.object instance
                user: The username that has added the note
                timestamp: The timestamp for when the note was added
                note: The text for the note to be added
        """

        # List of wx.objects to add to the notes widget
        _tmp_item = [wx.StaticText(self, id=id_set, label=timestamp, style=wx.EXPAND),
                     wx.StaticText(self, size=(40, -1), id=id_set, label=user, style=wx.EXPAND),
                     wx.StaticText(self, size=(50, -1), id=id_set, label=note, style=wx.ST_ELLIPSIZE_END)]

        # Binding for the items in the notes widget
        for item in _tmp_item:
            item.Bind(wx.EVT_LEFT_UP, self.evt_edit_notes_trigger)
            self.szr_grid.Add(item, flag=wx.ALL | wx.EXPAND)

        self.notes_list.append(_tmp_item)

        # Refresh both layouts so the scrollbar resets
        self.Layout()
        self.parent.Layout()

    def evt_edit_notes_trigger(self, event):
        """Determine which entry in the scrolled panel was clicked and pass that to the method handling the dialog

            Args:
                event: Click event that triggered this function
        """

        pass
        self.edit_notes(event.GetEventObject().GetId())

    def edit_notes(self, my_index):
        """Method to edit an existing note, based on the provided index in the list

            Args:
                my_index (int): Index for the notes entry you want to edit
        """

        pass
        print(self.notes_list[my_index][0].GetLabel(), self.notes_list[my_index][1].GetLabel(), self.notes_list[my_index][2].GetLabel())
        #dialog = ImageDialog(self.image_list, event.GetEventObject().GetId(), self.parent.part_num, self.parent.part_rev)
        #dialog.ShowModal()
        #dialog.Destroy()

    def evt_scroll(self, event):
        """Adds forced recalculation of layout on scroll - as default repainting of frames does not work here

            Args:
                event: Scroll event
        """

        wx.CallAfter(self.Layout)
        event.Skip()

class CompositeMugshot(wx.Panel):
    """Custom widget that overlays a "show schematic" button on top of the Mugshot widget

            Class Variables:
                mug_size (int): The size of the mugshot photo
                btn_size (int): Size of the "show schematic" button in the overlay

            Args:
                parent (ref): Reference to the parent wx.object
                root (ref): Reference to the root parts tab

            Attributes:
                parent (ref): Reference to the parent wx.object
                root (ref): Reference to the root parts tab
    """

    mug_size = 250
    btn_size = 40

    def __init__(self, parent, root):
        """Constructor"""
        wx.Panel.__init__(self, parent)

        self.parent = parent
        self.root = root

        # Primary part image
        if self.parent.mugshot:
            image = wx.Image(fn_path.concat_img(self.parent.part_num, self.parent.mugshot), wx.BITMAP_TYPE_ANY)
        else:
            image = wx.Image(fn_path.concat_gui('missing_mugshot.png'), wx.BITMAP_TYPE_ANY)

        # Draw button first as first drawn stays on top
        self.button_dwg = wx.BitmapButton(self,
                                          bitmap=wx.Bitmap(fn_path.concat_gui('schematic.png')),
                                          size=(CompositeMugshot.btn_size,) * 2,
                                          pos=(0, CompositeMugshot.mug_size - CompositeMugshot.btn_size))
        self.button_dwg.Bind(wx.EVT_SET_FOCUS, self.event_button_no_focus)
        self.button_dwg.Bind(wx.EVT_BUTTON, self.evt_blueprint)

        self.imageBitmap = wx.StaticBitmap(self, bitmap=wx.Bitmap(fn_gfx.crop_square(image, CompositeMugshot.mug_size)))

        self.sizer_main = wx.BoxSizer(wx.HORIZONTAL)
        self.sizer_main.Add(self.imageBitmap, flag=wx.ALL)

        self.SetSizer(self.sizer_main)
        self.Layout()
        self.Fit()

    def refresh(self, new_image=None):
        """Updates the mugshot to the image hash provided, directs to the no-image if None is provided

            Args:
                new_image (str): Image filename for mugshot to display
        """
        if new_image:
            temp = fn_path.concat_img(self.parent.part_num, new_image)
        else:
            temp = fn_path.concat_gui('missing_mugshot.png')

        # Update image
        self.imageBitmap.SetBitmap(wx.Bitmap(fn_gfx.crop_square(wx.Image(temp), CompositeMugshot.mug_size)))

    def evt_blueprint(self, event):
        """Loads a dialog or opens a program (unsure) showing the production drawing of said part

            Args:
                event: Button click event
        """

        _dlg = wx.RichMessageDialog(self,
                                   caption="This feature is not yet implemented",
                                   message="This feature will load a production drawing of the current part",
                                   style=wx.OK | wx.ICON_INFORMATION)
        _dlg.ShowModal()
        _dlg.Destroy()

    def event_button_no_focus(self, event):
        """Prevents focus from being called on the buttons

            Args:
                event: A focus event
        """
        pass

class CompositeAssemblies(wx.Panel):
    """Custom scrolled widget to contain sub-assembly and super-assembly data associated with the part of the parent tab

            Class Variables:
                btn_size (int): Size of the "add image" button in the overlay

            Args:
                parent (ref): Reference to the parent wx.object
                root (ref): Reference to the root parts tab

            Attributes:
                parent (ref): Reference to the parent wx.object
                root (ref): Reference to the root parts tab
    """

    btn_size = 25

    def __init__(self, parent, root):
        """Constructor"""
        wx.Panel.__init__(self, parent)

        self.parent = parent
        self.root = root

        # Draw Sub-Assembly edit button
        self.btn_sub_edit = wx.BitmapButton(self,
                                            bitmap=wx.Bitmap(fn_path.concat_gui('edit.png')),
                                            size=(CompositeAssemblies.btn_size,) * 2)
        self.btn_sub_edit.Bind(wx.EVT_SET_FOCUS, self.evt_button_no_focus)
        self.btn_sub_edit.Bind(wx.EVT_BUTTON, self.evt_sub_edit)

        # Draw Sub-Assembly help button
        self.btn_sub_help = wx.StaticBitmap(self, bitmap=wx.Bitmap(fn_path.concat_gui('help.png')))
        self.btn_sub_help.Bind(wx.EVT_LEFT_UP, self.evt_sub_help)

        # Draw Super-Assembly edit button
        self.btn_super_edit = wx.BitmapButton(self,
                                              bitmap=wx.Bitmap(fn_path.concat_gui('edit.png')),
                                              size=(CompositeAssemblies.btn_size,) * 2)
        self.btn_super_edit.Bind(wx.EVT_SET_FOCUS, self.evt_button_no_focus)
        self.btn_super_edit.Bind(wx.EVT_BUTTON, self.evt_super_edit)

        # Draw Super-Assembly help button
        self.btn_super_help = wx.StaticBitmap(self, bitmap=wx.Bitmap(fn_path.concat_gui('help.png')))
        self.btn_super_help.Bind(wx.EVT_LEFT_UP, self.evt_super_help)

        # Lists containing sub and super assembly info
        self.wgt_sub_assm = wx.ListBox(self,
                                       choices=[i[0] + " r" + i[1] for i in self.root.helper_wgt_sub],
                                       size=(CompositeMugshot.mug_size//2, -1), style=wx.LB_SINGLE | wx.LB_ALWAYS_SB)
        self.wgt_super_assm = wx.ListBox(self,
                                         choices=[i[0] + " r" + i[1] for i in self.root.helper_wgt_super],
                                         size=(CompositeMugshot.mug_size//2, -1), style=wx.LB_SINGLE | wx.LB_ALWAYS_SB)

        # Assembly list binds
        self.wgt_sub_assm.Bind(wx.EVT_LISTBOX, self.evt_click_sub_assm)
        self.wgt_sub_assm.Bind(wx.EVT_MOTION, self.evt_update_tooltip_sub)
        self.wgt_super_assm.Bind(wx.EVT_LISTBOX, self.evt_click_super_assm)
        self.wgt_super_assm.Bind(wx.EVT_MOTION, self.evt_update_tooltip_super)

        # Assembly and Main Sizers
        self.szr_sub_assm = wx.BoxSizer(wx.VERTICAL)
        self.szr_sub_assm.Add(wx.StaticText(self, label="Sub-Assemblies", style=wx.ALIGN_CENTER), border=5,
                              flag=wx.ALL | wx.EXPAND)
        self.szr_sub_assm.Add(self.wgt_sub_assm, proportion=1, flag=wx.ALL | wx.EXPAND)
        self.szr_super_assm = wx.BoxSizer(wx.VERTICAL)
        self.szr_super_assm.Add(wx.StaticText(self, label="Super-Assemblies", style=wx.ALIGN_CENTER), border=5,
                                flag=wx.ALL | wx.EXPAND)
        self.szr_super_assm.Add(self.wgt_super_assm, proportion=1, flag=wx.ALL | wx.EXPAND)
        self.szr_main = wx.BoxSizer(wx.HORIZONTAL)
        self.szr_main.Add(self.szr_sub_assm, proportion=1, flag=wx.ALL | wx.EXPAND)
        self.szr_main.Add(self.szr_super_assm, proportion=1, flag=wx.ALL | wx.EXPAND)

        # Set main sizer and recalculate the layout
        self.SetSizer(self.szr_main)
        self.Layout()

        # Bind button movement to resize
        self.Bind(wx.EVT_SIZE, self.evt_resize)

    def evt_click_sub_assm(self, event):
        """Open a parts tab based on what entry has been clicked

            Args:
                event: A list box click event object passed from the list box when activated
        """

        # Get the index of the clicked item, and open a new parts tab, based on part_num and part_rev
        _index = event.GetSelection()
        self.root.parent.open_parts_tab(*self.root.helper_wgt_sub[_index], wx.GetKeyState(wx.WXK_SHIFT))

        # Deselect the clicked entry of the list box
        event.GetEventObject().SetSelection(wx.NOT_FOUND)

    def evt_click_super_assm(self, event):
        """Open a parts tab based on what entry has been clicked

            Args:
                event: A list box click event object passed from the list box when activated
        """

        # Get the index of the clicked item, and open a new parts tab, based on part_num and part_rev
        _index = event.GetSelection()
        self.root.parent.open_parts_tab(*self.root.helper_wgt_super[_index], wx.GetKeyState(wx.WXK_SHIFT))

        # Deselect the clicked entry of the list box
        event.GetEventObject().SetSelection(wx.NOT_FOUND)

    def evt_update_tooltip_sub(self, event):
        """Update the tooltip with the name of the sub-assembly entry the mouse is over

            Args:
                event: A mouse movement event object passed from the movement event
        """

        # Calculate the index of the item that is under the mouse pointer
        _item_index = self.wgt_sub_assm.HitTest(event.GetPosition())

        # As long as we have a valid index then update the tooltip, otherwise empty it
        if _item_index != -1:
            _num, _rev = self.root.helper_wgt_sub[_item_index]
            _new_msg = self.root.data_wgt_sub[_num][_rev]
            if self.wgt_sub_assm.GetToolTipText() != _new_msg:
                self.wgt_sub_assm.SetToolTip(_new_msg)
        else:
            self.wgt_sub_assm.SetToolTip("")

    def evt_update_tooltip_super(self, event):
        """Update the tooltip with the name of the super-assembly entry the mouse is over

            Args:
                event: A mouse movement event object passed from the movement event
        """

        # Calculate the index of the item that is under the mouse pointer
        _item_index = self.wgt_super_assm.HitTest(event.GetPosition())

        # As long as we have a valid index then update the tooltip, otherwise empty it
        if _item_index != -1:
            _num, _rev = self.root.helper_wgt_super[_item_index]
            _new_msg = self.root.data_wgt_super[_num][_rev]
            if self.wgt_super_assm.GetToolTipText() != _new_msg:
                self.wgt_super_assm.SetToolTip(_new_msg)
        else:
            self.wgt_super_assm.SetToolTip("")

    def evt_sub_edit(self, event):
        """Show the edit dialog for sub-assemblies

            Args:
                event: A button event object passed from the button click
        """

        _dlg = dialog.EditSubAssemblies(self, self.root)
        _dlg.ShowModal()
        if _dlg: _dlg.Destroy()

    def evt_super_edit(self, event):
        """Show the edit dialog for super-assemblies

            Args:
                event: A button event object passed from the button click
        """

        _dlg = dialog.EditSuperAssemblies(self, self.root)
        _dlg.ShowModal()
        if _dlg: _dlg.Destroy()

    def evt_sub_help(self, event):
        """Show the term definition for sub-assembly

            Args:
                event: A click event object passed from the click event
        """

        _dlg = wx.RichMessageDialog(self,
                                    caption="Help: Term Definition",
                                    message="A sub-assembly in this context refers to components or assemblies that, "
                                            "together, assemble into this part.",
                                    style=wx.OK | wx.ICON_INFORMATION)
        _dlg.ShowModal()
        _dlg.Destroy()

    def evt_super_help(self, event):
        """Show the term definition for super-assembly

            Args:
                event: A click event object passed from the click event
        """

        _dlg = wx.RichMessageDialog(self,
                                    caption="Help: Term Definition",
                                    message="A super-assembly in this context refers to assemblies that contain "
                                            "this part.",
                                    style=wx.OK | wx.ICON_INFORMATION)
        _dlg.ShowModal()
        _dlg.Destroy()

    def evt_resize(self, event):
        """Move the button overlays when re-sized

            Args:
                event: A resize event object passed from the resize event
        """

        _help_shift = 6
        _help_size = 10

        # Get width and height of the resize and subtract a correction tuple
        (_w, _h) = event.GetSize() - (1, 1)

        # Move the buttons that edit the assembly lists, and correct to exclude the scrollbar width (17)
        self.btn_super_edit.SetPosition((_w - CompositeAssemblies.btn_size - 17, _h - CompositeAssemblies.btn_size))
        self.btn_sub_edit.SetPosition((_w // 2 - CompositeAssemblies.btn_size - 17, _h - CompositeAssemblies.btn_size))

        # Move the buttons that display help for the assembly lists
        self.btn_super_help.SetPosition((_w - _help_shift - _help_size // 2,
                                         (self.wgt_sub_assm.GetCharHeight() - _help_size) // 2 + 6))
        self.btn_sub_help.SetPosition((_w // 2 - _help_shift - _help_size // 2,
                                       (self.wgt_sub_assm.GetCharHeight() - _help_size) // 2 + 6))

        # Refresh Layout required for unknown reasons - otherwise odd scale behaviour
        self.Layout()

    def evt_button_no_focus(self, event):
        """Prevents focus from being called on the buttons

            Args:
                event: A focus event
        """
        pass


import pytest

import hat.monitor.common
import hat.monitor.client
import hat.monitor.server.master
import hat.monitor.server.server
from hat.monitor.common import ComponentInfo

from hat.util import aio
from test_unit.test_monitor import common

@pytest.fixture
def server_port(unused_tcp_port_factory):
    return unused_tcp_port_factory()

@pytest.fixture
def server_conf(server_port):
    return {
        'address': f'tcp+sbs://localhost:{server_port}',
        'default_rank': 1}

@pytest.fixture
def client_conf(server_port):
    return {
        'name': 'c1',
        'group': 'g1',
        'monitor_address': f'tcp+sbs://localhost:{server_port}',
        'component_address': None}

@pytest.mark.asyncio
async def test_client_connect_disconnect(server_conf, client_conf):
    components_queue = aio.Queue()
    server = await hat.monitor.server.server.create(server_conf)
    server.register_change_cb(
        lambda: components_queue.put_nowait(server.components))
    client = await hat.monitor.client.connect(client_conf)
    components = await components_queue.get()
    assert len(components) == 1
    c = components[0]
    assert (c.mid == server.mid and
            c.name == client_conf['name'] and
            c.group == client_conf['group'] and
            c.address == client_conf['component_address'] and
            c.rank == server_conf['default_rank'] and
            c.blessing is None and
            c.ready is None)
    await client.async_close()
    assert client.closed.done()
    assert await components_queue.get() == []
    await server.async_close()
    assert server.closed.done()

@pytest.mark.asyncio
async def test_client_set_ready(server_conf, client_conf):
    components_queue = aio.Queue()
    server = await hat.monitor.server.server.create(server_conf)
    server.register_change_cb(
        lambda: components_queue.put_nowait(server.components))
    client = await hat.monitor.client.connect(client_conf)
    assert (await components_queue.get())[0].ready is None
    client.set_ready(5)
    assert (await components_queue.get())[0].ready == 5
    client.set_ready(7)
    assert (await components_queue.get())[0].ready == 7
    client.set_ready(None)
    assert (await components_queue.get())[0].ready is None
    client.set_ready(-3)
    assert (await components_queue.get())[0].ready == -3
    await client.async_close()
    assert client.closed.done()
    await server.async_close()
    assert server.closed.done()

@pytest.mark.asyncio
async def test_server_set_rank(server_conf, client_conf):
    components_queue = aio.Queue()
    server = await hat.monitor.server.server.create(server_conf)
    server.register_change_cb(
        lambda: components_queue.put_nowait(server.components))
    client = await hat.monitor.client.connect(client_conf)
    c = (await components_queue.get())[0]
    assert c.rank == 1
    server.set_rank(c.cid, c.mid, 2)
    assert (await components_queue.get())[0].rank == 2
    server.set_rank(c.cid, c.mid, -11)
    assert (await components_queue.get())[0].rank == -11
    await client.async_close()
    assert client.closed.done()
    await server.async_close()
    assert server.closed.done()

@pytest.mark.asyncio
async def test_server_set_rank_nonexistent(server_conf):
    server = await hat.monitor.server.server.create(server_conf)
    server.set_rank(1, server.mid, 2)
    await server.async_close()
    assert server.closed.done()

@pytest.mark.asyncio
async def test_server_rank_cache(server_conf, client_conf):

    async def client_connect_info_queue():
        info_queue = aio.Queue()
        client = await hat.monitor.client.connect(client_conf)
        client.register_change_cb(lambda: info_queue.put_nowait(client.info))
        return client, info_queue

    async def get_info_until_not_none(info_queue):
        info = None
        while info is None:
            info = await info_queue.get()
        return info

    server = await hat.monitor.server.server.create(server_conf)
    client, info_queue = await client_connect_info_queue()
    info = await get_info_until_not_none(info_queue)
    assert info.rank == 1
    server.set_rank(info.cid, info.mid, 2)
    assert (await info_queue.get()).rank == 2
    await client.async_close()
    assert client.closed.done()

    client, info_queue = await client_connect_info_queue()
    info = await get_info_until_not_none(info_queue)
    assert info.rank == 2

    master = common.create_master(mid=server.mid, components=[
        server.components[0]._replace(rank=3)])

    server.set_master(master)
    assert (await info_queue.get()).rank == 3
    await client.async_close()
    assert client.closed.done()
    server.set_master(None)

    client, info_queue = await client_connect_info_queue()
    info = await get_info_until_not_none(info_queue)
    assert info.rank == 3

    master = common.create_master(mid=server.mid, components=[
        server.components[0]._replace(rank=4)])

    server.set_master(master)
    assert (await info_queue.get()).rank == 4
    master._set_components([i._replace(rank=5) for i in master.components])
    assert (await info_queue.get()).rank == 5
    await client.async_close()
    assert client.closed.done()
    server.set_master(None)

    client, info_queue = await client_connect_info_queue()
    info = await get_info_until_not_none(info_queue)
    assert info.rank == 5
    await client.async_close()
    assert client.closed.done()

@pytest.mark.asyncio
async def test_server_set_master_mid_component(server_conf):
    c1 = ComponentInfo(cid=1, mid=10, name='c1', group='g1', address=None,
                       rank=1, blessing=None, ready=None)
    c2 = ComponentInfo(cid=2, mid=11, name='c2', group='g2', address='1.2.3.4',
                       rank=2, blessing=3, ready=3)
    server_change_queue = aio.Queue()
    server = await hat.monitor.server.server.create(server_conf)
    server.register_change_cb(lambda: server_change_queue.put_nowait((None)))
    assert server.mid == 0 and server.components == []
    master = common.create_master(mid=5, components=[c1, c2])
    server.set_master(master)
    await server_change_queue.get()
    assert server.mid == 5 and server.components == [c1, c2]
    master._set_mid(3)
    await server_change_queue.get()
    assert server.mid == 3 and server.components == [c1, c2]
    master._set_components([c2])
    await server_change_queue.get()
    assert server.mid == 3 and server.components == [c2]
    server.set_master(None)
    await server_change_queue.get()
    assert server.mid == 0 and server.components == []
    await server.async_close()
    assert server.closed.done()

@pytest.mark.asyncio
async def test_server_master_set_rank(server_conf):
    server = await hat.monitor.server.server.create(server_conf)
    master = common.create_master()
    server.set_master(master)
    server.set_rank(1, 0, 10)
    assert (await master._rank_queue.get()) == (1, 0, 10)
    server.set_rank(3, 2, 5)
    assert (await master._rank_queue.get()) == (3, 2, 5)
    await server.async_close()
    assert server.closed.done()

@pytest.mark.asyncio
async def test_client_server_master(server_conf, client_conf):
    c2 = ComponentInfo(cid=2, mid=1, name='c2', group='g2', address='1.2.3.4',
                       rank=2, blessing=3, ready=3)
    client_change_queue = aio.Queue()
    server = await hat.monitor.server.server.create(server_conf)
    client = await hat.monitor.client.connect(client_conf)
    client.register_change_cb(lambda: client_change_queue.put_nowait(None))
    master = common.create_master(mid=1, components=[])

    client_info = None
    while client_info is None:
        await client_change_queue.get()
        client_info = client.info

    server_components = server.components
    server.set_master(master)
    await client_change_queue.get()
    assert client.components == master.components and client.info is None

    local_components = await master._components_queue.get()
    assert (len(local_components) == 1 and
            local_components == [i._replace(mid=master.mid)
                                 for i in server_components])
    c1 = local_components[0]._replace(mid=1, rank=7)
    master._set_components([c1, c2])
    assert server.components == master.components
    await client_change_queue.get()
    assert client.components == master.components and client.info == c1

    client.set_ready(12)
    local_components = await master._components_queue.get()
    assert len(local_components) == 1 and local_components[0].ready == 12
    c1 = local_components[0]._replace(mid=1, ready=12, blessing=34)
    master._set_components([c1, c2])
    assert server.components == master.components
    await client_change_queue.get()
    assert client.info == c1 and client.components == master.components

    master._set_mid(2)
    await client_change_queue.get()
    assert client.info.mid == 2

    server.set_master(None)
    await client_change_queue.get()
    assert client.info.mid == 0 and client.components == [client.info]

    await client.async_close()
    assert client.closed.done()
    await server.async_close()
    assert server.closed.done()


#!/usr/bin/env python
from setuptools import setup, find_packages

install_requires = ["Django>=2.2", "psycopg2-binary"]

extras_require = {
    "dev": ["pytest>=3.6", "pytest-cov", "pytest-django", "coveralls", "flake8"]
}

setup(
    name="opencivicdata",
    version="3.2.0",
    author="James Turk",
    author_email="james@openstates.org",
    license="BSD",
    description="python opencivicdata library",
    long_description="",
    url="",
    packages=find_packages(),
    include_package_data=True,
    install_requires=install_requires,
    extras_require=extras_require,
    platforms=["any"],
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: BSD License",
        "Natural Language :: English",
        "Operating System :: OS Independent",
        "Programming Language :: Python :: 3.6",
        "Programming Language :: Python :: 3.7",
        "Programming Language :: Python :: 3.8",
    ],
)


from flask import Flask, request
from flask_restful import Resource, Api, reqparse
from flask_cors import CORS

app = Flask(__name__)
CORS(app, origins='*')
api = Api(app)

ENVELOPES = []

class Envelope(Resource):
    def get(self, envelope_name):
        return [x for x in ENVELOPES if x["name"] == envelope_name][0]

    def put(self, envelope_name):
        ENVELOPES.append({
            'name': envelope_name,
            'amount': request.get_json()['amount']
        })
        return ENVELOPES[-1]

class EnvelopeList(Resource):
    def get(self):
        return ENVELOPES

api.add_resource(EnvelopeList, '/envelopes')
api.add_resource(Envelope, '/<string:envelope_name>')

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


import string
import nltk
from spacy.lang.en import English
from nltk.corpus import stopwords
from nltk.stem import SnowballStemmer
import re

nltk.download('stopwords')

def tokenize_preprocess_corpus(reports):
    '''This function uses spacy tokenizer'''

    nlp = English()
    # Create a Tokenizer with the default settings for English
    # including punctuation rules and exceptions
    tokenizer = nlp.Defaults.create_tokenizer(nlp)

    # this will be a nested list of tokens [['word1', 'word2',...], [...], [...], ...]
    tokenized_reports = []

    for report in reports:
        report = cleanText(report)
        tokens = tokenizer(report.strip())
        # 'token' is not a string type but rather spacy.token type
        # converting the spacy tokens into lists of words
        new_tokens = [str(token) for token in tokens]

        # removes the stopwords from the original tokens (still working-not completed)
        new_tokens = remove_stopwords(new_tokens)

        new_tokens=stemming(new_tokens)

        # appending unique word tokens only per document
        tokenized_reports.append(new_tokens)

    return tokenized_reports

def cleanText(text):
        text = re.sub('\|\|\|', ' ', text)
        text = text.lower()
        text = text.replace('x', '')
        return text

def stemming(tokens):

    stemmer = SnowballStemmer('english')
    stemmed_words=[]
    for token in tokens:
        stemmed_words.append(stemmer.stem(token))
    return stemmed_words

def remove_stopwords(tokens):
    '''This function will remove the stopwords'''

    # use this if you use stopword list directly from nltk

    stopWords = set(stopwords.words('english'))

    word_tokens = []

    for token in tokens:
        # removing stopwords and punctuations
        if token.lower() not in stopWords:
            word_tokens.append(token)
            # print(token)

    return word_tokens

#this was a test basis manual tokenization - not using for this classification
def manual_tokenization(reports):
    '''This function will tokenize the document and returns a list of tokenized doc'''

    # this will be a nested list of tokens [['word1', 'word2',...], [...], [...], ...]
    tokenized_reports = []

    for report in reports:
        # lowercase the string
        report = report.lower()

        # removing punctuation symbols
        report = report.translate(str.maketrans('', '', string.punctuation))

        # tokenize the text based on white space
        tokens = report.split()

        tokenized_reports.append(tokens)

    print(tokenized_reports[0])

    return tokenized_reports


from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
from . import sctrap
from .. import gp_utils

plist = ('b', 'c', 'd', 'e', 'f', 'g', 'h')
# Definitions of transit depths and durations.
t_depths = np.array([0.7266, 0.687, 0.367, 0.519, 0.673, 0.782, 0.346])/100.
t_duration = np.array([36.40, 42.37, 49.13, 57.21, 62.60, 68.40, 75.6])/(24*60)
loc = '/home/marko/K2GP/production/ttv_trappist/mcmc_times'

def convert_to_pd():
	ret_list = []

	for p in plist:
		file_template = '{}/{}.txt'
		with open(file_template.format(loc,p)) as f:
			data_list = f.readlines()

			df = pd.DataFrame(columns=['tr', 't'], index=range(len(data_list)))
			for i in range(len(data_list)):
				line_list = data_list[i].split()
				df.loc[i,'tr'] = line_list[0].split('-')[1]
				df.loc[i,'t'] = float(line_list[2])

			ret_list.append(df)

	return ret_list

def get_raw_tlist(t_min=None, t_max=None):
	'''
	Produces the raw expected transit timings.
	'''

	epoch_times = gp_utils.get_epoch_times()

	tlist = []

	for i in range(len(epoch_times.columns)):
		temp = epoch_times.loc[:,plist[i]]
		tlist.append(pd.DataFrame({'tr':temp.index, 't':temp}))
	for i in range(len(tlist)):
		if t_min is not None:
			tlist[i] = tlist[i][(tlist[i].t > t_min) & (tlist[i].t < t_max)]
		tlist[i].index = range(len(tlist[i]))

	return tlist

def produce_folds(dh = 3., pre_bin=5, post_bin=1):
	'''dh is the number of hours either side of the transit middle. '''

	dd = dh / 24.

	lcf = sctrap.get_results()
	lcf = lcf[~lcf.o_flag]
	lcf['f_detrended'] = lcf.f_detrended + 1.0
	# Follow is not required. Column gets switched to f later on.
	lcf['f'] = lcf.f_detrended

	tlist = convert_to_pd()
	raw_tlist = get_raw_tlist(t_min=min(lcf.t_bjd), t_max=max(lcf.t_bjd))

	fold_list, fold_pre_bin_list, fold_post_bin_list = [], [], []

	for i,p in enumerate(plist):
		transits = tlist[i]

		subbed_lcf = subtract_transits(lcf, i, raw_tlist)
		t_bin_pre, f_bin_pre = [], []
		for j in range(len(subbed_lcf)//pre_bin):
			t_bin_pre.append(np.mean(subbed_lcf.loc[j*pre_bin:(j+1)*pre_bin,'t_bjd']))
			f_bin_pre.append(np.mean(subbed_lcf.loc[j*pre_bin:(j+1)*pre_bin,'f_detrended']))
		lcf_bin = pd.DataFrame({'t_bjd':t_bin_pre, 'f_detrended':f_bin_pre})

		t_folded = []
		f_folded = []
		for j in range(len(transits)):
			tslice = subbed_lcf[(subbed_lcf.t_bjd > (transits.loc[j,'t'] - dd)) & (subbed_lcf.t_bjd < (transits.loc[j,'t'] + dd))]
			t_folded += list(tslice.t_bjd - transits.loc[j,'t'])
			f_folded += list(tslice.f_detrended)
		folded = pd.DataFrame({'t':t_folded, 'f':f_folded}).sort_values(by='t')

		# For the pre-bin folded.
		t_folded = []
		f_folded = []
		for j in range(len(transits)):
			tslice = lcf_bin[(lcf_bin.t_bjd > (transits.loc[j,'t'] - dd)) & (lcf_bin.t_bjd < (transits.loc[j,'t'] + dd))]
			t_folded += list(tslice.t_bjd - transits.loc[j,'t'])
			f_folded += list(tslice.f_detrended)
		folded_pre_bin = pd.DataFrame({'t':t_folded, 'f':f_folded}).sort_values(by='t')

		t_bin, f_bin = [], []
		# For the post bins the thing.
		for j in range(len(folded)//post_bin):
			t_bin.append(np.mean(folded.iloc[j*post_bin:(j+1)*post_bin].t))
			f_bin.append(np.mean(folded.iloc[j*post_bin:(j+1)*post_bin].f))
		folded_post_bin = pd.DataFrame({'t':t_bin, 'f':f_bin}).sort_values(by='t')

		fold_list.append(folded)
		fold_pre_bin_list.append(folded_pre_bin)
		fold_post_bin_list.append(folded_post_bin)

	return [fold_list, fold_pre_bin_list, fold_post_bin_list]

def plot_graph(main, highlight=None, hl=False):
	'''
	main and highlight as lists of pandas dataframes containing folded lightcurves.
	'''

	from matplotlib.ticker import MultipleLocator

	minorLocator = MultipleLocator(0.005)

	plt.rcParams["font.size"] = 4
	plt.rcParams["lines.linewidth"] = 0.3
	plt.rcParams["axes.linewidth"] = 0.3
	plt.rcParams["xtick.major.size"] = 2.0
	plt.rcParams["xtick.minor.size"] = 1.3
	plt.rcParams["xtick.major.width"] = 0.7
	plt.rcParams["xtick.minor.width"] = 0.3
	plt.rcParams["ytick.major.size"] = 2.0
	plt.rcParams["ytick.minor.size"] = 1.3
	plt.rcParams["ytick.major.width"] = 0.7
	plt.rcParams["ytick.minor.width"] = 0.3

	# Other cmap:
	# rgb(204, 51, 153) rgb(255, 153, 153) rgb(255, 204, 0) rgb(153, 102, 51) rgb(0, 153, 0) rgb(0, 153, 153) rgb(51, 51, 153)

	# Constants
	# The stack width.
	dy = 0.02
	colours_1 = ['r', 'b', 'g', 'y', 'r', 'b', 'g']
	colours_2 = np.array([(204.0, 51.0, 153.0), (255.0, 153.0, 153.0), (255.0, 204.0, 0.0), (255, 153, 0), (136, 204, 0), (112, 219, 219), (159, 159, 223)])/255.0
	alphas = [0.3, 0.3, 0.5, 0.7, 0.9, 1.0, 1.0]

	assert(len(main)==len(highlight))

	min_t = min([min(main[i].loc[:,'t']) for i in range(len(main))])
	max_t = max([max(main[i].loc[:,'t']) for i in range(len(main))])
	width_t = max_t - min_t

	# The stacked graph.
	fig, ax = plt.subplots(figsize=[1.8,3.0], dpi=100)

	for i in range(len(main)):
		# Main
		t = main[i].loc[:,'t']
		f = main[i].loc[:,'f'] - i*dy
		ax.plot(t, f, '.', color=colours_2[i], alpha=alphas[i], markersize=1.0)
		if highlight is not None:
			t = highlight[i].loc[:,'t']
			f = highlight[i].loc[:,'f'] - i*dy
			if hl is False:
				ax.plot(t, f, 'o', markeredgecolor='k', markeredgewidth=0.2, markerfacecolor='w', markersize=1.0, alpha=1.0)
			else:
				ax.plot(t, f, 'k-', alpha=1.0)

			# Label the planet.
			ax.text(min_t + 0.05*width_t, 1.0 - i*dy + 0.007, '{}'.format(plist[i]))

	# Aesthetics
	ax.set_xlabel('Time from mid-transit (d)')
	ax.set_ylabel('Relative brightness')
	ax.tick_params(axis='x',which='minor',bottom='off')
	ax.set_xlim([min_t, max_t])
	ax.set_ylim([0.865,1.015])

	print(fig.get_size_inches())

	fig.savefig('/home/marko/K2GP/plot_examples/stacked_transits_trappist.pdf',dpi=200)
	fig.savefig('/home/marko/K2GP/plot_examples/stacked_transits_trappist2.pdf',dpi=100)
	plt.tight_layout()
	plt.show()

def rebin(fold, n_bin):
	t_bin, f_bin = [], []
	# For the post bins the thing.
	for j in range(len(fold)//n_bin):
		t_bin.append(np.mean(fold.iloc[j*n_bin:(j+1)*n_bin].t))
		f_bin.append(np.mean(fold.iloc[j*n_bin:(j+1)*n_bin].f))
	binned = pd.DataFrame({'t':t_bin, 'f':f_bin}).sort_values(by='t')
	return binned

def rebin_int(fold, interval):
	t_bin, f_bin = [], []
	# For the post bins the thing.
	b1, b2 = min(fold.t), max(fold.t)
	nit = int((b2 - b1)//interval)
	for j in range(nit):
		sub = fold[(fold.t > j*interval+b1) & (fold.t < (j+1)*interval+b1)]
		t_bin.append(np.mean(sub.t))
		f_bin.append(np.mean(sub.f))
	binned = pd.DataFrame({'t':t_bin, 'f':f_bin}).sort_values(by='t')
	return binned

def remove_flares(fold, barrier=0.009):
	if not type(fold) in (list, tuple, np.ndarray):
		fold = [fold]
		tupled = False
	else:
		tupled = True
	for i in range(len(fold)):
		fold[i] = fold[i][fold[i].f < 1.009]
	if not tupled:
		return fold[0]
	else:
		return fold

def subtract_transits(lcf, planet, tlist):
	'''
	Subtracts all transits apart from planet (given as the integer).
	'''

	model = np.zeros_like(lcf.t)

	for i in range(len(plist)):
		if i != planet:
			depth = np.zeros_like(tlist[i].t) + t_depths[i]
			duration = np.zeros_like(tlist[i].t) + t_duration[i]
			model += transit_model(lcf.t_bjd, midpoint=tlist[i].t, depth=depth, duration=duration)

	new_lcf = lcf.copy()
	new_lcf['f_detrended'] = lcf.f_detrended - model

	return new_lcf

def main():
	full, pre, post = produce_folds(dh = 1.5, pre_bin=3, post_bin=5)
	new_post_1 = []
	new_post_2 = []
	pre = remove_flares(pre)
	for fold in pre:
		new_post_1.append(rebin(fold, 10))
		new_post_2.append(rebin_int(fold,interval=0.002))
	plot_graph(main=pre, highlight=new_post_1, hl=False)

def extract_transits():
	"""Extracts the transits of b from our data.
	"""
	#dh is the number of hours either side of the transit middle.
	dh = 2.
	dd = dh / 24.

	lcf = sctrap.get_results()
	lcf = lcf[~lcf.o_flag]
	lcf['f_detrended'] = lcf.f_detrended + 1.0
	# Following is not required. Column gets switched to f later on.
	lcf['f'] = lcf.f_detrended

	tlist = convert_to_pd()
	raw_tlist = get_raw_tlist(t_min=min(lcf.t_bjd), t_max=max(lcf.t_bjd))
	print("Find out what this looks like.")
	import pdb; pdb.set_trace()

	# TODO: remember to subtract the transits of the other planets.

	fold_list, fold_pre_bin_list, fold_post_bin_list = [], [], []

	for i,p in enumerate(plist):
		transits = tlist[i]

		subbed_lcf = subtract_transits(lcf, i, raw_tlist)
		t_bin_pre, f_bin_pre = [], []
		for j in range(len(subbed_lcf)//pre_bin):
			t_bin_pre.append(np.mean(subbed_lcf.loc[j*pre_bin:(j+1)*pre_bin,'t_bjd']))
			f_bin_pre.append(np.mean(subbed_lcf.loc[j*pre_bin:(j+1)*pre_bin,'f_detrended']))
		lcf_bin = pd.DataFrame({'t_bjd':t_bin_pre, 'f_detrended':f_bin_pre})

		t_folded = []
		f_folded = []
		for j in range(len(transits)):
			tslice = subbed_lcf[(subbed_lcf.t_bjd > (transits.loc[j,'t'] - dd)) & (subbed_lcf.t_bjd < (transits.loc[j,'t'] + dd))]
			t_folded += list(tslice.t_bjd - transits.loc[j,'t'])
			f_folded += list(tslice.f_detrended)
		folded = pd.DataFrame({'t':t_folded, 'f':f_folded}).sort_values(by='t')

		# For the pre-bin folded.
		t_folded = []
		f_folded = []
		for j in range(len(transits)):
			tslice = lcf_bin[(lcf_bin.t_bjd > (transits.loc[j,'t'] - dd)) & (lcf_bin.t_bjd < (transits.loc[j,'t'] + dd))]
			t_folded += list(tslice.t_bjd - transits.loc[j,'t'])
			f_folded += list(tslice.f_detrended)
		folded_pre_bin = pd.DataFrame({'t':t_folded, 'f':f_folded}).sort_values(by='t')

		t_bin, f_bin = [], []
		# For the post bins the thing.
		for j in range(len(folded)//post_bin):
			t_bin.append(np.mean(folded.iloc[j*post_bin:(j+1)*post_bin].t))
			f_bin.append(np.mean(folded.iloc[j*post_bin:(j+1)*post_bin].f))
		folded_post_bin = pd.DataFrame({'t':t_bin, 'f':f_bin}).sort_values(by='t')

		fold_list.append(folded)
		fold_pre_bin_list.append(folded_pre_bin)
		fold_post_bin_list.append(folded_post_bin)

	return [fold_list, fold_pre_bin_list, fold_post_bin_list]

def transit_model(t_array, midpoint, depth, duration):
	'''
	TODO
	'''
	try:
		assert(len(midpoint) == len(depth) == len(duration))
	except:
		import pdb; pdb.set_trace()

	tw = 0.15

	f_model = np.zeros_like(t_array)
	for i in range(len(midpoint)):
		f_model[(t_array > (midpoint[i] - duration[i]*tw)).values & (t_array < (midpoint[i] + duration[i]*tw)).values] -= depth[i]
		# Leading trapezoid edge.
		lmask = (t_array > (midpoint[i] - duration[i]*0.5)).values & (t_array < (midpoint[i] - duration[i]*tw)).values
		f_model[lmask] -= t_array[lmask]*depth[i]/(0.5 - tw)/duration[i] + depth[i]*(0.5*duration[i] - midpoint[i])/(0.5 - tw)/duration[i]
		# Trailing trapezoid edge (later).
		umask = (t_array < (midpoint[i] + duration[i]*0.5)).values & (t_array > (midpoint[i] + duration[i]*tw)).values
		f_model[umask] -= -t_array[umask]*depth[i]/(0.5 - tw)/duration[i] + + depth[i]*(0.5*duration[i] + midpoint[i])/(0.5 - tw)/duration[i]
	return f_model


from datetime import datetime
from pytz import timezone

def time():
    cartagena = timezone('US/Eastern')
    sa_time = datetime.now(cartagena)
    return (sa_time.strftime('%Y-%m-%d_%H:%M:%S'))

import urllib.request, json

def justtime():
    cartagena = timezone('US/Eastern')
    sa_time = datetime.now(cartagena)
    return (sa_time.strftime('%H:%M:%S'))

def temperatura():
    with urllib.request.urlopen("http://api.openweathermap.org/data/2.5/weather?id=3687238&appid=9583c3b4fa60a5323f4d1d115a5f2592") as url:
        data = json.loads(url.read().decode())
        return(data["main"]["temp"]-273.15)

def getparams():
    t = time()
    temp = temperatura()
    return(temp)
if __name__ == '__main__':
    i = getparams(),justtime()
    print(i)
    x = str(getparams())
    print(x)


import numpy as np
import pandas as pd
import requests
import json
import matplotlib.pyplot as plt

# Define query to API
api_url = 'https://api.rawg.io/api/'
query = 'platforms'

# Get request object
r = requests.get(api_url + query)

print(f"Status code: {r.status_code}\n")

# Store API response in a variable.
response_dict = r.json()

# Process results.
print(response_dict.keys())

# games_str = json.dumps(response_dict[1], indent = 2)
# print(games_str)

# Explore contents of a repository
repo_dicts = response_dict['results']
print(f"\n\n Repositories returned: {len(repo_dicts)}")
# Examine the first repository.
repo_dict = repo_dicts[0]
print(f"\nKeys: {len(repo_dict)} \n\n")
for key in sorted(repo_dict.keys()):
    print(key)

# # Print out the platforms:
# print(f"\n\nID:  \t PLATFORM:")
# for platform in np.arange(len(repo_dicts)):

#     platform_id = repo_dicts[platform].get('id')
#     platform_name = repo_dicts[platform].get('name')
#     platform_gamescount = repo_dicts[platform].get('games_count')

#     print(f"{platform_id} \t {platform_name} \t {platform_gamescount}")

# Generate DataFrame with general platforms information
platforms_general = pd.DataFrame(repo_dicts, columns = ['id','name','games_count'])
print(platforms_general)

# Compute basic statistics
# mean_games = np.mean(platforms_general['games_count'])
# median_games = np.median(platforms_general['games_count'])
# std_games = np.std(platforms_general['games_count'])
# mode_games = np.std(platforms_general['games_count'])
percentile_games_75 = np.percentile(platforms_general['games_count'], 75)

# Bar chart showing number of games per platform
platforms_75 = platforms_general[platforms_general.games_count > percentile_games_75]
platforms_75 = platforms_75.sort_values(by='games_count', ascending = True)

plt.barh(platforms_75.name, platforms_75.games_count, align='center', alpha=0.7)
plt.title("Top 25% platforms with most games")
plt.xlabel("Number of games")
plt.show()


from typing import List
class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        dictData={}
        res=[]
        for i in range(len(numbers)):
            if target-numbers[i] in dictData and i+1!=dictData[target-numbers[i]]:
                res.append(min(i+1,dictData[target-numbers[i]]))
                res.append(max(i+1,dictData[target-numbers[i]]))
                return res
            dictData[numbers[i]]=i+1
    def twoSum2(self, numbers: List[int], target: int) -> List[int]:
        i,j=0,len(numbers)-1
        while i<j:
            tmp=numbers[i]+numbers[j]
            if target==tmp:
                return [i+1,j+1]
            elif target<tmp:
                j-=1
            else:i+=1

sl=Solution()
print(sl.twoSum2([0,0,3,4],0))


from tinyec.ec import SubGroup, Curve
from Crypto.Random.random import randint
from web3 import Web3

p = int("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
n = int("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
x = int("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
y = int("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
h = 1
g = (x,y)
field = SubGroup(p, g, n, h)
curve = Curve(a = 0, b = 7, field = field, name = 'secp256k1')
private_key = randint(1, n)
public_key = private_key * curve.g
public_key_hex = Web3.toHex(public_key.x)[2:] + Web3.toHex(public_key.y)[2:]
address = Web3.keccak(hexstr = public_key_hex).hex()
address = "0x" + address[-40:]
address = Web3.toChecksumAddress(address)
print(private_key)
print(" public address-->", address)
#AD0B9C2E8E0E593542362C30AE9FF6459F0F0393E3496539D5C7CDD50655D2BC


"""Main application"""
from .model_trainers import ModelTrainer
from .predictors import Predictor
from .evaluation import ModelEvaluator
from .individual_importance import IndividualImportanceCalculator
from .model_grouping import ModelGrouper
from .subsetters import Subsetter
from .utils import filename_friendly_hash

import logging

import numpy

class ModelTrainTester(object):
    def __init__(
        self,
        matrix_storage_engine,
        model_trainer,
        model_evaluator,
        individual_importance_calculator,
        predictor,
        subsets,
    ):
        self.matrix_storage_engine = matrix_storage_engine
        self.model_trainer = model_trainer
        self.model_evaluator = model_evaluator
        self.individual_importance_calculator = individual_importance_calculator
        self.predictor = predictor
        self.subsets = subsets

    def generate_tasks(self, split, grid_config, model_comment=None):
        logging.info("Generating train/test tasks for split %s", split["train_uuid"])
        train_store = self.matrix_storage_engine.get_store(split["train_uuid"])
        if train_store.empty:
            logging.warning(
                """Train matrix for split %s was empty,
            no point in training this model. Skipping
            """,
                split["train_uuid"],
            )
            return []
        if len(train_store.labels.unique()) == 1:
            logging.warning(
                """Train Matrix for split %s had only one
            unique value, no point in training this model. Skipping
            """,
                split["train_uuid"],
            )
            return []
        train_tasks = self.model_trainer.generate_train_tasks(
            grid_config=grid_config,
            misc_db_parameters=dict(test=False, model_comment=model_comment),
            matrix_store=train_store
        )

        train_test_tasks = []
        for test_matrix_def, test_uuid in zip(
            split["test_matrices"], split["test_uuids"]
        ):
            test_store = self.matrix_storage_engine.get_store(test_uuid)

            if test_store.empty:
                logging.warning(
                    """Test matrix for uuid %s
                was empty, no point in generating predictions. Not creating train/test task.
                """,
                    test_uuid,
                )
                continue
            for train_task in train_tasks:
                train_test_tasks.append(
                    {
                        "test_store": test_store,
                        "train_store": train_store,
                        "train_kwargs": train_task,
                    }
                )
        return train_test_tasks

    def process_all_tasks(self, tasks):
        for task in tasks:
            self.process_task(**task)

    def process_task(self, test_store, train_store, train_kwargs):
        logging.info("Beginning train task %s", train_kwargs)
        with self.model_trainer.cache_models(), test_store.cache(), train_store.cache():
            # will cache any trained models until it goes out of scope (at the end of the task)
            # this way we avoid loading the model pickle again for predictions
            model_id = self.model_trainer.process_train_task(**train_kwargs)
            if not model_id:
                logging.warning("No model id returned from ModelTrainer.process_train_task, "
                                "training unsuccessful. Not attempting to test")
                return
            logging.info("Trained task %s and got model id %s", train_kwargs, model_id)
            as_of_times = test_store.metadata["as_of_times"]
            logging.info(
                "Testing and scoring model id %s with test matrix %s. "
                "as_of_times min: %s max: %s num: %s",
                model_id,
                test_store.uuid,
                min(as_of_times),
                max(as_of_times),
                len(as_of_times),
            )

            self.individual_importance_calculator.calculate_and_save_all_methods_and_dates(
                model_id, test_store
            )

            # Generate predictions for the testing data then training data
            for store in (test_store, train_store):
                predictions_proba = numpy.array(None)
                if self.predictor.replace:
                    logging.info(
                        "Replace flag set; generating new predictions and evaluations for"
                        "matrix %s-%s, and model %s",
                        store.uuid,
                        store.matrix_type,
                        model_id
                    )

                    predictions_proba = self.predictor.predict(
                        model_id,
                        store,
                        misc_db_parameters=dict(),
                        train_matrix_columns=train_store.columns(),
                    )

                for subset in self.subsets:
                    if self.predictor.replace or self.model_evaluator.needs_evaluations(
                        store, model_id, filename_friendly_hash(subset)
                    ):
                        logging.info(
                            "Evaluating matrix %s-%s, subset %s, and model %s",
                            store.uuid,
                            store.matrix_type,
                            filename_friendly_hash(subset),
                            model_id,
                        )

                        if not predictions_proba.any():
                            logging.info(
                                "Generating new predictions for"
                                "matrix %s-%s, and model %s to make evaluation",
                                store.uuid,
                                store.matrix_type,
                                model_id
                            )

                            predictions_proba = self.predictor.predict(
                                model_id,
                                store,
                                misc_db_parameters=dict(),
                                train_matrix_columns=train_store.columns(),
                            )

                        self.model_evaluator.evaluate(
                            predictions_proba=predictions_proba,
                            matrix_store=store,
                            model_id=model_id,
                            subset=subset,
                        )

                    else:
                        logging.info(
                            "The evaluations needed for matrix %s-%s, subset %s, and "
                            "model %s are all present"
                            "in db from a previous run (or none needed at all), so skipping!",
                            store.uuid,
                            store.matrix_type,
                            filename_friendly_hash(subset),
                            model_id
                        )

__all__ = (
    "IndividualImportanceCalculator",
    "ModelEvaluator",
    "ModelGrouper"
    "ModelTrainer",
    "Predictor",
    "ModelTrainTester",
    "Subsetter",
)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Nov 15 15:16:51 2018

@author: ubuntu
"""
from model.vgg16 import VGG16
from model.Pretrainedmodels import pretrained_models
from torch import nn
from collections import OrderedDict
import torch

''' 这一段可以看到怎么把参数加到_parameters变量中
    1. model对象调用__setattr__()方法，pytorch重写了这个方法
    2. 在__setattr__()方法中调用register_parameters()函数
    3. 在register_parameters()函数中，赋值self._parameters[name] = value

model = nn.Module()   # 创建所有变量包括：_parameters, _buffers
model.param = nn.Parameter(torch.ones(2,2))
model._parameters
'''

''' 这一段可以看到怎么把nn.sequential里边的module加到_module变量中去。
'''
inputs = torch.randn(1,3,224,224)
labels = torch.tensor([[1, 0]])

#model = nn.Sequential(OrderedDict([
#          ('conv1', nn.Conv2d(1,20,5)),
#          ('relu1', nn.ReLU()),
#          ('conv2', nn.Conv2d(20,64,5)),
#          ('relu2', nn.ReLU())
#        ]))

model = pretrained_models('vgg16',num_classes=2)
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

print(model.__dict__)

getattr(model, 'training')
getattr(model, '_parameters')

optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)     # 这一步有可能很复杂的扩展
loss.backward()    # 更新梯度
optimizer.step()   # 更新参数


from django.core.management.base import BaseCommand
from mimesis import Text, Business

from books.models import Book, Publisher
from shops.models import BookShop, Stock, Sale
import random

class Command(BaseCommand):
    help = 'Populate database with data'

    def handle(self, *args, **options):

        for _ in range(10):
            _publisher = Business()
            publisher = Publisher.objects.create(name=_publisher.company())

            for _book in range(50):
                _text = Text()
                Book.objects.create(title=_text.title(), publisher=publisher, annotation=_text.text(10))

            for s in range(6):
                _shop = Business()
                shop = BookShop.objects.create(name=_shop.company())

                for stock_book in random.sample(list(Book.objects.all()), 25):
                    Stock.objects.create(
                        book=stock_book,
                        shop=shop,
                        quantity=random.randint(10, 50)
                    )

                for stock_sale in random.sample(list(shop.stock_set.all()), 20):
                    Sale.objects.create(
                        book=stock_sale.book,
                        shop=stock_sale.shop,
                        quantity=random.randint(2, stock_sale.quantity)
                    )


import cv2
import numpy as np
from PIL import Image
import os
music_dir = "E:\\Music"
songs = os.listdir(music_dir)
os.startfile(os.path.join(music_dir, songs[9]))
maskPath = 'mask.png'

harcasPath = 'haarcascade_frontalface_default.xml'

faceCascade = cv2.CascadeClassifier(harcasPath)

mask = Image.open(maskPath)

def thug_mask(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    faces = faceCascade.detectMultiScale(gray, 2.1 )

    background = Image.fromarray(image)

    for (x, y, w, h) in faces:
        resized_mask = mask.resize((w, h), Image.ANTIALIAS)

        offset = (x, y)
        background.paste(resized_mask, offset, mask=resized_mask)

    return np.asarray(background)

cap = cv2.VideoCapture(0)

while True:
    _, frame = cap.read()

    cv2.imshow("Thug Life Filter", thug_mask(frame))

    if cv2.waitKey(1) == 27:
        break

cap.release()

cv2.destroyAllWindows()


# -*- coding: UTF-8 -*-
#beautiful爬取豆瓣Top250电影信息

import urllib3
import re
from bs4 import BeautifulSoup
import codecs

# 爬虫函数
def crawl(url):
    page = urllib3.urlopen(url)
    contents = page.read()
    soup = BeautifulSoup(contents, "html.parser")
    print
    u'豆瓣电影250: 序号 \t影片名\t 评分 \t评价人数'
    infofile.write(u"豆瓣电影250: 序号 \t影片名\t 评分 \t评价人数\r\n")
    print
    u'爬取信息如下:\n'
    for tag in soup.find_all(attrs={"class": "item"}):
        # print tag
        # 爬取序号
        num = tag.find('em').get_text()
        print
        num
        # 爬取电影名称
        name = tag.find(attrs={"class": "hd"}).a.get_text()
        name = name.replace('\n', ' ')
        print
        name
        infofile.write(num + " " + name + "\r\n")
        # 电影名称
        title = tag.find_all(attrs={"class": "title"})
        i = 0
        for n in title:
            text = n.get_text()
            text = text.replace('/', '')
            text = text.lstrip()
            if i == 0:
                print
                u'[中文标题]', text
                infofile.write(u"[中文标题]" + text + "\r\n")
            elif i == 1:
                print
                u'[英文标题]', text
                infofile.write(u"[英文标题]" + text + "\r\n")
            i = i + 1
        # 爬取评分和评论数
        info = tag.find(attrs={"class": "star"}).get_text()
        info = info.replace('\n', ' ')
        info = info.lstrip()
        print
        info
        mode = re.compile(r'\d+\.?\d*')
        print
        mode.findall(info)
        i = 0
        for n in mode.findall(info):
            if i == 0:
                print
                u'[分数]', n
                infofile.write(u"[分数]" + n + "\r\n")
            elif i == 1:
                print
                u'[评论]', n
                infofile.write(u"[评论]" + n + "\r\n")
            i = i + 1
        # 获取评语
        info = tag.find(attrs={"class": "inq"})
        if (info):  # 132部电影 [消失的爱人] 没有影评
            content = info.get_text()
            print
            u'[影评]', content
            infofile.write(u"[影评]" + content + "\r\n")
        print
        ''

# 主函数
if __name__ == '__main__':

    infofile = codecs.open("Result_Douban.txt", 'a', 'utf-8')
    url = 'http://movie.douban.com/top250?format=text'
    i = 0
    while i < 10:
        print
        u'页码', (i + 1)
        num = i * 25  # 每次显示25部 URL序号按25增加
        url = 'https://movie.douban.com/top250?start=' + str(num) + '&filter='
        crawl(url)
        infofile.write("\r\n\r\n\r\n")
        i = i + 1
    infofile.close()


#!/usr/bin/env python
# coding: utf-8

from bs4 import BeautifulSoup
import mq

import requests

class Spider:
    def __init__(self, qname):
        self.queue = mq.createMq(qname)

    def getPage(self, url):
        '''获得当前url对应的文本内容'''
        r = requests.get(url)
        soup = BeautifulSoup(r.text, 'html5lib')
        title = soup.find('h1', {'class': 'nolinks'}).get_text()
        author = soup.find('div', {'class': 'author-bio'}).a.h3.get_text()
        content = soup.find('div', {'class': 'post-content'}).get_text()
        data = {'title': title, 'author': author, 'content': content}
        print(data)

    def runOnePage(self):
        def callback(ch, method, properties, body):
            print(self.getPage(body))

        data = self.queue.doOneTask('urls',
                                    callback)
        self.queue.close()

    def runAllPage(self):
        pass

if __name__ == '__main__':
    spider = Spider('redis')
    spider.runOnePage()


import argparse
import glob
import logging
import os
import pickle
import shutil
import subprocess

from simulation_check import check_simulation_folder
logger = logging.getLogger('simulation_check')
logger.setLevel(logging.ERROR)

from simulation_analyze import analyze_simulation_folder

from SimulationConfig import SimulationConfig

logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

def read_command_line_parameters():
    parser = argparse.ArgumentParser()
    parser.add_argument('-r', '--runfolder', required = True,
                        help='run output folder ')
    parser.add_argument('-c', '--cfgfolder', required = True,
                        help='run config folder ')
    parser.add_argument('-s', '--sumfolder', required = True,
                        help='run summary folder')
    parser.add_argument('--rerun', required = False, action = 'store_true',
                        help = 'Whether or not to rerun the failed simulations')
    parser.add_argument('--redo', required = False, action = 'store_true',
                        help = 'Whether or not to rewrite the simulation '\
                        'summaries')
    return parser.parse_args()

class ExperimentSummarizer:
    PARAMETER_LATEX = "\\newcommand{{\\smallR}}{{{smallR}}}\n"\
                      "\\newcommand{{\\bigR}}{{{bigR}}}\n"\
                      "\\newcommand{{\\smallN}}{{{smallN}}}\n"\
                      "\\newcommand{{\\bigN}}{{{bigN}}}\n"

    def __init__(self, run_folder, cfg_folder, sum_folder, rerun_failed,
                 redo_summaries):
        self._run_folder = run_folder
        self._cfg_folder = cfg_folder
        self._sum_folder = sum_folder
        self._rerun_failed = rerun_failed
        self._redo_summaries = redo_summaries
        self._param_values = None

    def _get_possible_parameter_values(self):
        parameter_values_file = glob.glob(os.path.join(self._cfg_folder,
                                                       '*.pickle'))[0]
        with open(parameter_values_file, 'rb') as handle:
            self._param_values = pickle.load(handle)

    def _get_all_config_files(self):
        return glob.glob(os.path.join(self._cfg_folder, '*.cfg'))

    def _get_sim_name(self, config_file):
        return os.path.basename(config_file)[:-4]

    def _get_last_run(self, config_file):
        sim_name = self._get_sim_name(config_file)
        existing_runs = glob.glob(os.path.join(self._run_folder,
                                               sim_name + '_*/'))
        existing_runs.sort(key=lambda x: x.rstrip('/').split('_'))
        if not existing_runs:
            return None
        return existing_runs[-1]

    def _get_sim_config(self, simulation_folder):
        simulation_config = glob.glob(os.path.join(simulation_folder, '*.cfg'))
        return SimulationConfig().read_config(simulation_config)

    def _prepare_analyze_parameters(self, settings):
        parameters = ['R01']
        values = [settings['BDSky_exp_R0']]
        if settings['fix'] == 'p':
            parameters.append('becomeUninfectiousRate')
            values.append(settings['BDSky_exp_become_uninfectious_rate'])
        elif settings['fix'] == 'bUR':
            parameters.append('samplingProportion1')
            values.append(settings['BDSky_exp_sampling_proportion'])
        return (parameters, values)

    def _copy_all_summaries(self, simulation_folder):
        summary_files = glob.glob(os.path.join(simulation_folder, '*.tex'))
        for file in summary_files:
            shutil.copy(file, self._sum_folder)

        plot_files = glob.glob(os.path.join(simulation_folder, '*.pdf'))
        plot_folder = os.path.join(self._sum_folder, 'plots')
        if not os.path.exists(plot_folder):
            os.makedirs(plot_folder)
        for file in plot_files:
            shutil.copy(file, plot_folder)

    def _summarize_run(self, simulation_folder):
        settings = self._get_sim_config(simulation_folder)\
                                  .parameter_values
        parameters, values = self._prepare_analyze_parameters(settings)
        analyze_simulation_folder(simulation_folder, parameters, values,
                                  False, False)

    def _remove_all_files(self, file_list):
        for file in file_list:
            os.remove(file)

    def _create_run_summary(self, simulation_folder):
        existing_output = glob.glob(os.path.join(simulation_folder, '*.tex'))
        if not self._redo_summaries and existing_output:
            logger.info('Some summary output already created.')
        else:
            if existing_output:
                logger.info('Removing existing summaries.')
                self._remove_all_files(existing_output)
                plot_files = glob.glob(os.path.join(simulation_folder, '*.pdf'))
                self._remove_all_files(plot_files)
            logger.info('Creating summary output for the simulation.')
            self._summarize_run(simulation_folder)
        self._copy_all_summaries(simulation_folder)

    def _single_run_or_summarize(self, config_file):
        simulation_folder = self._get_last_run(config_file)
        if simulation_folder is None:
            logger.info('Running simulation for config file %s', config_file)
            subprocess.call(['./simulation_run.py', '-c', config_file])
        else:
            logger.info('Checking completeness for config file %s', config_file)
            incomplete = check_simulation_folder(simulation_folder,
                                                 self._rerun_failed)
            if incomplete:
                logger.info('This simulation is not completely done yet')
            else:
                logger.info('Starting run summary')
                self._create_run_summary(simulation_folder)

    def _summary_possible_parameter_values(self):
        if self._sum_folder is None:
            logger.info('No summary folder specified to write possible'\
                        ' parameter values.')
            return
        logger.info('Writing possible parameter values to the summary folder.')
        parameter_latex = self.PARAMETER_LATEX\
                              .format(smallR = min(self._param_values['R0']),
                                      bigR = max(self._param_values['R0']),
                                      smallN = min(self._param_values['N']),
                                      bigN  = max(self._param_values['N']))
        with open(os.path.join(self._sum_folder,
                               'possible_parameter_values.tex'), 'w') as handle:
            handle.write(parameter_latex)

    def run_or_summarize(self):
        self._get_possible_parameter_values()
        self._summary_possible_parameter_values()
        config_file_list = self._get_all_config_files()
        for config_file in config_file_list:
            self._single_run_or_summarize(config_file)

if __name__ == '__main__':
    args = read_command_line_parameters()
    run_folder = args.runfolder
    cfg_folder = args.cfgfolder
    sum_folder = args.sumfolder
    if not os.path.exists(sum_folder):
        os.makedirs(sum_folder)
    e = ExperimentSummarizer(args.runfolder, args.cfgfolder, args.sumfolder,
                             args.rerun, args.redo)
    e.run_or_summarize()


# uncompyle6 version 3.7.4
# Python bytecode 2.3 (62011)
# Decompiled from: Python 3.6.9 (default, Apr 18 2020, 01:56:04)
# [GCC 8.4.0]
# Embedded file name: build\bdist.win32\egg\demos\forest.py
# Compiled at: 2006-02-18 18:19:25
"""
A demonstration of the pedestrian interface with a forest scene.
"""
import math, random, sys, OpenGL.GL as ogl, OpenGL.GLU as oglu, pygame
sys.path.append('..')
import la, spyre
pygame.init()
hillLoc = (
 -10, 75, 10)

class terrain(spyre.Object):
    """draws the ground """
    __module__ = __name__

    def __init__(self, width=2000, depth=2000, x=0, y=0, z=0):
        spyre.Object.__init__(self)
        self.width = width
        self.depth = depth
        self.x = x
        self.y = y
        self.z = z
        self.quad = oglu.gluNewQuadric()

    def display(self):
        ogl.glPushMatrix()
        ogl.glTranslate(self.x, self.y, self.z)
        ogl.glColor4f(0.4, 0.5, 0.4, 1)
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_AMBIENT, [0.17, 0.2, 0.2, 0.0])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_DIFFUSE, [0.5, 0.5, 0.5, 0.1])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_SPECULAR, [0.7, 0.6, 0.8, 0.0])
        oglu.gluDisk(self.quad, 0, self.width, 60, 70)
        ogl.glTranslate(hillLoc[0], hillLoc[1], 0)
        oglu.gluCylinder(self.quad, 50, 25, hillLoc[2], 50, 50)
        ogl.glTranslate(0, 0, hillLoc[2])
        oglu.gluDisk(self.quad, 0, 25, 60, 70)
        ogl.glPopMatrix()

class deciduous(spyre.Object):
    """draws a deciduous tree"""
    __module__ = __name__

    def __init__(self, height, radius, x=0, y=0, z=0):
        spyre.Object.__init__(self)
        self.height = height
        self.radius = radius
        self.x = x
        self.y = y
        self.z = z
        self.quad = oglu.gluNewQuadric()

    def display(self):
        ogl.glPushMatrix()
        ogl.glTranslate(self.x, self.y, self.z)
        ogl.glColor4f(0.5, 0.6, 0.6, 1)
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_AMBIENT, [0.17, 0.2, 0.2, 0.0])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_DIFFUSE, [0.5, 0.5, 0.5, 0.1])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_SPECULAR, [0.7, 0.6, 0.8, 0.0])
        ogl.glMaterialf(ogl.GL_FRONT, ogl.GL_SHININESS, 50)
        oglu.gluCylinder(self.quad, self.radius / 20.0, self.radius / 20.0, self.height * 0.66, 60, 60)
        ogl.glColor4f(0.0, 0.9, 0.4, 1)
        ogl.glTranslate(0, 0, self.height - self.radius)
        oglu.gluSphere(self.quad, self.radius, 60, 60)
        ogl.glPopMatrix()

class conifer(spyre.Object):
    """draws a conifer (conical) tree"""
    __module__ = __name__

    def __init__(self, height, radius, x=0, y=0, z=0):
        spyre.Object.__init__(self)
        self.height = height
        self.radius = radius
        self.x = x
        self.y = y
        self.z = z
        self.quad = oglu.gluNewQuadric()

    def display(self):
        ogl.glPushMatrix()
        ogl.glTranslate(self.x, self.y, self.z)
        ogl.glColor4f(0.4, 0.6, 0.6, 1)
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_AMBIENT, [0.17, 0.2, 0.2, 0.0])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_DIFFUSE, [0.5, 0.5, 0.5, 0.1])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_SPECULAR, [0.6, 0.5, 0.7, 0.0])
        ogl.glMaterialf(ogl.GL_FRONT, ogl.GL_SHININESS, 50)
        oglu.gluCylinder(self.quad, self.radius / 20.0, self.radius / 20.0, self.height * 0.25, 60, 70)
        ogl.glColor4f(0.2, 0.9, 0.4, 1)
        ogl.glTranslate(0, 0, self.height * 0.25)
        oglu.gluCylinder(self.quad, self.radius, 0, self.height * 0.75, 60, 60)
        ogl.glPopMatrix()

class triConifer(spyre.Object):
    """draws a conifer with three frond levels"""
    __module__ = __name__

    def __init__(self, height, radius, x=0, y=0, z=0):
        spyre.Object.__init__(self)
        self.height = height
        self.radius = radius
        self.x = x
        self.y = y
        self.z = z
        self.quad = oglu.gluNewQuadric()

    def display(self):
        ogl.glPushMatrix()
        ogl.glTranslate(self.x, self.y, self.z)
        ogl.glColor4f(0.4, 0.4, 0.5, 1)
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_AMBIENT, [0.17, 0.2, 0.2, 0.0])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_DIFFUSE, [0.5, 0.5, 0.5, 0.1])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_SPECULAR, [0.7, 0.6, 0.8, 0.0])
        ogl.glMaterialf(ogl.GL_FRONT, ogl.GL_SHININESS, 50)
        oglu.gluCylinder(self.quad, self.radius / 20.0, self.radius / 20.0, self.height * 0.25, 60, 70)
        ogl.glColor4f(0.2, 0.9, 0.6, 1)
        ogl.glTranslate(0, 0, self.height * 0.25)
        oglu.gluCylinder(self.quad, self.radius * 0.9, 0, self.height * 0.5, 60, 60)
        ogl.glTranslate(0, 0, self.height * 0.25)
        oglu.gluCylinder(self.quad, self.radius, 0, self.height * 0.5, 60, 60)
        ogl.glTranslate(0, 0, self.height * 0.25)
        oglu.gluCylinder(self.quad, self.radius * 0.8, 0, self.height * 0.5, 60, 60)
        ogl.glPopMatrix()

class poplar(spyre.Object):
    """draws a poplar tree"""
    __module__ = __name__

    def __init__(self, height, radius, x=0, y=0, z=0):
        spyre.Object.__init__(self)
        self.height = height
        self.radius = radius
        self.x = x
        self.y = y
        self.z = z
        self.quad = oglu.gluNewQuadric()

    def display(self):
        ogl.glPushMatrix()
        ogl.glTranslate(self.x, self.y, self.z)
        ogl.glColor4f(0.6, 0.5, 0.6, 1)
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_AMBIENT, [0.17, 0.2, 0.2, 0.0])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_DIFFUSE, [0.5, 0.5, 0.5, 0.1])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_SPECULAR, [0.5, 0.5, 0.5, 0.0])
        ogl.glMaterialf(ogl.GL_FRONT, ogl.GL_SHININESS, 50)
        oglu.gluCylinder(self.quad, self.radius / 10.0, self.radius / 10.0, self.height * 0.1, 60, 70)
        ogl.glColor4f(0.3, 0.8, 0.1, 1)
        ogl.glTranslate(0, 0, self.height * 0.1 + self.radius)
        oglu.gluSphere(self.quad, self.radius, 20, 20)
        oglu.gluCylinder(self.quad, self.radius, self.radius, self.height * 0.5 - self.radius, 60, 60)
        ogl.glTranslate(0, 0, self.height * 0.5 - self.radius)
        oglu.gluCylinder(self.quad, self.radius, 0, self.height * 0.4, 60, 60)
        ogl.glPopMatrix()

class rock(spyre.Object):
    """draws a round rock"""
    __module__ = __name__

    def __init__(self, radius, x=0, y=0, z=0):
        spyre.Object.__init__(self)
        self.radius = radius
        self.x = x
        self.y = y
        self.z = z
        self.quad = oglu.gluNewQuadric()

    def display(self):
        ogl.glPushMatrix()
        ogl.glTranslate(self.x, self.y, self.z)
        ogl.glColor4f(0.3, 0.3, 0.32, 1)
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_AMBIENT, [0.17, 0.2, 0.2, 0.0])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_DIFFUSE, [0.5, 0.5, 0.5, 0.1])
        ogl.glMaterialfv(ogl.GL_FRONT, ogl.GL_SPECULAR, [0.8, 0.8, 0.8, 0.0])
        ogl.glMaterialf(ogl.GL_FRONT, ogl.GL_SHININESS, 50)
        oglu.gluSphere(self.quad, self.radius, 20, 20)
        ogl.glPopMatrix()

def elev(x, y):
    dist = math.sqrt((hillLoc[0] - x) ** 2 + (hillLoc[1] - y) ** 2)
    if dist < 50:
        if dist < 25:
            return hillLoc[2]
        else:
            return hillLoc[2] - hillLoc[2] * (dist - 25) / 25
    else:
        return 0

def main():
    engine = spyre.Engine()
    engine.addCamera(spyre.RovingCameraFrustum(engine, (10, -95, 8), (10, -10, 6), (0, 0, 1), elev))
    engine.camera.perspective(20, 1, 5, 500)
    engine.interface = spyre.PedestrianInterface(engine)
    engine.studio = spyre.StudioColorMat(engine)
    engine.studio.depthCueing(True, ogl.GL_LINEAR)
    light0 = spyre.Bulb([0.5, 0.6, 0.5, 1.0], [
     0.6, 0.7, 0.7, 1.0], [
     0.3, 0.3, 0.3, 1.0])
    engine.studio.addCamLight(light0, (0, 0, 10))
    solar = spyre.Sun([0.4, 0.4, 0.4, 1.0], [
     0.9, 1.0, 0.1, 1.0], [
     0.3, 0.3, 0.3, 1.0])
    engine.studio.addFixedLight(solar, (0, 100, 100))
    engine.add(terrain())
    engine.add(poplar(40, 2, -75, -10, 0))
    engine.add(poplar(42, 2, -79, -14, 0))
    engine.add(poplar(43, 2.2, -85, -19, 0))
    engine.add(poplar(38, 2, -95, -25, 0))
    engine.add(conifer(15, 7, -20, -10, 0))
    engine.add(conifer(15, 3, -30, -15, 0))
    engine.add(deciduous(25, 10, -22, 35, 5))
    engine.add(conifer(12, 5, -10, 90, hillLoc[2]))
    engine.add(conifer(13, 5, 0, 85, hillLoc[2]))
    engine.add(conifer(11, 4, 5, 75, hillLoc[2]))
    engine.add(triConifer(15, 10, 70, 100, 0))
    engine.add(triConifer(15, 10, 70, 70, 0))
    engine.add(poplar(25, 2, 73, -30, 0))
    engine.add(rock(2, 28, -40, 0))
    engine.add(rock(1.5, 20, -25, 0))
    engine.add(rock(2, 15, -13, 0))
    engine.add(rock(2.2, 20, 0, 0))
    engine.add(rock(1.7, 20, 45, 3))
    engine.add(rock(2, 24, 60, 0))
    engine.go()

if __name__ == '__main__':
    main()


'''
    Controlador principal de nuestra aplicacion
'''
# Importamos la librerias necesarias para el proyectoS
import re
from flask import Flask, render_template, request
from flask.helpers import get_debug_flag, url_for
from werkzeug.utils import redirect

from Registro import Registro
from db import DB_Control

# Creamos nuestro objeto aplicacion
app = Flask(__name__)
bd = r"/home/ldavid/Proyectos/Py_proj/POO/App/database.db"
tabla = "registro"

gbd = DB_Control(bd, tabla)
gbd.crear_tabla()
gbd.cerrar_cnx()

# Creamos nuestra primera ruta
@app.route("/")
def inicio():
    return render_template("inicio.html")

#Creamos una ruta para el registro, capas de resolver peticiones get y post
@app.route("/registro", methods = ['Get', 'Post'])

def registro():
    if request.method == "POST":
        reg = Registro(
            request.form['_nombre'],
            request.form['_edad'],
            request.form['_correo'],
            request.form['_ciudad'],
            request.form['_usuario'],
            request.form['_clave']
        )
        # Abrimos conexion
        gbd.abrir_cnx()
        # Buscamos si el registro ya existe
        resultado, data = gbd.busqueda("usuario",reg.usuario)
        if resultado == True:
            return "Usuario ya existe"
        gbd.registrar(reg)

        print(reg.edad)
        return(f"Nombre: {reg.nombre} | Correo: {reg.correo}")

    elif request.method == "GET":
        return render_template('registro.html')

# Creamos nuestra pantalla login, capaz de recibir peticiones get y post
@app.route("/login", methods = ['GET', 'POST'])
def login():
    if request.method == "POST":
        return redirect(url_for('dash'))
    else:
        return render_template('login.html')

@app.route("/dash")
def dash():
    return "Bienvenido"

if (__name__ == "__main__"):
    app.run(debug = True, port = 5000)


import torch
from torch import nn, optim
from torchvision import models

from collections import OrderedDict

def model(hidden_layers=[1024, 512], learning_rate=0.0008, arch="vgg19", device="cpu"):

    # Try to create a model from torchvision.models subpackage
    try:
        model = eval("models." + arch +"(pretrained=True)")
    except AttributeError:
        print("Model not available. Please try another architecture.")
        return None

    # don't compute gradients
    for param in model.parameters():
        param.requires_grad = False

    # create new classifier
    classifier = nn.Sequential(OrderedDict([
        ('fc1', nn.Linear(25088, int(hidden_layers[0]))),
        ('relu1', nn.ReLU()),
        ('dropout1', nn.Dropout(p=0.5)),
        ('fc2', nn.Linear(int(hidden_layers[0]), int(hidden_layers[1]))),
        ('relu2', nn.ReLU()),
        ('dropout2', nn.Dropout(p=0.5)),
        ('fc4', nn.Linear(int(hidden_layers[1]), 102)),
        ('output', nn.LogSoftmax(dim=1))
    ]))

    model.classifier = classifier
    criterion = nn.NLLLoss()
    optimizer = optim.Adam(model.classifier.parameters(), lr=learning_rate)

    if device == "cuda" and torch.cuda.is_available(): model.to("cuda")
    else: model.to("cpu")

    return model, criterion, optimizer

def load_checkpoint(filepath):
    """
    checkpoint = {'epochs': epochs,
                  'training_losses': training_losses,
                  'validation_losses': validation_losses,
                  'layers': [25088, 1024, 512, 102],
                  'optimizer_state_dict': optimizer.state_dict(),
                  'model_state_dict': model.state_dict()}
    """
    checkpoint = torch.load(filepath)

    loaded_model, _, _ = model(hidden_layers=checkpoint['layers'][1:3],
                                             learning_rate=0.0008,
                                             arch="vgg19",
                                             device="cpu")

    loaded_model.load_state_dict(checkpoint['model_state_dict'])
    loaded_model.class_to_idx = checkpoint['class_to_idx']
    return loaded_model