"""!@brief GUI prediction for Binary Neural Network, used to demonstrate progress to client.
Used as a demonstration of the neural network at the end of Sprint 2. GUI interface which allows a user to select an image. This image is then classified by the
neural network, and the certainty is displayed. If the file exists in the kaggle dataset CSV file, the correct class will be displayed, and a
tick or a cross will represent whether the classification was accurate.
"""

import sys
import os
import csv
import tkinter as tk
from tkinter.filedialog import askopenfilename
from keras.models import load_model
import numpy as np
from PIL import Image, ImageTk

imglist = []
window = tk.Tk()
window.withdraw()

# For usage, change MODEL_LOCATION and CSV_LOCATION to = "<.H5 OR CSV FILE PATH>"
MODEL_LOCATION = ""
CSV_LOCATION = ""

# Since binary classification, only 2 class names required.
class_to_name = ["cloudy", "clear"]

# Show an "Open" dialog box for user to select image, and return the path to the selected file
filename = askopenfilename()

def modelLoader(model_loc):
    """Given the path to a .h5 model file, loads and compiles the model."""
    model = load_model(model_loc)
    model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])
    return model

def initImage(filename):
    """Converts image to suitable format to be input into the model.
    Rescales by 1/255 to account for RGB value coefficients."""
    size = 150, 150
    # Convert image to suitable format to be input into the model.
    # Rescale by 1/255 to account for RGB value coefficients.
    img = Image.open(filename)
    img = img.resize(size, Image.ANTIALIAS)
    img = img.convert('RGB')
    x = np.asarray(img, dtype='float32')
    x = np.expand_dims(x, axis=0)
    x = x/255
    return x

def predictImage(image, model):
    """Given an augmented image, the function returns the prediction from the model,
    the class name of the prediction and the certainty percentage."""
    # Get the prediction from the model and obtain the class name.
    choice = model.predict(image)
    print(choice)
    classString = class_to_name[model.predict_classes(image)[0][0]]

    # Checking if the prediction is substantial evidence to use that class.
    # Display as certainty percentage
    if (choice >= 0.5):
        certainty= str(round(choice[0][0]*100, 2)) + "%"
    # If not display as uncertainty percentage
    else:
        certainty = str(round((1 - choice[0][0])*100, 2)) + "%"
    return choice, classString, certainty

def format(category):
    """Given a category name, returns the category name with spaces instead of underscores,
    and formatted to Title Case. clear_primary -> Clear Primary"""
    return category.replace("_", " ").title()

def restart_program():
    """Restarts the current program, so user can select another image to predict."""
    python = sys.executable
    os.execl(python, python, * sys.argv)

def getvals(filename):
    """Returns the actual image classification, specified in the given CSV. If not present "None" returned."""
    csvFile=open(CSV_LOCATION)
    reader=csv.reader(csvFile)
    for item in reader:
        if item[0] == filename:
            return item[1]
    return "None"

model = modelLoader(MODEL_LOCATION)
scaledImage = initImage(filename)
choice, out1, out2 = predictImage(scaledImage, model)

#getting the actual classes for the image
check = (getvals(os.path.basename(filename).split(".")[0]))

#just getting width and height in order to centre window
screen_width = int((window.winfo_screenwidth()/2) - 200)
screen_height = int((window.winfo_screenheight()/2) - 175)

window.geometry("400x425+" + str(screen_width) + "+" + str(screen_height))
window.deiconify()
window.title("CNN Predictions")

#importing image to the window
img = ImageTk.PhotoImage(Image.open(filename))
panel = tk.Label(window, image = img, height = "256", width = "256").pack()
T = tk.Text(window, height = 2)
T.config(font=("Arial"))
T.pack()
T.insert(tk.END,"I'm about " + out2 + " sure that is " + format(out1))
T.insert(tk.END, "\nActual: " + check + "\n")
T.tag_add("start", "1.10", "1.16")

T.tag_config("center", justify='center')
T.tag_add("center", 1.0, "end")

#highlights colour of certainty with colour codes
num = float(out2[:-1])
if(num >= 80):
    T.tag_config("start", foreground="green")
elif(num >= 70):
    T.tag_config("start", foreground="orange")
else:
    T.tag_config("start", foreground="red")

#output if the image is *actually* cloudy or clear
if (format(out1).lower() in check):
    result = tk.Label(window, text = "✓", fg = "green", font=(None, 50)).pack()
else:
    result = tk.Label(window, text = "✗", fg = "red", font=(None, 50)).pack()

b = tk.Button(window, text="Choose Another", command=restart_program, pady = '3', font=("Arial")).pack()
window.mainloop()


#!/usr/bin/env python3

#
a = [1, 2, 1, 4, 5, 1, 1, 101, 102, 103, 104, 105, 1, 2, 3, 4, 6, 7, 10]
largest = []
temp = []

print("********************************************************************************")
print("starting array = ", a)

# add the zeroth (first) number manually
temp.append(a[0])

# go down the list
for n in range(1, len(a)):
  # current number > end of temp, append it to temp
  if a[n] > temp[-1]:
    temp.append(a[n])
  # if it is smaller
  else:
    # compare len(temp) witn len(largest)
    # if temp is bigger, replace largest
    if len(temp) > len(largest):
      largest = temp
    # since we've hit a smaller number we also need to rest temp to the current number
    temp = [a[n]]

  print("====================================")
  print("step n  = ", n)
  print("(sub) a[n] = ", a[n])
  print("(sub) largest   -> ", largest)
  print("(sub)    temp   -> ", temp)
#
# at the end if the last temp is longer than largest, replace largest
if len(temp) > len(largest):
  largest = temp

print("largest increasing sequence = ", largest)


from django.urls import path
from . import views

urlpatterns = [
    path('hod',views.hodash, name='hodash'),
    path('hod/create-faculty', views.create_faculty, name="create_faculty"),
    path('hod/create-faculty1', views.create_faculty1, name="create_faculty1"),
    path('hod/create-course', views.create_course, name="create_course"),
    path('hod/create-class', views.create_class, name="create_class"),
    path('hod/assign_subject', views.assign_subject, name="assign_subject"),
    path('hod/assign_class', views.create_course, name="assign_class"),

    path('faculty',views.facdash, name='facdash'),
    path('faculty/add-students', views.add_students,name="add_students"),
    path('faculty/list-students', views.list_students,name="list_students"),
    path('faculty/list-students', views.list_students,name="list_students"),
    path('faculty/attendance', views.mark_attendance,name="mark_attendance"),
    path('faculty/timtable', views.add_timetable, name="add_timetable"),
    path('faculty/showreport', views.showreport, name="showreport"),
    path('sendwarning', views.sendwarning,name="sendwarning"),
]


from typing import Optional, Literal

import attrs
import numpy as np
import scipy.sparse as sp
from Recommenders.BaseRecommender import BaseRecommender
from Recommenders.Recommender_utils import check_matrix
from recsys_framework_extensions.data.io import DataIO
from recsys_framework_extensions.recommenders.base import SearchHyperParametersBaseRecommender
from recsys_framework_extensions.recommenders.mixins import MixinLoadModel
from recsys_framework_extensions.recommenders.rank import rank_data_by_row
from skopt.space import Categorical

T_SIGN = Literal[-1, 1]

@attrs.define(kw_only=True, frozen=True, slots=False)
class SearchHyperParametersFrequencyRecencyRecommender(SearchHyperParametersBaseRecommender):
    sign_frequency: Categorical = attrs.field(
        default=Categorical(
            categories=[-1, 1],
        )
    )
    sign_recency: Categorical = attrs.field(
        default=Categorical(
            categories=[-1, 1],
        )
    )

@attrs.define(kw_only=True, frozen=True, slots=False)
class SearchHyperParametersRecencyRecommender(SearchHyperParametersBaseRecommender):
    sign_recency: Categorical = attrs.field(
        default=Categorical(
            categories=[-1, 1],
        )
    )

class FrequencyRecencyRecommender(MixinLoadModel, BaseRecommender):
    RECOMMENDER_NAME = "FrequencyRecencyRecommender"

    def __init__(
        self,
        urm_train: sp.csr_matrix,
        uim_frequency: sp.csr_matrix,
        uim_timestamp: sp.csr_matrix,
        **kwargs,
    ):
        """
        Parameters
        ----------
        urm_train: csr_matrix
            A sparse matrix of shape (M, N), where M = #Users, and N = #Items. The content of this matrix is the latest
            recorded implicit interaction for the user-item pair (u,i), i.e., urm_train[u,i] = 1

        uim_frequency: csr_matrix
            A sparse matrix of shape (M, N), where M = #Users, and N = #Items. The content of this matrix is the
            frequency of impressions (number of times a given item has been impressed to a given user) for the
            user-item pair (u,i), i.e., uim_frequency[u,i] = frequency.

        uim_timestamp: csr_matrix
            A sparse matrix of shape (M, N), where M = #Users, and N = #Items. The content of this matrix is the
            latest recorded timestamp for the user-item pair (u,i), i.e., uim_timestamp[u,i] = timestamp.
        """
        super().__init__(
            URM_train=urm_train,
            verbose=True,
        )

        self._uim_frequency: sp.csr_matrix = uim_frequency.copy()
        self._uim_timestamp: sp.csr_matrix = uim_timestamp.copy()

        self._sign_frequency: T_SIGN = 1
        self._sign_recency: T_SIGN = 1
        self._sp_matrix_frequency_scores: sp.csr_matrix = sp.csr_matrix([], dtype=np.float32)
        self._sp_matrix_timestamp_scores: sp.csr_matrix = sp.csr_matrix([], dtype=np.float32)

    def fit(
        self,
        sign_frequency: T_SIGN,
        sign_recency: T_SIGN,
        **kwargs,
    ) -> None:

        sp_matrix_frequency_scores = sign_frequency * self._uim_frequency
        sp_matrix_timestamp_scores = sign_recency * self._uim_timestamp

        self._sign_frequency = sign_frequency
        self._sign_recency = sign_recency
        self._sp_matrix_frequency_scores = check_matrix(X=sp_matrix_frequency_scores, dtype=np.float32, format="csr")
        self._sp_matrix_timestamp_scores = check_matrix(X=sp_matrix_timestamp_scores, dtype=np.float32, format="csr")

    def save_model(
        self,
        folder_path: str,
        file_name: str = None
    ) -> None:
        if file_name is None:
            file_name = self.RECOMMENDER_NAME

        DataIO.s_save_data(
            folder_path=folder_path,
            file_name=file_name,
            data_dict_to_save={
                "_sign_frequency": self._sign_frequency,
                "_sign_recency": self._sign_recency,
                "_sp_matrix_frequency_scores": self._sp_matrix_frequency_scores,
                "_sp_matrix_timestamp_scores": self._sp_matrix_timestamp_scores,
            }
        )

    def load_model(
        self,
        folder_path: str,
        file_name: str = None,
    ) -> None:
        super().load_model(
            folder_path=folder_path,
            file_name=file_name,
        )

        assert hasattr(self, "_sign_frequency")
        assert hasattr(self, "_sign_recency")
        assert hasattr(self, "_sp_matrix_frequency_scores")
        assert hasattr(self, "_sp_matrix_timestamp_scores")

        self._sp_matrix_frequency_scores = check_matrix(X=self._sp_matrix_frequency_scores, format="csr", dtype=np.float32)
        self._sp_matrix_timestamp_scores = check_matrix(X=self._sp_matrix_timestamp_scores, format="csr", dtype=np.float32)

    def _compute_item_score(
        self,
        user_id_array: list[int],
        items_to_compute: list[int] = None
    ) -> np.ndarray:
        """
        Return
        ------
        np.ndarray
            A matrix with shape (M, N), where M = |user_id_array|, and N = #Items .
        """
        assert user_id_array is not None
        assert len(user_id_array) > 0

        num_score_users: int = len(user_id_array)
        num_score_items: int = self.URM_train.shape[1]

        arr_scores_timestamp = self._sp_matrix_timestamp_scores[user_id_array, :].toarray()
        arr_scores_frequency = self._sp_matrix_frequency_scores[user_id_array, :].toarray()

        assert arr_scores_frequency.shape == arr_scores_timestamp.shape
        assert num_score_items == arr_scores_timestamp.shape[1]

        item_scores = rank_data_by_row(
            keys=(arr_scores_timestamp, arr_scores_frequency)
        )

        # If we want to compute for only a certain group of items (`items_to_compute` not being None),
        # then we must have a mask that sets -INF to items outside this list.
        if items_to_compute is None:
            arr_mask_items: np.ndarray = np.ones_like(arr_scores_frequency, dtype=np.bool8)
        else:
            arr_mask_items = np.zeros_like(arr_scores_frequency, dtype=np.bool8)
            arr_mask_items[:, items_to_compute] = True

        item_scores = np.where(
            (arr_scores_frequency != 0) & (arr_scores_timestamp != 0) & arr_mask_items,
            item_scores,
            np.NINF,
        )

        assert item_scores.shape == (num_score_users, num_score_items)
        assert item_scores.shape == arr_scores_timestamp.shape
        assert item_scores.shape == arr_scores_frequency.shape

        return item_scores

