import multiprocessing
import sys
import os
import platform
if platform.platform() == "win32":
    import winreg as wr
else:
    wr = None
from pathlib import Path

from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtWidgets import *
from PyQt6.QtCore import QThread, pyqtSignal
from src.MaskRegistration.backend import transform

class RegistrationThread(QThread):
    finished_signal = pyqtSignal(str, bool)

    def __init__(self, dicom_1, mask_1, dicom_2, mask_2):
        super().__init__()
        self.dicom_1 = dicom_1
        self.mask_1 = mask_1
        self.dicom_2 = dicom_2
        self.mask_2 = mask_2

    def run(self):
        try:
            transform(
                input_dicom_folder_1=Path(self.dicom_1),
                input_mask_file=Path(self.mask_1),
                input_dicom_folder_2=Path(self.dicom_2),
                out_nii_file=Path(self.mask_2),
            )
        except Exception as error:
            self.finished_signal.emit(str(error), False)
        else:
            self.finished_signal.emit("Calculations successfully completed.", True)

class MaskRegistration(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("MaskRegistration - Wrapper for SimpleITK")
        myFont = QtGui.QFont()
        myFont.setPointSize(8)
        self.setFont(myFont)

        layout = QGridLayout()

        # Input DICOM
        dicom_1_button = QPushButton("Select Segmented DICOM")
        layout.addWidget(dicom_1_button, 0, 0, 1, 1)
        self.dicom_1_text = QLineEdit()
        layout.addWidget(self.dicom_1_text, 0, 1, 1, 1)
        dicom_1_button.clicked.connect(self.update_dicom_1)

        # Input Mask
        mask_1_button = QPushButton("Select Input Mask")
        layout.addWidget(mask_1_button, 1, 0, 1, 1)
        self.mask_1_text = QLineEdit()
        layout.addWidget(self.mask_1_text, 1, 1, 1, 1)
        mask_1_button.clicked.connect(self.update_mask_1)

        # Registration DICOM
        dicom_2_button = QPushButton("Select Registration DICOM")
        layout.addWidget(dicom_2_button, 2, 0, 1, 1)
        self.dicom_2_text = QLineEdit()
        layout.addWidget(self.dicom_2_text, 2, 1, 1, 1)
        dicom_2_button.clicked.connect(self.update_dicom_2)

        # Output Mask
        mask_2_button = QPushButton("Select Output Mask")
        layout.addWidget(mask_2_button, 3, 0, 1, 1)
        self.mask_2_text = QLineEdit()
        layout.addWidget(self.mask_2_text, 3, 1, 1, 1)
        mask_2_button.clicked.connect(self.update_mask_2)

        # Run Button
        self.run = QPushButton("RUN")
        self.run.setMinimumHeight(80)
        myFont = QtGui.QFont()
        myFont.setPointSize(12)
        myFont.setBold(True)
        self.run.setFont(myFont)
        self.run.setStyleSheet("background-color : red")
        layout.addWidget(self.run, 0, 2, 4, 1)
        self.run.clicked.connect(self.run_registration)

        # Create a QWidget for the popup
        self.popup_widget = QWidget()
        self.popup_widget.setWindowTitle("Registration and Transformation")
        self.popup_widget.setFixedSize(580, 320)
        self.popup_layout = QVBoxLayout()

        # Adding gif animation
        if getattr(sys, "frozen", False):
            # If it's compiled, adjust the path
            base_path = sys._MEIPASS
        else:
            # Otherwise, the path remains the same
            base_path = os.path.dirname(os.path.abspath(__file__))

            # Now, use this base_path to reference your gif
        gif_path = os.path.join(base_path, "loading.gif")

        self.movie = QtGui.QMovie(gif_path)
        self.movie.setScaledSize(QtCore.QSize(548, 309))
        self.label = QLabel(self.popup_widget)
        self.label.setMovie(self.movie)
        self.popup_layout.addWidget(self.label)
        self.popup_widget.setLayout(self.popup_layout)

        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)
        self.setMinimumSize(QtCore.QSize(1200, 100))

    def file_dialog(self, text: str, line_edit: QLineEdit, mode: str) -> None:
        """
        File Dialog method to handle file/folder selection.

        :param text: Dialog Title
        :param line_edit: Line Edit Widget
        :param mode: Mode (DIR, FILE, SAVE_FILE)
        """
        last_path = self.get_last_dicom_path()
        if mode == "DIR":
            dialog = QFileDialog.getExistingDirectory(self, text, last_path)
        elif mode == "FILE":
            dialog = QFileDialog.getOpenFileName(
                self, text, last_path, "NIFTI files (*.nii*)"
            )[0]
        elif mode == "SAVE_FILE":
            dialog = QFileDialog.getSaveFileName(
                self, text, last_path, "NIFTI files (*.nii*)"
            )[0]
        line_edit.setText(dialog)
        if dialog != "":
            self.save_last_dicom_path(Path(dialog).parent.as_posix())

    def update_dicom_1(self) -> None:
        """Update the dicom_1_text field with the selected directory."""
        self.file_dialog("Select Dicom Path 1", self.dicom_1_text, "DIR")
        if self.dicom_1_text.text() != "" and self.mask_1_text.text() == "":
            if (Path(self.dicom_1_text.text()) / "mask.nii.gz").exists():
                self.mask_1_text.setText(
                    os.path.join(self.dicom_1_text.text(), "mask.nii.gz")
                )

    def update_mask_1(self) -> None:
        """Update the mask_1_text field with the selected file."""
        self.file_dialog("Select Mask File 1", self.mask_1_text, "FILE")

    def update_dicom_2(self) -> None:
        """Update the dicom_2_text field with the selected directory."""
        self.file_dialog("Select Dicom Path 2", self.dicom_2_text, "DIR")
        if self.dicom_2_text.text() != "" and self.mask_2_text.text() == "":
            self.mask_2_text.setText(
                os.path.join(self.dicom_2_text.text(), "mask.nii.gz")
            )

    def update_mask_2(self) -> None:
        """Update the mask_2_text field with the selected file."""
        self.file_dialog("Select Save File Mask", self.mask_2_text, "SAVE_FILE")

    def run_registration(self):
        self.run.setEnabled(False)  # Deactivate RUN button
        self.popup_widget.show()
        self.movie.start()

        # Start registration in a separate thread
        try:
            if (
                not self.dicom_1_text.text()
                or not self.mask_1_text.text()
                or not self.dicom_2_text.text()
                or not self.mask_2_text.text()
            ):
                raise ValueError("Please fill in all the required fields.")
            self.registration_thread = RegistrationThread(
                self.dicom_1_text.text(),
                self.mask_1_text.text(),
                self.dicom_2_text.text(),
                self.mask_2_text.text(),
            )
            self.registration_thread.finished_signal.connect(self.registration_finished)
            self.registration_thread.start()
        except Exception as error:
            self.run.setEnabled(True)  # Deactivate RUN button
            self.popup_widget.close()
            self.movie.stop()
            msg = QMessageBox()
            msg.setWindowTitle("Error")
            msg.setText(f"Calculation failed: {str(error)}")
            msg.setIcon(QMessageBox.Icon.Warning)
            msg.setStyleSheet("color: red;")
            msg.exec()

    def registration_finished(self, message, success):
        # Reactivate RUN button
        self.run.setEnabled(True)
        # Stop the loading animation
        self.popup_widget.close()
        self.movie.stop()
        # Show message box
        msg = QMessageBox()
        msg.setWindowTitle("Success" if success else "Error")
        if success:
            msg.setText("Calculations successfully completed.")
        msg.setText(message)
        msg.setIcon(
            QMessageBox.Icon.Information if success else QMessageBox.Icon.Warning
        )
        msg.exec()
        # Clear text fields if successful
        if success:
            self.dicom_1_text.setText("")
            self.mask_1_text.setText("")
            self.dicom_2_text.setText("")
            self.mask_2_text.setText("")

    def save_last_dicom_path(self, path: str) -> None:
        """
        Save the last selected DICOM path to the Windows Registry.

        :param path: Path to save
        """
        if wr:
            key = wr.CreateKey(wr.HKEY_CURRENT_USER, r"Software\MaskRegistration")
            wr.SetValueEx(key, "LastDICOMPath", 0, wr.REG_SZ, path)
            wr.CloseKey(key)

    def get_last_dicom_path(self) -> str:
        """
        Retrieve the last selected DICOM path from the Windows Registry.

        :return: Last DICOM path
        """
        try:
            key = wr.OpenKey(wr.HKEY_CURRENT_USER, r"Software\MaskRegistration")
            path, _ = wr.QueryValueEx(key, "LastDICOMPath")
            wr.CloseKey(key)
            return path
        except Exception:
            return QtCore.QDir.currentPath()

if __name__ == "__main__":
    multiprocessing.freeze_support()
    app = QApplication(sys.argv)
    app.setStyle("Fusion")
    window = MaskRegistration()
    window.show()
    app.exec()


from dataclasses import dataclass
from functools import partial
import timeit

@dataclass(slots=False)
class Person:
    name:str
    address:str
    email:str

@dataclass(slots=True)
class PersonSlots:
    name:str
    address:str
    email:str

def get_set_del(person:Person|PersonSlots):
    person.name
    person.name = "12 Colorado, España"
    person.address="2323"

def main():
    print("main")
    person = Person(name="Gerardo",address="Madrid, España",email="email@email.com")
    personSlots = PersonSlots("Gerardo","Madrid, España","email@email.com")
    slots = min(timeit.repeat(partial(get_set_del,personSlots),number=100000))
    noSlots = min(timeit.repeat(partial(get_set_del,person),number=100000))

    print(f"No Slots: {(noSlots)}")
    print(f"Slots: {(slots)}")
    print(f"Improve: {(noSlots-slots)/noSlots:.2%}")

if __name__ == "__main__":
    main()


import joblib
import numpy as np
import pandas as pd
from gensim.models import KeyedVectors
from tqdm import tqdm

tqdm.pandas()

train_df = pd.read_table("./data/train.txt")
valid_df = pd.read_table("./data/valid.txt")
test_df = pd.read_table("./data/test.txt")

category2id = {
    "b":0,
    "t":1,
    "e":2,
    "m":3
}

train_df["CATEGORY_ID"] = train_df["CATEGORY"].map(category2id)
valid_df["CATEGORY_ID"] = valid_df["CATEGORY"].map(category2id)
test_df["CATEGORY_ID"] = test_df["CATEGORY"].map(category2id)

joblib.dump(train_df["CATEGORY_ID"].values, './data/y_train.joblib')
joblib.dump(valid_df["CATEGORY_ID"].values, './data/y_valid.joblib')
joblib.dump(test_df["CATEGORY_ID"].values, './data/y_test.joblib')

def sent2vec(text, model):
    vec = np.array([model[word] if word in model.vocab else np.zeros(shape=(model.vector_size,)) for word in text.split()])
    vec = np.mean(vec, axis=0)
    return vec

model = KeyedVectors.load_word2vec_format("./data/GoogleNews-vectors-negative300.bin", binary=True)

X_train = train_df["TITLE"].progress_map(lambda x: sent2vec(x, model))
X_valid = valid_df["TITLE"].progress_map(lambda x: sent2vec(x, model))
X_test = test_df["TITLE"].progress_map(lambda x: sent2vec(x, model))

