import blenderproc as bproc
import dataclasses
import dcargs
import json
import numpy as np
import os
from PIL import Image
import shutil
from typing import Literal
import imageio

from blenderproc.python.camera.CameraUtility import get_intrinsics_as_K_matrix

# Object to shapenet id mappings
obj_to_shapenet_ids = {
    "Airplane": {
        "used_synset_id": "02691156",
        "used_source_id": "8f4e31ee9912f54e77fd7318510b8627",
    },
    "Bag": {
        "used_synset_id": "02773838",
        "used_source_id": "4e4fcfffec161ecaed13f430b2941481",
    },
    "Car": {
        "used_synset_id": "02958343",
        "used_source_id": "1ae9732840a315afab2c2809513f396e",
    },
    "Guitar": {
        "used_synset_id": "03467517",
        "used_source_id": "4ff4b6305e3d5e2ad57700c05b1862d8",
    },
    "Lamp": {
        "used_synset_id": "03636649",
        "used_source_id": "8ef9c1ffaa6f7292bd73284bc3c3cbac",
    },
    "Cap": {
        "used_synset_id": "02954340",
        "used_source_id": "188702a3bb44f40c284432ce2f42f498",
    },
    "Motorbike": {
        "used_synset_id": "03790512",
        "used_source_id": "6bf1f988493dc23752ee90e577613070",
    },
    "Skateboard": {
        "used_synset_id": "04225987",
        "used_source_id": "619b49bae27807fb1082f2ea630bf69e",  #
    },
    "Camera": {
        "used_synset_id": "02942699",
        "used_source_id": "97690c4db20227d248e23e2c398d8046",
    },
}

@dataclasses.dataclass
class ViewPlanner:
    candidate_view_radius: float = (
        1.3  # heuristic: account for workspace size and arm kinematics
    )
    candidate_view_type: Literal["hemisphere", "circle", "sphere"] = "sphere"
    num_cam_positions: int = 100

@dataclasses.dataclass
class Args:
    #############################
    # Blenderproc rendering args #
    #############################
    view_planner: ViewPlanner = None
    shapenet_path: str = ""  # Path to the downloaded shape net core v2 dataset, get it from http://www.shapenet.org/
    blender_path: str = ""  # Path to the blender obj
    offline_gym_data_dir: str = "../active-nerf/offline_gym_data"  # TODO KL update Path to where the final files will be saved
    save_data_type: Literal["train", "val"] = "val"
    save_ray_info: bool = False  # Ray info (w.r.t a frame) consists of ray_coord, ray_length and ray weight
    convert_background_to_white: bool = False
    shapenet_obj: Literal[
        "Airplane",
        "Bag",
        "Car",
        "Guitar",
        "Lamp",
        "Cap",
        "Motorbike",
        "Skateboard",
        "Camera",
    ] = "Airplane"

##################### active nerf utils ###############################
def fibonacci_sphere(samples: int) -> np.ndarray:
    """Fibonacci sphere algorithm for uniform sampling on a sphere. Returns array with
    shape (samples, 3).

    Adapted from:
    https://stackoverflow.com/questions/9600801/evenly-distributing-n-points-on-a-sphere"""
    phi = np.pi * (3.0 - np.sqrt(5.0))  # Golden angle in radians.
    i = np.arange(samples)
    y = 1.0 - (i / float(samples - 1.0)) * 2.0  # y goes from 1 to -1.
    radius = np.sqrt(1 - y * y)  # Radius at y.
    theta = phi * i  # Golden angle increment.
    x = np.cos(theta) * radius
    z = np.sin(theta) * radius

    return np.array([x, y, z]).T

def get_candidate_camera_positions_circle(
    radius: float,
    cam_z: float,
    num_cam_positions: int,
    center_x: float = 0,
    center_y: float = 0,
) -> dict:
    """Returns a dictionary with keys as camera angles and values as camera positions."""
    cam_positions = {}
    single_angle = 360 / num_cam_positions
    for i in range(num_cam_positions):
        x = radius * np.cos(2 * np.pi / num_cam_positions * i) + center_x
        y = radius * np.sin(2 * np.pi / num_cam_positions * i) + center_y
        cam_positions[int(single_angle * i)] = np.array((x, y, cam_z))
    return cam_positions

def get_candidate_views(
    object_bounds: dict,
    num_cam_positions: int,
    candidate_view_radius: float = 0.8,
    candidate_view_type: str = "sphere",
):
    """Returns a list of openGL camera poses that point towards the object.
    Radius should come from object scene bounds
    """
    poi = object_bounds["poi"]
    size = object_bounds["size"]
    assert candidate_view_radius > size * np.sqrt(
        2
    ), "Sphere radius must be larger than object size"

    if candidate_view_type == "hemisphere":
        sphere_radius = candidate_view_radius
        fib_xyzs = fibonacci_sphere(2 * num_cam_positions)
        # heuristic: filter out values whose z value is below e.g. 0.25 to look from above
        filtered_xyzs = fib_xyzs[np.where(fib_xyzs[:, -1] > 0.4)]
        rescaled_xyzs = sphere_radius * filtered_xyzs
    elif candidate_view_type == "circle":
        circle_radius = candidate_view_radius * (
            object_bounds["xmax"] - object_bounds["xmin"]
        )  # heuristic: extra distance from object
        cam_z = poi[2]
        rescaled_xyzs = get_candidate_camera_positions_circle(
            circle_radius, cam_z, num_cam_positions
        )
        rescaled_xyzs = np.array(list(rescaled_xyzs.values()))
    elif candidate_view_type == "sphere":
        sphere_radius = candidate_view_radius
        fib_xyzs = fibonacci_sphere(num_cam_positions)
        rescaled_xyzs = sphere_radius * fib_xyzs

    world_xyzs = rescaled_xyzs + poi
    # calculate the camera poses
    openGL_cam_positions = []
    for loc in world_xyzs:
        rotation_mat = bproc.camera.rotation_from_forward_vec(poi - loc)
        openGL_cam_positions.append(
            bproc.math.build_transformation_mat(loc, rotation_mat)
        )
    return openGL_cam_positions

def get_obj_bounds(shapenet_obj):
    poi = np.zeros(3)
    size = 1
    return {
        "poi": poi,
        "size": size,
        "xmin": poi[0] - 2 * size,
        "xmax": poi[0] + 2 * size,
        "ymin": poi[1] - 2 * size,
        "ymax": poi[1] + 2 * size,
        "zmin": poi[2] - 2 * size,
        "zmax": poi[2] + 2 * size,
    }  # 2 * is rough heuristic

    blender_obj = shapenet_obj.blender_obj
    poi = blender_obj.location[:]
    bound_vals = blender_obj.bound_box[:]
    size = np.array([np.array(i) for i in list(bound_vals)]).max()

    return {
        "poi": poi,
        "size": size,
        "xmin": poi[0] - 2 * size,
        "xmax": poi[0] + 2 * size,
        "ymin": poi[1] - 2 * size,
        "ymax": poi[1] + 2 * size,
        "zmin": poi[2] - 2 * size,
        "zmax": poi[2] + 2 * size,
    }  # 2 * is rough heuristic

def get_transformations_template(
    fl_x=None, fl_y=None, c_x=None, c_y=None, aabb_scale=None, frames=[]
):
    transformations = {
        "fl_x": fl_x,
        "fl_y": fl_y,
        "c_x": c_x,
        "c_y": c_y,
        "aabb_scale": aabb_scale,
        "frames": frames,
    }
    return transformations

def openGL_to_openCV(cam2world_matrix):
    tmat = np.array(
        [
            [1.0, 0.0, 0.0, 0.0],
            [-0.0, -1.0, -0.0, -0.0],
            [-0.0, -0.0, -1.0, -0.0],
            [0.0, 0.0, 0.0, 1.0],
        ]
    )
    return np.matmul(cam2world_matrix, tmat)

############################# end of active nerf utils ################################

