'''
Module to facilitate DVH calculation and manipulation of Dose Volume Histograms

TODO: rescale DVH with fraction outside dose grid
'''

from copy import deepcopy
import numpy as np
import warnings

# Define how to cumulate / differentiate dose and volume
def cumulate_dose(d):
    for i in range(1, len(d)):
        d[i] += d[i - 1]
    return d

def differentiate_dose(d):
    return np.hstack(([d[0]], np.diff(d)))

def cumulate_volume(v):
    i = len(v) - 2
    while i >= 0:
        v[i] += v[i + 1]
        i -= 1
    return v

def differentiate_volume(v):
    return np.hstack((v[:-1] - v[1:], [v[-1]]))

def compute_dvh(dose_mask=None, mask=None, dose=None,
                edge_voxel_weight=None, bins=200,
                type='cum'):
    '''
    Compute a DVH curve for the given ROI from the given dose grid. Returns
    the DVH data. If no binary mask is specified, one will be computed for
    the dvh.roi. The value of each voxel contained within the mask is used
    to weight the dose data in the final histogram. Input parameter "bins"
    may be specified as an integer number of bins to include in the histogram,
    or it may be a vector of bin edges (see np.histogram).

    If an edge_voxel_weight is specified, all edge voxels in the x-y plane of
    the binary mask are multipled by the specified weight.
    '''
    from .dose_map import compute_dose_mask as cdm

    # Must have dose and mask, or dose_mask
    fraction_outside_dosegrid = None
    if dose_mask is None:
        if dose is None:
            raise ValueError('DVH computation requires a dose grid to compute DVH data')
        if mask is None:
            raise ValueError('DVH computation requires either an ROI or a binary mask')
        dose_mask, fraction_outside_dosegrid = cdm(dose=dose, mask=mask)
    elif hasattr(dose_mask, 'fraction_outside_dosegrid'):
        fraction_outside_dosegrid = dose_mask.fraction_outside_dosegrid

    # Compute histogram
    voxelVolume = abs(
        dose_mask.spacing[0] * dose_mask.spacing[1] * dose_mask.spacing[2])
    try:
        # modifiedBins = bins - 1
        useModifiedBins = True
    except ValueError:
        useModifiedBins = False

    # Compute the weight associated with each dose point
    mask_voxel_indices = dose_mask.data.nonzero()
    dose_weights = np.ones_like(
        dose_mask.data[mask_voxel_indices], dtype=np.float_)
    if (edge_voxel_weight is not None) and (edge_voxel_weight != 1):
        edge_mask = mask.get_mask_edge_voxels(exclude_z=True)
        dose_weights[edge_mask.data[mask_voxel_indices] > 0] *= edge_voxel_weight

    if useModifiedBins:
        # Last dose bin has a volume of 0
        hist, edges = np.histogram(
            dose_mask.data[mask_voxel_indices],
            bins=bins - 1,
            density=False,
            weights=dose_weights)
        hist = np.append(hist, 0)
    else:
        # Last dose bin may not have a volume of 0
        hist, edges = np.histogram(
            dose_mask.data[mask_voxel_indices],
            bins=bins,
            density=False,
            weights=dose_weights)
        edges = edges[:-1]

    dose_data = np.array(edges)
    dvh_volume_data = np.array(hist) * voxelVolume

    # If requesting a cumulative dvh, accumulate the volumes
    if 'cum' in type:
        i = len(dvh_volume_data) - 2
        while i >= 0:
            dvh_volume_data[i] += dvh_volume_data[i + 1]
            i -= 1
        dvh_volume_data[:] = [v / dvh_volume_data[0] for v in dvh_volume_data]

    return (dose_data, dvh_volume_data), fraction_outside_dosegrid

class Dvh(object):
    '''
    Dose Volume Histogram representation.

    Initialize the DVH class with either the data
    or both a structure and dose class.

    Keyword arguments:
        :data:  points defining a dose volume histogram
        :roi:   Roi class
        :mask:  Mask class
        :dose:  Dose class
    '''

    def __init__(self, data=None, roi=None, mask=None, dose=None):
        # DVH data: Nx2 numpy array [[dose,volume]] tuples
        self.data = data
        # An ROI class
        self.roi = deepcopy(roi)
        # Get a mask either from the ROI class or mask argument
        if mask is not None:
            self.mask = deepcopy(mask)
        elif self.roi is not None:
            self.mask = self.roi.mask
        # A dose class
        self.dose = deepcopy(dose)

        # If data wasn't provided, must have a dose and mask
        if self.data is None:
            if self.dose is None:
                raise ValueError('DVH computation requires a dose grid to compute DVH data')
            if self.mask is None:
                raise ValueError('DVH computation requires either an ROI or a binary mask')

        self.dose_type = None       # 'cum', 'diff'
        self.dose_units = None      # 'cGy', 'Gy', 'normalized'
        self.volume_type = None     # 'cum', 'diff'
        self.volume_units = None    # 'cm3', 'normalized'

        self.volume = None
        if self.mask is not None:
            self.volume = self.mask.get_volume()
        elif self.roi is not None:
            self.volume = self.roi.get_volume()

        # DVH values
        self.dose_data = []
        self.volume_data = []
        if data is not None:
            self.set_data(data)

        # These are updated by self.compute_dvh
        self.dose_mask = None
        self.min_dose = None
        self.max_dose = None
        self.mean_dose = None
        self.std_dose = None
        self.fraction_outside_dosegrid = None

        # Compute the DVH
        self.compute_dvh()

    def __str__(self):
        outputStr = 'Dose type:     ' + str(self.dose_type) + '\n' \
                  + 'Dose units:    ' + str(self.dose_units) + '\n' \
                  + 'Volume type:   ' + str(self.volume_type) + '\n' \
                  + 'Volume units:  ' + str(self.volume_units) + '\n' \
                  + 'Num Points:    ' + str(len(self.dose_data)) + '\n' \
                  + 'Min Dose:      ' + str(self.min_dose) + '\n' \
                  + 'Max Dose:      ' + str(self.max_dose) + '\n' \
                  + 'Mean Dose:     ' + str(self.mean_dose) + '\n' \
                  + 'Std Dose:      ' + str(self.std_dose) + '\n' \
                  + 'Fraction Outside Dose Grid: ' + str(self.fraction_outside_dosegrid)
        return outputStr

    def set_data(self, data):
        '''
        Set the DVH data.

        Positonal arguments:
            :data:  list of (dose, volume) tuples
        '''
        self.data = np.array(data)
        if len(self.data.shape) > 1 and self.data.shape[1] > 0:
            self.dose_data = self.data[:, 0]
            # Update dose statistics
            self.min_dose = np.min(self.dose_data)
            self.max_dose = np.max(self.dose_data)
            self.mean_dose = np.mean(self.dose_data)
            self.std_dose = np.std(self.dose_data)
            if self.dose_units is None:
                if self.min_dose <= 1.0 and self.max_dose == 1.0:
                    self.dose_units = 'normalized'
                elif self.max_dose > 1000:
                    self.dose_units = 'cGy'
                else:
                    self.dose_units = 'Gy'
        else:
            self.dose_data = []
            self.min_dose = None
            self.max_dose = None
            self.dose_units = None

        if len(self.data.shape) > 1 and self.data.shape[1] > 1:
            self.volume_data = self.data[:, 1]
            if self.volume is None:
                self.volume = np.amax(self.volume_data)
            if self.volume_units is None:
                if self.volume == 1.0:
                    self.volume_units = 'normalized'
                else:
                    self.volume_units = 'cm3'
        else:
            self.volume_data = []
            self.volume_units = None

    def get_dose(self, type='cum', normalized=False):
        '''
        Get the dose data.

        Positional arguments:
            :type:  type of dose to calculate
                - 'cum' for cumulative dose
                - 'diff' for differential dose
        Keyword arguments:
            :normalized:    boolean value. If True, normalize all dose values by the maximum dose.
        Returns:
            Dose data bins from the dvh object
        '''
        if 'cum' in type:
            d = self.get_cumulative_dose()
        elif 'diff' in type:
            d = self.get_differential_dose()
        else:
            raise ValueError('Dose type "{0}" not recognized.'.format(type))

        if normalized:
            maxdose = np.amax(d)
            if maxdose == 0:
                raise TypeError('Normalization error: Maximum dose is 0.')
            d = d / maxdose
        return d

    def get_cumulative_dose(self, normalized=None):
        '''
        Convert dose bin widths to cumulative dose points

        Returns:
            Cumulative dose data bins
        '''
        if self.dose_type != 'cum':
            self.dose_type = 'cum'
            self.dose_data = cumulate_dose(self.dose_data)
            self.data[:, 0] = self.dose_data

        if normalized and ('norm' not in self.dose_units.lower()):
            maxdose = np.amax(self.dose_data)
            if maxdose == 0:
                raise TypeError('Normalization error: Maximum dose is 0.')
            self.data[:, 0] /= maxdose

        return self.dose_data

    def get_differential_dose(self, normalized=None):
        '''
        Convert cumulative dose points to dose bin widths (e.g., DICOM standard)

        Returns:
            Differential dose data bins
        '''
        if self.dose_type != 'diff':
            self.dose_type = 'diff'
            self.dose_data = differentiate_dose(self.dose_data)
            self.data[:, 0] = self.dose_data

        if self.dose_units is not None and 'norm' in self.dose_units:
            if self.volume is not None and self.volume > 0:
                self.dose_data *= self.volume
                self.data[:, 0] *= self.volume
            else:
                raise Exception(
                    'Cannot compute differential dose \
                    when the dose points are normalized unless the dvh.volume is given'
                )
        return self.dose_data

    def get_volume(self, type, normalized=False):
        '''
        Get the volume data.

        Positional arguments:
            :type:  type of dose to calculate
                - 'cum' for cumulative dose
                - 'diff' for differential dose
        Keyword arguments:
            :normalized:    boolean value. If True, normalize all dose values by the maximum dose.
        Returns:
            Volume data from the dvh object
        '''
        if 'cum' in type:
            v = self.get_cumulative_volume()
        elif 'diff' in type:
            v = self.get_differential_volume()
        else:
            raise ValueError('Dose type "{0}" not recognized.'.format(type))

        if normalized:
            maxvolume = np.amax(v)
            if maxvolume == 0:
                warnings.warn('Maximum volume is 0, normalization not performed.', Warning)
                return v
            v = v / maxvolume
        return v

    def get_cumulative_volume(self):
        '''
        Convert differential volume bins to cumulative volume bins

        Returns:
            Cumulative volume data bins
        '''
        if self.volume_type != 'cum':
            self.volume_type = 'cum'
            self.volume_data = cumulate_volume(self.volume_data)
            self.data[:, 1] = self.volume_data
        return self.volume_data

    def get_differential_volume(self):
        '''
        Convert cumulative volumes to differential volumes

        Returns:
            Differential volume data bins
        '''
        if self.volume_type != 'diff':
            self.volume_type = 'diff'
            self.volume_data = differentiate_volume(self.volume_data)
            self.data[:, 1] = self.volume_data
        return self.volume_data

    def get_differential_dvh(self):
        '''
        Compute the differential DVH data points

        Returns:
            List of tuples of differential DVH datapoints
        '''
        dose = self.get_cumulative_dose()
        volume = self.get_differential_volume()
        return [(d, v) for d, v in zip(dose, volume)]

    def estimate_mean(self):
        '''
        Estimate the mean dose from the differential DVH

        Returns:
            Mean dose
        '''
        dose = np.array(self.dose_data)
        if self.dose_type != 'cum':
            dose = cumulate_dose(dose)

        volume = np.array(self.volume_data)
        if self.volume_type != 'diff':
            volume = differentiate_volume(volume)

        if sum(volume) > 0:
            return sum(dose * volume) / sum(volume)
        return 0

    def compute_dose_mask(self):
        '''
        Compute a dose mask using the DVH class' roi and dose variables.

        Returns:
            List of dose values corresponding to each nonzero index in the mask
        '''
        from .dose_map import compute_dose_mask as cdm

        self.dose_mask, self.fraction_outside_dosegrid = cdm(dose=self.dose, mask=self.mask)
        # Compute stats
        self.min_dose = self.dose.min
        self.max_dose = self.dose.max
        self.mean_dose = self.dose.mean
        self.std_dose = self.dose.std
        return self.dose_mask

    def compute_dvh(self):
        '''
        Compute a DVH curve for the given ROI from the given dose grid. Returns
        the DVH data. If no binary mask is specified, one will be computed for
        the dvh.roi. The value of each voxel contained within the mask is used
        to weight the dose data in the final histogram. Input parameter "bins"
        may be specified as an integer number of bins to include in the histogram,
        or it may be a vector of bin edges (see np.histogram).

        If an edge_voxel_weight is specified, all edge voxels in the x-y plane of
        the binary mask are multipled by the specified weight.
        '''
        self.dose_mask = self.compute_dose_mask()
        (self.dose_data, self.volume_data), frac_outside_dosegrid = compute_dvh(
            dose_mask=self.dose_mask)
        if frac_outside_dosegrid is not None:
            self.fraction_outside_dosegrid = frac_outside_dosegrid

        self.data = np.vstack((self.dose_data, self.volume_data)).T
        return self.data

    def get_dose_to_volume(self, v):
        '''
        Get the dose delivered to v percent of the volume.

        Keyword arguments:
            :v:     fraction of the volume (from 0 to 1)
        Returns:
            :d:     dose delivered to specified volume in cGy
        '''
        if self.data is None:
            self.compute_dvh()

        idx = (np.abs(self.data[:, 1] - v)).argmin()
        return self.data[idx, 0]

    def get_volume_with_dose(self, d):
        '''
        Get the dose delivered to v percent of the volume.

        Keyword arguments:
            :d:     dose value
        Returns:
            :v:     fraction of volume receiving specified dose
        '''
        if self.data is None:
            self.compute_dvh()

        if d <= self.max_dose:
            idx = (np.abs(self.data[:, 0] - d)).argmin()
            return self.data[idx, 1]
        else:
            return 0.0


