#!/usr/bin/env python3

# std
from math import ceil
import logging
from typing import List

# 3d party
import matplotlib.pyplot as plt
import matplotlib

# noinspection PyUnresolvedReferences
from mpl_toolkits.mplot3d import Axes3D  # NOTE BELOW (*)
import numpy as np
import pandas as pd

# ours
from clusterking.util.log import get_logger
from clusterking.plots.colors import ColorScheme

# (*) This import line is not explicitly used, but do not remove it!
# It is necessary to load the 3d support!

# fixme: Maybe not take _setup_all?
# todo: also have the 3d equivalent of ClusterPlot.fill (using voxels)
# todo: option to disable legend
class ClusterPlot(object):
    """Plot clusters in parameter space.

    After initialization, use the 'scatter' or 'fill' method for plotting.

    You can modify the attributes of this class to tweak some properties
    of the plots.
    """

    def __init__(self, data):
        """
        Args:
            data: :py:class:`~clusterking.data.data.Data` object
        """
        #: logging.Logger object
        self.log = get_logger("ClusterPlot", sh_level=logging.WARNING)

        #: Instance of pandas.DataFrame
        self.data = data

        # (Advanced) config values
        # Documented in docstring of this class

        #: Color scheme
        self.color_scheme = None

        #: List of markers of the get_clusters (scatter plot only).
        self.markers = None
        if not self.markers:
            self.markers = ["o", "v", "^", "v", "<", ">"]

        #: Maximal number of subplots
        self.max_subplots = 16

        #: Maximal number of columns of the subplot grid
        self.max_cols = 4

        #: Formatting of key-value pairs in title of plots
        self.kv_formatter = "{}={:.2f}"

        #: figure size of each subplot
        self.fig_base_size = 4

        #: Ratio of height/width. None: Automatically inferred
        self.aspect_ratio = None

        #: The name of the column that holds the cluster index
        self.cluster_column = "cluster"

        #: The name of the column that holds the benchmark yes/no information
        self.bpoint_column = "bpoint"

        #: Default marker size
        self.default_marker_size = (
            1 / 2 * matplotlib.rcParams["lines.markersize"] ** 2
        )
        #: Marker size of benchmark points
        self.bpoint_marker_size = 6 * self.default_marker_size

        #: If true, a legend is drawn
        self.draw_legend = True

        # Internal values: Do not modify
        # ----------------------------------------------------------------------

        # Names of the columns to be on the axes of
        # the plot.
        self._axis_columns = None

        self._clusters = None

        self._df_dofs = None

        self._fig = None
        self._axs = None

    # ==========================================================================
    # User access via property
    # ==========================================================================

    @property
    def fig(self):
        """The figure."""
        return self._fig

    # ==========================================================================
    # Quick access of simple logic
    # ==========================================================================

    @property
    def _ndim(self):
        return len(self._axis_columns)

    @property
    def figsize(self):
        """Figure size per subplot (width, height)"""
        if self.aspect_ratio is not None:
            aspect_ratio = self.aspect_ratio
        else:
            if len(self._axis_columns) == 1:
                aspect_ratio = 2 / self.fig_base_size
            elif len(self._axis_columns) == 2:
                y_width = self._get_lims(1)[1] - self._get_lims(1)[0]
                x_width = self._get_lims(0)[1] - self._get_lims(0)[0]
                if x_width == 0:
                    aspect_ratio = 1
                else:
                    aspect_ratio = y_width / x_width
            else:
                aspect_ratio = 1
        return self.fig_base_size, aspect_ratio * self.fig_base_size

    @property
    def _axli(self):
        """Note: axs contains all axes (subplots) as a 2D grid, axsli contains
        the same objects but as a simple list (easier to iterate over)"""
        return self._axs.flatten()

    @property
    def _has_bpoints(self):
        """True if we have benchmark points."""
        return self.bpoint_column in self.data.df.columns

    @property
    def _nsubplots(self):
        """Number of subplots."""
        # +1 to have space for legend!
        return max(1, len(self._df_dofs)) + int(self.draw_legend)

    @property
    def _ncols(self):
        """Number of columns of the subplot grid."""
        return min(self.max_cols, self._nsubplots)

    @property
    def _nrows(self):
        """Number of rows of the subplot grid."""
        # the ``int`` technically does not make a difference, but pycharm
        # thinks that ``ceil`` returns floats and therefore complains
        # otherwise
        return int(ceil(self._nsubplots / self._ncols))

    # ==========================================================================
    # Helper functions
    # ==========================================================================

    def _find_dofs(self):
        """Find all parameters that are not axes on
        the plots and attain at least two different values.
        These parameters are called the degrees of freedom (dofs)."""

        dofs = []
        for col in self.data.par_cols:
            if col not in self._axis_columns:
                if len(self.data.df[col].unique()) >= 2:
                    dofs.append(col)
        self.log.debug("dofs = {}".format(dofs))
        self._dofs = dofs

    def _sample_dofs(self):
        """For every dof, select values to be shown on it.
        Save this as the dataframe self._df_dofs"""

        if not self._dofs:
            df_dofs = pd.DataFrame([])
        else:
            df_dofs = self.data.df[self._dofs].drop_duplicates()
            df_dofs.sort_values(self._dofs, inplace=True)
            df_dofs.reset_index(inplace=True, drop=True)

        self.log.debug("number of subplots = {}".format(len(df_dofs)))

        # Reduce the number of subplots by only sampling several points of
        # the Wilson coeffs that aren't on the axes

        if len(df_dofs) > self.max_subplots:
            steps_per_dof = int(self.max_subplots ** (1 / len(self._dofs)))
            self.log.debug("number of steps per dof", steps_per_dof)
            for col in self._dofs:
                allowed_values = df_dofs[col].unique()
                indizes = list(
                    set(
                        np.linspace(
                            0, len(allowed_values) - 1, steps_per_dof, dtype=int
                        )
                    )
                )
                allowed_values = allowed_values[indizes]
                df_dofs = df_dofs[df_dofs[col].isin(allowed_values)]
            self.log.debug(
                "number of subplots left after "
                "subsampling = {}".format(len(df_dofs))
            )

        self._df_dofs = df_dofs

    def _setup_subplots(self):
        """Set up the subplot grid"""

        # 1. Initialize subplots
        # ----------------------

        # squeeze keyword: https://stackoverflow.com/questions/44598708/
        # do not share axes, that makes problems if the grid is incomplete
        subplots_args = {
            "nrows": self._nrows,
            "ncols": self._ncols,
            # todo: this is somewhat problematic, because this won't add space
            #   for titles etc. Please do this differently
            "figsize": (
                self._ncols * self.figsize[0],
                self._nrows * self.figsize[1],
            ),
            "squeeze": False,
        }
        if self._ndim == 3:
            subplots_args["subplot_kw"] = {"projection": "3d"}

        self._fig, self._axs = plt.subplots(**subplots_args)

        # 2. Setup frames
        # ---------------

        for isubplot in range(self._nrows * self._ncols):
            if self._ndim == 1:
                for loc in ["top", "left", "right"]:
                    self._axli[isubplot].spines[loc].set_visible(False)
                self._axli[isubplot].spines["bottom"].set_position("center")

        # 3. Hide plots
        # -------------

        # Since we initialize a grid of subplots, but might have less
        # subplots to actually show, we hide some of them here.

        for isubplot in range(self._nsubplots, self._nrows * self._ncols):
            self._axli[isubplot].set_visible(False)

        # 4. Setup labels
        # ---------------

        # Number of hidden plots
        ihidden = self._nrows * self._ncols - self._nsubplots + 1

        # Column number from which we have to start hiding plots
        # (note that all hidden plots are in the last row)
        icol_hidden = self._ncols - ihidden

        self.log.debug("ihidden = {}".format(ihidden))
        self.log.debug("icol_hidden = {}".format(icol_hidden))

        if self._ndim == 1:
            for isubplot in range(self._nrows * self._ncols):
                self._axli[isubplot].set_yticks([])

                irow = isubplot // self._ncols
                icol = isubplot % self._ncols

                if irow == self._nrows - 2 and icol >= icol_hidden:
                    self._axli[isubplot].set_xlabel(
                        self.data._get_axis_label(self._axis_columns[0])
                    )
                elif irow == self._nrows - 1 and icol <= icol_hidden:
                    self._axli[isubplot].set_xlabel(
                        self.data._get_axis_label(self._axis_columns[0])
                    )
                else:
                    self._axli[isubplot].set_xticklabels([])

        elif self._ndim == 2:
            for isubplot in range(self._nrows * self._ncols):
                irow = isubplot // self._ncols
                icol = isubplot % self._ncols

                # Set labels and ticks:

                if icol == 0:
                    self._axli[isubplot].set_ylabel(
                        self.data._get_axis_label(self._axis_columns[1])
                    )
                else:
                    self._axli[isubplot].set_yticklabels([])

                if irow == self._nrows - 2 and icol >= icol_hidden:
                    self._axli[isubplot].set_xlabel(
                        self.data._get_axis_label(self._axis_columns[0])
                    )
                elif irow == self._nrows - 1 and icol <= icol_hidden:
                    self._axli[isubplot].set_xlabel(
                        self.data._get_axis_label(self._axis_columns[0])
                    )
                else:
                    self._axli[isubplot].set_xticklabels([])

        elif self._ndim == 3:
            for isubplot in range(self._nsubplots):
                self._axli[isubplot].set_xlabel(
                    self.data._get_axis_label(self._axis_columns[0])
                )
                self._axli[isubplot].set_ylabel(
                    self.data._get_axis_label(self._axis_columns[1])
                )
                self._axli[isubplot].set_zlabel(
                    self.data._get_axis_label(self._axis_columns[2])
                )

        else:
            raise ValueError("Unsupported dimension {}".format(self._ndim))

        # 3. Add title to subplots
        # ------------------------

        for isubplot in range(self._nsubplots - int(self.draw_legend)):
            self._axli[isubplot].set_title(self._plot_title(isubplot))

        # 4. Set ranges
        # --------------

        # Set the xrange explicitly in order to not depend
        # on which get_clusters are shown etc.

        for isubplot in range(self._nsubplots):
            if self._ndim == 1:
                self._axli[isubplot].set_ylim([-1, 1])
            if self._ndim >= 1:
                self._axli[isubplot].set_xlim(self._get_lims(0))
            if self._ndim >= 2:
                self._axli[isubplot].set_ylim(self._get_lims(1))
            if self._ndim >= 3:
                self._axli[isubplot].set_zlim(self._get_lims(2))

    def _plot_title(self, isubplot):
        """Return title for subplot

        Args:
            isubplot: Index of subplot

        Returns: Title as string
        """
        kv = {key: self._df_dofs.iloc[isubplot][key] for key in self._dofs}
        strings = [
            self.kv_formatter.format(self.data._get_axis_label(key), value)
            for key, value in kv.items()
        ]
        max_line_length = 15
        title = ""
        current_line_length = 0
        for string in strings:
            if current_line_length == 0:
                title += string
                current_line_length = len(string)
            elif current_line_length + len(string) < max_line_length:
                title += " " + string
                current_line_length += len(string) + 1
            else:
                title += "\n" + string
                current_line_length = len(string)

        return title

    # todo: if scatter: use proper markers!
    def _add_legend(self):
        if not self.draw_legend:
            return
        legend_elements = []
        for cluster in self._clusters:
            color = self.color_scheme.get_cluster_color(cluster)
            # pycharm can't seem to find patches:
            # noinspection PyUnresolvedReferences
            p = matplotlib.patches.Patch(
                facecolor=color, edgecolor=color, label=cluster
            )
            legend_elements.append(p)
        self._axli[self._nsubplots - 1].legend(
            handles=legend_elements,
            loc="lower left",
            title="Clusters",
            frameon=False,
        )
        # todo: this shouldn't be necessary if setup axes worked as expected
        self._axli[self._nsubplots - 1].set_axis_off()

    def _get_lims(self, ax_no: int, stretch=0.1):
        """Get lower and upper limit of axis (including padding)

        Args:
            ax_no: 0 for x-axis, 1 for y-axis etc.
            stretch: Fraction of total value span to add as padding.

        Returns:
            (minimum of plotrange, maximum of plotrange)
        """
        mi = min(self.data.df[self._axis_columns[ax_no]].values)
        ma = max(self.data.df[self._axis_columns[ax_no]].values)
        d = ma - mi
        if d == 0.0:
            # Should only occur during testing or in other edge cases
            d = 1
        pad = stretch * d
        return mi - pad, ma + pad

    def _setup_all(self, cols: List[str], clusters=None) -> None:
        """Performs all setups.

        Args:
            cols: Names of the columns to be on the plot axes
            clusters: Clusters to plot

        Returns:
            None
        """
        if not 1 <= len(cols) <= 3:
            raise ValueError(
                "Plot dimension has to be between 1 and 3, but it is {}. "
                "Did you specify enough columns/parameters as axes?".format(
                    len(cols)
                )
            )
        if len(self.data.df) == 0:
            raise ValueError(
                "No data to plot. Please check if your dataframe contains "
                "any row."
            )
        self._clusters = clusters
        self._axis_columns = cols
        if not self._clusters:
            # todo: use d.clusters
            self._clusters = self.data.clusters(
                cluster_column=self.cluster_column
            )
        # Careful: Use the real number of clusters when initializing the
        # color scheme!
        # todo: do we really need to reinitialize this?
        self.color_scheme = ColorScheme(
            self.data.clusters(cluster_column=self.cluster_column)
        )
        self._find_dofs()
        self._sample_dofs()
        self._setup_subplots()

    def _set_fill_colors(self, matrix: np.ndarray) -> np.ndarray:
        """A helper function for the fill method. Given a n x m matrix of
        cluster numbers, this returns a n x m x 3 matrix, where the last 3
        dimensions contain the rgb value of the color that this cluster
        should be colored with.

        Args:
            matrix: m x n matrix containing cluster numbers

        Returns:
            n x m x 3 matrix with last 3 dimensions containing RGB codes
        """
        rows, cols = matrix.shape
        matrix_colored = np.zeros((rows, cols, 3))
        for irow in range(rows):
            for icol in range(cols):
                cluster = int(matrix[irow, icol])
                color = self.color_scheme.get_cluster_color(cluster)
                rgb = color[:3]
                matrix_colored[irow, icol] = rgb
        return matrix_colored

    # ==========================================================================
    # Plotting methods
    # ==========================================================================

    # todo: **kwargs
    # todo: factor out the common part of scatter and fill into its own method?
    def scatter(self, cols: List[str], clusters=None, **kwargs):
        """Create scatter plot, specifying the columns to be on the axes of the
        plot. If 3 column are specified, 3D scatter plots
        are presented, else 2D plots. If the dataframe contains more columns,
        such that each row is not only specified by the columns on the axes,
        a selection of subplots is created, showing 'cuts'.
        Benchmark points are marked by enlarged plot markers.

        Args:
            cols: The names of the columns to be shown on the x, y (and z)
               axis of the plots.
            clusters: The get_clusters to be plotted (default: all)
            **kwargs: Kwargs for ax.scatter

        Returns:
            The figure (unless the 'inline' setting of matplotllib is
            detected).
        """
        self._setup_all(cols, clusters)

        for isubplot in range(self._nsubplots - int(self.draw_legend)):
            for cluster in self._clusters:
                df_cluster = self.data.df[
                    self.data.df[self.cluster_column] == cluster
                ]
                for col in self._dofs:
                    df_cluster = df_cluster[
                        df_cluster[col] == self._df_dofs.iloc[isubplot][col]
                    ]

                if self._has_bpoints:
                    df_cluster_no_bp = df_cluster[
                        ~df_cluster[self.bpoint_column]
                    ]
                    df_cluster_bp = df_cluster[df_cluster[self.bpoint_column]]
                else:
                    df_cluster_no_bp = df_cluster
                    df_cluster_bp = pd.DataFrame()
                # df_cluster_non_bpoint = df_cluster[]]

                data = [
                    df_cluster_no_bp[col].values for col in self._axis_columns
                ]
                if self._ndim == 1:
                    # Insert trivial y value
                    data.append(0.1 + np.zeros(len(data[0])))

                self._axli[isubplot].scatter(
                    *data,
                    color=self.color_scheme.get_cluster_color(cluster),
                    marker=self.markers[(cluster - 1) % len(self.markers)],
                    label=cluster,
                    s=self.default_marker_size,
                    **kwargs
                )
                if self._has_bpoints:
                    bp_data = [
                        df_cluster_bp[col].values for col in self._axis_columns
                    ]
                    if self._ndim == 1:
                        # Insert trivial y value
                        bp_data.append(0.1 + np.zeros(len(bp_data[0])))
                    self._axli[isubplot].scatter(
                        *bp_data,
                        color=self.color_scheme.get_cluster_color(cluster),
                        marker=self.markers[(cluster - 1) % len(self.markers)],
                        label=cluster,
                        s=self.bpoint_marker_size,
                        **kwargs
                    )

        self._add_legend()

        if "inline" not in matplotlib.get_backend():
            return self._fig

    # todo: implement interpolation
    def fill(self, cols: List[str], kwargs_imshow=None):
        """Call this method with two column names, x and y. The results are
        similar to those of 2D scatter plots as created by the scatter
        method, except that the coloring is expanded to the whole xy plane.
        Note: This method only works with uniformly sampled NP!

        Args:
            cols: List of name of column to be plotted on x-axis and on y-axis
            kwargs_imshow: Additional keyword arguments to be passed to imshow

        Returns:
            The figure (unless the 'inline' setting of matplotllib is
            detected).
        """
        if not kwargs_imshow:
            kwargs_imshow = {}

        assert len(cols) == 2
        self._setup_all(cols)

        for isubplot in range(self._nsubplots - int(self.draw_legend)):
            df_subplot = self.data.df.copy()
            for col in self._dofs:
                df_subplot = df_subplot[
                    df_subplot[col] == self._df_dofs.iloc[isubplot][col]
                ]
            x = df_subplot[cols[0]].unique()
            y = df_subplot[cols[1]].unique()
            df_subplot.sort_values(
                by=[cols[1], cols[0]], ascending=[False, True], inplace=True
            )
            z = df_subplot[self.cluster_column].values
            # check if this makes sense
            z_matrix = z.reshape(y.shape[0], int(len(z) / y.shape[0]))

            imshow_config = {"interpolation": "none", "aspect": "auto"}
            imshow_config.update(kwargs_imshow)

            self._axli[isubplot].imshow(
                self._set_fill_colors(z_matrix),
                extent=[min(x), max(x), min(y), max(y)],
                **imshow_config
            )

        self._add_legend()
        if "inline" not in matplotlib.get_backend():
            return self._fig

    # ==========================================================================
    # Shortcuts for user
    # ==========================================================================

    def savefig(self, *args, **kwargs):
        """Equivalent to ``ClusterPlot.fig.savefig(*args, **kwargs)``: Saves
        figure to file, e.g. ``ClusterPlot.savefig("test.pdf")``."""
        self._fig.savefig(*args, **kwargs)