class RecencyRecommender(MixinLoadModel, BaseRecommender):
    RECOMMENDER_NAME = "RecencyRecommender"

    def __init__(
        self,
        urm_train: sp.csr_matrix,
        uim_timestamp: sp.csr_matrix,
        **kwargs,
    ):
        """
        Parameters
        ----------
        urm_train: csr_matrix
            A sparse matrix of shape (M, N), where M = #Users, and N = #Items. The content of this matrix is the latest
            recorded implicit interaction for the user-item pair (u,i), i.e., urm_train[u,i] = 1

        uim_timestamp: csr_matrix
            A sparse matrix of shape (M, N), where M = #Users, and N = #Items. The content of this matrix is the
            latest recorded timestamp for the user-item pair (u,i), i.e., uim_timestamp[u,i] = timestamp.
        """
        super().__init__(
            URM_train=urm_train,
            verbose=True,
        )

        self._uim_timestamp: sp.csr_matrix = uim_timestamp.copy()

        self._sign_recency: T_SIGN = 1
        self._sp_matrix_timestamp_scores: sp.csr_matrix = sp.csr_matrix([], dtype=np.float32)

    def fit(
        self,
        sign_recency: T_SIGN,
        **kwargs,
    ) -> None:

        sp_matrix_timestamp_scores = sign_recency * self._uim_timestamp

        self._sign_recency = sign_recency
        self._sp_matrix_timestamp_scores = check_matrix(X=sp_matrix_timestamp_scores, dtype=np.float32, format="csr")

    def _compute_item_score(
        self,
        user_id_array: list[int],
        items_to_compute: Optional[list[int]] = None,
    ) -> np.ndarray:
        """
        Computes the preference scores of users toward items.

        Notes
        -----
            :class:`BaseRecommender` ranks items in a further step by their score. Items with the highest scores are
            positioned first in the list.

        Return
        ------
        np.ndarray
            A matrix with shape (M, N), where M = |user_id_array|, and N = #Items .
        """
        assert user_id_array is not None
        assert len(user_id_array) > 0

        num_score_users: int = len(user_id_array)
        num_score_items: int = self.URM_train.shape[1]

        arr_timestamp_users: np.ndarray = self._sp_matrix_timestamp_scores[user_id_array, :].toarray()
        if items_to_compute is None:
            arr_mask_items: np.ndarray = np.ones_like(arr_timestamp_users, dtype=np.bool8)
        else:
            arr_mask_items = np.zeros_like(arr_timestamp_users, dtype=np.bool8)
            arr_mask_items[:, items_to_compute] = True

        item_scores = np.where(
            (arr_timestamp_users != 0) & arr_mask_items,
            arr_timestamp_users,
            np.NINF,
        )

        assert item_scores.shape == (num_score_users, num_score_items)

        return item_scores

    def save_model(
        self,
        folder_path: str,
        file_name: str = None
    ) -> None:
        if file_name is None:
            file_name = self.RECOMMENDER_NAME

        DataIO.s_save_data(
            folder_path=folder_path,
            file_name=file_name,
            data_dict_to_save={
                "_sign_recency": self._sign_recency,
                "_sp_matrix_timestamp_scores": self._sp_matrix_timestamp_scores,
            }
        )

    def load_model(
        self,
        folder_path: str,
        file_name: str = None,
    ) -> None:
        super().load_model(
            folder_path=folder_path,
            file_name=file_name,
        )

        assert hasattr(self, "_sign_frequency")
        assert hasattr(self, "_sp_matrix_timestamp_scores")

        self._sp_matrix_timestamp_scores = check_matrix(X=self._sp_matrix_timestamp_scores, format="csr", dtype=np.float32)


from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals

from googlecloudsdk.api_lib.compute import constants
from googlecloudsdk.api_lib.compute import instance_utils
from googlecloudsdk.api_lib.compute import path_simplifier
from googlecloudsdk.core.resource import resource_transform
import six

def TransformFirewallRule(r, undefined=''):
  """Returns a compact string describing a firewall rule.

  The compact string is a comma-separated list of PROTOCOL:PORT_RANGE items.
  If a particular protocol has no port ranges then only the protocol is listed.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    A compact string describing the firewall rule in r.
  """
  protocol = resource_transform.GetKeyValue(r, 'IPProtocol', None)
  if protocol is None:
    return undefined
  rule = []
  port_ranges = resource_transform.GetKeyValue(r, 'ports', None)
  try:
    for port_range in port_ranges:
      rule.append('{0}:{1}'.format(protocol, port_range))
  except TypeError:
    rule.append(protocol)
  return ','.join(rule)

def TransformOrganizationFirewallRule(rule, undefined=''):
  """Returns a compact string describing an organization firewall rule.

  The compact string is a comma-separated list of PROTOCOL:PORT_RANGE items.
  If a particular protocol has no port ranges then only the protocol is listed.

  Args:
    rule: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    A compact string describing the organizatin firewall rule in the rule.
  """
  protocol = resource_transform.GetKeyValue(rule, 'ipProtocol', None)
  if protocol is None:
    return undefined
  result = []
  port_ranges = resource_transform.GetKeyValue(rule, 'ports', None)
  try:
    for port_range in port_ranges:
      result.append('{0}:{1}'.format(protocol, port_range))
  except TypeError:
    result.append(protocol)
  return ','.join(result)

def TransformImageAlias(r, undefined=''):
  """Returns a comma-separated list of alias names for an image.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    A comma-separated list of alias names for the image in r.
  """
  name = resource_transform.GetKeyValue(r, 'name', None)
  if name is None:
    return undefined
  project = resource_transform.TransformScope(
      resource_transform.GetKeyValue(r, 'selfLink', ''),
      'projects').split('/')[0]
  aliases = [alias for alias, value in constants.IMAGE_ALIASES.items()
             if name.startswith(value.name_prefix)
             and value.project == project]
  return ','.join(aliases)

def TransformLocation(r, undefined=''):
  """Return the region or zone name.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    The region or zone name.
  """
  for scope in ('zone', 'region'):
    location = resource_transform.GetKeyValue(r, scope, None)
    if location:
      return resource_transform.TransformBaseName(location, undefined)
  return undefined

def TransformLocationScope(r, undefined=''):
  """Return the location scope name, either region or zone.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    The location scope name, either region or zone.
  """
  for scope in ('zone', 'region'):
    location = resource_transform.GetKeyValue(r, scope, None)
    if location:
      return scope
  return undefined

def TransformMachineType(r, undefined=''):
  """Return the formatted name for a machine type.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    The formatted name for a machine type.
  """
  if not isinstance(r, six.string_types):
    return undefined
  custom_family, custom_cpu, custom_ram = \
    instance_utils.GetCpuRamVmFamilyFromCustomName(r)
  if not custom_family or not custom_cpu or not custom_ram:
    return r
  # Restricting output to 2 decimal places
  custom_ram_gb = '{0:.2f}'.format(float(custom_ram) / (2**10))
  return 'custom ({0}, {1} vCPU, {2} GiB)'.format(custom_family, custom_cpu,
                                                  custom_ram_gb)

def TransformNextMaintenance(r, undefined=''):
  """Returns the timestamps of the next scheduled maintenance.

  All timestamps are assumed to be ISO strings in the same timezone.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    The timestamps of the next scheduled maintenance or undefined.
  """
  if not r:
    return undefined
  next_event = min(r, key=lambda x: x.get('beginTime', None))
  if next_event is None:
    return undefined
  begin_time = next_event.get('beginTime', None)
  if begin_time is None:
    return undefined
  end_time = next_event.get('endTime', None)
  if end_time is None:
    return undefined
  return '{0}--{1}'.format(begin_time, end_time)

def TransformOperationHttpStatus(r, undefined=''):
  """Returns the HTTP response code of an operation.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if there is no response code.

  Returns:
    The HTTP response code of the operation in r.
  """
  if resource_transform.GetKeyValue(r, 'status', None) == 'DONE':
    return (resource_transform.GetKeyValue(r, 'httpErrorStatusCode', None) or
            200)  # httplib.OK
  return undefined

def TransformProject(r, undefined=''):
  """Returns a project name from a selfLink.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    A project name for selfLink from r.
  """
  project = resource_transform.TransformScope(
      resource_transform.GetKeyValue(r, 'selfLink', ''),
      'projects').split('/')[0]
  return project or undefined

def TransformName(r, undefined=''):
  """Returns a resource name from an URI.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    A project name for selfLink from r.
  """
  if r:
    try:
      return r.split('/')[-1]
    except AttributeError:
      pass
  return undefined

def TransformQuota(r, undefined=''):
  """Formats a quota as usage/limit.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    The quota in r as usage/limit.
  """
  usage = resource_transform.GetKeyValue(r, 'usage', None)
  if usage is None:
    return undefined
  limit = resource_transform.GetKeyValue(r, 'limit', None)
  if limit is None:
    return undefined
  try:
    if usage == int(usage) and limit == int(limit):
      return '{0}/{1}'.format(int(usage), int(limit))
    return '{0:.2f}/{1:.2f}'.format(usage, limit)
  except (TypeError, ValueError):
    pass
  return undefined

def TransformScopedSuffixes(uris, undefined=''):
  """Get just the scoped part of the object the uri refers to."""

  if uris:
    try:
      return sorted([path_simplifier.ScopedSuffix(uri) for uri in uris])
    except TypeError:
      pass
  return undefined

def TransformStatus(r, undefined=''):
  """Returns the machine status with deprecation information if applicable.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    The machine status in r with deprecation information if applicable.
  """
  status = resource_transform.GetKeyValue(r, 'status', None)
  deprecated = resource_transform.GetKeyValue(r, 'deprecated', '')
  if deprecated:
    return '{0} ({1})'.format(status, deprecated.get('state', ''))
  return status or undefined