from threading import Thread, Event
from domogik.scenario.parameters.abstract import AbstractParameter
#from domogik.common.cron import CronExpression
import time
from domogik.common.utils import get_midnight_timestamp

class TimeHHMMParameter(AbstractParameter):
    """ This parameter  simply provides a time entry : hh:mm
    """

    def __init__(self, log = None, trigger = None):
        AbstractParameter.__init__(self, log, trigger)
        self.set_type("integer")
        self.add_expected_entry("time", "string", "Time (hh:mm)")

    def evaluate(self):
        """ Return string, or none if no string entered yet
        """
        params = self.get_parameters()
        tmp = params["time"].split(":")
        if len(tmp) != 2:
            self._log.warning("Bad time format for '{0}'. Expected : 'hh:mm'".format(params["time"]))
            self.expr = None
        try:
            given_time_in_minutes = int(tmp[0])*60 + int(tmp[1])
        except:  # bad format!
            self._log.warning("Bad time format for '{0}'. Expected : 'hh:mm'".format(params["time"]))
            self.expr = None
        return int(given_time_in_minutes)

    def destroy(self):
        """ Destroy fetch thread
        """
        AbstractParameter.destroy(self)


"""Visual helpers utilizing and extending OpenCV library"""

import cv2
import numpy as np

from .misc import clip_points

def resize(image, width=None, height=None, interp=None, pad=False, pad_color=0):
    """Resize the image down to or up to the specified size.

    Specify width or height for the image size if you want to preserve the aspect ratio of the image.
    You can pad your image with additional border to preserve the aspect ration if needed for custom
    width and height.

    :param numpy.ndarray image: input image
    :param int width: output image width
    :param int height: output image height
    :param int interp: interpolation used to resize the image
    :param bool pad: pad image with borders to preserve aspect ration
    :param (int, int, int) pad_color: pad borders color

    :returns: output image
    :rtype: numpy.ndarray
    """
    src_h, src_w = image.shape[:2]

    if width is None and height is None:
        # No size specified - return original image
        return image

    if width is None:
        # Calculate the ratio of the height and construct the dimensions
        ratio = height / float(src_h)
        width = int(src_w * ratio)

    if height is None:
        # Calculate the ratio of the width and construct the dimensions
        ratio = width / float(src_w)
        height = int(src_h * ratio)

    if width == src_w and height == src_h:
        # There is no change in size - return original image
        return image

    # Select best interpolation method if not specified
    if interp is None:
        if src_h > height or src_w > width:  # Shrinking image
            interp = cv2.INTER_AREA
        else:  # Stretching image
            interp = cv2.INTER_CUBIC

    src_aspect = src_w / src_h  # Aspect ratio of the source image
    aspect = width / height  # Aspect ratio of the new image

    # Compute scaling
    if src_aspect > 1 and aspect < 1 or src_aspect < 1 and aspect < 1:
        new_w = width
        new_h = np.round(new_w / src_aspect).astype(int) if pad else height
    elif src_aspect > 1 and aspect > 1 or src_aspect < 1 and aspect > 1:
        new_h = height
        new_w = np.round(new_h * src_aspect).astype(int) if pad else width
    else:  # Square image
        new_h, new_w = height, width

    # Resize image
    image = cv2.resize(image, (new_w, new_h), interpolation=interp)

    if pad:
        if len(image.shape) is 3 and not isinstance(pad_color, (list, tuple, np.ndarray)):
            # Color image - set pad color as RGB
            pad_color = [pad_color] * 3

        if aspect > 1:
            pad_horz = (width - new_w) / 2
            pad_left, pad_right = np.floor(pad_horz).astype(int), np.ceil(pad_horz).astype(int)
            pad_top, pad_bot = 0, 0
        elif aspect < 1:
            pad_vert = (height - new_h) / 2
            pad_top, pad_bot = np.floor(pad_vert).astype(int), np.ceil(pad_vert).astype(int)
            pad_left, pad_right = 0, 0
        else:
            pad_left, pad_right, pad_top, pad_bot = 0, 0, 0, 0

        # Pad the image with borders
        image = cv2.copyMakeBorder(image, pad_top, pad_bot, pad_left, pad_right,
                                   borderType=cv2.BORDER_CONSTANT, value=pad_color)

    return image

def rectangle_overlay(image, pt1, pt2, color, alpha):
    """Renders the rectangular overlay on the image.

    :param numpy.ndarray image: input image
    :param (int, int) pt1: bottom-left corner of the rectangle
    :param (int, int) pt2: top-right corner of the rectangle
    :param (int, int, int) color: rectangle color
    :param float alpha: alpha for overlay transparency
    """
    h, w = image.shape[:2]
    pt1, pt2 = clip_points([pt1, pt2], w, h)

    roi = image[pt1[1]:pt2[1], pt1[0]:pt2[0]]
    rect = np.zeros(roi.shape, dtype=np.uint8)
    rect[::] = color
    cv2.addWeighted(rect, alpha, roi, 1 - alpha, 0, roi)

def put_text(image, text, org, font_face=cv2.FONT_HERSHEY_SIMPLEX, font_scale=0.5,
             color=(0, 0, 0), bg_color=None, bg_alpha=1, thickness=1, line_type=cv2.LINE_AA,
             org_pos="tl", padding=2):
    """Renders the specified text string in the image.

    :param numpy.ndarray image: input image
    :param str text: text string to be drawn
    :param (int, int) org: corner of the text string in the image
        (the position of the corner is determined by org_pos parameter)
    :param int font_face: font type
    :param float font_scale: font scale factor
    :param (int, int, int) color: text color
    :param (int, int, int) bg_color: text background color
    :param float bg_alpha: text background alpha
    :param int thickness: thickness of the lines used to draw a text
    :param int line_type: line type
    :param str org_pos: corner position (org):
        'tl' - top-left, 'tr' - top-right, 'bl' - bottom-left, 'br' - bottom-right
    :param int padding: text padding
    """
    x, y = org
    ret, baseline = cv2.getTextSize(text, font_face, font_scale, thickness)

    # Calculate text and background box coordinates
    if org_pos == "tl":  # top-left origin
        bg_rect_pt1 = (x, y)
        bg_rect_pt2 = (x + ret[0] + 2 * padding, y + ret[1] + baseline + 2 * padding)
        text_org = (x + padding, y + ret[1] + padding)
    elif org_pos == "tr":  # top-right origin
        bg_rect_pt1 = (x - ret[0] - 2 * padding, y)
        bg_rect_pt2 = (x, y + ret[1] + baseline + 2 * padding)
        text_org = (x - ret[0] - padding, y + ret[1] + padding)
    elif org_pos == "bl":  # bottom-left origin
        bg_rect_pt1 = (x, y - ret[1] - baseline - 2 * padding)
        bg_rect_pt2 = (x + ret[0] + 2 * padding, y)
        text_org = (x + padding, y - padding - baseline)
    elif org_pos == "br":  # bottom-right origin
        bg_rect_pt1 = (x - ret[0] - 2 * padding, y - ret[1] - baseline - 2 * padding)
        bg_rect_pt2 = (x, y)
        text_org = (x - ret[0] - padding, y - baseline - padding)

    if bg_color:
        # Draw background box
        rectangle_overlay(image, bg_rect_pt1, bg_rect_pt2, bg_color, bg_alpha)

    cv2.putText(image,
                text=text,
                org=text_org,
                fontFace=font_face,
                fontScale=font_scale,
                color=color,
                thickness=thickness,
                lineType=line_type)

    return bg_rect_pt1, bg_rect_pt2


from Adafruit_IO import Client
from ConfigParser import SafeConfigParser
import subprocess
import time
import os

# Uses ConfigParser to grab parameters from file
config = SafeConfigParser()
config.read('/home/pi/projects/RPi_AdafruitIO_SysStats/aio.cfg')
ADAFRUIT_IO_USERNAME = config.get('aio', 'user')
ADAFRUIT_IO_KEY = config.get('aio', 'key')
dashboard = config.get('aio', 'dashboard')
sleep = config.get('default', 'sleep')

# Create an instance of the REST client.
aio = Client(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY)

while True:

    # Shell scripts for system monitoring from here:
    # https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-$
    # Added if statement to check if an external disk is attached at /dev/sda1 and if true gathers its info as Disk2
    cmd = "top -bn1 | grep load | awk '{printf \"%.2f\", $(NF-2)}'"
    CPU = subprocess.check_output(cmd, shell=True)
    cmd = "vcgencmd measure_temp | cut -d '=' -f 2 | head --bytes -3"
    Temp = subprocess.check_output(cmd, shell=True)
    cmd = "df -h | awk '$NF==\"/\"{printf \"%.2f\", $3}'"
    Disk1 = subprocess.check_output(cmd, shell=True)
    if os.path.exists("/dev/sda1"):
        cmd = "df -h | awk '$NF==\"/data\"{printf \"%.2f\", $3}'"
        Disk2 = subprocess.check_output(cmd, shell=True)
    cmd = "free -m | awk 'NR==2{printf \"%d\", $3}'"
    Mem = subprocess.check_output(cmd, shell=True)

    # send_data grabs dashboard from config file then combines all of it into a string.
    # Each Feed must use the Feed Key not just the name of the Feed.
    # The Feed Key is in the format of dashboard.feedname
    aio.send_data(dashboard + str('.') + str('cpuload'), CPU)
    aio.send_data(dashboard + str('.') + str('cputemp'), Temp)
    aio.send_data(dashboard + str('.') + str('disk1'), Disk1)
    if os.path.exists("/dev/sda1"):
        aio.send_data(dashboard + str('.') + str('disk2'), Disk2)
    aio.send_data(dashboard + str('.') + str('memusage'), Mem)

    time.sleep(float(sleep))


