# TODO:
#  ==============================================================================
#  S. Learn about and implement text input boxes so that the user can provide numbers for filtering parameters
#    1. Do the same for the OptionMenu widget class, dropdowns for selecting primary, secondary, tertiary inputs
#  ==============================================================================
#  A. Consider creating a new widget_container.py file (or some other name with similar meaning)
#    1. Not immediately necessary, but the GUI is gonna become more and more complicated so it may make more sense
#       to handle initialization-related aspects of the program within a class
#  B. It's REALLY not great practice that I'm initializing member variables like frames outside of __init__()
#    1. Would be better to, at that point within defineGrid(), initialize a WidgetContainer() instance which holds
#         those widgets as member variables AND defines them within its __init__ function
#  C. If clearing IS important, consider using
#             del tempList[:]
#         But don't jump to conclusions on doing so
#    1. Don't want to accidentally call any destructors for ttk objects and such,
#       since many will be referenced by two or more lists
#  D. Create a TXT or CSV input system for defining all of the GUI parameters that are currently hard-coded
#    1. Not at all concerned with this until I actually care about making things pretty beyond functionality
#  E. STRONGLY CONSIDER instance vs. class member variables and improve abstraction (as currently in D.)
#     Explanation: https://dev.to/ogwurujohnson/distinguishing-instance-variables-from-class-variables-in-python-81

__name__ = "hypnic_gui"

# Library Inputs
from timeit import default_timer
import tkinter
from tkinter import CENTER, ttk
# The partial() module can be used to allow widgets like Buttons to pass arguments along with their commands
# It is specifically useful where lambda can't be applied, like when such a parameter is being periodically changed
#   throughout some sort of iterative process, such as configuring commands within the controlBox Frames
# Credit to StackOverflow users "Dologan" and "Klamer Schutte" for their answer and associated comments on its use
# The answer can be viewed at https://stackoverflow.com/a/22290388
from functools import partial

# Local Inputs
import timing_container
import dimension_container
import state_container
import image_container
import style_container
import edit_container
import command_container
import hypnic_helpers

# G L O B A L   V A R I A B L E S
# Path to the text document which lists the paths to all input images
# TODO: Remove this global and define it from user input at runtime
INPUT_IMAGE_PATHS_FILE = "hypnic_images.txt"  # FLAG: Hard-coded GUI parameter!

