import os

import pyaedt

class Component:
    """Component extracted from ibis model."""

    def __init__(self):
        self._name = None
        self._manufacturer = None
        self._pins = {}

    @property
    def name(self):
        """Name of the component.

        Examples
        --------
        >>> ibis = ibis_reader.IbisReader(os.path.join(path_to_ibis_files, "u26a_800_modified.ibs"), circuit)
        >>> ibis.components["MT47H64M4BP-3_25"].name
        'MT47H64M4BP-3_25'

        """

        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @property
    def manufacturer(self):
        """Manufacturer of the component.

        Examples
        --------
        >>> ibis = ibis_reader.IbisReader(os.path.join(path_to_ibis_files, "u26a_800_modified.ibs"), circuit)
        >>> ibis.components["MT47H64M4BP-3_25"].manufacturer
        'Micron Technology, Inc.'

        """

        return self._manufacturer

    @manufacturer.setter
    def manufacturer(self, value):
        self._manufacturer = value

    @property
    def pins(self):
        """Pins of the component.

        Examples
        --------
        >>> ibis = ibis_reader.IbisReader(os.path.join(path_to_ibis_files, "u26a_800_modified.ibs"), circuit)
        >>> pins = ibis.components["MT47H64M4BP-3_25"].pins

        """

        return self._pins

    @pins.setter
    def pins(self, value):
        self._pins = value

class Pin(Component):
    """Pin from a component with all its data feature.

    Parameters
    ----------
    name : str
        Name of the pin.
    circuit : class:`pyaedt.circuit.Circuit`
        Circuit in which the pin will be added to.
    """

    def __init__(self, name, circuit):
        self._name = name
        self._circuit = circuit
        self._short_name = None
        self._signal = None
        self._model = None
        self._r_value = None
        self._l_value = None
        self._c_value = None

    @property
    def name(self):
        """Full name of the pin including the component name and the ibis filename.

        Examples
        --------
        >>> ibis = ibis_reader.IbisReader(os.path.join(path_to_ibis_files, "u26a_800_modified.ibs"), circuit)
        >>> ibis.components["MT47H64M4BP-3_25"].pins["A1_MT47H64M4BP-3_25_u26a_800"].name
        'A1_MT47H64M4BP-3_25_u26a_800'

        """
        return self._name

    @property
    def short_name(self):
        """Name of the pin without the name of the component.

        Examples
        --------
        >>> ibis = ibis_reader.IbisReader(os.path.join(path_to_ibis_files, "u26a_800_modified.ibs"), circuit)
        >>> ibis.components["MT47H64M4BP-3_25"].pins["A1_MT47H64M4BP-3_25_u26a_800"].short_name
        'A1'

        """
        return self._short_name

    @short_name.setter
    def short_name(self, value):
        self._short_name = value

    @property
    def signal(self):
        """Signal of the pin.

        Examples
        --------
        >>> ibis = ibis_reader.IbisReader(os.path.join(path_to_ibis_files, "u26a_800_modified.ibs"), circuit)
        >>> ibis.components["MT47H64M4BP-3_25"].pins["A1_MT47H64M4BP-3_25_u26a_800"].signal
        'VDD'

        """
        return self._signal

    @signal.setter
    def signal(self, value):
        self._signal = value

    @property
    def model(self):
        """Model of the pin.

        Examples
        --------
        >>> ibis = ibis_reader.IbisReader(os.path.join(path_to_ibis_files, "u26a_800_modified.ibs"), circuit)
        >>> ibis.components["MT47H64M4BP-3_25"].pins["A1_MT47H64M4BP-3_25_u26a_800"].signal
        'POWER'

        """
        return self._model

    @model.setter
    def model(self, value):
        self._model = value

    @property
    def r_value(self):
        """Resitance value in ohms.

        Examples
        --------
        >>> ibis = ibis_reader.IbisReader(os.path.join(path_to_ibis_files, "u26a_800_modified.ibs"), circuit)
        >>> ibis.components["MT47H64M4BP-3_25"].pins["A1_MT47H64M4BP-3_25_u26a_800"].r_value
        '44.3m'

        """

        return self._r_value

    @r_value.setter
    def r_value(self, value):
        self._r_value = value

    @property
    def l_value(self):
        """Inductance value in H.

        Examples
        --------
        >>> ibis = ibis_reader.IbisReader(os.path.join(path_to_ibis_files, "u26a_800_modified.ibs"), circuit)
        >>> ibis.components["MT47H64M4BP-3_25"].pins["A1_MT47H64M4BP-3_25_u26a_800"].l_value
        '1.99nH'

        """
        return self._l_value

    @l_value.setter
    def l_value(self, value):
        self._l_value = value

    @property
    def c_value(self):
        """Capacitance value in F.

        Examples
        --------
        >>> ibis = ibis_reader.IbisReader(os.path.join(path_to_ibis_files, "u26a_800_modified.ibs"), circuit)
        >>> ibis.components["MT47H64M4BP-3_25"].pins["A1_MT47H64M4BP-3_25_u26a_800"].c_value
        '0.59pF'

        """
        return self._c_value

    @c_value.setter
    def c_value(self, value):
        self._c_value = value

    def add(self):
        """Add a pin to the list of components in the Project Manager."""
        self._circuit.modeler.schematic.o_component_manager.AddSolverOnDemandModel(
            self.name,
            [
                "NAME:CosimDefinition",
                "CosimulatorType:=",
                7,
                "CosimDefName:=",
                "DefaultIBISNetlist",
                "IsDefinition:=",
                True,
                "Connect:=",
                True,
                "Data:=",
                [],
                "GRef:=",
                [],
            ],
        )

    def insert(self, x, y, angle=0.0):
        """Insert a pin at a defined location inside the graphical window.

        Parameters
        ----------
        x : float
            X position of the pin.
        y : float
            Y position of the pin.
        angle : float, optional
            Angle of the pin. The default value is ``"0.0"``.

        Returns
        -------
        :class:`pyaedt.modeler.Object3d.CircuitComponent`
            Circuit Component Object.

        """

        return self._circuit.modeler.schematic.create_component(
            component_library=None,
            component_name=self.name,
            location=[x, y],
            angle=angle,
        )

class Buffer:
    def __init__(self, ibis_name, short_name, circuit):
        self._ibis_name = ibis_name
        self._short_name = short_name
        self._circuit = circuit

    @property
    def name(self):
        """Full name of the buffer including the ibis filename."""
        return "{}_{}".format(self.short_name, self._ibis_name)

    @property
    def short_name(self):
        """Short name of the buffer without the ibis filename included."""
        return self._short_name

    def add(self):
        """Add a buffer to the list of components in the Project Manager."""
        self._circuit.modeler.schematic.o_component_manager.AddSolverOnDemandModel(
            self.name,
            [
                "NAME:CosimDefinition",
                "CosimulatorType:=",
                7,
                "CosimDefName:=",
                "DefaultIBISNetlist",
                "IsDefinition:=",
                True,
                "Connect:=",
                True,
                "Data:=",
                [],
                "GRef:=",
                [],
            ],
        )

    def insert(self, x, y, angle=0.0):
        """Insert a buffer at a defined location inside the graphical window.

        Parameters
        ----------
        x : float
            X position of the buffer.
        y : float
            Y position of the buffer.
        angle : float, optional
            Angle of the buffer. The default value is ``"0.0"``.

        Returns
        -------
        :class:`pyaedt.modeler.Object3d.CircuitComponent`
            Circuit Component Object.

        """

        return self._circuit.modeler.schematic.create_component(
            component_library=None,
            component_name=self.name,
            location=[x, y],
            angle=angle,
        )

class ModelSelector:
    def __init__(self):
        self._model_selector_items = []
        self._name = None

    @property
    def model_selector_items(self):
        """Model selector items."""
        return self._model_selector_items

    @model_selector_items.setter
    def model_selector_items(self, value):
        self._model_selector_items = value

    @property
    def name(self):
        """Name of the model selector."""
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

class ModelSelectorItem:
    def __init__(self):
        self._description = []
        self._name = None

    @property
    def description(self):
        """Description of the item."""
        return self._description

    @description.setter
    def description(self, value):
        self._description = value

    @property
    def name(self):
        """Name of the item."""
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