import enum
from collections import defaultdict
from typing import Callable, NoReturn, Any, Dict, List

class Event(enum.Enum):
    All = '*'
    ManagerProtocolValid = 'ManagerProtocolValid'
    ManagerProtocolClose = 'ManagerProtocolClose'

TypeEventHandler = Callable[[Event, Any], NoReturn]

class BroadCaster(object):
    def __init__(self):
        from server.manager_server import ManagerProtocol
        self.watchers = defaultdict(set)
        self.handlers: Dict[Event,  List[TypeEventHandler]] = defaultdict(list)
        self.manager_protocol: ManagerProtocol = None

    def listen_events(self, event: Event, payload):
        if event == Event.ManagerProtocolValid:
            self.manager_protocol = payload
        elif event == Event.ManagerProtocolClose:
            if self.manager_protocol is payload:
                self.manager_protocol = None

    def fire(self, event: Event, payload=None):
        assert event != Event.All, 'Event All cannot be fired'
        self.listen_events(event, payload)
        for handler in (self.watchers[Event.All] | self.watchers[event]):
            handler(event, payload)

    def add_watcher(self, event: Event, handler: TypeEventHandler):
        self.watchers[event].add(handler)
        self.handlers[handler].append(event)

    def remove_watcher(self, handler: TypeEventHandler):
        event_list = self.handlers.pop(handler, None)
        for event in event_list:
            self.watchers[event].discard(handler)


# %% import libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df=pd.read_csv("yeast.csv")

print(df.info())

df.drop(["SWISS-PROT"],axis=1,inplace = True)  #işimize yaramayan sütunu kaldırdık.
#%%
#MIT:0    NUC:1  CYT:2  ME1:3  ME2:4
#MEC3:5   EXC:6  VAC:7  ERL:8  POX:9
#  local:localization(bulunma konumu)
#  CYT (cytosolic or cytoskeletal)
#  NUC (nuclear) (nükleer)
#  MIT (mitochondrial)(mitokondriyal)
#  ME3 (membrane protein, no N-terminal signal)(membran proteini, N-terminal sinyali yok)
#  ME2 (membrane protein, uncleaved signal)(membran proteini, temizlenmemiş sinyal)
#  ME1 (membrane protein, cleaved signal)(membran proteini, bölünmüş sinyal)
#  EXC (extracellular)(hücre dışı)
#  VAC (vacuolar)(vakuolar)
#  POX (peroxisomal) (peroksizomal)
#  ERL (endoplasmic reticulum lumen)(endoplazmik retikulum lümeni)

df["local"]=[ 0 if each=="MIT" else each for each in df.local]
df["local"]=[ 1 if each=="NUC" else each for each in df.local]
df["local"]=[ 2 if each=="CYT" else each for each in df.local]
df["local"]=[ 3 if each=="ME1" else each for each in df.local]
df["local"]=[ 4 if each=="ME2" else each for each in df.local]
df["local"]=[ 5 if each=="ME3" else each for each in df.local]
df["local"]=[ 6 if each=="EXC" else each for each in df.local]
df["local"]=[ 7 if each=="VAC" else each for each in df.local]
df["local"]=[ 8 if each=="ERL" else each for each in df.local]
df["local"]=[ 9 if each=="POX" else each for each in df.local]

#%%

y=df.local.values
x_data=df.drop(["local"],axis=1)

# %%
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test=train_test_split(x_data,y,test_size=0.3,random_state=1)
# %%
# keras

from keras.models import Sequential
from keras.layers import Dense,Activation

#%%

model=Sequential()
model.add(Dense(16,input_dim=8))
model.add(Activation('relu'))
model.add(Dense(32))
model.add(Activation('relu'))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(optimizer="adam",loss="binary_crossentropy",metris=["accuracy"])

egitim=model.fit(x_train,y_train,epochs=100,validation_data=(x_test,y_test))

# %%
plt.plot(egitim.history['loss'])
plt.plot(egitim.history['val_loss'])
plt.title('model loss')
plt.xlabel('epochs')
plt.ylabel('loss values')
plt.legend(['loss','val_loss'],loc='lower right')
plt.show()

# %% cm
import sklearn.metrics as metrics
y_pred=model.predict_classes(x_test)
# %%
print("acc:",metrics.accuracy_score(y_test,y_pred))
# %%
print("cm:",metrics.confusion_matrix(y_test,y_pred))

# %%
print("f1:",metrics.f1_score(y_test,y_pred))

# %%
print(metrics.classification_report(y_test,y_pred))
# %% roc ve auc
probs=model.predict_proba(x_test)
fpr,tpr,threshold=metrics.roc_curve(y_test,probs)
roc_auc=metrics.auc(fpr,tpr)

plt.title("ROC")
plt.plot(fpr,tpr,label="AUC=%0.2f" %roc_auc)
plt.legend(loc="lower right")
plt.ylabel("TPR")
plt.xlabel("FPR")
plt.show()


"""
Volume and Volume Slice Rendering
=================================

Render a volume and volume slices. You should see:
* On the left: a raycasted volume fit snugly inside a red box.
* On the right: three orthogonal slices inside - and through the middle of - a green box.
* The volume has its corners darker and its very center is brighter.
"""
# test_example = true
# sphinx_gallery_pygfx_render = True

import numpy as np
from wgpu.gui.auto import WgpuCanvas, run
import pygfx as gfx

canvas = WgpuCanvas()
renderer = gfx.renderers.WgpuRenderer(canvas)

# Prepare a very small data volume. The data is integer and not uint8,
# so its not interpolated (a wgpu restriction). In this case this is intended.
voldata = np.ones((3, 3, 3), np.int16) * 200
voldata[1:-1, :, :] = 600
voldata[:, 1:-1, :] = 600
voldata[:, :, 1:-1] = 600
voldata[1, 1, 1] = 800

# Create a texture, (wrapped in a geometry) for it
geo = gfx.Geometry(grid=gfx.Texture(voldata, dim=3))

# Prepare two 3x3x3 boxes to indicate the proper position
box1 = gfx.Mesh(
    gfx.box_geometry(3.1, 3.1, 3.1),
    gfx.MeshBasicMaterial(color=(1, 0, 0, 1), wireframe=True, wireframe_thickness=1),
)
box2 = gfx.Mesh(
    gfx.box_geometry(3.1, 3.1, 3.1),
    gfx.MeshBasicMaterial(color=(0, 1, 0, 1), wireframe=True, wireframe_thickness=1),
)

# In scene1 we show a raycasted volume
scene1 = gfx.Scene()
vol = gfx.Volume(geo, gfx.VolumeRayMaterial(clim=(0, 2000)))
vol.local.position = (-1, -1, -1)
scene1.add(vol, box1)

# In scene2 we show volume slices
scene2 = gfx.Scene()
slice1 = gfx.Volume(geo, gfx.VolumeSliceMaterial(clim=(0, 1000), plane=(0, 0, 1, 0)))
slice2 = gfx.Volume(geo, gfx.VolumeSliceMaterial(clim=(0, 1000), plane=(0, 1, 0, 0)))
slice3 = gfx.Volume(geo, gfx.VolumeSliceMaterial(clim=(0, 1000), plane=(1, 0, 0, 0)))
for slice in (slice1, slice2, slice3):
    slice.local.position = (-1, -1, -1)
scene2.add(slice1, slice2, slice3, box2)

# Prepare a camera so we can see the result in 3D
camera = gfx.PerspectiveCamera(90, 16 / 9, depth_range=(0.1, 2000))
camera.local.position = (3, 3, 1)
camera.look_at((0, 1, 0))

def animate():
    w, h = canvas.get_logical_size()
    renderer.render(
        scene1, camera, rect=(0.0 * w, 0.0 * h, 0.5 * w, 1.0 * h), flush=False
    )
    renderer.render(
        scene2, camera, rect=(0.5 * w, 0.0 * h, 0.5 * w, 1.0 * h), flush=False
    )
    renderer.flush()

canvas.request_draw(animate)

if __name__ == "__main__":
    run()


import scipy as sp
import scipy.linalg as spla
import scipy.sparse as sps
import scipy.sparse.linalg as spsla

from householder import lcd

def pcg(A, b, x_0, P=None):
    if P is None:
        P = sp.identity(A.shape[0])
    P_inv = spla.inv(P)
    print('starting')
    r_0 = b - A @ x_0

    r_prev = r = r_0
    r_prod = (r.T @ P_inv @ (r))
    x = x_0
    p = P_inv @ r_0

    k = 0
    while True:
        k += 1
        Ap = A @ p
        alpha = (r_prod / (p.T @ Ap)).item()
        x = x + alpha*p # x_k initially stores x_{k-1}

        r_prev = r
        r_prev_prod = r_prod
        r = r - alpha * Ap
        r_prod = (r.T @ P_inv @ (r))
        beta = (r_prod / r_prev_prod).item()
        p = P_inv @ (r) + beta * p
        print(k, spla.norm(r))

        if spla.norm(r) <= 10**-12:
            print('terminating from residual')
            break

    print(x)
    print(A @ x)
    return x

if __name__ == "__main__":
    P = None
    N = 50
    A = lcd(0, 0, N)
    b = sp.ones((N**2, 1))
    x_0 = sp.zeros((N**2, 1))
    # pcg(A, b, x_0, sp.diag(sp.diag(A)))
    print()
    # P = spsla.spilu(A).solve(b)
    P = sp.diag(sp.diag(A.todense()))
    # P = spla.inv(P)
    # print(P)
    sol1 = pcg(A.todense(), b, x_0, P)

    sol2, info = spsla.cg(lcd(0, 0, N), b, x_0)
    sol2 = sol2.reshape((sol2.shape[0], 1))

    print(sol1 - sol2)


import random

def pivot(arr, k):
	n = len(arr)
	r = random.randrange(0, n)
	pivot = arr[r]
	arr[n-1], arr[r] = arr[r], arr[n-1]
	i = -1
	j = 0

	while(j < n-1):
		if arr[j] < pivot:
			i += 1
			if  i!=j: arr[i], arr[j] = arr[j], arr[i]
		j += 1
	arr[i+1],arr[n-1] = arr[n-1], arr[i+1]

	return i+1

def median(arr, k):
	n = len(arr)
	if n == 1:
		return arr[0]
	v = pivot(arr, k)
	if v == k:
		return arr[k]
	else:
		if v < k:
			return median(arr[v:], k-v)
		else:
			return median(arr[:v], k)

arr = list(map(int, input().split()))
print(median(arr, 2	))


from sys import exit, stdin, setrecursionlimit
from bisect import bisect_left, bisect_right, insort_left, insort_right
from collections import defaultdict, deque
from heapq import heappop, heappush, heapify
from itertools import permutations, combinations, accumulate
from math import sqrt
INF = 10**15
MOD = 998244353

N, M = map(int, input().split())
friends = [[0] * 4*N for _ in range(4*N)]
for _ in range(M):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    friends[a][b] = 1
    friends[b][a] = 1