def main(args):
    obj_name = (
        args.shapenet_obj
        if args.shapenet_path != ""
        else args.blender_path.split("/")[-1].split(".")[0]
    )
    offline_gym_obj_dir = os.path.join(args.offline_gym_data_dir, obj_name)
    # if os.path.isdir(offline_gym_obj_dir):
    #     shutil.rmtree(offline_gym_obj_dir)
    if not os.path.isdir(offline_gym_obj_dir):
        os.makedirs(offline_gym_obj_dir)

    bproc.init()

    intrinsics = get_intrinsics_as_K_matrix()
    transformations_template = get_transformations_template(
        fl_x=intrinsics[0][0],
        fl_y=intrinsics[1][1],
        c_x=intrinsics[0][2],
        c_y=intrinsics[1][2],
    )

    if args.shapenet_path != "":
        # Load the ShapeNet object into the scene
        shapenet_obj_ids = obj_to_shapenet_ids[args.shapenet_obj]
        obj = bproc.loader.load_shapenet(
            args.shapenet_path,
            used_synset_id=shapenet_obj_ids["used_synset_id"],
            used_source_id=shapenet_obj_ids["used_source_id"],
            move_object_origin=False,
        )
    elif args.blender_path != "":
        # Load the Blender object into the scene
        obj = bproc.loader.load_blend(args.blender_path)
        obj = bproc.loader.load_blend(args.blender_path)

    # Define lights and set location and energy level
    light1 = bproc.types.Light()
    light1.set_type("POINT")
    light1.set_location([0, 0, 5])
    light1.set_energy(200)

    light2 = bproc.types.Light()
    light2.set_type("POINT")
    light2.set_location([0, 5, 0])
    light2.set_energy(200)

    light3 = bproc.types.Light()
    light3.set_type("POINT")
    light3.set_location([0, -5, 0])
    light3.set_energy(200)

    light4 = bproc.types.Light()
    light4.set_type("POINT")
    light4.set_location([5, 0, 0])
    light4.set_energy(200)

    light5 = bproc.types.Light()
    light5.set_type("POINT")
    light5.set_location([-5, 0, 0])
    light5.set_energy(200)

    # Calculate the camera poses
    object_bounds = get_obj_bounds(obj)
    openGL_cam_positions = get_candidate_views(
        object_bounds,
        args.view_planner.num_cam_positions,
        args.view_planner.candidate_view_radius,
        args.view_planner.candidate_view_type,
    )

    # Add camera poses to scene
    for i in range(len(openGL_cam_positions)):
        openGL_transform_matrix = openGL_cam_positions[i]
        bproc.camera.add_camera_pose(openGL_transform_matrix)

    # Render the whole pipeline
    # bproc.renderer.set_output_format(enable_transparency=True)
    bproc.renderer.enable_depth_output(activate_antialiasing=False)
    data = bproc.renderer.render()

    image_dir = f"{offline_gym_obj_dir}/{args.save_data_type}"
    os.makedirs(image_dir)  # making directory for each image

    for i in range(len(openGL_cam_positions)):
        rgb = np.array(data["colors"][i])  # [..., :3] # remove alpha channel
        depth = np.array(data["depth"][i])
        distance = bproc.postprocessing.depth2dist(depth).astype(np.float32)

        if args.convert_background_to_white:
            rgb[depth > 1e8] = 255

        depth[depth > 1e8] = 0
        distance[distance > 1e8] = 0

        rgb_png = Image.fromarray(rgb)
        rgb_path = f"{args.save_data_type}/im_{i}.png"
        rgb_png.save(os.path.join(offline_gym_obj_dir, rgb_path))

        depth_exr = depth
        depth_path = f"{args.save_data_type}/im_{i}_depth.exr"
        imageio.imwrite(os.path.join(offline_gym_obj_dir, depth_path), depth_exr)

        distance_exr = distance
        distance_path = f"{args.save_data_type}/im_{i}_distance.exr"
        imageio.imwrite(os.path.join(offline_gym_obj_dir, distance_path), distance_exr)

        transform_dct = {
            "file_path": rgb_path,
            "depth_path": depth_path,
            "distance_path": distance_path,
            "transform_matrix": openGL_cam_positions[i].tolist(),
        }

        if args.save_ray_info:
            ray_lengths_path = f"{args.save_data_type}/ray_lengths_{i}.npy"
            ray_coords_path = f"{args.save_data_type}/ray_coords_{i}.npy"
            ray_weights_path = f"{args.save_data_type}/ray_weights_{i}.npy"
            ray_lengths = distance.copy()
            ray_coords = np.meshgrid(
                np.arange(distance.shape[0]), np.arange(distance.shape[1])
            )
            ray_weights = np.ones_like(distance)
            ray_weights[distance == 0] = 0  # do not supervise inf distance rays
            ray_info_dct = {
                "ray_lengths_path": ray_lengths_path,
                "ray_coords_path": ray_coords_path,
                "ray_weights_path": ray_weights_path,
            }

            np.save(os.path.join(offline_gym_obj_dir, ray_lengths_path), ray_lengths)
            np.save(os.path.join(offline_gym_obj_dir, ray_coords_path), ray_coords)
            np.save(os.path.join(offline_gym_obj_dir, ray_weights_path), ray_weights)

            transform_dct.update(ray_info_dct)

        transformations_template["frames"].append(transform_dct)

    with open(f"{offline_gym_obj_dir}/transforms_{args.save_data_type}.json", "w") as f:
        json.dump(transformations_template, f)

if __name__ == "__main__":
    args = dcargs.parse(Args)
    main(args)


from pycp2k.inputsection import InputSection
from ._andreussi1 import _andreussi1
from ._fattebert_gygi1 import _fattebert_gygi1

class _sccs2(InputSection):
    def __init__(self):
        InputSection.__init__(self)
        self.Section_parameters = None
        self.Alpha = None
        self.Beta = None
        self.Delta_rho = None
        self.Derivative_method = None
        self.Dielectric_constant = None
        self.Eps_sccs = None
        self.Eps_scf = None
        self.Gamma = None
        self.Max_iter = None
        self.Method = None
        self.Mixing = None
        self.ANDREUSSI = _andreussi1()
        self.FATTEBERT_GYGI = _fattebert_gygi1()
        self._name = "SCCS"
        self._keywords = {'Method': 'METHOD', 'Max_iter': 'MAX_ITER', 'Dielectric_constant': 'DIELECTRIC_CONSTANT', 'Mixing': 'MIXING', 'Eps_sccs': 'EPS_SCCS', 'Alpha': 'ALPHA', 'Delta_rho': 'DELTA_RHO', 'Derivative_method': 'DERIVATIVE_METHOD', 'Eps_scf': 'EPS_SCF', 'Gamma': 'GAMMA', 'Beta': 'BETA'}
        self._subsections = {'FATTEBERT_GYGI': 'FATTEBERT-GYGI', 'ANDREUSSI': 'ANDREUSSI'}
        self._aliases = {'Surface_tension': 'Gamma', 'Tau_pol': 'Eps_sccs', 'Epsilon_solvent': 'Dielectric_constant', 'Eps_iter': 'Eps_sccs', 'Eta': 'Mixing'}
        self._attributes = ['Section_parameters']

    @property
    def Epsilon_solvent(self):
        """
        See documentation for Dielectric_constant
        """
        return self.Dielectric_constant

    @property
    def Eps_iter(self):
        """
        See documentation for Eps_sccs
        """
        return self.Eps_sccs

    @property
    def Tau_pol(self):
        """
        See documentation for Eps_sccs
        """
        return self.Eps_sccs

    @property
    def Surface_tension(self):
        """
        See documentation for Gamma
        """
        return self.Gamma

    @property
    def Eta(self):
        """
        See documentation for Mixing
        """
        return self.Mixing

    @Epsilon_solvent.setter
    def Epsilon_solvent(self, value):
        self.Dielectric_constant = value

    @Eps_iter.setter
    def Eps_iter(self, value):
        self.Eps_sccs = value

    @Tau_pol.setter
    def Tau_pol(self, value):
        self.Eps_sccs = value

    @Surface_tension.setter
    def Surface_tension(self, value):
        self.Gamma = value

    @Eta.setter
    def Eta(self, value):
        self.Mixing = value


import json
import os
from datetime import datetime
from typing import Optional, Union

from aws_cdk import (
    aws_lambda,
    aws_secretsmanager as secretsmanager,
    aws_rds as rds,
    aws_ec2 as ec2,
    Stack,
    CustomResource,
    custom_resources,
)

from constructs import Construct