from numpy import *

arr = array([
    [1, 2, 3],
    [4, 5, 6]
])

# ndim function help to check the array is 1d or 2d in this case it returns 2 it means 2d
print(arr.ndim)
print(arr.shape)  # it will return type of array like 2x3 or 3x3

print(arr.size)  # it will return entire array size

'''you can also convert 2d array in 1d array'''

arr2 = arr.flatten()
print(arr2)

'''now 2d to 3d'''
arr = array([[1, 2, 3, 4, 5, 1], [6, 7, 8, 9, 0, 1]])
# it will create 2 2d array and in each 2d array we will have 2 1d array and each will have 3 value
arr3 = arr.reshape(2, 2, 3)
print(arr3)

'''matrix operations'''

# arr = array([[1, 2, 3, 4], [6, 7, 8, 9]])
# this one way of doing this

# second is
# semicolon represent as a how many row or after semicolon the value will be in new line
m = matrix('1 2 3; 4 4 5; 6 7 1')
m1 = matrix('1 2 1; 4 4 1; 2 1 1')

'if you want to get diagonal value like maths matrices '
print(diagonal(m))
print(m.min())  # minimum

'''You can addition or multiply two matrices in python'''

m3 = m + m1
m4 = m * m1
print(m3, "\n", m4)


from assembla.utils import parse_datetime, parse_date, parse_file
from assembla.cursor import Cursor

from utils import import_simplejson, DateTimeJSONEncoder

json = import_simplejson()

class ResultSet(list):
    """A list like object that holds results from a Twitter API query."""

class Model(object):

    def __init__(self, api=None):
        self._api = api

    def __getstate__(self):
        # pickle
        pickle = dict(self.__dict__)
        try:
            del pickle['_api']  # do not pickle the API reference
        except KeyError:
            pass
        return pickle

    def toJSON(self):
        return json.dumps(self)

    @classmethod
    def parse(cls, api, json):
        """Parse a JSON object into a model instance."""
        raise NotImplementedError

    @classmethod
    def parse_list(cls, api, json_list):
        """Parse a list of JSON objects into a result set of model instances."""
        results = ResultSet()
        for obj in json_list:
            if obj:
                results.append(cls.parse(api, obj))
        return results

    def __str__(self):
        """Return object id for easier serialization"""
        return str(self.id)

    def __repr__(self):
        return '<%s: %s>' % (self.__class__.__name__, self.__str__())

class Space(Model):

    @classmethod
    def parse(cls, api, json):
        space = cls(api)
        for k, v in json.items():
            if (k == 'created_at' or k == 'updated_at' or k == 'commercial_from') and v:
                setattr(space, k, parse_datetime(v))
            elif (k == 'restricted_date' or k == 'last_payer_changed_at') and v:
                setattr(space, k, parse_date(v))
            elif k == 'tabs_order':
                pass # for now
            #elif k == 'place':
                #if v is not None:
                    #setattr(space, k, Place.parse(api, v))
                #else:
                    #setattr(space, k, None)
            else:
                setattr(space, k, v)
        return space

    """
            if k == 'user':
                user_model = getattr(api.parser.model_factory, 'user')
                user = user_model.parse(api, v)
                setattr(space, 'author', user)
                setattr(space, 'user', user)  # DEPRECIATED
    """

    def destroy(self):
        return self._api.delete_space(space=self.id)

    def get_milestone(self, milestone_id):
        return self._api.get_milestone(space=self.id, milestone=milestone_id)

    def get_milestones(self):
        return list(Cursor(self._api.get_milestones, space=self.id).items())

    def create_milestone(self, milestone):
        return self._api.create_milestone(milestone, space=self.id)

    def get_components(self):
        return self._api.get_ticket_components(space=self.id)

    def create_component(self, component):
        return self._api.create_ticket_component(component, space=self.id)

    def get_custom_fields(self):
        return self._api.get_custom_fields(space=self.id)

    def create_custom_field(self, field):
        return self._api.create_custom_field(field, space=self.id)

    def get_ticket_statuses(self):
        return self._api.get_ticket_statuses(space=self.id)

    def create_ticket_status(self, status):
        return self._api.create_ticket_status(status, space=self.id)

    def get_tickets(self):
        return list(Cursor(self._api.get_tickets, space=self.id).items())

    def get_ticket(self, number):
        return self._api.get_ticket(space=self.id, ticket=number)

    def create_ticket(self, ticket):
        return self._api.create_ticket(ticket, space=self.id)

    def delete_ticket(self, ticket):
        return self._api.delete_ticket(ticket=ticket, space=self.id)