#dp[i][j]:= i,i+1,i+2,,,i+2*j-1人の2*j人の生徒をj組の組み合わせにする通り数
dp = [[0] * (N+1) for _ in range(4*N)]
#初期化: 生徒iから数えて0組を取り除く場合の数を1とする
for i in range(4*N):
    dp[i][0] = 1

#逆元によるnCkの高速計算
def inv(n): # MODを法とした逆元
    return pow(n, MOD-2, MOD)

mx = 300
fact = [1] * (mx+1) # 階乗を格納するリスト
for i in range(mx):
    fact[i+1] = fact[i] * (i+1) % MOD # 階乗を計算

def comb(n, k):
    return (fact[n] * inv(fact[n-k]) * inv(fact[k])) % MOD # comb(n,k) = n!/((n-k)!k!)

for j in range(1, N+1):
    for i in range(2*N):
        for k in range(1, j+1):
            dp[i][j] += ((dp[i+1][k-1] * dp[i+2*k][j-k])%MOD) * friends[i][i+2*k-1] * comb(j, k)
            dp[i][j] %= MOD

print(dp[0][N])


import pytest
from requests.exceptions import ConnectionError, MissingSchema

from ghapi.connection import Connection

@pytest.mark.parametrize(
    "token, url, expected_error, expected_repr",
    [
        [None, "hello", MissingSchema, ""],
        [None, "https://imaginary.website.dev", ConnectionError, ""],
        [None, "https://api.github.com", None, "Connection(url='https://api.github.com')"],
        ["DUMMY_TOKEN", "https://api.github.com", None, "Connection(url='https://api.github.com')"],
    ],
)
def test_connection_repr(token, url, expected_error, expected_repr):
    if expected_error is None:
        conn = Connection(token, url)
        assert str(conn) == expected_repr
    else:
        with pytest.raises(expected_error):
            Connection(token, url)

@pytest.mark.parametrize(
    "route, expected_url",
    [
        ["", "https://api.github.com"],
        ["/", "https://api.github.com/"],
        ["repos", "https://api.github.com/repos"],
        ["/repos", "https://api.github.com/repos"],
    ],
)
def test_connection_resolve(route, expected_url):
    conn = Connection()
    assert conn.resolve(route) == expected_url

@pytest.mark.parametrize(
    "token, is_error, expected_header",
    [
        [None, True, {}],
        ["", True, {}],
        ["DUMMY_TOKEN", False, {"Authorization": "Bearer DUMMY_TOKEN"}],
        ["TOKEN_BIS", False, {"Authorization": "Bearer TOKEN_BIS"}],
    ],
)
def test_connection_authorization(token, is_error, expected_header):
    conn = Connection(token)
    if is_error:
        with pytest.raises(ValueError):
            conn.authorization
    else:
        assert conn.authorization == expected_header


import argparse
import os
import infra.interfaces
import infra.path
import infra.network
import sys

from loguru import logger as LOG

def absolute_path_to_existing_file(arg):
    if not os.path.isabs(arg):
        raise argparse.ArgumentTypeError("Must provide absolute path")
    if not os.path.isfile(arg):
        raise argparse.ArgumentTypeError(f"{arg} is not a file")
    return arg

def nodes(args, n):
    return [
        infra.interfaces.HostSpec(
            rpc_interfaces={
                infra.interfaces.PRIMARY_RPC_INTERFACE: infra.interfaces.RPCInterface.from_args(
                    args
                )
            }
        )
        for _ in range(n)
    ]

def min_nodes(args, f):
    """
    Minimum number of nodes allowing 'f' faults
    """
    n = 2 * f + 1
    return nodes(args, n)

def max_nodes(args, f):
    """
    Maximum number of nodes allowing no more than 'f'
    faults for the consensus variant.
    """
    return min_nodes(args, f + 1)[:-1]

def max_f(args, number_nodes):
    return (number_nodes - 1) // 2

def cli_args(
    add=lambda x: None,
    parser=None,
    accept_unknown=False,
    ledger_chunk_bytes_override=None,
):
    LOG.remove()
    LOG.add(
        sys.stdout,
        format="<green>{time:HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
    )

    if parser is None:
        parser = argparse.ArgumentParser(
            formatter_class=argparse.ArgumentDefaultsHelpFormatter
        )
    parser.add_argument(
        "-b",
        "--binary-dir",
        help="Path to CCF binaries (cchost, scurl, keygenerator)",
        default=".",
    )
    parser.add_argument(
        "--oe-binary",
        help="Path to Open Enclave binary folder",
        type=str,
        default="/opt/openenclave/bin/",
    )
    parser.add_argument(
        "--library-dir",
        help="Path to CCF libraries (enclave images)",
        default=None,
    )
    parser.add_argument(
        "-d",
        "--debug-nodes",
        help="List of node ids. Nodes that are specified will need to be started manually",
        action="append",
        default=[],
    )
    parser.add_argument(
        "--perf-nodes",
        help="List of node ids. Nodes that should be run under perf, capturing performance data",
        action="append",
        default=[],
    )
    # "virtual" is deprecated (use enclave-platform)
    parser.add_argument(
        "-e",
        "--enclave-type",
        help="Enclave type",
        default=os.getenv("TEST_ENCLAVE", os.getenv("DEFAULT_ENCLAVE_TYPE", "release")),
        choices=("release", "debug", "virtual"),
    )
    parser.add_argument(
        "-t",
        "--enclave-platform",
        help="Enclave platform (Trusted Execution Environment)",
        default=os.getenv("TEST_ENCLAVE", os.getenv("DEFAULT_ENCLAVE_PLATFORM", "sgx")),
        choices=("sgx", "snp", "virtual"),
    )
    log_level_choices = ("trace", "debug", "info", "fail", "fatal")
    default_log_level = "info"
    parser.add_argument(
        "--host-log-level",
        help="Runtime host log level",
        default=default_log_level,
        choices=log_level_choices,
    )
    parser.add_argument(
        "--enclave-log-level",
        help="Runtime enclave log level",
        default=default_log_level,
        choices=log_level_choices,
    )
    parser.add_argument(
        "--log-format-json",
        help="Set node stdout log format to JSON",
        action="store_true",
        default=False,
    )
    parser.add_argument(
        "-p",
        "--package",
        help="The enclave package to load (e.g., liblogging)",
    )
    parser.add_argument(
        "--constitution",
        help="One or more paths to constitution script fragments",
        action="append",
        default=[],
    )
    parser.add_argument("--js-app-bundle", help="Path to js app bundle")
    parser.add_argument(
        "--jwt-issuer",
        help="Path to JSON file with JWT issuer definition",
        action="append",
        default=[],
    )
    parser.add_argument(
        "-o",
        "--network-only",
        help="Only start the network, do not run the client, and wait.",
        action="store_true",
    )
    parser.add_argument(
        "--sig-tx-interval",
        help="Number of transactions between signatures",
        type=int,
        default=5000,
    )
    parser.add_argument(
        "--sig-ms-interval",
        help="Milliseconds between signatures",
        type=int,
        default=100,
    )
    parser.add_argument(
        "--memory-reserve-startup",
        help="Reserve this many bytes of memory on startup, to simulate memory restrictions",
        type=int,
    )
    parser.add_argument(
        "--election-timeout-ms",
        help="Raft maximum election timeout for each node in the network",
        type=int,
        default=os.getenv("ELECTION_TIMEOUT_MS") or 4000,
    )
    parser.add_argument(
        "--consensus-update-timeout-ms",
        help="Raft maximum timeout before primary sends updates",
        type=int,
        default=100,
    )
    parser.add_argument(
        "--consensus",
        help="Consensus",
        default="CFT",
        choices=("CFT",),
    )
    parser.add_argument(
        "--worker-threads",
        help="number of worker threads inside the enclave",
        type=int,
        default=0,
    )
    parser.add_argument(
        "--pdb", help="Break to debugger on exception", action="store_true"
    )
    parser.add_argument(
        "--workspace",
        help="Temporary directory where nodes store their logs, ledgers, quotes, etc.",
        default=os.getenv("WORKSPACE", os.path.join(os.getcwd(), "workspace")),
    )

    default_label = os.path.splitext(os.path.basename(sys.argv[0]))[0]
    parser.add_argument(
        "--label", help="Unique identifier for the test", default=default_label
    )
    parser.add_argument(
        "--throws-if-reqs-not-met",
        help="Throws if test requirements are not met, skip test otherwise",
        action="store_true",
        default=True,
    )
    parser.add_argument(
        "--sn",
        help="Subject Name in node certificate, eg. CN=CCF Node",
    )
    parser.add_argument(
        "--subject-alt-names",
        help="Subject Alternative Name in node certificate. Can be either iPAddress:xxx.xxx.xxx.xxx, or dNSName:sub.domain.tld",
        action="append",
        default=[],
    )
    parser.add_argument(
        "--participants-curve",
        help="Curve to use for member and user identities",
        default=infra.network.EllipticCurve.secp384r1.name,
        type=lambda curve: infra.network.EllipticCurve[curve],
        choices=list(infra.network.EllipticCurve),
    )
    parser.add_argument(
        "--join-timer-s",
        help="Timer period when trying to join an existing network",
        type=int,
        default=1,
    )
    parser.add_argument(
        "--initial-member-count",
        help="Number of members when initializing the network",
        type=int,
        default=int(os.getenv("INITIAL_MEMBER_COUNT", "3")),
    )
    parser.add_argument(
        "--initial-operator-provisioner-count",
        help="Number of additional members with is_operator_provisioner set in their member_data when initializing the network",
        type=int,
        default=0,
    )
    parser.add_argument(
        "--initial-operator-count",
        help="Number of additional members with is_operator set in their member_data when initializing the network",
        type=int,
        default=0,
    )
    parser.add_argument(
        "--initial-user-count",
        help="Number of users when initializing the network",
        type=int,
        default=1,
    )
    parser.add_argument(
        "--initial-recovery-member-count",
        help="Number of initial members that are handed recovery shares",
        type=int,
        default=int(os.getenv("INITIAL_MEMBER_COUNT", "3")),
    )
    parser.add_argument(
        "--ledger-recovery-timeout",
        help="On recovery, maximum timeout (s) while reading the ledger",
        type=int,
        default=30,
    )
    parser.add_argument(
        "--ledger-chunk-bytes",
        help="Size (bytes) at which a new ledger chunk is created",
        type=str,
        default=ledger_chunk_bytes_override or "20KB",
    )
    parser.add_argument(
        "--snapshot-tx-interval",
        help="Number of transactions between two snapshots",
        type=int,
        default=10,
    )
    parser.add_argument(
        "--max-open-sessions",
        help="Soft cap on max open TLS sessions on each node",
        default=1000,
    )
    parser.add_argument(
        "--max-open-sessions-hard",
        help="Hard cap on max open TLS sessions on each node",
        default=1010,
    )
    parser.add_argument(
        "--jwt-key-refresh-interval-s",
        help="JWT key refresh interval in seconds",
        type=int,
        default=1800,
    )
    parser.add_argument(
        "--common-read-only-ledger-dir",
        help="Location of read-only ledger directory available to all nodes",
        type=str,
        default=None,
    )
    parser.add_argument(
        "--curve-id",
        help="Elliptic curve to use as for node and network identities",
        default=infra.network.EllipticCurve.secp384r1,
        type=lambda curve: infra.network.EllipticCurve[curve],
        choices=list(infra.network.EllipticCurve),
    )
    parser.add_argument(
        "--ccf-version",
        help="CCF version of local checkout",
        type=str,
    )
    parser.add_argument(
        "--initial-node-cert-validity-days",
        help="Initial validity period in days for certificates of nodes before the first certificate renewal",
        type=int,
        default=1,
    )
    parser.add_argument(
        "--initial-service-cert-validity-days",
        help="Initial validity period in days for service certificate before the first certificate renewal",
        type=int,
        default=1,
    )
    parser.add_argument(
        "--maximum-node-certificate-validity-days",
        help="Maximum allowed validity period in days for certificates of trusted nodes",
        type=int,
        default=365,
    )
    parser.add_argument(
        "--maximum-service-certificate-validity-days",
        help="Maximum allowed validity period in days for service certificate",
        type=int,
        default=365,
    )
    parser.add_argument(
        "--reconfiguration-type",
        help="Reconfiguration type",
        default="OneTransaction",
        choices=("OneTransaction", "TwoTransaction"),
    )
    parser.add_argument(
        "--previous-service-identity-file",
        help="Path to previous service identity file",
        type=str,
        default="",
    )
    parser.add_argument(
        "--config-file",
        help="Absolute path to node JSON configuration file",
        default=None,
    )
    parser.add_argument(
        "--max-http-body-size",
        help="Maximum allowed size for body of single HTTP request",
        default=1024 * 1024,  # 1MB
    )
    parser.add_argument(
        "--max-http-header-size",
        help="Maximum allowed size of single header in single HTTP request",
        default=1024 * 16,  # 16KB
    )
    parser.add_argument(
        "--max-http-headers-count",
        help="Maximum number of headers in single HTTP request",
        default=256,
        type=int,
    )
    parser.add_argument(
        "--http2",
        help="Enable HTTP/2 for all interfaces",
        action="store_true",
        default=False,
    )
    parser.add_argument(
        "--snp-endorsements-servers",
        help="Servers used to retrieve attestation report endorsement certificates (AMD SEV-SNP only)",
        action="append",
        default=[],
    )
    parser.add_argument(
        "--forwarding-timeout-ms",
        help="Timeout for forwarded RPC calls (in milliseconds)",
        type=int,
        default=infra.interfaces.DEFAULT_FORWARDING_TIMEOUT_MS,
    )
    parser.add_argument(
        "--tick-ms",
        help="Tick period (in milliseconds)",
        type=int,
        default=1,
    )
    parser.add_argument(
        "--max-msg-size-bytes",
        help="Maximum message size (bytes) allowed on the ring buffer",
        type=str,
        default="16MB",
    )
    parser.add_argument(
        "--gov-api-version",
        help="api-version to be used for accessing /gov endpoints",
        type=str,
        default=infra.clients.API_VERSION_PREVIEW_01,
    )

    add(parser)

    if accept_unknown:
        args, unknown_args = parser.parse_known_args()
    else:
        args = parser.parse_args()

    args.binary_dir = os.path.abspath(args.binary_dir)

    if args.library_dir is None:
        if os.path.basename(args.binary_dir) == "bin":
            args.library_dir = os.path.join(args.binary_dir, os.pardir, "lib")
        else:
            args.library_dir = args.binary_dir

    if not args.package and args.js_app_bundle:
        args.package = "libjs_generic"

    if accept_unknown:
        return args, unknown_args
    else:
        return args