class BootstrappedDb(Construct):
    """
    Given an RDS database, connect to DB and create a database, user, and
    password
    """

    def __init__(
        self,
        scope: Construct,
        id: str,
        db: Union[rds.DatabaseInstance, rds.DatabaseInstanceFromSnapshot],
        new_dbname: str,
        new_username: str,
        secrets_prefix: str,
        handler: Union[aws_lambda.Function, aws_lambda.SingletonFunction],
        db_engine: Optional[str] = None,
    ) -> None:
        super().__init__(scope, id)

        if not db.secret:
            raise ValueError("`db` value must have a secret attached.")

        if not db.engine and not db_engine:
            raise ValueError(
                "Either the provided `db` must have access to its `engine` property or"
                " you must provide a value for `db_engine` explicitly."
            )

        self.secret = secretsmanager.Secret(
            self,
            id,
            secret_name=os.path.join(
                secrets_prefix, id.replace(" ", "_"), self.node.id[-8:]
            ),
            generate_secret_string=secretsmanager.SecretStringGenerator(
                secret_string_template=json.dumps(
                    {
                        "dbname": new_dbname,
                        "engine": db_engine if db_engine else db.engine.engine_type,  # type: ignore
                        "port": db.instance_endpoint.port,
                        "host": db.instance_endpoint.hostname,
                        "username": new_username,
                    },
                ),
                generate_string_key="password",
                exclude_punctuation=True,
            ),
            description=f"Deployed by {Stack.of(self).stack_name}",
        )

        self.provider = custom_resources.Provider(
            scope, "BootstrapProvider", on_event_handler=handler
        )

        self.resource = CustomResource(
            scope=scope,
            id="BootstrapHandlerResource",
            service_token=self.provider.service_token,
            properties={
                "conn_secret_arn": db.secret.secret_arn,
                "new_user_secret_arn": self.secret.secret_arn,
                "version": handler.current_version.version,
            },
        )

        # Allow lambda to...
        # read new user secret
        self.secret.grant_read(handler)
        # read database secret
        db.secret.grant_read(handler)
        # connect to database
        db.connections.allow_from(handler, port_range=ec2.Port.tcp(5432))

    def is_required_by(self, construct: Construct):
        return construct.node.add_dependency(self.resource)


import asyncio
from datetime import datetime

from channels.db import database_sync_to_async
from channels.generic.http import AsyncHttpConsumer
from channels.generic.websocket import AsyncJsonWebsocketConsumer

from .models import Chan, Message

class ChatConsumer(AsyncJsonWebsocketConsumer):
    async def connect(self):
        # print(f'{self.scope=}')
        # print(f'{self.channel_name=}')
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = f'room_{self.room_name}'
        await self.set_chan()
        await self.channel_layer.group_add(self.room_group_name, self.channel_name)
        await self.accept()
        for message in await self.get_messages():
            await self.send_json(content={'message': message})

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

    async def receive_json(self, content):
        await self.channel_layer.group_send(self.room_group_name, {
            'type': 'chati_message',
            'message': content['message']
        })
        await self.add_message(content['message'])

    async def chati_message(self, event):
        await self.send_json(content={'message': event['message']})

    @database_sync_to_async
    def set_chan(self):
        self.chan = Chan.objects.get_or_create(name=self.room_name)[0]

    @database_sync_to_async
    def add_message(self, message):
        if self.scope['user'].is_authenticated:
            Message.objects.create(chan=self.chan, user=self.scope['user'], message=message)

    @database_sync_to_async
    def get_messages(self):
        return list(str(msg) for msg in Message.objects.filter(chan=self.chan))

class ServerSentEventsConsumer(AsyncHttpConsumer):
    async def handle(self, body):
        await self.send_headers(headers=[
            (b'Cache-Control', b'no-cache'),
            (b'Content-Type', b'text/event-stream'),
            (b'Transfer-Encoding', b'chunked'),
        ])
        while True:
            payload = f'data: {datetime.now():%x %X}\n\n'
            await self.send_body(payload.encode('utf-8'), more_body=True)
            await asyncio.sleep(1)


import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score
from sklearn import preprocessing
import matplotlib.pyplot as plt
import seaborn as sns
import os

os.chdir('/Users/CLETUS/Projects/python/mundoz')
heart = pd.read_csv('mun.csv', sep=',', header=0)
print(heart.head())

le = preprocessing.LabelEncoder()
heart['PATIENT_ID'] = le.fit_transform(heart['PATIENT_ID'].astype(str))
heart['Pvd'] = le.fit_transform(heart['Pvd'].astype(str))
heart['Diagnosis'] = le.fit_transform(heart['Diagnosis'].astype(str))
heart['ICD10 Diagnosis'] = le.fit_transform(heart['ICD10 Diagnosis'].astype(str))
heart.drop(['Attending Physician'], axis=1, inplace=True)
print(heart.head())

heart['Status'].replace(to_replace='Y',value=1,inplace=True)
heart['Status'].replace(to_replace='N',value=0,inplace=True)

print(heart.head())

Y = heart["Status"].values
X = heart.drop(labels = ["Status"],axis = 1)
# Create Train & Test Data
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=101)

model = GaussianNB()
# Train the model
model.fit(X_train, y_train)
# # Test Model
prediction_test = model.predict(X_test)
# # Print the prediction results
print(prediction_test)

print(accuracy_score(y_test, prediction_test))
# # %%
Predict = model.predict([[595,657,198738000,20101110,20101115,2,13,91]])
print(Predict)
# prediction_test = model.predict(X_test)
# # Print the prediction accuracy
# print (metrics.accuracy_score(y_test, prediction_test))
# # %%
# # To get the weights of all the variables
# weights = pd.Series(model.coef_[0],
#  index=X.columns.values)
# weights.sort_values(ascending = False)
# print (weights)
# feat_importances = pd.Series(model.coef_[0],index=X.columns.values)
# feat_importances.nlargest(10).plot(kind='barh')
# plt.show()
# # %%
# # Data to plot
# sizes = heart['churn'].value_counts(sort = True)
# colors = ["grey","purple"]
# labels = ["yes","no"]
# explode = (0, 0.1)  # only "explode" no label
# rcParams['figure.figsize'] = 5,5
# # Plot
# plt.pie(sizes, colors=colors,labels=labels,explode=explode,
#         autopct='%1.1f%%', shadow=True, startangle=270,)
# plt.title('Percentage of Churn in Dataset ')
# plt.show()
# # plot X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=101)
# # plt.scatter(X_test, y_test,  color='gray')
# # plt.plot(X_test, prediction_test, color='red', linewidth=2)
# # plt.show()

# # %%

# # RF = RandomForestClassifier(n_estimators=1000, max_depth=10, random_state=0).fit(X_train, y_train)
# # model3 = RF.predict(X_test)
# # round(RF.score(X_test, y_test), 4)

# # NN = MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(150, 10), random_state=1).fit(X_train, y_train)
# # model2 = NN.predict(X_test)
# # round(NN.score(X_test, y_test), 4)
# # print (metrics.accuracy_score(y_test, model3))
# # print (metrics.accuracy_score(y_test, model2))


# encoding: utf-8

"""
.. codeauthor:: Tsuyoshi Hombashi <tsuyoshi.hombashi@gmail.com>
"""

from __future__ import absolute_import, unicode_literals

import copy
import enum
import multiprocessing
from collections import Counter

from six import text_type
from six.moves import zip
from typepy import (
    Bool,
    DateTime,
    Dictionary,
    Infinity,
    Integer,
    IpAddress,
    List,
    Nan,
    NoneType,
    NullString,
    RealNumber,
    StrictLevel,
    String,
    is_empty_sequence,
)

from ._column import ColumnDataProperty
from ._common import MIN_STRICT_LEVEL_MAP, DefaultValue
from ._converter import DataPropertyConverter
from ._dataproperty import DataProperty
from ._formatter import Format
from ._line_break import LineBreakHandling
from .logger import logger

def nop(v):
    return v

@enum.unique
class MatrixFormatting(enum.Enum):
    # raise exception if the matrix is not properly formatted
    EXCEPTION = 1 << 1

    # trim to the minimum size column
    TRIM = 1 << 2

    # Append None values to columns so that it is the same as the maximum
    # column size.
    FILL_NONE = 1 << 3

    HEADER_ALIGNED = 1 << 4

