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

########### GUI2Exe SVN repository information ###################
# $Date$
# $Author$
# $Revision$
# $URL$
# $Id$
########### GUI2Exe SVN repository information ###################

# Start the imports

import os
import wx
# To print out the PList dictionary
import pprint

import wx.lib.buttons as buttons

from BaseBuilderPanel import BaseBuilderPanel
from Widgets import BaseListCtrl, MultiComboBox, PListEditor, _hasMacThings
from Constants import _py2app_target, _py2app_imports, _pywild, _iconwild, _plistwild, ListType
from Utilities import setupString

# Get the I18N things
_ = wx.GetTranslation

class Py2AppPanel(BaseBuilderPanel):

    def __init__(self, parent, projectName, creationDate):
        """
        Default class constructor.

        **Parameters:**

        * projectName: the name of the project we are working on
        * creationDate: the date and time the project was created

        """

        BaseBuilderPanel.__init__(self, parent, projectName, creationDate, name="py2app")

        # I need this flag otherwise all the widgets start sending changed
        # events when I first populate the full panel

        self.created = False

        # A whole bunch of static box sizers
        self.commonSizer_staticbox = wx.StaticBox(self, -1, _("Common Options"))
        self.includesSizer_staticbox = wx.StaticBox(self, -1, _("Includes"))
        self.packagesSizer_staticbox = wx.StaticBox(self, -1, _("Packages"))
        self.excludesSizer_staticbox = wx.StaticBox(self, -1, _("Excludes"))
        self.dylibExcludesSizer_staticbox = wx.StaticBox(self, -1, _("Dylib/Frameworks Excludes"))
        self.datamodelsSizer_staticbox = wx.StaticBox(self, -1, _("XC Data Models"))
        self.frameworksSizer_staticbox = wx.StaticBox(self, -1, _("Dylib/Frameworks Includes"))
        self.datafile_staticbox = wx.StaticBox(self, -1, _("Resources"))

        self.otherSizer_staticbox = wx.StaticBox(self, -1, _("Other Options"))

        # A simple label that holds information about the project
        transdict = dict(projectName=projectName, creationDate=creationDate)
        self.label = wx.StaticText(self, -1, _("Py2app options for: %(projectName)s (Created: %(creationDate)s)")%transdict)

        # A combobox to choose the application extension
        self.extensionCombo = MultiComboBox(self, [".app", ".plugin"], wx.CB_DROPDOWN|wx.CB_READONLY,
                                            self.GetName(), "extension")
        # The file picker that allows us to pick the script to be compiled by py2app
        self.scriptPicker = wx.FilePickerCtrl(self, style=wx.FLP_USE_TEXTCTRL,
                                              wildcard=_pywild, name="script")

        # A checkbox that enables the user to choose a different name for the
        # distribution directory. Default is unchecked, that means dist_dir="dist"
        self.distChoice = wx.CheckBox(self, -1, _("Dist Directory"), name="dist_dir_choice")
        # The name of the distribution directory (if enabled)
        self.distTextCtrl = wx.TextCtrl(self, -1, "dist", name="dist_dir")

        # Optimization level for py2app  1 for "python -O", 2 for "python -OO",
        # 0 to disable
        self.optimizeCombo = MultiComboBox(self, ["0", "1", "2"], wx.CB_DROPDOWN|wx.CB_READONLY,
                                           self.GetName(), "optimize")

        # The icon picker that allows us to pick the application icon
        self.iconPicker = wx.FilePickerCtrl(self, style=wx.FLP_USE_TEXTCTRL,
                                            wildcard=_iconwild, name="iconfile")

        # A picker for the PList file
        self.pListPicker = wx.FilePickerCtrl(self, style=wx.FLP_USE_TEXTCTRL,
                                             wildcard=_plistwild, name="plist")

        # To add/edit PList code
        self.pListChoice = wx.CheckBox(self, -1, _("PList Code"), name="plistCode_choice")
        editBmp = self.MainFrame.CreateBitmap("edit_add")
        removeBmp = self.MainFrame.CreateBitmap("remove")
        self.pListAddButton = buttons.ThemedGenBitmapTextButton(self, -1, editBmp, _("Add/Edit"),
                                                                size=(-1, 25), name="plistCode")
        self.pListRemoveButton = buttons.ThemedGenBitmapTextButton(self, -1, removeBmp, _("Remove"),
                                                                   size=(-1, 25), name="plistRemove")

        # A list control for the "includes" option, a comma separated list of
        # modules to include
        self.includeList = BaseListCtrl(self, columnNames=[_("Python Modules")], name="includes")
        # A list control for the "packages" option, a comma separated list of
        # packages to include
        self.packagesList = BaseListCtrl(self, columnNames=[_("Python Packages")], name="packages")
        # A list control for the "frameworks" option, a comma separated list of
        # frameworks/dylibs to include
        self.frameworksList = BaseListCtrl(self, columnNames=[_("Dylib/Frameworks Names")], name="frameworks")
        # A list control for the "excludes" option, a comma separated list of
        # modules to exclude
        self.excludeList = BaseListCtrl(self, columnNames=[_("Python Modules")], name="excludes")
        # A list control for the "dylib_excludes" option, a comma separated list of
        # dylibs/frameworks to exclude
        self.dylibExcludeList = BaseListCtrl(self, columnNames=[_("Dylib/Frameworks Names")], name="dylib_excludes")
        # A list control for the "xcdatamodels" option, a comma separated list of
        # xcdatamodels to compile and include
        self.datamodelsList = BaseListCtrl(self, columnNames=[_("XC Data Models Names")], name="datamodels")
        # A list control for the "resources" option. "resources" should contain
        # a sequence of (target-dir, files) tuples, where files is a sequence of
        # files to be copied
        self.datafileList = BaseListCtrl(self, columnNames=[_("Files Path")], name="resources")

        # output module dependency graph
        self.graphCheck = wx.CheckBox(self, -1, "Graph", name="graph")
        # This command line switch instructs py2app to create a python module cross
        # reference and display it in the webbrowser.  This allows to answer question
        # why a certain module has been included, or if you can exclude a certain module
        # and it's dependencies. Also, the html page includes links which will even
        # allow to view the source code of a module in the browser, for easy inspection.
        self.crossRefCheck = wx.CheckBox(self, -1, "Cross-Reference", name="xref")
        # Do not strip debug and local symbols from output
        self.noStripCheck = wx.CheckBox(self, -1, "No Strip", name="no_strip")
        # Do not change to the data directory (Contents/Resources) [forced for plugins]
        self.noChdirCheck = wx.CheckBox(self, -1, "No Chdir", name="no_chdir")
        # Depend on an existing installation of Python 2.4
        self.semiStandaloneCheck = wx.CheckBox(self, -1, "Semi Standalone", name="semi_standalone")
        # Use argv emulation (disabled for plugins)
        self.argvEmulationCheck = wx.CheckBox(self, -1, "Argv Emulation", name="argv_emulation")
        # Allow PYTHONPATH to effect the interpreter's environment
        self.usePythonPathCheck = wx.CheckBox(self, -1, "Use PYTHONPATH", name="use_pythonpath")
        # Include the system and user site-packages into sys.path
        self.sitePackagesCheck= wx.CheckBox(self, -1, "Site Packages", name="site_packages")
        # Force application to run translated on i386 (LSPrefersPPC=True)
        self.preferPPCCheck= wx.CheckBox(self, -1, "Prefer PPC", name="prefer_ppc")
        # Drop to pdb console after the module finding phase is complete
        self.debugModuleGraphCheck= wx.CheckBox(self, -1, "Debug Modulegraph", name="debug_modulegraph")
        # Skip macholib phase (app will not be standalone!)
        self.skipMacholibCheck= wx.CheckBox(self, -1, "Debug Skip Macholib", name="debug_skip_macholib")

        # Hold a reference to all the list controls, to speed up things later
        self.listCtrls = [self.includeList, self.packagesList, self.frameworksList, self.excludeList,
                          self.dylibExcludeList, self.datamodelsList, self.datafileList]

        # Do the hard work... quite a few to layout :-D
        self.LayoutItems()
        self.SetProperties()
        self.BindEvents()
        wx.CallAfter(self.EnableMacPList)

        self.Bind(wx.EVT_BUTTON, self.OnPListAdd, self.pListAddButton)
        self.Bind(wx.EVT_BUTTON, self.OnPListRemove, self.pListRemoveButton)

    # ========================== #
    # Methods called in __init__ #
    # ========================== #

    def SetProperties(self):
        """ Sets the properties fro Py2AppPanel and its children widgets. """

        # I use all the py2app default values (where applicable), and my standard
        # configuration or preferences otherwise. This can easily be changed later
        # with a user customizable default project options file (or wx.Config)

        self.distTextCtrl.Enable(False)

        # Set a bold font for the static texts
        font = self.GetFont()
        font.SetWeight(wx.FONTWEIGHT_BOLD)

        for child in self.GetChildren():
            if isinstance(child, wx.StaticText) or isinstance(child, wx.CheckBox):
                child.SetFont(font)

    def LayoutItems(self):
        """ Layouts the widgets using sizers. """

        # Create a whole bunch of sizers
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        otherSizer = wx.StaticBoxSizer(self.otherSizer_staticbox, wx.VERTICAL)
        otherSizer_1 = wx.FlexGridSizer(3, 4, 5, 5)
        plusSizer = wx.BoxSizer(wx.HORIZONTAL)
        minusSizer = wx.BoxSizer(wx.HORIZONTAL)

        dylibExcludesSizer = wx.StaticBoxSizer(self.dylibExcludesSizer_staticbox, wx.HORIZONTAL)
        excludesSizer = wx.StaticBoxSizer(self.excludesSizer_staticbox, wx.HORIZONTAL)
        packagesSizer = wx.StaticBoxSizer(self.packagesSizer_staticbox, wx.HORIZONTAL)
        includesSizer = wx.StaticBoxSizer(self.includesSizer_staticbox, wx.HORIZONTAL)
        datamodelsSizer = wx.StaticBoxSizer(self.datamodelsSizer_staticbox, wx.HORIZONTAL)
        datafilesSizer = wx.StaticBoxSizer(self.datafile_staticbox, wx.HORIZONTAL)
        frameworksSizer = wx.StaticBoxSizer(self.frameworksSizer_staticbox, wx.HORIZONTAL)

        commonSizer = wx.StaticBoxSizer(self.commonSizer_staticbox, wx.VERTICAL)

        # This grid bag sizer will hold all the list controls and widgets
        # that display py2app options
        commonGridSizer = wx.GridBagSizer(5, 5)

        commonSizer_7 = wx.BoxSizer(wx.VERTICAL)
        commonSizer_6 = wx.BoxSizer(wx.VERTICAL)
        commonSizer_5 = wx.BoxSizer(wx.VERTICAL)
        commonSizer_4 = wx.BoxSizer(wx.VERTICAL)
        commonSizer_3 = wx.BoxSizer(wx.VERTICAL)
        commonSizer_2 = wx.BoxSizer(wx.VERTICAL)
        commonSizer_1 = wx.BoxSizer(wx.VERTICAL)
        hSizer = wx.BoxSizer(wx.HORIZONTAL)

        # Add the VersionInfo text controls
        mainSizer.Add(self.label, 0, wx.ALL, 10)

        flag = wx.LEFT|wx.RIGHT|wx.EXPAND

        extension = wx.StaticText(self, -1, _("Extension"))
        commonSizer_1.Add(extension, 0, wx.RIGHT|wx.BOTTOM, 2)
        commonSizer_1.Add(self.extensionCombo, 0, wx.EXPAND, 0)
        commonGridSizer.Add(commonSizer_1, (1, 0), (1, 1), flag, 5)
        script = wx.StaticText(self, -1, _("Python Main Script"))
        commonSizer_2.Add(script, 0, wx.RIGHT|wx.BOTTOM, 2)
        commonSizer_2.Add(self.scriptPicker, 0, wx.EXPAND, 0)
        commonGridSizer.Add(commonSizer_2, (1, 1), (1, 4), flag, 5)
        commonSizer_3.Add(self.distChoice, 0, wx.RIGHT|wx.BOTTOM, 2)
        commonSizer_3.Add(self.distTextCtrl, 0, wx.EXPAND, 0)
        commonGridSizer.Add(commonSizer_3, (1, 5), (1, 1), flag, 5)

        optimize = wx.StaticText(self, -1, _("Optimize"))
        commonSizer_4.Add(optimize, 0, wx.RIGHT|wx.BOTTOM, 2)
        commonSizer_4.Add(self.optimizeCombo, 0, wx.EXPAND, 0)
        commonGridSizer.Add(commonSizer_4, (2, 0), (1, 1), flag|wx.TOP, 5)
        icon = wx.StaticText(self, -1, _("Icon File"))
        commonSizer_5.Add(icon, 0, wx.RIGHT|wx.BOTTOM, 2)
        commonSizer_5.Add(self.iconPicker, 0, wx.EXPAND, 0)
        commonGridSizer.Add(commonSizer_5, (2, 1), (1, 2), flag|wx.TOP, 5)
        plist = wx.StaticText(self, -1, _("PList File"))
        commonSizer_6.Add(plist, 0, wx.RIGHT|wx.BOTTOM, 2)
        commonSizer_6.Add(self.pListPicker, 0, wx.EXPAND, 0)
        commonGridSizer.Add(commonSizer_6, (2, 3), (1, 2), flag|wx.TOP, 5)
        commonSizer_7.Add(self.pListChoice, 0, wx.RIGHT|wx.BOTTOM, 2)
        hSizer.Add(self.pListAddButton, 0, wx.RIGHT, 5)
        hSizer.Add(self.pListRemoveButton, 0)
        commonSizer_7.Add(hSizer, 0, wx.EXPAND, 0)
        commonGridSizer.Add(commonSizer_7, (2, 5), (1, 1), flag|wx.TOP, 5)

        commonGridSizer.AddGrowableCol(2)
        commonGridSizer.AddGrowableCol(3)
        commonGridSizer.AddGrowableCol(4)
        commonGridSizer.SetEmptyCellSize((0, 0))

        commonSizer.Add(commonGridSizer, 1, wx.EXPAND|wx.BOTTOM, 5)
        mainSizer.Add(commonSizer, 0, wx.ALL|wx.EXPAND, 5)

        flag = wx.LEFT|wx.TOP|wx.BOTTOM|wx.EXPAND
        # Add the list controls
        includesSizer.Add(self.includeList, 1, flag, 5)
        includesSizer.Add(self.includeList.MakeButtons(), 0, wx.EXPAND|wx.LEFT, 3)
        packagesSizer.Add(self.packagesList, 1, flag, 5)
        packagesSizer.Add(self.packagesList.MakeButtons(), 0, wx.EXPAND|wx.LEFT, 3)
        frameworksSizer.Add(self.frameworksList, 1, flag, 5)
        frameworksSizer.Add(self.frameworksList.MakeButtons(), 0, wx.EXPAND|wx.LEFT, 3)
        plusSizer.Add(includesSizer, 1, wx.EXPAND)
        plusSizer.Add(packagesSizer, 1, wx.EXPAND|wx.LEFT, 5)
        plusSizer.Add(frameworksSizer, 1, wx.EXPAND|wx.LEFT, 5)
        mainSizer.Add(plusSizer, 1, wx.ALL|wx.EXPAND, 5)

        excludesSizer.Add(self.excludeList, 1, flag, 5)
        excludesSizer.Add(self.excludeList.MakeButtons(), 0, wx.EXPAND|wx.LEFT, 3)
        dylibExcludesSizer.Add(self.dylibExcludeList, 1, flag, 5)
        dylibExcludesSizer.Add(self.dylibExcludeList.MakeButtons(), 0, wx.EXPAND|wx.LEFT, 3)
        datamodelsSizer.Add(self.datamodelsList, 1, flag, 5)
        datamodelsSizer.Add(self.datamodelsList.MakeButtons(), 0, wx.EXPAND|wx.LEFT, 3)

        minusSizer.Add(excludesSizer, 1, wx.EXPAND)
        minusSizer.Add(dylibExcludesSizer, 1, wx.EXPAND|wx.LEFT, 5)
        minusSizer.Add(datamodelsSizer, 1, wx.EXPAND|wx.LEFT, 5)
        mainSizer.Add(minusSizer, 1, wx.ALL|wx.EXPAND, 5)

        datafilesSizer.Add(self.datafileList, 1, flag, 5)
        datafilesSizer.Add(self.datafileList.MakeButtons(), 0, wx.EXPAND|wx.LEFT, 3)
        mainSizer.Add(datafilesSizer, 1, wx.ALL|wx.EXPAND, 5)

        # Add the other options at the bottom
        otherSizer_1.Add(self.graphCheck, 0)
        otherSizer_1.Add(self.crossRefCheck, 0)
        otherSizer_1.Add(self.noStripCheck, 0)
        otherSizer_1.Add(self.noChdirCheck, 0)
        otherSizer_1.Add(self.semiStandaloneCheck, 0)
        otherSizer_1.Add(self.argvEmulationCheck, 0)
        otherSizer_1.Add(self.usePythonPathCheck, 0)
        otherSizer_1.Add(self.sitePackagesCheck, 0)
        otherSizer_1.Add(self.preferPPCCheck, 0)
        otherSizer_1.Add(self.debugModuleGraphCheck, 0)
        otherSizer_1.Add(self.skipMacholibCheck, 0)

        otherSizer_1.AddGrowableCol(0)
        otherSizer_1.AddGrowableCol(1)
        otherSizer_1.AddGrowableCol(2)
        otherSizer_1.AddGrowableCol(3)
        otherSizer.Add(otherSizer_1, 1, wx.EXPAND|wx.ALL, 5)
        mainSizer.Add(otherSizer, 0, wx.ALL|wx.EXPAND, 5)

        self.SetAutoLayout(True)
        self.SetSizer(mainSizer)

        self.SetupScrolling()
        self.label.SetFocus()

    def EnableMacPList(self):
        """
        Checks whether all the imports needed to build the PList editor are
        available.
        """

        if not _hasMacThings:
            # It was not possible to import py2app and
            # other Mac goodies...
            self.pListChoice.SetValue(0)
            self.pListChoice.Enable(False)
            self.pListAddButton.Enable(False)
            self.pListRemoveButton.Enable(False)

    def ValidateOptions(self):
        """ Validates the py2app input options before compiling. """

        # check if the script file exists
        if not os.path.isfile(self.scriptPicker.GetPath()):
            msg = _("Python main script is not a valid file.")
            self.MainFrame.RunError(2, msg, True)
            return False

        # check if the PList file is not empty and if it exists
        pListScript = self.pListPicker.GetPath()
        if pListScript and not os.path.isfile(pListScript):
            msg = _("PList file is not a valid file.")
            self.MainFrame.RunError(2, msg, True)
            return False

        # check if the icon file is not empty and if it exists
        icon = self.iconPicker.GetPath()
        if icon and not os.path.isfile(icon):
            msg = _("Icon file is not a valid file.")
            self.MainFrame.RunError(2, msg, True)
            return False

        # Everything is ok, let's go compiling...
        return True

    def PrepareForCompile(self):
        """ Retrieves all the data to prepare for compilation. """

        if not self.ValidateOptions():
            # No way, something went wrong with the options set by the user
            return None

        # Retrieve the project stored in the parent (LabelBook) properties
        project = self.GetParent().GetProject()
        # Send a message to out fancy bottom log window
        transdict = dict(projectName=project.GetName())
        self.MainFrame.SendMessage(0, _('Generating "%(projectName)s" setup script...')%transdict)

        # Get the project configuration (all the options, basically)
        configuration = project.GetConfiguration(self.GetName())
        # Get the custom code (if any) that the user added
        customCode = project.GetCustomCode(self.GetName())
        # Get the post-compilation code (if any) that the user added
        postCompile = project.GetPostCompileCode(self.GetName())

        for lists in self.listCtrls:
            # Last update for all the list controls
            lists.UpdateProject(False)

        # Build the target script file
        return self.BuildTargetClass(configuration, project, None, customCode, postCompile)

    def BuildTargetClass(self, configuration, project, manifestFile, customCode, postCompile):
        """ Builds the py2app compilation script file, returning it as a string. """

        # A couple of dictionaries to populate the setup string
        setupDict, importDict = {}, {}
        configuration = dict(configuration)
        distChoice = self.distChoice.GetValue()

        pListChoice = self.pListChoice.GetValue()
        usePListFile = True
        pListCode = {}

        if pListChoice:
            if "plist_code" in configuration:
                # Get the existing PList code (if any)
                pListCode = configuration["plist_code"]
                if pListCode:
                    usePListFile = False
                    plist_code = "plist_code = " + pprint.pformat(pListCode, width=100)

        # Loop over all the keys, values of the configuration dictionary
        for key, item in configuration.items():
            if key == "dist_dir_choice":
                continue
            if key == "script":
                buildDir, scriptFile = os.path.split(item)
                item = "r'%s'"%item
            elif key == "dist_dir":
                if not item.strip() or not distChoice:
                    item = "dist"
                    if distChoice:
                        self.MainFrame.SendMessage(1, _('Empty dist_dir option. Using default value "dist"'))
            elif key in ["iconfile", "plist"]:
                if key == "plist" and not usePListFile:
                    item = "plist_code"
                else:
                    if not item.strip():
                        item = None
                    else:
                        item = "r'%s'"%item

            if isinstance(self.FindWindowByName(key), wx.CheckBox):
                item = bool(int(item))

            if type(item) == ListType:
                # Terrible hack to setup correctly the string to be included
                # in the setup file
                item = setupString(key, item, True)

            setupDict[key] = item

        if not usePListFile:
            setupDict["plist_code"] = plist_code
        else:
            setupDict["plist_code"] = "# No code for PList"

        # Add the custom code (if any)
        setupDict["customcode"] = (customCode and [customCode.strip()] or ["# No custom code added"])[0]

        # Add the post-compilation code (if any)
        setupDict["postcompilecode"] = (postCompile and [postCompile.strip()] or ["# No post-compilation code added"])[0]

        # Include the GUI2Exe version in the setup script
        importDict["gui2exever"] = self.MainFrame.GetVersion()

        # Populate the "import" section
        setupScript = _py2app_imports % importDict

        # Populate the main section of the setup script
        setupScript += _py2app_target % setupDict

        # Send a message to out fancy bottom log window
        transdict = dict(projectName=project.GetName())
        self.MainFrame.SendMessage(0, _('Setup script for "%(projectName)s" succesfully created')%transdict)
        return setupScript, buildDir

    def OnPListAdd(self, event):
        """ Launches a custom PList editor. """

        if not self.ValidateOptions():
            # No way, something went wrong with the options set by the user
            return

        programName = self.scriptPicker.GetPath()
        programName = os.path.split(os.path.splitext(programName)[0])[1]

        # Retrieve the project stored in the parent (LabelBook) properties
        project = self.GetParent().GetProject()
        if "plist_code" in project["py2app"]:
            # Get the existing PList code (if any)
            pListCode = project["py2app"]["plist_code"]
        else:
            pListCode = {}

        dlg = PListEditor(self.MainFrame, programName,
                          pListFile=self.pListPicker.GetPath().strip(),
                          pListCode=pListCode)

        if dlg.ShowModal() == wx.ID_CANCEL:
            # User cancelled the modifications
            dlg.Destroy()
            return

        try:
            PList = dlg.GetPList()
        except:
            self.MainFrame.RunError(2, _("Invalid PList code encountered."))
            return

        project["py2app"]["plist_code"] = PList
        # Update the icon and the project name on the wx.aui.AuiNotebook tab
        self.MainFrame.UpdatePageBitmap(project.GetName() + "*", 1)

    def OnPListRemove(self, event):
        """ Deletes the PList code (if any) from the project. """

        # Retrieve the project stored in the parent (LabelBook) properties
        project = self.GetParent().GetProject()
        if "plist_code" in project["py2app"]:
            project["py2app"]["plist_code"] = {}
            # Update the icon and the project name on the wx.aui.AuiNotebook tab
            self.MainFrame.UpdatePageBitmap(project.GetName() + "*", 1)