class Model:
    def __init__(self):
        self._description = []
        self._name = None
        self._clamp = None
        self._enable = None

    @property
    def name(self):
        """Name of the item."""
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @property
    def model_type(self):
        """Type of the model."""
        return self._model_type

    @model_type.setter
    def model_type(self, value):
        self._model_type = value

    @property
    def clamp(self):
        """Clamp."""
        return self._clamp

    @clamp.setter
    def clamp(self, value):
        self._clamp = value

    @property
    def enable(self):
        """Is model enabled or not."""
        return self._enable

    @enable.setter
    def enable(self, value):
        self._enable = value

class Ibis:
    """Ibis model with all data extracted: name, components, models.

    Parameters
    ----------
    name : str
        Name of ibis model.
    circuit : class:`pyaedt.circuit.Circuit`
        Circuit in which the ibis components will be used.
    """

    # Ibis reader must work independently or in Circuit.
    def __init__(self, name, circuit):
        self.circuit = circuit
        self._name = name
        self._components = {}
        self._model_selectors = []
        self._models = []

    @property
    def name(self):
        """Name of the ibis model."""
        return self._name

    @property
    def components(self):
        """List of all components included in the ibis file."""
        return self._components

    @components.setter
    def components(self, value):
        self._components = value

    @property
    def model_selectors(self):
        """List of all model selectors included in the ibis file."""
        return self._model_selectors

    @model_selectors.setter
    def model_selectors(self, value):
        self._model_selectors = value

    @property
    def models(self):
        """List of all models included in the ibis file."""
        return self._models

    @models.setter
    def models(self, value):
        self._models = value

    @property
    def buffers(self):
        """Buffers included into the ibis model."""
        return self._buffers

    @buffers.setter
    def buffers(self, value):
        self._buffers = value

class IbisReader(object):
    """Reads *.ibis file content.
    Setup an Ibis object exposing all the extracted data.

    Parameters
    ----------
    filename : str
        Name of ibis model.
    circuit : class:`pyaedt.circuit.Circuit`
        Circuit in which the ibis components will be used.
    """

    def __init__(self, filename, circuit):
        self._filename = filename
        self._circuit = circuit
        self._ibis_model = None

    @property
    def ibis_model(self):
        "Ibis model gathering the entire set of data extracted from the *.ibis file."
        return self._ibis_model

    def parse_ibis_file(self):
        """Reads *.ibis file content.

        Parameters
        ----------
        filename : str
            Name of ibis model.
        circuit : class:`pyaedt.circuit.Circuit`
            Circuit in which the ibis components will be used.

        Returns
        ----------
        :class:`pyaedt.generic.ibis_reader.Ibis`
            Ibis object exposing all data from the ibis file.

        Examples
        --------
        Read u26a_800.ibs file provided in the AEDT suit installation.
        >>> import os
        >>> from pyaedt import Desktop
        >>> from pyaedt.circuit import Circuit
        >>> from pyaedt.generic import ibis_reader
        >>> desktop = Desktop()
        >>> circuit = Circuit()
        >>> ibis = ibis_reader.IbisReader(os.path.join(desktop.install_path, "buflib", "IBIS", "u26a_800.ibs"), circuit)

        """

        if not os.path.exists(self._filename):
            raise Exception("{} does not exist.".format(self._filename))

        ibis_name = pyaedt.generic.general_methods.get_filename_without_extension(self._filename)
        ibis = Ibis(ibis_name, self._circuit)

        # Read *.ibis file.
        with open(self._filename, "r") as ibis_file:
            while True:
                current_line = ibis_file.readline()
                if not current_line:
                    break

                if is_started_with(current_line, "[Component] "):
                    self.read_component(ibis, current_line, ibis_file)
                elif is_started_with(current_line, "[Model] "):
                    self.read_model(ibis, current_line, ibis_file)
                elif is_started_with(current_line, "[Model Selector] "):
                    self.read_model_selector(ibis, current_line, ibis_file)

        buffers = {}
        for model_selector in ibis.model_selectors:
            buffer = Buffer(ibis_name, model_selector.name, self._circuit)
            buffers[buffer.name] = buffer

        for model in ibis.models:
            buffer = Buffer(ibis_name, model.name, self._circuit)
            buffers[buffer.name] = buffer

        ibis.buffers = buffers

        if self._circuit:
            args = [
                "NAME:Options",
                "Mode:=",
                4,
                "Overwrite:=",
                False,
                "SupportsSimModels:=",
                False,
                "LoadOnly:=",
                False,
            ]
            arg_buffers = ["NAME:Buffers"]
            for buffer in buffers:
                arg_buffers.append("{}:=".format(buffers[buffer].short_name))
                arg_buffers.append([True, "IbisSingleEnded"])
            model_names = [i.name for i in ibis.models]
            arg_components = ["NAME:Components"]
            for component in ibis.components:
                arg_component = ["NAME:{}".format(ibis.components[component].name)]
                for pin in ibis.components[component].pins:
                    arg_component.append("{}:=".format(ibis.components[component].pins[pin].short_name))
                    if ibis.components[component].pins[pin].model not in model_names:
                        arg_component.append([False, False])
                    else:
                        arg_component.append([True, False])
                arg_components.append(arg_component)

            args.append(arg_buffers)
            args.append(arg_components)

            self._circuit.modeler.schematic.o_component_manager.ImportModelsFromFile(self._filename, args)

        self._ibis_model = ibis

    # Model
    def read_model(self, ibis, current_line, ibis_file):
        """Extracts model's info.

        Parameters
        ----------
        ibis : :class:`pyaedt.generic.ibis_reader.Ibis`
            ibis object containing all info.
        current_line : str
            Current line content.
        ibis_file : TextIO
            File's stream.

        """

        if not is_started_with(current_line, "[Model] "):
            return

        model = Model()
        model.name = current_line.split("]")[1].strip()
        current_line = ibis_file.readline().replace("\t", "").strip()

        while not is_started_with(current_line, "Model_type"):
            current_line = ibis_file.readline().replace("\t", "").strip()

        iStart = current_line.index(" ", 1)

        if iStart > 0:
            model.ModelType = current_line[iStart:].strip()

        # Clamp
        while not current_line:
            current_line = ibis_file.readline().strip.replace("clamp", "Clamp")

            if is_started_with(current_line, "[GND Clamp]"):
                model.Clamp = True
                break
            elif is_started_with(current_line, "[GND_Clamp]"):
                model.Clamp = True
                break
            elif is_started_with(current_line, "Enable ", True):
                model.Enable = current_line[len("Enable") + 1 :].strip()
            elif is_started_with(current_line, "[Rising Waveform]"):
                break
            elif is_started_with(current_line, "[Ramp]"):
                break

        ibis.models.append(model)

    # Model Selector
    def read_model_selector(self, ibis, current_line, ibis_file):
        """Extracts model selector's info.

        Parameters
        ----------
        ibis : :class:`pyaedt.generic.ibis_reader.Ibis`
            ibis object containing all info.
        current_line : str
            Current line content.
        ibis_file : TextIO
            File's stream.

        """

        if not is_started_with(current_line, "[Model Selector] "):
            return

        model_selector = ModelSelector()
        model_selector.model_selector_items = []
        model_selector.name = current_line.split("]")[1].strip()

        current_line = ibis_file.readline()

        # Model Selector
        while not is_started_with(current_line, "|") and current_line.strip() != "":
            model_selector.model_selector_items.append(self.make_model(current_line.strip()))
            current_line = ibis_file.readline()

        # ModelSelectorItem
        ibis.model_selectors.append(model_selector)

    @classmethod
    def make_model(cls, current_line):
        """Creates model object.

        Parameters
        ----------
        current_line : str
            Current line content.

        Returns
        -------
        :class:`pyaedt.generic.ibis_reader.ModelSelectorItem`
            Model selector item.

        """

        item = ModelSelectorItem()
        i_start = current_line.index(" ", 1)

        if i_start > 0:
            item.name = current_line[i_start:].strip()
            item.description = current_line[i_start:].strip()

        return item

    # Component
    def read_component(self, ibis, current_line, ibis_file):
        """Extracts component's info.

        Parameters
        ----------
        ibis : :class:`pyaedt.generic.ibis_reader.Ibis`
            ibis object containing all info.
        current_line : str
            Current line content.
        ibis_file : TextIO
            File's stream.

        """

        if not is_started_with(current_line, "[Component] "):
            return

        component = Component()
        component.name = self.get_component_name(current_line)
        current_line = ibis_file.readline()

        if is_started_with(current_line, "[Manufacturer]"):
            component.manufacturer = current_line.replace("[Manufacturer]", "").strip()

        while True:
            current_line = ibis_file.readline()
            if is_started_with(current_line, "[Package]"):
                break

        self.fill_package_info(component, current_line, ibis_file)

        # [pin]
        while not is_started_with(current_line, "[Pin] "):
            current_line = ibis_file.readline()

        while True:
            current_line = ibis_file.readline()
            if is_started_with(current_line, "|"):
                break

        current_line = ibis_file.readline()

        while not is_started_with(current_line, "|"):
            pin = self.make_pin_object(current_line, component.name, ibis)
            component.pins[pin.name] = pin
            current_line = ibis_file.readline()
            if current_line == "":
                break

        ibis.components[component.name] = component

    @classmethod
    def fill_package_info(cls, component, current_line, ibis_file):
        """Extracts model's info.

        Parameters
        ----------
        component : :class:`pyaedt.generic.ibis_reader.Component`
            Current line content.
        current_line : str
            Current line content.
        ibis_file : TextIO
            File's stream.

        """
        while is_started_with(current_line, "|") or is_started_with(current_line, "["):
            current_line = ibis_file.readline()

        if is_started_with(current_line, "R_pkg"):
            component.R_pkg = current_line.strip()
            current_line = ibis_file.readline()
        elif is_started_with(current_line, "L_pkg"):
            component.L_pkg = current_line.strip()
            current_line = ibis_file.readline()
        elif is_started_with(current_line, "C_pkg"):
            component.C_pkg = current_line.strip()

    @classmethod
    def get_component_name(cls, line):
        """Gets the name of the component.

        Parameters
        ----------
        line : str
            Current line content.

        Returns
        -------
        str
            Name of the component.

        """
        return line.replace("[Component]", "").strip()

    # Pin
    def make_pin_object(self, line, component_name, ibis):
        """Extracts model's info.

        Parameters
        ----------
        line : str
            Current line content.
        component_name : str
            Name of the component.
        ibis : :class:`pyaedt.generic.ibis_reader.Ibis`
            ibis object containing all info.

        Returns
        -------
        :class:`pyaedt.generic.ibis_reader.Pin`
            Pin object.

        """

        current_string = ""

        current_string = line.strip().replace("\t", " ")
        pin_name = self.get_first_parameter(current_string)
        pin = Pin(pin_name + "_" + component_name + "_" + ibis.name, ibis.circuit)
        pin.short_name = pin_name
        current_string = current_string[len(pin.short_name) + 1 :].strip()
        pin.signal = self.get_first_parameter(current_string)

        current_string = current_string[len(pin.signal) + 1 :].strip()
        pin.model = self.get_first_parameter(current_string)

        current_string = current_string[len(pin.model) + 1 :].strip()
        pin.r_value = self.get_first_parameter(current_string)

        current_string = current_string[len(pin.r_value) + 1 :].strip()
        pin.l_value = self.get_first_parameter(current_string)

        current_string = current_string[len(pin.l_value) + 1 :].strip()
        pin.c_value = self.get_first_parameter(current_string)

        return pin

    @classmethod
    def get_first_parameter(cls, line):
        """Gets first parameter string value.

        Parameters
        ----------
        line : str
            Current line content.

        Returns
        -------
        str
            First info extracted from the current line.

        """

        if line == "":
            return ""

        data = line.split(" ")
        return data[0].strip()