class DataPropertyExtractor(object):
    """
    .. py:attribute:: quoting_flags

        Configurations to add double quote to for each items in a matrix,
        where |Typecode| of table-value is |True| in the ``quote_flag_table``
        mapping table. ``quote_flag_table`` should be a dictionary.
        And is ``{ Typecode : bool }``. Defaults to:

        .. code-block:: json
            :caption: The default values

            {
                Typecode.BOOL: False,
                Typecode.DATETIME: False,
                Typecode.DICTIONARY: False,
                Typecode.INFINITY: False,
                Typecode.INTEGER: False,
                Typecode.IP_ADDRESS: False,
                Typecode.LIST: False,
                Typecode.NAN: False,
                Typecode.NULL_STRING: False,
                Typecode.NONE: False,
                Typecode.REAL_NUMBER: False,
                Typecode.STRING: False,
            }
    """

    @property
    def headers(self):
        return self.__headers

    @headers.setter
    def headers(self, value):
        if self.__headers == value:
            return

        self.__headers = value
        self.__clear_cache()

    @property
    def header_list(self):
        """alias to headers"""
        return self.headers

    @header_list.setter
    def header_list(self, value):
        """alias to headers"""
        self.headers = value

    @property
    def default_type_hint(self):
        return self.__default_type_hint

    @default_type_hint.setter
    def default_type_hint(self, value):
        if self.__default_type_hint == value:
            return

        self.__default_type_hint = value
        self.__clear_cache()

    @property
    def column_type_hints(self):
        return self.__col_type_hints

    @column_type_hints.setter
    def column_type_hints(self, value):
        if self.__col_type_hints == value:
            return

        if value:
            for type_hint in value:
                if type_hint not in (
                    Bool,
                    DateTime,
                    Dictionary,
                    Infinity,
                    Integer,
                    IpAddress,
                    List,
                    Nan,
                    NoneType,
                    RealNumber,
                    String,
                    NullString,
                    None,
                ):
                    raise ValueError("invalid type hint: {}".format(type(type_hint)))

        self.__col_type_hints = value
        self.__clear_cache()

    @property
    def column_type_hint_list(self):
        # deprecated: alias to column_type_hints
        return self.column_type_hints

    @column_type_hint_list.setter
    def column_type_hint_list(self, value):
        # deprecated: alias to column_type_hints
        self.column_type_hints = value

    @property
    def line_break_handling(self):
        return self.__line_break_handling

    @line_break_handling.setter
    def line_break_handling(self, value):
        if self.__line_break_handling == value:
            return

        self.__line_break_handling = value
        self.__update_dp_converter()

    @property
    def is_formatting_float(self):
        return self.__is_formatting_float

    @is_formatting_float.setter
    def is_formatting_float(self, value):
        self.__is_formatting_float = value

    @property
    def is_escape_html_tag(self):
        return self.__is_escape_html_tag

    @is_escape_html_tag.setter
    def is_escape_html_tag(self, value):
        if self.__is_escape_html_tag == value:
            return

        self.__is_escape_html_tag = value
        self.__update_dp_converter()

    @property
    def strip_str_header(self):
        return self.__strip_str_header

    @strip_str_header.setter
    def strip_str_header(self, value):
        if self.__strip_str_header == value:
            return

        self.__strip_str_header = value
        self.__clear_cache()

    @property
    def strip_str_value(self):
        return self.__strip_str_value

    @strip_str_value.setter
    def strip_str_value(self, value):
        if self.__strip_str_value == value:
            return

        self.__strip_str_value = value
        self.__clear_cache()

    @property
    def min_column_width(self):
        return self.__min_col_ascii_char_width

    @min_column_width.setter
    def min_column_width(self, value):
        if self.__min_col_ascii_char_width == value:
            return

        self.__min_col_ascii_char_width = value
        self.__clear_cache()

    @property
    def format_flags_list(self):
        return self.__format_flags_list

    @format_flags_list.setter
    def format_flags_list(self, value):
        if self.__format_flags_list == value:
            return

        self.__format_flags_list = value
        self.__clear_cache()

    @property
    def float_type(self):
        return self.__float_type

    @float_type.setter
    def float_type(self, value):
        if self.__float_type == value:
            return

        self.__float_type = value
        self.__clear_cache()

    @property
    def datetime_format_str(self):
        return self.__datetime_format_str

    @datetime_format_str.setter
    def datetime_format_str(self, value):
        if self.__datetime_format_str == value:
            return

        self.__datetime_format_str = value
        self.__clear_cache()

    @property
    def strict_level_map(self):
        return self.__strict_level_map

    @strict_level_map.setter
    def strict_level_map(self, value):
        if self.__strict_level_map == value:
            return

        self.__strict_level_map = value
        self.__clear_cache()

    @property
    def east_asian_ambiguous_width(self):
        return self.__east_asian_ambiguous_width

    @east_asian_ambiguous_width.setter
    def east_asian_ambiguous_width(self, value):
        if self.__east_asian_ambiguous_width == value:
            return

        self.__east_asian_ambiguous_width = value
        self.__clear_cache()

    @property
    def type_value_map(self):
        return self.__type_value_map

    @type_value_map.setter
    def type_value_map(self, value):
        if self.__type_value_map == value:
            return

        self.__type_value_map = value
        self.__clear_cache()

    @property
    def trans_func(self):
        # deprecated
        return self.__trans_func

    @trans_func.setter
    def trans_func(self, value):
        # deprecated
        if self.__trans_func is value:
            return

        self.__trans_func = value
        self.__clear_cache()

    def register_trans_func(self, trans_func):
        self.__trans_func_list.insert(0, trans_func)
        self.__clear_cache()

    @property
    def quoting_flags(self):
        return self.__quoting_flags

    @quoting_flags.setter
    def quoting_flags(self, value):
        if self.__quoting_flags == value:
            return

        self.__quoting_flags = value
        self.__clear_cache()

    @property
    def datetime_formatter(self):
        return self.__datetime_formatter

    @datetime_formatter.setter
    def datetime_formatter(self, value):
        if self.__datetime_formatter == value:
            return

        self.__datetime_formatter = value
        self.__clear_cache()

    @property
    def matrix_formatting(self):
        return self.__matrix_formatting

    @matrix_formatting.setter
    def matrix_formatting(self, value):
        if self.__matrix_formatting == value:
            return

        self.__matrix_formatting = value
        self.__clear_cache()

    def __init__(self):
        self.max_workers = multiprocessing.cpu_count()

        self.__headers = []
        self.__default_type_hint = None
        self.__col_type_hints = None

        self.__strip_str_header = None
        self.__strip_str_value = None
        self.__is_formatting_float = True
        self.__line_break_handling = LineBreakHandling.NOP
        self.__is_escape_html_tag = False
        self.__min_col_ascii_char_width = 0
        self.__format_flags_list = []
        self.__float_type = None
        self.__datetime_format_str = DefaultValue.DATETIME_FORMAT
        self.__strict_level_map = copy.deepcopy(DefaultValue.STRICT_LEVEL_MAP)
        self.__east_asian_ambiguous_width = 1

        self.__type_value_map = copy.deepcopy(DefaultValue.TYPE_VALUE_MAP)

        self.__trans_func = nop
        self.__trans_func_list = []
        self.__quoting_flags = copy.deepcopy(DefaultValue.QUOTING_FLAGS)
        self.__datetime_formatter = None
        self.__matrix_formatting = MatrixFormatting.TRIM

        self.__clear_cache()

    def __clear_cache(self):
        self.__update_dp_converter()
        self.__dp_cache_zero = self.__to_dp_raw(0)
        self.__dp_cache_one = self.__to_dp_raw(1)
        self.__dp_cache_true = self.__to_dp_raw(True)
        self.__dp_cache_false = self.__to_dp_raw(False)
        self.__dp_cache_map = {None: self.__to_dp_raw(None), "": self.__to_dp_raw("")}

    def to_dp(self, value):
        self.__update_dp_converter()

        return self.__to_dp(value, strip_str=self.strip_str_value)

    def to_dp_list(self, values):
        if is_empty_sequence(values):
            return []

        self.__update_dp_converter()

        return self._to_dp_list(values, strip_str=self.strip_str_value)

    def to_column_dp_list(self, value_dp_matrix, previous_column_dp_list=None):
        col_dp_list = self.__get_col_dp_list_base()

        logger.debug("converting to column dataproperty:")

        logs = [
            "  params:",
            "    prev_col_count={}".format(
                len(previous_column_dp_list) if previous_column_dp_list else None
            ),
            "    matrix_formatting={}".format(self.matrix_formatting),
        ]
        if self.column_type_hints:
            logs.append(
                "    column_type_hints=({})".format(
                    ", ".join(
                        [
                            type_hint.__name__ if type_hint else "none"
                            for type_hint in self.column_type_hints
                        ]
                    )
                )
            )
        else:
            logs.append("    column_type_hints=()")

        for log in logs:
            logger.debug(log)

        logger.debug("  results:")
        for col_idx, value_dp_list in enumerate(zip(*value_dp_matrix)):
            try:
                col_dp_list[col_idx]
            except IndexError:
                col_dp_list.append(
                    ColumnDataProperty(
                        column_index=col_idx,
                        min_width=self.min_column_width,
                        format_flags=self.__get_format_flags(col_idx),
                        is_formatting_float=self.is_formatting_float,
                        datetime_format_str=self.datetime_format_str,
                        east_asian_ambiguous_width=self.east_asian_ambiguous_width,
                    )
                )

            col_dp = col_dp_list[col_idx]
            col_dp.begin_update()

            try:
                col_dp.merge(previous_column_dp_list[col_idx])
            except (TypeError, IndexError):
                pass

            for value_dp in value_dp_list:
                col_dp.update_body(value_dp)

            col_dp.end_update()

            logger.debug("    {:s}".format(text_type(col_dp)))

        return col_dp_list

    def to_dp_matrix(self, value_matrix):
        self.__update_dp_converter()
        logger.debug("max_workers = {}".format(self.max_workers))

        value_matrix = self.__strip_data_matrix(value_matrix)

        if self.__is_dp_matrix(value_matrix):
            logger.debug("already a dataproperty matrix")
            return value_matrix

        if not self.max_workers:
            self.max_workers = multiprocessing.cpu_count()

        if self.max_workers <= 1:
            return self.__to_dp_matrix_st(value_matrix)

        return self.__to_dp_matrix_mt(value_matrix)

    def to_header_dp_list(self):
        self.__update_dp_converter()

        return self._to_dp_list(
            self.headers,
            type_hint=String,
            strip_str=self.strip_str_header,
            strict_level_map=MIN_STRICT_LEVEL_MAP,
        )

    @staticmethod
    def __is_dp_matrix(value):
        if not value:
            return False

        try:
            return isinstance(value[0][0], DataProperty)
        except (TypeError, IndexError):
            return False

    def __get_col_type_hint(self, col_idx):
        try:
            return self.column_type_hints[col_idx]
        except (TypeError, IndexError):
            return self.default_type_hint

    def __get_format_flags(self, col_idx):
        try:
            return self.format_flags_list[col_idx]
        except (TypeError, IndexError):
            return Format.NONE

    def __to_dp(self, data, type_hint=None, strip_str=None, strict_level_map=None):
        for trans_func in self.__trans_func_list:
            data = trans_func(data)

        if type_hint:
            return self.__to_dp_raw(
                data, type_hint=type_hint, strip_str=strip_str, strict_level_map=strict_level_map
            )

        try:
            if data in self.__dp_cache_map:
                return self.__dp_cache_map.get(data)
        except TypeError:
            # unhashable type
            pass

        if data == 0:
            if data is False:
                return self.__dp_cache_false
            return self.__dp_cache_zero
        if data == 1:
            if data is True:
                return self.__dp_cache_true
            return self.__dp_cache_one

        return self.__to_dp_raw(
            data, type_hint=type_hint, strip_str=strip_str, strict_level_map=strict_level_map
        )

    def __to_dp_raw(self, data, type_hint=None, strip_str=None, strict_level_map=None):
        value_dp = DataProperty(
            data,
            type_hint=(type_hint if type_hint is not None else self.default_type_hint),
            line_break_handling=self.line_break_handling,
            strip_str=strip_str,
            float_type=self.float_type,
            datetime_format_str=self.datetime_format_str,
            strict_level_map=(strict_level_map if type_hint is not None else self.strict_level_map),
            east_asian_ambiguous_width=self.east_asian_ambiguous_width,
        )

        return self.__dp_converter.convert(value_dp)

    def __to_dp_matrix_st(self, value_matrix):
        return list(
            zip(
                *[
                    _to_dp_list_helper(
                        self,
                        col_idx,
                        values,
                        self.__get_col_type_hint(col_idx),
                        self.strip_str_value,
                    )[1]
                    for col_idx, values in enumerate(zip(*value_matrix))
                ]
            )
        )

    def __to_dp_matrix_mt(self, value_matrix):
        from concurrent import futures

        col_data_map = {}

        try:
            with futures.ProcessPoolExecutor(self.max_workers) as executor:
                future_list = [
                    executor.submit(
                        _to_dp_list_helper,
                        self,
                        col_idx,
                        values,
                        self.__get_col_type_hint(col_idx),
                        self.strip_str_value,
                    )
                    for col_idx, values in enumerate(zip(*value_matrix))
                ]

                for future in futures.as_completed(future_list):
                    col_idx, value_dp_list = future.result()
                    col_data_map[col_idx] = value_dp_list
        finally:
            logger.debug("shutdown ProcessPoolExecutor: workers={}".format(self.max_workers))
            executor.shutdown()

        return list(zip(*[col_data_map[col_idx] for col_idx in sorted(col_data_map)]))

    def _to_dp_list(self, data_list, type_hint=None, strip_str=None, strict_level_map=None):
        if is_empty_sequence(data_list):
            return []

        type_counter = Counter()

        dp_list = []
        for data in data_list:
            expect_type_hint = type_hint
            if type_hint is None:
                try:
                    expect_type_hint, _count = type_counter.most_common(1)[0]
                    if not expect_type_hint(data, strict_level=StrictLevel.MAX).is_type():
                        expect_type_hint = None
                except IndexError:
                    pass

            dataprop = self.__to_dp(
                data=data,
                type_hint=expect_type_hint,
                strip_str=strip_str,
                strict_level_map=strict_level_map,
            )
            type_counter[dataprop.type_class] += 1

            dp_list.append(dataprop)

        return dp_list

    def __strip_data_matrix(self, data_matrix):
        header_col_size = len(self.headers) if self.headers else 0
        try:
            col_size_list = [len(data_list) for data_list in data_matrix]
        except TypeError:
            return []

        if self.headers:
            min_col_size = min([header_col_size] + col_size_list)
            max_col_size = max([header_col_size] + col_size_list)
        elif col_size_list:
            min_col_size = min(col_size_list)
            max_col_size = max(col_size_list)
        else:
            min_col_size = 0
            max_col_size = 0

        if self.matrix_formatting == MatrixFormatting.EXCEPTION:
            if min_col_size != max_col_size:
                raise ValueError(
                    "nonuniform column size: min={}, max={}".format(min_col_size, max_col_size)
                )

            return data_matrix

        if self.matrix_formatting == MatrixFormatting.HEADER_ALIGNED:
            if header_col_size > 0:
                format_col_size = header_col_size
            else:
                format_col_size = max_col_size
        elif self.matrix_formatting == MatrixFormatting.TRIM:
            format_col_size = min_col_size
        elif self.matrix_formatting == MatrixFormatting.FILL_NONE:
            format_col_size = max_col_size
        else:
            raise ValueError("unknown matrix formatting: {}".format(self.matrix_formatting))

        return [
            list(data_matrix[row_idx][:format_col_size]) + [None] * (format_col_size - col_size)
            for row_idx, col_size in enumerate(col_size_list)
        ]

    def __get_col_dp_list_base(self):
        header_dp_list = self.to_header_dp_list()
        col_dp_list = []

        for col_idx, header_dp in enumerate(header_dp_list):
            col_dp = ColumnDataProperty(
                column_index=col_idx,
                min_width=self.min_column_width,
                format_flags=self.__get_format_flags(col_idx),
                is_formatting_float=self.is_formatting_float,
                datetime_format_str=self.datetime_format_str,
                east_asian_ambiguous_width=self.east_asian_ambiguous_width,
            )
            col_dp.update_header(header_dp)
            col_dp_list.append(col_dp)

        return col_dp_list

    def __update_dp_converter(self):
        self.__dp_converter = DataPropertyConverter(
            type_value_map=self.type_value_map,
            quoting_flags=self.quoting_flags,
            line_break_handling=self.line_break_handling,
            is_escape_html_tag=self.is_escape_html_tag,
            datetime_formatter=self.datetime_formatter,
            datetime_format_str=self.datetime_format_str,
            float_type=self.float_type,
            strict_level_map=self.strict_level_map,
        )