import numpy as np

class InfeasibleProblemError(ValueError):
    pass

def convert_socp_to_cvxopt_format(c, socp_constraints):
    """
    socp_constraints = [(Nameₖ, (Aₖ, bfbₖ, bfcₖ, dₖ), ...]

    min_u   cᵀu
       s.t. dₖ + bfcₖ u ≻ |Aₖ u + bfbₖ|₂

    min cᵀu
    s.t Gₖ x + sₖ = hₖ,    k = 0, ..., M
        A x = b
        h₀ - G₀ x ⪰ 0     # Component wise inequalities
        hₖ[0] - Gₖ[0, :] x ⪰ | hₖ[1:] - Gₖ[1:, :] x |₂,    k = 1, ..., M

    """
    m = np.asarray(c).shape[-1]
    Gqs = []
    hqs = []
    for name, (A, bfb, bfc, d) in socp_constraints:
        # (name, (A, b, c, d))
        # |Au + bfb| < bfc' u + d
        # s.t. ||Ax + b||_2 <= c'x + d
        # But || h₁ - G₁x ||₂ ≺ h₀ - g₀' x
        # G = [g₀'; G₁] = [-c'; -A]
        # h = [h₀; h₁] = [d; b]
        Gqi = np.zeros((A.shape[0]+1, m))
        Gqi[0, :] = -bfc
        Gqi[1:, :] = -A
        Gqs.append(Gqi)
        hqi = np.zeros((A.shape[0]+1, 1))
        hqi[0, 0] = d.reshape(1, 1)
        hqi[1:, 0] = bfb
        hqs.append(hqi)

    return c, Gqs, hqs