# **************************************************************************** #
#                                                                              #
#                                                         :::      ::::::::    #
#    update.py                                          :+:      :+:    :+:    #
#                                                     +:+ +:+         +:+      #
#    By: atrouill <atrouill@student.42.fr>          +#+  +:+       +#+         #
#                                                 +#+#+#+#+#+   +#+            #
#    Created: 2021/09/08 10:01:25 by atrouill          #+#    #+#              #
#    Updated: 2022/05/03 17:27:38 by atrouill         ###   ########.fr        #
#                                                                              #
# **************************************************************************** #

import requests
import pathlib
from colorama import Style, Fore
import genmake.config as config
import os.path

def	get_last_version() -> dict:
	origin_infos = dict()
	headers = {"Accept": "application/vnd.github.v3+json"}
	url = "https://api.github.com/repos/arthur-trt/genmake/releases"
	try:
		r = requests.get(url, headers=headers)
	except:
		print("Error while trying to get the last version")
		return (None)
	if (r.status_code == 200):
		r = r.json()
		origin_infos["version"] = r[0]['tag_name']
		origin_infos["changelog"] = r[0]['body']
		return (origin_infos)
	return (None)

def obtain_generator_version() -> str:
	path = pathlib.Path("./Makefile")
	try:
		makefile = open(path, 'r')
	except:
		return (None)
	lines = makefile.readlines()
	for line in lines:
		if "# genmake v" in line:
			return(line.split(" ")[2].strip())

def	check_update():
	origin = get_last_version()
	gen = obtain_generator_version()

	if origin == None or gen == None:
		return (False)

	if (origin["version"] != ("v" + config.VERSION)):
		print(Fore.YELLOW, end='')
		print("A new version is available.")
		print("Please update with : 'python3 -m pip install --upgrade genmake'")
		print("Changelog :")
		changelog = origin["changelog"].split('\n')
		for line in changelog:
			print("\t" + line)
		print(Style.RESET_ALL)

	elif (("v" + config.VERSION) != gen) and (os.path.isfile('./Makefile')):
		print(Fore.YELLOW, end='')
		print("Your Makefile was generated with an old version of genmake")
		print("It is recommended to run 'genmake --remake' to correct possible bugs")
		print(Style.RESET_ALL)


import os
import json

# create a json description of all the projects with links and names
# frontend will embed the json and display on the docs page

github = "https://www.github.com/mailslurp/examples/tree/master/"

directories = next(os.walk('.'))[1]
directories = [path for path in directories if "." not in path]

links = list(map(lambda path: { "name": path.replace("-"," ").title(), "url": github + path}, directories))

json_object = json.dumps({ "links": links }, indent = 2)

with open('.manifest.json', 'w+') as output_file:
    output_file.write(json_object)

print("Build complete")


from matplotlib import pyplot as plt
import numpy as np

mu, sigma = np.mean(CHT_array), np.std(CHT_array)
fig, ax = plt.subplots(figsize=(10,6))

x1 = [i*50 for i in range(21)]
#plt.figure(figsize=(10,6))
n, bins, patches = ax.hist(CHT_list,
                            facecolor='blue',
                            alpha=0.6,
                            density=1,
                            bins=x1)

y = ((1 / (np.sqrt(2 * np.pi) * sigma)) *
     np.exp(-0.5 * (1 / sigma * (bins - mu))**2))
ax.plot(bins, y, '--')

plt.xlim(0, 1000)
plt.grid(True)
plt.xticks(x1)
ax.tick_params(axis="y", labelsize=20)
#plt.grid(axis='y', alpha=0.75)
fig.tight_layout()
plt.show()


import copy

from oslo.config import cfg

from cinder import context
from cinder import db
from cinder.openstack.common import jsonutils
from cinder import test
from cinder.volume import rpcapi as volume_rpcapi

CONF = cfg.CONF

class VolumeRpcAPITestCase(test.TestCase):

    def setUp(self):
        super(VolumeRpcAPITestCase, self).setUp()
        self.context = context.get_admin_context()
        vol = {}
        vol['host'] = 'fake_host'
        vol['availability_zone'] = CONF.storage_availability_zone
        vol['status'] = "available"
        vol['attach_status'] = "detached"
        vol['metadata'] = {"test_key": "test_val"}
        volume = db.volume_create(self.context, vol)

        snpshot = {
            'volume_id': 'fake_id',
            'status': "creating",
            'progress': '0%',
            'volume_size': 0,
            'display_name': 'fake_name',
            'display_description': 'fake_description'}
        snapshot = db.snapshot_create(self.context, snpshot)
        self.fake_volume = jsonutils.to_primitive(volume)
        self.fake_volume_metadata = volume["volume_metadata"]
        self.fake_snapshot = jsonutils.to_primitive(snapshot)
        self.fake_reservations = ["RESERVATION"]

    def test_serialized_volume_has_id(self):
        self.assertIn('id', self.fake_volume)

    def _test_volume_api(self, method, rpc_method, **kwargs):
        ctxt = context.RequestContext('fake_user', 'fake_project')

        if 'rpcapi_class' in kwargs:
            rpcapi_class = kwargs['rpcapi_class']
            del kwargs['rpcapi_class']
        else:
            rpcapi_class = volume_rpcapi.VolumeAPI
        rpcapi = rpcapi_class()
        expected_retval = 'foo' if method == 'call' else None

        target = {
            "version": kwargs.pop('version', rpcapi.BASE_RPC_API_VERSION)
        }

        if 'request_spec' in kwargs:
            spec = jsonutils.to_primitive(kwargs['request_spec'])
            kwargs['request_spec'] = spec

        expected_msg = copy.deepcopy(kwargs)
        if 'volume' in expected_msg:
            volume = expected_msg['volume']
            del expected_msg['volume']
            expected_msg['volume_id'] = volume['id']
        if 'snapshot' in expected_msg:
            snapshot = expected_msg['snapshot']
            del expected_msg['snapshot']
            expected_msg['snapshot_id'] = snapshot['id']
        if 'host' in expected_msg:
            del expected_msg['host']
        if 'dest_host' in expected_msg:
            dest_host = expected_msg['dest_host']
            dest_host_dict = {'host': dest_host.host,
                              'capabilities': dest_host.capabilities}
            del expected_msg['dest_host']
            expected_msg['host'] = dest_host_dict
        if 'new_volume' in expected_msg:
            volume = expected_msg['new_volume']
            del expected_msg['new_volume']
            expected_msg['new_volume_id'] = volume['id']

        if 'host' in kwargs:
            host = kwargs['host']
        else:
            host = kwargs['volume']['host']

        target['server'] = host
        target['topic'] = '%s.%s' % (CONF.volume_topic, host)

        self.fake_args = None
        self.fake_kwargs = None

        real_prepare = rpcapi.client.prepare

        def _fake_prepare_method(*args, **kwds):
            for kwd in kwds:
                self.assertEqual(kwds[kwd], target[kwd])
            return rpcapi.client

        def _fake_rpc_method(*args, **kwargs):
            self.fake_args = args
            self.fake_kwargs = kwargs
            if expected_retval:
                return expected_retval

        self.stubs.Set(rpcapi.client, "prepare", _fake_prepare_method)
        self.stubs.Set(rpcapi.client, rpc_method, _fake_rpc_method)

        retval = getattr(rpcapi, method)(ctxt, **kwargs)

        self.assertEqual(retval, expected_retval)
        expected_args = [ctxt, method]

        for arg, expected_arg in zip(self.fake_args, expected_args):
            self.assertEqual(arg, expected_arg)

        for kwarg, value in self.fake_kwargs.items():
            self.assertEqual(value, expected_msg[kwarg])

    def test_create_volume(self):
        self._test_volume_api('create_volume',
                              rpc_method='cast',
                              volume=self.fake_volume,
                              host='fake_host1',
                              request_spec='fake_request_spec',
                              filter_properties='fake_properties',
                              allow_reschedule=True,
                              snapshot_id='fake_snapshot_id',
                              image_id='fake_image_id',
                              source_volid='fake_src_id',
                              version='1.4')

    def test_create_volume_serialization(self):
        request_spec = {"metadata": self.fake_volume_metadata}
        self._test_volume_api('create_volume',
                              rpc_method='cast',
                              volume=self.fake_volume,
                              host='fake_host1',
                              request_spec=request_spec,
                              filter_properties='fake_properties',
                              allow_reschedule=True,
                              snapshot_id='fake_snapshot_id',
                              image_id='fake_image_id',
                              source_volid='fake_src_id',
                              version='1.4')

    def test_delete_volume(self):
        self._test_volume_api('delete_volume',
                              rpc_method='cast',
                              volume=self.fake_volume,
                              unmanage_only=False,
                              version='1.15')

    def test_create_snapshot(self):
        self._test_volume_api('create_snapshot',
                              rpc_method='cast',
                              volume=self.fake_volume,
                              snapshot=self.fake_snapshot)

    def test_delete_snapshot(self):
        self._test_volume_api('delete_snapshot',
                              rpc_method='cast',
                              snapshot=self.fake_snapshot,
                              host='fake_host')

    def test_attach_volume_to_instance(self):
        self._test_volume_api('attach_volume',
                              rpc_method='call',
                              volume=self.fake_volume,
                              instance_uuid='fake_uuid',
                              host_name=None,
                              mountpoint='fake_mountpoint',
                              mode='ro',
                              version='1.11')

    def test_attach_volume_to_host(self):
        self._test_volume_api('attach_volume',
                              rpc_method='call',
                              volume=self.fake_volume,
                              instance_uuid=None,
                              host_name='fake_host',
                              mountpoint='fake_mountpoint',
                              mode='rw',
                              version='1.11')

    def test_detach_volume(self):
        self._test_volume_api('detach_volume',
                              rpc_method='call',
                              volume=self.fake_volume)

    def test_copy_volume_to_image(self):
        self._test_volume_api('copy_volume_to_image',
                              rpc_method='cast',
                              volume=self.fake_volume,
                              image_meta={'id': 'fake_image_id',
                                          'container_format': 'fake_type',
                                          'disk_format': 'fake_type'},
                              version='1.3')

    def test_initialize_connection(self):
        self._test_volume_api('initialize_connection',
                              rpc_method='call',
                              volume=self.fake_volume,
                              connector='fake_connector')

    def test_terminate_connection(self):
        self._test_volume_api('terminate_connection',
                              rpc_method='call',
                              volume=self.fake_volume,
                              connector='fake_connector',
                              force=False)

    def test_accept_transfer(self):
        self._test_volume_api('accept_transfer',
                              rpc_method='call',
                              volume=self.fake_volume,
                              new_user='e5565fd0-06c8-11e3-'
                                       '8ffd-0800200c9b77',
                              new_project='e4465fd0-06c8-11e3'
                                          '-8ffd-0800200c9a66',
                              version='1.9')

    def test_extend_volume(self):
        self._test_volume_api('extend_volume',
                              rpc_method='cast',
                              volume=self.fake_volume,
                              new_size=1,
                              reservations=self.fake_reservations,
                              version='1.14')

    def test_migrate_volume(self):
        class FakeHost(object):
            def __init__(self):
                self.host = 'host'
                self.capabilities = {}
        dest_host = FakeHost()
        self._test_volume_api('migrate_volume',
                              rpc_method='cast',
                              volume=self.fake_volume,
                              dest_host=dest_host,
                              force_host_copy=True,
                              version='1.8')

    def test_migrate_volume_completion(self):
        self._test_volume_api('migrate_volume_completion',
                              rpc_method='call',
                              volume=self.fake_volume,
                              new_volume=self.fake_volume,
                              error=False,
                              version='1.10')

    def test_retype(self):
        class FakeHost(object):
            def __init__(self):
                self.host = 'host'
                self.capabilities = {}
        dest_host = FakeHost()
        self._test_volume_api('retype',
                              rpc_method='cast',
                              volume=self.fake_volume,
                              new_type_id='fake',
                              dest_host=dest_host,
                              migration_policy='never',
                              reservations=None,
                              version='1.12')

    def test_manage_existing(self):
        self._test_volume_api('manage_existing',
                              rpc_method='cast',
                              volume=self.fake_volume,
                              ref={'lv_name': 'foo'},
                              version='1.15')