def TransformVpnTunnelGateway(vpn_tunnel, undefined=''):
  """Returns the gateway for the specified VPN tunnel resource if applicable.

  Args:
    vpn_tunnel: JSON-serializable object of a VPN tunnel.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    The VPN gateway information in the VPN tunnel object.
  """
  target_vpn_gateway = resource_transform.GetKeyValue(vpn_tunnel,
                                                      'targetVpnGateway', None)
  if target_vpn_gateway is not None:
    return target_vpn_gateway

  vpn_gateway = resource_transform.GetKeyValue(vpn_tunnel, 'vpnGateway', None)
  if vpn_gateway is not None:
    return vpn_gateway

  return undefined

def TransformZone(r, undefined=''):
  """Returns a zone name from a selfLink.

  Args:
    r: JSON-serializable object.
    undefined: Returns this value if the resource cannot be formatted.

  Returns:
    A zone name for selfLink from r.
  """
  project = resource_transform.TransformScope(
      resource_transform.GetKeyValue(r, 'selfLink', ''), 'zones').split('/')[0]
  return project or undefined

def TransformTypeSuffix(uri, undefined=''):
  """Get the type and the name of the object the uri refers to."""

  try:
    # Since the path is assumed valid, we can just take the last two pieces.
    return '/'.join(uri.split('/')[-2:]) or undefined
  except (AttributeError, IndexError, TypeError):
    pass
  return undefined

_TRANSFORMS = {
    'firewall_rule': TransformFirewallRule,
    'org_firewall_rule': TransformOrganizationFirewallRule,
    'image_alias': TransformImageAlias,
    'location': TransformLocation,
    'location_scope': TransformLocationScope,
    'machine_type': TransformMachineType,
    'next_maintenance': TransformNextMaintenance,
    'name': TransformName,
    'operation_http_status': TransformOperationHttpStatus,
    'project': TransformProject,
    'quota': TransformQuota,
    'scoped_suffixes': TransformScopedSuffixes,
    'status': TransformStatus,
    'type_suffix': TransformTypeSuffix,
    'vpn_tunnel_gateway': TransformVpnTunnelGateway,
    'zone': TransformZone,
}

def GetTransforms():
  """Returns the compute specific resource transform symbol table."""
  return _TRANSFORMS


import datetime as dt
import json
import typing
from pathlib import Path
from sys import getfilesystemencoding

from qgis.gui import (
    QgsFileWidget,
    QgisInterface,
)
from qgis.core import (
    Qgis,
    QgsExpressionContextUtils,
    QgsMapLayer,
    QgsLayerMetadata,
    QgsMapLayerType,
    QgsProject,
)
from PyQt5 import uic
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from PyQt5.QtPrintSupport import QPrinter

from . import models
from . import utils
from .automation import AutomationButtonsWidget
from .checklist_picker import ChecklistPicker
from .constants import (
    ChecklistItemPropertyColumn,
    ChecklistModelColumn,
    CustomDataRoles,
    DatasetType,
    LayerChooserDataRole,
    QGIS_VARIABLE_PREFIX,
    TabPages,
    ValidationArtifactType,
)
from .report import ReportHandler
from .utils import log_message

# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
UI_DIR = Path(__file__).parents[1] / "ui"
FORM_CLASS, _ = uic.loadUiType(str(UI_DIR / "dataset_qa_workbench_dock.ui"))