class InstantMessenger(Model):

    @classmethod
    def parse(cls, api, json):
        im = cls(api)
        for k, v in json.items():
            setattr(im, k, v)
        return im

class User(Model):

    @classmethod
    def parse(cls, api, json):
        user = cls(api)
        for k, v in json.items():
            if k == 'im' or k == 'im2':
                setattr(user, k, InstantMessenger.parse(api, v))
            else:
                setattr(user, k, v)
        return user

    @classmethod
    def parse_list(cls, api, json_list):
        if isinstance(json_list, list):
            item_list = json_list
        else:
            item_list = json_list['users']

        results = ResultSet()
        for obj in item_list:
            results.append(cls.parse(api, obj))
        return results

class Ticket(Model):

    @classmethod
    def parse(cls, api, json):
        ticket = cls(api)
        for k, v in json.items():
            if (k == 'created_on' or k == 'updated_at' or k == 'completed_date') and v:
                setattr(ticket, k, parse_datetime(v))
            else:
                setattr(ticket, k, v)
        return ticket

    @classmethod
    def parse_list(cls, api, json_list):
        if isinstance(json_list, list):
            item_list = json_list
        else:
            item_list = json_list['tickets'] # XXX check

        results = ResultSet()
        for obj in item_list:
            results.append(cls.parse(api, obj))
        return results

    def toJSON(self):
        pickle = self.__getstate__()
        pickle = {'ticket': pickle}
        return json.dumps(pickle, cls=DateTimeJSONEncoder)

    def __str__(self):
        """Return ticket number for easier serialization"""
        return str(self.number)

    def get_associations(self):
        return self._api.get_associations(space=self.space_id, ticket=self.number)

    def create_association(self, association):
        return self._api.create_association(association, space=self.space_id, ticket=self.number)

    def get_comments(self):
        return list(Cursor(self._api.get_ticket_comments, space=self.space_id, ticket=self.number).items())

    def create_comment(self, comment):
        return self._api.create_ticket_comment(comment, space=self.space_id, ticket=self.number)

    def attach_file(self, filecontent, docmeta):
        docmeta.attachable_id = self.id
        return self._api.create_document(filecontent, docmeta, space=self.space_id)

    def destroy(self):
        return self._api.delete_ticket(space=self.space_id, ticket=self.number)

    def get_document(self, fileid):
        return self._api.get_document(space=self.space_id, document=fileid)

    def get_milestone(self):
        return self._api.get_milestone(space=self.space_id, milestone=self.milestone_id)

class TicketComment(Model):

    @classmethod
    def parse(cls, api, json):
        comment = cls(api)
        comment.file = None
        comment.comment = None
        for k, v in json.items():
            if (k == 'created_on' or k == 'updated_at') and v:
                v = parse_datetime(v)
            elif (k == 'comment') and v:
                if '[[file' in v or '[[image' in v:
                    comment.file = parse_file(v)
            setattr(comment, k, v)
        return comment

    def toJSON(self):
        pickle = self.__getstate__()
        pickle = {'ticket_comment': pickle}
        return json.dumps(pickle, cls=DateTimeJSONEncoder)

class TicketCustomField(Model):

    @classmethod
    def parse(cls, api, json):
        customfield = cls(api)
        for k, v in json.items():
            if (k == 'created_on' or k == 'updated_at') and v:
                setattr(customfield, k, parse_datetime(v))
            else:
                setattr(customfield, k, v)
        return customfield

    def toJSON(self):
        pickle = self.__getstate__()
        if pickle['list_options']:
            pickle['list_options'] = ','.join(pickle['list_options'])
        pickle = {'custom_field': pickle}
        return json.dumps(pickle, cls=DateTimeJSONEncoder)

class TicketComponent(Model):

    def __init__(self, name, api=None):
        super(TicketComponent, self).__init__(api = api)
        self.name = name

    @classmethod
    def parse(cls, api, json):
        component = cls(api)
        for k, v in json.items():
            setattr(component, k, v)
        return component

    def toJSON(self):
        pickle = {'component': self.name}
        return json.dumps(pickle)

    def __str__(self):
        return self.name

class TicketAssociation(Model):

    @classmethod
    def parse(cls, api, json):
        association = cls(api)
        for k, v in json.items():
            if (k == 'created_at' or k == 'updated_at') and v:
                setattr(association, k, parse_datetime(v))
            else:
                setattr(association, k, v)
        return association

    def toJSON(self):
        pickle = self.__getstate__()
        pickle = {'ticket_association': pickle}
        return json.dumps(pickle, cls=DateTimeJSONEncoder)

    def invert(self):
        tmp = self.ticket1_id
        self.ticket2_id = self.ticket1_id
        self.ticket1_id = tmp
        if self.relationship == 0:
            self.relationship = 1
        elif self.relationship == 1:
            self.relationship = 0
        elif self.relationship == 7:
            self.relationship = 8
        elif self.relationship == 8:
            self.relationship = 7

class TicketStatus(Model):

    @classmethod
    def parse(cls, api, json):
        status = cls(api)
        for k, v in json.items():
            if (k == 'created_at' or k == 'updated_at') and v:
                setattr(status, k, parse_datetime(v))
            else:
                setattr(status, k, v)
        return status

    def toJSON(self):
        pickle = self.__getstate__()
        pickle = {'status': pickle}
        return json.dumps(pickle, cls=DateTimeJSONEncoder)

class Milestone(Model):

    @classmethod
    def parse(cls, api, json):
        milestone = cls(api)
        for k, v in json.items():
            if (k == 'created_at' or k == 'updated_at') and v:
                setattr(milestone, k, parse_datetime(v))
            if (k == 'completed_date' or k == 'due_date') and v:
                setattr(milestone, k, parse_date(v))
            else:
                setattr(milestone, k, v)
        return milestone

    def toJSON(self):
        pickle = self.__getstate__()
        pickle = {'milestone': pickle}
        return json.dumps(pickle, cls=DateTimeJSONEncoder)

class Document(Model):

    @classmethod
    def parse(cls, api, json):
        document = cls(api)
        for k, v in json.items():
            if (k == 'created_at' or k == 'updated_at') and v:
                setattr(document, k, parse_datetime(v))
            else:
                setattr(document, k, v)
        return document

    def toJSON(self):
        pickle = self.__getstate__()
        pickle = {'document': pickle}
        return json.dumps(pickle, cls=DateTimeJSONEncoder)

class MergeRequest(Model):

    @classmethod
    def parse(cls, api, json):
        mergerequest = cls(api)
        for k, v in json.items():
            if k in ['applied_at', 'created_at', 'updated_at'] and v:
                setattr(mergerequest, k, parse_datetime(v))
            else:
                setattr(mergerequest, k, v)
        return mergerequest

    def toJSON(self):
        pickle = self.__getstate__()
        pickle = {'merge_request': pickle}
        return json.dumps(pickle, cls=DateTimeJSONEncoder)

class JSONModel(Model):

    @classmethod
    def parse(cls, api, json):
        return json

class IDModel(Model):

    @classmethod
    def parse(cls, api, json):
        if isinstance(json, list):
            return json
        else:
            return json['ids']

class ModelFactory(object):
    """
    Used by parsers for creating instances
    of models. You may subclass this factory
    to add your own extended models.
    """

    space = Space
    user = User

    ticket = Ticket
    ticketcomment = TicketComment
    ticketcustomfield = TicketCustomField
    ticketcomponent = TicketComponent
    ticketassociation = TicketAssociation
    ticketstatus = TicketStatus

    document = Document
    milestone = Milestone
    mergerequest = MergeRequest

    json = JSONModel
    ids = IDModel


"""
---> Checking for changes in data file
Multiple approaches possible:

*** Check every cell against a "master" copy, assuming you have one.
    (inefficient, but good for pinpointing tampered cells)

*** Check every row against a hash of that row.
    (somewhat inefficient, but good for practice, and good for pinpointing tampered rows)

*** Check hash of a file. (most efficient way)

A good pragmatic balance is to check every row against a hash of that row; storing the hash of the row may help us
pinpoint which row may have been tampered.

================================
Exercise Part 1
Write a convenience function that hashes strings and returns the digest, and add it to datafuncs.py.
It should wrap the SHA256 algorithm.
================================
"""
from hashlib import sha256
def hash_string(string):
    """
    Convenience wrapper that returns the hash of a string.
    """
    assert isinstance(string, str), f'{string} is not a string!'
    string = string.encode('utf-8')
    return sha256(string).hexdigest()

"""
Exercise Part 2
Inside datafuncs.py, write a utility function with the signature hash_data(handle), that does the following:

    - Use pandas to open the data file as specified by the handle as the variable df.
    - Create a new DataFrame called hashes.
    - Create a new column in hashes called concat, which is each column of data from df converted to strings and
    concatenated into a contiguous string.
    - Create a new column in hashes called hash, which is the computed the hash of each row of the contiguous strings.
    - Delete the concat column from hashes.
    - Save the hashes to disk as the file hashes.csv.
================================
"""
import pandas as pd
def hash_data(handle):
    df = pd.read_csv(handle)
    hashes = pd.DataFrame()
    hashes['concat'] = df.apply(lambda x: ''.join(str(x[col]) for col in df.columns), axis=1)
    hashes['hash'] = hashes['concat'].apply(lambda x: hash_string(x))
    del hashes['concat']
    return hashes

"""
Exercise Part 3 -> Implemented in test_datafuncs.py
Now, write a function test_divvy_corrupt(), that lets us compare the two CSV files and automatically finds out which
row has corrupted data. You will need to import the functions previously written.
"""