def is_started_with(src, find, ignore_case=True):
    """Verifies if a string content starts with a specific string or not.

    This is identical to ``str.startswith``, except that it includes
    the ``ignore_case`` parameter.

    Parameters
    ----------
    src : str
        Current line content.
    find : str
        Current line content.
    ignore_case : bool, optional
        Case sensitive or not. The default value is ``True``.

    Returns
    -------
    bool
        ``True`` if the src string starts with the pattern.

    """

    if ignore_case:
        return src.lower().startswith(find.lower())
    return src.startswith(find)


import bpy
import math
import numpy as np
from collections import defaultdict

import sys

sys.path.append('//')

class smart_dict(dict):
    @staticmethod
    def __missing__(key):
        return key

def cylinder_between(x1, y1, z1, x2, y2, z2, rot, r = 0.2, verts = 8):
    dx = x2 - x1
    dy = y2 - y1
    dz = z2 - z1
    dist = math.sqrt(dx**2 + dy**2 + dz**2)

    bpy.ops.mesh.primitive_cylinder_add(
        radius = r,
        depth = dist,
        vertices = verts,
        location = (dx/2 + x1, dy/2 + y1, dz/2 + z1),
        rotation= rot
    )

result = '-L'
rules = smart_dict({
    'L': "LF+RFR+FL-F-LFLFL-FRFR+",
    'R': "-LFLF+RFRFR+F+RF-LFL-FR"
})
angle = math.pi / 2
iterations = 3
new = ""
for n in range(iterations):
    for c in result:
        new = new + rules[c]
    result = new
print(result)

location = [0, 0, 0]
rotation = [0, 0, 0]

locations_done = {}

first_obj = True
for ix, c in enumerate(result):
    if c == 'F':
        new_x = location[0] + math.sin(rotation[1])
        new_z = location[2] + math.cos(rotation[1])

        if str([new_x, location[1], new_z]) not in locations_done:
            cylinder_between(location[0], location[1], location[2], new_x, location[1], new_z, rotation)

            if first_obj:
                bpy.ops.object.editmode_toggle()
                first_obj = False

        location[0] = new_x
        location[2] = new_z
        locations_done[str(location)] = True
    elif c == '+':
        rotation[1] += angle
    elif c == '-':
        rotation[1] -= angle
    rotation[1] = abs(rotation[1]) % (2 * math.pi) * np.sign(rotation[1])

    print(ix, c, location, rotation)

bpy.ops.object.editmode_toggle()
bpy.ops.object.shade_smooth()


# portsanner for IPv4 addresses and/or hostnames
# probing addresses is invasive
# make sure you are doing the right thing

import validators
import socket
import subprocess
import sys
from datetime import datetime

# clearing the screen
subprocess.call('clear', shell=True)

def is_valid(address):
    # returns the validator result, True or False.
    return validators.ip_address.ipv4(remote_server) or validators.domain(remote_server)

while True:  # True is always True. This loop will never end.
    remote_server = input('Enter a remote host to scan: ')
    if remote_server == 'exit':
        sys.exit(0)
    if is_valid(remote_server):
        break
    else:
        print(
            'This address was not recognized as a valid IPv4 address or hostname.'
            'Please try again. Type \'exit\' to quit.'
        )

remote_serverIP = socket.gethostbyname(remote_server)

# print the scanning ip
print('*' * 60)
print('Please wait, scanning remote host of well-know ports', remote_serverIP)
print('*' * 60)

# time scan started
start_time = datetime.now()

# scan all ports between 1 and 1024
try:
    for port in range(1, 1025):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        result = sock.connect_ex((remote_serverIP, port))
        if result == 0:
            print('Port {}: 	 Open'.format(port))
        sock.close()

# error handling
except KeyboardInterrupt:
    print('You pressed Ctrl+C')
    sys.exit(1)

except socket.gaierror:
    print('Hostname could not be resolved')
    sys.exit(1)

except socket.error:
    print('Could not connect to server')
    sys.exit(1)

# time for script to finish
end_time = datetime.now()
completion_time = end_time - start_time

# print completion time
print('Scanning completed in: ', completion_time)


import os.path
import json

#-------------------------------- CaesarCipher class --------------------------
class  CaesarCipher:
    def __init__(self, key) :
        if key >= 0:
            key = key % (ord('z') - ord('a'))
        else:
            key = -((-key) % (ord('z') - ord('a')))
        self.key = key

    def encrypt(self, toEncrypt) :
        encryptedWord = ""
        for char in toEncrypt :
            numOfChar = ord(char)
            if char.isalpha():
                if char.isupper():
                    numOfChar = self.getNumOfChar(ord('A') , ord('Z'), numOfChar)
                else:
                    numOfChar = self.getNumOfChar(ord('a') , ord('z'), numOfChar)
            encryptedWord += chr(numOfChar)
        return encryptedWord

    def decrypt(self, toDecrypt) :
        ciphered = CaesarCipher(-(self.key))
        return ciphered.encrypt(toDecrypt)

    def getNumOfChar(self, start, end, numOfChar):
        if (numOfChar + self.key < start):
            numOfChar = end + ((numOfChar + self.key) - start ) +1
        elif (numOfChar + self.key > end):
            numOfChar = start + (self.key - (end -numOfChar)) -1
        else :
            numOfChar = numOfChar + self.key
        return numOfChar