class DatasetQaWorkbenchDock(QtWidgets.QDockWidget, FORM_CLASS):
    add_report_to_layer_metadata_pb: QtWidgets.QPushButton
    dataset: typing.Optional[typing.Union[QgsMapLayer, str]]
    iface: QgisInterface
    tab_widget: QtWidgets.QTabWidget
    checklist_checks_tv: models.MyTreeView
    checklist_picker_dlg: ChecklistPicker
    checklist_name_le: QtWidgets.QLineEdit
    checklist_artifacts_le: QtWidgets.QLineEdit
    checklist_types_le: QtWidgets.QLineEdit
    checklist_description_te: QtWidgets.QTextEdit
    choose_checklist_pb: QtWidgets.QPushButton
    clear_checks_pb: QtWidgets.QPushButton
    validate_file_rb: QtWidgets.QRadioButton
    validate_layer_rb: QtWidgets.QRadioButton
    layer_chooser_lv: QtWidgets.QListView
    file_chooser: QgsFileWidget
    selected_checklist: typing.Optional[models.CheckList]
    report_te: QtWidgets.QTextEdit
    save_report_fw: QgsFileWidget
    save_report_pb: QtWidgets.QPushButton
    tab_widget: QtWidgets.QTabWidget
    run_post_validation_pb: QtWidgets.QPushButton
    configure_and_run_post_validation_pb: QtWidgets.QPushButton
    report_handler: typing.Optional[ReportHandler]

    closingPlugin = QtCore.pyqtSignal()

    def __init__(self, iface: QgisInterface, parent=None):
        """Constructor."""
        super(DatasetQaWorkbenchDock, self).__init__(parent)
        # Set up the user interface from Designer through FORM_CLASS.
        # After self.setupUi() you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)
        self.dataset = None
        self.save_report_pb.setDisabled(True)
        self.iface = iface
        self.checklists = []
        self.selected_checklist = None
        self.tab_widget.currentChanged.connect(self.update_tab_page)
        self.tab_widget.setTabEnabled(TabPages.CHOOSE.value, True)
        self.tab_widget.setTabEnabled(TabPages.VALIDATE.value, False)
        self.tab_widget.setTabEnabled(TabPages.REPORT.value, False)
        self.tab_pages = [self.tab_widget.widget(i.value) for i in TabPages]
        self.choose_checklist_pb.clicked.connect(self.show_checklist_picker)
        self.save_report_fw.fileChanged.connect(self.toggle_save_report_button)
        self.save_report_pb.clicked.connect(self.save_report)
        self.add_report_to_layer_metadata_pb.clicked.connect(
            self.add_report_to_layer_metadata
        )
        self.clear_checks_pb.clicked.connect(self.clear_all_checks)
        self.automate_all_checks_pb.clicked.connect(self.automate_all_checks)
        self.file_chooser.fileChanged.connect(self.selected_file_changed)
        self.validate_layer_rb.toggled.connect(
            self.respond_to_validate_layer_rb_toggled
        )
        self.report_handler = None
        # TODO: It might be necessary to disconnect these when plugin is unloaded
        QgsProject.instance().layersAdded.connect(self.respond_to_layers_added)
        QgsProject.instance().layersRemoved.connect(self.respond_to_layers_removed)

    def respond_to_layers_added(self, layers):
        utils.log_message("layers added")
        if self.selected_checklist is not None:
            current_dataset_type = self.selected_checklist.dataset_type
            model: QtGui.QStandardItemModel = self.layer_chooser_lv.model()
            for layer in layers:
                if utils.match_maplayer_type(layer.type()) == current_dataset_type:
                    item = QtGui.QStandardItem(layer.name())
                    item.setData(
                        layer.id(), LayerChooserDataRole.LAYER_IDENTIFIER.value
                    )
                    model.appendRow([item])

    def respond_to_layers_removed(self, layers: typing.List[str]):
        utils.log_message("layers removed")
        model: QtGui.QStandardItemModel = self.layer_chooser_lv.model()
        if model is not None:
            for row_idx in reversed(range(model.rowCount())):
                index = model.index(row_idx, 0)
                item = model.itemFromIndex(index)
                if item.data() in layers:
                    model.removeRow(row_idx)

    def clear_all_checks(self):
        utils.log_message(f"clear_all_checks_called")
        model = self.checklist_checks_tv.model()
        for row_index in range(model.rowCount()):
            utils.log_message(f"Unchecking row {row_index}...")
            checkbox_index = model.index(row_index, 1)
            model.setData(
                checkbox_index, QtCore.Qt.Unchecked, role=QtCore.Qt.CheckStateRole
            )
            head_index = model.index(row_index, 0)
            notes_index = model.index(
                ChecklistItemPropertyColumn.VALIDATION_NOTES.value, 1, parent=head_index
            )
            model.setData(notes_index, "", role=QtCore.Qt.EditRole)

    def automate_all_checks(self):
        utils.log_message(f"automate_all_checks_called")
        model = self.checklist_checks_tv.model()
        for row_index in range(model.rowCount()):
            item_head_index = model.index(row_index, 0)
            automation_index = model.index(
                ChecklistItemPropertyColumn.AUTOMATION.value, 1, parent=item_head_index
            )
            automation_widget = self.checklist_checks_tv.indexWidget(automation_index)
            if automation_widget:
                automation_widget.automator.perform_automation()

    def update_tab_page(self, index: int):
        if index == TabPages.REPORT.value:
            report = self.update_report()
            current_checklist = self.get_current_checklist()
            if current_checklist is not None and report is not None:
                if current_checklist.report is not None:
                    self.report_handler = ReportHandler(
                        self.iface,
                        report,
                        current_checklist.report.algorithm_id,
                        current_checklist.report.extra_parameters,
                    )

                self.toggle_post_validation_elements(
                    current_checklist.report is not None
                )
            else:
                self.toggle_post_validation_elements(False)

            self.add_report_to_layer_metadata_pb.setEnabled(
                self.validate_layer_rb.isChecked()
            )

    def get_current_checklist(self) -> typing.Optional[models.CheckList]:
        model = self.checklist_checks_tv.model()
        return getattr(model, "checklist", None)

    def update_report(self) -> typing.Optional[typing.Dict]:
        if self.validate_layer_rb.isChecked():
            current_layer_idx = self.layer_chooser_lv.currentIndex()
            layer_model = self.layer_chooser_lv.model()
            layer_id = layer_model.data(
                current_layer_idx, role=LayerChooserDataRole.LAYER_IDENTIFIER.value
            )
            if layer_id is not None:
                project = QgsProject.instance()
                layer = project.mapLayers()[layer_id]
                dataset = layer
            else:
                dataset = None
        else:
            dataset = Path(self.file_chooser.filePath()).name
        report = self.generate_report(dataset)
        if report:
            serialized = utils.serialize_report_to_html(report)
            self.report_te.setDocument(serialized)
        return report

    def toggle_post_validation_elements(self, enabled: bool):
        self.run_post_validation_pb.setEnabled(enabled)
        self.configure_and_run_post_validation_pb.setEnabled(enabled)
        if enabled:
            self.run_post_validation_pb.clicked.connect(
                self.report_handler.handle_report
            )
            self.configure_and_run_post_validation_pb.clicked.connect(
                self.report_handler.configure_and_handle_report
            )
        else:
            try:
                self.run_post_validation_pb.clicked.disconnect()
                self.configure_and_run_post_validation_pb.clicked.disconnect()
            except TypeError:
                # buttons were already disconnected
                pass

    def generate_report(self, dataset: typing.Union[QgsMapLayer, str]):
        checklist_model = self.checklist_checks_tv.model()
        if checklist_model is not None:
            result = get_report_contents(checklist_model, dataset)
        else:
            result = None
        return result

    def toggle_save_report_button(self, current_path: str):
        if current_path:
            self.save_report_pb.setDisabled(False)
        else:
            self.save_report_pb.setDisabled(True)

    def save_report(self):
        output = get_report_path(self.save_report_fw.filePath())
        printer = QPrinter(QPrinter.PrinterResolution)
        printer.setOutputFormat(QPrinter.PdfFormat)
        printer.setPaperSize(QPrinter.A4)
        printer.setOutputFileName(str(output))
        doc: QtGui.QTextDocument = self.report_te.document().clone()
        page_size = printer.pageRect().size()
        doc.setPageSize(QtCore.QSizeF(page_size.width(), page_size.height()))
        doc.print(printer)
        if output.is_file():
            # `doc.print` does not return a value, so this is a hacky way to
            # check if the file was saved correctly
            self.iface.messageBar().pushMessage(
                "Success", "Validation report saved!", level=Qgis.Info
            )
        else:
            self.iface.messageBar().pushMessage(
                "Error",
                f"Could not save validation report to: {output}",
                level=Qgis.Critical,
            )

    def add_report_to_layer_metadata(self):
        report = self.generate_report(dataset=self.dataset)
        add_report_to_layer(report, self.dataset)
        self.iface.messageBar().pushMessage(
            "Success", "Validation report added to layer metadata!", level=Qgis.Info
        )

    def selected_layer_changed(
        self, current: QtCore.QModelIndex, previous: QtCore.QModelIndex
    ):
        # NOTE: This method does not get called when list item is deselected
        self.dataset = self._get_current_layer()
        if self.dataset:
            self.load_checklist_steps(current, previous)

    def load_checklist_steps(
        self, current: QtCore.QModelIndex, previous: QtCore.QModelIndex
    ):
        utils.log_message(
            f"inside load_checklist_steps selected_checklist: {self.selected_checklist}"
        )
        utils.log_message(
            f"selected_checklist checks: {self.selected_checklist.checks}"
        )
        for head_check in self.selected_checklist.checks:
            head_check: models.ChecklistItemHead
            utils.log_message(
                f"check {head_check.name} description: "
                f"{head_check.check_properties[ChecklistItemPropertyColumn.DESCRIPTION.value]}"
            )
        checklist_checks_model = models.CheckListItemsModel(self.selected_checklist)
        self.checklist_checks_tv.setModel(checklist_checks_model)
        self.checklist_checks_tv.resized.connect(self.force_model_update)
        self.checklist_checks_tv.setTextElideMode(QtCore.Qt.ElideNone)
        self.checklist_checks_tv.setWordWrap(True)
        self.checklist_checks_tv.setAlternatingRowColors(True)
        self.add_automation_widgets()
        header = self.checklist_checks_tv.header()
        header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        delegate = models.ChecklistItemsModelDelegate(self.checklist_checks_tv)
        self.checklist_checks_tv.setItemDelegate(delegate)

    def add_automation_widgets(self):
        model = self.checklist_checks_tv.model()
        for head_row in range(model.rowCount()):
            head_index = model.index(head_row, 0)
            item_head: models.ChecklistItemHead = head_index.internalPointer().ref
            if item_head.automation.algorithm_id is not None:
                automation_index = model.index(
                    ChecklistItemPropertyColumn.AUTOMATION.value, 1, head_index
                )
                automation_widget = AutomationButtonsWidget(
                    checklist_item_head_index=head_index, dataset=self.dataset
                )
                self.checklist_checks_tv.setIndexWidget(
                    automation_index, automation_widget
                )

    def force_model_update(self):
        model = self.checklist_checks_tv.model()
        for row in range(model.rowCount()):
            parent = model.index(row, 0)
            properties = (
                ChecklistItemPropertyColumn.DESCRIPTION.value,
                ChecklistItemPropertyColumn.GUIDE.value,
                ChecklistItemPropertyColumn.VALIDATION_NOTES.value,
            )
            for property_row in properties:
                property_index = model.index(property_row, 1, parent)
                model.dataChanged.emit(property_index, property_index)

    def selected_file_changed(self, raw_path: str):
        utils.log_message(f"selected_file_changed raw_path: {raw_path}")
        if raw_path and self.validate_file_rb.isChecked():
            self.toggle_other_pages(True)
            self.dataset = Path(raw_path).expanduser().resolve()
            self.load_checklist_steps(None, None)
        elif not raw_path and self.validate_file_rb.isChecked():
            self.toggle_other_pages(False)
            self.dataset = None

    def toggle_other_pages(self, enabled: bool):
        self.tab_widget.setTabEnabled(TabPages.VALIDATE.value, enabled)
        self.tab_widget.setTabEnabled(TabPages.REPORT.value, enabled)

    def respond_to_validate_layer_rb_toggled(self, checked: bool):
        if checked:
            self.layer_chooser_lv.setEnabled(True)
            self.file_chooser.setEnabled(False)
            try:
                current_layer_selection: QtCore.QItemSelection = (
                    self.layer_chooser_lv.selectionModel().selection()
                )
            except AttributeError:
                pass
            else:
                self.selected_layer_selection_changed(current_layer_selection, None)
        else:
            self.layer_chooser_lv.setEnabled(False)
            self.file_chooser.setEnabled(True)
            self.selected_file_changed(self.file_chooser.filePath())

    def selected_layer_selection_changed(
        self, selected: QtCore.QItemSelection, deselected: QtCore.QItemSelection
    ):
        if len(selected.indexes()) > 0 and self.validate_layer_rb.isChecked():
            self.toggle_other_pages(True)
            # TODO: check if self.dataset is None
            self.dataset = self._get_current_layer()
        elif len(selected.indexes()) == 0 and self.validate_layer_rb.isChecked():
            self.toggle_other_pages(False)
            self.dataset = None

    def _get_current_layer(self) -> typing.Optional[QgsMapLayer]:
        current_layer_idx = self.layer_chooser_lv.currentIndex()
        utils.log_message(f"current_layer_idx: {current_layer_idx}")
        result = None
        if current_layer_idx != QtCore.QModelIndex():
            layer_model = self.layer_chooser_lv.model()
            layer_id = layer_model.data(
                current_layer_idx, role=LayerChooserDataRole.LAYER_IDENTIFIER.value
            )
            utils.log_message(f"layer_id: {layer_id}")
            layer_model = self.layer_chooser_lv.model()
            project = QgsProject.instance()
            try:
                result = project.mapLayers()[layer_id]
            except KeyError:
                utils.log_message(f"Unable to load layer {layer_id}")
        return result

    def show_checklist_picker(self):
        self.checklist_picker_dlg = ChecklistPicker(self.iface)
        self.checklist_picker_dlg.button_box.accepted.connect(self.load_checklist)
        self.checklist_picker_dlg.setModal(True)
        self.checklist_picker_dlg.show()
        self.checklist_picker_dlg.exec_()

    def load_checklist(self):
        selected_indexes = self.checklist_picker_dlg.checklists_tv.selectedIndexes()
        if any(selected_indexes):
            self.selected_checklist = self.get_selected_checklist(selected_indexes[0])
            log_message(f"the selected checklist is: {self.selected_checklist.name}")
            self.reset_loaded_checklist()
            self.load_checklist_elements(self.selected_checklist)
        else:
            log_message("no checklist was selected")

    def get_selected_checklist(self, index: QtCore.QModelIndex) -> models.CheckList:
        model = index.model()
        identifier_item = model.item(index.row(), ChecklistModelColumn.IDENTIFIER.value)
        result = identifier_item.data(
            role=CustomDataRoles.CHECKLIST_DOWNLOADER_IDENTIFIER.value
        )
        return result

    def load_checklist_elements(self, checklist: models.CheckList):
        self.checklist_name_le.setEnabled(True)
        self.checklist_artifacts_le.setEnabled(True)
        self.checklist_types_le.setEnabled(True)
        self.checklist_description_te.setEnabled(True)
        self.checklist_name_le.setText(checklist.name)
        self.checklist_artifacts_le.setText(checklist.validation_artifact_type.value)
        self.checklist_types_le.setText(checklist.dataset_type.value)
        self.checklist_description_te.setText(checklist.description)

        enable_layer_chooser = False
        enable_file_chooser = False
        if checklist.dataset_type in (DatasetType.VECTOR, DatasetType.RASTER):
            if checklist.validation_artifact_type == ValidationArtifactType.DATASET:
                enable_layer_chooser = True
            elif checklist.validation_artifact_type == ValidationArtifactType.STYLE:
                enable_layer_chooser = True
                enable_file_chooser = True
            else:
                enable_file_chooser = True
        else:
            enable_file_chooser = True
        if enable_file_chooser:
            self.validate_file_rb.setEnabled(True)
            self.validate_file_rb.setChecked(True)
            self.file_chooser.setEnabled(True)
            self.selected_file_changed(self.file_chooser.filePath())
        if enable_layer_chooser:
            self.validate_layer_rb.setEnabled(True)
            self.validate_layer_rb.setChecked(True)
            self.layer_chooser_lv.setEnabled(True)
            model = get_list_view_layers(checklist.dataset_type)
            self.layer_chooser_lv.setModel(model)
            selection_model: QtCore.QItemSelectionModel = (
                self.layer_chooser_lv.selectionModel()
            )
            log_message(f"selection_model: {selection_model}")
            selection_model.currentChanged.connect(self.selected_layer_changed)
            selection_model.selectionChanged.connect(
                self.selected_layer_selection_changed
            )

    def enable_dataset_chooser_elements(
        self,
        dataset_type: DatasetType,
        validation_artifact_type: ValidationArtifactType,
    ):
        enable_layer_chooser = False
        enable_file_chooser = False
        if dataset_type in (DatasetType.VECTOR, DatasetType.RASTER):
            if validation_artifact_type == ValidationArtifactType.DATASET:
                enable_layer_chooser = True
            elif validation_artifact_type == ValidationArtifactType.STYLE:
                enable_layer_chooser = True
                enable_file_chooser = True
            else:
                enable_file_chooser = True
        else:
            enable_file_chooser = True
        if enable_file_chooser:
            self.validate_file_rb.setEnabled(True)
            self.validate_file_rb.setChecked(True)
            self.file_chooser.setEnabled(True)
        if enable_layer_chooser:
            self.validate_layer_rb.setEnabled(True)
            self.validate_layer_rb.setChecked(True)
            self.layer_chooser_lv.setEnabled(True)
            model = get_list_view_layers(dataset_type)
            self.layer_chooser_lv.setModel(model)
            selection_model: QtCore.QItemSelectionModel = (
                self.layer_chooser_lv.selectionModel()
            )
            log_message(f"selection_model: {selection_model}")
            selection_model.currentChanged.connect(self.selected_layer_changed)
            selection_model.selectionChanged.connect(
                self.selected_layer_selection_changed
            )

    def reset_loaded_checklist(self):
        self.tab_widget.setTabEnabled(TabPages.VALIDATE.value, False)
        self.tab_widget.setTabEnabled(TabPages.REPORT.value, False)

        self.checklist_name_le.setEnabled(False)
        self.checklist_artifacts_le.setEnabled(False)
        self.checklist_types_le.setEnabled(False)
        self.checklist_description_te.setEnabled(False)
        self.validate_layer_rb.setEnabled(False)
        self.validate_file_rb.setEnabled(False)
        self.file_chooser.setEnabled(False)
        self.layer_chooser_lv.setEnabled(False)

        self.checklist_name_le.clear()
        self.checklist_artifacts_le.clear()
        self.checklist_types_le.clear()
        self.checklist_description_te.clear()
        self.validate_layer_rb.setChecked(False)
        self.validate_file_rb.setChecked(False)
        # TODO: clear loaded layers list view
        # TODO: clear file chooser

    def closeEvent(self, event: QtGui.QCloseEvent) -> None:
        self.closingPlugin.emit()
        event.accept()