"""

Hash of a file
It is possible to check the hash of a file. Let's add an existing implementation found online to our toolkit,
 datafuncs.py.

(All credit to StackOverflow community: http://stackoverflow.com/questions/3431825/generating-an-md5-checksum-of-a-file)

"""
def hash_file(fname):
    filehash = sha256()
    with open(fname, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            filehash.update(chunk)
    return filehash.hexdigest()

orig = hash_file('data/Divvy_Stations_2013.csv')

corr = hash_file('data/Divvy_Stations_2013_corrupt.csv')

print(orig)
print(corr)


# 노드 구조
class Node:
    def __init__(self, data):
        self.data = data
        self.left_child = None
        self.right_child = None

# 순회 결과를 저장할 리스트
pre_result = []
in_result = []
post_result = []

# 전위 순회
def pre_order(start):
    if start:
        pre_result.append(start.data)
        pre_order(start.left_child)
        pre_order(start.right_child)

# 중위순회
def in_order(start):
    if start:
        in_order(start.left_child)
        in_result.append(start.data)
        in_order(start.right_child)

# 후위 순회
def post_order(start):
    if start:
        post_order(start.left_child)
        post_order(start.right_child)
        post_result.append(start.data)

# 노드의 갯수
number = 15

# 노드를 저장할 리스트
nodes = [None] * (number + 1)

# 노드 초기화
for i in range(1, number + 1):
    nodes[i] = Node(i)

# 노드에 자식 노드 연결
for i in range(2, number + 1):
    if i % 2 == 0:
        nodes[i // 2].left_child = nodes[i]
    else:
        nodes[i // 2].right_child = nodes[i]

pre_order(nodes[1])
in_order(nodes[1])
post_order(nodes[1])

print("전위 순회 :", pre_result)
print("중위 순회 :", in_result)
print("후위 순회 :", post_result)


import os
import requests
from lxml import etree
import time
import random

def get_pic(link, hd, proxies=None):
    page_info = requests.get(link, headers=hd, proxies=proxies)
    page_info.encoding = 'utf-8'
    page_text = page_info.text
    page_info = etree.HTML(page_text)

    _title = page_info.xpath('//*[@id="subject_tpc"]/text()')[0]
    pic_list = page_info.xpath('//div[@id="read_tpc"]/img/@src')

    fp = r'H:\下载\imgs\{}'.format(_title)
    if not os.path.exists(fp):
        os.mkdir(fp)
    else:
        pass
    print('下载路径:{}'.format(fp))
    print('开始下载')

    start_time = time.perf_counter()
    for pic in pic_list:
        pic_name = pic.split('/')[-1]
        if pic_name not in os.listdir(fp):  # 检查是该pic是否已经被下载,如果没有,则下载它
            try:
                s = requests.session()
                s.keep_alive = False  # 关闭多余连接
                pic_info = requests.get(pic).content
                time.sleep(random.randint(1, 3))
            except ConnectionError:
                print('链接错误,请重试')
                break
            else:
                pic_path = fp + '\\' + pic_name
                with open(pic_path, 'wb') as f_save:
                    f_save.write(pic_info)
                    f_save.close()
                    print(pic_name, '下载完成')
        else:
            continue
    end_time = time.perf_counter()
    print('共耗时:', round((end_time - start_time), 2))

if __name__ == '__main__':
    proxy = {'http': '127.0.0.1:57816',
             'https': '127.0.0.1:57816'}

    headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
    (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36'}

    url = r'https://s1.v5uh.xyz/2048/read.php?tid-1972966-fpage-14.html'
    get_pic(url, headers)


import argparse
import json
from yatcobot.client import TwitterClient
from yatcobot.config import TwitterConfig, Config

parser = argparse.ArgumentParser(description='Download a tweet to json')
parser.add_argument('tweet_id', metavar='id', type=int)
parser.add_argument('--config', '-c', dest='config', default='../config.yaml', help='Path of the config file')

args = parser.parse_args()

Config.load(args.config)

client = TwitterClient(TwitterConfig.get().consumer_key,
                       TwitterConfig.get().consumer_secret,
                       TwitterConfig.get().access_token_key,
                       TwitterConfig.get().access_token_secret)

tweet = client.get_tweet(args.tweet_id)

with open('{}.json'.format(args.tweet_id), 'w') as f:
    json.dump(tweet, f, indent=2)


import time
import torch
import torchvision

class FashionMNIST(torch.utils.data.Dataset):
    def __init__(self, batch_size, size=(28, 28)):
        super().__init__()
        self.batch_size = batch_size
        self.root = "../data/"
        transf = torchvision.transforms.Compose([torchvision.transforms.Resize(size=size),
                                                torchvision.transforms.ToTensor()])

        self.train = torchvision.datasets.FashionMNIST(root=self.root,
                                                       train=True,
                                                       transform=transf,
                                                       download=True)

        self.val = torchvision.datasets.FashionMNIST(root=self.root,
                                                     train=False,
                                                     transform=transf,
                                                     download=True)
    def get_dataloader(self, train):
        dataset = self.train if train else self.val
        return torch.utils.data.DataLoader(dataset,
                                           shuffle=train,
                                           batch_size=self.batch_size)
    def get_traindataloader(self):
        return self.get_dataloader(train=True)
    def get_valdataloader(self):
        return self.get_dataloader(train=False)

class ADAdelta_Scratch(torch.optim.Adadelta):
    def __init__(self, parameters, rho):
        super().__init__(parameters, rho)
        self.parameters = parameters
        self.rho = rho
        self.states = []
        self.eta = 10**(-6)
        self.intermidiate_states = []

        self.init_states()
    def step(self):
        for param, state, intermidiate_state in zip(self.parameters, self.states, self.intermidiate_states):
            state[:] = self.rho*state + (1-self.rho)*torch.square(param.grad)
            deltas = param.grad*torch.sqrt(intermidiate_state+ self.eta)
            squared_deltas = torch.sqrt(state+ self.eta)
            update_grad = deltas.div_(squared_deltas)
            param[:] -= update_grad
            intermidiate_state[:] = self.rho*intermidiate_state - (1-self.rho)*torch.square(update_grad)

    def zero_grad(self):
        for param in self.parameters:
            if param.grad is not None:
                param.grad.zero_()

    def init_states(self):
        for param in self.parameters:
            self.states.append(torch.zeros_like(param))
            self.intermidiate_states.append(torch.zeros_like(param))

class Timer:
    def __init__(self):
        self.times = []
    def start(self):
        self.start_time = time.time()
    def stop(self):
        self.times.append(time.time()-self.start_time)


import pandas as pd
import numpy as np
import time,datetime
import string
import math
import matplotlib.pyplot as plt
import os
import networkx as nx
from copy import deepcopy
os.chdir('/Users/lvvv/Project')

#筛选数据
def venue_choice(train_data):
    venue=train_data['venueId'].value_counts()
    venue=venue[venue>1]
    c=np.zeros((3,len(venue.index)))
    a=list(venue.index)
    train_data=train_data[train_data.venueId.isin(a)].reset_index(drop=True)
    for i in range(len(train_data['userId'])):
        j=a.index(train_data['venueId'][i])
        c[0][j]=c[1][j]
        c[1][j]=train_data['userId'][i]
        if c[0][j]!=0 and c[0][j]!=c[1][j]:#不止出现一次并且前后两次用户Id不同
            c[2][j]=1
    return venue[c[2,:]>0]

#了解随时间分布情况，预处理使用
def time_div(train_data):
    l=[]
    for i in range(3000):
        if min(s)+3600*24*i>max(s):
            break
        t=(s>min(s)+3600*24*i)&(s<min(s)+3600*24*(i+1))
        l.append(len(t[t==True]))
    x=range(len(l))
    plt.plot(x,l,marker='o',ms=3)
    plt.savefig('num_date_new.png', dpi=300)

#计算co-occurrence 和time
def co_occurrence(train_data1,G,timescale):
    from copy import deepcopy
    user_list=list(train_data1['userId'].value_counts().index)
    venue=dict.fromkeys(train_data1['venueId'].value_counts().index, 0)
    #记录不同venue的co-occurence时间的数组
    venueCategory=list(train_data1['venueCategory'].value_counts().index)
    venue_time=dict(zip(venueCategory,[[] for i in range(len(venueCategory))]))

    for i in range(len(train_data1['userId'])-1):
        #前后时间
        t=train_data1['time'][i]
        t1=train_data1['time'][i+1]
        #前后用户id
        num1=train_data1['userId'][i]
        num2=train_data1['userId'][i+1]
        #大于规定时间间隔
        if t1-t>timescale:
            continue
        #处于同一地点且用户id不同
        if num1!=num2 and train_data1['venueId'][i]==train_data1['venueId'][i+1]:
            VCI=train_data1['venueCategory'][i]
            venue_time[VCI].append(t)
            venue_time[VCI].append(t1)

            if (num1,num2) in G.edges():
                G[num1][num2]['weight'][train_data1['venueId'][i]]+=1
            else:
                G.add_edge(num1,num2,weight=deepcopy(venue))#防止同时更改浅对象
                G[num1][num2]['weight'][train_data1['venueId'][i]]+=1
            j=i-1
            while j>=0:
                num1=train_data1['userId'][j]
                t2=train_data1['time'][j]
                if t1-t2>timescale:
                    break
                if num1!=num2 and train_data1['venueId'][j]==train_data1['venueId'][i+1]:
                    venue_time[VCI].append(t2)
                    if (num1,num2) in G.edges():
                        G[num1][num2]['weight'][train_data1['venueId'][i]]+=1
                    else:
                        G.add_edge(num1,num2,weight=deepcopy(venue))#防止同时更改浅对象
                        G[num1][num2]['weight'][train_data1['venueId'][i]]+=1
                j=j-1
    return G,venue_time

#计算location entropy
def location_entropy(train_data1):
    check_in_count=train_data1['venueId'].value_counts()
    userId=train_data1['userId'].value_counts()
    LE=[]
    for i in range(len(check_in_count)):
        #处于地点i的用户打卡次数
        new_data=train_data1[train_data1['venueId']==check_in_count.index[i]]['userId'].value_counts()
        #计算location entropy
        LE.append(-1*sum([m/sum(new_data)*math.log(m/sum(new_data)) for m in new_data if m!=0]))
    return LE

#计算diversity
def diversity(G):
    e=(1/(-0.9))
    for i in G.edges():
        co_sum=sum(list(G[i[0]][i[1]]['weight'].values()))
        G[i[0]][i[1]]['diversity']=0
        for j in G[i[0]][i[1]]['weight'].values():
            G[i[0]][i[1]]['diversity']+=(j/co_sum)**0.1
        G[i[0]][i[1]]['diversity']=G[i[0]][i[1]]['diversity']**e
    return G

#计算frequency
def frequency(G,LE):
    LE=np.exp(-mat(LE))
    for i in G.edges():
        G[i[0]][i[1]]['frequency']=(mat(list(G[i[0]][i[1]]['weight'].values()))*LE.T)[0,0]
    return G

#计算socail strength
def socail_strength(G):
    a=0.483
    b=0.520
    c=0.2
    for i in G.edges():
        G[i[0]][i[1]]['strength']=a*G[i[0]][i[1]]['diversity']+b*G[i[0]][i[1]]['frequency']+c
    return G

#画图
def drawGraph(fg, title='weighted_graph'):
    pos = nx.spring_layout(fg)
    nx.draw_networkx_nodes(fg, pos, node_shape='.', node_size=12)
    nx.draw_networkx_edges(fg, pos)
    nx.draw_networkx_labels(fg, pos,font_size=4)
    plt.savefig('1.png',dpi=300)
    plt.show()

#gephi，输出边表
def export_edge_list(G, labels=None, filename="edges.csv", delim=",", header=True):
    f=open(filename,'w')
    f.close()
    f = open(filename, 'w')
    if header:
        f.write("Source,Target,Weight,Type\n")
    for i,j,w in G.edges(data=True):
        f.write(str(i)+delim+str(j)+delim+str(w['weight'])+delim+"undirected"+"\n")
    f.close()

#划分不同venue的时间分布，需要先调用co_occurrence 函数获得VCI
def venue_time_draw(VCI,timescale):
    l=[]
    VCI=pd.Series(VCI)
    for i in VCI.index:
        if(VCI[i]==[]):
            l.append(False)
        else:
            l.append(True)
    a=VCI[l]
    plt.rcParams['figure.figsize']=(9,13)
    for i,k in enumerate(a):
        for j in k:
            plt.scatter((j%(24*3600)/3600+8)%24,i,c='b',s=2,alpha=0.3)
    plt.yticks(range(len(a.index)),list(a.index))
    plt.yticks(fontsize=10)
    plt.xticks(fontsize=16)
    plt.title('TKY_co-occurence_timescale_'+str(timescale), fontsize=24)
    plt.savefig('TKY_co-occurence_timescale_'+str(timescale)+'.png',dpi=300,bbox_inches="tight")
    plt.clf()

#主体函数
def main(train_data,timescale):
    t=time.clock()
    G = nx.Graph()
    t1=time.clock()
    G,VCI=co_occurrence(train_data,G,timescale)
    print("计算co-occurrence vector用时为：",time.clock()-t1)

    #划分不同venue的时间分布
    venue_time_draw(VCI,timescale)
    t1=time.clock()
    D=diversity(G)
    print("计算diversity用时为：",time.clock()-t1)

    t1=time.clock()
    LE=location_entropy(train_data)
    print("计算location entropy用时为：",time.clock()-t1)

    t1=time.clock()
    G=frequency(G,LE)
    print("计算frequency用时为：",time.clock()-t1)

    t1=time.clock()
    G=socail_strength(G)
    print("计算socail strength用时为：",time.clock()-t1)
    print("总用时为：",time.clock()-t)

    l=[]
    for i in G.edges():
        l.append(G[i[0]][i[1]]['strength'])
    print("------------timescale:",timescale,"--------------")
    print("最大值为：",max(l))
    print("平均值为：",sum(l)/len(l))
    print("最小值为：",min(l))
    print("-------------------------------------------------")
    #plt.scatter(pd.value_counts(l).index,pd.value_counts(l))
    #plt.savefig('TKY_div_'+str(timescale)+'.png')
    return G
#输出不同参数的边表，便于下一步的分析
def cal(i):
    train_data=pd.DataFrame(np.load("TKYtraindata.npy"))
    train_data.columns = ['userId', 'venueId', 'venueCategory','time']
    G=main(train_data,i)
    for j in [0.682,0.684,0.686,0.688]:
        G_friend=nx.Graph()
        for k in G.edges():
            G_degree=nx.degree(G)
            if G[k[0]][k[1]]['strength']>j and G_degree[k[0]]>1 and G_degree[k[1]]>1:
                G_friend.add_weighted_edges_from([(k[0],k[1],G[k[0]][k[1]]['strength'])])
        export_edge_list(G_friend,filename="TKYedges"+"_"+str(j)+"_"+str(i)+".csv")


from django.shortcuts import render
from django.http import HttpResponse
from shopping.views import shopping_cart
from datetime import datetime
from django.db import connection
import time

def get_cursor():
    return connection.cursor()

def member(request):
    return HttpResponse("会员")

def shop_cart(request):#购物车视图函数
    cookies = request.COOKIES

    if cookies.get('account'):
        account = request.GET.get("account")
        global shopping_cart
        if request.method == 'POST':
            if request.POST.get("book_plus"):
                shopping_cart[request.POST.get("book_plus")] += 1

            elif request.POST.get("book_reduce"):
                shopping_cart[request.POST.get("book_reduce")] -= 1
                if shopping_cart[request.POST.get("book_reduce")] == 0:  # 如果数量为零就移除购物车中该商品
                    shopping_cart.pop(request.POST.get("book_reduce"))

            elif request.POST.get("create_order"):#提交订单函数
                cursor = get_cursor()
                for key, value in shopping_cart.items():
                    if cursor.execute("select stock from books where bno='{}'".format(key)).fetchone()[0] < value:
                        #shopping_cart.clear()  # 清空购物车
                        return HttpResponse("{}库存不足,请查看库存从新选择并提交订单".format(key))

                ono = str(request.GET.get("account")) + "_" + str(int(time.time()))#获取账户名加空格加时间戳W为订单唯一ID

                total_price = 0#用来存放订单总价
                for key, value in shopping_cart.items():
                    price_and_discount = cursor.execute("select price, discount from books where bno='{}'".format(key)).fetchone()
                    price = price_and_discount[0]
                    discount = price_and_discount[1]
                    total_price += price * discount * value * 0.1#计算订单总价

                ####     插入操作,将订单信息插入order_form,    #####
                cursor.execute("insert into order_form(ono, submit_date, send_date, total_price, mno) values('{}','{}','{}','{:.2f}','{}')".format(ono, datetime.today(), '', total_price, account))
                #将订购信息插入order_information ,订单号，书号，书的数量，因为有主键约束，所有先进行插入order_form，后进行插入order_information
                for key, value in shopping_cart.items():
                    cursor.execute("insert into order_information(bno, ono, order_number) values('{}','{}','{}')".format(key, ono,value))
                #将订单图书在库存中减少
                for key, value in shopping_cart.items():
                    orig_stock = cursor.execute("select stock from books where bno='{}'".format(key)).fetchone()[0]
                    cursor.execute("update books set stock='{}' where bno='{}'".format(orig_stock - value, key))
                #订单提交到数据库，清空购物车字典
                shopping_cart.clear()#清空购物车
                return HttpResponse("订单提交成功")
            else:
                print("另类的post请求")
        context = {
            'account': account,#暂时没有用到
            'books': shopping_cart,

        }
        #print(context)
        return render(request, 'shopping_cart.html', context=context)
    else:
        return HttpResponse("请登录后查看购物车")


import os, sys
import sys
sys.path.append('/home/soopark0221/multiagent/RandomizedValueFunctions/baselines')

import argparse
import time
from datetime import datetime
import random
import numpy as np
import math
from collections import Counter
import torch
from torch.autograd import Variable
from tensorboardX import SummaryWriter
from baselines.common.schedules import LinearSchedule
from baselines.deepq.replay_buffer import ReplayBuffer

from qlearn.toys.agent import Agent
from qlearn.toys.multiagent import MultiAgent
from qlearn.toys.bootstrapped_agent import BootstrappedAgent
from qlearn.toys.bayes_backprop_agent import BayesBackpropAgent
from qlearn.toys.noisy_agent import NoisyAgent
from qlearn.toys.mnf_agent import MNFAgent
from qlearn.envs.nchain import NChainEnv
from qlearn.envs.multinchain import MultiNChainEnv

# from qlearn.toys.memory import ReplayBuffer
from qlearn.toys.test import test
from qlearn.envs.grid_envs import ZigZag6x10

parser = argparse.ArgumentParser(description='DQN')
parser.add_argument('--seed', type=int, default=510, help='Random seed')
parser.add_argument('--cuda', type=int, default=1, help='use cuda')
parser.add_argument('--max-steps', type=int, default=int(50e6), metavar='STEPS', help='Number of training steps')

parser.add_argument('--evaluation-episodes', type=int, default=1, metavar='N', help='Number of evaluation episodes to average over')
parser.add_argument('--model', type=str, metavar='PARAMS', help='Pretrained model (state dict)')
parser.add_argument('--replay_buffer_size', type=int, default=int(100000), metavar='CAPACITY', help='Experience replay memory capacity')
parser.add_argument('--learning-freq', type=int, default=10, metavar='k', help='Frequency of sampling from memory')
parser.add_argument("--learning-starts", type=int, default=32, help="number of iterations after which learning starts")
parser.add_argument('--discount', type=float, default=0.999, metavar='GAMMA', help='Discount factor')
parser.add_argument('--target-update-freq', type=int, default=100, metavar='TAU', help='Number of steps after which to update target network')
parser.add_argument('--lr', type=float, default=0.001, metavar='ETA', help='Learning rate')
parser.add_argument('--adam-eps', type=float, default=1.5e-4, metavar='EPSILON', help='Adam epsilon')
parser.add_argument('--batch-size', type=int, default=32, metavar='SIZE', help='Batch size')
parser.add_argument('--input-dim', type=int, default=8, help='the length of chain environment')
parser.add_argument('--evaluation-interval', type=int, default=10, metavar='STEPS', help='Number of training steps between evaluations')
parser.add_argument('--nheads', type=int, default=10, help='number of heads in Bootstrapped DQN')
parser.add_argument('--agent', type=str, default='DQN', help='type of agent')
parser.add_argument('--final-exploration', type=float, default=0.1, help='last value of epsilon')
parser.add_argument('--final-exploration-step', type=float, default=1000, help='horizon of epsilon schedule')
parser.add_argument('--max-episodes', type=int, default=int(2e3), metavar='EPISODES', help='Number of training episodes')
parser.add_argument('--hidden_dim', type=int, default=int(16), help='number of hidden unit used in normalizing flows')
parser.add_argument('--n-hidden', type=int, default=int(0), help='number of hidden layer used in normalizing flows')
parser.add_argument('--n-flows-q', type=int, default=int(1), help='number of normalizing flows using for the approximate posterior q')
parser.add_argument('--n-flows-r', type=int, default=int(1), help='number of normalizing flows using for auxiliary posterior r')
parser.add_argument('--logdir', type=str, default='logs', help='log directory')
parser.add_argument('--double-q', type=int, default=1, help='whether or not to use Double DQN')

parser.add_argument('--swag_start', default=1000, type=int, help='')
parser.add_argument('--swag_lr', default=0.0001, type=float, help='')
parser.add_argument('--sample_freq', default=30, type=int, help='')
parser.add_argument('--alg', default='ddpg', type=str, help='agent algorithm [ddpg, swag, wol]')
parser.add_argument('--discrete', action='store_true', help='discrete env')
parser.add_argument('--env', default='nchain', type=str, help='[nchain, lava, multinchain]')

# Setup
args = parser.parse_args()
assert args.agent in ['DQN', 'BootstrappedDQN', 'NoisyDQN', 'BayesBackpropDQN', 'MNFDQN', 'MultiDQN']

print(' ' * 26 + 'Options')
for k, v in vars(args).items():
  print(' ' * 26 + k + ': ' + str(v))

random.seed(args.seed)
np.random.seed(args.seed)
torch.manual_seed(args.seed)
if args.cuda:
    torch.cuda.manual_seed(args.seed)

# Environment
if args.env == 'nchain':
    env = NChainEnv(args.input_dim)
elif args.env == 'multinchain':
    env = MultiNChainEnv(args.input_dim)

action_space = env.action_space.n

# Log
date = time.strftime('%Y-%m-%d.%H%M')
run_dir = '{}/{}-{}-{}'.format(args.logdir, args.env, args.agent, date)

log = SummaryWriter(run_dir)
print('Writing logs to {}'.format(run_dir))

# Agent
if args.agent == 'BootstrappedDQN':
    dqn = BootstrappedAgent(args, env)
elif args.agent == 'NoisyDQN':
    dqn = NoisyAgent(args, env)
elif args.agent == 'BayesBackpropDQN':
    dqn = BayesBackpropAgent(args, env)
elif args.agent == 'MNFDQN':
    dqn = MNFAgent(args, env)
elif args.agent == 'MultiDQN':
    dqn = [MultiAgent(args, env, i) for i in range(2)]
else:
    dqn = Agent(args, env)

replay_buffer = ReplayBuffer(args.replay_buffer_size)
# mem = ReplayBuffer(args.memory_capacity)

# schedule of epsilon annealing
exploration = LinearSchedule(args.final_exploration_step, args.final_exploration, 1)

# import pdb
# pdb.set_trace()

# Training loop
if args.agent == 'MultiDQN':
    for i in range(2):
        dqn[i].online_net.train()
else:
    dqn.online_net.train()

timestamp = 0
for episode in range(args.max_episodes):
    episode_rew = 0
    epsilon = exploration.value(episode)
    #epsilon = 0.01
    state, done = env.reset(), False
    if args.agent == 'BootstrappedDQN':
        k = random.randrange(args.nheads)
    elif args.agent == 'VariationalDQN':
        dqn.online_net.freeze_noise()
    elif args.agent == 'BayesBackpropDQN':
        dqn.online_net.reset_noise()
    elif args.agent == 'MNFDQN':
        dqn.online_net.reset_noise()

    if args.alg == 'swag' and episode > args.swag_start+50:
        if args.agent == 'DQN':
            if episode < 700:
                scale = 0.9
            else:
                scale = 0.0
            dqn.swag_sample(scale=scale)
        elif args.agent == 'MultiDQN':
            for i in range(2):
                dqn[i].swag_sample(scale=scale)

    while not done:
        timestamp += 1

        if args.agent == 'BootstrappedDQN':
            action = dqn.act_single_head(state[None], k)
        elif args.agent in ['NoisyDQN', 'BayesBackpropDQN', 'MNFDQN']:
            action = dqn.act(state[None], eval=False)
        elif args.agent == 'DQN':
            if args.alg == 'swag':
                if episode <= args.swag_start+50:
                    action = dqn.act_e_greedy(state[None], epsilon=epsilon)
                else:
                    action = dqn.swag_act(state[None])
            else:
                action = dqn.act_e_greedy(state[None], epsilon=epsilon)
        elif args.agent == 'MultiDQN':
            action = []
            for i in range(2):
                if args.alg == 'swag':
                    if episode <= args.swag_start+50:
                        action.append(dqn[i].act_e_greedy(state[None], epsilon=epsilon))
                    else:
                        action.append(dqn[i].swag_act(state[None]))
                else:
                    action.append(dqn[i].act_e_greedy(state[None], epsilon=epsilon))
        next_state, reward, done, _ = env.step(action if args.agent == 'MultiDQN' else int(action))
        # Store the transition in memory
        replay_buffer.add(state, action, reward, next_state, float(done))
        episode_rew += reward

        # Move to the next state
        state = next_state
        #
        if timestamp % args.target_update_freq == 0:
            try:
                dqn.update_target_net()
            except: # if multiagent
                for i in range(2):
                    dqn[i].update_target_net()

    if timestamp > args.learning_starts:
        obses_t, actions, rewards, obses_tp1, dones = replay_buffer.sample(args.batch_size)
        #print(actions)
        if args.agent == 'MultiDQN':
            loss = 0
            for a_i in range(2):
                loss += dqn[a_i].learn(obses_t, actions, rewards, obses_tp1, dones, episode, dqn[1-a_i])
            loss /= 2

        else:
            loss = dqn.learn(obses_t, actions, rewards, obses_tp1, dones, episode)
        #log.add_scalar('loss', loss, timestamp)

    # if episode % 10 == 0:
    #     visited = []
    #     for transition in replay_buffer.memory:
    #         visited.append(transition.state.sum())
    #     print(Counter(visited))

    if episode > 4:
        avg_reward = test(args, env, dqn)  # Test
        print('episode: ' + str(episode) + ', Avg. reward: ' + str(round(avg_reward, 4)))
        log.add_scalar('test_reward', avg_reward, episode)
        log.add_scalar('episode_reward', episode_rew, episode)


import json
import logging

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer

class QueueConsumer(WebsocketConsumer):
    def connect(self):
        self.queue_id = self.scope["url_route"]["kwargs"]["queue_id"]
        self.room_group_name = f"queue_{self.queue_id}"

        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name, self.channel_name
        )

        self.accept()
        print(f"Consumer connected to queue {self.queue_id}")
        self.send(text_data=json.dumps({"message": "Connected"}))

    def disconnect(self, close_code):
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name, self.channel_name
        )

    def queue_message(self, event):
        message = event["message"]

        self.send(text_data=json.dumps(message))


import asyncio
from dataclasses import dataclass
from functools import cached_property
from PyQt5.QtCore import QObject, pyqtSignal
from bleak import BleakClient
from bleak.backends.device import BLEDevice

@dataclass
class QBleakClient(QObject):
    device: BLEDevice
    ecg_updated = pyqtSignal(list)
    Battery_level_read = pyqtSignal(int)

    def data_conv(self, sender, data):
        if data[0] == 0x00:
            timestamp = self.convert_to_unsigned_long(data, 1, 8)
            step = 3
            samples = data[10:]
            offset = 0
            ecg_package = []
            while offset < len(samples):
                ecg = self.convert_array_to_signed_int(samples, offset, step)
                offset += step
                ecg_package.append(ecg)
            self.ecg_updated.emit(ecg_package)

    def convert_array_to_signed_int(self, data, offset, length):
        return int.from_bytes(
            bytearray(data[offset: offset + length]), byteorder="little", signed=True,
        )

    def convert_to_unsigned_long(self, data, offset, length):
        return int.from_bytes(
            bytearray(data[offset: offset + length]), byteorder="little", signed=False,
        )

    def __post_init__(self):
        super().__init__()
        self.ECG_data = []

    @cached_property
    def client(self) -> BleakClient:
        return BleakClient(self.device, disconnected_callback=self._handle_disconnect)

    async def start(self):
        await self.client.connect()

        ## UUID for battery level ##
        BATTERY_LEVEL_UUID = "00002a19-0000-1000-8000-00805f9b34fb"

        BL = await self.client.read_gatt_char(BATTERY_LEVEL_UUID)
        Battery_level = int(BL[0])
        print(Battery_level, "%")
        self.Battery_level_read.emit(Battery_level)

        PMD_CONTROL = "FB005C81-02E7-F387-1CAD-8ACD2D8DF0C8"  ## UUID for Request of stream settings ##
        ECG_WRITE = bytearray([0x02, 0x00, 0x00, 0x01, 0x82, 0x00, 0x01, 0x01, 0x0E, 0x00])
        await self.client.write_gatt_char(PMD_CONTROL, ECG_WRITE)

        PMD_DATA = "FB005C82-02E7-F387-1CAD-8ACD2D8DF0C8"  ## UUID for Request of start stream ##
        await self.client.start_notify(PMD_DATA, self.data_conv)

    async def stop(self):
        await self.client.disconnect()

    def _handle_disconnect(self) -> None:
        print("Device was disconnected, goodbye.")
        # cancelling all tasks effectively ends the program
        for task in asyncio.all_tasks():
            task.cancel()


#!/usr/bin/env python3

# MUD Profile Examples: https://iotanalytics.unsw.edu.au/mudprofiles

import json
import time
import nmap
import re
#from six.moves import input

#These arrays store the TCP and UDP ports that scanned
#and found open on the IOT device
nmapTCP = []
nmapUDP = []

#These arrays store the unique TCP and UDP source ports that are
#allowed to be open, according to the IoT device's MUD file
uniqueMUDtcp = []
uniqueMUDudp = []

MUDtcp = []
MUDudp = []

def jsonPorter(configx):

    #These strings are used temporarily to contain
    #all TCP and UDP substrings from the MUD file
    TCPsourceStrings = ""
    UDPsourceStrings = ""

    #creates temporary array to store the TCP and UDP
    #ports from the MUD profile as some ports are repeated
    #in the MUD profile
    # uniqueMUDTCP = []
    # uniqueMUDUDP = []

    #Takes in the JSON file from user input, formats it
    with open(configx, 'r') as MUD:
        f1 = json.load(MUD)
    MUDtext = json.dumps(f1, indent=2)

    #################### Extracting TCP ports ####################

    #Extracting TCP ports, using regex
    portSnatcher = re.compile("tcp.*\s.*\s.*\s.*: \d+")
    result = portSnatcher.findall(MUDtext)

    #Cleaning output from MUD file and
    #appending to a TCP substring for port extraction later
    for index,item in enumerate(result):
        item.split()
        if 'source-port' in item:
            TCPsourceStrings += item

    #TCP ports are extractd and appended to a temporary TCP port array
    global MUDtcp
    MUDtcp = re.findall('\d+', TCPsourceStrings)
    # tcpTemp.append(port)
    # print tcpTemp

    #################### Extracting UDP ports ####################

    #Extracting UDP ports, using regex
    portSnatcher = re.compile("udp.*\s.*\s.*\s.*: \d+")
    result = portSnatcher.findall(MUDtext)

    #Cleaning output from MUD file and
    #appending to a UDP substring for port extraction later
    for index,item in enumerate(result):
        item.split()
        if 'source-port' in item:
            UDPsourceStrings += item

    #UDP ports are extractd and appended to a temporary UDP port array
    global MUDudp
    MUDudp = re.findall('\d+', UDPsourceStrings)

    # #this function only adds the unique TCP source-ports
    # #to the global MUDTCP array which is later presented to the user
    for port in MUDtcp:
        if port not in uniqueMUDtcp:
            uniqueMUDtcp.append(port)

    uniqueMUDtcp.sort()

    # #this program only adds the unique UDP source-ports
    # #to the global MUDTCP array which is later presented to the user
    for port in MUDudp:
        if port not in uniqueMUDudp:
            uniqueMUDudp.append(port)

    uniqueMUDudp.sort()

    # all the unique TCP and UDP ports have been added
    # to allPorts and is shown to the user
    # print allPorts

    # function returns the collection of all ports
    with open('ScanResults.txt', 'a') as f:
        f.write("The MUD file requires these TCP ports to be open:\n")
        for item in uniqueMUDtcp:
            f.write(item)
            f.write("\n")
        f.write("The MUD file requires these UDP ports to be open:\n")
        for item in uniqueMUDudp:
            f.write(item)
            f.write("\n")

def nmapScan(ip, portList, flags):

    result = ""
    scannedPorts = []

    #initiating the nmap port scanner
    nm = nmap.PortScanner()

    #this function scans the port
    #that is passed in to it
    for port in portList:

        #general command for scanning
        #could be improved to be stealthy
        nm.scan(ip,str(port),flags)
        # nm.scan(hosts=ip,arguments='-Pn')

        for host in nm.all_hosts():
            #Standard scanning procedure
            for proto in nm[host].all_protocols():
                lport = nm[host][proto].keys()

                for scannedPort in lport:
                    #Presenting the ports, portocols and status
                    result += ('\n' + ('Protocol : %s\t port : %s\tstate : %s' % (proto, scannedPort, nm[host][proto][scannedPort]['state'])))

                    #Scanned ports are added to the scannedPorts array
                    scannedPorts.append(scannedPort)

                    if proto=="TCP":
                    #Scanned TCP ports are added to the nmapTCP array
                        nmapTCP.append(scannedPort)

                    if proto=="UDP":
                    #Scanned UDP ports are added to the nmapTCP array
                        nmapUDP.append(scannedPort)

    #We present the results and return the total scanned ports
    print (result)

    with open('ScanResults.txt', 'a') as f:
        f.write(result)
        f.write("\n")

def nmapFullScan(ip,flags):

    result = ""
    scannedPorts = []
    # global nmapTCP
    # global nmapUDP

    #initiating the nmap port scanner
    nm = nmap.PortScanner()

    # for port in range(1,65535):
        #general command for scanning
        #could be improved to be stealthy

    # nm.scan(ip,str('1-65535'), '-Pn')
    nm.scan(hosts=ip,arguments=flags)

    for host in nm.all_hosts():
        #Standard scanning procedure
        for proto in nm[host].all_protocols():
            lport = nm[host][proto].keys()

            #the results are solted
            # lport.sort()

            for scannedPort in lport:
                #Presenting the ports, portocols and status
                if (nm[host][proto][scannedPort]['state'] == 'open'):
                    result += ('\n' + ('Protocol : %s\t port : %s\tstate : %s' % (proto, scannedPort, nm[host][proto][scannedPort]['state'])))

                #Scanned ports are added to the scannedPorts array
                scannedPorts.append(scannedPort)

                if proto=="tcp":
                #Scanned TCP ports are added to the nmapTCP array
                    print ("Under TCP")
                    print (scannedPort)

                    nmapTCP.append(scannedPort)

                if proto=="udp":
                #Scanned UDP ports are added to the nmapTCP array
                    print ("Under UDP")
                    print (scannedPort)

                    nmapUDP.append(scannedPort)

    nmapTCP.sort()
    nmapUDP.sort()
    print ("After Sorting in full scan")
    print (nmapTCP)
    print (nmapUDP)

    #We present the results and return the total scanned ports
    print (result)

    with open('ScanResults.txt', 'a') as f:
        # f.write("\nScan results (open ports) for all ports:")
        f.write(result)

def masterScanner(inputtedIP, inputtedMUD):

    ip = inputtedIP
    MUDfile = inputtedMUD

    with open('ScanResults.txt', 'a') as f:
        f.write("- - - - - - - - - - - - - - - - - - - - \n")
        f.write("Current scanning: " + ip + "\n")

    #We present the user with which ports are mentioned in the MUD file
    jsonPorter(MUDfile)

    with open('ScanResults.txt', 'a') as f:
        f.write("\nScanning TCP ports mentioned in the MUD file:")
    nmapScan(ip,uniqueMUDtcp,'-Pn -f')
    #nmapScan(ip,uniqueMUDtcp,'-Pn')

    with open('ScanResults.txt', 'a') as f:
        f.write("\nScanning UDP ports mentioned in the MUD file:")
    nmapScan(ip,uniqueMUDudp, '-Pn -sU')
    #nmapScan(ip,uniqueMUDudp, '-Pn')

    with open('ScanResults.txt', 'a') as f:
        f.write("\nPerforming complete scan of IP, only open ports are listed:")
    nmapFullScan(ip, '-Pn -f')
    nmapFullScan(ip, '-Pn -sU')

    print ("Before else ifs")
    print (nmapTCP)
    print (nmapUDP)

    with open('ScanResults.txt', 'a') as f:

        if uniqueMUDtcp == nmapTCP:
            f.write("\nTCP Ports are compliant, no extra open ports found outside MUD instructions.\n")
        elif len(nmapTCP) > len(uniqueMUDtcp):
            f.write("\nMore TCP ports are open than needed. TCP Ports are non-compliant.\n")
        else:
            f.write("\nMUD recommends having more TCP ports open, than on IoT currently. Device is over-protected.\n")

        if uniqueMUDudp == nmapUDP:
            f.write("UDP Ports are compliant, no extra open ports found outside MUD instructions.\n")
        elif len(nmapUDP) > len(uniqueMUDudp):
            f.write("\nMore UDP ports are open on IoT than needed. UDP Ports are non-compliant.\n")
        else:
            f.write("\nMUD recommends having more UDP ports open, than on IoT currently. Device is over-protected.\n")

#Asking the user for how many IP addresses to scan.
#DO NOT REMOVE, this breaks the loop on the 'for' loop.
print ("How many IP addresses (1 or more) do you wish to scan: ")
numberofIPs = int(input())
print ("What is the name of the json MUD file (include the .json extension): ")
MUDfile = input()
print ("\nPlease note, this program determines if the NUMBER of ports on your IoT matches the number of TCP/UDP ports in the MUD.")
print ("\nThis terminal will display content for troubleshooting only. The final esults of this scan will be inside 'ScanResults.txt' in the same directory as this file.")

with open('IP_Addresses.txt','r+') as f:
    ip = f.read().splitlines()
    for i in range(0,numberofIPs):
        masterScanner(ip[i], MUDfile)


"""
Project Name: class-manager-project
Author: Serrano, Jahaziel A.
Description: create, read, update, delete your classes to be aware of your class calendar
"""

from manager import Class
import re
from sys import stdout
RED   = "\033[1;31m"
RESET = "\033[0;0m"
BLUE =  "\033[1;34m"

"""" check/verify data before inserting """
def insert(obj):
    # Validate input before insert
    obj.setClassName(validate('[a-zA-Z0-9]+', 'Insert a class: '))
    obj.setProfessor(validate('[a-zA-Z]+', 'Insert professor: '))
    obj.setDay(validate('[a-zA-Z]+', 'Insert class day: '))
    obj.setHour(validate('[0-9]{2}:[0-9]{2}-[0-9]{2}:[0-9]{2}', 'Insert class hours: '))
    obj.setSemesterYear(validate('[0-9]{4}-[0-9]{4}', 'Insert semester year: '))
    obj.setSemester(validate('(primero|segundo)', 'Insert semester: '))

    # Insert Data and return status
    status = obj.insert()

    # Show process status
    if status == 1:
        stdout.write(BLUE)
        print(f'\nSucessfully inserted data!')
        stdout.write(RESET)
    else:
        stdout.write(RED)
        print(f'\nValueError: Data Already Exists!')
        stdout.write(RESET)

    # Show Data
    obj.showData()

""" Delete a class/row """
def delete(obj):
    # Show classes/rows
    obj.showData()

    # Verify if the usar want to delete then delete class\row
    choose = input('Are you sure? All data with specify class name will be deleted\nEscribir (y|Yes|Y) si desea cotinuar: ')
    if choose.strip() in 'y,Y,yes,Yes,YES,yEs,yES,YeS'.split(','):
        obj.setClassName(validate('[a-zA-Z0-9]+', 'Insert a class: '))
        count_delete = obj.delete()
    print(f'Deleted: {count_delete}')

    # Show classes/rows
    obj.showData()

""" Modify specify data"""
def modify(obj):
    # show Data
    obj.showData()

    # Ask Options
    print('\nChoose between this option: ')
    print('1. class\n2. professor\n3. days\n4. hour\n5. year\n6. semester')
    choose = validate('([1-6])', 'Which type data you want to modify: ')

    # Send to the Class Manager

    if int(choose) < 6 and int(choose) > 0:
        if choose in 'classname,class,1'.split(','):
            new_data = validate('[a-zA-Z0-9]+', 'Insert new data: ')
            old_data = validate('[a-zA-Z0-9]+', 'Insert old data: ')
            status = obj.modify(0, new_data, old_data)
        elif choose in 'professor,2'.split(','):
            new_data = validate('[a-zA-Z0-9]+', 'Insert new data: ')
            old_data = validate('[a-zA-Z0-9]+', 'Insert old data: ')
            status = obj.modify(1, new_data, old_data)
        elif choose in 'days,day,3'.split(','):
            new_data = validate('[a-zA-Z0-9]+', 'Insert new data: ')
            old_data = validate('[a-zA-Z0-9]+', 'Insert old data: ')
            status = obj.modify(2, new_data, old_data)
        elif choose in 'hour,hours,4'.split(','):
            new_data = validate('[a-zA-Z0-9]+', 'Insert new data: ')
            old_data = validate('[a-zA-Z0-9]+', 'Insert old data: ')
            status = obj.modify(3, new_data, old_data)
        elif choose in 'semesteryear,semesteryears,5'.split(','):
            new_data = validate('[a-zA-Z0-9]+', 'Insert new data: ')
            old_data = validate('[a-zA-Z0-9]+', 'Insert old data: ')
            status = obj.modify(4, new_data, old_data)
        elif choose in 'semester,semesters,6'.split(','):
            new_data = validate('[a-zA-Z0-9]+', 'Insert new data: ')
            old_data = validate('[a-zA-Z0-9]+', 'Insert old data: ')
            status = obj.modify(5, new_data, old_data)
    else:
        old_data = choose + ' option'
        status = 0

    # Show process status
    if status == 0:
        stdout.write(RED)
        print(f"\n{old_data} not found or doesn't exist")
        {stdout.write(RESET)}
    else:
        stdout.write(BLUE)
        print(f"\nSucessfully moified data!")
        stdout.write(RESET)

    # showData
    obj.showData()

""" Remove spaces and validate data"""
def validate(pattern, massage):
    data = None
    while data is None:
        data = input(massage)
        data = list(data)
        for char in data:
            if char == ' ':
                data.remove(char)
        data = ''.join(data)
        if re.search(pattern, data):
            return data.lower().strip()
        else:
            sys.stdout.write(RED)
            print(f"\tValueError: {data} format violated!\n\tFormat: {pattern} ")
            sys.stdout.write(RESET)
            data = None

""" Show option panel """
def print_option():
    print(f"""
Class Manager System
Programmer: Serrano Bermudez, Jahaziel A.
by Kubik
===============================================
           Choose between 1-4:
               1. Insert
               2. modify
               3. Delete
               4. show
               5. End Program
===============================================
   -Class Manager organiza tus clases-
   Si no ingresa un file este guardara
    los datos/cambios en classDB.csv
===============================================""")

def main():

    """ Show options panel """
    print_option()

    # Start console app
    while True:
        # ClassManager Object
        class_data = Class()
        operator = input('\n>> ')

        # Option 1: Insert a new class/row
        if operator == '1':
            """ check data and then insert it"""
            insert(class_data)
            print('\nProcess ends\n')

        # Option 2: Modify a column of a row/class
        elif operator == '2':
            """ Modify a spicific data """
            modify(class_data)
            print('\nProcess ends\n')

        # Option 3: Delete a row/class
        elif operator == '3':
            """Delete a row of data with the classname"""
            delete(class_data)

        # Option 4: Show all classes/rows on the console
        elif operator == '4':
            """Show the rows and there index"""
            class_data.showData()

        # Finish the program
        elif operator == '5':
            print('Program End\nThanks for used Clase Manager System')
            del class_data
            break

if __name__ == '__main__':
    main()


from django.db import models
from .product import Auto_part
import datetime

class Order(models.Model):
    first_name = models.CharField(verbose_name="Ім'я:",max_length=30, blank=False)
    second_name = models.CharField(verbose_name="Прізвище:",max_length=30, blank=False)
    city = models.CharField(verbose_name="Місто:",max_length=30, blank=False)
    nova_post_number = models.CharField(verbose_name="Номер нової пошти:",max_length=30, blank=False)
    oplata_on_post = models.BooleanField(verbose_name="Оплата у відділенні:",default=True)
    date_of_order = models.DateField(verbose_name="Коли було зроблене замовлення:",default=datetime.datetime.today)
    quantity_total = models.IntegerField(verbose_name="Кількість всіх товарів:")
    price_total = models.IntegerField(verbose_name="Ціна замовлення:")
    phone_number = models.CharField(verbose_name="Номер телефону:",blank=False, max_length=15)
    product = models.TextField(verbose_name="Замовлені запчастини:",blank=False)

    def placeOrder(self):
        self.save()
class QuickOrder(models.Model):
    date_of_order = models.DateField(verbose_name="Коли було зроблене замовлення:",default=datetime.datetime.today)
    price_total = models.IntegerField(verbose_name="Ціна замовлення:")
    phone_number = models.CharField(verbose_name="Номер телефону:",blank=False, max_length=15)
    product = models.TextField(verbose_name="Замовлені запчастини:",blank=False)

    def placeQuickOrder(self):
        self.save()


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        x = 0
        arr = []
        def inorder(node):
            nonlocal x
            if node is None:
                return None

            inorder(node.left)
            x+=1
            # print(f"{x} - {node.val}")
            if x == k:
                arr.append(node.val)
            inorder(node.right)

        inorder(root)
        return arr[0]


import random
code = "PLAY"
userCode = input("Enter " + code + " to play ")
result = 0
if userCode == "PLAY":
    random1 = random.randint(1,7)
    random2 = random.randint(1,7)
    random3 = random.randint(1,7)
    print(random1, random2, random3)
    firstNumber = int(input("Pick your first number "))
    secondNumber = int(input("Pick your second number "))
    thirdNumber = int(input("Pick your last number "))
    if random1 == firstNumber:
        result = result + 1
    if random2 == secondNumber:
        result = result + 1
    if random3 == thirdNumber:
        result = result + 1
else:
    print('Play next time!')

if result == 0 or result == 1:
        print('Try again next time')
elif result == 2:
        print('You got two out of three! You win!')
elif result == 3:
        print('Congratulation! JackPot!!')
else:
    print('Invalid results')


def solution(n, m, a_list):
    a_list = [x for x in a_list for _ in range(2)]
    dp_dict = {0: 0}
    a_index = 0
    while n not in dp_dict and a_index < m * 2:
        keys = list(dp_dict.keys()).copy()
        for key in keys:
            if key + a_list[a_index] <= n:
                dp_dict[key + a_list[a_index]] = a_list[a_index]

        a_index += 1
    combination_bill = []
    if n in dp_dict:
        while n > 0:
            last_bill = dp_dict[n]
            n -= last_bill
            combination_bill.append(last_bill)
        return len(combination_bill), combination_bill
    else:
        return -1

if __name__ == '__main__':
    n, m = map(int, input().split())
    a_list = list(map(int, input().split()))
    answer = solution(n, m, a_list)
    if isinstance(answer, int):
        print(answer)
    else:
        print(answer[0])
        print(*answer[1])


from qtpy import QtWidgets, QtCore
from openpype.tools.settings.settings.widgets import (
    ExpandingWidget
)

class Separator(QtWidgets.QFrame):
    def __init__(self, height=None, parent=None):
        super(Separator, self).__init__(parent)
        if height is None:
            height = 2

        splitter_item = QtWidgets.QWidget(self)
        splitter_item.setStyleSheet("background-color: #21252B;")
        splitter_item.setMinimumHeight(height)
        splitter_item.setMaximumHeight(height)

        layout = QtWidgets.QHBoxLayout(self)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.addWidget(splitter_item)

class ProxyLabelWidget(QtWidgets.QWidget):
    def __init__(self, label, mouse_release_callback=None, parent=None):
        super(ProxyLabelWidget, self).__init__(parent)

        self.mouse_release_callback = mouse_release_callback

        layout = QtWidgets.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        label_widget = QtWidgets.QLabel(label, self)
        layout.addWidget(label_widget)

        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)

        self.label_widget = label_widget

    def set_mouse_release_callback(self, callback):
        self.mouse_release_callback = callback

    def setText(self, text):
        self.label_widget.setText(text)

    def set_label_property(self, *args, **kwargs):
        self.label_widget.setProperty(*args, **kwargs)
        self.label_widget.style().polish(self.label_widget)

    def mouseReleaseEvent(self, event):
        if self.mouse_release_callback:
            return self.mouse_release_callback(event)
        return super(ProxyLabelWidget, self).mouseReleaseEvent(event)

__all__ = (
    "ExpandingWidget",
    "Separator",
)


import os, time
import torch
import torch.nn as nn
from datasets.dataset_loader import get_train_loader
from datasets.dataset_loader import get_test_loader
from models.get_network import get_network
import torch.optim as optim
from torch.utils.tensorboard import SummaryWriter
from utils.util import WarmUpLR
from criterion import LabelSmoothingCrossEntropy
from utils.util import split_weights

def train_engine(__C):
    # define network
    net = get_network(__C)
    net = net.cuda()

    if __C.n_gpu > 1 :
        net = nn.DataParallel(net, device_ids=__C.devices)

    # define dataloader
    train_loader = get_train_loader(__C)
    test_loader = get_test_loader(__C)

    # define optimizer and loss function
    if __C.label_smoothing:
        loss_function = LabelSmoothingCrossEntropy(__C.smoothing)
    else:
        loss_function = nn.CrossEntropyLoss()

    # define optimizer and training parameters
    if __C.no_bias_decay:
        params = split_weights(net)
    else:
        params = net.parameters()
    optimizer = optim.SGD(params, lr=__C.lr, momentum=0.9, weight_decay=5e-4)

    # define optimizer scheduler
    train_scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=__C.milestones, gamma=__C.lr_decay_rate)
    iter_per_epoch = len(train_loader)
    warmup_schedule = WarmUpLR(optimizer, iter_per_epoch * __C.warmup_epoch)

    # define tensorboard writer
    writer = SummaryWriter(log_dir=os.path.join(__C.tensorboard_log_dir,__C.model,__C.version))

    # define model save dir
    checkpoint_path = os.path.join(__C.ckpts_dir, __C.model, __C.version)
    if not os.path.exists(checkpoint_path):
        os.makedirs(checkpoint_path)
    checkpoint_path = os.path.join(checkpoint_path, '{net}-{epoch}-{type}.pth')

    # define log save dir
    log_path = os.path.join(__C.result_log_dir, __C.model)
    if not os.path.exists(log_path):
        os.makedirs(log_path)
    log_path = os.path.join(log_path,__C.version+'.txt')

    # write the hyper-parameters to log
    logfile = open(log_path, 'a+')
    logfile.write(str(__C))
    logfile.close()

    # if using pytorch-mixed_up-training create a scalar
    if __C.mixed_training:
        scalar = torch.cuda.amp.GradScaler()

    best_acc = 0.0
    loss_sum = 0
    for epoch in range(1, __C.epoch):
        if epoch > __C.warmup_epoch:
            train_scheduler.step(epoch)

        start = time.time()
        net.train()
        for step, (images, labels) in enumerate(train_loader):
            if epoch <= __C.warmup_epoch:
                warmup_schedule.step()
            images = images.cuda()
            labels = labels.cuda()
            # using gradient accumulation step

            optimizer.zero_grad()
            loss_tmp = 0
            for accu_step in range(__C.gradient_accumulation_steps):
                loss_tmp = 0
                sub_images = images[accu_step * __C.sub_batch_size:
                                    (accu_step + 1) * __C.sub_batch_size]
                sub_labels = labels[accu_step * __C.sub_batch_size:
                                    (accu_step + 1) * __C.sub_batch_size]

                if __C.mixed_training:
                    with torch.cuda.amp.autocast():
                        outputs = net(sub_images)
                        loss = loss_function(outputs, sub_labels)
                        loss = loss / __C.gradient_accumulation_steps
                    scalar.scale(loss).backward()
                else:
                    outputs = net(sub_images)
                    loss = loss_function(outputs, sub_labels)
                    loss = loss / __C.gradient_accumulation_steps
                    loss.backward()
                # loss_tmp += loss.cpu().data.numpy() * __C.gradient_accumulation_steps
                # loss_sum += loss.cpu().data.numpy() * __C.gradient_accumulation_steps
                loss_tmp += loss.cpu().data.numpy()
                loss_sum += loss.cpu().data.numpy()

            if __C.mixed_training:
                scalar.step(optimizer)
                scalar.update()
            else:
                optimizer.step()

            n_iter = (epoch-1) * len(train_loader) + step + 1
            print(
                '[{Version}] [{Model}] Training Epoch: {epoch} [{trained_samples}/{total_samples}]\tLoss: {:0.4f}\tLR: {:0.6f}'.format(
                    loss_tmp,
                    optimizer.param_groups[0]['lr'],
                    Version=__C.version,
                    Model=__C.model,
                    epoch=epoch,
                    trained_samples=step * __C.batch_size + len(images),
                    total_samples=len(train_loader.dataset)
                ))
            # update training loss for each iteration

            writer.add_scalar('[Epoch] Train/loss', loss_tmp, n_iter)
            if epoch <= __C.warmup_epoch:
                writer.add_scalar('[Epoch] Train/lr', warmup_schedule.get_lr()[0], epoch)
            else:
                writer.add_scalar('[Epoch] Train/lr', train_scheduler.get_lr()[0], epoch)

        # update the result logfile
        logfile = open(log_path, 'a+')
        logfile.write(
            'Epoch: ' + str(epoch) +
            ', Train Average Loss: {:.4f}'.format(loss_sum/len(train_loader.dataset)) +
            ', Lr: {:.6f}'.format(optimizer.param_groups[0]['lr']) +
            ', '
        )
        logfile.close()
        finish = time.time()
        print('epoch {} training time consumed: {:.2f}s'.format(epoch, finish - start))

        if __C.eval_every_epoch:
            start = time.time()
            net.eval()
            test_loss = 0.0
            correct = 0.0
            for (images, labels) in test_loader:
                images = images.cuda()
                labels = labels.cuda()
                eval_outputs = net(images)
                eval_loss = loss_function(eval_outputs, labels)
                test_loss += eval_loss.item()
                _, preds = eval_outputs.max(1)
                correct += preds.eq(labels).sum()
            finish = time.time()

            test_average_loss = test_loss / len(test_loader.dataset)  # 测试平均 loss
            acc = correct.float() / len(test_loader.dataset)  # 测试准确率

            # save model after every "save_epoch" epoches and model with the best acc
            if epoch > __C.milestones[1] and best_acc < acc:
                torch.save(net.state_dict(), checkpoint_path.format(net=__C.model, epoch=epoch, type='best'))
                best_acc = acc
                continue
            if not epoch % __C.save_epoch:
                torch.save(net.state_dict(), checkpoint_path.format(net=__C.model, epoch=epoch, type='regular'))

            # print the testing information
            print('Evaluating Network.....')
            print('Test set: Average loss: {:.4f}, Accuracy: {:.4f}, Time consumed:{:.2f}s'.format(
                test_average_loss,
                acc,
                finish - start
            ))
            print()

            # update the result logfile
            logfile = open(log_path, 'a+')
            logfile.write(
                'Test Average loss: {:.4f}'.format(test_average_loss) +
                ', Accuracy: {:.4f}'.format(acc) +
                '\n'
            )
            logfile.close()

            # update the tensorboard log file
            writer.add_scalar('[Epoch] Test/Average loss', test_average_loss, epoch)
            writer.add_scalar('[Epoch] Test/Accuracy', acc, epoch)