def optimizer_socp_cvxopt(u0, linear_objective, socp_constraints):
    """
    Solve the optimization problem

    min_u   A u + b
       s.t. h₀ - (G u)₀ ≻ |h₁ - (Gu)₁ |₂

    u0: reference control signal
    linear_objective: (

    convert to cvxopt format and pass to cvxopt

    min cᵀu
    s.t Gₖ x + sₖ = hₖ,    k = 0, ..., M
        A x = b
        s₀ ⪰ 0            # Component wise inequalities
        sₖ₀ ⪰ | sₖ₁ |₂,    k = 1, ..., M

    min cᵀu
    s.t Gₖ x + sₖ = hₖ,    k = 0, ..., M
        A x = b
        h₀ - G₀ x ⪰ 0     # Component wise inequalities
        hₖ[0] - Gₖ[0, :] x ⪰ | hₖ[1:] - Gₖ[1:, :] x |₂,    k = 1, ..., M

    """
    from cvxopt import solvers, matrix
    c, Gqs, hqs = convert_socp_to_cvxopt_format(linear_objective,
                                                socp_constraints)
    inputs_socp = dict(c = matrix(c),
                       Gq = list(map(matrix, Gqs)),
                       hq = list(map(matrix, hqs)))
    #print("optimizers.py:72", inputs_socp)
    sol = solvers.socp(**inputs_socp)
    if sol['status'] != 'optimal':
        if sol['status'] == 'primal infeasible':
            y_uopt = sol.get('z', u0)
        else:
            y_uopt = u0

        print("{c}.T [y, u]\n".format(c=c)
              + "s.t. "
              + "".join((" sq = {hq} - {Gq} [{y_uopt}]\n".format(hq=np.asarray(hq),
                                                             Gq=np.asarray(Gq),
                                                             y_uopt=np.asarray(y_uopt))
                     for Gq, hq in zip(Gqs, hqs))))
        raise InfeasibleProblemError("Infeasible problem: %s" % sol['status'])

    return np.asarray(sol['x']).astype(u0.dtype).reshape(-1)

def optimizer_socp_cvxpy(u0, linear_objective, socp_constraints, solver='GUROBI'):
    import cvxpy as cp
    x = cp.Variable(u0.shape)
    x.value = u0
    constraints = []
    for name, (A, bfb, bfc, d) in socp_constraints:
        constraints.append(cp.norm(A @ x + bfb) <= bfc @ x + d)

    obj = cp.Minimize(linear_objective @ x)
    prob = cp.Problem(obj, constraints)
    prob.solve(solver=solver)
    return x.value

def optimizer_qp_cvxpy(u0, quadratic_objective, linear_constraints, solver='GUROBI'):
    import cvxpy as cp
    x = cp.Variable(u0.shape)
    x.value = u0
    constraints = []
    for name, (bfc, d) in linear_constraints:
        constraints.append(0 <= bfc @ x + d)
    A, bfb = quadratic_objective
    obj = cp.Minimize(cp.sum_squares(A @ x + bfb))
    prob = cp.Problem(obj, constraints)
    prob.solve(solver=solver)
    return x.value


from django.db import models
from users.models import User

from dataclasses import dataclass

class ConnectionRequest(models.Model):
    number = models.PositiveIntegerField(db_index=True, verbose_name='Номер заявки')
    client = models.ForeignKey(
        'Client', related_name='connection_requests',
        on_delete=models.PROTECT,
        verbose_name='Клиент'
    )
    status = models.ForeignKey(
        'Status', related_name='connection_requests',
        on_delete=models.PROTECT,
        verbose_name='Статус заявки'
    )
    date_entered_status = models.DateTimeField(
        verbose_name='Дата входа заявки в статус'
    )
    service = models.ForeignKey(
        'Service', related_name='connection_requests',
        on_delete=models.PROTECT,
        verbose_name='Услуга'
    )
    additional_sales_channel = models.ForeignKey(
        'AdditionalSalesChannel',
        related_name='connection_requests',
        on_delete=models.PROTECT,
        blank=True, null=True,
        verbose_name='Доп.канал продаж'
    )
    reg_date = models.DateTimeField(verbose_name='Дата регистрации')
    reg_date_for_request = models.DateTimeField(
        null=True, verbose_name='Дата регистрации под заявки'
    )
    reg_date_brigade_for_TVP = models.DateTimeField(
        null=True, verbose_name='Регистрация наряда на ТВП'
    )
    completed_by = models.ForeignKey(
        User, related_name='completed_connection_requests',
        on_delete=models.PROTECT,
        blank=True, null=True,
        verbose_name='Оператор завершивший заявку'
    )
    rejection_date = models.DateTimeField(
        null=True, verbose_name='Дата отклонения под заявки'
    )
    TVP_test_type = models.ForeignKey(
        'TVPTestType', related_name='connection_requests',
        on_delete=models.PROTECT, null=True,
        verbose_name='Тип проверки ТВП'
    )
    TVP_presence = models.ForeignKey(
        'TVPPresence', related_name='connection_requests',
        on_delete=models.PROTECT, null=True,
        verbose_name='Наличие ТВП'
    )
    completion_TVP_date = models.DateTimeField(
        null=True, verbose_name='Завершение проверки ТВП'
    )
    TVP_check_duration = models.TimeField(
        null=True, verbose_name='Длительность проверки ТВП'
    )
    agreed_connection_date = models.DateTimeField(
        blank=True, null=True, verbose_name='Согласованная дата подключения'
    )
    installer = models.ForeignKey(
        'Installer', related_name='connection_requests',
        on_delete=models.PROTECT, blank=True, null=True,
        verbose_name='Инсталлятор'
    )
    agent_installer = models.ForeignKey(
        'AgentInstaller', related_name='connection_requests',
        on_delete=models.PROTECT, blank=True, null=True,
        verbose_name='Агент-инсталлятор'
    )
    comment_TVP_ShPD = models.CharField(
        max_length=250, blank=True, verbose_name='Комментарий ТВП ШПД',
        null=True
    )
    started_by = models.ForeignKey(
        User, related_name='started_connection_requests',
        on_delete=models.PROTECT, blank=True, null=True,
        verbose_name='Оператор заводивший заявку'
    )
    id_agreement_KURS = models.CharField(
        max_length=250, blank=True, verbose_name='ID Договор КУРС',
        null=True
    )
    note = models.CharField(
        max_length=250, blank=True, verbose_name='Примечание',
        null=True
    )
    contact_phone_number = models.PositiveIntegerField(
        blank=True, null=True, verbose_name='Контактный телефон',
        default=0
    )
    contact_person = models.CharField(
        max_length=200, blank=True, verbose_name='Контактное лицо',
        null=True
    )
    TP_ShPD_price = models.DecimalField(
        max_digits=8, decimal_places=2, blank=True,
        null=True, verbose_name='Стоимость ТП (ШПД)'
    )
    TP_IPTV_price = models.DecimalField(
        max_digits=8, decimal_places=2, blank=True,
        null=True, verbose_name='Стоимость ТП (IPTV)'
    )
    contract_created_by_fio = models.CharField(
        max_length=250, blank=True,
        verbose_name='ФИО сотрудника создавшего договор',
        null=True
    )
    IPTV_tariff_plan = models.ForeignKey(
        'IPTVTariffPlan', related_name='connection_requests',
        on_delete=models.PROTECT, blank=True, null=True,
        verbose_name='Тарифный план IPTV'
    )
    access_card_number = models.PositiveIntegerField(
        blank=True, null=True, verbose_name='Номер карты доступа'
    )
    IPTV_access_card_number = models.PositiveIntegerField(
        blank=True, null=True, verbose_name='Номер карты доступа IPTV'
    )
    tariff_plan = models.ForeignKey(
        'TariffPlan', related_name='connection_requests',
        on_delete=models.PROTECT, blank=True, null=True,
        verbose_name='Тарифный план'
    )
    client_number_SUS = models.PositiveIntegerField(
        blank=True, null=True, verbose_name='№ клиентский СУС'
    )
    sending_date_APTV = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата отправки на АПТВ'
    )
    finishing_date_APTV_planned = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата окончания АПТВ планируемая'
    )
    finishing_date_APTV_actual = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата окончания АПТВ фактическая'
    )
    APTV_duration = models.DurationField(
        blank=True, null=True, verbose_name='Длительность этапа АПТВ'
    )
    sending_date_DO = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата отправки на ДО'
    )
    finishing_date_DO_planned = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата окончания ДО планируемая'
    )
    finishing_date_DO_actual = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата окончания ДО фактическая'
    )
    DO_duration = models.DurationField(
        blank=True, null=True, verbose_name='Длительность этапа ДО',
    )

    class Meta:
        verbose_name = 'Заявка на подключение'
        verbose_name_plural = 'Заявки на подключение'
        ordering = ('-date_entered_status',)

    def __str__(self):
        return f"Заявка №{self.number}"

class Client(models.Model):
    title = models.CharField(max_length=250, verbose_name='Название клиента')
    INN = models.PositiveBigIntegerField(db_index=True, verbose_name='ИНН')

    class Meta:
        verbose_name = 'Клиент'
        verbose_name_plural = 'Клиенты'

    def __str__(self):
        return self.title

class Status(models.Model):
    title = models.CharField(max_length=100, verbose_name='Название')
    group = models.ForeignKey(
        'StatusGroup', related_name='statuses',
        on_delete=models.PROTECT, verbose_name='Группа'
    )

    class Meta:
        verbose_name = 'Статус заявки'
        verbose_name_plural = 'Статусы заявок'
        ordering = ('group', 'title')

    def __str__(self):
        return self.title