def get_list_view_layers(dataset_type: DatasetType) -> QtGui.QStandardItemModel:
    project = QgsProject.instance()
    result = QtGui.QStandardItemModel()
    for index, (id_, layer) in enumerate(project.mapLayers().items()):
        if utils.match_maplayer_type(layer.type()) == dataset_type:
            item = QtGui.QStandardItem(layer.name())
            item.setData(id_, LayerChooserDataRole.LAYER_IDENTIFIER.value)
            result.appendRow([item])
            log_message(
                f"retrieving layer id from the "
                f"item: {item.data(LayerChooserDataRole.LAYER_IDENTIFIER.value)}"
            )
    return result

def get_legal_layers(dataset_type: models.DatasetType) -> typing.Dict[str, QgsMapLayer]:
    project = QgsProject.instance()
    result = {}
    for id_, layer in project.mapLayers().items():
        if utils.match_maplayer_type(layer.type()) == dataset_type:
            result[id_] = layer
    return result

def get_report_contents(
    checklist_items: models.CheckListItemsModel, dataset: typing.Union[QgsMapLayer, str]
) -> typing.Dict:
    if isinstance(dataset, QgsMapLayer):
        name = dataset.name()
    else:
        name = dataset
    result = {
        "name": "Validation report",
        "validator": utils.get_qgis_variable(
            f"{QGIS_VARIABLE_PREFIX}_validator", "user_full_name"
        ),
        "generated": dt.datetime.now(dt.timezone.utc).isoformat(),
        "dataset": name,
        "dataset_is_valid": checklist_items.result,
        "checklist": checklist_items.checklist.name,
        "dataset_type": checklist_items.checklist.dataset_type.value,
        "artifact_type": checklist_items.checklist.validation_artifact_type.value,
        "description": checklist_items.checklist.description,
        "checks": [],
    }
    for row in range(checklist_items.rowCount()):
        name_idx = checklist_items.index(row, 0)
        node = name_idx.internalPointer()
        checklist_head: models.ChecklistItemHead = node.ref
        description_prop: models.ChecklistItemProperty = (
            checklist_head.check_properties[
                ChecklistItemPropertyColumn.DESCRIPTION.value
            ]
        )
        notes_prop: models.ChecklistItemProperty = checklist_head.check_properties[
            ChecklistItemPropertyColumn.VALIDATION_NOTES.value
        ]
        check = {
            "name": checklist_head.name,
            "validated": True
            if checklist_head.validated == QtCore.Qt.Checked
            else False,
            "description": checklist_head.description,
            "notes": checklist_head.validation_notes,
        }
        result["checks"].append(check)
    return result

def serialize_report(report: typing.Dict) -> str:
    return json.dumps(report, indent=2)

def add_report_to_layer(report: typing.Dict, layer: QgsMapLayer):
    history_msg = (
        f'{report["generated"]} - Validation report: '
        f'{"Valid" if report["dataset_is_valid"] else "Invalid"}'
    )
    abstract_msg = utils.serialize_report_to_plain_text(report)
    metadata: QgsLayerMetadata = layer.metadata()
    history: typing.List = metadata.history()
    history.append(history_msg)
    abstract: str = metadata.abstract()
    abstract = "\n\n---\n\n".join((abstract, abstract_msg))
    metadata.setAbstract(abstract)
    metadata.setHistory(history)
    layer.setMetadata(metadata)

def get_report_path(raw_path: str) -> Path:
    result = Path(raw_path).expanduser().resolve()
    if result.suffix.lower() != ".pdf":
        result = result.parent / f"{result.name}.pdf"
    return result


# Python program to copy or clone a list
# Using the Slice Operator

def Cloning(list1):
    li_copy = list1[:]
    return li_copy

list1 = [4, 8, 2, 10, 15, 18]
li2 = Cloning(list1)
print("Original List:", list1)
print("After Cloning:", li2)


#!/usr/local/bin/python3
__author__ = 'apaeffgen'
# -*- coding: utf-8 -*-

    # This file is part of Panconvert.
    #
    # Panconvert is free software: you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation, either version 3 of the License, or
    # (at your option) any later version.
    #
    # Panconvert is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with Panconvert.  If not, see <http://www.gnu.org/licenses/>.

from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5.QtCore import QSettings
from PyQt5.QtCore import QPoint, QSize
from source.gui.panconvert_dialog_batch import Ui_DialogBatch
from distutils.util import strtobool as str2bool
import platform

global openfiles, batch_open_path

def strtobool(input):
    """
        safe strtobool : if input is a boolean
        it return the input
    """
    if isinstance(input,bool):
        return input
    return str2bool(input)

class BatchDialog(QtWidgets.QDialog):

    def __init__(self, parent=None):

        global batch_open_path, openfile, batch_open_path_output

        QtWidgets.QWidget.__init__(self, parent)
        self.ui = Ui_DialogBatch()
        self.ui.setupUi(self)
        self.ui.ButtonSave.clicked.connect(self.batch_settings)
        self.ui.ButtonCancel.clicked.connect(self.closeEvent)
        self.ui.Button_Open_Path.clicked.connect(self.directory_dialog)
        self.ui.Button_Open_Path_Output.clicked.connect(self.directory_dialog_Output)

        #Initialize Settings
        batch_settings = QSettings('Pandoc', 'PanConvert')
        settings = QSettings('Pandoc', 'PanConvert')

        self.resize(settings.value("Batch_size", QSize(270, 225)))
        self.move(settings.value("Batch_pos", QPoint(50, 50)))

        # Path Settings
        batch_open_path = batch_settings.value('batch_open_path')
        self.ui.OpenPath.insert(batch_open_path)
        batch_open_path_output = batch_settings.value('batch_open_path_output')
        self.ui.OpenPath_Output.insert(batch_open_path_output)

        # Filter Settings
        batch_convert_filter = batch_settings.value('batch_convert_filter')
        self.ui.Filter.insert(batch_convert_filter)

        #Parameter Settings

        parameterBatchconvertDirectory = batch_settings.value('batch_convert_directory', True)
        parameterBatchconvertFiles = batch_settings.value('batch_convert_files', False)
        parameterBatchconvertRecursive = batch_settings.value('batch_convert_recursive', True)

        if batch_settings.value('batch_convert_directory') is not None:
            if platform.system() == 'Darwin':
                self.ui.ParameterBatchconvertDirectory.setChecked(parameterBatchconvertDirectory)
                self.ui.ParameterBatchconvertFiles.setChecked(parameterBatchconvertFiles)
                self.ui.ParameterBatchconvertRecursive.setChecked(parameterBatchconvertRecursive)
            else:
                self.ui.ParameterBatchconvertDirectory.setChecked(strtobool(parameterBatchconvertDirectory))
                self.ui.ParameterBatchconvertFiles.setChecked(strtobool(parameterBatchconvertFiles))
                self.ui.ParameterBatchconvertRecursive.setChecked(strtobool(parameterBatchconvertRecursive))

    def closeEvent(self, event):

        settings = QSettings('Pandoc', 'PanConvert')
        Dialog_Size = settings.value('Dialog_Size')
        if Dialog_Size is True or Dialog_Size == 'true':
            settings.setValue("Batch_size", self.size())
            settings.setValue("Batch_pos", self.pos())

        settings.sync()
        settings.status()
        BatchDialog.close(self)

    def batch_settings(self):
        global batch_open_path, openfiles, batch_open_path_output

        batch_settings = QSettings('Pandoc', 'PanConvert')
        batch_settings.setValue('batch_convert_directory', self.ui.ParameterBatchconvertDirectory.isChecked())
        batch_settings.setValue('batch_convert_files', self.ui.ParameterBatchconvertFiles.isChecked())
        batch_settings.setValue('batch_convert_recursive', self.ui.ParameterBatchconvertRecursive.isChecked())
        batch_settings.setValue('batch_open_path', self.ui.OpenPath.text())
        batch_settings.setValue('batch_open_path_output', self.ui.OpenPath_Output.text())
        batch_settings.setValue('batch_convert_filter', self.ui.Filter.text())
        batch_settings.sync()
        batch_settings.status()

        BatchDialog.close(self)

    def directory_dialog(self):

        global data, openfiles, batch_open_path
        self.ui.OpenPath.clear()

        fd = QtWidgets.QFileDialog(self)

        if batch_open_path == '':
            fd.setDirectory(QtCore.QDir.homePath())
        else:
            fd.setDirectory(batch_open_path)

        batch_directory = fd.getExistingDirectory()
        self.ui.OpenPath.insert(batch_directory)

    def directory_dialog_Output(self):

        global data, openfiles, batch_open_path_output
        self.ui.OpenPath_Output.clear()

        fd = QtWidgets.QFileDialog(self)

        if batch_open_path_output == '':
            fd.setDirectory(QtCore.QDir.homePath())
        else:
            fd.setDirectory(batch_open_path_output)

        batch_directory = fd.getExistingDirectory()
        self.ui.OpenPath_Output.insert(batch_directory)

if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    myapp = BatchDialog()
    myapp.show()
    myapp.exec_()


from linked_list import Node, LinkedList
from blossom_lib import flower_definitions

class HashMap:
    def __init__(self, size):
        self.array_size = size
        self.array = [LinkedList() for i in range(self.array_size)]

    def hash(self, key):
        return sum(key.encode())

    def compress(self, hash_code):
        return hash_code % self.array_size

    def assign(self, key, value):
        hash_code = self.hash(key)
        array_index = self.compress(hash_code)
        payload = Node([key, value])
        list_at_array = self.array[array_index]
        for i in list_at_array:
            if i[0] == key:
                i[1] = value
                return
        list_at_array.insert(payload)

    def retrieve(self, key):
        array_index = self.compress(self.hash(key))
        list_at_array = self.array[array_index]
        for node in list_at_array:
            if node[0] == key:
                return node[1]
            return None

    def get_all_items(self):
        all_items = []
        for linked_list in self.array:
            for node in linked_list:
                all_items.append(node)
        return all_items

blossom = HashMap(len(flower_definitions))

for flower in flower_definitions:
    blossom.assign(flower[0], flower[1])

print(blossom.retrieve('rose'))

all_items = blossom.get_all_items()

print(all_items)

for key, value in all_items:
    print("Key: " + key + " Value: " + value)


import Elliptic03,numpy
#imports essential packages

curve = Elliptic03.Curve("y**2 == x**3-2*x+2", -2, 2) #sets elliptical curve
P = Elliptic03.Point(curve, 1, 1) #sets point of infinite order
n=25 #sets how far we want to calculte height of point
error=0.001 #sets error to determine how much the value stabalizes

def stabalizer(arr):
    for x in range(0,n-1):
        if abs(arr[x+1]-arr[x])<error:
            return (x+1)
# stabalizes function that inputs array and loops through to find the first time values are within a set error

array=[]
Q=P
for x in range(1,n):
    Q+=P
    largest=float(max(abs(Q.xCoord.denominator),abs(Q.xCoord.numerator)))
    value = numpy.log(largest)/((x+1)**2)
    array.append(value)
    #Loops through n times and calculates the height of the Logarithmic height of the elliptical curve, appends to an array
    #print(value)

print("It takes",stabalizer(array),"times before the difference in the logarithmic height of the point is within", error)


import requests
import common_functions as common
from datetime import datetime

def get_request(url):
    user_agent = common.get_rand_user_agent_from_file("assets/useragents.txt")
    try:
        request = requests.get(url, {'user-agent':user_agent})
        if request.status_code is not 200: return
        return request
    except requests.exceptions.HTTPError as err:
        print('HTTP Error occured')
        print('Response is: {content}'.format(content=err.response.content))
    except requests.exceptions.RequestException as err:
        print('HTTP Error occured')
    except Exception as e:
        print(e)