#-------------------------------- VigenereCipher class --------------------------
class VigenereCipher:
    def __init__(self, numbersList):
        self.keysList = numbersList.copy()

    def encrypt(self, strToEncrypt):
        lenOfKeyList = len(self.keysList)
        counter = 0
        encryptedStr = ''
        for char in strToEncrypt:
            if counter == lenOfKeyList:
                counter = 0
            if char.isalpha():
                cipher = CaesarCipher(self.keysList[counter])
                encryptedStr = encryptedStr + cipher.encrypt(char)
                counter = counter + 1
            else:
                encryptedStr = encryptedStr + char
        return encryptedStr

    def decrypt(self, strToDecrypt):
        lenOfKeyList = len(self.keysList)
        counter = 0
        decryptedStr = ''
        for char in strToDecrypt:
            if counter == lenOfKeyList:
                counter = 0
            if char.isalpha():
                cipher = CaesarCipher(self.keysList[counter])
                decryptedStr = decryptedStr + cipher.decrypt(char)
                counter = counter + 1
            else:
                decryptedStr = decryptedStr + char
        return decryptedStr

#-------------------------------- External Functions --------------------------
def getVigenereFromStr(inputStr):
    listOfKeys = []
    firstLetter = ''
    for char in inputStr:
        if char.isalpha():
            if char.islower():
                firstLetter = 'a'
            else:
                firstLetter = 'A'
            listOfKeys.append(ord(char) - ord(firstLetter))
    temp_vigener = VigenereCipher(listOfKeys)
    return temp_vigener

def loadEncryptionSystem(dir_path):
    jsonFile = open(dir_path + "//config.json")
    data = json.load(jsonFile)
    type = data['type']
    ifEncrypt = data['encrypt']
    key = data['key']
    jsonFile.close()

    ifKeyIsString = isinstance(key, str)
    if type == 'Vigenere':
        if ifKeyIsString:
            cipher = getVigenereFromStr(key)
        else:
            cipher = VigenereCipher(key)
    else:
        cipher = CaesarCipher(key)
    files = [f for f in os.listdir('.') if os.path.isfile(f)]
    #if needs to encrypt .txt files to .enc files
    if ifEncrypt:
        for file in files:
            if file.endswith('.txt'):
                originalFile = open(file, 'r')
                encryptedFileName = os.path.splitext(file)[0] + '.enc'
                encryptedFile = open(encryptedFileName, 'w')
                strForEncrypting = ''
                for line in originalFile:
                    strForEncrypting = strForEncrypting + line
                encryptedFile.write(cipher.encrypt(strForEncrypting))
                originalFile.close()
                encryptedFile.close()
    # if needs to decrypt .enc files to .txt files
    else:
        for file in files:
            if file.endswith('.enc'):
                # fileName = os.path.splitext(os.path.split(txtFile_path)[1])[0]
                originalFile = open(file, 'r')
                decryptedFileName = os.path.splitext(file)[0] + '.txt'
                decryptedFile = open(decryptedFileName, 'w')
                strForDecrypting = ''
                for line in originalFile:
                    strForDecrypting = strForDecrypting + line
                decryptedFile.write(cipher.decrypt(strForDecrypting))
                originalFile.close()
                decryptedFile.close()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import torch
import torch.nn as nn