def _to_dp_list_helper(extractor, col_idx, data_list, type_hint, strip_str):
    return (col_idx, extractor._to_dp_list(data_list, type_hint=type_hint, strip_str=strip_str))


#!/usr/bin/env python

import category_encoders as ce
from pandas import concat, Series
from time import time
from pandas.core.frame import DataFrame
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.compose import ColumnTransformer
from sklearn.metrics import f1_score
from sklearn.model_selection import train_test_split
from scipy.sparse import hstack, csr_matrix, vstack
import numpy as np
from sklearn.utils import resample

# generating training and validation data sets from sparse matrices
def train_val_upsampling_split(train_values_df, train_labels_df, upsampling=False):
    X_train, X_val, y_train, y_val = train_test_split(
        train_values_df, train_labels_df, test_size=0.3, random_state=42)
    if upsampling:
        X = hstack((X_train, y_train)).toarray()
        level_list = []
        for level in range(1, 4):
            level_filter = X[:, -1] == level
            level_X = X[level_filter, 0:-1]
            level_y = X[level_filter, -1].ravel()
            level_list.append([level_X, level_y])
        level_low, level_medium, level_high = level_list
        # medium level has the highest count, so let's increase the other two by up-sampling
        upsampled_list = []
        for upsampled in [level_low, level_high]:
            tmp_upsampled_list = []
            for arr in upsampled:
                tmp_upsampled_list.append(resample(arr,
                                          replace=True,  # sample with replacement
                                          n_samples=len(level_medium[1]),  # match number in medium level
                                          random_state=33))  # reproducible results
            upsampled_list.append(tmp_upsampled_list)  # type: ignore
        upsampled_list.append(level_medium)  # notice: append works in place
        mat_x_list, mat_y_list = [], []
        for mat_x, mat_y in upsampled_list:
            mat_x_list.append(csr_matrix(mat_x))
            mat_y_list.append(mat_y)
        X_train = vstack(mat_x_list)
        y_train = Series(np.concatenate(mat_y_list, axis=0).ravel())
        y_val = y_val.iloc[:, 0]
    print(f'X_train.shape: {X_train.shape}')
    print(f'y_train.shape: {y_train.shape}')
    print(f'X_val.shape: {X_val.shape}')
    print(f'y_val.shape: {y_val.shape}\n')
    return X_train, X_val, y_train, y_val