joblib.dump(X_train.values, './data/X_train.joblib')
joblib.dump(X_valid.values, './data/X_valid.joblib')
joblib.dump(X_test.values, './data/X_test.joblib')


import logging
import os
import warnings

def _get_logging_level(default: str = "DEBUG"):
    lv = os.environ.get("LOG_LEVEL", default)

    try:
        lv = getattr(logging, lv)
    except AttributeError:
        warnings.warn(
            f"LOG_LEVEL has an invalid value of {lv}. Defaulting to {default}"
        )
        return getattr(logging, default)
    else:
        return lv

logging.basicConfig(
    format="%(asctime)s %(levelname)s %(message)s",
)

logger = logging.getLogger("arxiv-sanity-bot")
logger.setLevel(_get_logging_level())
logger.handlers = [logging.FileHandler("arxiv-sanity-bot.log")]


from botocore.exceptions import ClientError
from botocore.config import Config as botocore_config
import json
import logging
import random
import time

from lib import awshelper
from lib import config
from lib import ddb
from lib import utility

def get_source_buckets(input_parameters, account_id):
    """ Get all eligible source buckets

    Arguments:
        input_parameters {config.S3InsightsInput} -- Input parameters for the current execution
        account_id {string} -- AWS account id

    Returns:
        dict<string, dict<string, list(string)>> -- Source buckets
    """
    source_buckets = {}
    account_id = account_id.lower()
    account_config = next(account_config for account_config in input_parameters.accounts if utility.compare_strings(account_config.id, account_id))
    source_buckets[account_id] = {}
    s3_client = awshelper.get_client(
        awshelper.ServiceName.s3,
        None,
        account_id,
        input_parameters.run_id)

    # Exclude the consolidation and inventory destination buckets
    pipeline_buckets = []
    if utility.compare_strings(account_id, awshelper.SessionManager.get_host_account_id()):
        pipeline_buckets.append(config.DeploymentDetails.consolidated_inventory_bucket_name)
        for region in input_parameters.supported_regions:
            bucket_name = get_destination_bucket_name(input_parameters.run_id, region)
            pipeline_buckets.append(bucket_name)
    response = s3_client.list_buckets()
    for bucket in response["Buckets"]:
        name = bucket["Name"].lower()
        if name not in account_config.exclude and name not in pipeline_buckets:
            try:
                location = s3_client.get_bucket_location(
                    Bucket=name)
                region = location['LocationConstraint']
                if region is None:
                    region = 'us-east-1'
                region = region.lower()
                if region in input_parameters.supported_regions:
                    if region not in source_buckets[account_id]:
                        source_buckets[account_id][region] = []
                    source_buckets[account_id][region].append(name)
            except ClientError as e:
                logging.error(f'error while retrieving bucket information for {account_id}:{name}. error details: {e}')

    return source_buckets

def get_destination_bucket_name(run_id, region):
    """ Get destination bucket name for a region

    Arguments:
        run_id {string} -- run_id for the current execution
        region {string} -- AWS region name

    Returns:
        string -- Destination bucket name
    """
    host_account_id = awshelper.SessionManager.get_host_account_id()
    return utility.get_resource_name(
        run_id,
        f'dest-{host_account_id}',
        region)

def is_bucket_empty(s3_resource, bucket_name):
    """ Check if a given S3 bucket is empty

    Arguments:
        s3_resource {Boto3.S3.ServiceResource} -- Boto3 S3 resource
        bucket_name {string} -- bucket name

    Returns:
        boolean -- Flag indicating if the bucket is empty
    """
    empty = True
    client_error = None
    bucket = s3_resource.Bucket(bucket_name)
    try:
        s3_objects = bucket.objects.all()
        for s3_object in s3_objects:
            empty = False
            break
    except ClientError as e:
        logging.error(f'error while listing objects from {bucket_name}. error details:{e}')
        client_error = e
    return empty, client_error

def is_destination_bucket_name(input_parameters, bucket_name):
    """ Check if the given S3 bucket is a destination bucket

    Arguments:
        input_parameters {config.S3InsightsInput} -- Input parameters for the current execution
        bucket_name {string} -- Bucket name

    Returns:
        boolean -- Flag indicating if the bucket is a destination bucket
    """
    for region in input_parameters.supported_regions:
        destination_bucket_name = get_destination_bucket_name(input_parameters.run_id, region)
        if utility.compare_strings(destination_bucket_name, bucket_name):
            return True
    return False

class StackDetails(object):
    def __init__(self, client, name):
        """ Constructor for creating an instance of

        Arguments:
            object {StackDetails} -- Instance of StackDetails
            client {Boto3.CloudFormation.Client} -- Boto3 CloudFormation client
            name {string} -- CloudFormation stack name
        """
        self.client = client
        self.name = name

    def is_complete(self, in_progress_state_name, complete_state_name):
        """ Check if the CloudFormation stack operation has finished

        Arguments:
            in_progress_state_name {string} -- In-progress state name
            complete_state_name {[string} -- Complete state name

        Raises:
            utility.S3InsightsException: When the stack status is neither in-progress nor complete

        Returns:
            boolean -- Flag indicating if the operation has finished successfully
        """
        details = self.client.describe_stacks(StackName=self.name)
        logging.info(f'current stack details: {self.name} {details}')
        current_status = details['Stacks'][0]['StackStatus'].lower()
        if utility.compare_strings(current_status, in_progress_state_name):
            return False
        elif utility.compare_strings(current_status, complete_state_name):
            return True
        else:
            error_message = f'unknown stack status. Stack name:{self.name} current status:{current_status} expected status:{in_progress_state_name}/{complete_state_name} details:{details}'
            raise utility.S3InsightsException(error_message)

def wait_for_stack_operations_to_finish(stacks, in_progress_state_name, complete_state_name, max_iteration_count):
    """ Wait for stack operations to finish

    Arguments:
        stacks {list(StackDetails)} -- List of stacks
        in_progress_state_name {string} -- In-progress state name
        complete_state_name {[string} -- Complete state name
        max_iteration_count {integer} -- Max iteration count

    Raises:
        utility.S3InsightsException: When stacks do not move to the complete state in the alloted time
    """
    are_stacks_ready = False
    attempts = 0
    while are_stacks_ready is False and attempts < max_iteration_count:
        are_stacks_ready = True
        attempts = attempts + 1
        for stack in stacks:
            if stack.is_complete(in_progress_state_name, complete_state_name) == False:
                are_stacks_ready = False
                time.sleep(30)
                break
    if are_stacks_ready is False:
        raise utility.S3InsightsException('stacks did not finish in the alloted time')

def get_stack_name(run_id):
    """ Get CloudFormation stack name

    Arguments:
        run_id {string} -- run_id for the current Step Function execution

    Returns:
        string -- CloudFormation Stack name
    """
    return utility.get_resource_name(
        run_id,
        'stack',
        'dest-resources')

def create_inventory_destination_buckets(input_parameters):
    """ Create inventory destination buckets

    Arguments:
        input_parameters {config.S3InsightsInput} -- Input parameters for the current execution
    """
    template_file_path = utility.get_file_path(__file__, "template/inventory-destination.json")
    with open(template_file_path, "r") as template_file:
        template_text = template_file.read()
    stacks = []
    regions = input_parameters.supported_regions
    for region in regions:
        bucket_name = get_destination_bucket_name(
            input_parameters.run_id,
            region)
        topic_name = utility.get_resource_name(
            input_parameters.run_id,
            'sns',
            'notification-topic')

        acceleration_status = 'Enabled'

        parameters = [
            {
                'ParameterKey': 'BucketName',
                'ParameterValue': bucket_name
            },
            {
                'ParameterKey': 'SQSArn',
                'ParameterValue': config.DeploymentDetails.sqs_arn
            },
            {
                'ParameterKey': 'TopicName',
                'ParameterValue': topic_name
            },
            {
                'ParameterKey': 'AccelerationStatus',
                'ParameterValue': acceleration_status
            }
        ]

        stack_name = get_stack_name(input_parameters.run_id)
        cloudformation_client = awshelper.get_client(
            awshelper.ServiceName.cloudformation,
            region)
        response = cloudformation_client.create_stack(
            StackName=stack_name,
            TemplateBody=template_text,
            Parameters=parameters)
        logging.info(f'create stack response: {response}')
        stacks.append(StackDetails(cloudformation_client, stack_name))
    wait_for_stack_operations_to_finish(
        stacks,
        'create_in_progress',
        'create_complete',
        20)

def create_inventory_configuration_helper(account_id):
    """ Helper function to create inventory configurations

    Arguments:
        account_id {string} -- AWS account id
    """
    input_parameters = ddb.get_input_parameters()
    source_buckets = get_source_buckets(input_parameters, account_id)
    ddb.store_source_buckets(source_buckets)
    create_bucket_inventory_configurations(
        input_parameters.run_id,
        source_buckets)

def create_bucket_inventory_configurations(run_id, source_buckets):
    """ Enable S3 inventory for the given list of source buckets

    Arguments:
        run_id {string} -- run_id for the current Step Function execution
        source_buckets {dict<string, dict<string, list(string)>>} -- Source buckets
    """
    host_account_id = awshelper.SessionManager.get_host_account_id()
    for account_id in source_buckets:
        for region in source_buckets[account_id]:
            s3_resource = awshelper.get_resource(awshelper.ServiceName.s3, account_id, run_id)
            s3_client = awshelper.get_client(
                awshelper.ServiceName.s3,
                region,
                account_id,
                run_id)
            for bucket_name in source_buckets[account_id][region]:
                logging.info(f'Processing {bucket_name} in {region} from {account_id}')
                is_empty, client_error = is_bucket_empty(s3_resource, bucket_name)
                if client_error is None:
                    if is_empty:
                        # Update DB status
                        logging.info(f'{bucket_name} in {region} from {account_id} is empty')
                        ddb.update_source_bucket_inventory_status(bucket_name, ddb.BucketInventoryStatus.bucket_is_empty)
                    else:
                        destination_prefix = account_id + "/" + region
                        destination_bucket = "arn:aws:s3:::" + get_destination_bucket_name(run_id, region)
                        inventory_id = utility.get_resource_name(run_id, 's3-inventory', 'orc')
                        inventory_configuration_orc = {
                            "Schedule": {
                                "Frequency": "Daily"
                            },
                            "IsEnabled": True,
                            "Destination": {
                                "S3BucketDestination": {
                                    "Prefix": destination_prefix,
                                    "Format": "ORC",
                                    "Bucket": destination_bucket,
                                    "AccountId": host_account_id
                                }
                            },
                            "OptionalFields": [
                                "Size",
                                "LastModifiedDate",
                                "StorageClass",
                                "ETag",
                                "ReplicationStatus",
                                "IsMultipartUploaded",
                                "EncryptionStatus",
                                "ObjectLockMode",
                                "ObjectLockRetainUntilDate",
                                "ObjectLockLegalHoldStatus"
                            ],
                            "IncludedObjectVersions": "All",
                            "Id": inventory_id
                        }
                        try:
                            response = s3_client.put_bucket_inventory_configuration(
                                Bucket=bucket_name,
                                Id=inventory_id,
                                InventoryConfiguration=inventory_configuration_orc)
                            logging.info(f'put bucket inventory configuration response:{response}')
                            ddb.update_source_bucket_inventory_status(bucket_name, ddb.BucketInventoryStatus.in_progress)
                        except ClientError as e:
                            logging.error(f'error while creating inventory configuration on {account_id}:{region}:{bucket_name}. error details:{e}')