def log_not_parsing(url, message):
    try:
        current_datetime = datetime.today().strftime("%d_%m_%y-%H_%M_%S")
        log_file = open("logs\\logfile_"+current_datetime+".txt", 'w')

        log_file.write(message)
        log_file.write(datetime.today().strftime("%d-%m-%y %H:%M:%S")+' Not parsing url: '+url)
        log_file.write("/n")
        log_file.close()
    except Exception as e:
        print('Log writing error: '+str(e))
        raise SystemExit()


#!/usr/bin/python
# -*- coding: UTF-8 -*-
import amber_actuator as a
import sys, getopt
import json
import datetime

def getFromActuator(actuatorID=1, ipaddr="127.0.0.1"):
    param = []
    j = a.AmberActuator(actuatorID,ipaddr)

    # param = [
    #    j.position.kp,
    #    j.position.ki,
    #    j.position.up_limit,
    #    j.position.down_limit,
    #    j.speed.kp,
    #    j.speed.ki,
    #    j.speed.acceleration,
    #    j.speed.deceleration,
    #    j.speed.speed_limit,
    #    j.current.kp,
    #    j.current.ki,
    #    j.current.current_limit,
    # ]
    dictparam = {
        'Attribute': {
            'ActuatorID': j.actuator_id,
            'Gear': j.attribute.gear,
            'PoleNumber': j.attribute.pole_number,
        },
        'Position': {
            'Kp': j.position.kp,
            'Ki': j.position.ki,
            'UpLimit': j.position.up_limit,
            'DownLimit': j.position.down_limit,
        },
        'Speed': {
            'Kp': j.speed.kp,
            'Ki': j.speed.ki,
            'Acceleration': j.speed.acceleration,
            'Deceleration': j.speed.deceleration,
            'SpeedLimit': j.speed.speed_limit,
        },
        'Current': {
            'Kp': j.current.kp,
            'Ki': j.current.ki,
            'CurrentLimit': j.current.current_limit,
        }
    }
    return dictparam

def main(argv):
    actuatorID = 1
    t = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')

    outputfile = t + '(' + str(actuatorID) + ')' + '.json'
    ipaddr = "127.0.0.1"
    try:
        opts, args = getopt.getopt(argv, "h:j:o:a:", ["actuator=", "ofile=", "ipaddr="])
    except getopt.GetoptError:
        print('backup.py -j <jointID(actuatorID)> -o <outputfile> -a <ipAddress>')
        sys.exit(2)
    for opt, arg in opts:
        if opt == '-h':
            print('backup.py  -j <jointID(actuatorID)> -o <outputfile> -a <ipAddress>')
            sys.exit()
        elif opt in ("-j", "--actuator"):
            actuatorID = arg
            outputfile = t + '-j' + str(actuatorID) + '.json'

        elif opt in ("-o", "--ofile"):
            outputfile = arg
        elif opt in ("-a", "--ipaddr"):
            ipaddr = arg
    dictParam = getFromActuator(actuatorID=int(actuatorID), ipaddr=ipaddr)
    with open(outputfile, 'w', encoding='utf-8') as outfile:
        print(f"Backup Parameter from actuator {actuatorID} to {outputfile}")
        json.dump(dictParam, outfile, indent=4)

if __name__ == "__main__":
    main(sys.argv[1:])


#!/usr/bin/env python

import yaml
import boto3
import click
import logging

import botocore

from boto3.session import Session

logging.basicConfig(level=logging.INFO)

def disable_security_hub():
    logging.warn('This script will disassociate all member accounts and then '
                 'disable security hub completely in all accounts and all '
                 'regions defined in the config file!')
    proceed = click.prompt('Proceed?', type=bool)

    if not proceed:
        logging.info('Not proceeding!')
        return

    config = get_config()
    member_account_ids = get_member_account_ids(config=config)
    disassociate_member_accounts_from_master(
        profile_name=config.get('security_hub_master_profile'),
        account_ids=member_account_ids
    )
    delete_member_accounts_from_master(
        profile_name=config.get('security_hub_master_profile'),
        account_ids=member_account_ids
    )
    profile_names = config.get('security_hub_member_profiles')
    disable_security_hub_in_member_accounts(profile_names=profile_names)

def disable_security_hub_in_member_accounts(profile_names):
    logging.info('Disabling Security Hub in all Member accounts')
    config = get_config()
    for profile_name in profile_names:
        for region_name in config.get('regions'):
            disable_security_hub_in_region(
                profile_name=profile_name,
                region_name=region_name
            )

def get_master_account_session(region_name, profile_name):
    return Session(
        region_name=region_name,
        profile_name=profile_name
    )

def disassociate_member_accounts_from_master(profile_name, account_ids):
    config = get_config()
    for region_name in config.get('regions'):
        session = get_master_account_session(
            region_name=region_name,
            profile_name=profile_name
        )
        security_hub_client = session.client('securityhub')

        logging.info('Disassociating all member accounts from master for '
                     'region %s' % region_name)
        try:
            security_hub_client.disassociate_members(AccountIds=account_ids)
        except botocore.exceptions.ClientError as exception:
            if exception.response['Error']['Code'] == 'UnrecognizedClientException':
                logging.info('Ignoring region %s, probably not enabled' % region_name)

def delete_member_accounts_from_master(profile_name, account_ids):
    config = get_config()
    for region_name in config.get('regions'):
        session = get_master_account_session(
            region_name=region_name,
            profile_name=profile_name
        )
        security_hub_client = session.client('securityhub')

        logging.info('Deleting all member accounts from master for '
                     'region %s' % region_name)
        try:
            security_hub_client.delete_members(AccountIds=account_ids)
        except botocore.exceptions.ClientError as exception:
            if exception.response['Error']['Code'] == 'UnrecognizedClientException':
                logging.info('Ignoring region %s, probably not enabled' % region_name)

def get_member_account_ids(config):
    logging.info('Getting all member account IDs from profiles in config')
    return [
        get_account_id_from_profile(profile_name=profile_name)
        for profile_name in config.get('security_hub_member_profiles')
    ]
def get_account_id_from_profile(profile_name):
    session = Session(
        profile_name=profile_name
    )
    sts_client = session.client('sts')
    response = sts_client.get_caller_identity()
    return response['Account']

def disable_security_hub_in_region(profile_name, region_name):
    logging.info('Disabling SecurityHub for %s in %s '
                 'region' % (profile_name, region_name))
    session = Session(
        region_name=region_name,
        profile_name=profile_name
    )
    security_hub_client = session.client('securityhub')
    try:
        security_hub_client.disable_security_hub()
    except botocore.exceptions.ClientError as exception:
        if exception.response['Error']['Code'] == 'UnrecognizedClientException':
            logging.info('Ignoring region %s, probably not enabled' % region_name)

def get_config():
    with open('config.yml') as yaml_file:
        config = yaml.safe_load(yaml_file)
    return config

if __name__ == '__main__':
    disable_security_hub()