# Given a nucleotide p, we denote its complementary nucleotide as p.
# The reverse complement of a string Pattern = p1…pn is the string
# Pattern = pn … p1 formed by taking the complement of each nucleotide
# in Pattern, then reversing the resulting string. We will need the
# solution to the following problem throughout the book:

# Reverse Complement Problem: Reverse complement a nucleotide pattern.
#      Input: A DNA string Pattern.
#      Output: Pattern, the reverse complement of Pattern.

# CODE CHALLENGE: Solve the Reverse Complement Problem.

# Sample Input:
#      AAAACCCGGT

# Sample Output:
#      ACCGGGTTTT

dataset = input("What is the DNA string pattern? ")

forwardString = list(str(dataset.upper()))

def complement(DNAstring):
	for n, i in enumerate(DNAstring):
		if i == "A":
			DNAstring[n] = "T"
		elif i == "T":
			DNAstring[n] = "A"
		elif i == "C":
			DNAstring[n] = "G"
		elif i == "G":
			DNAstring[n] = "C"

	DNAstring.reverse()
	answer = ''.join(DNAstring)
	print(" ")
	print(answer)
	return None

complement(forwardString)


"""
28. Search a 2D Matrix
Write an efficient algorithm that searches for a value in an m x n matrix.

This matrix has the following properties:

Integers in each row are sorted from left to right.
The first integer of each row is greater than the last integer of the previous row.
Example
Example 1:
    Input:  [[5]],2
    Output: false

    Explanation:
	    false if not included.

Example 2:
    Input: [
        [1,  3,  5,  7],
        [10, 11, 16, 20],
        [23, 30, 34, 50]
    ],3
    Output: true

	Explanation:
	return true if included.
Challenge
O(log(n) + log(m)) time
"""

from typing import List

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix:
            return False
        m, n = len(matrix), len(matrix[0])
        start, end = 0, m - 1
        while start < end - 1:
            mid = (start + end) // 2
            if matrix[mid][0] > target:
                end = mid - 1
            else:
                start = mid
        x = start if matrix[end][0] > target else end
        if matrix[x][0] > target or matrix[x][n - 1] < target:
            return False
        start, end = 0, n - 1
        while start < end - 1:
            mid = (start + end) // 2
            if matrix[x][mid] > target:
                end = mid - 1
            else:
                start = mid
        if matrix[x][start] == target or matrix[x][end] == target:
            return True
        return False

def main():
    s = Solution()
    source = [
        [1, 3, 5, 7],
        [10, 11, 16, 20],
        [23, 30, 34, 50]
    ]
    target = 0
    print(s.searchMatrix(source, target))

if __name__ == "__main__":
    main()


from LL1 import *

registers = []
stack_registers = Stack()

class Register:
    def __init__(self, n: str, value: int):
        self.name = n
        self.value = value
        self.busy = False

def init_registers():
    global registers
    registers.append(Register('eax', 0))
    registers.append(Register('ebx', 0))
    registers.append(Register('ecx', 0))
    registers.append(Register('edx', 0))

def get_register(prev=False):
    r = False
    if not prev:
        for register in registers:
            if not register.busy:
                r = register
                break
        if r:
            r.busy = True
        else:
            r = registers.pop(0)
            print('push ' + r.name)
            stack_registers.push(r.name)
            r.busy = True
            registers.append(r)
    else:
        for i in range(len(registers)):
            if registers[i].name == prev:
                r = registers[i - 1]
    return r

def pop_register(top=False):
    if len(stack_registers):
        name = stack_registers.pop()
        prev = 0
        if registers[0].name == name:
            prev = len(registers) - 1
        else:
            for i in range(len(registers)):
                if registers[i].name == name:
                    if top:
                        prev = i
                    else:
                        prev = i - 1
                    break
        return prev
    return -1

def generate_asm_code(triads: List, tree: Node):
    init_registers()
    main = False
    reg1 = 0
    reg2 = 0
    cur = tree
    while cur is not None:
        if cur.data.id == 'блок':
            break
        if cur.data.type == DATA_TYPE.index('TYPE_SHORT_INT'):
            print('my_main' + cur.data.id + ':', cur.data.id)
        cur = cur.left
    for triad in triads:
        if triad.value[0] == TDiv:
            if main:
                m = tree.find_down('блок', tree)
                v1 = tree.find_down(triad.value[1].value, tree) \
                    if tree.find_down(triad.value[1].value, m.right) is None \
                    else tree.find_down(triad.value[1].value,
                                        m.right)
                v2 = tree.find_down(triad.value[2].value, tree) \
                    if tree.find_down(triad.value[2].value, m.right) is None \
                    else tree.find_down(triad.value[2].value,
                                        m.right)
                if triad.value[1].is_address:
                    if not triad.value[2].is_address:
                        if v2 is None:
                            print('div ' + reg1.name + ',', triad.value[2].value)
                        else:
                            if v2.data.glob:
                                print('div ' + reg1.name + ',', '[' + v2.data.id + ']')
                            else:
                                print('div ' + reg1.name + ',', '[ebp-' + str(v2.data.shift) + ']')
                    else:
                        pos = pop_register()
                        if pos > -1:
                            reg2 = registers[pos]
                            # stack_registers.push(reg2.name)
                            print('div ' + reg2.name + ',', reg1.name)
                            print('pop ' + reg1.name)
                            reg1 = reg2
                        else:
                            reg2 = get_register(reg1.name)
                            print('div ' + reg2.name + ',', reg1.name)
                            reg1.busy = False
                            reg1 = reg2
                else:
                    if not triad.value[2].is_address:
                        reg1 = get_register()
                        if v1 is None:
                            print('mov ' + reg1.name + ',', triad.value[1].value)
                        else:
                            if v1.data.glob:
                                print('div ' + reg1.name + ',', '[' + v1.data.id + ']')
                            else:
                                print('mov ' + reg1.name + ',', '[ebp-' + str(v1.data.shift) + ']')
                        if v2 is None:
                            print('div ' + reg1.name + ',', triad.value[2].value)
                        else:
                            if v2.data.glob:
                                print('div ' + reg1.name + ',', '[' + v2.data.id + ']')
                            else:
                                print('div ' + reg1.name + ',', '[ebp-' + str(v2.data.shift) + ']')
                    else:
                        reg2 = get_register()
                        if v1 is None:
                            print('mov ' + reg2.name + ',', triad.value[1].value)
                        else:
                            if v1.data.glob:
                                print('div ' + reg1.name + ',', '[' + v1.data.id + ']')
                            else:
                                print('mov ' + reg1.name + ',', '[ebp-' + str(v1.data.shift) + ']')
                        print('div ' + reg1.name + ',', reg2.name)
                        reg2.busy = False
            else:
                if triad.value[1].is_address:
                    if not triad.value[2].is_address:
                        if isinstance(triad.value[2].value, int):
                            print('div ' + reg1.name + ',', triad.value[2].value)
                        else:
                            print('div ' + reg1.name + ',', '[' + triad.value[2].value + ']')
                    else:
                        pos = pop_register()
                        if pos > -1:
                            reg2 = registers[pos]
                            # stack_registers.push(reg2.name)
                            print('div ' + reg2.name + ',', reg1.name)
                            print('pop ' + reg1.name)
                            reg1 = reg2
                        else:
                            reg2 = get_register(reg1.name)
                            print('div ' + reg2.name + ',', reg1.name)
                            reg1.busy = False
                            reg1 = reg2
                else:
                    if not triad.value[2].is_address:
                        reg1 = get_register()
                        if isinstance(triad.value[1].value, int):
                            print('mov ' + reg1.name + ',', triad.value[1].value)
                        else:
                            print('mov ' + reg1.name + ',', '[' + triad.value[1].value + ']')
                        if isinstance(triad.value[2].value, int):
                            print('div ' + reg1.name + ',', triad.value[2].value)
                        else:
                            print('div ' + reg1.name + ',', '[' + triad.value[2].value + ']')
                    else:
                        reg2 = get_register()
                        if isinstance(triad.value[1].value, int):
                            print('mov ' + reg2.name + ',', triad.value[1].value)
                        else:
                            print('mov ' + reg2.name + ',', '[' + triad.value[1].value + ']')
                        print('div ' + reg1.name + ',', reg2.name)
                        reg2.busy = False
        elif triad.value[0] == TAssignment:
            if main:
                m = tree.find_down('блок', tree)
                v = tree.find_down(triad.value[1].value, m.right)
                if triad.value[2].is_address:
                    print('mov [ebp-' + str(v.data.shift) + '], eax')
                else:
                    print('mov [ebp-' + str(v.data.shift) + '],', triad.value[2].value)
            else:
                if triad.value[2].is_address:
                    print('mov [' + str(triad.value[1].value) + '], eax')
                else:
                    print('mov [' + str(triad.value[1].value) + '],', triad.value[2].value)
        elif triad.value[0] == TMain:
            print('?my_main PROC')
            print('push ebp')
            print('mov ebp, esp')
            print('sub esp,', tree.get_size_int(0))
            print('push ebx')
            print('push esi')
            print('push edi')
            main = True
        elif triad.value[0] == TEnd:
            print('pop edi')
            print('pop esi')
            print('pop ebx')
            print('mov esp, ebp')
            print('pop ebp')
            print('ret 0')
            print('?my_main ENDP')