def remove_bucket_inventory_configurations(input_parameters, source_buckets_ddb):
    """ Remove inventory configurations from the given list of source buckets

    Arguments:
        input_parameters {config.S3InsightsInput} -- Input parameters for the current execution
        source_buckets_ddb {dict<string, dict<string, list(string)>>} -- Source buckets
    """
    for account_id in source_buckets_ddb:
        for region in source_buckets_ddb[account_id]:
            s3_client = awshelper.get_client(
                awshelper.ServiceName.s3,
                region,
                account_id,
                input_parameters.run_id)

            for bucket in source_buckets_ddb[account_id][region]:
                bucket_name = bucket.name
                remove_bucket_inventory_configuration_internal(
                    s3_client,
                    input_parameters.run_id,
                    account_id,
                    region,
                    bucket_name)

def remove_bucket_inventory_configuration(run_id, account_id, region, bucket_name):
    """ Remove inventory configuration from the given S3 bucket

    Arguments:
        run_id {string} -- run_id for the current Step Function execution
        account_id {string} -- AWS account id
        region {string} -- AWS region name
        bucket_name {string} -- Bucket name
    """
    s3_client = awshelper.get_client(
        awshelper.ServiceName.s3,
        region,
        account_id,
        run_id)
    remove_bucket_inventory_configuration_internal(s3_client, run_id, account_id, region, bucket_name)

def remove_bucket_inventory_configuration_internal(s3_client, run_id, account_id, region, bucket_name):
    """ Helper function for removing nventory configuration from the given S3 bucket

    Arguments:
        s3_client {boto3.S3.Client} -- Boto3 S3 client
        run_id {string} -- run_id for the current Step Function execution
        account_id {string} -- AWS account id
        region {string} -- AWS region name
        bucket_name {string} -- Bucket name
    """
    try:
        id = utility.get_resource_name(run_id, 's3-inventory', 'orc')
        response = s3_client.delete_bucket_inventory_configuration(
            Bucket=bucket_name,
            Id=id)
        logging.info(f'delete bucket inventory response for {account_id}:{region}:{bucket_name} = {response}')
    except ClientError as e:
        logging.error(f'error while deleting inventory configuration from {account_id}:{region}:{bucket_name}. error details:{e}')

def get_inventory_prefix_at_consolidated_bucket(run_id):
    """ Get the prefix to use for partitioning inventory objects

    Arguments:
        run_id {string} -- run_id for the current Step Function execution

    Returns:
        string -- S3 prefix
    """
    return f'{config.ServiceParameters.consolidated_inventory_s3_folder}/{run_id}/'

def copy_inventory_object_into_consolidation_bucket(run_id, source_bucket_name, source_object_key, destination_bucket_name):
    """ Copy inventory object into the consolidation bucket

    Arguments:
        run_id {string} -- run_id for the current Step Function execution
        source_bucket_name {string} -- Source bucket name
        source_object_key {string} -- Source object key
        destination_bucket_name {string} -- Destination bucket name
    """
    session = awshelper.SessionManager.get_host_aws_session()
    s3_resource = session.resource('s3', config=botocore_config(s3={'use_accelerate_endpoint': True}))
    object_key_parts = source_object_key.split('/')
    object_key_parts_len = len(object_key_parts)
    new_object_key = "{0}account={1}/region={2}/bucketname={3}/{4}".format(
        get_inventory_prefix_at_consolidated_bucket(run_id),
        object_key_parts[0],
        object_key_parts[1],
        object_key_parts[2],
        object_key_parts[object_key_parts_len - 1])

    copy_source = {
        'Bucket': source_bucket_name,
        'Key': source_object_key
    }

    try:
        s3_resource.meta.client.copy(
            copy_source,
            destination_bucket_name,
            new_object_key)
    except ClientError as e:
        if 'Error' in e.response and 'Code' in e.response['Error']['Code'] and utility.compare_strings(e.response['Error']['Code'], "slowdown"):
            wait_in_seconds = random.randint(1, 120)

            # S3 is throttling upload operations. Let's back off for a few seconds
            logging.warning(f's3 is throttling copy request for {source_bucket_name}:{source_object_key}. wait time in seconds:{wait_in_seconds}')
            time.sleep(wait_in_seconds)
        raise

def delete_regional_s3_inventory_bucket(input_parameters, region):
    """ Delete the staging destination bucket for the given region

    Arguments:
        input_parameters {config.S3InsightsInput} -- Input parameters for the current execution
        region {string} -- AWS region name
    """
    s3_resource = awshelper.get_resource(awshelper.ServiceName.s3)
    bucket_name = get_destination_bucket_name(input_parameters.run_id, region)
    logging.info(f'deleting all objects from {region} {bucket_name}')
    try:
        bucket = s3_resource.Bucket(bucket_name)
        bucket.objects.all().delete()
    except ClientError as e:
        logging.error(f'error while deleting all s3 objects from inventory destination bucket {bucket_name}. error details: {e}')

    cloudformation_client = awshelper.get_client(
        awshelper.ServiceName.cloudformation,
        region)
    stack_name = get_stack_name(input_parameters.run_id)
    logging.info(f'deleting cloudformation stack {stack_name} from {region}')
    try:
        response = cloudformation_client.delete_stack(
            StackName=stack_name)
        logging.info(response)
    except ClientError as e:
        logging.error(f'error while deleting inventory destnation bucket stack {stack_name} for {region} region. error details: {e}')

def update_source_bucket_inventory_status(input_parameters, account_id):
    """ Update inventory status for all applicable source buckets under the given AWS account

    Arguments:
        input_parameters {config.S3InsightsInput} -- Input parameters for the current execution
        account_id {string} -- AWS account id
    """
    source_buckets = get_source_buckets(input_parameters, account_id)
    source_buckets_details = ddb.get_source_buckets_details(account_id)
    s3_resources = {}
    for ddb_bucket in source_buckets_details:
        inventory_status = ddb_bucket[ddb.TableFieldName.inventory_status]
        if utility.compare_strings(inventory_status, ddb.BucketInventoryStatus.in_progress):
            ddb_account_id = ddb_bucket[ddb.TableFieldName.account_id]
            ddb_region = ddb_bucket[ddb.TableFieldName.region]
            ddb_bucket_name = ddb_bucket[ddb.TableFieldName.sortkey]

            if not (ddb_account_id in source_buckets
                    and ddb_region in source_buckets[ddb_account_id]
                    and ddb_bucket_name in source_buckets[ddb_account_id][ddb_region]):
                logging.info(f'{ddb_bucket_name} not available anymore. updating the ddb entry')
                ddb.update_source_bucket_inventory_status(
                    ddb_bucket_name,
                    ddb.BucketInventoryStatus.bucket_not_available)
            else:
                if ddb_account_id not in s3_resources:
                    s3_resources[ddb_account_id] = awshelper.get_resource(awshelper.ServiceName.s3, ddb_account_id, input_parameters.run_id)
                s3_resource = s3_resources[ddb_account_id]
                is_empty, client_error = is_bucket_empty(s3_resource, ddb_bucket_name)
                remove_inventory_configuration = False
                if client_error is not None:
                    logging.info(f'{ddb_bucket_name} bucket access lost for some reason. updating the ddb entry')
                    ddb.update_source_bucket_inventory_status(
                        ddb_bucket[ddb.TableFieldName.sortkey],
                        ddb.BucketInventoryStatus.bucket_access_lost)
                    remove_inventory_configuration = True
                elif is_empty:
                    logging.info(f'{ddb_bucket_name} is empty. Updating the DDB entry')
                    ddb.update_source_bucket_inventory_status(
                        ddb_bucket[ddb.TableFieldName.sortkey],
                        ddb.BucketInventoryStatus.bucket_is_empty)
                    remove_inventory_configuration = True

                if remove_inventory_configuration:
                    remove_bucket_inventory_configuration(
                        input_parameters.run_id,
                        ddb_account_id,
                        ddb_region,
                        ddb_bucket_name)

def process_inventory_object(event):
    """ Process an inventory object once it has been stored in a staging destination bucket

    Arguments:
        event {json} -- S3 notification event
    """
    if 'Records' in event:
        input_parameters = ddb.get_input_parameters()
        for record in event['Records']:
            if 'body' in record:
                body_json = json.loads(record['body'])
                if 'Records' in body_json:
                    for record in body_json['Records']:
                        if 'eventName' in record and record['eventName'] == 'ObjectCreated:Put':
                            source_bucket_name = record['s3']['bucket']['name']
                            if is_destination_bucket_name(input_parameters, source_bucket_name):
                                source_object_key = record['s3']['object']['key']
                                object_key_parts = source_object_key.split('/')
                                object_key_parts_len = len(object_key_parts)

                                bucket_account_id = object_key_parts[0].lower()
                                bucket_region = object_key_parts[1].lower()
                                bucket_name = object_key_parts[2].lower()
                                logging.info(f'source_object_key:{source_object_key} bucket_account_id:{bucket_account_id} bucket_name:{bucket_name}')
                                if ddb.is_inprogress_inventory_job(bucket_account_id, bucket_name):
                                    if object_key_parts_len > 4:
                                        if utility.compare_strings(object_key_parts[object_key_parts_len - 1], 'manifest.checksum'):
                                            ddb.update_source_bucket_inventory_status(object_key_parts[2], ddb.BucketInventoryStatus.done)
                                            remove_bucket_inventory_configuration(
                                                input_parameters.run_id,
                                                bucket_account_id,
                                                bucket_region, bucket_name
                                            )
                                        elif utility.compare_strings(object_key_parts[object_key_parts_len - 2], 'data'):
                                            copy_inventory_object_into_consolidation_bucket(
                                                input_parameters.run_id,
                                                source_bucket_name,
                                                source_object_key,
                                                config.DeploymentDetails.consolidated_inventory_bucket_name
                                            )
                                else:
                                    logging.warning('Received an unexpected SQS notification')


import trio
import json
import time
from collections import deque
import logging
from constants import *

log = logging.getLogger(__name__)
log.setLevel(logging.INFO)

# the key used to store timestamps to invalidate packets
# this could be a per-instance constant, but it will be much easier if
# everything uses the same key
TIME_KEY = 't'

class ConnectionClosed(Exception):
    pass