class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        n = len(coins)
        @cache
        def s(n,amt):
            if amt==0: return 1
            if n==0: return 0
            cur = coins[n-1]
            ans = 0
            for cOfCurrentType in range(0,1+(amt//cur)):
                ans+=s(n-1,amt-cOfCurrentType*cur)
            return ans
        return s(n,amount)


import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import numpy as np
import torchvision.models as models
from model.utils.config import cfg
import cv2
import pdb
import random

def save_net(fname, net):
    import h5py
    h5f = h5py.File(fname, mode='w')
    for k, v in net.state_dict().items():
        h5f.create_dataset(k, data=v.cpu().numpy())

def load_net(fname, net):
    import h5py
    h5f = h5py.File(fname, mode='r')
    for k, v in net.state_dict().items():
        param = torch.from_numpy(np.asarray(h5f[k]))
        v.copy_(param)

def weights_normal_init(model, dev=0.01):
    if isinstance(model, list):
        for m in model:
            weights_normal_init(m, dev)
    else:
        for m in model.modules():
            if isinstance(m, nn.Conv2d):
                m.weight.data.normal_(0.0, dev)
            elif isinstance(m, nn.Linear):
                m.weight.data.normal_(0.0, dev)

def clip_gradient(optimizer, clip_norm):
    """Computes a gradient clipping coefficient based on gradient norm."""
    combined_grads = optimizer.get_optimizer_combined_grads()[0]
    total_norm = torch.sqrt(torch.sum(torch.norm(combined_grads.detach()) ** 2)).item()

    norm = (clip_norm / max(total_norm, clip_norm))
    combined_grads.mul_(norm)

def vis_detections(im, class_name, dets, thresh=0.8):
    """Visual debugging of detections."""
    for i in range(np.minimum(10, dets.shape[0])):
        bbox = tuple(int(np.round(x)) for x in dets[i, :4])
        score = dets[i, -1]
        if score > thresh:
            cv2.rectangle(im, bbox[0:2], bbox[2:4], (0, 204, 0), 2)
            cv2.putText(im, '%s: %.3f' % (class_name, score), (bbox[0], bbox[1] + 15), cv2.FONT_HERSHEY_PLAIN,
                        1.0, (0, 0, 255), thickness=1)
    return im

def adjust_learning_rate(optimizer, decay=0.1):
    """Sets the learning rate to the initial LR decayed by 0.5 every 20 epochs"""
    for param_group in optimizer.param_groups:
        param_group['lr'] = decay * param_group['lr']

def save_checkpoint(state, filename):
    torch.save(state, filename)

def _smooth_l1_loss(bbox_pred, bbox_targets, bbox_inside_weights, bbox_outside_weights, sigma=1.0, dim=[1]):

    sigma_2 = sigma ** 2
    box_diff = bbox_pred - bbox_targets
    in_box_diff = bbox_inside_weights * box_diff
    abs_in_box_diff = torch.abs(in_box_diff)
    smoothL1_sign = (abs_in_box_diff < 1. / sigma_2).detach().float()
    in_loss_box = torch.pow(in_box_diff, 2) * (sigma_2 / 2.) * smoothL1_sign \
                  + (abs_in_box_diff - (0.5 / sigma_2)) * (1. - smoothL1_sign)
    out_loss_box = bbox_outside_weights * in_loss_box
    loss_box = out_loss_box
    for i in sorted(dim, reverse=True):
      loss_box = loss_box.sum(i)
    loss_box = loss_box.mean()
    return loss_box

def _crop_pool_layer(bottom, rois, max_pool=True):
    # code modified from
    # https://github.com/ruotianluo/pytorch-faster-rcnn
    # implement it using stn
    # box to affine
    # input (x1,y1,x2,y2)
    """
    [  x2-x1             x1 + x2 - W + 1  ]
    [  -----      0      ---------------  ]
    [  W - 1                  W - 1       ]
    [                                     ]
    [           y2-y1    y1 + y2 - H + 1  ]
    [    0      -----    ---------------  ]
    [           H - 1         H - 1      ]
    """
    rois = rois.detach()
    batch_size = bottom.size(0)
    D = bottom.size(1)
    H = bottom.size(2)
    W = bottom.size(3)
    roi_per_batch = rois.size(0) / batch_size
    x1 = rois[:, 1::4] / 16.0
    y1 = rois[:, 2::4] / 16.0
    x2 = rois[:, 3::4] / 16.0
    y2 = rois[:, 4::4] / 16.0

    height = bottom.size(2)
    width = bottom.size(3)

    # affine theta
    zero = Variable(rois.data.new(rois.size(0), 1).zero_())
    theta = torch.cat([\
      (x2 - x1) / (width - 1),
      zero,
      (x1 + x2 - width + 1) / (width - 1),
      zero,
      (y2 - y1) / (height - 1),
      (y1 + y2 - height + 1) / (height - 1)], 1).view(-1, 2, 3)

    if max_pool:
      pre_pool_size = cfg.POOLING_SIZE * 2
      grid = F.affine_grid(theta, torch.Size((rois.size(0), 1, pre_pool_size, pre_pool_size)))
      bottom = bottom.view(1, batch_size, D, H, W).contiguous().expand(roi_per_batch, batch_size, D, H, W)\
                                                                .contiguous().view(-1, D, H, W)
      crops = F.grid_sample(bottom, grid)
      crops = F.max_pool2d(crops, 2, 2)
    else:
      grid = F.affine_grid(theta, torch.Size((rois.size(0), 1, cfg.POOLING_SIZE, cfg.POOLING_SIZE)))
      bottom = bottom.view(1, batch_size, D, H, W).contiguous().expand(roi_per_batch, batch_size, D, H, W)\
                                                                .contiguous().view(-1, D, H, W)
      crops = F.grid_sample(bottom, grid)

    return crops, grid

def _affine_grid_gen(rois, input_size, grid_size):

    rois = rois.detach()
    x1 = rois[:, 1::4] / 16.0
    y1 = rois[:, 2::4] / 16.0
    x2 = rois[:, 3::4] / 16.0
    y2 = rois[:, 4::4] / 16.0

    height = input_size[0]
    width = input_size[1]

    zero = Variable(rois.data.new(rois.size(0), 1).zero_())
    theta = torch.cat([\
      (x2 - x1) / (width - 1),
      zero,
      (x1 + x2 - width + 1) / (width - 1),
      zero,
      (y2 - y1) / (height - 1),
      (y1 + y2 - height + 1) / (height - 1)], 1).view(-1, 2, 3)

    grid = F.affine_grid(theta, torch.Size((rois.size(0), 1, grid_size, grid_size)))

    return grid

def _affine_theta(rois, input_size):

    rois = rois.detach()
    x1 = rois[:, 1::4] / 16.0
    y1 = rois[:, 2::4] / 16.0
    x2 = rois[:, 3::4] / 16.0
    y2 = rois[:, 4::4] / 16.0

    height = input_size[0]
    width = input_size[1]

    zero = Variable(rois.data.new(rois.size(0), 1).zero_())

    # theta = torch.cat([\
    #   (x2 - x1) / (width - 1),
    #   zero,
    #   (x1 + x2 - width + 1) / (width - 1),
    #   zero,
    #   (y2 - y1) / (height - 1),
    #   (y1 + y2 - height + 1) / (height - 1)], 1).view(-1, 2, 3)

    theta = torch.cat([\
      (y2 - y1) / (height - 1),
      zero,
      (y1 + y2 - height + 1) / (height - 1),
      zero,
      (x2 - x1) / (width - 1),
      (x1 + x2 - width + 1) / (width - 1)], 1).view(-1, 2, 3)

    return theta


import sys

sys.path.append('../')

from RecSys_Course_AT_PoliMi.Pipeline.recommender_tuning import hypertune
from RecSys_Course_AT_PoliMi.Pipeline.data_extraction import get_dataframes
from RecSys_Course_AT_PoliMi.Pipeline.matrices_creation import get_URM_split_val
from RecSys_Course_AT_PoliMi.Recommenders.Neural.MultVAERecommender import MultVAERecommender_OptimizerMask
from RecSys_Course_AT_PoliMi.Pipeline.optuna_utils import Integer, Real, Categorical

item_features_df, train_sessions_df, train_purchases_df, \
test_sessions_df, candidate_items_df = get_dataframes(path_to_dataset='../')

URM_train, URM_val_views, URM_val_purch, mapped_items_to_ignore, mapped_val_sessions_arr, val_session_mapping, item_mapping = get_URM_split_val(
    item_features_df=item_features_df,
    train_purchases_df=train_purchases_df,
    train_sessions_df=train_sessions_df,
    val_start_ts='2021-05-01',
    val_end_ts='2021-06-01',
    unique_interactions=True,
    abs_half_life=None,
    cyclic_decay=False,
    purch_weight=1,
    view_weight=1,
    score_graph=False,
)

hyp = {
    "epochs": Categorical([500]),
    "learning_rate": Real(low=1e-5, high=1e-2, prior="log-uniform"),
    "l2_reg": Real(low=1e-6, high=1e-2, prior="log-uniform"),
    "dropout": Real(low=0., high=0.8, prior="uniform"),
    "total_anneal_steps": Integer(100000, 600000),
    "anneal_cap": Real(low=0., high=0.6, prior="uniform"),
    "batch_size": Categorical([128, 256, 512, 1024]),

    "encoding_size": Integer(1, min(512, 23690)),
    "next_layer_size_multiplier": Integer(2, 10),
    "max_n_hidden_layers": Integer(1, 4),

    # Constrain the model to a maximum number of parameters so that its size does not exceed 7 GB
    # Estimate size by considering each parameter uses float32
    "max_parameters": Categorical([7*1e9*8/32]),
    "validation_every_n": 4,
    "validation_metric": "MRR",
    "lower_validations_allowed": 4
}

best_params = hypertune(
    URM_train=URM_train,
    URM_val_views=URM_val_views,
    URM_val_purch=URM_val_purch,
    item_mapping=item_mapping,
    mapped_items_to_ignore=mapped_items_to_ignore,
    num_trials=300,
    recommender_class=MultVAERecommender_OptimizerMask,
    hyperparameters_dict=hyp
)


from app.model.employee import EmployeeModel
from app.db.configuration import sa
from flask.testing import FlaskClient
from flask import Flask
from typing import Any

class TestEmployeeResourceDelete:

    def test_when_deleted(self, client: FlaskClient, app: Flask, employee_model_data: dict[str, Any]) -> None:
        with app.app_context():
            sa.session.add(EmployeeModel(**employee_model_data))
            sa.session.commit()

        response = client.delete(f"/employees/{employee_model_data['full_name']}")

        assert 200 == response.status_code
        assert b'Deleted employee with id' in response.data

    def test_when_employee_does_not_exist(self, client: FlaskClient) -> None:
        response = client.delete('/employees/Employee')

        assert 400 == response.status_code
        assert b'Employee not found' in response.data


import csv, sqlite3
import sqlalchemy as sa

conn = sqlite3.connect('books.db')
curs = conn.cursor()
curs.execute("DROP TABLE books;")

curs.execute('''CREATE TABLE books
    (title VARCHAR(200) PRIMARY KEY,
     author VARCHAR(80),
     year INT);''')

with open('books2.csv', 'r') as books:
    seperate = csv.DictReader(books)
    to_db = [(i['title'], i['author'], i['year']) for i in seperate]

curs.executemany("INSERT INTO books(title, author, year) VALUES (?,?,?);", to_db)
curs.execute("SELECT * FROM books ORDER BY year DESC;")
mytable = curs.fetchall()
# print ()
# for row in (mytable):
#     print (row)
conn.commit()
conn.close()

eng = sa.create_engine('sqlite:///books.db')
conx = eng.connect()
meta = sa.MetaData()
books = sa.Table('books', meta, autoload_with=eng)

query = sa.select(books.columns.title).order_by(books.columns.title)
results = conx.execute(query)
mytable2 = results.fetchall()

print()
for row in (mytable2):
    print (row)
conx.close()


from config.env import env
from config.settings.base import *  # noqa

# GENERAL
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
SECRET_KEY = env("DJANGO_SECRET_KEY")
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS")

# DATABASES
# ------------------------------------------------------------------------------
DATABASES["default"] = env.db("DATABASE_URL")  # noqa F405
DATABASES["default"]["ATOMIC_REQUESTS"] = True  # noqa F405
DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60)  # noqa F405

# CACHES
# ------------------------------------------------------------------------------
CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.redis.RedisCache",
        "LOCATION": env("REDIS_URL"),
    }
}

# SECURITY
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-ssl-redirect
SECURE_SSL_REDIRECT = env.bool("DJANGO_SECURE_SSL_REDIRECT", default=True)
# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure
SESSION_COOKIE_SECURE = True
# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure
CSRF_COOKIE_SECURE = True
# https://docs.djangoproject.com/en/dev/topics/security/#ssl-https
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-seconds
# TODO: set this to 60 seconds first and then to 518400 once you prove the former works
SECURE_HSTS_SECONDS = 60
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains
SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool(
    "DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True
)
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload
SECURE_HSTS_PRELOAD = env.bool("DJANGO_SECURE_HSTS_PRELOAD", default=True)
# https://docs.djangoproject.com/en/dev/ref/middleware/#x-content-type-options-nosniff
SECURE_CONTENT_TYPE_NOSNIFF = env.bool(
    "DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True
)

# EMAIL
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email
DEFAULT_FROM_EMAIL = env(
    "DJANGO_DEFAULT_FROM_EMAIL",
)
# https://docs.djangoproject.com/en/dev/ref/settings/#server-email
SERVER_EMAIL = env("DJANGO_SERVER_EMAIL")
# https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
EMAIL_SUBJECT_PREFIX = env(
    "DJANGO_EMAIL_SUBJECT_PREFIX",
)

# ADMIN
# ------------------------------------------------------------------------------
# Django Admin URL regex.
ADMIN_URL = env("DJANGO_ADMIN_URL")

# LOGGING
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#logging
# See https://docs.djangoproject.com/en/dev/topics/logging
# for more details on how to customize your logging configuration.
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}},
    "formatters": {
        "verbose": {
            "format": "%(levelname)s %(asctime)s %(module)s "
            + "%(process)d %(thread)d %(message)s"
        }
    },
    "handlers": {
        "mail_admins": {
            "level": "ERROR",
            "filters": ["require_debug_false"],
            "class": "django.utils.log.AdminEmailHandler",
        },
        "console": {
            "level": "DEBUG",
            "class": "logging.StreamHandler",
            "formatter": "verbose",
        },
    },
    "root": {"level": "INFO", "handlers": ["console"]},
    "loggers": {
        "django.request": {
            "handlers": ["mail_admins"],
            "level": "ERROR",
            "propagate": True,
        },
        "django.security.DisallowedHost": {
            "level": "ERROR",
            "handlers": ["console", "mail_admins"],
            "propagate": True,
        },
    },
}


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

# Python program to compute and visualize the
# histogram of Blue channel of image

# importing libraries
import sys, time, os, datetime, glob
import cv2
import argparse
import numpy as np
from matplotlib import pyplot as plt

from platform import python_version

print(f"(Sys version) :|: {sys.version} :|:")
os.system("which python")
print(f"(Python version) :#: {python_version()} :#:")

# reading the input image
img = cv2.imread('mountain.png')
#img = cv2.imread('dark_tones.jpg')

img_blue = img[:,:,2]
img_green = img[:,:,1]
img_red = img[:,:,0]

# split the image into its BGR components
(B, G, R) = cv2.split(img)
# find the maximum pixel intensity values for each
# (x, y)-coordinate,, then set all pixel values less
# than M to zero
M = np.maximum(np.maximum(R, G), B)

print(B.min(),B.max())
print(G.min(),G.max())
print(R.min(),R.max())

print(M.min(),M.max())

R[R < M] = 0
G[G < M] = 0
B[B < M] = 0

# print(R)
# print(G)
# print(B)
# merge the channels back together and return the image
mergeimg=cv2.merge([B, G, R])

# print(max(img_blue))
# print(min(img_blue))
# print(max(img_green))
# print(min(img_green))
# print(max(img_red))
# print(min(img_red))