class HypnicGUI(tkinter.Tk):

    # Constructor has a wrapper_ argument for the program's HypnicWrapper instance
    def __init__(self, wrapper_, *args, **kwargs):

        # INITIALIZATION TIMER
        # Timer beginning upon initialization of this object
        self.initTimer = default_timer()

        # OTHER TIMERS
        # List of all timers, initialized as containing only self.initTimer
        self.timers = [self.initTimer]

        # The HypnicGUI instance can refer to the HypnicWrapper instance
        # TODO: Since I'm writing all of these classes for use as single instances, it amy make the most
        #       sense to transition such member variables to "above" the __init__()
        self.wrapper = wrapper_

        # Begins by running the initialization function for the basic instance of tkinter.Tk
        tkinter.Tk.__init__(self, *args, **kwargs)

        # TODO: Consider using dicts instead of lists, for storing the ttk widgets and such
        # I N I T I A L I Z A T I O N     O F     W I D G E T - R E L A T E D     V A R I A B L E S
        # GENERAL WIDGET LIST
        # Stores all of the ttk widgets that belong to the GUI
        # Widgets include but are not limited to instances of Frame, Label, Button, etc.
        self.widgets = []

        # SPECIFIC WIDGET LISTS
        # Stores  the ttk INPUT-RELATED widget instances.
        # NOTE: This *CAN* include ttk Button objects for example, even though they have their own wider-scoped list
        self.inputWidgets = []

        # I N I T I A L I Z A T I O N     O F     F R A M E - R E L A T E D     V A R I A B L E S
        # GENERAL FRAME LIST
        # Stores all of the ttk Frame objects that belong to the GUI
        self.frames = []

        # CUSTOM FRAME LISTS (mainly for storing frames which do not have their own individual member variables)
        #     - Also potentially useful for keeping narrow-scope groups of similar frames together
        # self.photoBoxFrames stores each of the 4 frames held within self.photoBox
        self.photoBoxFrames = []

        # self.controlBoxFrames stores each frame from each row within self.controlBox
        self.controlBoxFrames = []

        # I N I T I A L I Z A T I O N     O F     L A B E L - R E L A T E D     V A R I A B L E S
        # GENERAL LABEL LIST
        # Stores all of the ttk Label objects that belong to the GUI
        self.labels = []

        # SPECIFIC LABEL LISTS
        # Divides labels into separate lists based on whether or not they contain associated images or text

        # Stores  the ttk Label objects which have an assigned image property
        self.imageLabels = []
        # Stores  the ttk Label objects which have some assigned text property
        # TODO: Determine whether textvariable Label objects should also be included within the array for text Labels,
        #       and/or vice versa, or kept mutually exclusive from one another
        self.textLabels = []
        # Stores  the ttk Label objects which have some assigned textvariable property
        self.textvariableLabels = []

        # CUSTOM LABEL LISTS
        # self.photoBoxImageLabels stores each of the 4 Labels which hold images for each of the 4 "photoBox*" frames
        self.photoBoxImageLabels = []

        # I N I T I A L I Z A T I O N     O F     B U T T O N - R E L A T E D     V A R I A B L E S
        # GENERAL BUTTON LIST
        # Stores all of the ttk Button objects that belong to the GUI
        self.buttons = []

        # CUSTOM BUTTON LISTS
        # Stores each of the buttons that fall within any of the Control Box frames in CenterContent
        self.controlBoxButtons = []

        # I N I T I A L I Z A T I O N     O F    R A D I O B U T T O N - R E L A T E D     V A R I A B L E S
        # GENERAL RADIOBUTTON LIST
        # Stores all of the ttk Radiobutton objects that belong to the GUI
        self.radiobuttons = []

        # CUSTOM RADIOBUTTON LISTS
        # Stores each of the Radiobuttons that fall within any of the Control Box frames in CenterContent
        self.controlBoxRadiobuttons = []

        # I N I T I A L I Z A T I O N     O F    C H E C K B U T T O N - R E L A T E D     V A R I A B L E S
        # GENERAL CHECKBUTTON LIST
        # Stores all of the ttk Checkbutton objects that belong to the GUI
        self.checkbuttons = []

        # CUSTOM CHECKBUTTON LISTS
        # Stores each of the Checkbuttons that fall within any of the Control Box frames in CenterContent
        self.controlBoxCheckbuttons = []

        # I N I T I A L I Z A T I O N     O F    C O M B O B O X - R E L A T E D     V A R I A B L E S
        # GENERAL COMBOBOX LIST
        # Stores all of the ttk Combobox objects that belong to the GUI
        self.comboboxes = []

        # CUSTOM COMBOBOX LISTS
        # Stores each of the Comboboxes that fall within any of the Control Box frames in CenterContent
        self.controlBoxComboboxes = []

        # C O N T A I N E R     C L A S S     I N I T I A L I Z A T I O N
        # NOTE: THIS SHOULD ONLY BE DONE AFTER DEFINING THE EMPTY LISTS ABOVE, JUST IN CASE A CONSTRUCTOR NEEDS ACCESS

        # DimensionContainer instance must exist before self.styleObj or self.edit are initialized!
        self.dims = dimension_container.DimensionContainer(self)
        self.stateObj = state_container.StateContainer(self)
        # StyleContainer.__init__() depends on self.dims so self.dims MUST be initialized already!
        self.styleObj = style_container.StyleContainer(self)
        # EditContainer.__init__() depends on self.dims so self.dims MUST be initialized already!
        self.edit = edit_container.EditContainer(self)
        # TODO: Replace INPUT_IMAGE_PATHS_FILE with runtime user input, the entire reason it's passed in by the GUI
        self.img = image_container.ImageContainer(self, INPUT_IMAGE_PATHS_FILE)
        # Depends on a variety of things having already been defined, including dimensions and images
        #  - For this reason, it's probably best to keep CommandContainer last in the instantiation order
        self.cmd = command_container.CommandContainer(self)

        # C O N F I G U R I N G     A D D I T I O N A L     G U I     P R O P E R T I E S

        # It's completely fine for these to be hard-coded as it's not anything the user should have or need control over
        self.iconbitmap(default='media/hficon.ico')
        self.wm_title("hypnic-functions GUI Client")
        # NOTE: The line below can be uncommented in order to force a specific set of window dimensions
        # self.minsize(width=self.dims.windowWidth, height=self.dims.windowHeight)
        self.maxsize(width=self.dims.windowWidth, height=self.dims.windowHeight)
        self.state('zoomed')

        # Calls functions related to constructing the GUI and initializes associated values
        # The following must be done before calling defineGrid():
        self.defineGrid()
        # The following must be done before calling colorFrames():
        self.colorFrames()
        # The following must be done before calling fillGrid():
        self.fillGrid()
        # The following must be done before calling styleWidgets():
        self.styleWidgets()

        # T I M I N G - R E L A T E D

        # TODO: TimingContainer SHOULD BE initialized first, and right at the beginning of the function
        #   A. However, due to the fact that it currently loads its own image (a legacy of when it was a standalone
        #      program as hypnic7.py
        #   B. Need to edit normal_math_timing.py and timing_container.py to not use its own images on initialization
        self.time = timing_container.TimingContainer(self)

    # Defines the GUI layout using tkinter's grid() and Frame() modules
    def defineGrid(self):

        # tempList is a temporary list used to store elements which will be appended to member variable lists which
        #   contain relevant ttk objects such as self.frames, self.widgets, etc.
        # This is being done as a best practice for code readability as things can get ugly when dealing with appends
        #   to more than just one of the member variable lists
        tempList = []

        # FRAMES WHICH ARE CHILDREN OF THE WINDOW AS A WHOLE
        # Defines the main 4 containers: Top Toolbar, Main Content, Bottom Toolbar, and Bottom Infobar
        self.topToolbar = tkinter.ttk.Frame(self, height=self.dims.topToolbarHeight)
        self.mainContent = tkinter.ttk.Frame(self)
        self.bottomToolbar = tkinter.ttk.Frame(self, height=self.dims.bottomToolbarHeight)
        self.bottomInfobar = tkinter.ttk.Frame(self, height=self.dims.bottomInfobarHeight)

        # Specifies that mainContent is the (only) row which should have expansion priority
        self.grid_rowconfigure(1, weight=1)
        # Specifies that column 0 (the only column, containing all of the 4 main frames) should expand to maximum width
        # This is important so that columns within the frames of each mainContent row have proper width behavior
        self.grid_columnconfigure(0, weight=1)

        # Populates templist with the newly defined frames
        tempList = [self.topToolbar, self.mainContent, self.bottomToolbar, self.bottomInfobar]
        # Iterates through the newly-defined tempList, appending all values to the relevant widget lists
        for e in tempList:
            self.widgets.append(e)
            self.frames.append(e)

        # In this case because each element has separate values for padding, the current DimensionContainer framework
        # does not support iteratively calling the ttk.Frame.grid() method for the newly created frames
        # So we arrange the 4 main containers manually instead
        self.topToolbar.grid(row=0, sticky="nsew", ipadx=self.dims.topToolbarPadX,
                             ipady=self.dims.topToolbarPadY)
        self.mainContent.grid(row=1, sticky="nsew", ipadx=self.dims.mainContentPadX,
                              ipady=self.dims.mainContentPadY)
        self.bottomToolbar.grid(row=2, sticky="nsew", ipadx=self.dims.bottomToolbarPadX,
                                ipady=self.dims.bottomToolbarPadY)
        self.bottomInfobar.grid(row=3, sticky="nsew", ipadx=self.dims.bottomInfobarPadX,
                                ipady=self.dims.bottomInfobarPadY)
        # NOTE: Clearing tempList just in case!
        # TODO: See note at top of file about clearing tempList
        tempList = []

        # FRAMES WHICH ARE CHILDREN OF self.mainContent
        # Defines the 3 container frames within Main Content: Left Content, Center Content, and Right Content
        self.leftContent = tkinter.ttk.Frame(self.mainContent, width=self.dims.leftContentWidth)
        self.centerContent = tkinter.ttk.Frame(self.mainContent)
        # NOTE: Instead of hard-coding the width of rightContent, can set it relative to centerContent by removing the
        #       explicit width definition and calling grid_columnconfigure() for BOTH columns 1 AND 2
        # TODO: Consider implementing the above NOTE
        self.rightContent = tkinter.ttk.Frame(self.mainContent, width=self.dims.rightContentWidth)

        # Specifies that mainContent's row 0 (the only row) and column 1 (Center Content) have priority for space-filling
        self.mainContent.grid_rowconfigure(0, weight=1)
        self.mainContent.grid_columnconfigure(1, weight=1)

        # Populates templist with the newly defined frames
        tempList = [self.leftContent, self.centerContent, self.rightContent]
        # Iterates through the newly-defined tempList, appending all values to the relevant widget lists
        for e in tempList:
            self.widgets.append(e)
            self.frames.append(e)

        # In this case because each element has separate values for padding, the current DimensionContainer framework
        # does not support iteratively calling the ttk.Frame.grid() method for the newly created frames
        # So we arrange each of the three column containers manually
        self.leftContent.grid(row=0, column=0, sticky="nsew", ipadx=self.dims.leftContentPadX,
                              ipady=self.dims.leftContentPadY)
        self.centerContent.grid(row=0, column=1, sticky="nsew", ipadx=self.dims.centerContentPadX,
                                ipady=self.dims.centerContentPadY)
        self.rightContent.grid(row=0, column=2, sticky="nsw", ipadx=self.dims.rightContentPadX,
                               ipady=self.dims.rightContentPadY)

        # NOTE: Clearing tempList just in case!
        # TODO: See note at top of file about clearing tempList
        tempList = []

        # FRAMES WHICH ARE CHILDREN OF self.leftContent

        # Iterates through the number of rows and columns specified within dimension_container.py
        for r in range(self.dims.numPhotoBoxRows):
            for c in range(self.dims.numPhotoBoxCols):
                # Initializes (and appends to self.widgets) a new Frame with self.leftContent as a parent
                # TODO: I BELIEVE that my appending to a member variable which was initialized in __init__, all of those
                #       Frame entities should continue to exist indefinitely. But if I run into problems, this very
                #       well could be the cause and I'll have to learn more about memory management in Python OOP
                self.widgets.append(tkinter.ttk.Frame(self.leftContent,
                                                      width=self.dims.photoBoxWidth,
                                                      height=self.dims.photoBoxHeight))
                # Appends the same Frame to self.frames and self.photoBoxFrames
                self.frames.append(self.widgets[-1])
                self.photoBoxFrames.append(self.widgets[-1])
                # Specifies that the relevant row and column of self.leftContent has equal priority for space-filling
                self.leftContent.grid_rowconfigure(r, weight=1)
                self.leftContent.grid_columnconfigure(c, weight=1)
                # Specifies that the newly initialized Frame is a member of the grid cell at (row, col) in centerContent
                self.widgets[-1].grid(row=r, column=c, sticky="nsew", ipadx=self.dims.photoBoxPadX,
                                      ipady=self.dims.photoBoxPadY)

        # FRAMES WHICH ARE CHILDREN OF self.centerContent
        # Defines the individual control frames as rows within self.centerContent
        # These are not stored as directly-callable member variables but instead exist within their own list.
        #   This list, self.centerContents, is an even-more-specific list maintained IN ADDITION TO the other relevant
        #   lists like self.frames as opposed to being a replacement

        # Iterates through the number of rows and columns specified within dimension_container.py
        for r in range(self.dims.numControlBoxRows):
            for c in range(self.dims.numControlBoxCols):
                # Initializes (and appends to self.widgets) a new Frame with self.centerContent as a parent
                # TODO: I BELIEVE that my appending to a member variable which was initialized in __init__, all of those
                #       Frame entities should continue to exist indefinitely. But if I run into problems, this very
                #       well could be the cause and I'll have to learn more about memory management in Python OOP
                self.widgets.append(tkinter.ttk.Frame(self.centerContent))
                # Appends the same Frame to self.frames and self.controlBoxFrames
                self.frames.append(self.widgets[-1])
                self.controlBoxFrames.append(self.widgets[-1])
                # Specifies that the relevant row and column of self.centerContent has equal priority for space-filling
                self.centerContent.grid_rowconfigure(r, weight=1)
                self.centerContent.grid_columnconfigure(c, weight=1)
                # Specifies that the newly initialized Frame is a member of the grid cell at (row, col) in centerContent
                self.widgets[-1].grid(row=r, column=c, sticky="nsew", ipadx=self.dims.controlBoxPadX,
                                      ipady=self.dims.controlBoxPadY)

    # Colors the frames defined in self.defineGrid()
    # NOTE: Currently based on random generation because I'm not concerned about this aspect of things
    def colorFrames(self):
        for f in range(len(self.frames)):
            self.frames[f].configure(style=self.styleObj.frameStyles[f])

    # Fills the previously-defined GUI with label elements
    def fillGrid(self):
        # tempList is a temporary list used to store elements which will be appended to member variable lists which
        #   contain relevant ttk objects such as self.labels, self.imageLabels, self.buttons, etc.
        # This is being done as a best practice for code readability as things can get ugly when dealing with appends
        #   to more than just one of the member variable lists
        tempList = []

        # WIDGETS IN TOP TOOLBAR
        # WIDGETS IN MAIN CONTENT
        #  - WIDGETS IN LEFT CONTENT
        #    - WIDGETS IN PHOTO BOX FRAMES
        self.fillPhotoBoxImages()
        #  - WIDGETS IN CENTER CONTENT
        #    - WIDGETS IN CONTROL BOX FRAMES
        self.fillControlBoxButtons()
        self.fillControlBoxRadiobuttons()
        self.fillControlBoxCheckbuttons()
        self.fillControlBoxComboboxes()

    # Defines images for each of the 4 Photo Box Frames within leftContent
    def fillPhotoBoxImages(self):
        # for i in range(self.dims.numPhotoBoxRows * self.dims.numPhotoBoxCols):
        for i in range(self.dims.numPhotoBoxRows * self.dims.numPhotoBoxCols):
            # Initializes (and appends to self.widgets) a new Label with the relevant self.photoBoxFrames elt as parent
            # TODO: I BELIEVE that my appending to a member variable which was initialized in __init__, all of those
            #       Frame entities should continue to exist indefinitely. But if I run into problems, this very
            #       well could be the cause and I'll have to learn more about memory management in Python OOP
            self.widgets.append(tkinter.ttk.Label(self.photoBoxFrames[i], image=self.img.tkImages[i]))
            # Appends the same Label to self.labels, self.imageLabels, and self.photoBoxImageLabels
            self.labels.append(self.widgets[-1])
            self.imageLabels.append(self.widgets[-1])
            self.photoBoxImageLabels.append(self.widgets[-1])
            # Places the Image Label within its frame
            self.widgets[-1].place(relx=self.dims.defaultLabelPlaceRelX,
                                   rely=self.dims.defaultLabelPlaceRelY,
                                   anchor=self.dims.defaultLabelPlaceAnchor)

    # Defines buttons for each controlBox within centerContent
    def fillControlBoxButtons(self):

        # iterates from zero stopping before (number of rows multiplied by number of columns)
        for i in range(self.dims.numControlBoxRows * self.dims.numControlBoxCols):
            # Number of buttons created is defined by DimensionContainer.numControlBoxButtons
            buttonCount = self.dims.defaultControlBoxButtonCount
            if i < len(self.dims.controlBoxButtonCounts):
                buttonCount = self.dims.controlBoxButtonCounts[i]
            for n in range(buttonCount):
                # Initializes (and appends to self.widgets) a new Button with the relevant self.controlBoxFrames elt as parent
                # TODO: I BELIEVE that my appending to a member variable which was initialized in __init__, all of those
                #       Frame entities should continue to exist indefinitely. But if I run into problems, this very
                #       well could be the cause and I'll have to learn more about memory management in Python OOP
                self.widgets.append(tkinter.ttk.Button(self.controlBoxFrames[i]))
                # Appends the same Button to self.buttons, self.inputWidgets, and self.controlBoxButtons
                self.buttons.append(self.widgets[-1])
                self.inputWidgets.append(self.widgets[-1])
                self.controlBoxButtons.append(self.widgets[-1])
                self.widgets[-1].grid(row=n, column=0, sticky="nsew", ipadx=self.dims.controlBoxPadX,
                   ipady=self.dims.controlBoxPadY)

                """
                # Places the Button within its frame
                self.widgets[-1].place(relx=self.dims.controlBoxButtonPlaceRelX,
                                       rely=((n + 1) / (buttonCount + 1)),
                                       anchor=self.dims.controlBoxButtonPlaceAnchor)
                """

        # CONFIGURING TEXT for each BUTTON in self.controlBoxButtons
        # Multiple properties can be changed with a single call of configure(), but I'm often
        #   keeping things separate because this content is later going to be split up between many functions
        # For the time being, if I want to set human-defined button text within the code I could create a list where
        #   each element is a string and the number of elements is equal to the number of buttons, etc.
        # TODO: Either use the variable below or get rid of it entirely
        # TODO: Actually consider making wider-scoped "buttonStrings"-type of list variables
        # Initialized as a list of empty strings, where length is equal to the number of cells in centerContent
        self.controlBoxButtonStrings = [""] * len(self.controlBoxButtons)
        # Manual definition of button text
        # NOTE: Doesn't really belong in this file at all, let alone here
        # TODO: Remedy the above note by storing button text information in a new file, likely another custom class
        self.controlBoxButtonStrings[0] = "Load A"
        self.controlBoxButtonStrings[1] = "Load B"
        self.controlBoxButtonStrings[2] = "Load C"
        self.controlBoxButtonStrings[3] = "Load D"

        self.controlBoxButtonStrings[4] = "Save A"
        self.controlBoxButtonStrings[5] = "Save B"
        self.controlBoxButtonStrings[6] = "Save C"
        self.controlBoxButtonStrings[7] = "Save D"

        self.controlBoxButtonStrings[8] = "Undo A"
        self.controlBoxButtonStrings[9] = "Undo B"
        self.controlBoxButtonStrings[10] = "Undo C"
        self.controlBoxButtonStrings[11] = "Undo D"

        self.controlBoxButtonStrings[12] = "Redo A"
        self.controlBoxButtonStrings[13] = "Redo B"
        self.controlBoxButtonStrings[14] = "Redo C"
        self.controlBoxButtonStrings[15] = "Redo D"

        self.controlBoxButtonStrings[16] = "Scale A"
        self.controlBoxButtonStrings[17] = "Scale B"
        self.controlBoxButtonStrings[18] = "Scale C"
        self.controlBoxButtonStrings[19] = "Scale D"

        self.controlBoxButtonStrings[20] = "Apply A"
        self.controlBoxButtonStrings[21] = "Apply B"
        self.controlBoxButtonStrings[22] = "Apply C"
        self.controlBoxButtonStrings[23] = "Apply D"

        # Sets any still-undefined strings to "Button [N]" where [N] is the current value of i
        # s is the string and i is the index of that string within self.controlBoxButtonStrings
        for i, s in enumerate(self.controlBoxButtonStrings):
            if s == "":
                self.controlBoxButtonStrings[i] = "Button " + str(i)

        # Uses the newly-completed list of strings to configure each item in self.controlBoxButtons
        for i, b in enumerate(self.controlBoxButtons):
            self.controlBoxButtons[i].configure(text=self.controlBoxButtonStrings[i])

        # CONFIGURING COMMANDS for each BUTTON in self.controlBoxButtons
        for i, b in enumerate(self.controlBoxButtons):
            b.configure(command=partial(self.cmd.cmdButtonDefault, i))

        # Overwrites with some custom commands
        self.controlBoxButtons[0].configure(command=partial(self.cmd.cmdButtonLoad, 0))
        self.controlBoxButtons[1].configure(command=partial(self.cmd.cmdButtonLoad, 1))
        self.controlBoxButtons[2].configure(command=partial(self.cmd.cmdButtonLoad, 2))
        self.controlBoxButtons[3].configure(command=partial(self.cmd.cmdButtonLoad, 3))
        self.controlBoxButtons[4].configure(command=partial(self.cmd.cmdButtonSave, 0))
        self.controlBoxButtons[5].configure(command=partial(self.cmd.cmdButtonSave, 1))
        self.controlBoxButtons[6].configure(command=partial(self.cmd.cmdButtonSave, 2))
        self.controlBoxButtons[7].configure(command=partial(self.cmd.cmdButtonSave, 3))
        self.controlBoxButtons[8].configure(command=partial(self.cmd.cmdButtonUndo, 0))
        self.controlBoxButtons[9].configure(command=partial(self.cmd.cmdButtonUndo, 1))
        self.controlBoxButtons[10].configure(command=partial(self.cmd.cmdButtonUndo, 2))
        self.controlBoxButtons[11].configure(command=partial(self.cmd.cmdButtonUndo, 3))
        self.controlBoxButtons[12].configure(command=partial(self.cmd.cmdButtonRedo, 0))
        self.controlBoxButtons[13].configure(command=partial(self.cmd.cmdButtonRedo, 1))
        self.controlBoxButtons[14].configure(command=partial(self.cmd.cmdButtonRedo, 2))
        self.controlBoxButtons[15].configure(command=partial(self.cmd.cmdButtonRedo, 3))
        self.controlBoxButtons[16].configure(command=partial(self.cmd.cmdButtonScale, 0))
        self.controlBoxButtons[17].configure(command=partial(self.cmd.cmdButtonScale, 1))
        self.controlBoxButtons[18].configure(command=partial(self.cmd.cmdButtonScale, 2))
        self.controlBoxButtons[19].configure(command=partial(self.cmd.cmdButtonScale, 3))
        # TODO: Update these so that the second argument isn't necessarily equal to the first
        #        - NOTE: This may involve reducing the number of arguments to cmdButtonApply() and instead specifying
        #                things like primary/secondary input image indices through radiobuttons
        self.controlBoxButtons[20].configure(command=partial(self.cmd.cmdButtonApply, 0))
        self.controlBoxButtons[21].configure(command=partial(self.cmd.cmdButtonApply, 1))
        self.controlBoxButtons[22].configure(command=partial(self.cmd.cmdButtonApply, 2))
        self.controlBoxButtons[23].configure(command=partial(self.cmd.cmdButtonApply, 3))

    # Defines Radiobuttons for each controlBox within centerContent
    def fillControlBoxRadiobuttons(self):

        # iterates from zero stopping before (number of rows multiplied by number of columns)
        for i in range(self.dims.numControlBoxRows * self.dims.numControlBoxCols):
            # Number of radiobuttons created is defined by DimensionContainer.numControlBoxRadiobuttons
            radiobuttonCount = self.dims.defaultControlBoxRadiobuttonCount
            if i < len(self.dims.controlBoxRadiobuttonCounts):
                radiobuttonCount = self.dims.controlBoxRadiobuttonCounts[i]
            for n in range(radiobuttonCount):
                # Initializes (and appends to self.widgets) a new Radiobutton with the relevant Frame as the parent
                self.widgets.append(tkinter.ttk.Radiobutton(self.controlBoxFrames[i]))
                # Appends the same Radiobutton to self.radiobuttons, self.inputWidgets, and self.controlBoxImageLabels
                self.radiobuttons.append(self.widgets[-1])
                self.inputWidgets.append(self.widgets[-1])
                self.controlBoxRadiobuttons.append(self.widgets[-1])
                # NOTE: A column value of 1 is used for Radiobuttons, as opposed to the 0 used for Buttons
                self.widgets[-1].grid(row=n, column=1, sticky="nsew", ipadx=self.dims.controlBoxPadX,
                                      ipady=self.dims.controlBoxPadY)

        # CONFIGURING TEXT for each RADIOBUTTON in self.controlBoxRadiobuttons
        # Initialized as a list of empty strings, where length is equal to the number of cells in centerContent
        self.controlBoxRadiobuttonStrings = [""] * len(self.controlBoxRadiobuttons)
        # Manual definition of radiobutton text
        # NOTE: Doesn't really belong in this file at all, let alone here
        # TODO: Remedy the above note by storing radiobutton text information in a new file, likely another custom class
        self.controlBoxRadiobuttonStrings[:10] = ["Fill",
                                                  "Grayscale",
                                                  "Add",
                                                  "Subtract",
                                                  "Copy",
                                                  "Swap",
                                                  "Average",
                                                  "Multiply",
                                                  "Divide",
                                                  "Snow"]
        self.controlBoxRadiobuttonStrings[10:14] = ["Primary A",
                                                    "Primary B",
                                                    "Primary C",
                                                    "Primary D",]
        self.controlBoxRadiobuttonStrings[14:18] = ["Secondary A",
                                                    "Secondary B",
                                                    "Secondary C",
                                                    "Secondary D", ]

        # Sets any still-undefined strings to "Radio [N]" where [N] is the current value of i
        # s is the string and i is the index of that string within self.controlBoxRadiobuttonStrings
        for i, s in enumerate(self.controlBoxRadiobuttonStrings):
            if s == "":
                self.controlBoxRadiobuttonStrings[i] = "Radio " + str(i)

        # Uses the newly-completed list of strings to configure each item in self.controlBoxRadiobuttons
        for i, b in enumerate(self.controlBoxRadiobuttons):
            b.configure(text=self.controlBoxRadiobuttonStrings[i])

        # CONFIGURING COMMANDS for each RADIOBUTTON in self.controlBoxRadiobuttons
        for i, b in enumerate(self.controlBoxRadiobuttons[:10]):
            b.configure(command=partial(self.cmd.cmdRadiobuttonSetManipType, i))

        # Configures state variables for some of the radiobuttons
        # Also attaches the variables to the widget reference objects, as described in the following reference:
        # http://effbot.org/tkinterbook/checkbutton.htm
        for i in range(10):
            self.controlBoxRadiobuttons[i].configure(variable=self.stateObj.raManipType, value=i)
            self.controlBoxRadiobuttons[i].var = self.stateObj.raManipType
        for i in range(10, 14):
            # NOTE: (i - 10) is inherently based on this hard-coded stuff. TODO: Clean up eventually
            self.controlBoxRadiobuttons[i].configure(variable=self.stateObj.raPrimaryInputImage, value=(i - 10))
            self.controlBoxRadiobuttons[i].var = self.stateObj.raPrimaryInputImage
        for i in range(14, 18):
            # NOTE: (i - 14) is inherently based on this hard-coded stuff. TODO: Clean up eventually
            self.controlBoxRadiobuttons[i].configure(variable=self.stateObj.raSecondaryInputImage, value=(i - 14))
            self.controlBoxRadiobuttons[i].var = self.stateObj.raSecondaryInputImage

    # Defines Checkbuttons for each controlBox within centerContent
    def fillControlBoxCheckbuttons(self):

        # iterates from zero stopping before (number of rows multiplied by number of columns)
        for i in range(self.dims.numControlBoxRows * self.dims.numControlBoxCols):
            # Number of checkbuttons created is defined by DimensionContainer.numControlBoxCheckbuttons
            checkbuttonCount = self.dims.defaultControlBoxCheckbuttonCount
            if i < len(self.dims.controlBoxCheckbuttonCounts):
                checkbuttonCount = self.dims.controlBoxCheckbuttonCounts[i]
            for n in range(checkbuttonCount):
                # Initializes (and appends to self.widgets) a new Checkbutton with the relevant Frame as the parent
                self.widgets.append(tkinter.ttk.Checkbutton(self.controlBoxFrames[i]))
                # Appends the same Checkbutton to self.checkbuttons, self.inputWidgets, and self.controlBoxImageLabels
                self.checkbuttons.append(self.widgets[-1])
                self.inputWidgets.append(self.widgets[-1])
                self.controlBoxCheckbuttons.append(self.widgets[-1])
                # NOTE: A column value of 2 is used for Checkbuttons, as opposed to the 1/0 used by Radio/Buttons
                # NOTE: A row value of (n + 1) is used to ensure that checkbuttons appear below the comboboxes in row 0
                #  - This is not meant to be permanent and is just a quick fix for earlier versions of the program
                #  - TODO: Define actual widget rows correctly for each control box, instead of this (n + 1) method
                self.widgets[-1].grid(row=(n + 1), column=2, sticky="nsew", ipadx=self.dims.controlBoxPadX,
                                      ipady=self.dims.controlBoxPadY)

        # CONFIGURING TEXT for each CHECKBUTTON in self.controlBoxCheckbuttons
        # Initialized as a list of empty strings, where length is equal to the number of cells in centerContent
        self.controlBoxCheckbuttonStrings = [""] * len(self.controlBoxCheckbuttons)
        # Manual definition of checkbutton text
        # NOTE: Doesn't really belong in this file at all, let alone here
        # TODO: Remedy the above note by storing checkbutton text information in a new file, likely another custom class
        for i in range(20):  # FLAG: Hard-coded GUI parameter!
            self.controlBoxCheckbuttonStrings[i] = "Check " + chr(65 + i)

        # Sets any still-undefined strings to "Check [N]" where [N] is the current value of i
        # s is the string and i is the index of that string within self.controlBoxCheckbuttonStrings
        for i, s in enumerate(self.controlBoxCheckbuttonStrings):
            if s == "":
                self.controlBoxCheckbuttonStrings[i] = "Check " + str(i)

        # Custom Checkbutton String definitions
        self.controlBoxCheckbuttonStrings[0] = "Output Red Channel"
        self.controlBoxCheckbuttonStrings[1] = "Output Green Channel"
        self.controlBoxCheckbuttonStrings[2] = "Output Blue Channel"
        self.controlBoxCheckbuttonStrings[3] = "Red Channel In"
        self.controlBoxCheckbuttonStrings[4] = "Green Channel In"
        self.controlBoxCheckbuttonStrings[5] = "Blue Channel In"
        self.controlBoxCheckbuttonStrings[6] = "Red Channel In"
        self.controlBoxCheckbuttonStrings[7] = "Green Channel In"
        self.controlBoxCheckbuttonStrings[8] = "Blue Channel In"
        self.controlBoxCheckbuttonStrings[9] = "Red Channel In"
        self.controlBoxCheckbuttonStrings[10] = "Green Channel In"
        self.controlBoxCheckbuttonStrings[11] = "Blue Channel In"
        self.controlBoxCheckbuttonStrings[12] = "Wrap Colors"

        # Uses the newly-completed list of strings to configure text for each item in self.controlBoxCheckbuttons
        for i, b in enumerate(self.controlBoxCheckbuttons):
            b.configure(text=self.controlBoxCheckbuttonStrings[i])

        # Configures state variables for some of the checkbuttons
        # Also attaches the variables to the widget reference objects, as described in the following reference:
        # http://effbot.org/tkinterbook/checkbutton.htm
        #     NOTE: Be sure to use the get() method

        # CONFIGURING COMMANDS for each CHECKBUTTON in self.controlBoxCheckbuttons
        for i, b in enumerate(self.controlBoxCheckbuttons):
            b.configure(command=partial(self.cmd.cmdCheckbuttonDefault, i))

        # Custom Checkbutton Configurations
        self.controlBoxCheckbuttons[0].configure(variable=self.stateObj.chPrimaryOutputRedChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[0].var = self.stateObj.chPrimaryOutputRedChannel
        self.controlBoxCheckbuttons[1].configure(variable=self.stateObj.chPrimaryOutputGreenChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[1].var = self.stateObj.chPrimaryOutputGreenChannel
        self.controlBoxCheckbuttons[2].configure(variable=self.stateObj.chPrimaryOutputBlueChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[2].var = self.stateObj.chPrimaryOutputBlueChannel
        self.controlBoxCheckbuttons[3].configure(variable=self.stateObj.chPrimaryInputRedChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[3].var = self.stateObj.chPrimaryInputRedChannel
        self.controlBoxCheckbuttons[4].configure(variable=self.stateObj.chPrimaryInputGreenChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[4].var = self.stateObj.chPrimaryInputGreenChannel
        self.controlBoxCheckbuttons[5].configure(variable=self.stateObj.chPrimaryInputBlueChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[5].var = self.stateObj.chPrimaryInputBlueChannel
        self.controlBoxCheckbuttons[6].configure(variable=self.stateObj.chSecondaryInputRedChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[6].var = self.stateObj.chSecondaryInputRedChannel
        self.controlBoxCheckbuttons[7].configure(variable=self.stateObj.chSecondaryInputGreenChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[7].var = self.stateObj.chSecondaryInputGreenChannel
        self.controlBoxCheckbuttons[8].configure(variable=self.stateObj.chSecondaryInputBlueChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[8].var = self.stateObj.chSecondaryInputBlueChannel
        self.controlBoxCheckbuttons[9].configure(variable=self.stateObj.chTertiaryInputRedChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[9].var = self.stateObj.chTertiaryInputRedChannel
        self.controlBoxCheckbuttons[10].configure(variable=self.stateObj.chTertiaryInputGreenChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[10].var = self.stateObj.chTertiaryInputGreenChannel
        self.controlBoxCheckbuttons[11].configure(variable=self.stateObj.chTertiaryInputBlueChannel, onvalue=1, offvalue=0)
        self.controlBoxCheckbuttons[11].var = self.stateObj.chTertiaryInputBlueChannel
        self.controlBoxCheckbuttons[12].configure(variable=self.stateObj.chWrapColors, onvalue=1, offvalue=0)
        # NOTE: The line directly below serves no current purpose other than to maintain that ch commands are possible
        self.controlBoxCheckbuttons[12].configure(
            command=partial(self.cmd.cmdCheckbuttonWrapColors, 333))  # FLAG: Hard-coded GUI parameter!
        self.controlBoxCheckbuttons[12].var = self.stateObj.chWrapColors

    # Defines Comboboxes for each controlBox within centerContent
    def fillControlBoxComboboxes(self):

        # Generates the tuple representing the choices available within each dropdown
        #   Specifically, a list of consecutive characters beginning with "A"
        imageChoiceList = [chr(n + 65) for n in range(self.dims.numPhotoBoxRows * self.dims.numPhotoBoxCols)]

        # iterates from zero stopping before (number of rows multiplied by number of columns)
        for i in range(self.dims.numControlBoxRows * self.dims.numControlBoxCols):
            # Number of comboboxes created is defined by DimensionContainer.numControlBoxComboboxes
            comboboxCount = self.dims.defaultControlBoxComboboxCount
            if i < len(self.dims.controlBoxComboboxCounts):
                comboboxCount = self.dims.controlBoxComboboxCounts[i]
            for n in range(comboboxCount):
                # Initializes (and appends to self.widgets) a new Combobox with the relevant Frame as the parent
                # state is set to "readonly" so that the user can only choose from pre-defined options
                # Also provides the list of choices generated prior to this for loop block
                self.widgets.append(tkinter.ttk.Combobox(self.controlBoxFrames[i], state="readonly", values=imageChoiceList))
                # Configures the first (0th) element to be selected upon initialization
                self.widgets[-1].current(0)
                # Appends the same Combobox to self.comboboxes, self.inputWidgets, and self.controlBoxImageLabels
                self.comboboxes.append(self.widgets[-1])
                self.inputWidgets.append(self.widgets[-1])
                self.controlBoxComboboxes.append(self.widgets[-1])
                # NOTE: A column value of 2 is used for Comboboxes, as opposed to the 1/0 used by Radio/Buttons
                self.widgets[-1].grid(row=n, column=2, sticky="nsew", ipadx=self.dims.controlBoxPadX,
                                      ipady=self.dims.controlBoxPadY)

    # Sets the necessary style parameters for each ttk-specific widget
    def styleWidgets(self):
        print("PLACEHOLDER FOR CONTENT WITHIN THE HypnicGUI.styleWidgets() function")


from hive_worker_hot_coffee.parsers.manual_parser.qyxg_xzcf.sc_l_tax_base import SC_l_tax_base

class Parser__qyxg_xzcf__gzz_l_tax(SC_l_tax_base):
    """甘孜州"""
    key_word_map = {
        '行政处罚决定文书号': 'punish_code',
        '行政处罚决定书文号': 'punish_code',
        '政处罚决定文书号': 'punish_code',
        '行政处罚文书号': 'punish_code',

        '处罚名称': 'case_name',
        '处罚类别': 'punish_category', '处罚类别1': 'punish_category',
        '罚类别': 'punish_category',
        '处罚事由': 'punish_type',
        '处罚依据': 'punish_basis',
        '行政相对人名称': 'company_name', '行政相对人名': 'company_name',

        # '行政相对人代码-1': 'credit_code',
        '（统一社会信用代码）': 'credit_code',
        '行政相对人代码-1（统一社会信用代码）': 'credit_code',
        '行政相对人代码/1（统一社会信用代码）': 'credit_code', '行统一社会信用代码': 'credit_code',
        '统一社会信用代码': 'credit_code',
        '统一社会代码': 'credit_code',
        '行政相对人代码-1（社会统一信用代码）': 'credit_code',
        '行政相对人代码（统一社会信用代码）': 'credit_code', '统一社会信用代': 'credit_code', '行政相对人代码1（统一社会信用代码）': 'credit_code',

        '行政相对人统一社会信用代码（纳税人识别号）': 'credit_code',  # 需要特殊处理
        '统一社会信用代码（纳税人识别号）': 'credit_code',  # 需要特殊处理
        '纳税人识别号（统一社会信用代码）': 'credit_code',  # 需要特殊处理
        '纳税人识别号（统一社会信息代码）': 'credit_code',  # 需要特殊处理，乐山

        '行政相对人代码-2（组织机构代码）': 'organization_code',
        '行政相对人代码/2（组织机构代码）': 'organization_code',
        # '行政相对人代码-2': 'organization_code',

        '（纳税人识别号）': 'tax_code',
        '行政相对人代码-3': 'tax_code',
        '行政相对人代码-3（纳税人识别号）': 'tax_code',
        '行政相对人代码/3（纳税人识别号）': 'tax_code',
        '统一社会信用代码（纳税人识别码）': 'tax_code',
        '纳税人识别号': 'tax_code',
        '行政相对人代码（纳税人识别号）': 'tax_code',

        '行政相对人代码-4（居民身份证号）': 'id_number',
        '行政相对人代码/4（居民身份证号）': 'id_number',
        '（居民身份证）': 'id_number',
        '行政相对人代码-4 ': 'id_number',
        '行政相对人代码-4': 'id_number',

        '法定代表人姓名': 'frname',
        '法定代表人': 'frname',
        '处罚结果': 'punish_content',
        '兴处罚决定日期': 'punish_date',
        '处罚决定日期': 'punish_date', '处罚日期': 'punish_date',
        '处罚机关': 'punish_org',
        '当前状态': 'punish_status',
        '地方编码': 'administrative_code',
        '数据更新时间': 'update',
        '数据更新时间戳': 'update',
        '公示期限': 'public_period',
        '备注': 'remark',

    }


import heapq
from collections import namedtuple

Task = namedtuple("Task", ["priority", "name"])

class Tasks:
    def __init__(self):
        self.heap = []

    def add(self, name, priority):
        heapq.heappush(self.heap, Task(-1 * priority, name))

    def next(self):
        return heapq.heappop(self.heap).name

if __name__ == "__main__":
    t = Tasks()
    t.add("siivous", 10)
    t.add("ulkoilu", 50)
    t.add("opiskelu", 50)
    print(t.next())  # opiskelu
    t.add("treffit", 100)
    print(t.next())  # treffit
    print(t.next())  # ulkoilu


import boto3
import os

def storageClient():
    dynamodbClient = boto3.client(
        'dynamodb',
        region_name=os.getenv('DYNAMO_AWS_REGION'),
        aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
        aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY'),
        endpoint_url=os.getenv('DYNAMO_ENDPOINT_URL'),
    )
    return dynamodbClient

def storageResource():
    dynamodb = boto3.resource(
        'dynamodb',
        region_name=os.getenv('DYNAMO_AWS_REGION'),
        aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
        aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY'),
        endpoint_url=os.getenv('DYNAMO_ENDPOINT_URL'),
    )

    dynamodb.meta.client.meta.config.connect_timeout = 10
    dynamodb.meta.client.meta.config.read_timeout = 25

    return dynamodb

def storage(table):
    dynamo = storageResource()

    return dynamo.Table(table)


'''
Given an array of strings, group anagrams together.

Example:

Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]
Note:

All inputs will be in lowercase.
The order of your output does not matter.
'''

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        anagrams = {}
        result = []

        for word in strs:
            order = list(word)
            order.sort()
            key = ''.join(order)
            if key in anagrams: anagrams[key].append(word)
            else: anagrams[key]=[word]

        for key, val in anagrams.items(): result.append(val)

        return result

#Store anagrams in hashmap based key that is the sorted version of the word which by definition should be the same for anagrams


budget = float(input())
season = input()
is_hotel = False
is_camp = False
location = ''
costs = 0

if 0 < budget <= 100:
    location = 'Bulgaria'
    if season == 'summer':
        costs = budget * 0.3
        is_camp = True
    elif season == 'winter':
        costs = budget * 0.7
        is_hotel = True
elif 100 < budget <= 1000:
    location = 'Balkans'
    if season == 'summer':
        costs = budget * 0.4
        is_camp = True
    elif season == 'winter':
        costs = budget * 0.8
        is_hotel = True
elif budget > 1000:
    location = 'Europe'
    costs = budget * 0.9
    is_hotel = True

if is_hotel:
    print(f'Somewhere in {location}\n'
          f'Hotel - {costs:.2f}')
elif is_camp:
    print(f'Somewhere in {location}\n'
          f'Camp - {costs:.2f}')


"""Using Generators"""
import itertools

print('Ex 4.1.2')

def translate(sentence):
    words = {'esta': 'is', 'la': 'the', 'en': 'in', 'gato': 'cat', 'casa': 'house', 'el': 'the'}
    translation_gen = (words[w] for w in sentence.split())
    translated = ' '.join(translation_gen)
    return translated

print(translate("el gato esta en la casa"))

print('\nEx 4.1.2')

def is_prime(n: int):
    if n <= 1:
        return False

    for i in range(2, n):
        if n % i == 0:
            return False

    return True

def next_numbers(n: int):
    while True:
        n += 1
        yield n

def first_prime_over(n):
    # prime_generator = (num for num in range(n, 10 ** 100))
    # for next_num in prime_generator:
    for next_num in next_numbers(n):
        # print(f'No checking: {next_num}')
        if is_prime(next_num):
            return next_num

print(first_prime_over(1000000))

# print('\npermutate')
#
#
# def permutate(seq):
#     """permutate a sequence and return a list of the permutations"""
#     if not seq:
#         return [seq]
#     else:
#         temp_perm = []
#         for i in range(len(seq)):
#             part = seq[:i] + seq[i+1:]
#             # print(f'seq: {seq} - part: {part} (seq[:{i}]: {seq[:i]}; seq[i+1:]: {seq[i+1:]})')
#             for p in permutate(part):
#                 temp_perm.append(seq[i:i+1] + p)
#         return temp_perm
#
#
# print(permutate([0, 5, 2]))

print('\nEx 4.2.2')

def parse_ranges(ranges_string):
    range_segments = (map(int, seg.split('-')) for seg in ranges_string.split(','))
    one_range = (num for start, end in range_segments for num in range(start, end + 1))
    return one_range

print(list(parse_ranges("1-2,4-4,8-10")))
print(list(parse_ranges("0-0,4-8,20-21,43-45")))

print('\nEx 4.3.4')

def get_fibo():
    n1, n2 = 0, 1
    while True:
        yield n1
        n1, n2 = n2, n1 + n2

fibo_gen = get_fibo()
print(next(fibo_gen))
print(next(fibo_gen))
print(next(fibo_gen))
print(next(fibo_gen))

print('\nEx 4.3.4')

def gen_secs():
    for sec in range(60):
        yield sec

def gen_minutes():
    for minute in range(60):
        yield minute

def gen_hours():
    for hour in range(24):
        yield hour

def gen_time():
    for h in gen_hours():
        for m in gen_minutes():
            for s in gen_secs():
                yield f'{h:02}:{m:02}:{s:02}'

# for gt in gen_time():
#     print(gt)

def gen_years(start=2019):
    year = start
    while True:
        yield year
        year += 1

def gen_months():
    for mon in range(1, 13):
        yield mon

def gen_days(month, leap_year=True):
    this_month_days = 31
    if month in (4, 6, 9, 11):
        this_month_days = 30
    elif 2 == month:
        this_month_days = 29 if leap_year else 28

    for day in range(1, this_month_days + 1):
        yield day

def gen_date():
    for y in gen_years():
        for mon in gen_months():
            leap_year = True if y % 4 == 0 and (y % 100 != 0 or y % 400 == 0) else False
            for d in gen_days(mon, leap_year):
                for time in gen_time():
                    yield f'{d:02}/{mon:02}/{y} {time}'

date_gen = gen_date()
for i in range(1000000 * 10):
    timestamp = next(date_gen)
    if i % 1000000 == 0:
        print(timestamp)


import numpy as np
import os
import torch
import torch.nn as nn
from imageio import imread
from PIL import Image
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, utils
from torchvision.transforms import RandomCrop, Resize, ToTensor, Normalize
import matplotlib.pyplot as plt
from alexnet import AlexNet, AlexNetSelf, AlexNetSelf_deep
from functions import ourTrain
from Datasets import ClassesDataset
from torch.optim.lr_scheduler import StepLR
folder_name = "/var/tmp/st9_data/"
# Hyperparameters
model_save_name = 'ss_deep_1_clsf_1'
model_load_name = 'ss_deep_1'
load = True
save = True
lr=0.001
in_size = 227
tile_size = 75
batch_size = 64
n_epochs = 15
num_classes = 48
step_size = 5
gamma = 0.3
########

train_dataset = ClassesDataset(folder_name+"dataset2/train/",in_size=in_size, num_classes=num_classes)
val_dataset = ClassesDataset(folder_name+"dataset2/val",in_size=in_size, num_classes=num_classes)
test_dataset = ClassesDataset(folder_name+"dataset2/test",in_size=in_size, num_classes=num_classes)
print("len train dataset: ", len(train_dataset))
print("len val dataset: ", len(val_dataset))
print("len test dataset: ", len(test_dataset))

train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=4)
val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=True, num_workers=4)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True, num_workers=4)

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print('Device: ' + ('gpu' if torch.cuda.is_available() else 'cpu'))

model = AlexNetSelf_deep(tile_size,in_size,selftrain=False,num_classes=num_classes)
model = model.to(device)
optimizer = torch.optim.Adam(model.parameters(),lr=lr,weight_decay=0.001)
loss_function = nn.CrossEntropyLoss()
scheduler = StepLR(optimizer, step_size=step_size, gamma=gamma)

train_losses, val_losses, train_accuracies_1, train_accuracies_3, train_accuracies_5, val_accuracies_1, \
val_accuracies_3, val_accuracies_5 = ourTrain(model, train_loader, val_loader, optimizer, loss_function, scheduler,
                                                        device=device, saveWeights=save, saving_path="models/model_"+model_save_name,
                                                        loadWeights=load, loading_path='models/model_'+model_load_name,
                                                        print_every=100, n_epochs=n_epochs, folder_name=folder_name)

results = np.zeros((n_epochs,8))
results[:,0]=train_losses
results[:,1]=val_losses
results[:,2]=train_accuracies_1
results[:,3]=train_accuracies_3
results[:,4]=train_accuracies_5
results[:,5]=val_accuracies_1
results[:,6]=val_accuracies_3
results[:,7]=val_accuracies_5

np.savetxt(folder_name+'experiments/exp_'+str(model_load_name)+'_to_'
           +str(model_save_name)+'_lr='+str(lr)+'_step='+str(step_size)+'_gamma='+str(gamma)+'_nclasses='+str(num_classes)+'_nepochs='+str(n_epochs)+'.txt', results, fmt='%s')


import numpy as np
import matplotlib.pyplot as plt

def l_Ir(ll_r,ll_m):
    print("ll_r")
    print(ll_r.shape)
    print("ll_m")
    print(ll_m)
    #ll_r_T=np.transpose(ll_r,(1,0))
    t0=np.matmul(ll_r.T,ll_r)
    #print(t0[np.nonzero(t0)])
    t1=np.linalg.inv(np.matmul(ll_r.T,ll_r))
    print("t1")
    print(t1)
    t2=np.matmul(t1,ll_r.T)
    print("t2")
    print(t2)
    ll_Ir=np.matmul(t2,ll_m)
    print("answer!")
    print(ll_Ir)
    return ll_Ir

#Data file visibilities will be pulled from
datams='sgr_apr07_flagcor.ms'
ms.open(datams,nomodify=True)

#Collect data from ms
visdata = ms.getdata(['antenna1','antenna2','data','data_desc_id','axis_info'],ifraxis=True)
visdata['data'] = np.squeeze(visdata['data'])
ms.close()

print(len(visdata['axis_info']['time_axis']['MJDseconds']))
print(len(np.unique(visdata['axis_info']['time_axis']['MJDseconds'])))

ELO=np.unique(visdata['axis_info']['time_axis']['MJDseconds'])
print(ELO)

allants=np.concatenate((visdata['antenna1'],visdata['antenna2']))
antlist=np.unique(allants)
#print(antlist)

#Calculating number of antennas and baselines
nant=int(len(antlist))
nbl=int(nant*(nant-1)/2)

print(nant)
print(nbl)
#print(len(np.unique(visdata['antenna1'])))
#print(len(np.unique(allants)))

#Defining Jacobian and measured phase matrix
script_L=np.zeros((nbl,nant,len(ELO)),dtype=int)
r_size=script_L.shape
l_m=np.zeros((nbl,1,len(ELO)),dtype=float)
anttrack=np.full(shape=(nbl,2,len(ELO)),fill_value=-1,dtype=int)
l_r=np.zeros((nbl,1,len(ELO)),dtype=float)

'''
for ant1 in np.unique(visdata['antenna1']):
    for ant2 in np.unique(visdata['antenna2']):
        if ant1 < ant2:
            thisbase = (visdata['antenna1']==ant1) & (visdata['antenna2']==ant2)
            #print(len(visdata['data'][0][thisbase]))
'''

#Setting integer for cycling through baselines
nb=0
refant=4
tb=0
for time in ELO:
    thistime=(visdata['axis_info']['time_axis']['MJDseconds']==time)
    itime=np.where(ELO==time)[0]
    print(itime)
    nb=0
    for ant1 in np.unique(visdata['antenna1']):
        for ant2 in np.unique(visdata['antenna2']):
            if ant1 < ant2:
                thisbase = (visdata['antenna1']==ant1) & (visdata['antenna2']==ant2)
                iant1=np.where(antlist==ant1)[0]
                iant2=np.where(antlist==ant2)[0]
                #print(iant1)
                #print(iant2)
                if thisbase.sum()>0:
                    print("length!")
                    #print(visdata['data'][0][thisbase][0][thistime][0])
                    pt=visdata['data'][0][thisbase][0][thistime][0]
                    #print(pt)
                    amp=np.absolute(pt)
                    print(amp)
                    if amp<=0:
                        #print("ah!")
                        nb+=1
                        continue
                    else:
                        l_m[nb,0,itime]=np.log10(amp)
                        anttrack[nb,0,itime]=ant1
                        anttrack[nb,1,itime]=ant2

                        script_L[nb,iant1,itime]=1
                        script_L[nb,iant2,itime]=1

                        nb+=1
                    '''
                    if ant2==4: Theta_r[nb,ant1]=1
                    if ant2!=4:
                        Theta_r[nb,ant1]=1
                        Theta_r[nb,ant2]=-1
                    '''

                    '''
                    if ant1==refant: script_L[nb,iant2-1]=1
                    if ant2==refant: script_L[nb,iant1]=1
                    if ant1!=refant and ant1>refant:
                        script_L[nb,iant1-1,itime]=1
                        script_L[nb,iant2-1,itime]=1
                    if ant1!=refant and ant2<refant:
                        script_L[nb,iant1,itime]=1
                        script_L[nb,iant2,itime]=1
                    if (ant1!=refant and (ant2>refant and ant1<refant)):
                        script_L[nb,iant1,itime]=1
                        script_L[nb,iant2-1,itime]=1
                    '''

    script_L_chunk=script_L[:,:,tb]
    l_m_chunk=l_m[:,:,tb]
    l_r[:,:,itime]=l_Ir(ll_r=script_L_chunk,ll_m=l_m_chunk)
    print(str(itime))
    tb+=1

print("script_L \n"+str(script_L))
print("l_m \n"+str(l_m))

#print(script_L[:,:,0].shape)
#print(l_m[:,:,0].shape)

l_r=[l_Ir(ll_r=script_L[:,:,int(x)],ll_m=l_m[:,:,int(x)]) for x in np.where(ELO==x)]
#t1=np.linalg.inv(np.matmul(Theta_r.T,Theta_r))
#t2=np.matmul(t1,Theta_r.T)
#theta_Ir=np.matmul(t2,theta_m)

print("l_r \n"+str(l_r))

#Residuals
l_del=l_m-np.matmul(script_L,l_r)

print("l_del \n"+str(l_del))

l_Ir_res=l_Ir(ll_r=script_L,ll_m=l_del)

print("l_Ir w/ resids: \n"+str(l_Ir_res))

l_Ir_final=l_r+l_Ir_res

print("final amps (log form) \n"+str(l_Ir_final))

Ir_converted=np.vstack([10.0**x for x in l_Ir_final])

print("final amps (converted) \n"+str(Ir_converted))

bpts=range(nant-1)
#print(len(bpts))
#print([:,0].shape)

plt.scatter(bpts,Ir_converted[:,0])
plt.show()


from copy import deepcopy
import json
import re

from errors import Asg3Error
from helpers import tokenize

class DocData:
  """
    Represents doc data in a structured format.
      docs: list of tuples containing the data.
        tuple[0] is the doc string, tuple[1] indicates
        whether it is positive or non-positive.
        -1 -> unknown
        0 -> negative
        1 -> positive
      label_count: keeps a count of the number of docs by label
      name: given id for the object
      words: all unique words from data, mapped to list of
        indexes of docs that use that word
  """

  def __init__(self, name, priors):
    self.docs = []
    self.label_count = {}
    self.name = name
    self.priors = deepcopy(priors)
    self.vocab = set()
    self.words = {}

    # initialize vars
    for i in range(2):
      self.label_count[i] = 0

  def add_doc(self, doc, flag):
    """
      Adds doc and doc components to class data.
        -1 -> unknown
        0 -> negative
        1 -> positive
    """

    self.docs.append((doc, flag))

    # add the doc's words
    tokens = tokenize(doc)

    # update the vocab
    self.vocab.update(tokens)

    if flag != -1:
      self.label_count[flag] += len(tokens)

    # get the number of times that this word appears in the doc
    word_counts = {}
    for word in tokens:
      if word not in word_counts:
        word_counts[word] = 0
      word_counts[word] += 1

    # increment all of the word counts
    for word in tokens:
      if word not in self.words:
        self.words[word] = {}
      self.words[word][len(self.docs)-1] = word_counts[word]

    # for word in tokens:
    #   if word not in self.words:
    #     self.words[word] = set()
    #   # associate this word with the index of this doc
    #   self.words[word].add(len(self.docs)-1)

  def add_docs(self, docs, flag):
    """
      Add doc data to the object. Must specify the label to use for all included docs.
        -1 -> unknown
        0 -> negative
        1 -> positive
    """
    if flag not in [-1, 0, 1]:
      raise Asg3Error('flag')

    for doc in docs:
      self.add_doc(doc, flag)

  def load(self, doc_data_obj):
    """
      Loads a model from a saved one
    """
    obj = json.load(doc_data_obj)
    self.docs = obj['docs']
    self.label_count = obj['label_count']
    self.name = obj['name']
    self.priors = obj['priors']
    self.vocab = set(obj['vocab'])
    self.words = {w: set(self.words[w]) for w in obj['words']}

  def num_positive(self):
    return self.label_count[1]

  def num_positive_docs(self):
    n = 0
    for doc in self.docs:
      if doc[1] == 1:
        n += 1
    return n

  def num_negative(self):
    return self.label_count[0]

  def num_negative_docs(self):
    n = 0
    for doc in self.docs:
      if doc[1] == 0:
        n += 1
    return n

  def stringify(self):
    """
      Saves the model to a file for later loading
    """
    return json.dumps({
      'docs': self.docs,
      'label_counts': self.label_count,
      'name': self.name,
      'priors': self.priors,
      'vocab': list(self.vocab),
      'words': {w: list(self.words[w]) for w in self.words}
    })

  def vocab_size(self):
    return len(self.vocab)


def fib_seq(n):
    if n == 0:
        print(0)
        return

    if n < 0:
        raise Exception("Can't use negative n")

    def helper(idx, curr, prev):
        print(curr)
        if idx == n:
            return
        helper(idx + 1, curr + prev, curr)

    print(0)
    helper(1, 1, 0)

def print_fib(n):
    try:
        fib_seq(n)
    except:
        print("Invalid n")

def fib_tester():
    f = input('Which Fibonacci number to go up to?: ')
    print_fib(int(f)-1)


import random
from tkinter import (LEFT, TOP, Button, Canvas, Entry, Frame, Label,
                     OptionMenu, StringVar, W)

from core.config.config import ALL_METHODS, DATA_PATH
from core.recognition import parallel_recognition, recognition
from PIL import Image, ImageTk

class ExperimentFrame(Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.consistent_frame = Frame(self)
        self.parallel_frame = Frame(self)
        self.canvas_frame = Frame(self)

    # =============== ПОСЛЕДОВАТЕЛЬНАЯ СИСТЕМА ===============

        self.cons_label = Label(
            self.consistent_frame,
            text="Последовательная система",
            font='Times 15'
        )

        self.method_label = Label(self.consistent_frame, text="Метод: ")

        self.method = StringVar()
        self.method.set(ALL_METHODS[1])
        self.method_drop = OptionMenu(
            self.consistent_frame,
            self.method,
            *ALL_METHODS
        )
        self.method_drop.configure(width=10)

        # Параметр метода
        self.param_label = Label(self.consistent_frame, text="Параметр: ")
        self.p_entry = Entry(self.consistent_frame, width=7)

        # Номер, с которого будут браться шаблоны для каждого человека
        self.from_templ_label = Label(self.consistent_frame, text="С: ")
        self.from_template_entry = Entry(self.consistent_frame, width=7)

        # Номер, по который будут браться шаблоны для каждого человека
        self.to_templ_label = Label(self.consistent_frame, text="По: ")
        self.to_template_entry = Entry(self.consistent_frame, width=7)
        self.score_label = Label(self.consistent_frame, text="Точность:")
        self.score_result = Label(self.consistent_frame, text="")

        # Список классифицируемых изображений
        self.result_images = []

        # Список содержащий по шаблону для
        # каждого из классифицируемых изображений
        self.templates = []

        # Запуск исследования
        self.run_but = Button(
            self.consistent_frame,
            text="Запустить",
            command=lambda: self.consistent_experiment()
        )

    # =============== ПАРАЛЛЕЛЬНАЯ СИСТЕМА ===============
        self.parallel_label = Label(
            self.parallel_frame,
            text="Параллельная система",
            font='Times 15'
        )

        # ПАРАМЕТРЫ

        # Histogram
        self.hist_label = Label(self.parallel_frame, text="Histogram: ")
        self.hist_entry = Entry(self.parallel_frame, width=7)

        # Scale
        self.scale_label = Label(self.parallel_frame, text="Scale: ")
        self.scale_entry = Entry(self.parallel_frame, width=7)

        # Gradient
        self.gradient_label = Label(self.parallel_frame, text="Gradient: ")
        self.gradient_entry = Entry(self.parallel_frame, width=7)

        # DFT
        self.dft_label = Label(self.parallel_frame, text="DFT: ")
        self.dft_entry = Entry(self.parallel_frame, width=7)

        # DCT
        self.dct_label = Label(self.parallel_frame, text="DCT: ")
        self.dct_entry = Entry(self.parallel_frame, width=7)

        # Число шаблонов
        self.templ_num_label = Label(self.parallel_frame, text="L: ")
        self.templ_num_entry = Entry(self.parallel_frame, width=7)

        # Запуск параллельного исследования
        self.parallel_button = Button(
            self.parallel_frame,
            text="Запустить",
            command=lambda: self.parallel_experiment()
        )

        self.canvas = Canvas(self.canvas_frame, width=1000, height=900)

    # =============== МЕСТОПОЛОЖЕНИЕ ВИДЖЕТОВ ===============

        self.consistent_frame.pack(side=TOP, anchor=W)
        self.parallel_frame.pack(side=TOP, anchor=W)
        self.canvas_frame.pack(side=TOP, anchor=W)

        # Настройка фрейма для последовательной системы
        self.cons_label.pack(side=TOP, padx=10, pady=7, anchor=W)
        self.method_label.pack(side=LEFT, anchor=W, padx=10, pady=7)
        self.method_drop.pack(side=LEFT, anchor=W, padx=10, pady=7)

        self.param_label.pack(side=LEFT, anchor=W, padx=10, pady=7)
        self.p_entry.pack(side=LEFT, anchor=W, padx=10, pady=7)

        self.from_templ_label.pack(side=LEFT, anchor=W, padx=10, pady=7)
        self.from_template_entry.pack(side=LEFT, anchor=W, padx=10, pady=7)

        self.to_templ_label.pack(side=LEFT, anchor=W, padx=10, pady=7)
        self.to_template_entry.pack(side=LEFT, anchor=W, padx=10, pady=7)

        self.run_but.pack(side=LEFT, anchor=W, padx=10, pady=7)

        self.score_label.pack(side=LEFT, anchor=W, padx=10)
        self.score_result.pack(side=LEFT, anchor=W)

        # Настройка фрейма для параллельной системы
        self.parallel_label.pack(side=TOP, padx=10, pady=7, anchor=W)
        self.hist_label.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.hist_entry.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.scale_label.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.scale_entry.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.gradient_label.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.gradient_entry.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.dft_label.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.dft_entry.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.dct_label.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.dct_entry.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.templ_num_label.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.templ_num_entry.pack(side=LEFT, padx=10, pady=7, anchor=W)
        self.parallel_button.pack(side=TOP, padx=10, pady=7, anchor=W)

        # Настройка фрейма с Canvas
        self.canvas.pack(side=TOP)

    def consistent_experiment(self) -> None:
        """
        Проведение эксперимента с последовательной системой
        и отображение результатов.
        """
        score, images, templates = recognition(
            "ORL",
            # research_method.get(),
            self.method.get(),
            int(self.p_entry.get()),
            int(self.from_template_entry.get()),
            int(self.to_template_entry.get()),
        )
        self.score_result.config(text=score)

        templ_posx = 50
        templ_posy = 50

        res_posx = 300
        res_posy = 50

        random_indexes = [random.randrange(len(images)) for _ in range(5)]

        for index in random_indexes:
            templ = Image.fromarray(templates[index])
            templ.resize((50, 50))
            templ = ImageTk.PhotoImage(templ)
            self.templates.append(templ)
            self.canvas.create_image(templ_posx, templ_posy, image=templ)

            templ_posy += 80

            img = Image.fromarray(images[index])
            img.resize((50, 50))
            img = ImageTk.PhotoImage(img)
            self.result_images.append(img)
            self.canvas.create_image(res_posx, res_posy, image=img)

            res_posy += 80

    def parallel_experiment(self) -> None:
        """
        Проведение эксперимента с параллельной системой
        и отображение результатов.
        """
        params = [
            ('hist', int(self.hist_entry.get())),
            ('scale', int(self.scale_entry.get())),
            ('grad', int(self.gradient_entry.get())),
            ('dft', int(self.dft_entry.get())),
            ('dct', int(self.dct_entry.get()))
        ]
        L = int(self.templ_num_entry.get())
        scores = parallel_recognition(
            db_name='ORL',
            params=params,
            templ_to=L
        )

        posx = 250
        posy = 250

        image = Image.open(
            DATA_PATH + "results/parallel_experiment_result.png"
        )
        image = image.resize((500, 300))
        image = ImageTk.PhotoImage(image)
        self.result_images.append(image)
        self.canvas.create_image(posx, posy, image=image)


import PyPDF2

base_path = "/home/jorden/Documents/prive/repositories/nr-incredibles/National Rapporteur Publications/Annual plan 2017/Annual plan 2017 .pdf"

pdfFileObj = open(base_path, 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)

print('Number of pages: ' + str(pdfReader.numPages))

for i in range(pdfReader.numPages):
    page = pdfReader.getPage(i)
    print(page.extractText())


import arviz as az
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from matplotlib.animation import FuncAnimation

az.style.use("arviz-doc")
np.random.seed(252)

fig, axes = plt.subplots(2, 1, figsize=(10, 6), sharey=True, sharex=True)

x = np.linspace(0, 1, 1000)
pdf = stats.beta(2, 5).pdf(x)
axes[0].plot(x, pdf, "k--")
axes[1].plot(x, pdf, "k--")
axes[0].set_ylim(0, 3.5)
axes[0].set_yticks([])
axes[0].set_title("Muestras independientes")
axes[1].set_title("Muestras autocorrelacionadas")

ind = np.random.beta(2, 5, 1000)
dep = np.empty(1000)
dep[0::2] = ind[:500] + 0.05
dep[1::2] = np.sort(ind[500:]) - 0.05

tmp = []

def update(idx):
    global tmp
    for t in tmp:
        try:
            t.remove()
        except:
            pass

    if idx > 20:
        idx = 20

    fig.suptitle(f"Número de muestras = {idx*50}", fontsize=18)
    a = axes[0].hist(ind[: idx * 50], bins="auto", density=True, color="C1")[2]
    b = axes[1].hist(dep[: idx * 50], bins="auto", density=True, color="C1")[2]
    tmp.extend([a, b])

ani = FuncAnimation(fig, update, frames=25, interval=500, repeat=False)
ani.save("../diapo/img/ess.gif")


import random

def solve(rows,cols,matrix):
    setA = set()
    setB = set()
    for i in range(rows):
        row = matrix[i]

        sumA, sumB = 0, 0
        for j in range(cols):
            if (j + 1) % 2 == 0:
                sumB += row[j]
            else:
                sumA += row[j]

        setA.add(sumA)
        setB.add(sumB)

    common_elements = setA.intersection(setB)
    common_elements = sorted(common_elements)
    convert_into_str_for_output = ''
    for i in common_elements:
        convert_into_str_for_output=convert_into_str_for_output+str(i)+' '

    if common_elements:
        outfile.write(f"{convert_into_str_for_output}\n")
    else:
        outfile.write(f"-1\n")

for i in range(1, 11):
    if i <= 9:
        s1 = f"./in0{i}.txt"
        s2 = f"./out0{i}.txt"
    else:
        s1 = f"./in{i}.txt"
        s2 = f"./out{i}.txt"

    with open(s1, 'w') as infile, open(s2, 'w') as outfile:
        n = 1 + random.randint(0, 9)
        m = 1 + random.randint(0, 9)
        infile.write(f"{n} {m}\n")
        l = []
        for j in range(n):
            row = []
            for i in range(m):
                v = (random.randint(1, 10))
                row.append(v)
                infile.write(f"{v} ")
            l.append(row)
            infile.write(f"\n")
        solve(n,m,l)


from sklearn.metrics import f1_score, precision_recall_curve, precision_recall_fscore_support, auc
from matplotlib import pyplot as plt
import numpy as np

def no_sampling(x_train, x_test, y_train, y_test, classifier, standalone=False):

	clf = classifier
	clf.fit(x_train, y_train)

	y_pred = clf.predict(x_test)

	if standalone:
		# calculate scores
		lr_probs = classifier.predict_proba(x_test)
		lr_probs = lr_probs[:, 1]
		lr_precision, lr_recall, _ = precision_recall_curve(y_test, lr_probs)
		lr_f1, lr_auc = f1_score(y_test, y_pred, average='micro'), auc(lr_recall, lr_precision)
		print('No Sampling: f1 = %.2f%% auc = %.2f%%' % (lr_f1 * 100, lr_auc * 100))
		prec, rec, f1, _ = precision_recall_fscore_support(y_test, y_pred, average='micro')
		print('No Sampling: precision = %.2f%% recall = %.2f%%' % (prec * 100, rec * 100))
		no_skill = len(y_test[y_test == 0]) / len(y_test)

		# Precision - Recall Curve Plot
		plt.plot([0, 1], [no_skill, no_skill], linestyle='--', label='No Skill')
		plt.plot(lr_recall, lr_precision, marker='.', label='No Sampling')
		plt.xlabel('Recall')
		plt.ylabel('Precision')
		plt.legend()
		plt.title("Precision-Recall Curve")
		plt.show()

	return y_pred

def only_majority_class(x_train, x_test, y_train, y_test, classifier):
	'''
	classifier is dump variable, only for reasons of uniformity.
	Function classifies data into the majority class.
	'''

	y_pred = np.zeros(y_test.shape[0])

	# calculate scores
	prec, rec, f1, _ = precision_recall_fscore_support(y_test, y_pred, average='micro')
	print('Only majority: f1 = %.2f%%' % (f1 * 100))

if __name__ == '__main__':
	from data_preprocessing import read_preprocessed
	from pathlib import Path
	from sklearn.ensemble import AdaBoostClassifier

	clf = AdaBoostClassifier()

	datapath = Path('data')
	x_train, x_test, y_train, y_test = read_preprocessed(datapath)

	no_sampling(x_train, x_test, y_train, y_test, clf, standalone=True)


from collections import defaultdict
import time

import pytest

from mos_tests.functions import common
from mos_tests.functions import os_cli

@pytest.mark.check_env_('has_ironic_conductor')
@pytest.mark.need_devops
@pytest.mark.testrail_id('631921', params={'boot_instance_before': False})
@pytest.mark.testrail_id('631922', params={'boot_instance_before': True})
@pytest.mark.parametrize('boot_instance_before', [True, False],
                         ids=['boot_instance_before', 'boot_instance_after'])
def test_reboot_conductor(env, ironic, os_conn, ironic_nodes, make_image,
                          flavors, keypair, devops_env, boot_instance_before):
    """Check ironic state after restart conductor node

    Scenario:
        1. Boot Ironic instance (if `boot_instance_before`)
        2. Reboot Ironic conductor.
        3. Wait 5-10 minutes.
        4. Run network verification.
        5. Run OSTF including Ironic tests.
        6. Verify that CLI ironicclient can list nodes, ports, chassis, drivers
        7. Boot new Ironic instance (if not `boot_instance_before`).
    """
    flavor, ironic_node = zip(flavors, ironic_nodes)[0]
    image = make_image(node_driver=ironic_node.driver)
    if boot_instance_before:
        instance = ironic.boot_instance(image=image,
                                        flavor=flavor,
                                        keypair=keypair)

    conductor = env.get_nodes_by_role('ironic')[0]

    devops_node = devops_env.get_node_by_fuel_node(conductor)
    devops_node.reset()

    time.sleep(10)

    common.wait(conductor.is_ssh_avaliable,
                timeout_seconds=60 * 10,
                sleep_seconds=20,
                waiting_for='ironic conductor node to reboot')

    def is_ironic_available():
        try:
            ironic.client.driver.list()
            return True
        except Exception:
            return False

    common.wait(is_ironic_available,
                timeout_seconds=60 * 5,
                sleep_seconds=20,
                waiting_for='ironic conductor service to start')

    result = env.wait_network_verification()
    assert result.status == 'ready', 'Result data:\n{0}'.format(result.data)

    env.wait_for_ostf_pass(['sanity'], timeout_seconds=60 * 5)

    with env.get_nodes_by_role('controller')[0].ssh() as remote:
        ironic_cli = os_cli.Ironic(remote)
        for cmd in ['node-list', 'port-list', 'chassis-list', 'driver-list']:
            ironic_cli(cmd)

    if not boot_instance_before:
        instance = ironic.boot_instance(image=image,
                                        flavor=flavor,
                                        keypair=keypair)

    assert os_conn.nova.servers.get(instance.id).status == 'ACTIVE'

@pytest.mark.check_env_('has_2_or_more_ironic_conductors')
@pytest.mark.need_devops
@pytest.mark.testrail_id('638353')
def test_reboot_all_ironic_conductors(env, devops_env):
    """Check ironic state after restart all conductor nodes

    Scenario:
        1. Ensure ironic conductor service works correctly on each conductor
            node (e.g., ensure "ironic driver-list" returns correct list of
            drivers)
        2. Shutdown all ironic conductor nodes
        3. Turn on all ironic conductor nodes
        4. SSH to controller and ensure that "ironic driver-list" return same
            result as for step 1
    """
    controller = env.get_nodes_by_role('controller')[0]
    with controller.ssh() as remote:
        driver_hosts = os_cli.Ironic(remote).get_driver_hosts()

    conductors = env.get_nodes_by_role('ironic')
    conductor_hosts = set(node.data['fqdn'] for node in conductors)

    assert conductor_hosts == driver_hosts
    devops_nodes = [devops_env.get_node_by_fuel_node(x) for x in conductors]

    for node in devops_nodes:
        node.destroy()

    for node in devops_nodes:
        node.start()

    common.wait(lambda: all(x.is_ssh_avaliable() for x in conductors),
                timeout_seconds=10 * 60,
                waiting_for='conductor nodes to boot')

    with controller.ssh() as remote:
        ironic_cli = os_cli.Ironic(remote)
        common.wait(lambda: ironic_cli.get_driver_hosts() == conductor_hosts,
                    timeout_seconds=60 * 2,
                    waiting_for="ironic conductor to register their drivers")

@pytest.mark.check_env_('has_2_or_more_ironic_conductors')
@pytest.mark.need_devops
@pytest.mark.testrail_id('675246')
def test_kill_conductor_service(env, os_conn, ironic_nodes, make_image,
                                flavors, keypair, env_name, ironic):
    """Kill ironic-conductor service with one bare-metal node

    Scenario:
        1. Launch baremetal instance
        2. Kill Ironic-conductor service for conductor node that had booted
            instance
        3. Wait some time
        4. Baremetal node must be reassigned to another Ironic-conductor
        5. Run OSTF including Ironic tests.
        6. Check that Ironic instance still ACTIVE and operable

    Info: https://bugs.launchpad.net/mos/+bug/1557464
    """
    flavor, ironic_node = zip(flavors, ironic_nodes)[0]
    image = make_image(node_driver=ironic_node.driver)

    def find_conductor_node(ironic_node_uuid, conductors):
        cmd = 'ls /var/log/remote/ironic/{0}/'.format(ironic_node_uuid)
        for conductor in conductors:
            with conductor.ssh() as remote:
                result = remote.execute(cmd)
                if result.is_ok:
                    return conductor

    def find_takeover_node(ironic_node_uuid, conductors):
        grep = 'grep "taking over node {inst_uid}" {log}'.format(
            inst_uid=ironic_node_uuid,
            log='/var/log/ironic/ironic-conductor.log')
        for conductor in conductors:
            with conductor.ssh() as remote:
                result = remote.execute(grep)
                if result.is_ok:
                    return conductor

    instance = ironic.boot_instance(image=image,
                                    flavor=flavor,
                                    keypair=keypair)

    conductors = env.get_nodes_by_role('ironic')
    conductor = find_conductor_node(ironic_node.uuid, conductors)
    if conductor is None:
        raise Exception("Can't find conductor node booted istance")

    with conductor.ssh() as remote:
        remote.check_call('service ironic-conductor stop')

    conductors.remove(conductor)
    common.wait(
        lambda: (find_takeover_node(ironic_node.uuid, conductors)
                 not in (conductor, None)),
        timeout_seconds=10 * 60,
        waiting_for='node to migrate to another conductor',
        sleep_seconds=60)

    assert os_conn.nova.servers.get(instance.id).status == 'ACTIVE'

    with os_conn.ssh_to_instance(env,
                                 instance,
                                 vm_keypair=keypair,
                                 username='ubuntu') as remote:
        remote.check_call('uname')

@pytest.mark.testrail_id('1295473')
@pytest.mark.check_env_('has_ironic_conductor')
@pytest.mark.parametrize('ironic_nodes', [2], indirect=True)
@pytest.mark.need_devops
def test_restart_all_ironic_services(env, os_conn, ironic_nodes, ironic,
                                     make_image, flavors, keypair):
    """Test ironic after restarting all ironic services

    Scenario:
        1. Launch baremetal instance 'test1'
        2. Check that 'test1' instance ACTIVE and operable
        3. Stop all ironic-<name> services on each controllers and ironic
            nodes:
            service ironic-<name of service> restart
        4. Check that 'test1' instance are accesible with SSH
        5. Launch all ironic services
        6. Launch baremetal instance 'test2'
        7. Check that 'test1' instance ACTIVE and operable
        8. Delete created instances
    """
    image = make_image(node_driver=ironic_nodes[0].driver)

    instance1 = ironic.boot_instance(name='test1',
                                     image=image,
                                     flavor=flavors[0],
                                     keypair=keypair)

    nodes = (set(env.get_nodes_by_role('controller')) |
             set(env.get_nodes_by_role('ironic')))
    ironic_services_cmd = ("service --status-all 2>&1 | grep '+' | "
                           "grep ironic | awk '{ print $4 }'")

    stopped_services = defaultdict(set)
    for node in nodes:
        with node.ssh() as remote:
            output = remote.check_call(ironic_services_cmd).stdout_string
            for service in output.splitlines():
                remote.check_call('service {0} stop'.format(service))
                stopped_services[node].add(service)

    assert os_conn.is_server_ssh_ready(instance1)

    for node, services in stopped_services.items():
        with node.ssh() as remote:
            for service in services:
                remote.check_call('service {0} start'.format(service))

    instance2 = ironic.boot_instance(name='test2',
                                     image=image,
                                     flavor=flavors[1],
                                     keypair=keypair)

    instance1.delete()
    instance2.delete()

    os_conn.wait_servers_deleted([instance1, instance2])


# 1. Python: Reverse Words and Swap Cases
# Implement a function that takes a string consisting of words separated by single spaces and returns a string containing all those words but in the reverse order and such that all cases of letters in the original string are swapped, i.e. lowercase letters become uppercase and uppercase letters become lowercase.
# Example
# sentence = "rUns dOg"
# Reverse the word order and swap the case of all letters, then return the string "DoG RuNS".

sentence = "rUns dOg"
result = ""
split_sent = sentence.split()
split_sent.reverse()
for i in range(len(split_sent)):
    for j in range(len(split_sent[i])):
        word = split_sent[i]
        if (ord(word[j]) >= 65 and ord(word[j]) <= 90):
            result += word[j].lower()
        elif (ord(word[j]) >= 97 and ord(word[j]) <= 122):
            result += word[j].upper()
    result += " "
print(result)


from django.urls import path

from . import views

urlpatterns = [
    path('', views.CartView.as_view()),
    path('add-to-cart/<slug:ct_model>/<slug:product_slug>/',
         views.AddToCartView.as_view()),
    path('delete-from-cart/<slug:ct_model>/<slug:product_slug>/',
         views.DeleteProductFromCartView.as_view())
]


"""Required modules"""
import time
from datetime import datetime
import requests
from dateutil import relativedelta

class IotHandler:
    """Handler class for challange_slide_182"""

    url = "https://jsonmock.hackerrank.com/api"
    iot_devices_endpoint = "/iot_devices/search"

    def get_data(self):
        """Get all data from API and return in weird shape"""

        params = {
            "page": 1
        }
        response_body_all = []
        for _ in range(10):
            response = requests.get(f"{self.url}{self.iot_devices_endpoint}",
                                    params=params, timeout=10)
            response_body = response.json()
            response_body_all.append(response_body["data"])
            params["page"] += 1

        return response_body_all

    def parse_all_records(self):
        """Parse data and return as list of dictionaries"""

        final_table_records = []
        data = self.get_data()
        for i in data:
            temp_table = []
            temp_table.append(i)
            for j in temp_table[0]:
                final_table_records.append(j)
            temp_table = []
        return final_table_records

    def num_devices(self, status_query: str, threshold: int, date_str: str) -> int:
        """Return num of devices with given parameters"""

        counter = 0
        check_list = []
        timestamp_start = int(time.mktime(datetime.strptime(date_str, "%m-%Y").timetuple()))
        timestamp_end = int((datetime.fromtimestamp(timestamp_start) +
                            relativedelta.relativedelta(months=1)).timestamp())

        final_table = self.parse_all_records()
        for dictionary in final_table:
            if dictionary["status"] == status_query \
                    and dictionary["operatingParams"]["rootThreshold"] > threshold\
                    and timestamp_start * 1000 < dictionary["timestamp"] < timestamp_end * 1000:
                counter += 1
                check_list.append(dictionary)
        return counter


import numpy as np
import torch
from torch.distributions import Categorical
import torch.multiprocessing as mp
from worker import worker

class ParallelEnv:
    def __init__(self, n_workers):
        self.n_workers = n_workers
        self.workers = []

        self.master_ends, worker_ends = zip(*[mp.Pipe() for _ in range(n_workers)])

        for worker_end in worker_ends:
            p = mp.Process(target=worker, args=(worker_end,))
            p.daemon = True
            p.start()
            self.workers.append(p)

    def reset(self, level):
        for master_end in self.master_ends:
            master_end.send(('reset', level))
        return np.stack([master_end.recv() for master_end in self.master_ends])

    def step(self, actions):
        for master_end, action in zip(self.master_ends, actions):
            master_end.send(('step', action))

        results = [master_end.recv() for master_end in self.master_ends]
        observations, rewards, dones, infos = zip(*results)

        return np.stack(observations), np.stack(rewards), np.stack(dones), infos

    def close(self):
        for master_end in self.master_ends:
            master_end.send(('close', None))
        for worker in self.workers:
            worker.join()

    def solve(self, level, model):
        observation = torch.tensor(self.reset(level))
        actions = torch.zeros((self.n_workers, 300), dtype=torch.uint8)

        for t in range(300):
            with torch.no_grad():
                pi, _ = model(observation)

                p = Categorical(pi)
                action = p.sample()
                actions[:, t] = action

            observation, reward, done, info = self.step(action.tolist())
            observation = torch.tensor(observation)
            dones = [env["finished"] for env in info]

            if any(dones) == True:
                index = [i for i,done in enumerate(dones) if done == True][0]

                return True, actions[index, 0:t+1]

        return False, actions[0]


# -*- coding: utf-8 -*-
from ..iterators.wmt import WMTIterator
from .attention import Model as Attention

# Same model as attention but using WMTIterator
class Model(Attention):
    def __init__(self, seed, logger, **kwargs):
        # Call parent's init first
        super(Model, self).__init__(seed, logger, **kwargs)

        self.data_mode = kwargs.get('data_mode', 'pairs')

    def load_valid_data(self, from_translate=False, data_mode='single'):
        if from_translate:
            self.valid_ref_files = self.data['valid_trg']
            if isinstance(self.valid_ref_files, str):
                self.valid_ref_files = list([self.valid_ref_files])

            self.valid_iterator = WMTIterator(
                    mask=False,
                    batch_size=1,
                    pklfile=self.data['valid_src'],
                    srcdict=self.src_dict, n_words_src=self.n_words_src,
                    mode=data_mode)
        else:
            # Take the first validation item for NLL computation
            self.valid_iterator = WMTIterator(
                    batch_size=self.batch_size,
                    pklfile=self.data['valid_src'],
                    trgdict=self.trg_dict, srcdict=self.src_dict,
                    n_words_trg=self.n_words_trg, n_words_src=self.n_words_src,
                    mode='single') # Override the given parameter

        self.valid_iterator.read()

    def load_data(self):
        self.train_iterator = WMTIterator(
                batch_size=self.batch_size,
                shuffle_mode=self.smode,
                logger=self.logger,
                pklfile=self.data['train_src'],
                trgdict=self.trg_dict, srcdict=self.src_dict,
                n_words_trg=self.n_words_trg, n_words_src=self.n_words_src,
                mode=self.data_mode)
        # Prepare batches
        self.train_iterator.read()
        self.load_valid_data()


class Tag:
    size_of_users_largest_box = {
                'tooltip':'Largest Box Size',
                'icon' : 'glyphicon-th',
                'data_display' : 'Box of {0}',
                'data' :lambda user: max_or_default([len(items_in(box)) for box in load_public_boxes(user)])
                }

    date_created = {
        'tooltip':'Date Created',
        'icon' : 'glyphicon-time',
        'data_display' : '{0}',
        'data': lambda box : box.created_at.strftime("%d/%m/%Y")
    }

    monetary_value = {
        'tooltip':'Value',
        'icon' : 'glyphicon-credit-card',
        'data_display' : '£{0}',
        'data' : lambda x : format_pence_as_pounds(x.monetary_value)
    }

    itemcount = {
        'tooltip': 'Items',
        'icon' : 'glyphicon-unchecked',
        'data_display' : '{0} Items',
        'data' : lambda x : x.itemcount
    }

    public_boxcount = {
        'tooltip' : 'Public Boxes',
        'icon' : 'glyphicon-th-large',
        'data_display' : '{0} Boxes',
        'data' : lambda user: user.boxcount
    }

    users_name = {
        'tooltip' : 'View Profile',
        'icon' : 'glyphicon-user',
        'data_display' : '{0}',
        'data' : lambda box: box.auth_user.username,
        'href' : lambda box: URL('default','profile_page',vars=dict(user=box.auth_user.id))
    }

    item_type = {
        'tooltip' : 'Type',
        'icon' : 'glyphicon-list',
        'data_display' : '{0}',
        'data' : lambda item: ITEM_TYPES[item.itm_type].capitalize()
    }

    public_itemcount = dict(itemcount)
    public_itemcount['tooltip']= 'Public Items'


'''Given a string s of '(' , ')' and lowercase English characters.

Your task is to remove the minimum number of parentheses ( '(' or ')', in any positions ) so that the resulting parentheses string is valid and return any valid string.

Formally, a parentheses string is valid if and only if:

It is the empty string, contains only lowercase characters, or
It can be written as AB (A concatenated with B), where A and B are valid strings, or
It can be written as (A), where A is a valid string.

Example 1:

Input: s = "lee(t(c)o)de)"
Output: "lee(t(c)o)de"
Explanation: "lee(t(co)de)" , "lee(t(c)ode)" would also be accepted.
Example 2:

Input: s = "a)b(c)d"
Output: "ab(c)d"'''

from collections import deque

class Solution:
    def minRemoveToMakeValid(self, s):
        length=len(s)

        stack1=[]
        num_left=0
        num_right=0
        for i in range(length):
            if s[i]!='(' and s[i]!=')':
                stack1.append(s[i])
            elif s[i]=='(':
                stack1.append(s[i])
                num_left+=1
            else:
                if num_left>num_right:
                    stack1.append(s[i])
                    num_right+=1
        stack3=[]
        deque1=deque()

        length2=len(stack1)
        num_left=0
        num_right=0
        for i in range(-1,-length2-1,-1):
            if deque1==deque() and stack1[i]=='(':
                pass
            elif deque1!=deque() and  stack1[i]=='(' and num_left<num_right:
                deque1.appendleft(stack1[i])
                stack3.append(stack1[i])
                num_left+=1
            elif stack1[i]==')':
                stack3.append(stack1[i])
                deque1.appendleft(stack1[i])
                num_right+=1
            elif stack1[i]!='(':
                stack3.append(stack1[i])
        return ''.join(stack3[::-1])

Minimum Remove to Make Valid Parentheses.py