class JSONStream:
    """ A wrapper around a trio.Stream """

    def __init__(self, stream):
        self._stream = stream

        # TODO: use lockable!!
        self._write_semaphore = trio.Semaphore(1)

        # blocks reading from stream and _read_buf at the same time
        self._read_semaphore = trio.Semaphore(1)

        self._read_buf = bytearray()

    async def read(self):
        async with self._read_semaphore:
            log.debug(f"Acquired reading semaphore")
            i = self._read_buf.find(b'\n')
            while i == -1:
                try:
                    data = await self._stream.receive_some(BUFSIZE)
                except trio.BrokenResourceError:
                    raise ConnectionClosed("stream closed suddenly while reading")

                if not data:
                    raise ConnectionClosed("stream closed while reading")

                self._read_buf += data

                i = self._read_buf.find(b'\n')
                log.debug(f"Adding to buffer {data}")

            i += 1

            line = str(self._read_buf[:i], encoding='utf-8')
            self._read_buf[:i] = []

        log.debug(f"(release read semaphore) Parsing line: {line!r}")

        if line.strip() == "":
            raise ValueError(f"Invalid empty value: {line!r}")

        try:
            obj = json.loads(line)
        except ValueError:
            log.exception(f"Invalid JSON: {line!r}")
            raise

        if not isinstance(obj, dict):
            raise ValueError(f"should be dict, got {type(obj)} in {obj}")

        log.info(f"Read {obj!r}")
        return obj

    async def write(self, obj):
        log.info(f"Sending {obj}")
        if not isinstance(obj, dict):
            raise ValueError(f"should send dict, got {obj!r}")

        await self._write_semaphore.acquire()
        log.debug(f"Sending {obj}")
        try:
            await self._stream.send_all(bytes(json.dumps(obj) + '\n', encoding='utf-8'))
        except trio.BrokenResourceError:
            raise ConnectionClosed(f"stream closed while writing")

        self._write_semaphore.release()
        log.debug("Release writing semaphore")

    async def aclose(self):
        log.info(f"Closing stream {self}")
        with trio.move_on_after(1) as cancel_scope:
            await self._write_semaphore.acquire()
            log.debug("Got write semaphore")
            await self._read_semaphore.acquire()
            log.debug("Got read semaphore")

        if cancel_scope.cancelled_caught:
            log.warning("Forcefully closing stream after 1 second, "
                        "semaphore weren't acquired")

        await self._stream.aclose()
        log.debug('Stream closed, releasing semaphores')
        self._write_semaphore.release()
        self._read_semaphore.release()