# plot the above computed histogram
plt.imshow(mergeimg)
plt.title('Image Histogram For Blue Channel GFG')
plt.show()

# computing the histogram of the blue channel of the image
hist = cv2.calcHist([img],[0],None,[256],[0,256])

print(hist.min(),hist.max())

# np.savetxt(time.strftime("%Y%m%d_%H%M%S")+"_Blue.csv", np.vstack((hist)).T, delimiter=', ')
# np.savetxt(time.strftime("%Y%m%d_%H%M%S")+"_Blue.csv", np.vstack((hist)), delimiter=', ')
np.savetxt("mountain_Blue.csv", np.vstack((hist)), delimiter=', ')

# plot the above computed histogram
plt.plot(hist, color='b')
plt.title('Image Histogram For Blue Channel GFG')
plt.show()

# reading the input image
img = cv2.imread('mountain.png')
#img = cv2.imread('dark_tones.jpg')

# computing the histogram of the green channel of the image
hist = cv2.calcHist([img],[1],None,[256],[0,256])

# plot the above computed histogram
plt.plot(hist, color='g')
plt.title('Image Histogram For Green Channel GFG')
plt.show()

# reading the input image
img = cv2.imread('mountain.png')
#img = cv2.imread('dark_tones.jpg')

# computing the histogram of the Red channel of the image
hist = cv2.calcHist([img],[2],None,[256],[0,256])

# plot the above computed histogram
plt.plot(hist, color='r')
plt.title('Image Histogram For Red Channel GFG')
plt.show()

# reading the input image
img = cv2.imread('mountain.png')
#img = cv2.imread('dark_tones.jpg')

# define colors to plot the histograms
colors = ('b','g','r')

# compute and plot the image histograms
for i,color in enumerate(colors):
	hist = cv2.calcHist([img],[i],None,[256],[0,256]) # bit depth to 8-bit "BIT DEPTH"
	plt.plot(hist,color = color) # bit depth to 8-bit "BIT DEPTH"
plt.title('Image Histogram GFG')
plt.show()

print(type(img))
print(img.shape)
print(type(img.shape))

h, w, c = img.shape
print('width:  ', w)
print('height: ', h)
print('channel:', c)

h, w, _ = img.shape
print('width: ', w)
print('height:', h)

print('width: ', img.shape[1])
print('height:', img.shape[0])

print(img.shape[1::-1])

print(len(hist))
print(len(color))

image = cv2.imread('dark_tones.jpg')

gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

histogram = cv2.calcHist([gray_image], [0], None, [256], [0, 256])
plt.plot(histogram, color='k')
plt.show()

image = cv2.imread('dark_tones.jpg')

for i, col in enumerate(['b', 'g', 'r']):
    hist = cv2.calcHist([image], [i], None, [256], [0, 256])
    plt.plot(hist, color = col)
    plt.xlim([0, 256])

plt.show()

w=cv2.imread('mountain.png',1)
cv2.imshow('image',w)
b,g,r = cv2.split(w)
height = np.size(w, 0)
width = np.size(w, 1)
bw = np.zeros((height,width))

# for i in range(1,height):
#     for j in range(1,width):
#         if(b[i,j]<g[i,j] and r[i,j]<g[i,j] and g[i,j]>125):
#             bw[i,j]=1
# cv2.imshow('Black and White image',bw)
# kernel = np.ones((5,5),np.uint8)
# bw= cv2.erode(bw,kernel,iterations = 4)
# cv2.imshow('Eroded image',bw)
# bw = cv2.dilate(bw,kernel,iterations = 3)
# cv2.imshow('Final Image',bw)
# cv2.waitKey(0)
# cv2.destroyAllWindows()


#!/usr/bin/python3

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from typing import List, Tuple
import config as CONF
import sys

"""
Reads datapts from the file data.pts and plots them in an interactive 3D plot.
"""

def read_datapts(file="data.pts"):
    with open(file, 'r') as f:
        lines = f.readlines()
        n = len(lines)
        x = np.ndarray(n)
        y = np.ndarray(n)
        z = np.ndarray(n)
        for n, line in enumerate(lines):
            x[n], y[n], z[n] = line.strip().split("\t")
    return (x, y, z)

if __name__ == "__main__":
    data_x, data_y, data_z = read_datapts("data.pts")

    fig = plt.figure(figsize=(12, 8))
    ax = fig.add_subplot(111, projection='3d')
    ax.scatter(data_x, data_y, data_z, label="datapoints",
               marker=',', s=1) #,
               #linewidths=0.1, edgecolors='b')

    # plot corners of test domain
    domain_x = [0,  CONF.Lx, CONF.Lx,        0, 0]
    domain_y = [0,        0, CONF.Ly,  CONF.Ly, 0]
    domain_z = [0,        0,       0,        0, 0]
    ax.plot3D(domain_x, domain_y, domain_z, c='red')
    domain_x = [0, CONF.Lx, CONF.Lx,       0,       0]
    domain_y = [0,       0, CONF.Ly, CONF.Ly,       0]
    domain_z = [CONF.Lz, CONF.Lz, CONF.Lz, CONF.Lz, CONF.Lz]
    ax.plot3D(domain_x, domain_y, domain_z, c='red', label="domain bounds")

    ax.set_xlim((-CONF.Lx/2, CONF.Lx*3/2))
    ax.set_ylim((-CONF.Ly/4, CONF.Ly*3/4))
    ax.set_zlim((0, CONF.Lz*2))
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    ax.legend()

    fig.tight_layout()

    if len(sys.argv) > 1:
        plt.suptitle(" ".join([str(arg) for arg in sys.argv[1:]]))
    else:
        print("You may add a suptitle by passing arguments.")
    plt.show()


import glob
import os.path
from shutil import copyfile

packer_folde = "/home/hungpt/Downloads/dataset-packed-pe-master/packed/TELock"
original_telock_folder = "/home/hungpt/Desktop/original_for_telock"
non_packed_folder = "/home/hungpt/Downloads/dataset-packed-pe-master/not-packed"

list_files = glob.glob(packer_folde + "/*.exe")

for file in list_files:
    # print(file)
    original_name_file = os.path.basename(file)[7:]
    # print(original_name_file)
    src = os.path.join(non_packed_folder, original_name_file)
    if not os.path.exists(src):
        continue
    path = "timeout 60m java -jar Main.jar asm/testcase/{}".format(original_name_file)
    print(path)
    # dst = os.path.join(original_telock_folder, original_name_file)
    # copyfile(src, dst)


import threading, requests

class MyThread(threading.Thread):
    def __init__(self, data=None):
        threading.Thread.__init__(self)
        self.add = data

    # 重写run()方法
    def run(self):
        for arc in self.add["data"]:
            # 调用 getName() 方法获取当前执行该程序的线程名
            # print(threading.current_thread().getName() + " " + str(arc))
            self.add_gift(uid=self.add["uid"], prop_id=arc[0], pricing_id=arc[1], nums=self.add["nums"],
                          business=self.add["business"])

    def add_gift(self, uid, prop_id, pricing_id, nums, business):
        print(
            "uid:{}, prop_id:{}, pricing_id:{}, nums:{}, business:{}".format(uid, prop_id, pricing_id, nums, business))
        url = "http://turnover-bg-test.yy.com/props/addProps/" + str(business)
        data = {
            "propId": prop_id,
            "pricingId": pricing_id,
            "uid": str(uid),
            "nums": nums,
            "countryCode": "cn"
        }
        response = requests.get(url=url, params=data)
        print("response.url:{}".format(response.url))
        print("response.text:{}".format(response.text))

    def use_threading(self, data):
        mythread = MyThread(data)
        # 启动子线程
        mythread.start()
        # 主线程执行此循环
        for i in range(len(data["data"])):
            print("主线程执行此循环:threading.current_thread().getName():{}".format(threading.current_thread().getName()))


def is_prime(num):
    flag = True
    for i in range(2, int(num/2)):
        if num % i == 0:
            flag = False
            break

    if flag:
        print(f"{num} - is a Prime Number")
    else:
        print(f"{num} - is Not a Prime Number")

if __name__=='__main__':
    # num = int(input("Enter a number: "))
    # is_prime(num)
    l2 = list(range(1,11))
    l = list((1,2,3,4,5,"Guru",7,8,9))
    print(l)
    l.reverse()
    print(l)
    x = l[::-1]
    print(x)


# https://realpython.com/pipenv-guide/#pipenv-introduction
# 1. Install virtual environment if not installed
# pip install pipenv
# 2. Switch to virtual environment
# pipenv shell
# 3. Install pytest if not installed
# pipenv install pytest
# 4. Run test
# pytest -v
#       - only works when test file start with test_ or end with _test
#         Report in verbose mode
# pytest -q
#       - Run in quiet mode (can be helpful when running hundreds or thousands of tests at once).
# pytest -s
#       - Don't capture console output (show print statements on the console).
# pytest --ignore
#       - Ignore the specified path when discovering tests.
# pytest --maxfail
#       - Stop after the specified number of failures.
# pytest "testname"
#       - specifies the module name to run only the tests in that module
# DirectoryName/
#       - runs any tests found in the specified directory
# -k "expression"
#       - matches tests found that match the evaluatable expression in the string.
#         The string values can include module, class and function names
#         (i.e. "TestClass and TestFunction").
# -m "expression"
#       - matches tests found that have a "pytest.mark" decorator that matches the
#       specified expression.
# 5. Deactivate virtual environment
# deactivate
# exit
# 6. Show dependency graph
# pipenv graph
import os
import pytest
from pytest import raises
from unittest.mock import MagicMock
from Checkout import Checkout

lineCnt = 0

@pytest.fixture()
def checkout():
    checkout = Checkout()
    checkout.addItemPrice("a", 1)
    checkout.addItemPrice("b", 2)
    return checkout

def test_canCalculateTotal(checkout):
    checkout.addItem("a")
    assert checkout.calculateTotal() == 1

def test_getCorrectTotalWithMultipleItems(checkout):
    checkout.addItem("a")
    checkout.addItem("b")
    assert checkout.calculateTotal() == 3

def test_canAddDiscountRule(checkout):
    checkout.addDiscount("a", 3, 2)

def test_canApplyDiscountRule(checkout):
    checkout.addDiscount("a", 3, 2)
    checkout.addItem("a")
    checkout.addItem("a")
    checkout.addItem("a")
    assert checkout.calculateTotal() == 2

def test_exceptionWithBadItem(checkout):
    with pytest.raises(Exception):
        checkout.addItem("c")

def test_verifyReadPricesFile(checkout, monkeypatch):
    mock_file = MagicMock()
    mock_file.__enter__.return_value.__iter__.return_value = ["c 3"]
    mock_open = MagicMock(return_value = mock_file)
    monkeypatch.setattr("builtins.open", mock_open)
    mock_exists = MagicMock(return_value=True)
    monkeypatch.setattr("os.path.exists", mock_exists)
    checkout.readPricesFile("testfile")
    checkout.addItem("c")
    result = checkout.calculateTotal()
    mock_open.assert_called_once_with("testfile")
    assert result == 3

def test_verifyReadFileException(checkout, monkeypatch):
    mock_file = MagicMock()
    mock_file.__enter__.return_value.__iter__.return_value = ["c 3"]
    mock_open = MagicMock(return_value=mock_file)
    monkeypatch.setattr("builtins.open", mock_open)
    mock_exists = MagicMock(return_value=False)
    monkeypatch.setattr("os.path.exists", mock_exists)
    with raises(Exception):
        checkout.readPricesFile("testfile")