def __main__():
    sc = TScanner('test.txt')
    triads, tree = ll1(sc)
    # print_triads(triads)
    generate_asm_code(triads, tree)

if __name__ == '__main__':
    __main__()

Теория языков программирования/Л.Р. № 5/asm_generate.py


log_config_file = "src/bot/logging_info.ini"
post_replied_to_file = "data/posts_replied_to.txt"
responses_csv = "data/dialogues.csv"
trigger_file = "src/bot/trigger.json"
sub_json = "src/bot/subs.json"
praw_ini = "praw.ini"
env = "src/bot/.env"
bot_name = 'crowmaster-bot'

answer_template = """ \n --- \n *^(I am a bot. Okay, thanks.)*"""


# Python3 implementation for the above approach
# From GeeksForGeeks: https://www.geeksforgeeks.org/vertex-cover-problem-dynamic-programming-solution-for-tree/

def addEdge(adj, x, y):
	adj[x].append(y)
	adj[y].append(x)

def dfs(adj, dp, src, par):
	for child in adj[src]:
		if child != par:
			# print(dp)
			dfs(adj, dp, child, src)

	for child in adj[src]:
		if child != par:
			# not including source in the vertex cover
			dp[src][0] = dp[child][1] + dp[src][0]

			# including source in the vertex cover
			dp[src][1] = dp[src][1] + min(dp[child][1], dp[child][0])
		# print(dp)

def minSizeVertexCover(adj, N):
	# dp = [[0 for j in range(2)] for i in range(N+1)]
	# for i in range(1, N+1):
	dp = [[0 for j in range(2)] for i in range(N)]
	for i in range(N):
		# 0 denotes not included in vertex cover
		dp[i][0] = 0

		# 1 denotes included in vertex cover
		dp[i][1] = 1

	# dfs(adj, dp, 1, -1)
	# print(dp)
	dfs(adj, dp, 0, -1)

	# printing minimum size vertex cover

	print(min(dp[0][0], dp[0][1]))
	vc_result = 'VC = {'
	for x in range(N):
		current = dp[x]
		if current[1] <= current[0]:
			try:
				int(vc_result[-1])
				vc_result += ', '
			except:
				pass
			vc_result += f'{x}'
	print(vc_result + '}')

'''
# Driver Code
"""
	    1
	   / \
	  2	  7
	 / \
    3   6
   /|\
  4 8 5
"""
# number of nodes in the tree
N = 8

# adjacency list representation of the tree
adj = [[] for i in range(N+1)]
addEdge(adj, 1, 2)
addEdge(adj, 1, 7)
addEdge(adj, 2, 3)
addEdge(adj, 2, 6)
addEdge(adj, 3, 4)
addEdge(adj, 3, 8)
addEdge(adj, 3, 5)

minSizeVertexCover(adj, N)
'''


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

from itertools import permutations
from apriori import apriori
import rdflib
import os, re, time, sys
import argparse

def get_index(g):
    index = 1
    dict_forward = {}
    dict_reverse = {}
    for subject, predicate, obj in g:
        if not (subject, predicate, obj) in g:
            raise Exception("Iterator / Container Protocols are Broken!!")
        if dict_forward.get(str(subject), -1) == -1:
            dict_forward[str(subject)] = index
            dict_reverse[index] = str(subject)
            index = index + 1
        if dict_forward.get(str(predicate), -1) == -1:
            dict_forward[str(predicate)] = index
            dict_reverse[index] = str(predicate)
            index = index + 1
        if dict_forward.get(str(obj), -1) == -1:
            dict_forward[str(obj)] = index
            dict_reverse[index] = str(obj)
            index = index + 1
    return dict_forward,dict_reverse

def match_path(g,path,path1,dict_forward):
    match_result = {}
    if len(path) == 1:
        for sub in g.subjects():
            if re.search(path[0], sub) is None:
                continue
            if match_result.get(sub, -1) == -1:
                match_result[sub] = {sub}
            else:
                match_result[sub].add(sub)
    else:
        if int(path1[0]) == 1:
            for sub in g.subjects():
                if re.search(path[0], sub) is None:
                    continue
                for pre, obj in g.predicate_objects(sub):
                    if re.search(path[1], obj) is None:
                        continue
                    if match_result.get(sub, -1) == -1:
                        match_result[sub] = {obj}
                    else:
                        match_result[sub].add(obj)
        else:
            for obj in g.objects():
                if re.search(path[0], obj) is None:
                    continue
                for sub, pre in g.subject_predicates(obj):
                    if re.search(path[1], sub) is None:
                        continue
                    if match_result.get(obj, -1) == -1:
                        match_result[obj] = {sub}
                    else:
                        match_result[obj].add(sub)
        for idx, val in enumerate(path1[1:], 1):
            if int(val) == 1:
                for key, values in match_result.items():
                    set_tmp = set()
                    for value in values:
                        for pre, obj in g.predicate_objects(value):
                            if re.search(path[idx + 1], obj) is None:
                                continue
                            set_tmp.add(obj)
                    match_result[key] = set_tmp
            else:
                for key, values in match_result.items():
                    set_tmp = set()
                    for value in values:
                        for sub, pre in g.subject_predicates(value):
                            if re.search(path[idx + 1], sub) is None:
                                continue
                            set_tmp.add(sub)
                    match_result[key] = set_tmp
    record = []
    for key, values in match_result.items():
        for value in values:
            list_tmp = []
            for pre, obj in g.predicate_objects(key):
                list_tmp.append(dict_forward[str(obj)])
            for sub, pre in g.subject_predicates(key):
                list_tmp.append(dict_forward[str(sub)])
            if key == value:
                continue
            for pre, obj in g.predicate_objects(value):
                list_tmp.append(dict_forward[str(obj)])
            for sub, pre in g.subject_predicates(value):
                list_tmp.append(dict_forward[str(sub)])
            list_tmp = list(set(list_tmp))
            record.append(list_tmp)
    return record
def match_path2(g,path,path1,dict_forward):
    match_result = {}
    if len(path) == 1:
        for sub in g.subjects():
            if sub.find(path[0]) < 0:
                continue
            if match_result.get(sub, -1) == -1:
                match_result[sub] = {sub}
            else:
                match_result[sub].add(sub)
    else:
        if int(path1[0]) == 1:
            for sub in g.subjects():
                if sub.find(path[0]) < 0:
                    continue
                for pre, obj in g.predicate_objects(sub):
                    if obj.find(path[1]) < 0:
                        continue
                    if match_result.get(sub, -1) == -1:
                        match_result[sub] = {obj}
                    else:
                        match_result[sub].add(obj)
        else:
            for obj in g.objects():
                if obj.find(path[0]) < 0:
                    continue
                for sub, pre in g.subject_predicates(obj):
                    if sub.find(path[1]) < 0:
                        continue
                    if match_result.get(obj, -1) == -1:
                        match_result[obj] = {sub}
                    else:
                        match_result[obj].add(sub)
        for idx, val in enumerate(path1[1:], 1):
            if int(val) == 1:
                for key, values in match_result.items():
                    set_tmp = set()
                    for value in values:
                        for pre, obj in g.predicate_objects(value):
                            if obj.find(path[idx + 1]) < 0:
                                continue
                            set_tmp.add(obj)
                    match_result[key] = set_tmp
            else:
                for key, values in match_result.items():
                    set_tmp = set()
                    for value in values:
                        for sub, pre in g.subject_predicates(value):
                            if sub.find(path[idx + 1]) < 0:
                                continue
                            set_tmp.add(sub)
                    match_result[key] = set_tmp
    record = []
    for key, values in match_result.items():
        for value in values:
            list_tmp = []
            for pre, obj in g.predicate_objects(key):
                list_tmp.append(dict_forward[str(obj)])
            for sub, pre in g.subject_predicates(key):
                list_tmp.append(dict_forward[str(sub)])
            if key == value:
                continue
            for pre, obj in g.predicate_objects(value):
                list_tmp.append(dict_forward[str(obj)])
            for sub, pre in g.subject_predicates(value):
                list_tmp.append(dict_forward[str(sub)])
            list_tmp = list(set(list_tmp))
            record.append(list_tmp)
    return record

def match_sparql(g,sparql_query,dict_forward):
    qres = g.query(sparql_query)
    record = []
    for row in qres:
        list_tmp = []
        for item in row:
            for pre, obj in g.predicate_objects(item):
                list_tmp.append(dict_forward[str(obj)])
            for sub, pre in g.subject_predicates(item):
                list_tmp.append(dict_forward[str(sub)])
        list_tmp = list(set(list_tmp))
        record.append(list_tmp)
    return record

def write_file(graphfile, record,query_node,dict_reverse):
    itemfile = "path_itemsets.txt"
    rulesfile = "path_rules.txt"
    rulesdict_file= "path_rule_dict.text"
    if os.path.exists(itemfile):
        os.remove(itemfile)
    if os.path.exists(rulesfile):
        os.remove(rulesfile)
    if os.path.exists(rulesdict_file):
        os.remove(rulesdict_file)
    itemfile_write = open(itemfile, 'a', encoding='utf-8')
    rulesfile_write = open(rulesfile, 'a', encoding='utf-8')

    #print(len(record))
    itemsets, rules = apriori(record,query_node=query_node, min_support=0.5, min_confidence=0.9)
    for (key, value) in itemsets.items():
        itemset = []
        for item_tuple in value.keys():
            for item in item_tuple:
                itemset.append(dict_reverse[item])
        #print(itemset)
        itemfile_write.write(str(itemset))
        itemfile_write.write("\n")
    rule_dict = {}
    for rule in rules:
        lhs_itemset = []
        rhs_itemset = []
        for item in rule.lhs:
            lhs_itemset.append(dict_reverse[item])
        for item in rule.rhs:
            rhs_itemset.append(dict_reverse[item])
        for item in rule.lhs+rule.rhs:
            if rule_dict.get(dict_reverse[item], -1) == -1:
                rule_dict[dict_reverse[item]] = [str(lhs_itemset) + "->" + str(rhs_itemset)+"\tsupport="+str(rule.support)+"\tconfidence="+str(rule.confidence)+'\tlift='+str(rule.lift)]
            else:
                rule_dict[dict_reverse[item]].append(str(lhs_itemset) + "->" + str(rhs_itemset)+"\tsupport="+str(rule.support)+"\tconfidence="+str(rule.confidence)+'\tlift='+str(rule.lift))

        rulesfile_write.write(str(lhs_itemset))
        rulesfile_write.write("->")
        rulesfile_write.write(str(rhs_itemset))
        rulesfile_write.write("\n")
    with open(rulesdict_file, 'w', encoding='utf8') as outfile:
        for key, values in rule_dict.items():
            outfile.write(key + ":[")
            for value in values:
                lhs_itemset = []
                rhs_itemset = []
                for item in rule.lhs:
                    lhs_itemset.append(dict_reverse[item])
                for item in rule.rhs:
                    rhs_itemset.append(dict_reverse[item])
                outfile.write(str(lhs_itemset))
                outfile.write("->")
                outfile.write(str(rhs_itemset))
                outfile.write(", ")
            outfile.write("]\n")
    return rule_dict