# one-hot encodes categorical columns and create mean-target encoding columns in dataframe
def target_encode_multiclass(train_values_df, train_labels_df, test_values_df=None):
    onehot_enc = ce.OneHotEncoder()
    train_labels_onehot_df = onehot_enc.fit_transform(train_labels_df)
    class_names = train_labels_onehot_df.columns
    cat_train_values_df = train_values_df.select_dtypes('category')
    num_train_values_df = train_values_df.select_dtypes(exclude='category')
    num_pipeline = Pipeline([('imputer', SimpleImputer(strategy='median')),
                             ('std_scaler', StandardScaler())])
    num_train_values_arr = num_pipeline.fit_transform(num_train_values_df)
    num_train_values_df = DataFrame(num_train_values_arr, columns=num_train_values_df.columns,
                                    index=train_values_df.index)
    if test_values_df is not None:
        cat_test_values_df = test_values_df.select_dtypes('category')
        num_test_values_df = test_values_df.select_dtypes(exclude='category')
        num_test_values_arr = num_pipeline.fit_transform(num_test_values_df)
        num_test_values_df = DataFrame(num_test_values_arr, columns=num_test_values_df.columns,
                                       index=test_values_df.index)
    for class_name in class_names:
        enc = ce.target_encoder.TargetEncoder(min_samples_leaf=10, smoothing=0.1)
        enc.fit(cat_train_values_df, train_labels_onehot_df[class_name])
        temp_train_df = enc.transform(cat_train_values_df)
        temp_train_df.columns = [str(col)+'_'+str(class_name) for col in temp_train_df.columns]
        num_train_values_df = concat([num_train_values_df, temp_train_df], axis=1)
        if test_values_df is not None:
            temp_test_df = enc.transform(cat_test_values_df)  # type: ignore
            temp_test_df.columns = [str(col)+'_'+str(class_name) for col in temp_test_df.columns]
            num_test_values_df = concat([num_test_values_df, temp_test_df], axis=1)  # type: ignore
    if test_values_df is not None:
        return num_train_values_df, num_test_values_df  # type: ignore
    else:
        return num_train_values_df

# multi-category encoder function to test category functions in category_encoders with earthquake data
def test_category_encoders(classifier, X_strat_train, y_strat_train, X_strat_val, y_strat_val, num_attrib, cat_attrib):
    encoder_list = [
                    ce.backward_difference.BackwardDifferenceEncoder,
                    ce.basen.BaseNEncoder,
                    ce.binary.BinaryEncoder,
                    ce.cat_boost.CatBoostEncoder,  # didn't work with earthquake data
                    ce.hashing.HashingEncoder,  # didn't work with earthquake data
                    ce.helmert.HelmertEncoder,
                    ce.james_stein.JamesSteinEncoder,
                    ce.one_hot.OneHotEncoder,  # didn't work with earthquake data
                    ce.leave_one_out.LeaveOneOutEncoder,  # didn't work with earthquake data
                    ce.m_estimate.MEstimateEncoder,
                    ce.ordinal.OrdinalEncoder,
                    ce.polynomial.PolynomialEncoder,
                    ce.sum_coding.SumEncoder,
                    ce.target_encoder.TargetEncoder,  # didn't work with earthquake data
                    ce.woe.WOEEncoder
                    ]
    for encoder in encoder_list:
        t0 = time()
        numeric_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='median')),
                                              ('scaler', StandardScaler())])
        categorical_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='constant',
                                                  fill_value='missing')), ('woe', encoder())])

        preprocessor = ColumnTransformer(transformers=[('num', numeric_transformer, num_attrib),
                                                       ('cat', categorical_transformer, cat_attrib)], n_jobs=-1)

        pipe = Pipeline(steps=[('preprocessor', preprocessor), ('classifier', classifier)])
        print(f'Fitting encoder: {encoder}')
        model = pipe.fit(X_strat_train, y_strat_train)

        y_pred = model.predict(X_strat_val)
        print(f'''Time elapsed: {time() - t0:.4f} sec, micro-averaged F1 score: {f1_score(y_strat_val,y_pred,
        average='micro'):.8f}''')


#! /usr/bin/env python3
# _*_ coding: utf8 _*_

import os
import socket
import sys
from multiprocessing import shared_memory, active_children
from builtins import OSError

sharedMemorySize = 20

def create_tubes(path_tube_1, path_tube_2):
    try:
        os.mkfifo(path_tube_1, 0o0600)
        os.mkfifo(path_tube_2, 0o0600)
    except OSError as error:
        print(error)
        sys.exit("Could not create tubes : ")

def create_shared_memory(name, create):
    try:
        return shared_memory.SharedMemory(name, create, sharedMemorySize)
    except (ValueError, FileExistsError, OSError) as error:
        print(error)
        sys.exit("Could not create shared memory : ")

def create_socket():
    created_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    created_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    return created_socket

def fill_shared_memory(shared_memory, data):
    shared_memory.buf[:sharedMemorySize] = data

def free_communication_system(shared_memory_name, path_tube_1, path_tube_2):
    try:
        if(os.path.exists(path_tube_1)):
            os.unlink(path_tube_1)
    except OSError as error:
        print("Warning : ", error)
    try:
        if(os.path.exists(path_tube_2)):
            os.unlink(path_tube_2)
    except OSError as error:
        print("Warning : ", error)
    try:
        if os.path.exists("/run/shm/leclerc"):
            shared_memory_to_delete = shared_memory.SharedMemory(shared_memory_name)
            shared_memory_to_delete.unlink()
    except OSError as error:
        print("Warning : ", error)

def delete_socket(socket_to_delete):
    socket_to_delete.close()
    del socket_to_delete

def terminate_children():
    active_children_list = active_children()
    for child in active_children_list:
        child.terminate()
    return active_children_list


import concurrent.futures
import re
import time
import xml.etree.ElementTree as ET

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