# モデルの定義
class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv1 = nn.Conv2d( 3, 16, kernel_size=3, stride=1, padding=1)
        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)
        self.fc = nn.Linear(32 * 8 * 8, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = nn.ReLU()(x)
        x = self.conv2(x)
        x = nn.ReLU()(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x

model = MyModel()


# -*- coding: utf-8 -*-
from flask import request
from flask.templating import DispatchingJinjaLoader
from flask.globals import _request_ctx_stack
from sqlalchemy.sql import and_
from unidecode import unidecode
import string, random, re

class ModifiedLoader(DispatchingJinjaLoader):
  def _iter_loaders(self, template):
    bp = _request_ctx_stack.top.request.blueprint
    if bp is not None and bp in self.app.blueprints:
      loader = self.app.blueprints[bp].jinja_loader
      if loader is not None:
        yield loader, template

    loader = self.app.jinja_loader
    if loader is not None:
      yield loader, template

def slugify(text, delim=u'-'):
  _punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')

  """Generates an ASCII-only slug."""
  result = []
  for word in _punct_re.split(text.lower()):
      result.extend(unidecode(word).split())
  return unicode(delim.join(result))

def slugify_unique(slug, Obj, current=False):
  id   = 0

  if current:
    id = current.id

  link = slugify(slug)

  count = Obj.query.filter(and_(Obj.link.like(link+'%'), Obj.id != id)).count()

  while Obj.query.filter(and_(Obj.id != id), Obj.link == link).count() != 0:
    link = "%s-%d" % (link, count)
    count += 1

  return link

def generate_password():
  char_set  = string.ascii_uppercase + string.digits
  return ''.join(random.sample(char_set, 6))

def get_page():
  if (request.args.get('page') is not None):
    page = int(request.args.get('page'))
  else:
    page = 1

  return page

def remove_html_tags(data):
  p = re.compile(r'<.*?>')
  return p.sub('', data)


#
# @lc app=leetcode id=1594 lang=python3
#
# [1594] Maximum Non Negative Product in a Matrix
#

# @lc code=start

from functools import cache

class Solution:
    def maxProductPath(self, grid: List[List[int]]) -> int:
        n = len(grid)
        m = len(grid[0])

        @cache
        def dfs(r, c, val):
            val *= grid[r][c]
            if r == n - 1 and c == m - 1:
                return val
            return max(
                dfs(dr, dc, val)
                for dr, dc in ((r, c + 1), (r + 1, c))
                if (0 <= dr < n and 0 <= dc < m)
            )

        res = dfs(0, 0, 1)
        return -1 if res < 0 else res % (10**9 + 7)

# @lc code=end


"""Tests for signal-based models"""
import numpy as np
import pytest

from nessai_models.signals import (
    LinearSignal,
    SinusoidalSignal,
)

all_models = [
    LinearSignal,
    SinusoidalSignal,
]

@pytest.fixture(params=all_models)
def SignalModelClass(request):
    """Signal model classes fixture."""
    return request.param

@pytest.mark.parametrize("n_points", [10, 100])
@pytest.mark.parametrize("sigma", [1, 2])
def test_max_likelihood(SignalModelClass, n_points, sigma):
    """Assert the maximum likelihood is the correct value.

    Sets the data to have zero noise.
    """
    model = SignalModelClass(n_points=n_points, sigma=sigma)
    model.data = model.signal_model(**model.truth)
    expected = n_points * -np.log(2 * np.pi * sigma**2)
    actual = model.log_likelihood(model.truth)
    np.testing.assert_almost_equal(actual, expected, decimal=12)


# -*- coding: utf-8 -*-
import scrapy
from scrapy_splash import SplashRequest
import json
from scrapy import Request
from queue import Queue
from zhihustar.items import ZhihustarItem
import requests

#  思路分析
# 1 首先获取每个用户的用户名
# 2 进入其主页获取其关注者
class StarSpider(scrapy.Spider):
    name = 'star'
    allowed_domains = ['www.zhihu.com']
    #start_urls = ['http://www.zhihu.com/']
    #这是轮子哥关注者的json格式的信息
    base_url = 'https://www.zhihu.com/api/v4/members/excited-vczh/followees?include=data%5B%2A%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F%28type%3Dbest_answerer%29%5D.topics&limit=20&offset=0'
    urlqueue = Queue()

    def start_requests(self):
        self.urlqueue.put(self.base_url)
        #该页面是不需要js渲染是能直接得到的数据

        yield Request(url=self.base_url,callback=self.parse)

    # 注意没有粉丝怎么办
    def parse(self, response):

        data = json.loads(response.text)

        #获取下一组用户的url,需要先判断data关键字对应的value不能为None
        if len(data.get('data'))!=0:
            next_url = data.get('paging').get('next')
            yield Request(url=next_url,callback=self.parse)
            # 得到用户数组
            users = data.get('data')
            # 每组用户信息由一个字典组成
            for user in users:
                user_name = user.get('url_token')
                # print(user_url)
                # print(type(user_url)) --str
                # 获取粉丝的粉丝
                user_url = 'https://www.zhihu.com/api/v4/members/' + user_name + '/followees?include=data%5B%2A%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F%28type%3Dbest_answerer%29%5D.topics&limit=20&offset=0'
                # 得到每个用户的主页链接
                user_main_url = 'https://www.zhihu.com/people/' + user_name + '/activities'
                yield Request(url=user_url, callback=self.parse)

                # proxy_pool_flash = 'http://127.0.0.1:5555/random'
                # ip = requests.get(proxy_pool_flash).text
                # proxy = 'http://' + ip

                yield SplashRequest(url=user_main_url, callback=self.parse_each_user)

    #解析每个用户的主页获取其关注数
    def parse_each_user(self,response):
        number_of_followers = response.xpath('//strong[@class="NumberBoard-itemValue"]')
        if number_of_followers:
            Item = ZhihustarItem()
            Item['url'] = response.url
            Item['followers'] = number_of_followers[1].xpath('./text()').extract_first().strip()
            number = Item['followers'].replace(',','')
            if int(number) > 10000:
                yield Item


# coding = 'utf-8
import os
import csv
import requests
from bs4 import BeautifulSoup
from selenium import webdriver

# APP类用于存放 (name, category ,detail_page, privacy_link)
class APP:
    def __init__(self, name: str, category: str, detail_page: str, privacy_link: str):
        self.name = name
        self.category = category
        self.detail_page = detail_page
        self.privacy_link = privacy_link
        self.state = 'success'

# 定义全局变量 WEBROOT为根目录
WEBROOT = "https://app.mi.com/category/"
APP_LIST = []

# 定义 selenium的 webdriver为 chromedriver并忽略系统代理
option = webdriver.ChromeOptions()
option.add_argument('headless')
option.add_argument('--ignore-ssl-error')
browser = webdriver.Chrome(options=option)

# 利用 requests库获取静态 html
def get_html_text(url):
    try:
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (XHTML, like Gecko) '
                          'Chrome/58.0.3029.110 Safari/537.36 '
        }
        r = requests.get(url, timeout=30, headers=headers)
        r.raise_for_status()
        r.encoding = 'utf-8'
        return r.text
    except:
        return "There are some errors when get the original page!"

# 利用selenium库模拟请求获取动态页面,用于获取category下的所有app_detail_page
def get_detail_page(url):
    app_tuple_list = []
    try:
        browser.get(url)
        soup = BeautifulSoup(browser.page_source, features='lxml')
    except requests.HTTPError:
        return "There are some errors when get the download page!"
    all_app_tag = soup.find('ul', {"class": "applist", "id": "all-applist"})
    app_tag = all_app_tag.next
    app_tag_list = []
    while app_tag:
        app_tag_list.append(app_tag)
        app_tag = app_tag.nextSibling
    for app_tag in app_tag_list:
        name = app_tag.text[:-4]
        category = app_tag.text[-4:]
        detail_page = app_tag.next.attrs['href']
        app_tuple = (name, category, detail_page)
        app_tuple_list.append(app_tuple)
    return app_tuple_list

# 从 category获取 detail_page,再到 detail_page中获取 privacy_policy_link
def get_privacy_link(url):
    app_tuple_list = get_detail_page(url)
    for app_tuple in app_tuple_list:
        name = app_tuple[0]
        category = app_tuple[1]
        detail_page = app_tuple[2]
        soup = BeautifulSoup(get_html_text("https://app.mi.com/" + detail_page), 'html.parser')
        # print(soup)
        tag = soup.find('a', {"style": "color: #707070;"})
        try:
            privacy_link = tag.get('href')
            temp = APP(name, category, detail_page, privacy_link)
            APP_LIST.append(temp)
            print("Successfully append: ({}, {}, {}, {})".format(name, category, detail_page, privacy_link))
        except AttributeError:
            pass
    return None

# 将所有APP_LIST中的 (name, category ,detail_page, privacy_link)对写入csv
def write_csv():
    path = os.getcwd() + "/app_list/" + APP_LIST[0].category + ".csv"
    file = open(path, 'w', newline='', encoding='gbk')
    writer = csv.writer(file)
    writer.writerow(('ApplicationName', 'Category', 'DetailPage', 'PrivacyPolicyLink'))
    for app in APP_LIST:
        writer.writerow((app.name, app.category, app.detail_page, app.privacy_link))
    print("AppList has been written successfully!")
    file.close()

def app_spider_run():
    # 获取小米应用市场中 14类 APP的 detail page和 privacy policy url并写入csv
    for i in range(1, 15):  # https://app.mi.com/category/{1~29}#page={0~2}
        APP_LIST = []
        for j in range(3):
            get_privacy_link(WEBROOT + str(i) + '#page=' + str(j))
        write_csv()

def get_privacy_text():
    # 从 csv读取 privacy link并获取 html写入 txt中
    csv_root = os.getcwd() + "/app_list"
    for root, dirs, files in os.walk(csv_root, topdown=False):
        for name in files:
            path = os.path.join(root, name)
            file = open(path, 'r', encoding='gbk')
            reader = csv.reader(file)
            for row in reader:
                if row[0] == 'ApplicationName':  # 过滤表头
                    pass
                else:
                    name = row[0]
                    category = row[1]
                    package = row[2][12:]
                    privacy_link = row[3]
                    html_text = get_html_text(privacy_link)
                    soup = BeautifulSoup(html_text, 'html.parser')
                    policy = soup.text
                    state = write_txt(category, package, policy)
                    write_state_csv(name, category, package, privacy_link, state)

# 将 privacy policy text写入单个 txt文件
def write_txt(category, package_name, privacy_text):
    root = os.getcwd() + "/privacy_policy/" + category + "/"
    if os.path.exists(root):
        pass
    else:
        os.makedirs(root)
    path = root + package_name + '.txt'
    if os.path.exists(path):
        print(path + "already exists!")
        state = 'success'
        return state
    else:
        # 尝试 gbk解码写入txt
        try:
            file = open(path, 'w', newline='', encoding='gbk')
            file.write(privacy_text)
            file.close()
            state = 'success'
        except UnicodeEncodeError:
            print("\nGBK Encoding Error happens in " + package_name)
            print("......Continue trying to decode with UTF8 ......")
            # 若 UnicodeEncodeError,则尝试 utf-8解码写入
            try:
                file = open(path, 'w', newline='', encoding='utf-8')
                file.write(privacy_text)
                file.close()
                print("Successfully decode with UTF8")
                state = 'success'
            except UnicodeEncodeError:
                # 若仍然 UnicodeEncodeError,则删除 txt文件,并在 app.state中写入 error
                state = 'error'
                os.path.exists(path)
                os.remove(path)
                print("UTF8 Encoding Error happens in " + package_name)
                print("......Automatically deletes the privacy policy txt ......")
        return state

def write_state_csv(name, category, package, privacy_link, state):
    path = os.getcwd() + "/privacy_policy/" + category + "/" + category + ".csv"
    file = open(path, 'a', newline='', encoding='gbk')
    writer = csv.writer(file)
    if os.path.getsize(path) == 0:
        writer.writerow(('ApplicationName', 'Category', 'DetailPage', 'PrivacyPolicyLink', 'State'))
    writer.writerow((name, category, package, privacy_link, state))
    print("Privacy Policy State has been successfully written!")
    file.close()

if __name__ == '__main__':

    app_spider_run()

    # Result example
    # Successfully append: (怡禾, 医疗健康, / details?id=com.yaeherhealth.app, https: // www.yaeyatech.com / private-protocol.html)
    # Successfully append: (小鹿中医 - 养生调理, 医疗健康, / details?id=com.xiaolu.patient, https: // s.xiaoluyy.com / xiaoluyyapp / agreement / legal.html)
    # Successfully append: (上海助医, 医疗健康, / details?id=com.lihuan.zhuyi, https: // shzy.91985.com / zhuyistaticpage / privacy.html)
    # Successfully append: (基因宝, 医疗健康, / details?id=com.laso.lasogene, https: // static.genebox.cn / static / privacy.html)

    get_privacy_text()

    # Result example
    # if policy.txt already exists
        # C:\Users\Rainbow\Desktop\Privacy Policy Violations\Coding\Spider_for_Miapp/privacy_policy/体育运动/com.magic.ball.sport.txtalready exists!
        # Privacy Policy State has been successfully written!
        # C:\Users\Rainbow\Desktop\Privacy Policy Violations\Coding\Spider_for_Miapp/privacy_policy/体育运动/com.ttzcy.caiyun.txtalready exists!
        # Privacy Policy State has been successfully written!
    # if policy.txt not exists (only error messages are displayed)
        # GBK Encoding Error happens in com.gooooal.app.events
        # ......Continue trying to decode with UTF8 ......
        # Successfully decode with UTF8
        # GBK Encoding Error happens in a.com.happy.step
        # ......Continue trying to decode with UTF8 ......
        # Successfully decode with UTF8


import logging
from typing import List
import unittest

from oplog.operation import Operation

class ListLoggingHandler(logging.Handler):
    def __init__(self):
        super().__init__()
        self.logs = []

    def emit(self, record):
        self.logs.append(record)

class LoggedTestCase(unittest.TestCase):
    def setUp(self):
        super().setUp()

        logger = logging.getLogger()
        logger.setLevel(logging.DEBUG)
        self.handler = ListLoggingHandler()
        self.handler.logs = []

        logger.addHandler(self.handler)

    def tearDown(self):
        super().tearDown()

class OpLogTestCase(LoggedTestCase):
    @property
    def ops(self) -> List[Operation]:
        return [log.oplog for log in self.handler.logs]

    def get_op(self, name: str) -> Operation:
        for op in self.ops:
            if op.name == name:
                return op
        raise LookupError(f"Operation with name {name} not found")

    def tearDown(self):
        Operation.factory_reset()
        return super().tearDown()

class LoggedAsyncTestCase(unittest.IsolatedAsyncioTestCase):
    async def asyncSetUp(self):
        await super().asyncSetUp()

        logger = logging.getLogger()
        logger.setLevel(logging.DEBUG)
        self.handler = ListLoggingHandler()
        self.handler.logs = []

        logger.addHandler(self.handler)

    async def asyncTearDown(self):
        await super().asyncTearDown()

class OpLogAsyncTestCase(LoggedAsyncTestCase):
    @property
    def ops(self) -> List[Operation]:
        return [log.oplog for log in self.handler.logs]

    def get_op(self, name: str) -> Operation:
        for op in self.ops:
            if op.name == name:
                return op
        raise LookupError(f"Operation with name {name} not found")

    async def asyncTearDown(self):
        Operation.factory_reset()
        return super().tearDown()


from sklearn.preprocessing import LabelEncoder
import datetime
import logging
import numpy as np
import pandas as pd

def cat_feature_encoding(df: pd.DataFrame) -> pd.DataFrame:
    """
    Categorical Feature Encoding to prepare the dataset for training

    :param
    df: pd.DataFrame
        Dataframe for categorical feature encoding to be applied to
    :return:
    pd.DataFrame
    """
    # get a list of all categorical features in the datasets
    d_type = pd.DataFrame(df.dtypes)
    d_type.rename({0: 'dtype'}, axis=1, inplace=True)
    d_type.reset_index(inplace=True)
    d_type['dtype'] = d_type['dtype'].astype('string')
    cat_col = d_type.loc[(d_type['dtype'] == 'object')]['index'].to_list()

    # Add categorical features that are not objects
    # Listed in the data overview section of the Kaggle competition
    card_cat = [f'card{x}' for x in range(1, 7)]
    addr_cat = [f'addr{x}' for x in range(1, 3)]
    id_cat = [f'id_{x}' for x in range(12, 39)]
    cat_col += card_cat + addr_cat + id_cat
    cat_col = list(set(cat_col))

    for i in range(len(cat_col)):
        if cat_col[i] in df.columns:
            le = LabelEncoder()
            le.fit(list(df[cat_col[i]].astype(str).values) + list(df[cat_col[i]].astype(str).values))
            df[cat_col[i]] = le.transform(list(df[cat_col[i]].astype(str).values))

    return df

def feature_engineering(df: pd.DataFrame) -> pd.DataFrame:
    """
    Feature engineering for IEEE Fraud Detection Dataset

    :param
    df: pd.DataFrame
        Dataframe for feature engineering to be applied to

    :return:
    pd.DataFrame
    """
    startdate = datetime.datetime.strptime('2017-12-01', "%Y-%m-%d")

    df['cents'] = (df['TransactionAmt'] - np.floor(df['TransactionAmt'])).astype('float32')
    df['log_TransactionAmt'] = np.log(df['TransactionAmt'])
    df[['P_email_1', 'P_email_2', 'P_email_3']] = df['P_emaildomain'].str.split('.', expand=True)
    df.drop('P_emaildomain', axis=1, inplace=True)
    df[['R_email_1', 'R_email_2', 'R_email_3']] = df['R_emaildomain'].str.split('.', expand=True)
    df.drop('R_emaildomain', axis=1, inplace=True)
    df['Date'] = df['TransactionDT'].apply(lambda x: (startdate + datetime.timedelta(seconds=x)))
    df['Weekdays'] = df['Date'].dt.dayofweek
    df['Hours'] = df['Date'].dt.hour
    df['Days'] = df['Date'].dt.day
    df['Month'] = (df['Date'].dt.year - 2017) * 12 + df['Date'].dt.month

    # Aggregate features together
    df['uid'] = df['card1'].astype(str) + '_' + df['addr1'].astype(str)
    df['uid2'] = df['uid'].astype(str) + '_' + np.floor(df.Days - df.D1).astype(str)
    for feature in ['TransactionAmt', 'D9', 'D10', 'C1', 'C5']:
        for agg in ['mean', 'std']:
            temp = df.groupby(['uid2'])[feature].agg([agg]).reset_index().rename(
                columns={f'{agg}': f'{feature}_{agg}_uid'})
            temp.index = list(temp['uid2'])
            temp = temp[f'{feature}_{agg}_uid'].to_dict()
            df[f'{feature}_{agg}_uid'] = df['uid2'].map(temp).astype('float32')
    df.drop('uid2', axis=1, inplace=True)

    for feature in ['card1', 'card4']:
        for agg in ['mean', 'std']:
            df[f'TransactionAmt_{agg}_{feature}'] = df['TransactionAmt'] / df.groupby([feature])[
                'TransactionAmt'].transform(agg)
            df[f'id_01_{agg}_{feature}'] = df['TransactionAmt'] / df.groupby([feature])['id_01'].transform(agg)

    return df

def reduce_mem_usage2(df):
    """ iterate through all the columns of a dataframe and modify the data type
        to reduce memory usage.
    """
    start_mem = df.memory_usage().sum() / 1024 ** 2
    logging.info('Memory usage of dataframe is {:.2f} MB'.format(start_mem))

    for col in df.columns:
        col_type = df[col].dtype

        if col_type != object:
            c_min = df[col].min()
            c_max = df[col].max()
            if str(col_type)[:3] == 'int':
                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
                    df[col] = df[col].astype(np.int8)
                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                    df[col] = df[col].astype(np.int16)
                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
                    df[col] = df[col].astype(np.int32)
                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
                    df[col] = df[col].astype(np.int64)
            else:
                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
                    df[col] = df[col].astype(np.float16)
                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
                    df[col] = df[col].astype(np.float32)
                else:
                    df[col] = df[col].astype(np.float64)
        else:
            df[col] = df[col].astype('category')

    end_mem = df.memory_usage().sum() / 1024 ** 2
    logging.info('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
    logging.info('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))

    return df


from collections import defaultdict
from typing import List

class FourSumII:
    def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:
        sumMap=defaultdict(int)
        for a in A:
            for b in B:
                sumMap[a+b]+=1

        result=0
        for c in C:
            for d in D:
                result+=sumMap[-(c+d)]

        return result

if __name__ == '__main__':
    init = FourSumII()
    A = [1, 2]
    B = [-2, -1]
    C = [-1, 2]
    D = [0, 2]
    print(init.fourSumCount(A, B, C, D))


import logging
import time
import os
import importlib
import WorkManager
import FileManager
from pandayoda.common import MessageTypes
from pandayoda.common.yoda_multiprocessing import Process, Event

logger = logging.getLogger(__name__)

config_section = os.path.basename(__file__)[:os.path.basename(__file__).rfind('.')]

class Yoda(Process):
    def __init__(self, queues, config, rank, worldsize):
        ''' config: configuration of Yoda
      '''
        # call Thread constructor
        super(Yoda, self).__init__()

        # message queues
        self.queues = queues

        # rank number
        self.rank = rank

        # world size
        self.worldsize = worldsize

        # config settings
        self.config = config

        # keep track of if the wallclock has expired
        self.wallclock_expired = Event()

        # this is used to trigger the thread exit
        self.exit = Event()

    def stop(self):
        ''' this function can be called by outside threads to cause the Yoda thread to exit'''
        self.exit.set()

    # this runs when 'yoda_instance.start()' is called
    def run(self):
        ''' this is the function called when the user runs yoda_instance.start() '''
        try:
            self.subrun()
        except Exception:
            logger.exception('Yoda failed with uncaught exception')
            raise

    def subrun(self):
        ''' this function is the business logic, but wrapped in exception '''

        self.read_config()

        # set logging level
        logger.info('Yoda Thread starting')
        logger.info('loglevel:                    %s', self.loglevel)
        logger.info('loop_timeout:                %s', self.loop_timeout)
        top_working_path = os.getcwd()
        logger.debug('cwd:                        %s', top_working_path)

        # setup harvester messenger to share with FileManager and WorkManager
        logger.debug('setup harvester messenger')
        harvester_messenger = self.get_harvester_messenger()
        harvester_messenger.setup(self.config)
        # wait for setup to complete
        harvester_messenger.sfm_har_config_done.wait()

        # a list of ranks that have exited
        self.exited_droids = []

        # a dictionary of subthreads
        subthreads = {}

        # create WorkManager thread
        subthreads['WorkManager'] = WorkManager.WorkManager(self.config, self.queues, harvester_messenger)
        subthreads['WorkManager'].start()

        # create FileManager thread
        subthreads['FileManager'] = FileManager.FileManager(self.config, self.queues, top_working_path,
                                                            harvester_messenger)
        subthreads['FileManager'].start()

        # start message loop
        while not self.exit.is_set():
            logger.debug('start loop')

            # process incoming messages from other threads or ranks
            self.process_incoming_messages()

            # check if all droids have exited
            if len(self.exited_droids) >= (self.worldsize - 1):
                logger.info('all droids have exited, exiting yoda')
                self.stop()
                break

            # check the status of each subthread
            logger.debug('checking all threads still alive')
            keys = subthreads.keys()
            for name in keys:
                thread = subthreads[name]
                # if the thread is not alive, throw an error
                if not thread.is_alive():
                    logger.warning('%s is no longer running.', name)
                    del subthreads[name]
                    if name == 'WorkManager':
                        self.stop()
                        continue
                # else:
                # logger.debug('%s %s is running.',self.prelog,name)

            if len(subthreads) == 0:
                logger.info('no subthreads remaining, exiting')
                self.stop()
                break

            if self.queues['Yoda'].empty():
                logger.debug('sleeping %s', self.loop_timeout)
                self.exit.wait(timeout=self.loop_timeout)

        # send the exit signal to all droid ranks
        logger.info('sending exit signal to droid ranks')
        for ranknum in range(1, self.worldsize):
            if ranknum not in self.exited_droids:
                if self.wallclock_expired.is_set():
                    self.queues['MPIService'].put(
                        {'type': MessageTypes.WALLCLOCK_EXPIRING, 'destination_rank': ranknum})
                else:
                    self.queues['MPIService'].put({'type': MessageTypes.DROID_EXIT, 'destination_rank': ranknum})

        # send the exit signal to all subthreads
        for name, thread in subthreads.iteritems():
            logger.info('sending exit signal to %s', name)
            thread.stop()

        # wait for sub threads to exit
        for name, thread in subthreads.iteritems():
            logger.info('waiting for %s to join', name)
            thread.join()
            logger.info('%s has joined', name)

        while not self.queues['MPIService'].empty():
            logger.info('waiting for MPIService to send exit messages to Droid, sleep for %s', self.loop_timeout)
            time.sleep(self.loop_timeout)

        logger.info('Yoda is exiting')

    def read_config(self):

        if config_section in self.config:
            # read log level:
            if 'loglevel' in self.config[config_section]:
                self.loglevel = self.config[config_section]['loglevel']
                logger.info('%s loglevel: %s', config_section, self.loglevel)
                logger.setLevel(logging.getLevelName(self.loglevel))
            else:
                logger.warning('no "loglevel" in "%s" section of config file, keeping default', config_section)

            # read loop timeout:
            if 'loop_timeout' in self.config[config_section]:
                self.loop_timeout = int(self.config[config_section]['loop_timeout'])
                logger.info('%s loop_timeout: %s', config_section, self.loop_timeout)
            else:
                logger.warning('no "loop_timeout" in "%s" section of config file, keeping default %s', config_section,
                               self.loop_timeout)

            # messenger_plugin_module
            if 'messenger_plugin_module' in self.config[config_section]:
                self.messenger_plugin_module = self.config[config_section]['messenger_plugin_module']
            else:
                raise Exception(
                    'Failed to retrieve "messenger_plugin_module" from config file section %s' % config_section)
        else:
            raise Exception('no %s section in the configuration' % config_section)

    def process_incoming_messages(self):

        while not self.queues['Yoda'].empty():

            qmsg = self.queues['Yoda'].get(block=False)

            # process message
            logger.debug('received message: %s', qmsg)

            if qmsg['type'] == MessageTypes.DROID_HAS_EXITED:
                logger.debug(' droid rank %d has exited', qmsg['source_rank'])
                self.exited_droids.append(qmsg['source_rank'])
                logger.debug('%s droid ranks have exited', len(self.exited_droids))
            else:
                logger.error(' could not interpret message: %s', qmsg)

    def get_harvester_messenger(self):
        # try to import the module specified in the config
        # if it is not in the PYTHONPATH this will fail
        try:
            return importlib.import_module(self.messenger_plugin_module)
        except ImportError:
            logger.exception('Failed to import messenger_plugin: %s', self.messenger_plugin_module)
            raise


import os
from typing import Dict, Optional, Tuple

from ape.api import UpstreamProvider
from ape.exceptions import ContractLogicError, ProviderError, VirtualMachineError
from ape_ethereum.provider import Web3Provider
from web3 import HTTPProvider, Web3
from web3.exceptions import ContractLogicError as Web3ContractLogicError
from web3.gas_strategies.rpc import rpc_gas_price_strategy
from web3.middleware import geth_poa_middleware

_ENVIRONMENT_VARIABLE_NAMES = ("WEB3_INFURA_PROJECT_ID", "WEB3_INFURA_API_KEY")
# NOTE: https://docs.infura.io/learn/websockets#supported-networks
_WEBSOCKET_CAPABLE_ECOSYSTEMS = {
    "ethereum",
    "polygon",
    "linea",
}

class InfuraProviderError(ProviderError):
    """
    An error raised by the Infura provider plugin.
    """

class MissingProjectKeyError(InfuraProviderError):
    def __init__(self):
        env_var_str = ", ".join([f"${n}" for n in _ENVIRONMENT_VARIABLE_NAMES])
        super().__init__(f"Must set one of {env_var_str}")

class Infura(Web3Provider, UpstreamProvider):
    network_uris: Dict[Tuple[str, str], str] = {}

    @property
    def uri(self) -> str:
        ecosystem_name = self.network.ecosystem.name
        network_name = self.network.name
        if (ecosystem_name, network_name) in self.network_uris:
            return self.network_uris[(ecosystem_name, network_name)]

        key = None
        for env_var_name in _ENVIRONMENT_VARIABLE_NAMES:
            env_var = os.environ.get(env_var_name)
            if env_var:
                key = env_var
                break

        if not key:
            raise MissingProjectKeyError()

        prefix = f"{ecosystem_name}-" if ecosystem_name != "ethereum" else ""
        network_uri = f"https://{prefix}{network_name}.infura.io/v3/{key}"
        self.network_uris[(ecosystem_name, network_name)] = network_uri
        return network_uri

    @property
    def http_uri(self) -> str:
        # NOTE: Overriding `Web3Provider.http_uri` implementation
        return self.uri

    @property
    def ws_uri(self) -> Optional[str]:
        # NOTE: Overriding `Web3Provider.ws_uri` implementation
        if self.network.ecosystem.name not in _WEBSOCKET_CAPABLE_ECOSYSTEMS:
            return None

        # Remove `http` in default URI w/ `ws`, also infura adds `/ws` to URI
        return "ws" + self.uri[4:].replace("v3", "ws/v3")

    @property
    def connection_str(self) -> str:
        return self.uri

    def connect(self):
        self._web3 = Web3(HTTPProvider(self.uri))

        # Any chain that *began* as PoA needs the middleware for pre-merge blocks
        ethereum_goerli = 5
        optimism = (10, 420)
        polygon = (137, 80001)
        linea = (59144, 59140)

        if self._web3.eth.chain_id in (ethereum_goerli, *optimism, *polygon, *linea):
            self._web3.middleware_onion.inject(geth_poa_middleware, layer=0)

        self._web3.eth.set_gas_price_strategy(rpc_gas_price_strategy)

    def disconnect(self):
        self._web3 = None

    def get_virtual_machine_error(self, exception: Exception, **kwargs) -> VirtualMachineError:
        txn = kwargs.get("txn")
        if not hasattr(exception, "args") or not len(exception.args):
            return VirtualMachineError(base_err=exception, txn=txn)

        args = exception.args
        message = args[0]
        if (
            not isinstance(exception, Web3ContractLogicError)
            and isinstance(message, dict)
            and "message" in message
        ):
            # Is some other VM error, like gas related
            return VirtualMachineError(message["message"], txn=txn)

        elif not isinstance(message, str):
            return VirtualMachineError(base_err=exception, txn=txn)

        # If get here, we have detected a contract logic related revert.
        message_prefix = "execution reverted"
        if message.startswith(message_prefix):
            message = message.replace(message_prefix, "")

            if ":" in message:
                # Was given a revert message
                message = message.split(":")[-1].strip()
                return ContractLogicError(revert_message=message, txn=txn)
            else:
                # No revert message
                return ContractLogicError(txn=txn)

        return VirtualMachineError(message, txn=txn)


# Import libraries
import sys

sys.path.insert(0, '../../')

import os
import pygame
import pygame_menu

from random import randrange

from GameWindow  import *
# -----------------------------------------------------------------------------
# Constants and global variables
# -----------------------------------------------------------------------------
ABOUT = ['Szpil: Śląski świat ',
         'Autor: Ola Duda',
         '',  # new line
         'Email: oladuda1999@gmail.com']
DIFFICULTY = ['EASY']
FPS = 60.0
WINDOW_SIZE = (800, 600)

clock = None  # type: pygame.time.Clock
main_menu = None  # type: pygame_menu.Menu
surface = None  # type: pygame.Surface

# -----------------------------------------------------------------------------
# Methods
# -----------------------------------------------------------------------------

def play_function( font, test=False):
    # Define globals
    global main_menu
    global clock
    global play_menu

    #start_game()

    game_menu = pygame_menu.Menu(
        height=WINDOW_SIZE[1],
        onclose=pygame_menu.events.DISABLE_CLOSE,
        title='Game Menu',
        width=WINDOW_SIZE[0] ,
    )

    # Reset main menu and disable
    # You also can set another menu, like a 'pause menu', or just use the same
    # main_menu as the menu that will check all your input.
    main_menu.disable()
    main_menu.reset(1)

    user_name = game_menu.add_text_input('Miano: ', default='')
    game_menu.add_button('Grej',start_game,user_name,surface)
    game_menu.add_button('Wrōć',pygame_menu.events.BACK)
    game_menu.mainloop(surface)

    while True:

        # noinspection PyUnresolvedReferences
        clock.tick(60)

        # Application events
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                exit()
            elif e.type == pygame.KEYDOWN:
                if e.key == pygame.K_ESCAPE:
                    main_menu.enable()

                    # Quit this function, then skip to loop of main-menu on line 317
                    return

        pygame.display.flip()

        # If test returns
        if test:
            break

def read_game():
    # loading
    with open('data/savefile.dat', 'rb') as f:
        user = pickle.load(f)
    return user

def main_background():
    """
    Function used by menus, draw on background while menu is active.
    :return: None
    """
    global surface
    surface.fill((128, 0, 128))

def main(test=False):
    """
    Main program.
    :param test: Indicate function is being tested
    :type test: bool
    :return: None
    """

    # -------------------------------------------------------------------------
    # Globals
    # -------------------------------------------------------------------------
    global clock
    global main_menu
    global surface

    # -------------------------------------------------------------------------
    # Init pygame
    # -------------------------------------------------------------------------
    pygame.init()
    os.environ['SDL_VIDEO_CENTERED'] = '1'

    # Create pygame screen and objects
    surface = pygame.display.set_mode(WINDOW_SIZE)
    pygame.display.set_caption('Szpil po ślōnsku')
    clock = pygame.time.Clock()

    # -------------------------------------------------------------------------
    # Create menus: Play Menu
    # -------------------------------------------------------------------------
    play_menu = pygame_menu.Menu(
        height=WINDOW_SIZE[1] ,
        onclose=pygame_menu.events.DISABLE_CLOSE,
        title='Grej myni',
        width=WINDOW_SIZE[0] ,
    )

    submenu_theme = pygame_menu.themes.THEME_DARK.copy()
    submenu_theme.widget_font_size = 15
    play_submenu = pygame_menu.Menu(
        height=WINDOW_SIZE[1] ,
        theme=submenu_theme,
        title='Myni',
        width=WINDOW_SIZE[0] ,
    )
    for i in range(30):
        play_submenu.add_button('Back {0}'.format(i), pygame_menu.events.BACK)
    play_submenu.add_button('Wrōć', pygame_menu.events.RESET)

    play_menu.add_button('Nowy szpil', play_function,pygame.font.Font(pygame_menu.font.FONT_FRANCHISE, 30))

    play_menu.add_button('Wgrej szpil', play_submenu)
    play_menu.add_button('Wrōć', pygame_menu.events.BACK)

    # -------------------------------------------------------------------------
    # Create menus:About
    # -------------------------------------------------------------------------
    about_theme = pygame_menu.themes.THEME_DARK.copy()
    about_theme.widget_margin = (0, 0)
    about_theme.widget_offset = (0, 0.05)

    about_menu = pygame_menu.Menu(
        height=WINDOW_SIZE[1] ,
        onclose=pygame_menu.events.DISABLE_CLOSE,
        theme=about_theme,
        title='Ô autor',
        width=WINDOW_SIZE[0] ,
    )
    for m in ABOUT:
        about_menu.add_label(m, align=pygame_menu.locals.ALIGN_LEFT, font_size=20)
    about_menu.add_label('')
    about_menu.add_button('Wrōć', pygame_menu.events.BACK)

    # -------------------------------------------------------------------------
    # Create menus: Main
    # -------------------------------------------------------------------------
    main_theme = pygame_menu.themes.THEME_DARK.copy()
    main_theme.menubar_close_button = False  # Disable close button

    main_menu = pygame_menu.Menu(
        height=WINDOW_SIZE[1],
        onclose=pygame_menu.events.DISABLE_CLOSE,
        theme=main_theme,
        title='Myni bazowe',
        width=WINDOW_SIZE[0]
    )

    main_menu.add_button('Grej', play_menu)
    main_menu.add_button('Ô autor', about_menu)
    main_menu.add_button('Zakōńcz', pygame_menu.events.EXIT)

    # -------------------------------------------------------------------------
    # Main loop
    # -------------------------------------------------------------------------
    while True:

        # Tick
        clock.tick(FPS)

        # Paint background
        main_background()

        # Application events
        events = pygame.event.get()
        for event in events:
            if event.type == pygame.QUIT:
                exit()

        # Main menu
        main_menu.mainloop(surface, main_background, disable_loop=test, fps_limit=FPS)

        # Flip surface
        pygame.display.flip()

        # At first loop returns
        if test:
            break

if __name__ == '__main__':
    main()


from image import Image
from numpy import clip
from itertools import product

class Dithering:
    def __init__(self, image: Image, colors_qty: int):
        self.image = image
        self.factor = image.colors_per_channel/(colors_qty - 1)

    def dither(self) -> []:
        for (y, x) in product(range(0, self.image.width - 1),
                              range(1, self.image.height - 1)):
            self._quantize_pixel(x, y)

    def _quantize_pixel(self, x: int, y: int) -> None:
        old_pixel = self.image.raw_image[x][y]
        new_pixel = self._find_closest_colors(old_pixel)
        quant_error = old_pixel - new_pixel
        self.image.raw_image[x][y] = new_pixel

        self._propagate_error(x + 1, y, quant_error * 0.4375)
        self._propagate_error(x - 1, y + 1, quant_error * 0.1875)
        self._propagate_error(x, y + 1, quant_error * 0.3125)
        self._propagate_error(x + 1, y + 1, quant_error * 0.0625)

    def _find_closest_colors(self, pixel: []) -> []:
        return [round(color/self.factor)*self.factor for color in pixel]

    def _propagate_error(self, x: int, y: int, quant_error: []) -> None:
        clip(self.image.raw_image[x][y] + quant_error,
             0, self.image.colors_per_channel,
             out=self.image.raw_image[x][y])