def get_query_node_result(query_node,rule_dict,dict_reverse):
    rule_set=set(rule_dict[dict_reverse[query_node[0]]])
    for node in query_node[1:]:
        node=dict_reverse[node]
        rule_set=rule_set.intersection(rule_dict[node])
    with open("query_result.txt",'w',encoding='utf8') as outfile:
        for rule in rule_set:
            outfile.write(rule+'\n')
    for i in range(len(query_node)):
        query_node[i]=dict_reverse[query_node[i]]

    for p in permutations(query_node):
        for i in range(1,len(query_node)):
            rule_str='[\''
            for j in range(i):
                rule_str+=p[j]+'\', \''
            rule_str=rule_str[:-3]+']->[\''
            for j in range(i,len(p)):
                rule_str+=p[j]+'\', \''
            rule_str=rule_str[:-3]+']'
            result_dict={"rule":rule_str}
            for rule in rule_set:
                if rule.find(rule_str)>=0:
                    re_group=re.search('support=(.*?)confidence=(.*?)lift=(.*)', rule)
                    result_dict["support"]=re_group[1]
                    result_dict["confidence"]=re_group[2]
                    result_dict["lift"]=re_group[3]
                    print(result_dict)

def main_algorithm(args):
    graphfile = args.graph_file
    g = rdflib.Graph()
    result = g.parse(graphfile, format="nt")
    dict_forward,dict_reverse=get_index(g)
    query_node=args.query_node.strip('\n').split(',')
    for i in range(len(query_node)):
        query_node[i]='http://www.tsinghua-west.com/Guxi/'+query_node[i]

    if args.query_type == 'path':
        path_node_list=args.query_file.strip('\n').split(',')
        path=path_node_list[:int((len(path_node_list)+1)/2)]
        path1=path_node_list[int((len(path_node_list)+1)/2):]
        #print(path,path1)
        match_result = match_path2(g, path, path1, dict_forward)
        for i in range(len(query_node)):
            query_node[i]=dict_forward[query_node[i]]

        rule_dict=write_file(g,match_result,query_node,dict_reverse)
        get_query_node_result(query_node,rule_dict,dict_reverse)
    else:
        sparql_query=args.query_file
        sparql_query=sparql_query.replace('_',' ')
        match_result = match_sparql(g, sparql_query, dict_forward)
        for i in range(len(query_node)):
            query_node[i]=dict_forward[query_node[i]]
        rule_dict = write_file(g, match_result, query_node, dict_reverse)
        get_query_node_result(query_node, rule_dict, dict_reverse)

if __name__ == '__main__':
    start_time=time.time()
    parser = argparse.ArgumentParser()
    basic = parser.add_argument('-g', '--graph_file',dest='graph_file', type=str, required=True, help='input graph file')
    basic = parser.add_argument('-t', '--query_type',dest='query_type', type=str, required=True, help='query type')
    basic = parser.add_argument('-q', '--query_file', dest='query_file', type=str, required=True, help='query file')
    basic = parser.add_argument('-x', '--query_node', dest='query_node', type=str, required=True, help='query node')
    if len(sys.argv[1:])!=8:
        parser.print_help()        #print usage
        parser.exit()
    args = parser.parse_args()

    main_algorithm(args)


import redis
import json
import logging
import time
import arrow
from flight_database import FlightDatabase

logging.basicConfig(level=logging.WARNING)
redis_connection = redis.Redis("redis", decode_responses=True)
flight_db = FlightDatabase()

def process_message(message):
    if message["airline"] in ("XXX", "DCM", "FWR", "FFL", "XAA"):
        return

    # Split callsign into operator and suffix and remove leading zeros.
    operator_icao = message["callsign"][:3]
    suffix = message["callsign"][3:].lstrip("0")
    callsign = "{}{}".format(operator_icao, suffix)
    if not message["etd"]["etdType"] == "ACTUAL":
        return
    departure = int(arrow.get(message["etd"]["timeValue"]).timestamp())
    arrival = int(arrow.get(message["eta"]["timeValue"]).timestamp())
    duration = arrival - departure
    if duration <= 0:
        logging.warning(f"departure >= arrival: {message}")
        return
    if message["igtd"] is not None:
        igtd = int(arrow.get(message["igtd"]).timestamp())
    else:
        igtd = None
    if message.get("gate_departure") is not None:
        gate_departure = int(arrow.get(message["gate_departure"]).timestamp())
        if gate_departure > departure:
            logging.warning(f"gate_departure > departure: {message}")
            return
    else:
        gate_departure = None
    if message.get("gate_arrival") is not None:
        gate_arrival = int(arrow.get(message["gate_arrival"]).timestamp())
        if gate_arrival < arrival:
            logging.warning(f"gate_arrival < arrival: {message}")
            return
    else:
        gate_arrival = None
    origin = message["origin"]
    destination = message["destination"]
    historic_flight = {
        "callsign": callsign,
        "igtd": igtd,
        "gate_departure": gate_departure,
        "origin": origin,
        "departure": departure,
        "departure_actual": message["etd"]["etdType"] == "ACTUAL",
        "destination": destination,
        "arrival": arrival,
        "arrival_actual": message["eta"]["etaType"] == "ACTUAL",
        "gate_arrival": gate_arrival,
    }
    logging.debug(json.dumps(historic_flight, indent=2))
    logging.info(
        f"{callsign} {origin}-{destination} {duration / 60:.1f} minutes"
    )
    redis_connection.set("historic_flight_processed", time.time())
    flight_db.set_historic_flight(historic_flight)

while True:
    try:
        _pubsub = redis_connection.pubsub(ignore_subscribe_messages=True)
        _pubsub.subscribe("SWIM-ARRIVALS")
        for message in _pubsub.listen():
            if not message["type"] == "message":
                continue
            process_message(json.loads(message["data"]))
    except redis.exceptions.ConnectionError:
        logging.exception("reconnecting to Redis in 5s.")
        time.sleep(5)


"""Basic RNN model
"""
from typing import Literal

import torch
import torch.nn as nn
import torch.nn.functional as F

class Attention(nn.Module):
    """Self Attention Module"""

    def __init__(
        self,
        hidden_size: int,
        proj_hidden_size: int,
    ):
        """Self Attention Module

        Args:
            hidden_size (int): Hidden Size of Encoder Outputs
            proj_hidden_size (int): Hidden Size of Self Attention hidden layer
        """
        super(Attention, self).__init__()
        self.projection = nn.Sequential(
            nn.Linear(hidden_size, proj_hidden_size),
            nn.ReLU(True),
            nn.Linear(proj_hidden_size, 1),
        )

    def forward(self, encoder_outputs: torch.tensor) -> torch.tensor:
        """Forward Propagation

        Args:
            encoder_outputs (torch.tensor): Output hidden states for all encoder timestamps. Dimension: bs, sequence_length, hidden_size

        Returns:
            torch.tensor: Weighted tensor for all encoder hidden states
        """
        att_energy = self.projection(encoder_outputs)  # (bs, seq_len, 1)
        att_weights = F.softmax(att_energy.squeeze(2), dim=1)  # (bs, seq_len)
        outputs = (encoder_outputs * att_weights.unsqueeze(2)).sum(
            dim=1
        )  # (bs, hidden_size)
        return outputs

class RNNModel(nn.Module):
    """RNN Model"""

    def __init__(
        self,
        in_channels: int,
        num_classes: int,
        sequence_len: int,
        hidden_size: int = 64,
        num_layers: int = 2,
        rnn_type: Literal["RNN", "LSTM", "GRU"] = "GRU",
        bidirectional: bool = True,
        dropout: float = 0.0,
        use_attention: bool = True,
        proj_size: int = 64,
    ):
        """RNN Model

        Args:
            in_channels (int): Number of input channels for each timestep.
            num_classes (int): Sequence Length
            sequence_len (int): Number of output class labels
            hidden_size (int, optional): RNN hidden size to pass to next time step. Defaults to 64.
            num_layers (int, optional): Number of RNN layers. Defaults to 2.
            rnn_type (str, "LSTM", "RNN" or "GRU"): Type of RNN architecture. Defaults to "LSTM". Need to be UPPERCASE.
            bidirectional (bool, optional): Use bidirectional RNN. Defaults to True.
            dropout (float, optional): Dropout Rate. Defaults to 0.25.
            use_attention (bool, optional): Use self-attention. Defaults to False.
            proj_size (int, optional): Hidden size for self-attention network. Default to 64.
        """

        super(RNNModel, self).__init__()

        self.bidirectional = bidirectional
        self.sequence_len = sequence_len
        self.use_attention = use_attention

        self.rnn_type = rnn_type
        rnn_obj = getattr(nn, rnn_type)
        self.rnn = rnn_obj(
            input_size=in_channels,
            hidden_size=hidden_size,
            num_layers=num_layers,
            bias=False,
            batch_first=True,
            dropout=dropout,
            bidirectional=bidirectional,
        )

        self.dropout = nn.Dropout(p=dropout)

        if use_attention:
            if self.bidirectional:
                self.linear = nn.Linear(4 * hidden_size, num_classes)
                self.self_attention = Attention(2 * hidden_size, proj_size)
            else:
                self.linear = nn.Linear(2 * hidden_size, num_classes)
                self.self_attention = Attention(hidden_size, proj_size)
        else:
            self.self_attention = None
            if self.bidirectional:
                self.linear = nn.Linear(2 * hidden_size, num_classes)
            else:
                self.linear = nn.Linear(hidden_size, num_classes)

    def forward(self, inputs: torch.tensor) -> torch.tensor:
        """Forward Pass

        Args:
            inputs (torch.tensor): Input Mini Batch

        Returns:
            torch.tensor: Output Probability
        """
        ## Input Dimension = (bs, input_size, sequence_len)
        x = inputs.permute(0, 2, 1)  # Dimension = (bs, sequence_len, input_size)
        # x = self.dropout(inputs)
        outs, _ = self.rnn(x)  # (bs, sequence_len, hidden_size)
        rnn_out = outs[:, -1, :]  # (bs, hidden_size)
        att_out = self.self_attention(outs)  # (bs, hidden_size)
        final_out = torch.cat((rnn_out, att_out), dim=1)

        probs = self.linear(final_out)  # (bs, num_classes)

        return probs

    def __str__(self):
        """Model Name"""
        if self.use_attention:
            return "RNN_ATT"
        else:
            return "RNN"

if __name__ == "__main__":
    model = RNNModel(
        in_channels=128, num_classes=31, sequence_len=126, use_attention=True
    )
    sample_batch = torch.rand(5, 128, 126)
    out = model(sample_batch)
    print(out.size())