class NetworkHandler:
    """
    Abstracts the creation of session with specific retry strategy and multithreading
    """

    def __init__(self):
        self.session = self.mount_session()
        self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)

    def mount_session(self):
        retry_strategy = Retry(
            total=5,
            respect_retry_after_header=True,
            backoff_factor=0.1,
            status_forcelist=[429, 500, 502, 503, 504, 520],
            allowed_methods=["GET", "POST"],
        )
        retry_strategy.DEFAULT_BACKOFF_MAX = 5
        adapter = HTTPAdapter(max_retries=retry_strategy)
        session = requests.Session()
        session.mount(prefix="https://", adapter=adapter)
        session.mount(prefix="http://", adapter=adapter)
        return session

class Archiver:
    """
    Used for authenticating and interacting with the archive.org API.
    """

    def __init__(self, s3_access_key, s3_secret_key):
        """
        Initialize the object
        :param s3_access_key: s3_access_key
        :param s3_secret_key: s3_secret_key
        """

        self.s3_access_key = s3_access_key
        self.s3_secret_key = s3_secret_key
        self.session = NetworkHandler().session
        self.executor = NetworkHandler().executor

        headers = {
            "Accept": "application/json",
            "Authorization": f"LOW {self.s3_access_key}:{self.s3_secret_key}",
        }
        self.session.headers.update(headers)

    def save_pages(
        self,
        pages: list,
        capture_all=False,
        capture_outlinks=False,
        capture_screenshot=False,
        force_get=False,
        skip_first_archive=True,
        outlinks_availability=False,
        email_result=False,
    ):
        """
        Save a list of webpages to the archive.org API using multithreading and automatic retries
        """

        results = []
        failures = []
        with self.executor as executor:
            future_to_url = {
                executor.submit(
                    self.save_page,
                    url,
                    capture_all=capture_all,
                    capture_outlinks=capture_outlinks,
                    capture_screenshot=capture_screenshot,
                    force_get=force_get,
                    skip_first_archive=skip_first_archive,
                    outlinks_availability=outlinks_availability,
                    email_result=email_result,
                ): url
                for url in pages
            }
            for future in concurrent.futures.as_completed(future_to_url):
                url = future_to_url[future]
                try:
                    results.append(future.result())
                except Exception as exc:
                    failures.append(url)
            if failures:
                results.extend(
                    self.save_pages(
                        failures,
                        capture_all=capture_all,
                        capture_outlinks=capture_outlinks,
                        capture_screenshot=capture_screenshot,
                        force_get=force_get,
                        skip_first_archive=skip_first_archive,
                        outlinks_availability=outlinks_availability,
                        email_result=email_result,
                    )
                )
            return results

    def save_page(
        self,
        url,
        capture_all=False,
        capture_outlinks=False,
        capture_screenshot=False,
        force_get=False,
        skip_first_archive=True,
        outlinks_availability=False,
        email_result=False,
    ):
        """
        Save a single webpage to archive.org
        """

        save_url = f"https://web.archive.org/save/{url}"
        response = self.session.post(
            url=save_url,
            data={
                "url": url,
                "capture_all": capture_all,
                "capture_outlinks": capture_outlinks,
                "force_get": force_get,
                "skip_first_archive": skip_first_archive,
                "capture_screenshot": capture_screenshot,
                "outlinks_availability": outlinks_availability,
                "email_result": email_result,
            },
        )
        if response.status_code == 200:
            data = response.json()
            if data.get("status") is None and data.get("job_id"):
                status = "submitted"
            else:
                status = data.get("status")

            formatted_response = {
                "url": url,
                "job_id": data.get("job_id"),
                "message": data.get("message"),
                "status": status,
                "full_response": data,
            }
            return formatted_response

        else:
            formatted_response = {
                "url": url,
                "status_code": response.status_code,
                "full_response": response.text,
            }
            return formatted_response

    def get_save_status(self, job_id: str):
        """
        Given a job_id, get the save status of the job.
        :param job_id: job_id
        :return: save_status
        """
        url = f"https://web.archive.org/save/status/{job_id}?_t={int(time.time())}"
        response = self.session.get(url=url)
        if response.status_code == 200:
            data = response.json()
            if data.get("status") == "error":
                return self.get_save_status(job_id=job_id)
            else:
                return data
        else:
            return response.text

    def get_user_status_request(self):
        """
        Get the current number of active and available session of the user account.
        """
        url = f"https://web.archive.org/save/status/user?_t={int(time.time())}"
        response = self.session.get(url=url)
        if response.status_code == 200:
            try:
                return response.json()
            except:
                if "Too Many Requests" in response.text:
                    return 429, "Too Many Requests"
                return response.text
        else:
            return response.status_code, response.text

class Sitemap:
    def __init__(self, sitemap_URL):
        self.location = sitemap_URL
        self.LOCAL_PREFIX = "file://"
        self.local_sitemap = self._sitemap_is_local()
        self.content = self._load_sitemap()
        self.encoded_content = ET.fromstring(self.content)
        self.namespace = self._get_namespace()
        self.type = self._get_sitemap_type()

    def _sitemap_is_local(self):
        """
        Returns True if we believe a URI to be local, False otherwise.
        """
        return self.location.startswith(self.LOCAL_PREFIX) or self.location.startswith(
            "/"
        )

    def _load_sitemap(self):
        """Loads a sitemap from a local file or download it from the internet."""
        if self.local_sitemap:
            sitemap_filepath = sitemap_filepath[len(self.LOCAL_PREFIX) :]

            # Try to open the file, error on failure
            try:
                with open(sitemap_filepath, "r") as fp:
                    contents = fp.read()
            except IOError as e:
                print(e)
                raise
            return contents

        else:
            response = requests.get(self.location)
            try:
                # Raise `requests.exceptions.HTTPError` if 4XX or 5XX status
                response.raise_for_status()
            except requests.exceptions.HTTPError as e:
                print(e)
                raise
            else:
                return response.text.encode("utf-8")

    def _get_sitemap_type(self):
        if "sitemapindex" in self.encoded_content.tag:
            return "sitemapindex"
        elif "urlset" in self.encoded_content.tag:
            return "urlset"
        else:
            return None

    def _get_namespace(self):
        """Extract the namespace using a regular expression."""
        match = re.match(r"{.*}", self.encoded_content.tag)
        return match.group(0) if match else ""

    def extract_pages_from_sitemap(self):
        """
        Extract the various pages from the sitemap text.
        """
        if self.type == "urlset":
            urls = []
            for loc_node in self.encoded_content.findall(f".//{self.namespace}loc"):
                urls.append(loc_node.text)

            return list(set(urls))
        elif self.type == "sitemapindex":
            raise NotImplementedError(
                "sitemapindex not implemented yet.\nPlease retry with a urlset sitemap."
            )
        else:
            raise ValueError(f"Unknown sitemap type: {self.type}")


import time
from unittest import TestCase
from alttester import By
from tests.base.alt_unity_driver_wrapper import AltUnityDriverWrapper

class TestPrivacyPolicySkip(TestCase, AltUnityDriverWrapper):

    def setUp(self):
        super().set_up(enable_alt_unity_tester=True)

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

    def test_enter(self):
        if self.isIosPlatform:
            return

        print("Finding policy accept button")
        acceptButton = self.alt_unity_driver.wait_for_object(By.NAME, 'ButtonOk')

        print("Tap on policy accept button")
        acceptButton.tap()

        self.saveScreenshot("enter")

        time.sleep(3)

    def test_exit(self):
        if self.isIosPlatform:
            return

        print("Finding again policy accept button")
        self.alt_unity_driver.wait_for_object_to_not_be_present(By.NAME, 'ButtonOk')
        self.saveScreenshot("exit")


from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static

admin.site.site_header = "Mickey Ice Creams Admin"
admin.site.site_title = "Mickey Ice Creams Admin Portal"
admin.site.index_title = "Welcome to Mickey Ice Creams"

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('home.urls')),
]


import random

def GetRandomNumber():
    return random.randint(1, 7)

keepGoing=True
while(keepGoing):

    #randomly choose a number

    randNumber = GetRandomNumber()

    #print random number
    print(randNumber)

    #ask user if they want to roll again
    answer = input("would you like to roll again? Yes or no")

    #if so,
    if(answer.upper() =="YES" or answer.upper() == "Y"):
        #repeat
        print("ok we'll roll again.")
    #keepgoing = true
    #if not,
    else:
    #exit
        print("goodbye.")
        keepGoing=False


