void add_new_personaje_in_plataforma(tSimbolo simbolo){
	int i;
	bool encontrado=false;
	for(i=0; i < list_size(personajes_jugando); i++){
		t_estado_personaje * personaje = list_get(personajes_jugando, i);
		if(personaje->simbolo == simbolo){
			encontrado =true;
			break;
		}
	}
	if(!encontrado){
		t_estado_personaje personaje;
		personaje.simbolo = simbolo;
		personaje.estado = false;
		list_add_new(personajes_jugando, &personaje, sizeof(t_estado_personaje));
	}
}
void detectInterbloqueos(void* argumentos) {

    t_list* bloqueados;
    paramInterbloqueo_t parametros;
    memcpy(&parametros, argumentos, sizeof(paramInterbloqueo_t));

    int cantBloq, marcados;

    // Iteramos infinitamente
    while (1) {
        pthread_mutex_lock(&semNiv);
        cantBloq = 0;
        marcados = 0;
        bloqueados = list_create();
        //log_trace(logger, "Initializing locking sysem activatinasdqu..,");
        int contPer1, contPer2;
        personaje_t* levantador1, *levantador2;

        //--Recorrer los personajes
        for (contPer1 = 0; contPer1 < list_size(personajes); contPer1++) {
            levantador1 = list_get(personajes, contPer1);

            //--marca a los que no estan bloqueados
            if (levantador1->blocked) {
                levantador1->marcado = false;
                cantBloq++;
            } else {
                levantador1->marcado = true;
                marcados++;
            }
        }

        for (; cantBloq >= 0; cantBloq--) { //(En el peor de los casos, tiene que asignar 2n-1 veces)
            //Por cada pj no marcado
            for (contPer1 = 0; contPer1 < list_size(personajes); contPer1++) {
                levantador1 = list_get(personajes, contPer1);
                if (!levantador1->marcado) {
                    //Si necesita un recurso de uno marcado
                    for (contPer2 = 0; contPer2 < list_size(personajes); contPer2++) {
                        levantador2 = list_get(personajes, contPer2);

                        if (levantador2->marcado && tieneLoQueNecesito(levantador2, levantador1)) {
                            log_trace(logger, "Marque a %c", levantador1->chirimbolo);
                            levantador1->marcado = true;
                            marcados++;
                            break;
                        }
                    }
                }
            }

        };

        //Estan en DeadLock los que no esten marcados
        for (contPer1 = 0; contPer1 < list_size(personajes); contPer1++) {
            levantador1 = list_get(personajes, contPer1);
            if (!levantador1->marcado) {
                list_add_new(bloqueados, levantador1, sizeof(personaje_t));
                log_trace(logger, "%c esta en Deadlock", levantador1->chirimbolo);
            }
        }

        //--Si la lista tiene más de 1 deadlockeados, se la mandamos al orquestador
        if ((list_size(bloqueados) > 1) && (parametros.recovery)) {
            //--Envía un header con la cantidad de personajes
            orq_t header;
            header.type = NIVEL;
            header.detail = HAYINTERBLOQUEO;
            header.port = list_size(bloqueados);

            if (send(parametros.numSock, &header, sizeof(header), 0) == -1) {
                log_error(logger, "Send: %s", strerror(errno));
                exit(EXIT_FAILURE);
            }
            log_trace(logger, "Header: cantidad: %d", list_size(bloqueados));

            //--Envía los personajes
            message_t message;
            personaje_t* levantadorBlk;
            while (list_size(bloqueados) != 0) {
                levantadorBlk = list_remove(bloqueados, 0);
                message.name = levantadorBlk->chirimbolo;

                if (send(parametros.numSock, &message, sizeof(message), 0) == -1) {
                    log_error(logger, "Send: %s", strerror(errno));
                    exit(EXIT_FAILURE);
                }

                log_trace(logger, "\tPersonaje: %c", message.name);
            }
            list_destroy_and_destroy_elements(bloqueados, free);
        }

        // Mandamos el proceso a dormir para que espere el tiempo definido por archivo de config.
        pthread_mutex_unlock(&semNiv);
        sleep(parametros.tiempoChequeo);
        log_trace(logger, ">>>Revisando DL<<<");
    }
}
int main(int argc, char* argv[]) {
    // Lo puse t0d0 en el llamado de abajo, no se porque y si se puede capturar 2 veces la señal como estaba hecho.
    // signal(SIGINT, notificarPersonajes);

    pthread_mutex_init(&semNiv, NULL);

    logger = logInit(argv, argv[1]);

    // Capturamos sigint y avisamos a los personajes para que cierren y cerramos el nivel.
    signal(SIGINT, cerrarForzado);

    t_config *configNivel;
    char** arrCaja;
    char* nom_nivel;
    char* ip_orq;
    char* port_orq;
    char* dir_orq;
    char ip[16];
    int puerto;

    //--Creamos el config
    configNivel = config_try_create(
                      //"nivel1.config" //Modo Debug
                      argv[1], "Nombre,orquestador,TiempoChequeoDeadlock,Recovery,ip,puerto,Caja1");

    ITEM_NIVEL *ListaItems = NULL;

    //--Creamos cada caja de recursos
    char* cajaAux;
    cajaAux = malloc(sizeof(char) * 6);
    sprintf(cajaAux, "Caja1");

    //--Inicializa la lista con los personajes y sus recursos
    personajes = list_create();
    personaje_t pjAux;

    int t = 1;
    int cols = 0;
    int rows = 0;
    int posXCaja = 0;
    int posYCaja = 0;
    nivel_gui_inicializar();
    // Conseguimos el area del nivel
    char state = nivel_gui_get_area_nivel(&cols, &rows);
    // Validamos que no haya habido error
    if (state != EXIT_SUCCESS) {
        cerrarNivel("Error al intentar conseguir el area del nivel (GUI).");
        exit(EXIT_FAILURE);
    }
    char* messageLimitErr;
    messageLimitErr = malloc(sizeof(char) * 100);

    //--Mientras pueda levantar el array
    while ((arrCaja = config_try_get_array_value(configNivel, cajaAux)) != NULL ) {
        posXCaja = atoi(arrCaja[3]);
        posYCaja = atoi(arrCaja[4]);
        // Validamos que la caja a crear esté dentro de los valores posibles del mapa
        if (posXCaja > rows || posYCaja > cols || posXCaja < 1 || posYCaja < 1) {
            sprintf(messageLimitErr, "La caja %c excede los limites de la pantalla. (%d,%d) - (%d,%d)", arrCaja[1][0], posXCaja, posYCaja, rows, cols);
            cerrarNivel(messageLimitErr);
            exit(EXIT_FAILURE);
        }
        // Si pasó la validacion, la creamos.
        CrearCaja(&ListaItems, arrCaja[1][0], atoi(arrCaja[3]), atoi(arrCaja[4]), atoi(arrCaja[2]));
        //--Rearma el cajaAux para la iteracion
        sprintf(cajaAux, "Caja%d", ++t);
    }

    free(cajaAux);

    //--Boludeces de los sockets
    message_t message;
    fd_set master, temp;
    struct sockaddr_in myAddress;
    struct sockaddr_in remoteAddress;
    int maxSock;
    int sockListener;
    int sockOrq;

    //--Saludo al orquestador

    //--Obetenemos el string del nombre y dirección del orquestador
    nom_nivel = config_get_string_value(configNivel, "Nombre");
    dir_orq = config_get_string_value(configNivel, "orquestador");
    puerto = config_get_int_value(configNivel, "puerto");
    memcpy(ip, config_get_string_value(configNivel, "ip"), 16);
    // Conseguimos el tiempo de espera de chequeo
    int tiempoChequeo = config_get_int_value(configNivel, "TiempoChequeoDeadlock");

    ip_orq = strtok(dir_orq, ":"); 	//--Separar ip
    port_orq = strtok(NULL, ":");	//--Separar puerto

    // Crear un socket:
    struct sockaddr_in socketInfo;
    if ((sockOrq = socket(AF_INET, SOCK_STREAM, 0)) != 0) {

        socketInfo.sin_family = AF_INET;
        socketInfo.sin_addr.s_addr = inet_addr(ip_orq);
        socketInfo.sin_port = htons(atoi(port_orq));

        // Conectar el socket con la direccion 'socketInfo'.
        if (connect(sockOrq, (struct sockaddr*) &socketInfo, sizeof(socketInfo)) == -1) {
            perror("Connect");
            exit(EXIT_FAILURE);
        }

        log_info(logger, "Conexión con orquestador.");

        orq_t orqMsj;
        orqMsj.type = NIVEL;
        orqMsj.detail = SALUDO;
        strcpy(orqMsj.name, nom_nivel);

        //memcpy(orqMsj.ip, &localhost->sin_addr.s_addr, 16);
        strcpy(orqMsj.ip, ip);
        orqMsj.port = puerto;

        //--Envía el "Saludo" para ser agregado
        if (send(sockOrq, &orqMsj, sizeof(orq_t), 0) == -1) {
            perror("Saludo");
            exit(EXIT_FAILURE);
        }
    }

    // Definimos los threads
    pthread_t thr_interbloqueos;
    paramInterbloqueo_t parametros;
    parametros.numSock = sockOrq;
    parametros.tiempoChequeo = tiempoChequeo;
    parametros.recovery = config_get_int_value(configNivel, "Recovery");

    // y los lanzamos
    if (pthread_create(&thr_interbloqueos, NULL, (void*) detectInterbloqueos, (void *) &parametros)) {
        log_error(logger, strerror(errno));
        exit(EXIT_FAILURE);
    }

    int maxRows, maxCols;
    int posX, posY;
    int posItemY, posItemX;
    int i;

    nivel_gui_get_area_nivel(&maxRows, &maxCols);

    nivel_gui_dibujar(ListaItems, nom_nivel);

    iniSocks(&master, &temp, &myAddress, remoteAddress, &maxSock, &sockListener, puerto, logger);
    while (1) {
        //--Gestiona un cliente ya conectado
        i = getSockChanged(&master, &temp, &maxSock, sockListener, &remoteAddress, &message, sizeof(message_t), logger);
        if (i != -1) {

            pthread_mutex_lock(&semNiv);

            int contPj;
            int contRec;
            char *auxRec;
            personaje_t *tempAux;
            //--Recibe mensaje y define comportamiento según el tipo
            switch (message.type) {
            case SALUDO:
                //--Agregamos personaje a la lista de items y a la de personajes/recursos
                CrearPersonaje(&ListaItems, i, message.name, INIX, INIY);
                pjAux.numSock = i;
                pjAux.chirimbolo = message.name;
                pjAux.blocked = false;
                pjAux.recursos = list_create();
                list_add_new(personajes, &pjAux, sizeof(personaje_t));

                //--Armamos la estrucura para enviar la posición inicial
                message.type = SALUDO;
                message.detail = INIX;
                message.detail2 = INIY;

                log_info(logger, "Se agregó el personaje %c con el socket %d", message.name, i);

                if (send(i, &message, sizeof(message), 0) == -1)
                    perror("Respuesta posición inicial");
                break;
            case POSICION:
                //--Obtiene posición del item pedido
                getPosRec(ListaItems, message.detail, &posX, &posY);

                //--Armamos la estrucura para enviar la posición del recurso pedido
                message.type = POSICION;
                message.detail = posX;
                message.detail2 = posY;

                if (send(i, &message, sizeof(message), 0) == -1)
                    perror("Respuesta posición recurso");
                break;
            case MOVIMIENTO:
                //--Devuelve las posiciones X e Y del item
                if (getPosPer(ListaItems, i, &posX, &posY) == -1)
                    perror("GetPosItem");

                switch (message.detail) {

                case ARRIBA:
                    if (posY > 1)
                        posY--;
                    break;

                case ABAJO:
                    if (posY < maxRows)
                        posY++;
                    break;

                case IZQUIERDA:
                    if (posX > 1)
                        posX--;
                    break;
                case DERECHA:
                    if (posX < maxCols)
                        posX++;
                    break;
                }

                //--Define confirmación y la devuelve
                message.type = MOVIMIENTO;
                message.detail2 = message.detail;
                message.detail = 1;
                if (send(i, &message, sizeof(message), 0) == -1)
                    perror("Confirmacion");

                //--Desbloquear en caso de que esté bloqueado
                for (contPj = 0; contPj < list_size(personajes); contPj++) {
                    tempAux = list_get(personajes, contPj);

                    if (tempAux->numSock == i && tempAux->blocked)
                        tempAux->blocked = false;
                }

                MoverPersonaje(ListaItems, i, posX, posY);
                break;
            case PEDIDO:
                //--Obtiene posición del item pedido y del personaje
                getPosRec(ListaItems, message.detail, &posItemX, &posItemY);
                getPosPer(ListaItems, i, &posX, &posY);

                //--Valida si llegó al recurso
                if ((posItemX == posX) && (posItemY == posY)) {

                    //-- Siempre le tiene que agregar a la lista de recursos, este o no bloqueado
                    //--Agrega el recurso a la lista de recursos del personaje
                    int contPj;
                    personaje_t* tempAux;
                    for (contPj = 0; contPj < list_size(personajes); contPj++) {
                        tempAux = list_get(personajes, contPj);

                        if (tempAux->numSock == i) {
                            list_add_new(tempAux->recursos, &(message.detail), sizeof(message.detail));
                            break;
                        }
                    }

                    //--Resta uno a la cantidad del item
                    int result = restarQuantityRec(ListaItems, message.detail);

                    if (result >= 0) {

                        log_info(logger, "A %d se le da el recurso %c", i, message.detail);

                        //--Si pudo restar la cantidad
                        tempAux->blocked = false;
                        //--Define confirmación y la devuelve
                        message.detail = 1;
                        if (send(i, &message, sizeof(message), 0) == -1)
                            perror("Confirmacion");

                    } else {
                        //--Si el recurso ya no tiene instacias
                        tempAux->blocked = true;

                        log_info(logger, "A %d se le niega el recurso %c", i, message.detail);
                        //--Define rechazo y lo devuelve
                        message.detail = 0;
                        if (send(i, &message, sizeof(message), 0) == -1)
                            perror("Confirmacion");
                    }
                } else {
                    log_error(logger, "Posicion erronea al pedir recurso");
                    exit(EXIT_FAILURE);
                }

                break;
            case SALIR:
                for (contPj = 0; contPj < list_size(personajes); contPj++) {
                    tempAux = list_get(personajes, contPj);

                    if (tempAux->numSock == i) {
                        //--Elimina y libera la lista de recursos de personaje

                        for (contRec = 0; contRec < list_size(tempAux->recursos); contRec++) {
                            auxRec = list_get(tempAux->recursos, contRec);
                            //--Suma la cantidad de recursos que el personaje libera
                            sumarQuantityRec(ListaItems, *auxRec, 1);
                        }

                        list_destroy_and_destroy_elements(tempAux->recursos, free);

                        //--Elimina y libera al personaje de la lista de personajes
                        list_remove_and_destroy_element(personajes, contPj, free);
                        BorrarPer(&ListaItems, i);
                        break;
                    }
                }

                log_debug(logger, "%d se desconectó", i);
                break;
            }
            nivel_gui_dibujar(ListaItems, nom_nivel);

            pthread_mutex_unlock(&semNiv);
        }

    }

    nivel_gui_terminar();
    return 0;
}
void* planificador(void* argumentos) {
	int q = 1; //En que parte del quantum esta
	int contIndex = 0;
	int proxPj = 0;

	nivel_t argu;
	memcpy(&argu, argumentos, sizeof(nivel_t));

	message_t mensaje;
	personaje_t pjAuxiliar; //--Este sirve para crear los personajes nuevos
	personaje_t* pjLevantador = malloc(sizeof(personaje_t)); //--Este sirve para levantar de la lista y usar

//--Boludeces de los sockets
	fd_set master, temp;
	struct sockaddr_in myAddress;
	struct sockaddr_in remoteAddress;
	int maxSock;
	int sockListener;
	int i, contPj;
	_Bool encontrado = false, pedirNoRequiereQuantum;

//para forzar el turno si se desbloquea

	iniSocks(&master, &temp, &myAddress, remoteAddress, &maxSock, &sockListener, argu.puertoPlan, logger);
	while (1) {
		i = getSockChanged(&master, &temp, &maxSock, sockListener, &remoteAddress, &mensaje, sizeof(mensaje), logger);
		if (i != -1) { //Conexcion que cambia
			pthread_mutex_lock(&semNiv);
			switch (mensaje.type) {
			case SALUDO:
				pjAuxiliar.name = mensaje.name;
				pjAuxiliar.sockID = i;
				pjAuxiliar.index = ++contIndex;
				pjAuxiliar.recursos = list_create(); //Arma la lista delos recursos

				list_add_new(argu.l_personajesRdy, &pjAuxiliar, sizeof(personaje_t));

				log_trace(logger, "Se agrego %c a la lista (%d)", mensaje.name, list_size(argu.l_personajesRdy));
				imprimirLista(argu.nombre, argu.l_personajesRdy, argu.l_personajesBlk, proxPj);

				if (list_size(argu.l_personajesRdy) == 1) {
					//--Mandar primer turno al primero

					mensaje.type = PERSONAJE;
					mensaje.detail = TURNO;

					if (send(pjAuxiliar.sockID, &mensaje, sizeof(message_t), 0) == -1) {
						log_error(logger, "send: %s", strerror(errno));
						exit(EXIT_FAILURE);
					}
				}

				break;
			case TURNO:
				pedirNoRequiereQuantum = true;
				if (mensaje.detail2 != NADA) {
					//--Agregar recurso pedido a su lista de recursos
					// (se lo agregamos aca, para saber poque recurso esta bloqueado, antes de mandarlo a la lista de bloqueados)
					list_add_new(pjLevantador->recursos, &(mensaje.detail2), sizeof(mensaje.detail2));
					pedirNoRequiereQuantum = false;

					if (mensaje.detail == BLOCK) { //Si volvió bloqueado, marcar personaje como bloqueado

						log_info(logger, "Personaje: %c esta bloquado por: %c", pjLevantador->name, mensaje.detail2);
						//-- Lo saca de listos, y lo pone en bloquados
						list_add(argu.l_personajesBlk, list_remove(argu.l_personajesRdy, proxPj));

						//Para que pase al otro PJ
						proxPj--;
						imprimirLista(argu.nombre, argu.l_personajesRdy, argu.l_personajesBlk, proxPj);

						q = Quantum + 1;
					}
					q--;
				}

				if (list_size(argu.l_personajesRdy) != 0) {

					//--Si ya terminó su quantum
					if (q >= Quantum) {
						proxPj++; //Solo avanza en la lista si se le acabo el Qauntum
						proxPj = abs(proxPj) % list_size(argu.l_personajesRdy);
						q = 1;
					} else {
						q++;
					}
					//--Cachear pj
					pjLevantador = list_get(argu.l_personajesRdy, proxPj);

					//--Si hay a quien enviarle el próximo turno

					mensaje.type = PERSONAJE;
					mensaje.detail = TURNO;

					if (pedirNoRequiereQuantum)
						usleep(delay);
					log_trace(logger, "Turno para %c", pjLevantador->name);
					if (send(pjLevantador->sockID, &mensaje, sizeof(message_t), 0) == -1) {
						log_error(logger, "send: %s", strerror(errno));
					}
				}
				break;
			case REINICIAR:
				mensaje.detail = DIEPOTATO;
				// Enviar mensaje de muerte al personaje, porque solicitó reiniciar.
				if (send(i, &mensaje, sizeof(mensaje), 0) == -1) {
					log_error(logger, "send: %s", strerror(errno));
					exit(EXIT_FAILURE);
				}
				break;
			case SALIR:
				encontrado = false;

				for (contPj = 0; contPj < list_size(argu.l_personajesBlk); contPj++) { //Cicla los personajes
					pjLevantador = list_get(argu.l_personajesBlk, contPj);
					if (pjLevantador->sockID == i) {
						encontrado = true; //Si lo encontras en Blk
						list_remove(argu.l_personajesBlk, contPj); //y sacarlo de la lista
						break;
					}
				}

				//Si no lo encuentra
				if (!encontrado) { //Si no lo encontras, buscarlo en rdy
					for (contPj = 0; contPj < list_size(argu.l_personajesRdy); contPj++) { //Cicla los personajes
						pjLevantador = list_get(argu.l_personajesRdy, contPj);
						if (pjLevantador->sockID == i) {
							list_remove(argu.l_personajesRdy, contPj); //y sacarlo de la lista
							break;
						}
					}
				}
				//Jamas deveria pasar que no lo encuentre

				int contRec;
				char* recurso;
				int j;
				personaje_t* pjLevantadorBlk = malloc(sizeof(personaje_t));
				//Si esta seteado "encontrado" es porque estaba bloqueado, entonces el ultimo recurso de la lista no es un recurso real.
				for (contRec = 0; contRec < list_size(pjLevantador->recursos) - (encontrado ? 1 : 0); contRec++) {
					recurso = list_get(pjLevantador->recursos, contRec);

					for (j = 0; j < list_size(argu.l_personajesBlk); j++) {
						//--Cicla los personajes bloqueados
						pjLevantadorBlk = list_get(argu.l_personajesBlk, j);
						//Si el ultimo recurso, es el que libera

						char* recursoLevantado = list_get(pjLevantadorBlk->recursos, list_size(pjLevantadorBlk->recursos) - 1);
						if (*recursoLevantado == *recurso) {
							log_trace(logger, "Se desbloqueo %c por %c recurso", pjLevantadorBlk->name, *recurso);
							//Desbloquear
							list_add(argu.l_personajesRdy, pjLevantadorBlk);
							list_remove(argu.l_personajesBlk, j);

							imprimirLista(argu.nombre, argu.l_personajesRdy, argu.l_personajesBlk, proxPj - 1);

							break;
						}
					}
				}

				//Limpia las cosas, porque se fue
				list_destroy_and_destroy_elements(pjLevantador->recursos, free);

				// forzar un mensaje de turno para volver a multiplexar
				if (list_size(argu.l_personajesRdy) > 0) {

					proxPj--;
					proxPj = abs(proxPj) % list_size(argu.l_personajesRdy);
					q = 1;

					imprimirLista(argu.nombre, argu.l_personajesRdy, argu.l_personajesBlk, proxPj);
					//--Cachear pj
					usleep(delay);
					mensaje.detail = TURNO;
					pjLevantador = list_get(argu.l_personajesRdy, proxPj);

					log_trace(logger, "Turno para %c", pjLevantador->name);
					if (send(pjLevantador->sockID, &mensaje, sizeof(message_t), 0) == -1) {
						log_error(logger, "send: %s", strerror(errno));
					}

				}

				if (mensaje.detail2 == FOSHIZZLE) {
					mensaje.detail2 = NADA;
					//Cuando un PJ termina tod0 su plan, se fija si hay otros PJs dando vueltas, o termina
					orqTerminoTodo(); //<-- Aca esta el execve
				}
				//End case SALIR
				break;
			}
			pthread_mutex_unlock(&semNiv);
		}
	}
	return NULL ;
}
void orquestador(void) {
	//Tirar hilos
	pthread_t threads[20]; //Solo 20 planificadores concurrentemente
	int cantidadHilos = 0; //Para que cuando sume empieze en 0;

	l_niveles = list_create();
	orq_t orqMsj;

	int lastPlan = PUERTO_PLAN;

	//--Boludeces de los sockets
	fd_set master, temp;
	struct sockaddr_in myAddress;
	struct sockaddr_in remoteAddress;
	int maxSock;
	int sockListener;
	int i;
	_Bool nivelEncontrado;

	iniSocks(&master, &temp, &myAddress, remoteAddress, &maxSock, &sockListener, PUERTO_ORQ, logger);
	while (1) {
		i = getSockChanged(&master, &temp, &maxSock, sockListener, &remoteAddress, &orqMsj, sizeof(orqMsj), logger);
		if (i != -1) { //Solo lo hace si el select esta levantando un socket que ya tenia. La primera vuelta sale con -700
			nivel_t nivel; // = (nivel_t*) malloc(sizeof(nivel_t));
			char* nombrePJ = malloc(sizeof(char));
			nivel_t* aux;
			int indList;
			int indListPers;

			pthread_mutex_lock(&semNiv);
			//--Switch según quien envió el mensaje
			switch (orqMsj.type) {
			case NIVEL:
				//--Switch según el tipo de mensaje
				switch (orqMsj.detail) {
				case SALUDO:

					//--Armar estructura nueva
					strcpy(nivel.ip, orqMsj.ip);
					strcpy(nivel.nombre, orqMsj.name);
					nivel.puerto = orqMsj.port;

					lastPlan = lastPlan + 15;
					nivel.puertoPlan = lastPlan;
					nivel.l_personajesRdy = list_create();
					nivel.l_personajesBlk = list_create();
					nivel.sock = i;

					list_add_new(l_niveles, (void*) &nivel, sizeof(nivel_t));

					log_trace(logger, "Se conectó el nivel: %s, IP: %s, Puerto: %d", orqMsj.name, orqMsj.ip, orqMsj.port);
					//Tira el nuevo hilo

					if (pthread_create(&threads[cantidadHilos++], NULL, planificador, (void *) &nivel)) { //-- Mandamos al hilo t0do el nivel
						log_error(logger, "pthread_create: %s", strerror(errno));
						exit(EXIT_FAILURE);
					}
					log_debug(logger, "Nuevo hilo de '%s' que atiende puerto: %d", orqMsj.name, lastPlan);

					break;
				case SALIR:
					for (indList = 0; indList < list_size(l_niveles); ++indList) { //Cicla en la lista niveles
						aux = (nivel_t*) list_get(l_niveles, indList);
						if (aux->sock == i) { //Cuando lo encuentra, la borra
							list_remove(l_niveles, indList);
							break;
						}
					}

					break;
					//----------------------------REGION CRITICA--------------------
				case HAYINTERBLOQUEO:
					log_trace(logger, "Llego mensaje de deadlock en nivel de socket %d", i);
					for (indList = 0; indList < list_size(l_niveles); ++indList) { //Cicla en la lista niveles
						aux = (nivel_t*) list_get(l_niveles, indList);
						if ((aux->sock == i) && (list_size(aux->l_personajesBlk) != 0)) { // Busca el nivel y si tiene algun personaje bloqueado

							message_t message;
							personaje_t *levantadorPJ;
							personaje_t victima;
							victima.index = 0;

							int contPjDLk, tope;
							tope = orqMsj.port;

							//--Ciclo que recibe todos los personajes del deadlock
							for (contPjDLk = 1; contPjDLk <= tope; contPjDLk++) {
								if (recv(i, &message, sizeof(message), 0) == -1) {
									log_error(logger, "Recv: %s", strerror(errno));
									exit(EXIT_FAILURE);
								}

								//--Buscar el personaje que nos mandaron
								int contPjBlk;
								for (contPjBlk = 0; contPjBlk < list_size(aux->l_personajesBlk); contPjBlk++) {
									levantadorPJ = list_get(aux->l_personajesBlk, contPjBlk);

									//--Si lo encuentra, sale del ciclo
									if (levantadorPJ->name == message.name)
										break;
								}
								//--Si el índice es mayor, setear nueva víctima
								if (victima.index < levantadorPJ->index)
									victima = *levantadorPJ;
							}

							log_info(logger, "\n>>>>>VICTIMA: %c\n", victima.name);
							message.detail = DIEPOTATO;
							//--Matar víctima
							if (send(victima.sockID, &message, sizeof(message), 0) == -1) {
								log_error(logger, "Send: %s", strerror(errno));
								exit(EXIT_FAILURE);
							}

							break;
						}
					}
					break;
					//****************REGION CRITICA*******************************
				}
				break;
			case PERSONAJE:
				//--Switch según el tipo de mensaje
				switch (orqMsj.detail) {
				case SALUDO:
					nivelEncontrado = false;
					//--Busca en la lista de niveles, el nivel pedido
					for (indList = 0; indList < list_size(l_niveles); ++indList) { //Cicla en la lista de niveles
						aux = (nivel_t*) list_get(l_niveles, indList);
						if (string_equals_ignore_case(aux->nombre, orqMsj.name)) {
							nivelEncontrado = true;
							log_trace(logger, "Se conectó el personaje: %c, Pide: %s", orqMsj.ip[0], orqMsj.name);

							//Cuando la encuentra, arma la estructura con la información del NIVEL y la envía.
							orqMsj.port = aux->puerto;
							strcpy(orqMsj.ip, aux->ip);

							if (send(i, &orqMsj, sizeof(orq_t), 0) == -1) {
								log_error(logger, "send: %s", strerror(errno));
								exit(EXIT_FAILURE);
							}

							//--Arma la estructura con la información del PLANIFICADOR de ese nivel y la envía

							//strcpy(orqMsj.ip, ipOrq);
							orqMsj.port = aux->puertoPlan;

							if (send(i, &orqMsj, sizeof(orq_t), 0) == -1) {
								log_error(logger, "send: %s", strerror(errno));
								exit(EXIT_FAILURE);
							}
							break;
						}
					}
					if (!nivelEncontrado) { //Si no encontro el nivel, decirselo
						orqMsj.detail = NADA;
						if (send(i, &orqMsj, sizeof(orq_t), 0) == -1) {
							log_error(logger, "send: %s", strerror(errno));
							exit(EXIT_FAILURE);
						}
					}
					break;
				case SALIR:
					//--Busca en la lista de niveles, el nivel pedido
					for (indList = 0; indList < list_size(l_niveles); ++indList) { //Cicla en la lista de niveles
						aux = (nivel_t*) list_get(l_niveles, indList);
						if (!strcmp(aux->nombre, orqMsj.name)) {
							for (indListPers = 0; indListPers < list_size(aux->l_personajesRdy); ++indListPers) { //--Busca al personaje en la lista del nivel.

								nombrePJ = list_get(aux->l_personajesRdy, indListPers);
								if (orqMsj.ip[0] == *nombrePJ)
									list_remove(aux->l_personajesRdy, indListPers);
								break;
							}
						}
					}
					break;
				}
				break;
			}
			pthread_mutex_unlock(&semNiv);
		}
	}
}