class StatusGroup(models.Model):
    title = models.CharField(max_length=30, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Группа статуса'
        verbose_name_plural = 'Группы статусов'

    def __str__(self):
        return self.title

class Service(models.Model):
    title = models.CharField(max_length=50, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Услуга'
        verbose_name_plural = 'Услуги'

    def __str__(self):
        return self.title

class AdditionalSalesChannel(models.Model):
    title = models.CharField(max_length=60, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Доп.канал продажи'
        verbose_name_plural = 'Доп.каналы продажи'

    def __str__(self):
        return self.title

class TVPTestType(models.Model):
    title = models.CharField(max_length=50, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Тип проверки ТВП'
        verbose_name_plural = 'Типы проверок ТВП'

    def __str__(self):
        return self.title

class TVPPresence(models.Model):
    title = models.CharField(max_length=50, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Наличие ТВП'
        verbose_name_plural = 'Наличие ТВП'

    def __str__(self):
        return self.title

class Installer(models.Model):
    first_name = models.CharField(max_length=50, verbose_name='Имя')
    last_name = models.CharField(max_length=50, verbose_name='Фамилия')
    surname = models.CharField(max_length=50, verbose_name='Отчество')

    class Meta:
        verbose_name = 'Инсталлятор'
        verbose_name_plural = 'Инсталляторы'

    def __str__(self):
        return f"{self.last_name} {self.first_name} {self.surname}"

class AgentInstaller(models.Model):
    title = models.CharField(max_length=250, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Агент-инсталлятор'
        verbose_name_plural = 'Агенты-инсталляторы'

    def __str__(self):
        return self.title

class IPTVTariffPlan(models.Model):
    title = models.CharField(max_length=100, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Тарифный план IPTV'
        verbose_name_plural = 'Тарифные планы IPTV'

    def __str__(self):
        return self.title

class TariffPlan(models.Model):
    title = models.CharField(max_length=100, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Тарифный план'
        verbose_name_plural = 'Тарифные планы'

    def __str__(self):
        return self.title

#
# class File(models.Model):
#     title = models.CharField(max_length=256, default='No title', verbose_name='Название')
#     file = models.FileField(upload_to='files', verbose_name='Файл')
#     upload_at = models.DateTimeField(auto_now_add=True, verbose_name='Дата загрузки')
#
#     class Meta:
#         verbose_name = 'Файл .xlsx с заявками'
#         verbose_name_plural = 'Файлы .xlsx с заявками'
#         ordering = ('-upload_at',)
#

@dataclass
class DataExel:
    number: int
    client: str
    inn: int
    status: str
    date_entered_status: str
    service: str
    additional_sales_channel: str
    reg_date: str
    reg_date_for_request: str
    reg_date_brigade_for_TVP: str
    completed_by: str
    rejection_date: str
    TVP_test_type: str
    TVP_presence: str
    completion_TVP_date: str
    TVP_check_duration: str
    agreed_connection_date: str
    installer: str
    agent_installer: str
    comment_TVP_ShPD: str
    started_by: str
    id_agreement_KURS: str
    number_agreement_KURS: str
    note: str
    contact_phone_number: str
    contact_person: str
    TP_ShPD_price: str
    TP_IPTV_price: str
    contract_created_by_fio: str
    IPTV_tariff_plan: str
    access_card_number: str
    IPTV_access_card_number: str
    tariff_plan: str
    client_number_SUS: str
    sending_date_APTV: str
    finishing_date_APTV_planned: str
    finishing_date_APTV_actual: str
    APTV_duration: str
    sending_date_DO: str
    finishing_date_DO_planned: str
    finishing_date_DO_actual: str
    DO_duration: str


from datetime import datetime
from django.shortcuts import render, redirect
from .models import Team
from cars.models import Car
from django.contrib.auth.models import User
from django.core.mail import send_mail
from django.contrib import messages
from django.core.paginator import Paginator

# Create your views here.

def home(request):
    teams = Team.objects.all()

    """Starting the paginating Shit"""

    featured_cars = Car.objects.order_by('-created_date').filter(sold=False,is_featured=True)

    all_cars = Car.objects.order_by('-created_date').filter(sold=False)
    paginator = Paginator(all_cars,6)
    page = request.GET.get('page')
    all_cars = paginator.get_page(page)

    brand_search = Car.objects.filter(sold=False).values_list('brand', flat=True).distinct()
    city_search = Car.objects.filter(sold=False).values_list('city', flat=True).distinct()
    year_search = [x for x in range(2010,datetime.now().year)]
    body_style_search = ['sedan','hatchback','SUV']
    data = {
        'teams': teams,
        'featured_cars': featured_cars,
        'all_cars': all_cars,
        'brand_search': sorted(brand_search),
        'city_search': sorted(city_search),
        'year_search': year_search,
        'body_style_search': body_style_search,
    }
    return render(request, 'pages/home.html', data)

def about(request):
    teams = Team.objects.all()
    data = {
        'teams': teams,
    }
    return render(request, 'pages/about.html', data)

def services(request):
    return render(request, 'pages/services.html')

def contact(request):
    if request.method == 'POST':
        name = request.POST['name']
        email = request.POST['email']
        subject = request.POST['subject']
        phone = request.POST['phone']
        message = request.POST['message']

        email_subject = 'You have a new message from Carzone website regarding ' + subject
        message_body = 'Name: ' + name + '. Email: ' + email + '. Phone: ' + phone + '. Message: ' + message

        admin_info = User.objects.get(is_superuser=True)
        admin_email = admin_info.email
        send_mail(
                email_subject,
                message_body,
                '',
                [admin_email],
                fail_silently=False,
            )
        messages.success(request, 'Thank you for contacting us. We will get back to you shortly')
        return redirect('contact')

    return render(request, 'pages/contact.html')


import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as trans
import os
import numpy as np
from torch.utils.data import Dataset, DataLoader
from torchvision.transforms import ToTensor
from torchvision import datasets, transforms
from torch.nn.modules.utils import _single, _pair, _triple

inpsiz = 784
hidensiz = 500
numclases = 10
numepchs = 100
bachsiz = 32
l_r = 0.001

data = np.load('data.npy')
test_data = np.load('test_data.npy')
label = np.load('label.npy')
test_label = np.load('test_label.npy')

device = 'cuda' if torch.cuda.is_available() else 'cpu'

def quantize(v, bit=4):
    factor = torch.max(torch.relu(v)) * (2**(bit-1))
    return (v*factor).int()

class MyConv2d(torch.nn.modules.conv._ConvNd):
    """
    Implements a standard convolution layer that can be used as a regular module
    """

    def __init__(self, in_channels, out_channels, kernel_size, stride=1,
                 padding=0, dilation=1, groups=1,
                 bias=True, padding_mode='zeros', use_Q=True):
        kernel_size = _pair(kernel_size)
        stride = _pair(stride)
        padding = _pair(padding)
        dilation = _pair(dilation)
        super(MyConv2d, self).__init__(
            in_channels, out_channels, kernel_size, stride, padding, dilation,
            False, _pair(0), groups, bias, padding_mode)
        self.use_Q = use_Q

    def reset_Q(self):
        self.Q_weight = quantize(torch.tensor(self.weight.view(self.weight.size(0), -1).t()))

    def forward(self, input):
        return myconv2d(input, self.weight, self.bias, self.stride,
                        self.padding, self.dilation, self.groups, self.Q_weight, self.use_Q)

def myconv2d(input, weight, bias=None, stride=(1, 1), padding=(0, 0), dilation=(1, 1), groups=1, Q=None,  use_Q=True):
    """
    Function to process an input with a standard convolution
    """
    batch_size, in_channels, in_h, in_w = input.shape
    out_channels, in_channels, kh, kw = weight.shape
    out_h = int((in_h - kh + 2 * padding[0]) / stride[0] + 1)
    out_w = int((in_w - kw + 2 * padding[1]) / stride[1] + 1)
    unfold = torch.nn.Unfold(kernel_size=(kh, kw), dilation=dilation, padding=padding, stride=stride)
    inp_unf = unfold(input)
    w_ = weight.view(weight.size(0), -1).t()    # w_(9, 32)

    X = inp_unf.transpose(1, 2)
    out_unf = (X @ w_ + bias)

    q_X = quantize(X)
    q_bias = quantize(bias)
    upper = quantize(q_X @ Q + q_bias)

    mask = (upper <= 0)

    if use_Q:
        out_unf[mask] = 0

    out_unf = out_unf.transpose(1, 2)
    out = out_unf.view(batch_size, out_channels, out_h, out_w)  # (1, 32, 26, 26)
    return out.float()

nn.Conv2d = MyConv2d

class MyDS(Dataset):
    """Face Landmarks dataset."""

    def __init__(self, data, label, transform=None):
        self.data = data
        self.label = label
        self.transform = transform

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

    def __getitem__(self, idx):
        x = self.data[idx]
        y = self.label[idx]

        if self.transform:
            return self.transform(torch.tensor(x.reshape(1, 28, 28), dtype=torch.float32)), torch.tensor(y,
                                                                                dtype=torch.long)
        else:
            return torch.tensor(x, dtype=torch.float32), torch.tensor(y, dtype=torch.long)

t = transforms.Compose([
    transforms.Normalize(mean=(0.5,), std=(0.5,))
])

ds = MyDS(data, label, t)
test_ds = MyDS(test_data, test_label, t)

trainldr = torch.utils.data.DataLoader(dataset=ds,
                                       batch_size=bachsiz,
                                       shuffle=True)
test_trainldr = torch.utils.data.DataLoader(dataset=test_ds,
                                            batch_size=1000)

print('train data len is ', len(trainldr.dataset))
print('test data len is ', len(test_trainldr.dataset))

class neural_network(nn.Module):
    def __init__(self):
        super(neural_network, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1, use_Q=True)
        self.conv2 = nn.Conv2d(32, 64, 3, 1, use_Q=False)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = torch.relu(x)
        x = self.conv2(x)
        x = torch.relu(x)
        x = torch.max_pool2d(x, 2)
        x = self.dropout1(x)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = torch.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        return x

modl = neural_network().to(device)
modl.load_state_dict(torch.load('cnn.pt', map_location=device), strict=False)

modl.conv1.reset_Q()
modl.conv2.reset_Q()

modl.eval()
with torch.no_grad():
    correct = 0
    total = 0
    for x, (imgs, lbls) in enumerate(test_trainldr):
        imgs = imgs.reshape(-1, 1, 28, 28).to(device)
        lbls = lbls.to(device)
        outp = modl(imgs)
        pred = outp.data.max(1, keepdim=True)[1].to(device)
        correct += pred.eq(lbls.data.view_as(pred)).sum().detach().cpu().item()
        total += torch.numel(pred)
    print('Acc = {}'.format(correct / total))

torch.save(modl.state_dict(), 'cnn.pt')


import yaml
import sys

def SkeletonInstance():
    skeleton = """description:
  set: Bischoff & Ratcliff
  name: '1.1'
constraints:
- name: orientation
- name: support
objectives:
- name: average_fill_rate
  weight: 1.0
  priority: 1
- name: item_count
  weight: 1.0
  priority: 2"""
    return yaml.load( skeleton, Loader=yaml.FullLoader )

def create_instance(instance, solution, solution_file_name):

    skeleton = SkeletonInstance()
    with open(instance) as f:
        instance = yaml.load( f, Loader=yaml.FullLoader )
    if not instance is None:
        container = {}
        palletkinds = []
        container["palletkinds"] = palletkinds
        boxkinds = []
        container["boxkinds"] = boxkinds
        containerkinds = []
        c = {}
        c["id"] = 1
        c["quantity"] = 1
        c["loadingspaces"] = []
        l = {}
        l["id"] = 1
        l["position"] = "0,0,0"
        l["size"] = {}
        l["size"]["length"] = instance['data']["containerkinds"][0]["loadingspaces"][0]["size"]["length"]
        l["size"]["width"] = instance['data']["containerkinds"][0]["loadingspaces"][0]["size"]["width"]
        l["size"]["height"] = instance['data']["containerkinds"][0]["loadingspaces"][0]["size"]["height"]
        c["loadingspaces"].append(l)
        containerkinds.append(c)
        container["containerkinds"] = containerkinds

        with open(solution) as f:
            solution = yaml.load( f, Loader=yaml.FullLoader )
        if not solution is None:
            itemkinds = []
            ids = []
            for i in solution['layout']['containers'][0]['loadingspaces'][0]['placements']:
                if i['itemid'] in ids:
                    itemkinds[ids.index(i['itemid'])]["quantity"] += 1
                    itemkinds[ids.index(i['itemid'])]["placed"] += 1
                    itemkinds[ids.index(i['itemid'])]["positions"].append(i["position"])
                    itemkinds[ids.index(i['itemid'])]["given_orientation"].append(i["orientation"])
                else:
                    ids.append(i['itemid'])
                    temp_block_dict = {}
                    temp_block_dict["id"] = i['itemid']
                    temp_block_dict["quantity"] = 1
                    temp_block_dict["placed"] = 1
                    temp_block_dict["positions"] = [i["position"]]
                    temp_block_dict["given_orientation"] = [i["orientation"]]
                    temp_block_dict["support"] = 1.0
                    temp_block_dict["color"] = i['color']
                    #only possible orientation is to place facing upwards like it was created
                    temp_block_dict["orientations"] = instance['data']['itemkinds'][i['itemid']-1]['orientations']
                    temp_block_dict["size"] = {}
                    temp_block_dict["size"]["width"] = instance['data']['itemkinds'][i['itemid']-1]['size']["width"]
                    temp_block_dict["size"]["length"] = instance['data']['itemkinds'][i['itemid']-1]['size']["length"]
                    temp_block_dict["size"]["height"] = instance['data']['itemkinds'][i['itemid']-1]['size']["height"]
                    itemkinds.append(temp_block_dict)
            for i in solution['layout']['unplaced']:
                if i['itemid'] in ids:
                    itemkinds[ids.index(i['itemid'])]["quantity"] += i["quantity"]
                else:
                    ids.append(i['itemid'])
                    temp_block_dict = {}
                    temp_block_dict["id"] = i['itemid']
                    temp_block_dict["quantity"] = i["quantity"]
                    temp_block_dict["placed"] = 0
                    temp_block_dict["support"] = 1.0
                    temp_block_dict["color"] = instance['data']['itemkinds'][i['itemid']-1]['color']
                    #only possible orientation is to place facing upwards like it was created
                    temp_block_dict["orientations"] = instance['data']['itemkinds'][i['itemid']-1]['orientations']
                    temp_block_dict["size"] = {}
                    temp_block_dict["size"]["width"] = instance['data']['itemkinds'][i['itemid']-1]['size']["width"]
                    temp_block_dict["size"]["length"] = instance['data']['itemkinds'][i['itemid']-1]['size']["length"]
                    temp_block_dict["size"]["height"] = instance['data']['itemkinds'][i['itemid']-1]['size']["height"]
                    itemkinds.append(temp_block_dict)

            container["itemkinds"] = itemkinds
            skeleton['data'] = container

        with open(solution_file_name, 'w') as file:
            documents = yaml.dump(skeleton, file)
        file.close()

def parse_args():
    if sys.argv == []:
        exit()
    return sys.argv[1], sys.argv[2], sys.argv[3]

if __name__ == "__main__":
    create_instance(*parse_args())


import logging
import os
from io import StringIO

import pandas as pd
import requests

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
api_token = os.environ.get('EODHD_API_KEY')

def fetch_exchanges():
    url = f'https://eodhistoricaldata.com/api/exchanges-list/?api_token={api_token}&fmt=json'
    response = requests.get(url)

    if response.status_code == 200:
        return response.json()
    else:
        raise requests.exceptions.RequestException(f'Error: {response.status_code}')

def fetch_country_macro_data(country, indicator):
    url = f'https://eodhistoricaldata.com/api/macro-indicator/{country}?api_token={api_token}&fmt=json&indicator={indicator}'
    response = requests.get(url)
    response.raise_for_status()
    return response.json()

def fetch_exchange_tickers(exchange_code, delisted=0):
    url = f'https://eodhistoricaldata.com/api/exchange-symbol-list/{exchange_code}?api_token={api_token}&delisted={delisted}'
    response = requests.get(url)

    if response.status_code == 200:
        csv_data = StringIO(response.text)
        df = pd.read_csv(csv_data)
        tickers = df.to_dict('records')
        return tickers
    else:
        raise requests.exceptions.RequestException(f'Error {response.status_code} for exchange {exchange_code}')

def fetch_stock_fundamental_data(ticker):
    try:
        url = f'https://eodhistoricaldata.com/api/fundamentals/{ticker}?api_token={api_token}'
        response = requests.get(url)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.HTTPError as e:
        logging.error(f"Error fetching fundamental data for {ticker}")
        write_ticker_to_failed_tickers(ticker)

        logging.error(f"Error: {e}")
        return None

def fetch_stock_ticker_price(ticker):
    try:
        url = f'https://eodhistoricaldata.com/api/eod/{ticker}?api_token={api_token}&period=m'
        response = requests.get(url)
        response.raise_for_status()
        return response.text
    except requests.exceptions.HTTPError as e:
        logging.error(f"Error fetching price data for {ticker}")
        write_ticker_to_failed_tickers(ticker)

        logging.error(f"Error: {e}")
        return None

def fetch_index_price(ticker, exchange):
    try:
        url = f'https://eodhistoricaldata.com/api/eod/{ticker}.{exchange}?api_token={api_token}&period=m'
        response = requests.get(url)
        response.raise_for_status()
        return response.text
    except requests.exceptions.HTTPError as e:
        logging.error(f"Error fetching price data for {ticker}")
        write_ticker_to_failed_tickers(ticker)

        logging.error(f"Error: {e}")
        return None

def fetch_stock_tickers(ticker):
    logging.info(f"Fetching stock tickers for {ticker}")
    url = f'https://eodhistoricaldata.com/api/fundamentals/{ticker}?api_token={api_token}'
    response = requests.get(url)
    response.raise_for_status()

    data = response.json()
    stock_tickers = [data["General"]["PrimaryTicker"]]

    for listing_index in data["General"]["Listings"]:
        stock_tickers.append(f'{data["General"]["Listings"][listing_index]["Code"]}.{data["General"]["Listings"][listing_index]["Exchange"]}')

    logging.info(f"Finished fetching stock tickers for {ticker}" )
    return list(set(stock_tickers))

def fetch_stock_sentiment_data(source, all_tickers):
    logging.info(f"Fetching stock sentiment data for source {source}")
    if source not in {"news", "tweets"}:
        logging.error(f"Invalid source {source}")
        raise ValueError(f"Invalid source {source}")

    url = f'https://eodhistoricaldata.com/api/{source+"-" if source == "tweets" else ""}sentiments?s={",".join(all_tickers)}&api_token={api_token}'
    response = requests.get(url)
    response.raise_for_status()

    logging.info(f"Finished fetching stock sentiment data for source {source}")
    return response.json()

def fetch_index_constituents(index_code,exchange):
    url = f'https://eodhistoricaldata.com/api/fundamentals/{index_code}.{exchange}?api_token={api_token}'
    response = requests.get(url)
    response.raise_for_status()
    json_response = response.json()
    constituents = []
    for listing_index in json_response["Components"]:
        constituents.append(f'{json_response["Components"][listing_index]["Code"]}.{json_response["Components"][listing_index]["Exchange"]}')

    # Also add hitorical constituents if available
    if "HistoricalTickerComponents" in json_response:
        for listing_index in json_response["HistoricalTickerComponents"]:
            constituents.append(f'{json_response["HistoricalTickerComponents"][listing_index]["Code"]}')

    return constituents

def write_ticker_to_failed_tickers(ticker):
    failed_tickers = pd.read_csv("failed_tickers.csv", header=0)
    failed_tickers.loc[len(failed_tickers)] = [ticker]
    failed_tickers.to_csv("failed_tickers.csv", index=False)


from PyQt5.QtWidgets import QApplication, QListWidget, QMenuBar, QMainWindow, QDockWidget, QTextEdit
import sys
from PyQt5 import QtGui
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt

class DockDialog(QMainWindow):
    def __init__(self):
        super().__init__()
        self.title = "Pyqt5 QDockAble"
        self.top = 500
        self.left = 500
        self.width = 600
        self.height = 200
        self.iconName = "transistor.jpg"
        self.setWindowIcon(QIcon(self.iconName))
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.createDockWidget()

    def createDockWidget(self):
        menubar = self.menuBar()
        file = menubar.addMenu("File")
        file.addAction("New")
        file.addAction("save")
        file.addAction("Close")
        self.dock = QDockWidget("Dockable", self)
        self.listwidget = QListWidget()
        list = ["Python", "C++", "java", "c#"]
        self.listwidget.addItems(list)
        self.dock.setWidget(self.listwidget)
        self.setCentralWidget(QTextEdit())
        self.addDockWidget(Qt.RightDockWidgetArea, self.dock)

if __name__ == "__main__":
    App = QApplication(sys.argv)
    Dock = DockDialog()
    Dock.show()
    sys.exit(App.exec())


import motivation as motivation
from django.urls import path

from . import views

urlpatterns = [
    path('', views.home_lifts, name='home_lifts'),
    path('edit/<int:id>', views.edit_lift, name='edit'),
    path('add-lift', views.create_lift, name='create_lift'),
    path('delete-lift/<int:id>', views.delete_lift, name='delete_lift'),
    path('edit-lift/<int:id>', views.edit_lift, name='edit_lift'),
    # Nutrition paths
    path('nutrition', views.home_nutrition, name='home_nutrition'),
    path('add-food', views.create_food, name='create_food'),
    path('delete-food/<int:id>', views.delete_food, name='delete_food'),
    path('edit-food/<int:id>', views.edit_food, name='edit_food'),
    # Motivation path
    path('motivation', views.motivation, name='motivation'),
    # Weight Paths
    path('weight', views.home_weight, name='home_weight'),
    path('add-weight', views.add_weight, name='add_weight'),
    path('delete-weight/<int:id>', views.delete_weight, name='delete_weight'),
    path('edit-weight/<int:id>', views.edit_weight, name='edit_weight'),
    # Register Path
    path('register', views.register_view, name="register"),
    # Login Path
    path('login', views.login_view, name="login"),
    # Logout Path
    path('logout', views.logout_view, name="logout"),

]


from src.GraphAlgo import GraphAlgo
import networkx as nx
import time

def current_time() -> int:
    """
    get current time in millisecond
    :return:
    """
    return int(round(time.time() * 1000))

def execute(file_name):
    """
    execute time test (in millisecond) with GraphAlgo and NetworkX classes by file_name json of a graph
    :param file_name:
    :return:
    """
    graph_algo = GraphAlgo()

    print(file_name)

    # graph_algo load graph
    millis_at_start = current_time()
    graph_algo.load_from_json(file_name)
    millis_at_end = current_time()
    print('load:', millis_at_end - millis_at_start, 'ms')

    # networkX load graph
    millis_at_start = current_time()
    network = nx.DiGraph()
    network.add_nodes_from(graph_algo.get_graph().get_all_v().keys())
    for i in graph_algo.get_graph().get_all_v().keys():
        childes = graph_algo.get_graph().all_out_edges_of_node(i)
        for k, v in childes.items():
            network.add_edge(i, k, weight=float(v))
    millis_at_end = current_time()
    print('X - load:', millis_at_end - millis_at_start, 'ms')

    # graph_algo shortest path
    millis_at_start = current_time()
    graph_algo.shortest_path(0, 9)
    millis_at_end = current_time()
    print('shortest_path:', millis_at_end - millis_at_start, 'ms')

    # networkX shortest path
    millis_at_start = current_time()
    try:
        nx.shortest_path(network, source=0, target=9, method='dijkstra')
    except nx.NodeNotFound:
        print('path not found!')
    millis_at_end = current_time()
    print('X - shortest_path:', millis_at_end - millis_at_start, 'ms')

    # graph_algo connected component
    millis_at_start = current_time()
    graph_algo.connected_component(0)
    millis_at_end = current_time()
    print('connected_component:', millis_at_end - millis_at_start, 'ms')

    # networkX connected component
    millis_at_start = current_time()
    components = nx.strongly_connected_components(network)
    for i in components:
        if 0 in i:
            break
    millis_at_end = current_time()
    print('X - connected_component:', millis_at_end - millis_at_start, 'ms')

    # graph_algo connected components
    millis_at_start = current_time()
    graph_algo.connected_components()
    millis_at_end = current_time()
    print('connected_components:', millis_at_end - millis_at_start, 'ms')

    # networkX connected components
    millis_at_start = current_time()
    nx.strongly_connected_components(network)
    millis_at_end = current_time()
    print('X - connected_component:', millis_at_end - millis_at_start, 'ms')

if __name__ == '__main__':

    # paths
    graphs_no_pos = 'data/graphs_no_pos/'
    graphs_on_circle = 'data/graphs_on_circle/'
    graphs_random_pos = 'data/graphs_random_pos/'

    # seeds
    zero = '0'
    one = '1'
    two = '2'

    # execute check
    execute(graphs_no_pos + 'G_10_80_' + zero + '.json')
    execute(graphs_no_pos + 'G_100_800_' + zero + '.json')
    execute(graphs_no_pos + 'G_1000_8000_' + zero + '.json')
    execute(graphs_no_pos + 'G_10000_80000_' + zero + '.json')
    execute(graphs_no_pos + 'G_20000_160000_' + zero + '.json')
    execute(graphs_no_pos + 'G_30000_240000_' + zero + '.json')


"""mysite URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/dev/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
# from django.conf.urls import handler404, handler500
# from django.conf import settings
# from django.conf.urls.static import static
from . import views

# Project总路由
urlpatterns = [
    path('', views.home, name='url_home'),     # project首页url: localhost:8080/
    path('admin/', admin.site.urls),
    path('blog/', include('blog.blog_urls')),   # blog app分支url: localhost:8080/blog
    path('comment/', include('comment.comment_urls')),  # comment app分支url: localhost:8080/comment
    path('user/', include('user_admin.user_urls')),   # user_admin app分支url: localhost:8080/user
    # 设置ckeditor url
    # path('ckeditor/', include('ckeditor-uploader.urls')),
]

# 自定义404、500页面
handler404 = 'mysite.views.page_not_found'
# handler500 = 'mysite.views.page_error'

# urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


from wagtail.admin.menu import admin_menu

import pytest

from wagtailpurge.constants import APP_ICON
from wagtailpurge.models import REQUEST_CLASSES

def test_menu_item_registered():
    purge_menu_item = None
    for item in admin_menu.registered_menu_items:
        if (
            getattr(item, "label", "") == "Purge"
            and getattr(item, "icon_name", "") == APP_ICON
        ):
            purge_menu_item = item
            break
    assert purge_menu_item is not None

@pytest.mark.parametrize("model", [m for m in REQUEST_CLASSES])
def test_index_urls_registered(admin_client, model):
    # Visit the index url for this model
    response = admin_client.get(f"/admin/wagtailpurge/{model.__name__.lower()}/")
    # If the URL weren't registered, this would be a 404
    assert response.status_code == 200

@pytest.mark.parametrize("model", [m for m in REQUEST_CLASSES])
def test_submit_urls_registered(admin_client, model):
    # Visit the submit url for this model
    response = admin_client.get(f"/admin/wagtailpurge/{model.__name__.lower()}/create/")
    # If the URL weren't registered, this would be a 404
    assert response.status_code == 200


from flask import Flask, render_template, request, make_response
from fastai import *
from fastai.vision import *
import os
IMG_FOLDER = '/static'
app = Flask(__name__)
app.config['IMG_FOLDER'] = IMG_FOLDER
learn = load_learner('model/')

@app.route('/upload')
def upload():
   return render_template('upload.html')

@app.route('/result', methods = ['GET', 'POST'])
def upload_file():
   if request.method == 'POST':
      f = request.files['file']
      f.save('static/img.jpg')
      f.close()
      img = open_image('static/img.jpg')
      prediction = learn.predict(img)[0]
      template = open('templates/result.html', 'w')
      content = """<!DOCTYPE html>

    <meta charset="UTF-8">
    <title>Result</title>

            prediction = """ + str(prediction) + """

"""
      template.write(content)
      template.close()

      resp = make_response(render_template("result.html"))
      resp.headers['Cache-Control'] =  'no-cache, no-store'
      resp.headers['Pragma'] = 'no-cache'
      return resp

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


#Chapter04-03
#파이썬 조건문
#while

#Whiel <expr>:
#   <statement(s)>
#한글 지원
import sys
import io
sys.stdout  = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr  = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
#예제1
n = 5
while n > 0:
    print(n)
    n = n - 1

#예제2
a = ['Kim','Park','Lee']

while a:
    print(a.pop())
    #print(a)하면 무한 반복해서 위험한 코드
    #Last in First

#예제3
#break, countinue

n =5
while n > 0:
    n -= 1
    if n == 2:
        break
    print(n)
print('end')

#예제4
#break, countinue
m = 5
while m > 0:
    m -= 1
    if m == 2:
        continue
    print(m)
print('end')

#if 중첩
#예제5
i = 1
while i<= 10:
    print(i)
    if i==6:
        break
    i += 1

#wjile - else 구문
#예제6
n = 10
while n > 0:
    n -= 1
    print(n)
    if n == 5:
        break
else:
    print('else out.')

    #정상적으로 모든 것을 잘 수행하면 else를 수행
    #break문 있으면 else문 아들어감

#예제7
a = ['foo', 'bar', 'baz', 'qux']
x = 'qux'
i = 0
while i < len(a):
    if a[i] == x:
        break
    print(a[i] , '를 찾았습니다.')


import torch
import torch.nn as nn
import torch.nn.functional as F
from models.nrms.doc_encoder import DocEncoder
from models.nrms.attention import  AdditiveAttention
from models.nrms.mha import MultiheadAttention

class NRMS(nn.Module):
    def __init__(self, hparams, weight=None, p=.2):
        super(NRMS, self).__init__()
        self.hparams = hparams
        self.p = p
        self.doc_encoder = DocEncoder(hparams, weight=weight)
        self.mha = MultiheadAttention(
            input_dim=hparams["encoder_size"],
            num_heads=hparams["nhead"],
            embed_dim=hparams["encoder_size"]
        ).cuda()
        self.additive_attn = AdditiveAttention(hparams['encoder_size'], hparams['v_size']).cuda()
        self.criterion = nn.CrossEntropyLoss().cuda()
        self.dropout = torch.nn.Dropout(self.p).cuda()

    def forward(self, clicks, cands, labels=None):
        """forward

        Args:
            clicks (tensor): [num_user, num_click_docs, seq_len]
            cands (tensor): [num_user, num_candidate_docs, seq_len]
        """
        num_click_docs = clicks.shape[1]
        num_cand_docs = cands.shape[1]
        num_user = clicks.shape[0]
        seq_len = clicks.shape[2]
        clicks = clicks.reshape(-1, seq_len) # [B, seq_len]
        cands = cands.reshape(-1, seq_len) # [B, seq_len]
        click_embed = self.doc_encoder(clicks) # [B, encoder_size]
        cand_embed = self.doc_encoder(cands) # [B, encoder_size]
        click_embed = click_embed.reshape(num_user, num_click_docs, -1) # [B, num_click_docs, encoder_size]
        cand_embed = cand_embed.reshape(num_user, num_cand_docs, -1) # [B, num_cand_docs, encoder_size]
        click_output, _ = self.mha(click_embed) # [B, num_click_docs, encoder_size]
        click_output = self.dropout(click_output) # [B, num_click_docs, encoder_size]

        click_repr, _ = self.additive_attn(click_output) # [B, encoder_size]
        logits = torch.bmm(click_repr.unsqueeze(1), cand_embed.permute(0, 2, 1)).squeeze(1).cuda() # [B, num_cand_docs]
        if labels is not None:
            labels = labels.cuda()
            loss = self.criterion(logits, labels)
            return loss, logits
        return logits


import os
import sys
import json
import zipfile
import construct
import argparse
import subprocess
import shutil
import importlib

import validators
import colorama
from Crypto.PublicKey import RSA

sys.path.append("..")

from Updater import settings
from Updater import registry
from Updater import rsa_signing
from Updater import updater
from Updater import messages
from Updater.messages import MessageType

DEFAULT_SETTINGS_PATH = "settings.json"
BUILD_DIRECTORY = "build"
SERVICE_EXECUTABLE = "service.exe"
LAUNCHER_EXECUTABLE = "launcher.exe"
PYINSTALLER_OUTPUT_DIR = "dist"
INSTALLER_SETUP_SCRIPT = "setup_script.iss"
INSTALLER_SETUP_TEMPLATE = "setup_template.iss"
INNO_SETUP_INSTALL_FOLDER = r"C:\Program Files (x86)\Inno Setup 6"
INNO_SETUP_COMPILER = os.path.join(INNO_SETUP_INSTALL_FOLDER, "ISCC.exe")

def load_settings():
    try:
        with open(DEFAULT_SETTINGS_PATH, "r") as settings_file:
            data = settings_file.read()
            return json.loads(data)
    except FileNotFoundError:
        # If settings file is not found, use default settings
        pass
    return dict()

def save_settings(values):
    try:
        with open(DEFAULT_SETTINGS_PATH, "w") as settings_file:
            data = json.dumps(values)
            settings_file.write(data)
    except PermissionError:
        return False
    return True

def add_to_settings(values):
    current_settings = load_settings()

    current_settings.update(values)
    return save_settings(current_settings)

def zip_directory(path, zip_handler):
    for root, dirs, files in os.walk(path):
        for file in files:
            file_path = os.path.join(root, file)
            relative_path = os.path.relpath(file_path, path)
            zip_handler.write(file_path, relative_path)

        for dir_name in dirs:
            dir_path = os.path.join(root, dir_name)
            relative_path = os.path.relpath(dir_path, path)
            zip_handler.write(dir_path, relative_path)

def generate_rsa_keys(display_keys=True):
    key_pair = RSA.generate(bits=settings.RSA_KEY_SIZE)

    # Adds the keys to settings file
    rsa_settings = dict(
        RSA_MODULO=hex(key_pair.n),
        PUBLIC_KEY=hex(key_pair.e),
    )
    if not add_to_settings(rsa_settings):
        print(f"Failed to add rsa key to {DEFAULT_SETTINGS_PATH}")
        return False

    # Adds the keys to registry
    if not registry.exists(settings.REGISTRY_PATH):
        registry.create_key(settings.REGISTRY_PATH)
    registry.set_value(settings.RSA_MODULO_REGISTRY, hex(key_pair.n))
    registry.set_value(settings.RSA_PUBLIC_REGISTRY, hex(key_pair.e))
    registry.set_value(settings.RSA_PRIVATE_REGISTRY, hex(key_pair.d))

    # Displays the keys to the user
    print("RSA keys were generated!")
    print("")
    if display_keys:
        show_rsa_keys()
    return True

def show_rsa_keys():
    print("RSA Modulo (n):")
    if registry.exists(settings.RSA_MODULO_REGISTRY):
        print(registry.get_value(settings.RSA_MODULO_REGISTRY))
    else:
        print("Not available.")
    print("")

    print("RSA Public Key (e):")
    if registry.exists(settings.RSA_PUBLIC_REGISTRY):
        print(registry.get_value(settings.RSA_PUBLIC_REGISTRY))
    else:
        print("Not available.")
    print("")

    print("RSA Private Key (d):")
    if registry.exists(settings.RSA_PRIVATE_REGISTRY):
        print(registry.get_value(settings.RSA_PRIVATE_REGISTRY))
    else:
        print("Not available.")
    return True

def show_server_information():
    address_id = "Not available"
    if registry.exists(settings.ADDRESS_ID_REGISTRY):
        address_id = registry.get_value(settings.ADDRESS_ID_REGISTRY)

    ip = "Not available"
    if registry.exists(settings.UPDATING_SERVER_REGISTRY):
        ip = registry.get_value(settings.UPDATING_SERVER_REGISTRY)

    port = "Not available"
    if registry.exists(settings.PORT_REGISTRY):
        port = registry.get_value(settings.PORT_REGISTRY)

    print(f"Address ID: \t{address_id}")
    print(f"Domain (IP): \t{ip}")
    print(f"Port: \t\t{port}")
    return True

def send_server_information(ip, port, spread=True):
    # Validates the ip or domain (syntax only)
    if validators.domain(ip) is not True:
        if validators.ip_address.ipv4(ip) is not True:
            if validators.ip_address.ipv6(ip) is not True:
                print(f"Failed to validate ip or domain: {ip}. Check for typing mistakes.")
                return False

    # Validates port number
    if validators.between(port, min=1, max=65535) is not True:
        print(f"Invalid port number: {port} is not between 1 and 65535")
        return False

    if not registry.exists(settings.ADDRESS_ID_REGISTRY):
        print(f"Address ID was not found in the registry! (Location: {settings.ADDRESS_ID_REGISTRY})")
        return False
    if not registry.exists(settings.RSA_PRIVATE_REGISTRY):
        print(f"RSA Private Key was not found in the registry! (Location: {settings.RSA_PRIVATE_REGISTRY})")
        return False
    address_id = registry.get_value(settings.ADDRESS_ID_REGISTRY)

    # Creates server message
    server_update_dict = dict(
        type=MessageType.SERVER_UPDATE,
        signature=0,
        address_id=address_id + 1,  # Increases the address id, to indicate the information is new and up to date.
        address_size=len(ip),
        address=ip.encode("ascii"),
        port=port,
        spread=spread
    )

    # Calculate signature of message
    try:
        server_update_message = messages.SERVER_UPDATE_MESSAGE.build(server_update_dict)

        # Update signature
        server_update_dict["signature"] = messages.sign_message(server_update_message)
        server_update_message = messages.SERVER_UPDATE_MESSAGE.build(server_update_dict)
    except construct.ConstructError as e:
        # Should never occur
        print(f"Failed to build server update message: {e.args}")
        return False

    # Sends server information update (should also update local server information)
    updater.send_broadcast(server_update_message)
    print("Server information was sent to services!")
    return True

def create_update(update_path, major, minor):
    version = updater.Version(major, minor)

    try:
        update_filepath = settings.UPDATE_PATH
        update_filepath = f"{update_filepath}.{version}"
        update_file = open(update_filepath, "wb")
    except PermissionError:
        print(f"Failed to write update file {settings.UPDATE_PATH}. Insufficient permission or file is locked.")
        return False

    # Creating update zip
    with update_file:
        update_zip = zipfile.ZipFile(update_file, "w")
        zip_directory(update_path, update_zip)
        update_zip.close()

    # Updating registry with update info
    version_registry = version.get_update_registry_path()
    registry.set_value(version_registry, os.path.abspath(update_filepath))
    version.update_current_version()

    print(f"Created update version {version} successfully!")
    return True

def broadcast_update_version(spread=True):
    # Gets the update info and update file
    update_version = updater.Version.get_current_version()
    version_registry = update_version.get_update_registry_path()
    update_filepath = registry.get_value(version_registry)

    # Tries to open update file (might fail if clients are downloading it)
    try:
        file_size = os.stat(update_filepath).st_size
        update_file = open(update_filepath, "rb")
    except PermissionError:
        print(f"Failed to write update file {settings.UPDATE_PATH}. Insufficient permission or file is locked.")
        return False

    # Calculates size and signature of update
    data_received = 0
    hash_object = settings.HASH_MODULE()

    # Calculate update signature
    with update_file:
        while data_received < file_size:
            chunk = update_file.read(settings.VERSION_CHUNK_SIZE)
            hash_object.update(chunk)
            data_received += len(chunk)
    signature = rsa_signing.sign_hash(hash_object)

    # Creates broadcast message
    version_update_dict = dict(
        type=MessageType.VERSION_UPDATE,
        header_signature=0,
        major=update_version.major,
        minor=update_version.minor,
        size=file_size,
        update_signature=signature,
        spread=spread
    )

    # Calculate signature of message
    try:
        version_update_message = messages.VERSION_UPDATE_MESSAGE.build(version_update_dict)

        # Update signature
        version_update_dict["header_signature"] = messages.sign_message(version_update_message)
        print(f"Spread: {version_update_dict['spread']}")
        version_update_message = messages.VERSION_UPDATE_MESSAGE.build(version_update_dict)
    except construct.ConstructError:
        # Should never occur
        print(f"Failed to build request update message")
        return False

    # Sends the message
    updater.send_broadcast(version_update_message)
    # After the update is announced, the service will send it to the clients, when they ask for it
    print(f"Broadcast was sent with version {update_version} !")
    return True

def execute_program(program, script, parameters="", **kwargs):
    command = f"{program} {parameters} {script}"
    print(f"Executing: {command}" + colorama.Fore.LIGHTBLUE_EX)
    result = subprocess.call(command, **kwargs)
    print(colorama.Fore.RESET)
    return result == 0

def clean_installer():
    # Delete all registry keys
    if registry.key_exists(settings.REGISTRY_PATH):
        registry.delete_key_recursive(settings.REGISTRY_PATH)
        print(f"Deleted registry key {settings.REGISTRY_PATH} successfully!")

    # Delete settings file
    if os.path.exists(DEFAULT_SETTINGS_PATH):
        os.remove(DEFAULT_SETTINGS_PATH)
        print(f"Deleted {DEFAULT_SETTINGS_PATH} successfully!")

    # Delete all setup file

    # Updater
    if os.path.isdir(r"..\Updater\build"):
        shutil.rmtree(r"..\Updater\build")
    if os.path.isdir(r"..\Updater\dist"):
        shutil.rmtree(r"..\Updater\dist")
    if os.path.exists(r"..\Updater\service.spec"):
        os.remove(r"..\Updater\service.spec")

    # Launcher
    if os.path.isdir(r"..\Launcher\build"):
        shutil.rmtree(r"..\Launcher\build")
    if os.path.isdir(r"..\Launcher\dist"):
        shutil.rmtree(r"..\Launcher\dist")
    if os.path.exists(r"..\Launcher\launcher.spec"):
        os.remove(r"..\Launcher\launcher.spec")

    # Server
    if os.path.exists(INSTALLER_SETUP_SCRIPT):
        os.remove(INSTALLER_SETUP_SCRIPT)
    if os.path.isdir(BUILD_DIRECTORY):
        shutil.rmtree(BUILD_DIRECTORY)
    if os.path.isdir("Output"):
        shutil.rmtree("Output")

    pass

def create_installer(program_name, major, minor, software_path, updater_path, launcher_path, ip, port):
    # Validate server, port
    # Validates the ip or domain (syntax only)
    if validators.domain(ip) is not True:
        if validators.ip_address.ipv4(ip) is not True:
            if validators.ip_address.ipv6(ip) is not True:
                print(f"Failed to validate ip or domain: {ip}. Check for typing mistakes.")
                return False

    # Validates port number
    if validators.between(port, min=1, max=65535) is not True:
        print(f"Invalid port number: {port} is not between 1 and 65535")
        return False

    # Save software name, program name, major, minor, ip, port to settings
    program_settings = dict(
        SOFTWARE_NAME=program_name.capitalize(),
        PROGRAM=f"{program_name}.exe",
        UPDATING_SERVER=ip,
        PORT=port,
        UPDATE_MAJOR=major,
        UPDATE_MINOR=minor,
        VERSION_MAJOR=major,
        VERSION_MINOR=minor,
    )
    importlib.reload(settings)
    settings.__values__.update(program_settings)
    settings.init_settings(save=False, load=False)

    if not add_to_settings(program_settings):
        print(f"Failed to write settings file {DEFAULT_SETTINGS_PATH}")
        return False
    print("Created new settings file!\n")

    # Generate RSA keys and add to settings/registry
    generate_rsa_keys(display_keys=False)

    # Create build directory
    if not os.path.isdir(BUILD_DIRECTORY):
        os.mkdir(BUILD_DIRECTORY)

    # Run pyinstaller for updater and copy executable to build directory (Create folder as well)
    service_folder = os.path.join(BUILD_DIRECTORY, "Updater")
    if not os.path.isdir(service_folder):
        os.mkdir(service_folder)
    service_script = SERVICE_EXECUTABLE.replace(".exe", ".py")
    if not execute_program("pyinstaller", os.path.join(updater_path, service_script), r"--hidden-import win32timezone --onefile", cwd=updater_path):
        print(f"Failed to run pyinstaller for {updater_path}")
        return False
    shutil.copyfile(os.path.join(updater_path, PYINSTALLER_OUTPUT_DIR, SERVICE_EXECUTABLE),
                    os.path.join(service_folder, SERVICE_EXECUTABLE))
    print("Built service successfully!\n")

    # Run pyinstaller for launcher and copy executable to build directory
    launcher_script = LAUNCHER_EXECUTABLE.replace(".exe", ".py")
    if not execute_program("pyinstaller", os.path.join(launcher_path, launcher_script), r"-p ..\ --onefile -w", cwd=launcher_path):
        print(f"Failed to run pyinstaller for {launcher_path}")
        return False
    shutil.copyfile(os.path.join(launcher_path, PYINSTALLER_OUTPUT_DIR, LAUNCHER_EXECUTABLE),
                    os.path.join(BUILD_DIRECTORY, LAUNCHER_EXECUTABLE))
    print("Built launcher successfully!\n")

    # Copy files for program_path to build directory
    program_folder = os.path.join(BUILD_DIRECTORY, program_name)
    if not os.path.isdir(program_folder):
        os.mkdir(program_folder)
    shutil.copytree(software_path, program_folder, dirs_exist_ok=True)
    print("Copied program files to build directory.\n")

    # Copy settings file to build directory
    settings_filename = os.path.basename(DEFAULT_SETTINGS_PATH)
    shutil.copyfile(DEFAULT_SETTINGS_PATH, os.path.join(service_folder, settings_filename))
    print("Copied settings file to build directory.\n")

    # Create Inno Setup Script using template
    inno_setup_script_parameters = f"""
        #define MyAppName "{program_name}"
        #define MyAppVersion "{major}.{minor}"
        #define UpdaterFolder "Updater"
        #define SettingsFile "{settings_filename}"
        #define LauncherName "{LAUNCHER_EXECUTABLE}"
        #define ServiceName "{SERVICE_EXECUTABLE}"
        #define BuildDir "{BUILD_DIRECTORY}"
    """
    with open(INSTALLER_SETUP_TEMPLATE, "r") as setup_template:
        template = setup_template.read()
    with open(INSTALLER_SETUP_SCRIPT, "w") as setup_script:
        setup_script.write(inno_setup_script_parameters)
        setup_script.write(template)
    print("Created Inno Setup script for installer!")

    # Compile script and create setup
    if not execute_program(INNO_SETUP_COMPILER, INSTALLER_SETUP_SCRIPT):
        print(f"Failed to compile setup script {INSTALLER_SETUP_SCRIPT}")
        return False
    print("Compiled setup script successfully!")
    print("Created installer in Output folder!")

    return True

def main():
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers()

    # Top level commands
    rsa_group = subparsers.add_parser("rsa")
    update_group = subparsers.add_parser("update")
    server_group = subparsers.add_parser("server")
    setup_group = subparsers.add_parser("setup")

    # Sub-commands of rsa

    subparsers = rsa_group.add_subparsers()
    # generate
    rsa_generate = subparsers.add_parser("generate")
    rsa_generate.set_defaults(func=generate_rsa_keys)
    # show
    rsa_show = subparsers.add_parser("show")
    rsa_show.set_defaults(func=show_rsa_keys)

    # Sub-commands of update

    subparsers = update_group.add_subparsers()
    # create
    update_create = subparsers.add_parser("create")
    update_create.add_argument("update_path", metavar="<Path to Update Folder>", type=str,
                              help="The path to the update folder (the folder that contains all the files of the software).")
    update_create.add_argument("major", metavar="<major>", type=int,
                               help="The major number of the version.")
    update_create.add_argument("minor", metavar="<minor>", type=int,
                               help="The minor number of the version.")
    update_create.set_defaults(func=create_update)

    # broadcast
    update_broadcast = subparsers.add_parser("broadcast")
    update_broadcast.add_argument("-s", "--spread", action="store_true",
                                  help="Sets 'spread' bit flag in broadcast message, will tell other clients to forward this message.")
    update_broadcast.set_defaults(func=broadcast_update_version)

    # Sub-commands of server

    subparsers = server_group.add_subparsers()
    # show
    server_show = subparsers.add_parser("show")
    server_show.set_defaults(func=show_server_information)
    # update
    server_update = subparsers.add_parser("update")
    server_update.add_argument("ip", metavar="<ip or domain>", type=str,
                               help="The ip or the domain of the update server.")
    server_update.add_argument("port", metavar="<port>", type=int,
                               help="The port that the updating service will listen on.")
    server_update.add_argument("-s", "--spread", action="store_true",
                               help="Sets 'spread' bit flag in broadcast message, will tell other clients to forward this message.")
    server_update.set_defaults(func=send_server_information)

    # Sub-commands of setup

    subparsers = setup_group.add_subparsers()
    # create
    setup_create = subparsers.add_parser("create")
    setup_create.add_argument("program_name", metavar="<Program Name>", type=str,
                              help=r"The program's executable name. Needs to be stored at <Program Folder>\<Program Name>.exe")
    setup_create.add_argument("major", metavar="<major>", type=int,
                              help="The major number of the version.")
    setup_create.add_argument("minor", metavar="<minor>", type=int,
                              help="The minor number of the version.")
    setup_create.add_argument("-s", "--software_path", metavar="[Path to Software Folder]", type=str, default=r"..\Program",
                              help=r"The path to the software folder. Defaults to ..\Program")
    setup_create.add_argument("-u", "--updater_path", metavar="[Path to Updater Folder]", type=str, default=r"..\Updater",
                              help=r"The path to the updater folder.  Defaults to ..\Updater")
    setup_create.add_argument("-l", "--launcher_path", metavar="[Path to Launcher Folder]", type=str, default=r"..\Launcher",
                              help=r"The path to the launcher folder.  Defaults to ..\Launcher")
    setup_create.add_argument("-i", "--ip", metavar="[Updating Server Address]", type=str, default=r"127.0.0.1",
                              help=r"The IP address or domain of the update server.  Defaults to 127.0.0.1")
    setup_create.add_argument("-p", "--port", metavar="[Updating Server Port]", type=int, default=r"55555",
                              help=r"The port of the update service. Defaults to 55555")
    setup_create.set_defaults(func=create_installer)
    # clean
    setup_clean = subparsers.add_parser("clean")
    setup_clean.set_defaults(func=clean_installer)

    # Parse everything
    args = parser.parse_args()

    # Initialize settings
    colorama.init()
    installer_settings = load_settings()
    settings.__values__.update(installer_settings)
    settings.init_settings(save=False)

    # call command function
    try:
        func = args.func
    except AttributeError:
        print(f"Invalid command. Run with `{sys.argv[0]} -h` for usage.")
        return
    del args.func
    func(**vars(args))

if __name__ == "__main__":
    main()


import os
import openai
import json
from keys import openai_APIKEY, openai_BASE, zhipuai_APIKEY
import zhipuai
from datetime import datetime
import re
class GPTProcessor:
    def __init__(self):
        openai.api_key = openai_APIKEY
        openai.api_base = openai_BASE
        zhipuai.api_key = zhipuai_APIKEY
        self.id = 0

    def ask_chatgpt(self, my_messages): #可以做异步，和GPT连接请求发出后，在全部完成前可以切换到其它线程
        print({"role": "user", "content": my_messages[0]['content'] + '\n' + my_messages[1]['content']})
        response = zhipuai.model_api.sse_invoke(
            model="chatglm_pro",
            prompt=[
                {"role": "user", "content": my_messages[0]['content']},
                {"role": "assistant", "content": "好的"},
                {"role": "user", "content": my_messages[1]['content']},
            ],
            temperature=0.95,
            top_p=0.1,
            incremental=True
        )
        result = ''
        for event in response.events():
            if event.event == "add":
                result += event.data
        #delete ' ' from the first
        while (len(result) > 0 and result[0] == ' '):
            result = result[1:]
        print('ANS=',result)
        return result

    # def ask_chatgpt(self, my_messages): #可以做异步，和GPT连接请求发出后，在全部完成前可以切换到其它线程
    #     ans = openai.ChatCompletion.create(
    #             model="gpt-3.5-turbo",
    #             messages=my_messages,
    #         ).choices[0].message.content
    #     print('ANS=',ans)
    #     return ans

    def txt2json(self, text):
        result = self.ask_chatgpt(text)
        return result

    def first_guess(self,title,text):
        my_messages = [
            {"role": "system", "content": "根据下面这个标题和部分文字，你觉得是否可能是某种活动 的 预告 售票 报名，请直接告诉我答案为'是'或'否'。请不要回复任何其它内容。请回复一个字，不要回复多个字。如果是活动的总结请返回'否'，如果你觉得不确定，也请回复'是'。请严格地以唯一的格式回复我"},
            {"role": "user", "content": title + '\n' + text[:20]},
        ]
        ans = self.ask_chatgpt(my_messages)
        if ans == '否':
            return False
        return True

    def Text_to_JSON(self, text):
        try:
            my_messages = [
                {"role": "system", "content": "Now that you are engaged in professional text processing, please let me know if the push below is a preview of an event (such as a lecture or ticket collection) （不包括活动总结). If so, please use JSON format to tell me the 'event_name', 'event_time', 'location', 'organizational_unit'. 时间尽可能规范到特定的时刻，如果有多个时间请一并输出，如没有则以null存在，推送发布时间为2023年，如果有多个活动，请返回list，如果没有则返回空list。Otherwise, tell me the activity category it belongs to. please use JSON format!去除内容中的所有引号的存在"},
                {"role": "user", "content": text + "please use JSON format!! 如果出现了内容中的引号,请不要存在,以防止json格式无法读取"},
            ]
            infolist = self.ask_chatgpt(my_messages)
            infolist = infolist.replace('\n', ' ')
        except:
            my_messages = [
                {"role": "system", "content": "请获取下文（这是一篇推送的前半部分）的摘要，不要忽略所有的，时间，地点，主办方，主题，摘要，尤其是时间"},
                {"role": "user", "content": text[-1500:]},
            ]
            summary1 = self.ask_chatgpt(my_messages)
            my_messages = [
                {"role": "system", "content": "Now that you are engaged in professional text processing, please let me know if the push below is a preview of an event (such as a lecture or ticket collection) (不包括活动总结). If so, please use JSON format to tell me the 'event_name', 'event_time', 'location', 'organizational_unit'. 时间尽可能规范到特定的时刻，如果有多个时间请一并输出，如没有则以null存在，推送发布时间为2023年。Otherwise, tell me the activity category it belongs to."},
                {"role": "user", "content": summary + '\n' + text[:-1500]},
            ]
            infolist = self.ask_chatgpt(my_messages)
            infolist = infolist.replace('\n', ' ')

        try:
            # print(infolist)
            #contrive json from string, from first '{ to the first '}' after the first '{'
            json_list = infolist[infolist.find('{'):infolist.find('}')+1]
            json_list = json.loads(json_list)
            my_messages = [
                {"role": "system", "content": "请获取下面活动信息的摘要，请包含主要内容但不要太长，请以描述的方式返回，请直接返回摘要，不要回答任何其它内容"},
                {"role": "user", "content": text},
            ]
            zhaiyao = self.ask_chatgpt(my_messages)
            # zhaiyao = zhaiyao.replace('\n', ' ')
            # zhaiyao = zhaiyao.replace(' ', '')
            # zhaiyao = zhaiyao[zhaiyao.find('{'):zhaiyao.find('}')+1]
            #add event_summary : zhaiyao to json_list
            json_list['event_summary'] = zhaiyao

        except Exception as e:
            print('Error: json.loads error')
            print(e)
            return []
        if type(json_list) != list:
            json_list = [json_list]
        should_exist = ['event_name', 'event_time', 'location', 'organizational_unit', 'event_summary']
        result_list = []
        for info in json_list:
            all_exist = True
            for key in should_exist:
                if key not in info:
                    print('Error: ', key, ' not exist')
                    all_exist = False
                    break
            if not all_exist:
                continue

            ask_time_message = [
                {"role": "system", "content": "提取下面的时间中最早的时刻，并严格转化为以 ????-??-?? ??:??:?? 的格式回复我。如果没有时间，请回复'没有'，以上格式代表年月日时分秒，如2023-09-11 15:00:00。严格转化格式，不要是其它的格式，必须以`-`和`:`分割，且每个部分都是数字。请一定保留 秒，即使没有显示的表现，默认以 00 填充"},
                {"role": "user", "content": str(info.get('event_time', None))},
            ]
            start_time_str = self.ask_chatgpt(ask_time_message)
            pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})'
            match = re.search(pattern, start_time_str)
            if match is None:
                pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2})'
                match = re.search(pattern, start_time_str)
            try:
                extracted_datetime = match.group(1)
                start_time = str(extracted_datetime)
                if len(start_time) == 16:
                    start_time += ':00'
            except Exception as e:
                print('Error: datetime.strptime error')
                print(e)
                continue

            ask_time_message = [
                {"role": "system", "content": "提取下面的时间中最晚的时刻，并严格转化为以 ????-??-?? ??:??:?? 的格式回复我。如果没有时间，请回复'没有'，以上格式代表年月日时分秒，如2023-09-11 15:00:00。严格转化格式，不要是其它的格式，必须以`-`和`:`分割，且每个部分都是数字。请一定保留 秒，即使没有显示的表现，默认以 00 填充"},
                {"role": "user", "content": str(info.get('event_time', None))},
            ]
            end_time_str = self.ask_chatgpt(ask_time_message)
            pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})'
            match = re.search(pattern, end_time_str)
            if match is None:
                pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2})'
                match = re.search(pattern, end_time_str)
            try:
                extracted_datetime = match.group(1)
                end_time = str(extracted_datetime)
                if len(end_time) == 16:
                    end_time += ':00'
            except:
                print('Error: datetime1.strptime error')
                continue

            json_data = {
                'event_name': info.get('event_name', None),
                'date1': start_time[:10],
                'time1': start_time[11:],
                'date2': end_time[:10],
                'time2': end_time[11:],
                'event_time': str(info.get('event_time', None)),
                'location': info.get('location', None),
                'organizational_unit': info.get('organizational_unit', None),
                'event_summary': info.get('event_summary', None),
            }
            print(json_data)
            result_list.append(json_data)
        return result_list

    def process_dir(self, current_dir):
        for filename in os.listdir(current_dir):
            try:
                file_path = os.path.join(current_dir, filename)

                if os.path.isdir(file_path):
                    self.process_dir(file_path)

                elif filename.endswith('.txt'):
                    with open(file_path,encoding='utf-8') as f:
                        text = f.read()
                    json_data = self.Text_to_JSON(text)

            except:
                print('Error processing file: ', filename)
                continue
        print('Done!')

if __name__ == '__main__':
    test_text = '''
    你是煞笔
'''
    processor = GPTProcessor()
    print ( processor.Text_to_JSON(test_text) )