#Importamos los siguientes módulos que nos serán de utilidad para poder leer la información de la página web
import http.client
import json

headers = {'User-Agent': 'http-client'}

conn = http.client.HTTPSConnection("api.fda.gov") #Establecemos conexión con la página solicitada
conn.request("GET", "/drug/label.json?&limit=10", None, headers) #GET: enviamos solicitud
r1 = conn.getresponse() #Obtenemos la respuesta de la solicitud enviada
if r1.status == 404: #Comprobamos si se ha podido encontrar el recurso correctamente (código 200), o si no se ha podido (código 404)
    print("ERROR, recurso no encontrado.")
    exit(1)
print(r1.status, r1.reason) #Imprimimos el código de estado de la respuesta
datos_raw = r1.read().decode("utf-8") #Convertimos la información para que sea legible
conn.close()

info = json.loads(datos_raw)['results'] #Convertimos la información a json

for elem in range(len(info)): #Con esto iteramos sobre los datos de los 10 medicamentos diferentes que queremos
    print('El id del medicamento es:', info[elem]['id']) #Imprimimos todas las id de los medicamentos


from ia import *
import copy

class Cobaia:
    def __init__(self, nome, entradas, estrutura: list = [3,3],chance_mutacao=0.05) -> None:
        self.nome = "Cobaia_" + nome
        self.cerebro = Cerebro("Cerebro_" + self.nome, entradas, estrutura, [self.zero, self.um], chance_mutacao)
        self.pontos = 0
        self.resultado = None

    def um(self):
        self.resultado = 1

    def zero(self):
        self.resultado = 0

    def pulse(self, valor: list[int]):
        self.cerebro.pulse(valor)
        return self.resultado

    def mutar(self):
        self.cerebro.mutar()

    def Add_pontos(self, pontos):
        self.pontos += pontos

class Tabuleiro:
    def __init__(self, limite_geracoes=100, qtd_selecao_melhores = 10) -> None:
        self.cobaias: list[Cobaia] = []

        self.geracao = 0
        self.limite_geracoes = limite_geracoes

        self.qtd_selecao_melhores = qtd_selecao_melhores

    def Init_cobaias(self,quantidade,  entradas, estrutura: list = [3,3],chance_mutacao=0.05):
        for cobaia in range(quantidade):
            nova_cobaia = Cobaia(str(cobaia-1), entradas, estrutura,chance_mutacao)
            self.cobaias.append(nova_cobaia)

    def Get_melhores(self) -> list[Cobaia]:
        melhores = sorted(self.cobaias,key=lambda x: x.pontos, reverse=True)[0:self.qtd_selecao_melhores]

        return melhores

    def Nova_Geracao(self):
        cobaias = self.cobaias
        qtd_cobaias = len(cobaias)

        melhores_cobaias = self.Get_melhores()

        copias =  self.qtd_selecao_melhores/qtd_cobaias

        novas_cobaias: list[Cobaia] = []

        index = 0
        index_melhor = 0
        copiados = 1

        indexes = []

        for i in range(qtd_cobaias):
            indexes.append(i)

        while len(novas_cobaias) < qtd_cobaias:

            cont = 0
            for i in indexes:
                if type(i) == type(1):
                    cont += 1

            if cont > 0:
                index = None

                while not(type(index) == type(1)):
                    index = random.sample(indexes,k=1)[0]

                cobaia_pai: Cobaia =  copy.deepcopy(melhores_cobaias[index_melhor])
                cobaia_pai.mutar()
                # cobaia_pai.pontos = 0
                indexes[index] = cobaia_pai

                if copiados == len(melhores_cobaias):
                    copiados = 0
                    index_melhor += 1
                else:
                    copiados += 1

                self.cobaias = indexes
                self.geracao += 1
            else:
                break

    def Pulse(self, valor: list[int], esperado: list[int]):
        for cobaia in self.cobaias:
            results = []

            for index, val in enumerate(valor):
                # print(val)
                cobaia.pulse(val)
                if cobaia.resultado == esperado[index]:
                    results.append(True)
                else:
                    results.append(False)

            if False in results:
                cobaia.Add_pontos(-1)
            else:
                cobaia.Add_pontos(1)

    def TESTE_add_pontos(self):
        for cobaia in self.cobaias:
            cobaia.Add_pontos(random.randint(0,100))

tab = Tabuleiro(limite_geracoes=10000,qtd_selecao_melhores=10)
tab.Init_cobaias(100,1, estrutura=[2,1])

contagem = 0
melhor_pontuacao = 0

while tab.geracao < tab.limite_geracoes:
    contagem += 1
    cls()

    for i in range(10):
        tab.Pulse([[0],[1]],[0,1])

    melhor_cobaia = tab.Get_melhores()[0]
    print("="*40)
    print("Geração: ", tab.geracao)
    print("Contagem: ", contagem+1)
    print("Melhor Cobaia: ", melhor_cobaia.nome)
    melhor_pontuacao = melhor_cobaia.pontos
    print("Pontos: ", melhor_pontuacao)

    melhores = tab.Get_melhores()

    print(f"{'n°':<2} |{'Cobaia':<10}|{'Pontos':>10}|{'Teste 0':>10}|{'Teste 1':>10}")
    print(f"{'1°':<2} |{melhores[0].nome:<10}|{melhores[0].pontos:>10}|{melhores[0].pulse([0]):>10}|{melhores[0].pulse([1]):>10}")
    print(f"{'2°':<2} |{melhores[1].nome:<10}|{melhores[1].pontos:>10}|{melhores[1].pulse([0]):>10}|{melhores[1].pulse([1]):>10}")
    print(f"{'3°':<2} |{melhores[2].nome:<10}|{melhores[2].pontos:>10}|{melhores[2].pulse([0]):>10}|{melhores[2].pulse([1]):>10}")
    print(f"{'4°':<2} |{melhores[3].nome:<10}|{melhores[3].pontos:>10}|{melhores[3].pulse([0]):>10}|{melhores[3].pulse([1]):>10}")
    print(f"{'5°':<2} |{melhores[4].nome:<10}|{melhores[4].pontos:>10}|{melhores[4].pulse([0]):>10}|{melhores[4].pulse([1]):>10}")
    print(f"{'6°':<2} |{melhores[5].nome:<10}|{melhores[5].pontos:>10}|{melhores[5].pulse([0]):>10}|{melhores[5].pulse([1]):>10}")
    print(f"{'7°':<2} |{melhores[6].nome:<10}|{melhores[6].pontos:>10}|{melhores[6].pulse([0]):>10}|{melhores[6].pulse([1]):>10}")
    print(f"{'8°':<2} |{melhores[7].nome:<10}|{melhores[7].pontos:>10}|{melhores[7].pulse([0]):>10}|{melhores[7].pulse([1]):>10}")
    print(f"{'9°':<2} |{melhores[8].nome:<10}|{melhores[8].pontos:>10}|{melhores[8].pulse([0]):>10}|{melhores[8].pulse([1]):>10}")
    print(f"{'10°':<2}|{melhores[9].nome:<10}|{melhores[9].pontos:>10}|{melhores[9].pulse([0]):>10}|{melhores[9].pulse([1]):>10}")

    if melhor_pontuacao >= 10:
        break
    else:
        tab.Nova_Geracao()

print("="*40)
print("Melhor Pontuacao: ", melhor_pontuacao)
print("Geração: ", tab.geracao)

melhor_cobaia = tab.Get_melhores()[0]
print("Teste do melhor! ", melhor_cobaia.nome)
print("Pontos: ", melhor_cobaia.pontos)

melhor_cobaia.pulse([0],[0])
print("Teste 0: ", melhor_cobaia.resultado)
melhor_cobaia.pulse([0],[0])
print("Teste 0: ", melhor_cobaia.resultado)
melhor_cobaia.pulse([0],[0])
print("Teste 0: ", melhor_cobaia.resultado)
melhor_cobaia.pulse([1],[1])
print("Teste 1: ", melhor_cobaia.resultado)
melhor_cobaia.pulse([1],[1])
print("Teste 1: ", melhor_cobaia.resultado)
melhor_cobaia.pulse([1],[1])
print("Teste 1: ", melhor_cobaia.resultado)