class TimedStream(JSONStream):

    """ Time aware JSON stream. It discards old messages. Good any stream based
    on UDP. If you use TCP, it's very unlikely that you want to use this class.
    Instead, just use a regular JSONStream.

    I agree this is a very bad name, but I don't have any better ideas right
    now...
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._last_timestamp = 0

    async def read(self):
        obj = await super().read()

        if TIME_KEY not in obj:
            raise ValueError(f"no time key ({TIME_KEY!r}) in {obj!r}")

        if obj[TIME_KEY] < self._last_timestamp:
            log.warning(f"Discarding old message (t={self._last_timestamp}) {obj}")
            return await self.read()

        self._last_timestamp = obj[TIME_KEY]
        del obj[TIME_KEY]

        return obj

    async def write(self, obj):
        if TIME_KEY in obj:
            raise ValueError(f"key {TIME_KEY!r} is reserved in {obj!r}")

        obj[TIME_KEY] = time.time()
        return await super().write(obj)

if __name__ == "__main__":
    logging.basicConfig(
        format='%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S',
        level=logging.DEBUG
    )
    log.setLevel(logging.DEBUG)

    async def handler(stream):
        stream = JSONStream(stream)
        while True:
            print(await stream.read())
    log.info("running")
    trio.run(trio.serve_tcp, handler, 9043)


from tkinter import *
import cv2
import PIL.Image, PIL.ImageTk
import pyttsx3
import datetime
import findJoke as joke
from AnimatedGIF import *
from battery_events import *
import speech_recognition as sr
import wikipedia
import webbrowser
import os
import youtube as ytb
import random
import smtplib
import roman
def sysreboot():

    ch = takeCommand().lower()
    if 'yes' in ch:
        speak('System restarting in, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1')
        os.system("shutdown /r /t 1")
    elif 'no' in ch:
        speak('System reboot, terminated!')
    else:
        speak("I didn't get that! say once more!" )
        sysreboot()
def ctime():
     strTime = datetime.datetime.now().strftime("%H houres and %M minutes")
     speak(f"Sir, the time is {strTime}")
## function
def sysshutdown():

    ch = takeCommand().lower()

    if 'yes' in ch:
      speak('System shutting down in, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1')
      os.system("shutdown /s /t 1")
    elif 'no' in ch:
      speak('System shut down, terminated!')
    else:
        speak("I didn't get that! say once more!" )
        sysshutdown()
#from Class1 import Student
#import pytesseract
from PIL import Image

#pytesseract.pytesseract.tesseract_cmd = r"C:\Users\mridu\AppData\Local\Tesseract-OCR\tesseract.exe"

numbers = {'hundred':100, 'thousand':1000, 'lakh':100000}
a = {'name':'your email'}
engine = pyttsx3.init('sapi5')
voices = engine.getProperty('voices')
engine.setProperty('voice', voices[1].id)

window = Tk()

global var
global var1

var = StringVar()
var1 = StringVar()

def speak(audio):
    engine.say(audio)
    engine.runAndWait()

def sendemail(to, content):
    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.ehlo()
    server.starttls()
    server.login('email id', 'password') # email id - use any email id whose security/privacy is off
    server.sendmail('email id', to, content)
    server.close()

def wishme():
    hour = int(datetime.datetime.now().hour)
    if hour >= 0 and hour <= 12:
        var.set("Good Morning Manoj") #Name - your Name
        speak('Starting system sir!')
        speak('Loading Dependencies!')
        bevents()
        window.update()
        speak("Good Morning Manoj!")
    elif hour >= 12 and hour <= 18:
        var.set("Good Afternoon Manoj!")
        speak('Starting system sir!')
        speak('Loading Dependencies!')
        bevents()
        window.update()
        speak("Good Afternoon Manoj!")
    else:
        var.set("Good Evening Manoj")
        speak('Starting system!')
        speak('Loading Dependencies!')

        bevents()
        window.update()
        speak("Good Evening Manoj!")
    speak("waiitn for response") #BotName - Give a name to your assistant

def takeCommand():
    r = sr.Recognizer()
    try:
        with sr.Microphone() as source:
            var.set("Listening...")
            window.update()
            print("Listening...")
            r.energy_threshold = 500
            audio = r.listen(source,timeout = 2)
    except:
        takeCommand()
    try:
        var.set("Recognizing...")
        window.update()
        print("Recognizing")
        query = r.recognize_google(audio, language='en-in')
    except Exception as e:
        return "None"
    var1.set(query)
    window.update()
    return query

def play():
    btn2['state'] = 'disabled'
    btn0['state'] = 'disabled'
    btn1.configure(bg = 'orange')
    wishme()
    while True:
        btn1.configure(bg = 'orange')
        query = takeCommand().lower()
        print(query)
        print(type(query))
        if 'exit' in query:
            var.set("Bye sir")

            btn1.configure(bg = '#5C85FB')
            btn2['state'] = 'normal'
            btn0['state'] = 'normal'
            window.update()
            speak("Bye sir")
            break

        elif 'wikipedia' in query:
            if 'open wikipedia' in query:
                webbrowser.open('wikipedia.com')
            else:
                try:
                    speak("searching wikipedia")
                    query = query.replace("according to wikipedia", "")
                    results = wikipedia.summary(query, sentences=2)
                    speak("According to wikipedia")
                    var.set(results)
                    window.update()
                    speak(results)
                except Exception as e:
                    var.set('sorry sir could not find any results')
                    window.update()
                    speak('sorry sir could not find any results')
        elif 'clear bin' or 'recycle' in query:
            try:
                import winshell
                winshell.recycle_bin().empty(confirm=False, show_progress=False, sound=False)
                window.update()
                speak('Trash Cleared!')
            except Exception as e:
                window.update()
                speak('Bin is clean sir!')
        elif 'power status' in query:
            bevents()
            window.update()
        elif 'shutdown system' in query or 'shutdown' or 'shut down' in query:
            speak("System Shut Down Initiated! Are you sure sir?")
            sysshutdown()
            window.update()
        elif "joke" in query:
            # search query for joke
            speak("Looking for a good joke for you")
            my_joke = joke.tellAJoke()
            print(my_joke)
            window.update()
            speak(my_joke)
        elif 'reboot system' in query:
            speak("System Shut Down Initiated! Are you sure sir?")
            sysreboot()
            window.update()

        elif 'open youtube' in query:
            var.set('opening Youtube')
            window.update()
            speak('opening Youtube')
            query_text=query.split(' ')[1]
            ytb.playYoutubeVideo(query_text)

        elif 'open course error' in query:
            var.set('opening course era')
            window.update()
            speak('opening course era')
            webbrowser.open("coursera.com")

        elif 'open google' in query:
            var.set('opening google')
            window.update()
            speak('opening google')
            webbrowser.open("google.com")

        elif 'hello' in query:
            var.set('Hello Sir')
            window.update()
            speak("Hello Sir")

        elif 'open stackoverflow' in query:
            var.set('opening stackoverflow')
            window.update()
            speak('opening stackoverflow')
            webbrowser.open('stackoverflow.com')

        elif ('play music' in query) or ('change music' in query):
            var.set('Here are your favorites')
            window.update()
            speak('Here are your favorites')
            music_dir = 'D:\My Music\Favourites' # Enter the Path of Music Library
            songs = os.listdir(music_dir)
            n = random.randint(0,27)
            os.startfile(os.path.join(music_dir, songs[n]))

        elif 'the time' or 'time' in query:
            strtime = datetime.datetime.now().strftime("%H:%M:%S")
            var.set("Sir the time is %s" % strtime)
            window.update()
            speak("Sir the time is %s" %strtime)

        elif 'the date' or 'date' in query:
            strdate = datetime.datetime.today().strftime("%d %m %y")
            var.set("Sir today's date is %s" %strdate)
            window.update()
            speak("Sir today's date is %s" %strdate)

        elif 'thank you' in query:
            var.set("Welcome Sir")
            window.update()
            speak("Welcome Sir")

        elif 'can you do for me' in query:
            var.set('I can do multiple tasks for you sir. tell me whatever you want to perform sir')
            window.update()
            speak('I can do multiple tasks for you sir. tell me whatever you want to perform sir')

        elif 'old are you' in query:
            var.set("I am a little baby sir")
            window.update()
            speak("I am a little baby sir")

        elif 'open media player' in query:
            var.set("opening VLC media Player")
            window.update()
            speak("opening V L C media player")
            path = "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe" #Enter the correct Path according to your system
            os.startfile(path)

        elif 'your name' in query:
            var.set("Myself Jarvis Sir")
            window.update()
            speak('myself Jarvis sir')

        elif 'who creates you' in query:
            var.set('My Creator is Mr. Manoj')
            window.update()
            speak('My Creator is Mr. Manoj')

        elif 'say hello' in query:
            var.set('Hello Everyone! My self Jarvis')
            window.update()
            speak('Hello Everyone! My self Jarvis')

        elif 'open pycharm' in query:
            var.set("Openong Pycharm")
            window.update()
            speak("Opening Pycharm")
            path = "C:\\Program Files\\JetBrains\\PyCharm Community Edition 2018.3.2\\bin\\pycharm64.exe" #Enter the correct Path according to your system
            os.startfile(path)

        elif 'open chrome' in query:
            var.set("Opening Google Chrome")
            window.update()
            speak("Opening Google Chrome")
            path = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe" #Enter the correct Path according to your system
            os.startfile(path)

        elif 'email to me' in query:
            try:
                var.set("What should I say")
                window.update()
                speak('what should I say')
                content = takeCommand()
                to = a['name']
                sendemail(to, content)
                var.set('Email has been sent!')
                window.update()
                speak('Email has been sent!')

            except Exception as e:
                print(e)
                var.set("Sorry Sir! I was not able to send this email")
                window.update()
                speak('Sorry Sir! I was not able to send this email')

        elif "open python" in query:
            var.set("Opening Python Ide")
            window.update()
            speak('opening python Ide')
            os.startfile('C:\\Users\\mridu\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Python 3.7\\IDLE (Python 3.7 64-bit)') #Enter the correct Path according to your system

        elif 'open code blocks' in query:
            var.set('Opening Codeblocks')
            window.update()
            speak('opening Codeblocks')
            os.startfile("C:\\Program Files (x86)\\CodeBlocks\\codeblocks.exe") #Enter the correct Path according to your system

        elif 'open anaconda' in query:
            var.set('Opening Anaconda')
            window.update()
            speak('opening anaconda')
            os.startfile("C:\\Users\\mridu\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Anaconda3 (64-bit)\\Anaconda Navigator") #Enter the correct Path according to your system

        elif 'calculation' in query:
            sum = 0
            var.set('Yes Sir, please tell the numbers')
            window.update()
            speak('Yes Sir, please tell the numbers')
            while True:
                query = takeCommand()
                if 'answer' in query:
                    var.set('here is result'+str(sum))
                    window.update()
                    speak('here is result'+str(sum))
                    break
                elif query:
                    if query == 'x**':
                        digit = 30
                    elif query in numbers:
                        digit = numbers[query]
                    elif 'x' in query:
                        query = query.upper()
                        digit = roman.fromRoman(query)
                    elif query.isdigit():
                        digit = int(query)
                    else:
                        digit = 0
                    sum += digit

        elif 'click photo' in query:
            stream = cv2.VideoCapture(0)
            grabbed, frame = stream.read()
            if grabbed:
                cv2.imshow('pic', frame)
                cv2.imwrite('pic.jpg',frame)
            stream.release()

        elif 'record video' in query:
            cap = cv2.VideoCapture(0)
            out = cv2.VideoWriter('output.avi', -1, 20.0, (640,480))
            while(cap.isOpened()):
                ret, frame = cap.read()
                if ret:

                    out.write(frame)

                    cv2.imshow('frame',frame)
                    if cv2.waitKey(1) & 0xFF == ord('q'):
                        break
                else:
                    break
            cap.release()
            out.release()
            cv2.destroyAllWindows()

def update(ind):
    frame = frames[(ind)%100]
    ind += 1
    label.configure(image=frame)
    window.after(100, update, ind)

label2 = Label(window, textvariable = var1,)
label2.config(font=("Courier", 20))
var1.set('')
label2.pack()
# window.configure(background='black')
label1 = Label(window, textvariable = var,)
label1.config(font=("Courier", 20))
var.set('Welcome')
label1.pack()

frames = [PhotoImage(file='Anim.gif',format = 'gif -index %i' %(i)) for i in range(100)]
window.title('JARVIS')
# lbl_with_my_gif = AnimatedGif(window, 'Anim.gif', 0.001)  # (tkinter.parent, filename, delay between frames)
# lbl_with_my_gif.pack()  # Packing the label with the animated gif (grid works just as well)
# lbl_with_my_gif.start_thread()
label = Label(window, width = 500, height = 500)
label.pack()
window.after(0, update, 0)

btn0 = Button(text = 'WISH ME',width = 20, command = wishme, bg = '#5C85FB')
btn0.config(font=("Courier", 12))
btn0.pack()
btn1 = Button(text = 'PLAY',width = 20,command = play, bg = '#5C85FB')
btn1.config(font=("Courier", 12))
btn1.pack()
btn2 = Button(text = 'EXIT',width = 20, command = window.destroy, bg = '#5C85FB')
btn2.config(font=("Courier", 12))
btn2.pack()

window.mainloop()


from django.urls import path
# vistas importadas
from . import views

urlpatterns = [

    path('home/', views.IndexView.as_view()),
    path('lista/', views.PruebaListviwe.as_view()),
    path('lista-prueba/', views.ModeloPruebaListView.as_view()),
    path(
        'add-prueba/',
        views.PruebaCreateView.as_view(),
        name='prueba_add'),
    path(
        'resume-foundation/',
        views.ResumeFoundationView.as_view(),
        name='resume_foundation'),
]


import pathlib
import os

import sys
import cv2
import numpy as np

import PyQt5
from PyQt5 import uic
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

from pathlib import Path

file_abspath = os.path.abspath(__file__)
folder_abspath = os.path.dirname(file_abspath)

form_class = uic.loadUiType(os.path.join(folder_abspath, "simple_video.ui"))[0]

def letter_box_resize(img, dsize):

    original_height, original_width = img.shape[:2]
    target_width, target_height = dsize

    ratio = min(
        float(target_width) / original_width,
        float(target_height) / original_height)
    resized_height, resized_width = [
        round(original_height * ratio),
        round(original_width * ratio)
    ]

    img = cv2.resize(img, dsize=(resized_width, resized_height))

    pad_left = (target_width - resized_width) // 2
    pad_right = target_width - resized_width - pad_left
    pad_top = (target_height - resized_height) // 2
    pad_bottom = target_height - resized_height - pad_top

    # padding
    img = cv2.copyMakeBorder(img,
                             pad_top,
                             pad_bottom,
                             pad_left,
                             pad_right,
                             cv2.BORDER_CONSTANT,
                             value=(0, 0, 0))

    try:
        if not(img.shape[0] == target_height and img.shape[1] == target_width):  # 둘 중 하나는 같아야 함
            raise Exception('Letter box resizing method has problem.')
    except Exception as e:
        print('Exception: ', e)
        exit(1)

    return img

class WindowClass(QMainWindow, form_class) :
    def __init__(self) :
        super().__init__()
        self.setupUi(self)

        self.video_capture = None

        #Icon Load
        self.pushButton_file_open.setIcon(QIcon(os.path.join(folder_abspath, 'images', 'icon_file_open.png')))

        self.pushButton_play.setIcon(QIcon(os.path.join(folder_abspath, 'images', 'icon_play.png')))
        self.pushButton_play.setIconSize(QSize(32, 32))

        self.pushButton_scene_save.setIcon(QIcon(os.path.join(folder_abspath, 'images', 'icon_save.png')))
        self.pushButton_scene_save.setIconSize(QSize(32, 32))

        self.pushButton_scene_remove.setIcon(QIcon(os.path.join(folder_abspath, 'images', 'icon_remove.png')))
        self.pushButton_scene_save.setIconSize(QSize(32, 32))

        self.pushButton_file_open.clicked.connect(self.load_video)
        self.pushButton_play.clicked.connect(self.play)
        self.pushButton_scene_init.pressed.connect(self.init_scene_setting)
        self.pushButton_scene_start.pressed.connect(self.set_scene_start_frame)
        self.pushButton_scene_end.pressed.connect(self.set_scene_end_frame)
        self.pushButton_scene_save.clicked.connect(self.save)
        self.pushButton_scene_remove.clicked.connect(self.remove_scene)
        self.pushButtonECGOk.clicked.connect(self.recodeECGQuality)
        self.pushButton_play.setEnabled(False)
        self.pushButton_scene_init.setEnabled(False)
        self.pushButton_scene_start.setEnabled(False)
        self.pushButton_scene_end.setEnabled(False)
        self.pushButton_scene_save.setEnabled(False)
        self.pushButton_scene_remove.setEnabled(False)

        self.horizontalSlider.setEnabled(False)
        self.horizontalSlider.valueChanged.connect(self.move_frame)

        self.comboBoxECG.setCurrentIndex(0)
        self.comboBoxECG.currentIndexChanged.connect(self.getECGPart)
        self.pushButtonECGRemove.clicked.connect(self.removeECGPart)
        self.radioButtonECGGood.toggled.connect(lambda:self.type_ecg_choose(self.radioButtonECGGood))
        self.radioButtonECGBad.toggled.connect(lambda:self.type_ecg_choose(self.radioButtonECGBad))
        self.radioButtonECGOther.toggled.connect(lambda:self.type_ecg_choose(self.radioButtonECGOther))

        self.radioButtonImgGood.toggled.connect(lambda:self.type_img_choose(self.radioButtonImgGood))
        self.radioButtonImgBad.toggled.connect(lambda:self.type_img_choose(self.radioButtonImgBad))
        self.radioButtonImgOther.toggled.connect(lambda:self.type_img_choose(self.radioButtonImgOther))

        self.radioButtonRhythmSinus.toggled.connect(lambda:self.type_rhythm_choose(self.radioButtonRhythmSinus))
        self.radioButtonRhythmArrh.toggled.connect(lambda:self.type_rhythm_choose(self.radioButtonRhythmArrh))

        self.scene_progressbar_timer = QTimer()

        self.video_play_timer = QTimer()
        self.video_play_timer.timeout.connect(self.read_next_frame)

        self.scene_progressbar_timer.setInterval(1000/60.)
        self.scene_progressbar_timer.timeout.connect(self.draw_scene_progress_bar)
        self.scene_progressbar_timer.start()

        QShortcut(Qt.Key_Space, self, self.play)

        self.listWidget.itemClicked.connect(self.move_scene)

        self.typeECG = {'ECG part': 'First part','ECG quality': 'undefined',
                        'Img quality': 'undefined',
                        'Rhythm': 'undefined',}

    def getECGPart(self):
        self.typeECG['ECG part'] = self.comboBoxECG.currentText()
    def video_capture_release(self):
        if self.video_capture == None:
            return None
        self.video_capture.release()

    def load_video(self):

        self.video_file = QFileDialog.getOpenFileName(self, "Open a file", folder_abspath , "video file (*.mp4 *.avi *.mkv *.MP4 *.AVI *.MKV)")[0]
        print(self.video_file)
        if len(self.video_file) == 0:
            return None

        self.scene_start_frame_index = 0
        self.scene_end_frame_index = 0

        self.video_name = Path(self.video_file).resolve().stem
        self.patient_name = self.video_file.split('/')[-2]
        print(self.patient_name)
        self.frame_index = 0

        self.video_capture_release()
        self.video_capture = cv2.VideoCapture(self.video_file, apiPreference=cv2.CAP_FFMPEG)

        if self.video_capture == None or not self.video_capture.isOpened():
            return self.video_capture_release()

        self.video_fps = self.video_capture.get(cv2.CAP_PROP_FPS)
        self.video_num_frames = int(self.video_capture.get(cv2.CAP_PROP_FRAME_COUNT))

        self.video_play_timer.setInterval(1000./self.video_fps)

        self.horizontalSlider.blockSignals(True)
        self.horizontalSlider.setValue(0)
        self.horizontalSlider.blockSignals(False)

        self.horizontalSlider.setEnabled(True)
        self.horizontalSlider.setMinimum(0)
        self.horizontalSlider.setMaximum(self.video_num_frames)

        self.pushButton_play.setEnabled(True)
        self.pushButton_scene_init.setEnabled(False)
        self.pushButton_scene_start.setEnabled(True)
        self.pushButton_scene_end.setEnabled(False)
        self.pushButton_scene_save.setEnabled(True)
        self.pushButton_scene_remove.setEnabled(True)

        self.listWidget.clear()
        self.read_next_frame()

    def play(self):
        if not self.pushButton_play.isEnabled():
            return None

        if self.video_play_timer.isActive():
            self.pushButton_play.setIcon(QIcon(os.path.join(folder_abspath, "images", 'icon_play.png')))
            self.video_play_timer.stop()
        else:
            self.pushButton_play.setIcon(QIcon(os.path.join(folder_abspath, "images", 'icon_pause.png')))
            self.video_play_timer.start()

    def init_scene_setting(self):
        self.pushButton_scene_start.setEnabled(True)
        self.pushButton_scene_end.setEnabled(False)
        self.pushButton_scene_init.setEnabled(False)

    def set_scene_start_frame(self):
        self.scene_start_frame_index = self.frame_index

        self.pushButton_scene_start.setEnabled(False)
        self.pushButton_scene_end.setEnabled(True)
        self.pushButton_scene_init.setEnabled(True)

    def set_scene_end_frame(self):
        self.scene_end_frame_index = self.frame_index
        self.init_scene_setting()
        self.listWidget.addItem(str(self.scene_start_frame_index) + "_" + str(self.scene_end_frame_index))

    def recodeECGQuality(self):
        ecgQualityNote = ''
        if self.typeECG['ECG quality'] == 'Others':
            ecgQualityNote = self.lineEditECG.text()
        self.listWidgetECG.addItem(self.typeECG['ECG part']+ ' - '+self.typeECG['ECG quality']+' '+ecgQualityNote)

    def move_scene(self):
        if self.video_play_timer.isActive():
            self.video_play_timer.stop()

        clicked_item = self.listWidget.currentItem().text()
        clicked_item = clicked_item.split('_')

        start_frame_index = int(clicked_item[0])

        self.frame_index = start_frame_index
        self.video_capture.set(cv2.CAP_PROP_POS_FRAMES, self.frame_index)

        self.read_next_frame()

        print(str(self.listWidget.currentRow()) + " : " + self.listWidget.currentItem().text())

    def remove_scene(self):
        self.removeItemRow = self.listWidget.currentRow()
        self.listWidget.takeItem(self.removeItemRow)

    def removeECGPart(self):
        self.removeItemRow = self.listWidgetECG.currentRow()
        self.listWidgetECG.takeItem(self.removeItemRow)
    def type_ecg_choose(self, btn):
        if btn.text()=='Good' and btn.isChecked()==True:
            self.typeECG['ECG quality'] = 'Good'
        elif btn.text()=='Bad' and btn.isChecked()==True:
            self.typeECG['ECG quality'] = 'Bad'
        elif btn.text()=='Others' and btn.isChecked()==True:
            self.typeECG['ECG quality'] = 'Others'

    def type_img_choose(self, btn):
        if btn.text()=='Good' and btn.isChecked()==True:
            self.typeECG['Img quality'] = 'Good'
        elif btn.text()=='Bad' and btn.isChecked()==True:
            self.typeECG['Img quality'] = 'Bad'
        elif btn.text()=='Others' and btn.isChecked()==True:
            self.typeECG['Img quality'] = 'Others'

    def type_rhythm_choose(self, btn):
        if btn.text()=='Sinus Rhythm' and btn.isChecked()==True:
            self.typeECG['Rhythm'] = 'Sinus Rhythm'
        elif btn.text()=='Arrhythmia' and btn.isChecked()==True:
            self.typeECG['Rhythm'] = 'Arrhythmia'
        elif btn.text()=='Others' and btn.isChecked()==True:
            self.typeECG['Rhythm'] = 'Others'

    def save(self):
        # 判断类型是否选择
        # print(self.radioButtonRateGood.isChecked())

        if self.listWidget.count() == 0:
            return None

        if self.video_play_timer.isActive():
            self.video_play_timer.stop()

        self.scene_progressbar_timer.stop()
        if not os.path.isdir("./" + self.video_name):
            os.mkdir("./" + self.video_name)
        if self.typeECG['Img quality']=='undefined':
            msg_box = QMessageBox(QMessageBox.Warning, "提示", "图像质量未标记")
            msg_box.exec_()
        if self.typeECG['Rhythm']=='undefined':
            msg_box = QMessageBox(QMessageBox.Warning, "提示", "心率类型未标记")
            msg_box.exec_()
        # 保存关键帧
        for item_index in range(self.listWidget.count()):
            item = self.listWidget.item(item_index).text()
            item = item.split('_')

            start_frame_index = int(item[0])
            end_frame_index = int(item[1])

            self.video_capture.set(cv2.CAP_PROP_POS_FRAMES, start_frame_index)

            scene_folder = os.path.join("./label/",self.patient_name,self.video_name, "s" + format(item_index + 1, '02d'))
            print(scene_folder)
            for i in range(start_frame_index, end_frame_index):
                if not os.path.isdir(scene_folder):
                    os.makedirs(scene_folder)

                read_frame, frame = self.video_capture.read()

                frame_name = self.video_name + "_f" + format(i, '05d') + ".png"
                cv2.imwrite(os.path.join(scene_folder, frame_name), frame)
        # 保存信息
        with open(os.path.join("./label/",self.patient_name,self.video_name,self.video_name + '.txt'), 'w') as f:
            ImgNote = ''
            RhythmNote = ''
            if self.typeECG['Img quality'] == 'Others':
                ImgNote = self.lineEditImg.text()
            if self.typeECG['Rhythm'] == 'others':
                RhythmNote = self.lineEditRhythm.text()

            self.frameItems = self.listWidget.findItems('_',  Qt.MatchContains)
            f.write('keyFrameIndex: {')
            for i in range(len(self.frameItems)):
                f.write(self.frameItems[i].text())
                f.write(', ')
            f.write('}\n')
            self.ecgItems = self.listWidgetECG.findItems('-',  Qt.MatchContains)
            f.write('ecgQualityIndex: {')
            for i in range(len(self.ecgItems)):
                f.write(self.ecgItems[i].text())
                f.write(', ')
            f.write('}\n')

            f.write('Img quality: '+ self.typeECG['Img quality']+' '+ImgNote+'\n')
            f.write('Rhythm: '+ self.typeECG['Rhythm']+' '+RhythmNote)
            # print(1)

        self.scene_progressbar_timer.start()
        msg_box = QMessageBox(QMessageBox.Warning, "保存结果", "恭喜！标记保存完毕")
        msg_box.exec_()

    def move_frame(self):
        if self.video_play_timer.isActive():
            self.video_play_timer.stop()

        self.frame_index = self.horizontalSlider.value()-1
        self.video_capture.set(cv2.CAP_PROP_POS_FRAMES, self.frame_index)

        self.read_next_frame()

        if not self.pushButton_scene_start.isEnabled():#
            if self.frame_index < self.scene_start_frame_index:
                QMessageBox.question(self, 'Message', 'Scene setting is intialized', QMessageBox.Yes)
                self.init_scene_setting()

    def read_next_frame(self):
        if not self.pushButton_play.isEnabled():
            return None

        read_frame, frame = self.video_capture.read()

        if read_frame:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame = letter_box_resize(frame, (self.label_frame.width(), self.label_frame.height()))
            height, width, channels = frame.shape
            bytesPerLine = channels * width
            qImg = QImage(frame.data, width, height, bytesPerLine, QImage.Format_RGB888)
            pixmap01 = QPixmap.fromImage(qImg)

            self.label_frame.setPixmap(pixmap01)
            self.frame_index += 1

            self.horizontalSlider.blockSignals(True)
            self.horizontalSlider.setValue(self.frame_index)
            self.horizontalSlider.blockSignals(False)

            self.label_frame_index.setText(str(self.frame_index)+ "/" + str(self.video_num_frames))

    def draw_scene_progress_bar(self):
        if not self.pushButton_play.isEnabled():
            return None

        scene_progress_bar = np.zeros((self.label_scene_progress_bar.height(), self.label_scene_progress_bar.width(), 3), np.uint8)

        if not self.pushButton_scene_start.isEnabled():
            start_frame_index = int(self.label_scene_progress_bar.width() * (float(self.scene_start_frame_index) / self.video_num_frames))
            end_frame_index = int(self.label_scene_progress_bar.width() * (float(self.frame_index) / self.video_num_frames))
            scene_progress_bar[:, start_frame_index:end_frame_index] = [255, 255, 0]

        for item_index in range(self.listWidget.count()):
            item = self.listWidget.item(item_index).text()
            item = item.split('_')

            start_frame_index = int(self.label_scene_progress_bar.width() * (float(item[0]) / self.video_num_frames))
            end_frame_index = int(self.label_scene_progress_bar.width() * (float(item[1]) / self.video_num_frames))

            scene_progress_bar[:, start_frame_index:end_frame_index] = [0, 255, 0]

        height, width, channels = scene_progress_bar.shape
        bytesPerLine = channels * width
        qImg = QImage(scene_progress_bar.data, width, height, bytesPerLine, QImage.Format_RGB888)
        pixmap01 = QPixmap.fromImage(qImg)
        self.label_scene_progress_bar.setPixmap(pixmap01)

if __name__ == "__main__" :
    app = QApplication(sys.argv)
    myWindow = WindowClass()
    myWindow.show()
    app.exec_()


"""Utils that materialize plugins"""
# pylint: disable=global-statement
import logging
import pydoc
from typing import Any, Dict

from plynx.base.executor import BaseExecutor
from plynx.base.hub import BaseHub
from plynx.base.resource import BaseResource
from plynx.utils.config import PluginsConfig, get_plugins

def _isinstance_namedtuple(x: Any) -> bool:
    return isinstance(x, tuple) and getattr(x, '_fields', None) is not None

def _as_dict(obj: Any):
    if _isinstance_namedtuple(obj):
        return {
            key: _as_dict(getattr(obj, key)) for key in obj._fields
        }
    elif isinstance(obj, list):
        return [_as_dict(value) for value in obj]
    return obj

class _ResourceManager:
    def __init__(self, plugins: PluginsConfig):
        self.resources = plugins.resources
        self.kind_to_resource_class: Dict[str, BaseResource] = {
            resource.kind: pydoc.locate(resource.cls)   # type: ignore
            for resource in self.resources
        }
        self.kind_to_resource_dict: Dict[str, Dict[str, Any]] = {
            resource.kind: resource._asdict() for resource in self.resources
        }
        for kind, resource_class in self.kind_to_resource_class.items():
            logging.info(f"Initializing resource `{kind}`")
            self.kind_to_resource_dict[kind]['display_raw'] = resource_class.DISPLAY_RAW

class _ExecutorManager:
    def __init__(self, plugins: PluginsConfig):
        self.kind_to_executor_class: Dict[str, BaseExecutor] = {}
        self.kind_to_icon = {}
        self.kind_to_color = {}
        self.kind_to_title = {}
        for o_or_w in plugins.workflows + plugins.operations + plugins.dummy_operations:
            self.kind_to_executor_class[o_or_w.kind] = pydoc.locate(o_or_w.executor)    # type: ignore
            if not self.kind_to_executor_class[o_or_w.kind]:
                raise Exception(f"Executor `{o_or_w.executor}` not found")
            self.kind_to_icon[o_or_w.kind] = o_or_w.icon
            self.kind_to_color[o_or_w.kind] = o_or_w.color
            self.kind_to_title[o_or_w.kind] = o_or_w.title

        self.kind_info = {}
        for kind, executor_class in self.kind_to_executor_class.items():
            logging.info(f"Initializing executor `{kind}`")
            self.kind_info[kind] = {
                'is_graph': executor_class.IS_GRAPH,
                'title': self.kind_to_title[kind],
                'icon': self.kind_to_icon[kind],
                'color': self.kind_to_color[kind],
            }

class _OperationManager:
    def __init__(self, plugins: PluginsConfig):
        self.operations = plugins.operations
        self.kind_to_operation_dict = {
            operation.kind: _as_dict(operation) for operation in self.operations
        }

class _HubManager:
    def __init__(self, plugins: PluginsConfig):
        self.hubs = plugins.hubs
        self.kind_to_hub_class: Dict[str, BaseHub] = {
            hub.kind: pydoc.locate(hub.cls)(**hub.args)     # type: ignore
            for hub in self.hubs
        }
        self.kind_to_hub_dict = {
            hub.kind: hub._asdict() for hub in self.hubs
        }

class _WorkflowManager:
    def __init__(self, plugins: PluginsConfig):
        self.workflows = plugins.workflows
        self.kind_to_workflow_dict = {
            workflow.kind: workflow._asdict() for workflow in self.workflows
        }

_plugins: PluginsConfig = get_plugins()

_RESOURCE_MANAGER = None
_OPERATION_MANAGER = None
_HUB_MANAGER = None
_WORKFLOW_MANAGER = None
_EXECUTOR_MANAGER = None

_PLUGINS_DICT = None

def get_resource_manager():
    """Generate Resource plugin structure"""
    global _RESOURCE_MANAGER
    if not _RESOURCE_MANAGER:
        _RESOURCE_MANAGER = _ResourceManager(_plugins)
    return _RESOURCE_MANAGER

def get_operation_manager():
    """Generate Operation plugin structure"""
    global _OPERATION_MANAGER
    if not _OPERATION_MANAGER:
        _OPERATION_MANAGER = _OperationManager(_plugins)
    return _OPERATION_MANAGER

def get_hub_manager():
    """Generate Hub plugin structure"""
    global _HUB_MANAGER
    if not _HUB_MANAGER:
        _HUB_MANAGER = _HubManager(_plugins)
    return _HUB_MANAGER

def get_workflow_manager():
    """Generate Workflow plugin structure"""
    global _WORKFLOW_MANAGER
    if not _WORKFLOW_MANAGER:
        _WORKFLOW_MANAGER = _WorkflowManager(_plugins)
    return _WORKFLOW_MANAGER

def get_executor_manager():
    """Generate Exectutor plugin structure"""
    global _EXECUTOR_MANAGER
    if not _EXECUTOR_MANAGER:
        _EXECUTOR_MANAGER = _ExecutorManager(_plugins)
    return _EXECUTOR_MANAGER

def get_plugins_dict():
    """Generate all of the plugins structure"""
    global _PLUGINS_DICT
    if not _PLUGINS_DICT:
        _PLUGINS_DICT = {
            'resources_dict': get_resource_manager().kind_to_resource_dict,
            'operations_dict': get_operation_manager().kind_to_operation_dict,
            'hubs_dict': get_hub_manager().kind_to_hub_dict,
            'workflows_dict': get_workflow_manager().kind_to_workflow_dict,
            'executors_info': get_executor_manager().kind_info,
        }
    return _PLUGINS_DICT


import aiohttp
import aioipfs
import os
import pprint
import asyncio

from dverify import get_user_token

from config import MEME_BACKEND, ADMIN_TOKEN, DEFAULT_TAG, IMG_DIR

MESSAGE_USER_REACTION_CACHE = {
}  # message with 2, meme_id and a list of users who have tried to upvote (either sucesfully or not)

def valid_image_url(url: str):
    image_extensions = [
        'png', 'jpg', 'jpeg', 'gif', 'bmp', 'PNG', 'JPG', 'JPEG', 'GIF', 'BMP'
    ]
    for image_extension in image_extensions:
        if url.endswith('.' + image_extension):
            return True
    return False

async def upload_to_ipfs(files, file_hash_dict):
    print('now adding to ipfs')
    client = aioipfs.AsyncIPFS()

    async for added_file in client.add(*files, recursive=True):
        print('Imported file {0}, CID: {1}'.format(added_file['Name'],
                                                   added_file['Hash']))
        file_hash_dict[added_file['Name']] = added_file['Hash']

    await client.close()

async def meme_party_post(image_name, message, file_hash_dict):
    print('now adding to meme_party')
    discord_username = str(message.author)
    url = f"{MEME_BACKEND}/museum/memes/"
    headers = {
        "Authorization": f"Token {ADMIN_TOKEN}",
        "Content-Type": "application/json"
    }
    json = {
        "title": f'{image_name}',
        "meme_lord": f"{discord_username}",
        "description": "",
        "image":
        f"http://139.59.103.146:8080/ipfs/{file_hash_dict[image_name]}",
        "tags": [{
            "name": f"{DEFAULT_TAG}"
        }],
        "discord_username": discord_username
    }
    async with aiohttp.ClientSession() as session:
        async with session.post(url, json=json, headers=headers) as resp:
            print(resp.status)
            try:
                meme = await resp.json()
            except:
                meme = await resp.text()
                open('erro_log.html', 'w').write(meme)
                return
            logging_fields = ['image', 'id', 'poaster', 'meme_lord']
            meme = {k: meme[k] for k in logging_fields}
            pprint.pprint(meme)
            return resp.status, meme

async def download_image(url: str, images_path: str = ""):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            if resp.status == 200:
                image_name = os.path.basename(url)
                with open(images_path, "wb") as f:
                    f.write(await resp.read())

async def handle_image(attachment, message):
    file_hash_dict = {}
    print(f'Processing New Meme From: {message.author}')
    await download_image(attachment.url,
                         os.path.join(IMG_DIR, attachment.filename))
    await upload_to_ipfs([os.path.join(IMG_DIR, attachment.filename)],
                         file_hash_dict)
    upload_status, meme = await meme_party_post(attachment.filename, message,
                                                file_hash_dict)
    if upload_status in [200, 201]:
        await message.add_reaction("✅")
        MESSAGE_USER_REACTION_CACHE[message.id] = {
            "meme_id": meme["id"],
            "upvoters": []
        }
    else:
        await message.add_reaction("❌")
    print(MESSAGE_USER_REACTION_CACHE)

async def handle_upvote(user, message):
    max_times_to_sleep = 3

    while message.id not in MESSAGE_USER_REACTION_CACHE and max_times_to_sleep > 0:
        await asyncio.sleep(10)
        max_times_to_sleep -= 1

    if message.id not in MESSAGE_USER_REACTION_CACHE:
        return

    if str(user) in MESSAGE_USER_REACTION_CACHE[message.id]["upvoters"]:
        return

    user_auth_token = await get_user_token(user)

    if user_auth_token is None:
        return

    print('now handling upvote')

    meme_id = int(MESSAGE_USER_REACTION_CACHE[message.id]["meme_id"])

    url = f"{MEME_BACKEND}/museum/upvote/"
    headers = {
        "Authorization": f"Token {user_auth_token}",
        "Content-Type": "application/json"
    }
    json = {
        "id": meme_id,
    }
    async with aiohttp.ClientSession() as session:
        async with session.post(url, json=json, headers=headers) as resp:
            print(resp.status)
            try:
                meme = await resp.json()
            except:
                meme = await resp.text()
                open('erro_log.html', 'w').write(meme)
                return
            logging_fields = ['image', 'id', 'poaster', 'meme_lord']
            meme = {k: meme[k] for k in logging_fields}
            print(f'upvoted {meme["id"]} on behalf of {user}')
            # pprint.pprint(meme)
            MESSAGE_USER_REACTION_CACHE[message.id]["upvoters"].append(
                str(user))
            print(MESSAGE_USER_REACTION_CACHE)
            return resp.status, meme

# reaction handling
# if message.id is not in cache then asyncio.sleep for upto 3 times


# -*- coding: utf-8 -*-
#from https://stackoverflow.com/questions/2490334/simple-way-to-encode-a-string-according-to-a-password
key = 'FYLÄ,Xäcu2bÄLU!GECö3Qowo-lAfU7Pö'
import base64
def encode(clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc))

def decode(enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)


import requests
from bs4 import BeautifulSoup
import csv
from datetime import datetime
from multiprocessing import Pool

def get_html_text(url):
    """
    Функция, возвращающая html страницу
    """
    try:
        res = requests.get(url, timeout=30)
        return res.text

    except requests.ConnectionError:
        print("Connection Error")

    except requests.Timeout:
        print("Timeout Error")

    except requests.RequestException:
        print("Request Exception")

def get_all_news_from_page(html):
    """
    Функция, возвращающая список сслылок на новости на одной странице
    """
    soup = BeautifulSoup(html, 'lxml')
    links = soup.find_all('header', class_='entry-header')
    l_links = []
    for i in links:
        a = i.find('a').get('href')
        l_links.append(a)
    return l_links

def get_content(html):
    """
    Функция, возвращающая текст и залоговок новости
    """
    soup = BeautifulSoup(html, 'lxml')
    try:
        text = soup.find('div', class_='entry-content').text.strip()
    except:
        text = ''
    try:
        title = soup.find('h1', class_='entry-title').text.strip()
    except:
        title = ''
    data = {'text': text, 'title': title}

    return data

def pool_func(url):
    """
    Функция для выполнения мультипроцессинга
    """
    html = get_html_text(url)
    data = get_content(html)
    write_csv(data)

def write_csv(data):
    """
    Функция, записывающая данные в csv файл
    """
    with open('panorama_news_satire.csv', 'a', encoding='utf8') as f:
        writer = csv.writer(f)
        writer.writerow((data['text'], data['title']))
        print(data['title'])
        print('--------------------------------')
        print()

def main():
    start = datetime.now()
    for i in range(1, 511):  # итерация по количеству страниц на сайте
        print(i)
        url = 'https://panorama.pub/page/{}?s'.format(i)
        all_links = get_all_news_from_page(get_html_text(url))

        with Pool(20) as pool:
            pool.map(pool_func, all_links)

        end = datetime.now()
        t = end - start
        print(str(t))

if __name__ == '__main__':
    main()

data/Парсер новостей (на примере сайта ИА Панорама).py


from simtrees._setup_cfg import paths
from simfiles.configs.APOSTLE import (
    res_str,
    vol_str,
    phys_str,
    snap_id,
    machine,
)
from itertools import product

path_bases = {
    "cosma": "/cosma6/data/dp004/lg/snapshots_all/Merger_Trees",
}

snap = 127
for res, vol, phys in product(range(1, 4), range(1, 13), ["hydro", "DMO"]):
    if (res == 1) and (
        ((phys == "hydro") and (vol not in [1, 4, 6, 10, 11]))
        or ((phys == "DMO") and (vol not in [1, 4, 11]))
    ):
        continue

    fpath = "{:s}/{:s}_{:s}_{:s}/snapshots/treedir_{:03d}/".format(
        path_bases[machine], vol_str[vol], res_str[res], phys_str[phys], snap
    )
    fbase = "tree_{:03d}".format(snap)
    sfbase = "subfind_{:03d}".format(snap)
    paths[snap_id(res=res, phys=phys, vol=vol, snap=snap)] = (
        fpath,
        fbase,
        sfbase,
    )


# libraries
import pandas as pd
from keras.optimizers import Adam
from keras.layers import Dense
from keras.models import Sequential
from sklearn.model_selection import train_test_split

#reading the dataset
dataset = pd.read_csv('/code/wines.csv')

# pre-processing & cleaning the dataset
y = dataset['Class']
y_cat = pd.get_dummies(y)
x = dataset.drop('Class', axis=1)

# spliting the dataset
x_train, x_test, y_train, y_test = train_test_split(x,y_cat,test_size=0.1,random_state=20)

#creating the model
model = Sequential()
model.add(Dense(units=64, input_shape=(13,), activation='relu'))
model.add(Dense(units=3, activation='softmax'))
model.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer=Adam())
model.fit(x_train,y_train, validation_data=(x_test,y_test), epochs=20, verbose=0)

#calculating accuracy
accuracy = model.evaluate(x_test, y_test, verbose=0)
accuracy = accuracy[1]*100

# storing accuracy
import os
os.system("sudo touch /code/accuracy.txt")
os.system("echo {} > /code/accuracy.txt".format(accuracy))

# saving the model to send to the client
model.save('/code/multiclassNN.h5')


import numpy as np
import os
import pyqtgraph as pg

from core.module import Connector
from gui.colordefs import QudiPalettePale as palette
from gui.guibase import GUIBase
from qtpy import QtCore
from qtpy import QtWidgets
from qtpy import uic

class AomMainWindow(QtWidgets.QMainWindow):

    """ Create the Main Window based on the *.ui file. """

    def __init__(self, **kwargs):
        # Get the path to the *.ui file
        this_dir = os.path.dirname(__file__)
        ui_file = os.path.join(this_dir, 'ui_aom.ui')

        # Load it
        super().__init__(**kwargs)
        uic.loadUi(ui_file, self)
        self.show()

class AomGui(GUIBase):

    """ FIXME: Please document
    """
    _modclass = 'aomgui'
    _modtype = 'gui'

    # declare connectors
    aomlogic = Connector(interface='AomLogic')

    sigPsatFinished = QtCore.Signal()
    sigAomChange = QtCore.Signal()

    def __init__(self, config, **kwargs):
        super().__init__(config=config, **kwargs)

    def on_activate(self):
        """ Definition and initialisation of the GUI.
        """

        self._aom_logic = self.get_connector('aomlogic')

        # Use the inherited class 'CounterMainWindow' to create the GUI window
        self._mw = AomMainWindow()

        self.psat_image = pg.PlotDataItem(self._aom_logic.powers,
                                          self._aom_logic.psat_data,
                                          pen=pg.mkPen(palette.c1, style=QtCore.Qt.DotLine),
                                          symbol='o',
                                          symbolPen=palette.c1,
                                          symbolBrush=palette.c1,
                                          symbolSize=7)

        self.psat_fit_image = pg.PlotDataItem(self._aom_logic.psat_fit_x,
                                              self._aom_logic.psat_fit_y,
                                              pen=pg.mkPen(palette.c2))

        # Add the display item to the xy and xz ViewWidget, which was defined in the UI file.
        self._mw.psat_plot_PlotWidget.addItem(self.psat_image)
        self._mw.psat_plot_PlotWidget.addItem(self.psat_fit_image)
        self._mw.psat_plot_PlotWidget.setLabel(axis='left', text='Fluoresence', units='c/s')
        self._mw.psat_plot_PlotWidget.setLabel(axis='bottom', text='Power', units='W')
        self._mw.psat_plot_PlotWidget.showGrid(x=True, y=True, alpha=0.8)
        self._mw.setPower.setValue(self.get_power())
        self._mw.setPower.valueChanged.connect(self.set_power)
        self._mw.setPower.setMaximum(self._aom_logic.current_maximum_power()*1000)
        self._mw.set_to_psat.clicked.connect(self.set_power_to_psat)
        self._aom_logic.power_available.connect(self.update_power_available)

        #####################
        # Connecting user interactions
        self._mw.run_psat_Action.triggered.connect(self.run_psat_clicked)
        self._mw.save_psat_Action.triggered.connect(self.save_clicked)

        ##################
        # Handling signals from the logic
        self._aom_logic.psat_updated.connect(self.update_data)
        self._aom_logic.psat_fit_updated.connect(self.update_fit)
        self._aom_logic.aom_updated.connect(self.update_aom)

        return 0

    def show(self):
        """Make window visible and put it above all other windows.
        """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()
        return

    def on_deactivate(self):
        """ Deactivate the module
        """
        # disconnect signals
        self._mw.run_psat_Action.triggered.disconnect()
        self._mw.save_psat_Action.triggered.disconnect()
        self._aom_logic.psat_updated.disconnect()
        self._mw.close()
        return

    def update_aom(self):
        self._mw.setPower.blockSignals(True)
        self._mw.setPower.setValue(self.get_power())
        self._mw.setPower.blockSignals(False)

    def set_power_to_psat(self):
        self._aom_logic.set_power(self._aom_logic.fitted_Psat)

    def update_data(self):
        """ The function that grabs the data and sends it to the plot.
        """

        """ Refresh the plot widgets with new data. """
        # Update psat plot
        self.psat_image.setData(self._aom_logic.powers, self._aom_logic.psat_data)

        return 0

    def set_power(self,power):
        self._aom_logic.set_power(power/1000)

    def get_power(self):
        return self._aom_logic.get_power()*1000

    def update_fit(self):
        """ Refresh the plot widgets with new data. """
        if self._aom_logic.psat_fit_available():
            # Update psat plot
            self.psat_fit_image.setData(self._aom_logic.psat_fit_x, self._aom_logic.psat_fit_y)
            self._mw.Isat_display.setText("{:.2f}".format(self._aom_logic.fitted_Isat/1000))
            self._mw.Psat_display.setText("{:.2f}".format(self._aom_logic.fitted_Psat*1000))
            self._mw.bg_display.setText("{:.2f}".format(self._aom_logic.fitted_offset/1000))

    def run_psat_clicked(self):
        """ Handling the Start button
        """
        self.log.info("Running psat")
        self._aom_logic.run_psat()
        return self._aom_logic.module_state()

    def save_clicked(self):
        """ Handling the save button to save the data into a file.
        """
        if self._aom_logic.psat_available():
            self._aom_logic.save_psat()
        return self._aom_logic.module_state()

    def update_max_power(self, count_length):
        """Function to ensure that the GUI displays the current value of the logic

        @param int count_length: adjusted count length in bins
        @return int count_length: see above
        """
        self._mw.setPower.blockSignals(True)
        self._mw.count_length_SpinBox.setValue(count_length)
        self._pw.setXRange(0, count_length / self._counting_logic.get_count_frequency())
        self._mw.count_length_SpinBox.blockSignals(False)
        return count_length

    def update_power_available(self, state):
        pass

    def update_saving_Action(self, start):
        pass


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

#-:-:-:-:-:-:-:-:-:#
#    XSRFProbe     #
#-:-:-:-:-:-:-:-:-:#

#Author: 0xInfection
#This module requires XSRFProbe
#https://github.com/0xInfection/XSRFProbe

import urllib.error
import re, html.parser
from bs4 import BeautifulSoup
from urllib.parse import urlparse
from xsrfprobe.modules import Parser
from xsrfprobe.core.colors import *
from xsrfprobe.files.config import *
from xsrfprobe.files.dcodelist import *
from xsrfprobe.core.request import Get
from xsrfprobe.core.verbout import verbout
from xsrfprobe.core.logger import ErrorLogger
from xsrfprobe.files.discovered import INTERNAL_URLS

class Handler:  # Main Crawler Handler
    '''
    This is a crawler that is used to fetch all the Urls
        associated to the HTML page, and susequently
            crawl them and build checks for CSRFs.
    '''
    def __init__(self, start, opener):
        self.visited = list()
        self.toVisit = list()
        self.uriPatterns = list()
        self.currentURI = ''
        self.opener = opener
        self.toVisit.append(start)

    def __next__(self):
        self.currentURI = self.toVisit[0]
        self.toVisit.remove(self.currentURI)
        return self.currentURI

    def getVisited(self):
        return self.visited

    def getToVisit(self):
        return self.toVisit

    def noinit(self):
        if self.toVisit:
            return True
        return False

    def resolveBaseRef(self, link):
        parsob = urlparse(link)
        return parsob.path

    def checkExclusion(self, link):
        if link in EXCLUDE_DIRS:
            return True
        return False

    def process(self, root):
        url = self.currentURI
        try:
            query = Get(url)
            if query != None and not str(query.status_code).startswith('4'):
                INTERNAL_URLS.append(url)
            else:
                if url in self.toVisit:
                    self.toVisit.remove(url)

        except (urllib.error.HTTPError, urllib.error.URLError) as msg:
            verbout(R, 'HTTP Request Error: '+msg.__str__())
            ErrorLogger(url, msg.__str__())
            if url in self.toVisit:
                self.toVisit.remove(url)
            return None

        # Making sure the content type is in HTML format, so that BeautifulSoup
        # can parse it...
        if not query or not re.search('html', query.headers['Content-Type']):
            return None

        # Just in case there is a redirection, we are supposed to follow it :D
        verbout(GR, 'Making request to new location...')
        if hasattr(query.headers, 'Location'):
            url = query.headers['Location']
        verbout(O,'Reading response...')
        response = query.content

        try:
            verbout(O, 'Trying to parse response...')
            soup = BeautifulSoup(response)

        except html.parser.HTMLParseError:
            verbout(R, 'BeautifulSoup Error: '+url)
            self.visited.append(url)
            if url in self.toVisit:
                self.toVisit.remove(url)
            return None

        for m in soup.findAll('a', href=True):
            app = ''
            # Making sure that href is not a function or doesn't begin with http://
            if not re.match(r'javascript:', m['href']) or re.match('http://', m['href']):
                app = Parser.buildUrl(url, m['href'])

            # If we get a valid link
            if app != '' and re.search(root, app):
                # Getting rid of Urls starting with './'
                p = re.compile(RID_SINGLE)
                app = p.sub('', app)

                uriPattern = removeIDs(app)
                if self.notExist(uriPattern) and app != url:
                    if not self.checkExclusion(self.resolveBaseRef(app)):
                        verbout(G, 'Added :> ' +color.BLUE+ app)
                        self.toVisit.append(app)
                        self.uriPatterns.append(uriPattern)
                    else:
                        verbout(O, 'Skipping due to exclusion: '+app)

        self.visited.append(url)
        return soup

    def getUriPatterns(self):
        return self.uriPatterns

    def notExist(self, test):
        if test not in self.uriPatterns:
            return 1
        return 0

    def addUriPatterns(self, Parser):
        self.uriPatterns.append(Parser)

    def addVisited(self, Parser):
        self.visited.append(Parser)

def removeIDs(Parser):
    '''
    This function removes the IDs from the Urls which are built.
    '''
    p = re.compile(NUM_SUB)
    Parser = p.sub('=', Parser)
    p = re.compile(NUM_COM)
    Parser = p.sub('\\1', Parser)
    return Parser


"""Add watering timestamp

Revision ID: a4aa0f43b257
Revises: 56a2f2c760af
Create Date: 2021-01-05 17:08:24.522331

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = "a4aa0f43b257"
down_revision = "56a2f2c760af"
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table("plants", schema=None) as batch_op:
        batch_op.add_column(
            sa.Column(
                "last_watering",
                sa.DateTime(),
                server_default=sa.text("CURRENT_TIMESTAMP"),
                nullable=False,
            )
        )

    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table("plants", schema=None) as batch_op:
        batch_op.drop_column("last_watering")

    # ### end Alembic commands ###