#GAME OF LIFE
import os
import copy
import pygame
import module_button
#Display
#------
#Colors
#------
BLACK = (0, 0, 0)
GREY=(50,50,50)
WHITE = (255, 255, 255)
BLUE=(127,255,212)
#--------------
#Box Dimensions
#--------------
WIDTH = 9
HEIGHT = 9
MARGIN = 1
#-----------------
#Button Dimensions
#-----------------
B_MARGIN=2
B_WIDTH=60
B_HEIGHT=18
#------------------------------------------------------
#To read the design names present in the designs folder
#------------------------------------------------------
names = []
# r=root, d=directories, f = files
for r, d, f in os.walk('design\\'):
	for file in f:
		if '.txt' in file:
			names.append(file.split('.')[0])

button={}
b_color=[]
T=0
pygame.init()
WINDOW_SIZE = [501, 542]
#------------------
#Loading the assets
#------------------
logo=pygame.image.load(".\logo.png")
start=pygame.image.load(".\start.png")
info=pygame.image.load(".\info.png")
winlogo=pygame.image.load(".\winlogo.png")
cover=pygame.image.load(".\cover.png")

screen = pygame.display.set_mode(WINDOW_SIZE)
pygame.display.set_caption("GameOfLife")
pygame.display.set_icon(winlogo)
clock = pygame.time.Clock()
#-----
#Fonts
#-----
font1 = pygame.font.SysFont('freesansbold.ttf', 20)
font2 = pygame.font.SysFont('freesansbold.ttf', 16)
#---------
#FUNCTIONS
#---------

infinite_grid=False
fps=60
#m is the main matrix
m=[]
#new_m is the temporary matrix
new_m=[]
#extra_size is not visible to user
extra_size=10
grid_size=50
n=grid_size+2*extra_size
#--------------------------------------------------------------------
#Function to get the position of the box over which mouse is hovering
#--------------------------------------------------------------------
def m_coordinate():
	return pygame.mouse.get_pos()[0] // (WIDTH + MARGIN)+extra_size, pygame.mouse.get_pos()[1] // (HEIGHT + MARGIN)
#-----------------------
#Function to render text
#-----------------------
def textfunc(text,textcolour, coordinate):
	textsurface=font2.render(text, True, textcolour)
	textrect=textsurface.get_rect()
	textrect.center=(coordinate[0]+B_WIDTH/2,coordinate[1]+B_HEIGHT/2)
	screen.blit(textsurface,textrect)
#--------------------------
#Function to reset the grid
#--------------------------
def reset_game():
	global fps, new_m, m, BLACK, WHITE, infinite_grid, b_color,T
	BLACK = (0, 0, 0)
	WHITE = (255, 255, 255)
	fps=60
	T=0
	infinite_grid=False
	m=[]
	new_m=[]
	b_color=[WHITE]*len(names)
	for n_rows in range(n):
		row_temp=[]
		for n_col in range(n):
			row_temp.append(0)
		m.append(row_temp)

	new_m=copy.deepcopy(m)
	screen.fill(WHITE)
	screen.blit(cover,(0,200))
	pygame.display.flip()
	pygame.time.delay(1000)

reset_game()
#----------------------------
#Function to display the grid
#----------------------------
def display(l):
	#l refers to the matrix
	global fps, n, m, button, button_grid, button_info, b_color, T
	screen.fill(GREY)
	screen.blit(logo,(0,0))

	for row in range(7,grid_size):
		for column in range(extra_size,grid_size+extra_size):
			color = BLACK
			if l[row][column] == 1:
				color = WHITE
			elif l[row][column] == 2:
				color = BLUE
			pygame.draw.rect(screen,color,[(MARGIN + WIDTH)*(column-extra_size)+MARGIN,(MARGIN + HEIGHT)*row+MARGIN,WIDTH,HEIGHT])

	#fps bar
	text = font1.render("fps", True, (0,0,0))
	fps_bar_back=pygame.rect.Rect(434,53,64,10)
	fps_bar=pygame.rect.Rect(436,55,fps,6)
	pygame.draw.rect(screen, (0,0,0) ,fps_bar_back)
	pygame.draw.rect(screen, BLUE ,fps_bar)
	screen.blit(text,(411,52))
	#Manual input of position
	textT = font1.render("T:"+str(T), True, (0,0,0))
	screen.blit(textT,(360,52))
	for i in range(len(names)):
		if i<=7:
			coord=((B_MARGIN + B_WIDTH)* i + B_MARGIN*1,500 + B_MARGIN*1)
		else:
			coord=((B_MARGIN + B_WIDTH)* (i-8) + B_MARGIN*1,500 + B_HEIGHT + B_MARGIN*2)
		button[names[i]]=pygame.rect.Rect(coord[0],coord[1],B_WIDTH,B_HEIGHT)
		pygame.draw.rect(screen, b_color[i] ,button[names[i]])
		textfunc(names[i],BLACK,coord)

	#Grid_Button
	coord=((B_MARGIN + B_WIDTH)* 7 + B_MARGIN*1,520 + B_MARGIN*1)
	button_grid=pygame.rect.Rect(coord[0],coord[1],B_WIDTH,B_HEIGHT)
	pygame.draw.rect(screen, WHITE ,button_grid)
	textfunc('GRID',BLACK,coord)

	#Info_Button
	coord=(485,40)
	button_info=pygame.rect.Rect(coord[0],coord[1],10,10)
	pygame.draw.rect(screen, (0,0,0) ,button_info)
	textsurface=font2.render('i', True, (255,255,255))
	textrect=textsurface.get_rect()
	textrect.center=(coord[0]+4,coord[1]+6)
	screen.blit(textsurface,textrect)

	if fps<=0.5:
		fps+=1
	if fps>60:
		fps=60
	clock.tick(fps)
	pygame.display.flip()
	b_color=[WHITE]*len(names)
#------------------------------------------
#Function to check the neighbours of a cell
#------------------------------------------
#xth row and yth column
def check_n(x,y):
	global m
	global new_m
	sum_n=0
	try:
		sum_n=m[x-1][y]+m[(x+1)%n][y]+m[x][(y+1)%n]+m[x][y-1]+m[x-1][y-1]+m[x-1][(y+1)%n]+m[(x+1)%n][y-1]+m[(x+1)%n][(y+1)%n]
	except:
		pass
	if sum_n<2:
		new_m[x][y]=0
	elif sum_n==2 and m[x][y]:
		pass
	elif sum_n==3:
		new_m[x][y]=1
	else:
		new_m[x][y]=0
#----------------------------------
#Function to simulate infinite grid
#----------------------------------
def infinite_func():
	global new_m

	if sum(new_m[grid_size-1]+new_m[grid_size-2])==0 and infinite_grid:
		for i in range(extra_size*2):
			new_m[grid_size+i]=[0]*n
	if sum(new_m[7]+new_m[8])==0 and infinite_grid:
		for i in range(7):
			new_m[i]=[0]*n
	for i in range(7,7+grid_size):
		if new_m[i][extra_size]==0 and new_m[i][extra_size+1]==0:
			pass
		else:
			break
	else:
		for i in range(7,7+grid_size):
			for j in range(extra_size):
				new_m[i][j]=0
	for i in range(7,7+grid_size):
		if new_m[i][grid_size+extra_size-2]==0 and new_m[i][grid_size+extra_size-1]==0:
			pass
		else:
			break
	else:
		for i in range(7,7+grid_size):
			for j in range(grid_size+extra_size,n):
				new_m[i][j]=0
#------------------------------------------------------------------------------------------------------------------
#Function which when given a tuple of coordinates assigns a suitable value to the corresponding positions of matrix
#------------------------------------------------------------------------------------------------------------------
def preset(tupl,l,n=1):
	for i in tupl:
		l[i[0]][i[1]]=n
#--------------------------------------------------------------------------------
#Function which handles the event btw clicking on a button & clicking on the grid
#--------------------------------------------------------------------------------
def button_click(desn,file_name):
	global m, new_m,inv
	hover=True
	inv=[False,False,False]
	#inverse=(x_inv, y_inv, rot_inv)
	while hover:
		for event in pygame.event.get():
			new_m=copy.deepcopy(m)
			x,y=m_coordinate()

			try:
				#new_m is a temporary matrix
				preset(desn(file_name,x,y,inverse=inv),new_m,2)
				display(new_m)
			except:
				pass
			if event.type == pygame.MOUSEBUTTONDOWN:
				if event.button==1:
					x,y=m_coordinate()
					preset(desn(file_name,x,y,inverse=inv),m)
					inv=[False,False, False]
					hover=False
			elif event.type== pygame.KEYDOWN:
					if event.key== pygame.K_ESCAPE:
						hover=False
						break
					if event.key== pygame.K_RIGHT:
						inv[2]= not(inv[2])
					if event.key== pygame.K_LEFT:
						inv[0]= not(inv[0])
					if event.key== pygame.K_UP:
						inv[1]= False
					if event.key== pygame.K_DOWN:
						inv[1]= True
#-------------
#main function
#-------------
def main():
	global m, fps, n,new_m, WIDTH, HEIGHT, MARGIN, infinite_grid, WHITE, BLACK,T
	display(m)

	#Allowing the user to fill in the grid
	running=True
	while running:
		for event in pygame.event.get():
			if event.type==pygame.QUIT:
				running=False
				quit()
			elif event.type == pygame.KEYDOWN:
				if event.key== pygame.K_RETURN:
					running=False
				if event.key== pygame.K_q:
					infinite_grid=True
					pass
			elif event.type == pygame.MOUSEBUTTONDOWN:
				if event.button==1:
					column,row=m_coordinate()
					if row<grid_size:
						m[row][column] = 1

					elif button_grid.collidepoint(event.pos):
						MARGIN=1-MARGIN
						if WIDTH==9:
							WIDTH+=1
							HEIGHT+=1
						else:
							WIDTH-=1
							HEIGHT-=1
					if button_info.collidepoint(event.pos):
						screen.fill(WHITE)
						screen.blit(info,(0,0))
						pygame.display.flip()
						pygame.time.delay(3000)

					for i in range(len(names)):
						if button[names[i]].collidepoint(event.pos):
							button_click(module_button.new_button,names[i])
			display(m)
			for i in range(len(names)):
						if button[names[i]].collidepoint(pygame.mouse.get_pos()):
							b_color[i]=BLUE
						else:
							b_color[i]=WHITE

	#Running the GOL Algorithm on the given grid
	running=True
	fps=5
	while running:
		T+=1
		new_m=copy.deepcopy(m)
		for i in range(n):
			if 1 not in m[i-1]+m[i]+m[(i+1)%n]:
					continue
			for j in range(n):
				check_n(i,j)
		if infinite_grid:
			infinite_func()
		m=new_m
		display(m)

		keystate = pygame.key.get_pressed()
		if keystate[pygame.K_RIGHT]:
			fps+=0.5
		if keystate[pygame.K_LEFT]:
			fps-=0.5

		for event in pygame.event.get():
			if event.type==pygame.QUIT:
				running=False

			elif event.type == pygame.KEYDOWN:
				if event.key == pygame.K_UP:
					fps=30
				elif event.key == pygame.K_DOWN:
					fps=5
				elif event.key == pygame.K_ESCAPE:
					reset_game()
					main()
				elif event.key == pygame.K_c:
					if BLACK[0]>WHITE[0]:
						change=5
					else:
						change=-5
					old_fps=fps
					fps=60
					for i in range (51):
						BLACK = ((BLACK[0]-change),)*3
						WHITE = ((WHITE[0]+change),)*3
						display(m)
					fps=old_fps

			elif event.type == pygame.MOUSEBUTTONDOWN:
				if event.button==1:
					if button_grid.collidepoint(event.pos):
						MARGIN=1-MARGIN
						if WIDTH==9:
							WIDTH+=1
							HEIGHT+=1
						else:
							WIDTH-=1
							HEIGHT-=1
					elif button_info.collidepoint(event.pos):
						screen.fill(WHITE)
						screen.blit(info,(0,0))
						pygame.display.flip()
						pygame.time.delay(3000)

#Intro screen
screen.fill(WHITE)
screen.blit(start,(0,0))
pygame.time.delay(2600)
pygame.display.flip()

running=True
while running:
	for event in pygame.event.get():
		if event.type == pygame.KEYDOWN:
			if event.key== pygame.K_RETURN:
				running=False
		elif event.type==pygame.QUIT:
			running=False
			quit()
#Running the main function
main()


def sortByHeight(a):
    temp = []
    length = len(a) - 1
    i = 0
    dict = {}

    while i <= length:
        if a[i] < 0:
            dict[i] = a[i]
        else:
            temp.append(a[i])
        i += 1

    temp.sort()

    result = []

    for k in range(len(a)):
        if k in dict:
            result.append(dict[k])
        else:
            result.append(temp.pop(0))

    return result


#import iso_handling
#import pal5_mock_ps
import scipy
import scipy.signal
import csv

labels=['CFHT','LSST 1-year','LSST 10-year','WFIRST']
colors=['seagreen','firebrick', 'slateblue', 'darkorange']

###################
# Start with CDM-like
dire = '/Users/hendel/projects/streamgaps/streampepper/'

xi_wfirst = scipy.genfromtxt(dire+'csd_13323_5-9_003bg.dat', delimiter=',', loose=True, invalid_raise=False,skip_header=1)
xi_cfht =   scipy.genfromtxt(dire+'csd_3200_5-9_013bg.dat',  delimiter=',', loose=True, invalid_raise=False,skip_header=1)
xi_lsst =   scipy.genfromtxt(dire+'csd_5318_5-9_005bg.dat',  delimiter=',', loose=True, invalid_raise=False,skip_header=1)
xi_lsst10 = scipy.genfromtxt(dire+'csd_7101_5-9_004bg.dat',  delimiter=',', loose=True, invalid_raise=False,skip_header=1)

ratearrs = [xi_cfht[:,0],xi_lsst[:,0],xi_lsst10[:,0],xi_wfirst[:,0]]
dataarrs = [xi_cfht[:,1:],xi_lsst[:,1:],xi_lsst10[:,1:],xi_wfirst[:,1:]]

#for rate in [-1.5,1]
def kde_epanechnikov(x,h,ydata):
	"""ydata= ln[(1+xdata)/(1-xdata)]"""
	h= numpy.ones_like(x)*h
	h[x < -1.]= h[x < -1.]*(-1.*(x[x < -1.]+1.)+1.) # use slightly wider kernel at small values
	y= numpy.log((1.35+(x+.25))/(1.35-(x+.25)))
	#r= numpy.fabs(numpy.tile(y,(len(ydata),1)).T-ydata)/h
	r= numpy.fabs(numpy.tile(y,(len(ydata),1)).T-ydata)/numpy.tile(h,(len(ydata),1)).T
	r[r > 1.]= 1. # Gets around multi-D slicing
	return numpy.sum(0.75*(1.-r**2.),axis=1)/h*(1./(1.35+(x+.25))+1./(1.35-(x+.25)))

def upper_limit(xxs, kdey_full):
	cp= np.cumsum(kdey_full)/numpy.sum(kdey_full)
	cp = cp+(.000001*(np.arange(len(kdey_full))))
	uplim_95= scipy.interpolate.InterpolatedUnivariateSpline(cp,xxs,k=1)(0.95)
	return uplim_95

def credible_interval(xxs, kdey_full, frac=.68):
	# Get peak and 68% around the peak
	kdey_full = kdey_full + (.000001*np.flip(np.arange(len(xxs))))
	bf= xxs[numpy.argmax(kdey_full)]
	if np.sum(kdey_full[((xxs<bf)&(xxs>(np.min(xxs)+.05)))]<(.5*numpy.max(kdey_full)))==0:
		raise NameError('Not two-sided enough')
	sindx= numpy.argsort(-kdey_full) # minus reverses sort
	cp= numpy.cumsum((kdey_full/numpy.sum(kdey_full))[sindx])
	m= xxs[sindx][cp > frac]
	uplim= numpy.amin(m[m > bf])
	lowlim= numpy.amax(m[m < bf])
	return lowlim, bf, uplim

def compute_abc(data, dataarr, rates, eps=5., deps=.85, faccept=.05):
	sindx= (np.abs(dataarr[:,1]-data[1]) < eps)*(np.abs(dataarr[:,2]-data[2]) < eps)*(np.abs(dataarr[:,3]-data[3]) < (eps))\
							*(np.abs(dataarr[:,4]-data[4]) < (eps))#*(np.abs(d[:,5]-data[4]) < eps)
	while sum(sindx) > len(dataarr)*faccept:
		eps=eps*deps
		#print mod, eps, teps, sum(sindx)
		sindx= (np.abs(dataarr[:,1]-data[1]) < eps)*(np.abs(dataarr[:,2]-data[2]) < eps)*(np.abs(dataarr[:,3]-data[3]) < (eps))\
								*(np.abs(dataarr[:,4]-data[4]) < (eps))#*(np.abs(d[:,5]-data[4]) < eps)
	scale=1.
	kernel_width=.25
	rate_full= rates[sindx]
	#print len(rate_full)
	xxs= numpy.linspace(-1.5,1.,151)
	#kdey_full= kde_epanechnikov(xxs,kernel_width,numpy.log((1.6+rate_full)/(1.6-rate_full)))\
	kdey_full= kde_epanechnikov(xxs,kernel_width,numpy.log((1.35+(rate_full+.25))/(1.35-(rate_full+.25))))\
		+numpy.random.uniform(size=len(xxs))*0.000001
	kdey_full/= numpy.sum(kdey_full)*(xxs[1]-xxs[0])
	return xxs, kdey_full

def compute_twostream_abc(data1, data2, dataarr, rates, eps=5., deps=.85, faccept=.05):
	sindx1= (np.abs(dataarr[:,1]-data1[1]) < eps)*(np.abs(dataarr[:,2]-data1[2]) < eps)*(np.abs(dataarr[:,3]-data1[3]) < (eps))\
							*(np.abs(dataarr[:,4]-data1[4]) < (eps))#*(np.abs(d[:,5]-data[4]) < eps)
	sindx2= (np.abs(dataarr[:,1]-data2[1]) < eps)*(np.abs(dataarr[:,2]-data2[2]) < eps)*(np.abs(dataarr[:,3]-data2[3]) < (eps))\
							*(np.abs(dataarr[:,4]-data2[4]) < (eps))#*(np.abs(d[:,5]-data[4]) < eps)
	sindx=(sindx1&sindx2)
	while sum(sindx) > len(dataarr)*faccept:
		eps=eps*deps
		#print mod, eps, teps, sum(sindx)
		sindx1= (np.abs(dataarr[:,1]-data1[1]) < eps)*(np.abs(dataarr[:,2]-data1[2]) < eps)*(np.abs(dataarr[:,3]-data1[3]) < (eps))\
								*(np.abs(dataarr[:,4]-data1[4]) < (eps))#*(np.abs(d[:,5]-data[4]) < eps)
		sindx2= (np.abs(dataarr[:,1]-data2[1]) < eps)*(np.abs(dataarr[:,2]-data2[2]) < eps)*(np.abs(dataarr[:,3]-data2[3]) < (eps))\
								*(np.abs(dataarr[:,4]-data2[4]) < (eps))#*(np.abs(d[:,5]-data[4]) < eps)
		sindx=(sindx1&sindx2)
	scale=1.
	kernel_width=.25
	rate_full= rates[sindx]
	#print len(rate_full)
	xxs= numpy.linspace(-1.5,1.,151)
	kdey_full= kde_epanechnikov(xxs,kernel_width,numpy.log((1.35+(rate_full+.25))/(1.35-(rate_full+.25))))\
		+numpy.random.uniform(size=len(xxs))*0.000001
	kdey_full/= numpy.sum(kdey_full)*(xxs[1]-xxs[0])
	return xxs, kdey_full

def ecdf(data):
    xp = np.sort(data)
    yp = np.arange(1, len(data)+1) / len(data)
    def ecdf_instance(x):
        return np.interp(x, xp, yp, left=0, right=1)
    return ecdf_instance

########################################################################################################################
########################################################################################################################
########################################################################################################################
########################################################################################################################
########################################################################################################################
########################################################################################################################
#Power spectra
bins=np.linspace(0,15,151)
centroids = (bins[1:] + bins[:-1]) / 2.
px, py= scipy.signal.csd(np.ones(151),np.ones(151), fs=1./(centroids[1]-centroids[0]),scaling='spectrum',nperseg=len(centroids))
px= 1./px

plt.figure(figsize=(9,4))
#Compare CDM-like and much lower
plt.subplot(121)
for i, d in enumerate(dataarrs):
	plt.loglog(px,np.nanmedian(d[(ratearrs[i]> -.02)&(ratearrs[i]<.02)],axis=0), color = colors[i], label = labels[i])
	plt.fill_between(px, np.nanpercentile(d[(ratearrs[i]> -.02)&(ratearrs[i]<.02)], (25), axis=0),  y2= np.nanpercentile(d[(ratearrs[i]> -.02)&(ratearrs[i]<.02)], (75), axis=0), color=colors[i], alpha=0.2)
plt.legend(loc='upper left')
plt.title('CDM rate ')
plt.xlabel(r'$k_{\xi}$ [deg]')#plt.xlabel('Scale [deg]')
plt.ylabel(r'$\sqrt{P_{\delta\delta}(k_{\xi})}$')#plt.ylabel('Power')
plt.ylim(0.05,0.8)

plt.subplot(122)
for i, d in enumerate(dataarrs):
	plt.loglog(px,np.nanmedian(d[(ratearrs[i]> -.42)&(ratearrs[i]<-.38)],axis=0), color = colors[i], label = labels[i])
	plt.fill_between(px, np.nanpercentile(d[(ratearrs[i]> -.42)&(ratearrs[i]<-.38)], (25), axis=0),  y2= np.nanpercentile(d[(ratearrs[i]> -.42)&(ratearrs[i]<-.38)], (75), axis=0), color=colors[i], alpha=0.2)
plt.legend(loc='upper left')
plt.title('0.4x CDM rate ')
plt.xlabel(r'$k_{\xi}$ [deg]')#plt.xlabel('Scale [deg]')
plt.ylabel(r'$\sqrt{P_{\delta\delta}(k_{\xi})}$')#plt.ylabel('Power')
plt.ylim(0.05,0.8)

plt.savefig('/Users/hendel/projects/streamgaps/streampepper/paper_figures/ps_vs_rate_comparison.png',dpi=300,bbox_inches='tight')

########################################################################################################################
########################################################################################################################
########################################################################################################################
########################################################################################################################
########################################################################################################################
########################################################################################################################
#Constraints by survey

#single stream PDFs
csvabc= open(dire+'5-9_constraints_onestream.csv','w')
abcwriter= csv.writer(csvabc, delimiter=',')
for n in np.arange(10000)*10:
	for i, dataarr in enumerate(dataarrs):
		data = dataarr[n]
		xxs, kdey_full = compute_abc(data, dataarr, ratearrs[i])
		#plt.plot(xxs,kdey_full,label=labels[i],color=colors[i])#,'-',lw=3.,color=color,zorder=zorder,overplot=overplot)

		try:
			lowlim, bf, uplim = credible_interval(xxs, kdey_full)
			#print(labels[i]+': constrained, %1.3f, [%1.3f, %1.3f], %r'%(bf, lowlim, uplim, ((d[n,0]<uplim)&(d[n,0]>lowlim))))
			abcwriter.writerow(list(['constrained', format(ratearrs[i][n],'.4f'), format(bf,'.4f'), format(lowlim,'.4f'), format(uplim,'.4f'), ((ratearrs[i][n]<uplim)&(ratearrs[i][n]>lowlim))]))
			csvabc.flush()
		except:
			uplim_95 = upper_limit(xxs, kdey_full)
			#print(labels[i]+': upper limit, <%1.3f, %r'%(uplim_95, ((d[n,0]<uplim_95))))
			abcwriter.writerow(list(['upperlimit', format(ratearrs[i][n],'.4f'), '0', '0', format(uplim_95,'.4f'),((ratearrs[i][n]<uplim_95))]))
			csvabc.flush()

csvabc.close()

####save double stream PDFs
csvabc= open(dire+'5-9_constraints_twostream.csv','w')
abcwriter= csv.writer(csvabc,delimiter=',')
for n in np.arange(1000)*10:
	nrate, noff = np.divmod(n,10)
	for i, dataarr in enumerate(dataarrs):
		rates = ratearrs[i]
		ratesort = np.argsort(rates)
		unsort = np.argsort(ratesort)
		data1 = dataarr[n]
		data2 = dataarr[(ratesort[np.searchsorted(rates[ratesort],rates[nrate],side='right')])+noff]
		xxs, kdey_full = compute_twostream_abc(data1, data2, dataarr, ratearrs[i])

		try:
			lowlim, bf, uplim = credible_interval(xxs, kdey_full)
			#print(labels[i]+': constrained, %1.3f, [%1.3f, %1.3f], %r'%(bf, lowlim, uplim, ((d[n,0]<uplim)&(d[n,0]>lowlim))))
			abcwriter.writerow(list(['constrained', format(ratearrs[i][n],'.4f'), format(bf,'.4f'), format(lowlim,'.4f'), format(uplim,'.4f'), ((ratearrs[i][n]<uplim)&(ratearrs[i][n]>lowlim))]))
			csvabc.flush()
		except:
			uplim_95 = upper_limit(xxs, kdey_full)
			#print(labels[i]+': upper limit, <%1.3f, %r'%(uplim_95, ((d[n,0]<uplim_95))))
			abcwriter.writerow(list(['upperlimit', format(ratearrs[i][n],'.4f'), '0', '0', format(uplim_95,'.4f'),((ratearrs[i][n]<uplim_95))]))
			csvabc.flush()

csvabc.close()

########################################
########################################
########################################
####Pal5 ABC plots

onestream_types =                       	scipy.genfromtxt(dire+'5-9_constraints_onestream.csv', unpack=True, delimiter=',', comments=None, usecols=(0), dtype=None)
onestream_types =							onestream_types.astype('str')
onestream_tf =                           	scipy.genfromtxt(dire+'5-9_constraints_onestream.csv', unpack=True, delimiter=',', comments=None, usecols=(5), dtype=None)
onestream_rates, onestream_maxs, onestream_lowlims, onestream_uplims = 	scipy.genfromtxt(dire+'5-9_constraints_onestream.csv', unpack=True, delimiter=',', comments=None, usecols=(1,2,3,4))

####Scatter true vs infered
plt.figure(figsize=(4,4))
plt.subplot(111,aspect='equal')
for i, dataarr in enumerate([xi_cfht[:,1:],xi_lsst[:,1:],xi_lsst10[:,1:],xi_wfirst[:,1:]]):
	plt.scatter(onestream_rates[i::4][onestream_types[i::4]=='constrained'], onestream_maxs[i::4][onestream_types[i::4]=='constrained'],
		s=3, color = colors[i], label = labels[i], alpha = .3)
	#plt.errorbar(onestream_rates[i::4][onestream_types[i::4]=='upperlimit'],  onestream_uplims[i::4][onestream_types[i::4]=='upperlimit'],
	#	uplims=True, yerr=.03, linestyle='none', marker=None, color = colors[i], alpha =0.3)
plt.legend(loc='upper left')
plt.plot([-1.5,1],[-1.5,1],c='k', lw=2)
plt.xlabel('True rate')
plt.ylabel('Inferred rate')
plt.title('One stream - Pal5')
for i, label in enumerate(labels):
	s_res = np.sqrt(np.sum((onestream_rates[i::4][onestream_types[i::4]=='constrained']- onestream_maxs[i::4][onestream_types[i::4]=='constrained'])**2)/(sum(onestream_types[i::4]=='constrained')-2))
	plt.text(1,-1.4+.1*i, label+' residual standard deviation = %1.2f dex'%(s_res), horizontalalignment='right', verticalalignment='center')
plt.savefig('/Users/hendel/projects/streamgaps/streampepper/paper_figures/onestream_accuracy.png',dpi=300,bbox_inches='tight')

####Histograms of constrained vs upper limits

rates = onestream_rates
types = onestream_types
tf = onestream_tf
plt.figure(figsize=(9,5))
ratebins = np.linspace(-1.5,1,25)
for i in np.arange(4):
	plt.subplot(2,2,i+1)
	h, be = np.histogram(rates, bins=ratebins)
	plt.hist(rates[i::4][(types[i::4]=='upperlimit' )&(tf[i::4]==True)], bins=ratebins, histtype='step', color=colors[i], label=(labels[i]+' limit'), lw=2,linestyle=':', cumulative=False)
	plt.hist(rates[i::4][(types[i::4]=='constrained')&(tf[i::4]==True)], bins=ratebins, histtype='step', color=colors[i], label=(labels[i]+' constraint'), lw=2, cumulative=False)
	#plt.hist(rates[i::4], weights=(.5*np.ones(len(rates[i::4]))), bins=ratebins, histtype='step', color='k', label=(labels[i]+' 50\%'), lw=1, cumulative=False)
	plt.hist(rates[i::4][tf[i::4]==False], bins=ratebins, histtype='step', color='r', label=(labels[i]+' error'), lw=1, cumulative=False)

	plt.legend(fontsize=8)
	if i in [2,3]:plt.xlabel('True impact rate')
	if i in [0,2]:plt.ylabel('Number of streams')
	plt.ylim(0,250)
plt.savefig('/Users/hendel/projects/streamgaps/streampepper/paper_figures/onestream_constraint.png',dpi=300,bbox_inches='tight')

####Determine where 50% are constrained
plt.figure(figsize=(4,4))
for i in np.arange(4):
	cnecdf = diff(ecdf(rates[i::4][(types[i::4]=='constrained' )&(tf[i::4]==True)])(np.linspace(-1.5,1.,51)))
	ulecdf = diff(ecdf(rates[i::4][(types[i::4]=='upperlimit' )&(tf[i::4]==True)])(np.linspace(-1.5,1.,51)))
	plt.plot(np.linspace(-1.5,1.,50),cnecdf/(ulecdf+cnecdf), lw=2, label=labels[i]+' %1.2f'%(min(np.linspace(-1.5,1.,50)[cnecdf/(ulecdf+cnecdf)>.5])) ,color = colors[i])
plt.legend()
plt.plot([-1.5,1],[.5,.5],c='k',linestyle=':')
plt.xlim(-1.5,1)
plt.xlabel('True impact rate')
plt.ylabel('Fraction constrained')
plt.savefig('/Users/hendel/projects/streamgaps/streampepper/paper_figures/onestream_expectedconstraint.png',dpi=300,bbox_inches='tight')

########### for 2 pal5s if interested
twostream_types =                       	scipy.genfromtxt(dire+'5-9_constraints_twostream.csv', unpack=True, delimiter=',', comments=None, usecols=(0), dtype=None)
twostream_types =							twostream_types.astype('str')
twostream_tf =                           	scipy.genfromtxt(dire+'5-9_constraints_twostream.csv', unpack=True, delimiter=',', comments=None, usecols=(5), dtype=None)
twostream_rates, twostream_maxs, twostream_lowlims, twostream_uplims = 	scipy.genfromtxt(dire+'5-9_constraints_twostream.csv', unpack=True, delimiter=',', comments=None, usecols=(1,2,3,4))

plt.subplot(122,aspect='equal')
#plt.subplot(111,aspect='equal')
for i, dataarr in enumerate([xi_cfht[:,1:],xi_lsst[:,1:],xi_lsst10[:,1:],xi_wfirst[:,1:]]):
	plt.scatter (twostream_rates[i::4][twostream_types[i::4]=='constrained'], twostream_maxs[i::4][twostream_types[i::4]=='constrained'],
		s=3, color = colors[i], label = labels[i])
	#plt.errorbar(twostream_rates[i::4][twostream_types[i::4]=='upperlimit'],  twostream_uplims[i::4][twostream_types[i::4]=='upperlimit'],
	#	uplims=True, yerr=.03, linestyle='none', marker=None, color = colors[i], alpha =0.3)
plt.legend()
plt.plot([-1.5,1],[-1.5,1],c='k', lw=2)
plt.xlabel('True rate')
plt.ylabel('Inferred rate')
plt.title('Two stream - Two Pal5s')


import webbrowser

from PySide6 import QtCore, QtWidgets

from mapclientplugins.sparccurationhelperstep.ui_sparccurationhelperwidget import Ui_SparcCurationHelperWidget
from sparc.curation.tools.utilities import convert_to_bytes
from sparc.curation.tools.ondisk import OnDiskFiles

class SparcCurationHelperWidget(QtWidgets.QWidget):

    def __init__(self, parent=None):
        super(SparcCurationHelperWidget, self).__init__(parent)
        self._ui = Ui_SparcCurationHelperWidget()
        self._ui.setupUi(self)
        self._ui.tabPlotAnnotation.setVisible(False)

        self._callback = None

        self._make_connections()

    def _make_connections(self):
        self._ui.pushButtonDocumentation.clicked.connect(self._documentationButtonClicked)
        self._ui.pushButtonDone.clicked.connect(self._done_button_clicked)

    def set_dataset_location(self, location):
        max_size = convert_to_bytes('3MiB')
        OnDiskFiles().setup_dataset(location, max_size)
        self._ui.tabContextAnnotation.update_info(location)
        self._ui.tabScaffoldAnnotation.update_annotations(location)

    def register_done_execution(self, callback):
        self._callback = callback

    def _documentationButtonClicked(self):
        webbrowser.open("https://abi-mapping-tools.readthedocs.io/en/latest/mapclientplugins.sparccurationhelperstep/docs/index.html")

    def _done_button_clicked(self):
        QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
        self._ui.tabContextAnnotation.write_context_annotation()
        self._callback()
        QtWidgets.QApplication.restoreOverrideCursor()


# Los métodos de cadena forman parte del tipo str.
# Esto significa que los métodos existen como variables de cadena o directamente como parte de la cadena.
# Por ejemplo, el método [.title()] se puede usar directamente con una cadena:

example_title =  "temperatures and facts about the moon".title()
print(example_title)
# Esto nos imprimiría:
#   Temperatures And Facts About The Moon

# tambien podemos usarlo en la variable:
example_title_2 = "temperatures and facts about the moon"
print(example_title_2.title())
# Esto nos imprimiría:
#   Temperatures And Facts About The Moon

# --------------------------------------------------------------------------------------------------------

# Division de una cadena

# Un metodo comun es [.split()] Sin argumentos, el metodo separará la cadena en cada espacio.

# ejemplo:
temperatures = """Daylight: 260 F Nighttime: -280 F"""
print(str(temperatures.split()))
# Esto nos imprimiría:
#   ['Daylight:', '260', 'F', 'Nighttime:', '-280', 'F']

# Si a esto le añadimos el caracter de nueva linea implícito se puede usar para divir
# la cadena al final de cada linea y crear lineas unicas:  [.split(\n)
# ejemplo:
temperatures = """Daylight: 260 F
Nighttime: -280 F"""
print(str(temperatures.split('\n')))
# Esto nos imprimiría:
#    ['Daylight: 260 F', 'Nighttime: -280 F']

# --------------------------------------------------------------------------------------------------------

# Busqueda de cadena

# El operador [in] lo utilizamos para encontrar palabras clave o caractéres:
# ejemplo:

"Moon" in "This text will describe facts and challenges with space travel"
#False
"Moon" in "This text will describe facts about the Moon"
#True

# -------------------------------------------------------------------------------------------------------
# Un enfoque para buscar la posicion de una palabra especifica en una cadena
# consiste en usar el metodo [.find()]
# ejemplo:

temperatures = """Saturn has daytime temperature of -170 degrees Celsius,
while Mars has -28 Celsius."""
print(str(temperatures.find("Moon")))
# Esto imprimirá -1 y significa que no se encuentra la palabra "Moon"
print(str(temperatures.find("Mars")))
# Esto imprimirá el lugar donde "Mars" se encuentra, en este caso "62"

# --------------------------------------------------------------------------------------------------------

# Si unicamente queremos saber si el contenido existe es usar el metodo [.count()]
# esto nos devolverá las veces que se repita esta palabra o caractér

# ejemplo:
print(str(temperatures.count("Mars")))
# Imprime 1
print(str(temperatures.count("Moon")))
# Imprime 0

# Debemos tomar en cuenta que buscará la palabra tal y como la escribimos (Mayusculas o minusculas)
# por tanto podemos convertir todo a una cadena de letras minusculas con [.lower()]
# ejemplo:
example_lower = "The Moon And The Earth".lower()
print(example_lower)
# Esto nos imprime "the moon and the earth"

# Para comprobar una palabra en un texto con [.lower()] podemos hacerlo así:
example_text_lower = "Temperatures on the Moon can vary wildly."
"temperatures" in example_text_lower
# Si usamos unicamente la variable será False, por los caractéres
"temperatures" in example_text_lower.lower()
# En este caso es True, por la busqueda en minuscula y los caractéres también

# De la misma manera podemos pasar todo a mayusculas con [.upper()]
# ejemplo:
example_upper = "The Moon And The Earth"
print(example_upper.upper())
# Esto nos imprime "THE MOON AND THE EARTH"

# ---------------------------------------------------------------------------------------------------------

# A veces tendremos problemas un poco complejos, ejemplo:
temperatures = "Mars Average Temperature: -60 C"
# Extraer la temperatura en Marte, entonces:
# dividimos en partes con ":" como referencia
parts = temperatures.split(':')
# Usamos [-1] para obtener el ultimo elemento que esté en las divisiones
print(parts[-1])

# ---------------------------------------------------------------------------------------------------------

# De igual manera podemos encontrar más irregulares y debemos usar distintas tecnicas:
mars_temperature = "The highest temperature on Mars is about 30 C"
for item in mars_temperature.split():
    if item.isnumeric():
    # El metodo [.isnumeric()] se utiliza para encontrar enteros
        print(item)

# Además el método [.isdecimal()] se utiliza para encontrar decimales
# IMPORTANTE [.isnumeric()] FUNCIONA UNICAMENTE CON POSITIVOS

# Para el caso de los negativos podemos uar métodos como [.startswith('-')]
# ejemplo:
"-60".startswith('-')
#True

# El método [.endswith()] comprueba el ultimo caracter de la cadena
#ejemplo:
if "30 C".endswith("C"):
    print("This temperature is in Celsius")
    #Imprmirá dicha frase ya que se cumple la condicion

# ---------------------------------------------------------------------------------------------------------

# Ademas de los métodos anteriores podemos usar [.replace()] para buscar y reemplazar repeticiones
# ejemplo:
example_replace = "Saturn has a daytime temperature of -170 degrees Celsius, while Mars has -28 Celsius.".replace("Celsius", "C")
print(example_replace)
# Esto imprimirá "Saturn has a daytime temperature of -170 degrees C, while Mars has -28 C."

# ----------------------------------------------------------------------------------------------------------

# Casi como el método [.split()], existe [.join()] con la diferencia que este los agrupa (lo contrario a split)
# este metodo necesita un elemento iterable (como una lista de python) como argumento, por lo que se usa distinto
# a los demás métodos de cadena
# ejemplo:
example_join = ["The Moon is drifting away from the Earth.", "On average, the Moon is moving about 4cm every year"]
print(' '.join(example_join))
# Esto imprimirá 'The Moon is drifting away from the Earth. On average, the Moon is moving about 4cm every year'


import os
import pytest
import sys
import subprocess

WIN = sys.platform == 'win32'

def test_it(cookies, venv, capfd):
    result = cookies.bake(extra_context={
        'project_name': 'Test Project',
        'repo_name': 'myapp',
    })
    assert result.exit_code == 0
    assert result.project.basename == 'myapp'

    out, err = capfd.readouterr()
    if WIN:
        assert 'Scripts\\pserve' in out
    else:
        assert 'bin/pserve' in out

    cwd = result.project.strpath

    # this is a hook for executing scaffold tests against a specific
    # version of pyramid (or a local checkout on disk)
    if 'OVERRIDE_PYRAMID' in os.environ:  # pragma: no cover
        venv.install(os.environ['OVERRIDE_PYRAMID'], editable=True)

    venv.install(cwd + '[testing]', editable=True)
    subprocess.check_call([venv.python, '-m', 'pytest', '-q'], cwd=cwd)

def test_it_invalid_module_name(cookies, venv, capfd):
    result = cookies.bake(extra_context={
        'repo_name': '0invalid',
    })
    assert result.exit_code == -1


from sqlalchemy_declarative import Person, Base, Address
from sqlalchemy import create_engine
engine = create_engine('sqlite:///sqlalchemy_example.db')
Base.metadata.bind = engine
from sqlalchemy.orm import sessionmaker
DBSession = sessionmaker()
DBSession.bind = engine
session = DBSession()
# Make a query to find all Persons in the database
cursor = session.query(Person).all()
for c in cursor:
    print(c.name)
print("---------")

# Return the first Person from all Persons in the database
person = session.query(Person).first()
print(person.name)

# Find all Address whose person field is pointing to the person object
session.query(Address).filter(Address.person == person).all()

# Retrieve one Address whose person field is point to the person object
session.query(Address).filter(Address.person == person).one()
address = session.query(Address).filter(Address.person == person).one()
print(address.post_code)


from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
da=datasets.load_iris()
print(da.keys())
print(da.DESCR)
s1=da.data
s2=da.target
model=KNeighborsClassifier()
model.fit(s1,s2)
y1=model.predict([[4,5,6,7]])
print(y1)


from django.shortcuts import render

from .forms import df, Pretraga
from .models import Dogadjaji, Prijava, Ocenjivanje, Glasao, Poziv
from korisnici.models import Clanovi
from django.contrib.auth.decorators import login_required

from django.contrib.auth.models import User
from django.urls import reverse
from django.http import HttpResponseRedirect, HttpResponse
from django.utils import timezone

# Create your views here.
@login_required
def dodajDogadjaj(request):
    organizator = request.user
    clan = Clanovi.objects.get(user=organizator)
    ima = False
    if Dogadjaji.objects.filter(organizator=clan):
        ima = True
    if request.method == "POST":

        forma = df(data=request.POST)

        if forma.is_valid():
            naziv = forma.cleaned_data['naziv']
            mesto = forma.cleaned_data['mesto']
            opis = forma.cleaned_data['opis']
            datum_odrzavanja = forma.cleaned_data['datum_odrzavanja']
            novac_za_prijavu = forma.cleaned_data['novac_za_prijavu']
            potrebno_igraca = forma.cleaned_data['potrebno_igraca']
            grad = forma.cleaned_data['grad']
            sport = forma.cleaned_data['sport']
            novcana_nagrada = forma.cleaned_data['novcana_nagrada']
            dogadjaj = Dogadjaji(naziv=naziv, mesto=mesto, opis=opis, datum_odrzavanja=datum_odrzavanja,
                                 novac_za_prijavu=novac_za_prijavu, potrebno_igraca=potrebno_igraca,
                                 grad=grad, sport=sport, novcana_nagrada=novcana_nagrada, organizator=clan)
            dogadjaj.save()
            prijava_organizatora = Prijava(prijava_za_dogadjaj=dogadjaj, prijavu_poslao=clan, organizator=organizator,
                                           primljen="Primljen")
            prijava_organizatora.save()
            print('\n\n\nRADII\n\n\n')
        else:
            print("\n\n\nGRESKA")
            print(forma.errors)
            print("\n\n\n")

        return HttpResponseRedirect(reverse('korisnici:clanInfo'))

    else:
        forma = df
        return render(request, 'dogadjaji/nov_dogadjaj.html', context={"cl_form": forma})

@login_required
def pretraga(request):
    clan = Clanovi.objects.get(user=request.user)
    svi_dogadjaji = Dogadjaji.objects.all().exclude(organizator=clan).exclude(
        datum_odrzavanja__lt=timezone.now()).exclude()
    moje_prijave = Prijava.objects.filter(prijavu_poslao=clan)
    prijavio = []
    for jedna in moje_prijave:
        prijavio.append(jedna.prijava_za_dogadjaj_id)
    ima = False
    if Dogadjaji.objects.filter(organizator=clan):
        ima = True
    if request.method == 'POST':
        forma = Pretraga(request.POST)
        try:
            prosecna_ocena_pretrage = float(request.POST['rating'][:-1])
        except Exception as e:
            prosecna_ocena_pretrage = 0
            print(e)
        print("\n\n\n")
        print(prosecna_ocena_pretrage)
        print(type(prosecna_ocena_pretrage))
        print("\n\n\n")
        if forma.is_valid():
            grad = forma.cleaned_data['grad']
            sport = forma.cleaned_data['sport']
            ucesce = forma.cleaned_data['ucesce']
            nagrade = forma.cleaned_data['nagrade']
            potrebno_igraca = forma.cleaned_data['potrebno_igraca']
            trazi = True
            if ucesce == "Ne placa se ucesce":
                print('||||' + nagrade + "|||||||")
                if potrebno_igraca == 0:
                    print('igraca 0')
                    prikazani = svi_dogadjaji.filter(grad=grad, sport=sport, novac_za_prijavu=0,
                                                     novcana_nagrada=nagrade, odrzano=0,
                                                     organizator__prosecna_ocena__gte=prosecna_ocena_pretrage).exclude()

                else:
                    print('igraca 1')
                    prikazani = svi_dogadjaji.filter(grad=grad, sport=sport, potrebno_igraca=potrebno_igraca,
                                                     novcana_nagrada=nagrade, odrzano=0,
                                                     organizator__prosecna_ocena__gte=prosecna_ocena_pretrage)

            else:
                if potrebno_igraca == 0:
                    print("ima ucesca igraca 0")
                    prikazani = svi_dogadjaji.filter(grad=grad, sport=sport, novac_za_prijavu__gt=0,
                                                     novcana_nagrada=nagrade, odrzano=0,
                                                     organizator__prosecna_ocena__gte=prosecna_ocena_pretrage)
                else:
                    print('ima ucesca igraca 1')
                    prikazani = svi_dogadjaji.filter(grad=grad, sport=sport, novac_za_prijavu__gt=0,
                                                     novcana_nagrada=nagrade, odrzano=0,
                                                     potrebno_igraca=potrebno_igraca,
                                                     organizator__prosecna_ocena__gte=prosecna_ocena_pretrage)
        else:
            print(forma.errors)
            return HttpResponseRedirect(reverse('dogadjaji:pretraga'))
    else:
        trazi = False
        prikazani = svi_dogadjaji.filter(sport=clan.omiljeni_sport, grad=clan.grad,
                                         odrzano=0)
    forma = Pretraga
    print(prikazani)
    return render(request, 'dogadjaji/pretraga.html',
                  context={'trazi': trazi, 'prikazani': prikazani, 'forma': forma, "imaaa": ima, 'prijavio': prijavio})

@login_required
def prijava(request, id_dog):
    user = request.user
    clan = Clanovi.objects.get(user=user)

    dogadjaj = Dogadjaji.objects.get(id=id_dog)
    organizator = dogadjaj.organizator.user
    print(dogadjaj)
    print(clan.user.username)
    prijave_ovog_igraca = Prijava.objects.filter(prijavu_poslao=clan, prijava_za_dogadjaj=dogadjaj)
    if dogadjaj.ima_igraca >= dogadjaj.potrebno_igraca:
        return HttpResponse(
            "<title>MAXO</title>"
            "

Maksimalan broj clanova je vec "
            "prijavljen na ovaj dogadjaj "
            "

Prozor ce se zatvoriti za 5 sekundi
"
            "")
    if prijave_ovog_igraca:
        return HttpResponse(
            "<title>MAXO</title>"
            "

Vec ste se prijavili za ovaj "
            "dogadjaj

Prozor ce se zatvoriti za 5 sekundi
"
            "")
    if clan != dogadjaj.organizator:
        prijava = Prijava(prijavu_poslao=clan, prijava_za_dogadjaj=dogadjaj, organizator=organizator)
        prijava.save()
        return HttpResponse(
            "<title>MAXO</title>"
            "

Prijava uspesno poslata."
            " Mozete zatvoriti ovu stranicu.

Prozor ce se zatvoriti za 5 sekundi
"
            "")
    else:
        return HttpResponse(
            "<title>MAXO</title>"
            "

Ne mozete da se prijavite na svoj turnir."
            "

Prozor ce se zatvoriti za 5 sekundi
"
            "")

@login_required
def mojiDogadjaji(request):
    user = request.user
    clan = Clanovi.objects.get(user=user)
    moji_dogadjaji = Dogadjaji.objects.filter(organizator=clan, odrzano=0)
    moje_prijave_cekanje = Prijava.objects.filter(organizator=user, primljen="Ceka se odgovor")
    print(moje_prijave_cekanje)
    return render(request, 'dogadjaji/moji_dogadjaji.html',
                  context={'user': user, 'clan': clan, 'moji_dogadjaji': moji_dogadjaji, 'ceka': moje_prijave_cekanje})

@login_required
def prijava_rezultat(request, prijava_id):
    user = request.user
    if request.method == "POST":
        prijava_poslata = Prijava.objects.get(id=prijava_id)
        za_dogadjaj = Dogadjaji.objects.get(id=prijava_poslata.prijava_za_dogadjaj.id)
        print(za_dogadjaj)
        prijavu_poslao_clan = prijava_poslata.prijavu_poslao
        prijava_poslata_user = prijavu_poslao_clan.user
        if za_dogadjaj.potrebno_igraca == za_dogadjaj.ima_igraca:
            return HttpResponse("Dogadjaj je vec popunjen")
        if prijava_poslata.prijavu_poslao == user:
            return HttpResponse("Ne mozete se prijaviti na svoj turnir")
        else:
            if prijava_poslata.prijava_za_dogadjaj.odrzano == 1:
                return HttpResponse("Ovaj dogadjaj je vec zavrsen")
            else:
                if prijava_poslata.primljen == "Primljen":
                    return HttpResponse("Igrac je vec primljen na dogadjaj")
                elif prijava_poslata.primljen == "Odbijen":
                    return HttpResponse("Igrac je vec odbijen sa turnira")
                else:
                    if request.POST['izbor'] == "prihvati":

                        prijava_poslata.primljen = "Primljen"
                        prijava_poslata.save()
                        za_dogadjaj.ima_igraca += 1
                        za_dogadjaj.save()
                        print("\n\n\nPrimljen\n\n\n")
                        return HttpResponseRedirect(reverse("dogadjaji:moji_dogadjaji"))
                    else:
                        prijava_poslata.primljen = "Odbijen"
                        prijava_poslata.save()
                        print("\n\n\nPrimljen\n\n\n")
                        return HttpResponseRedirect(reverse("dogadjaji:moji_dogadjaji"))

    else:
        return HttpResponseRedirect(reverse("dogadjaji:moji_dogadjaji"))

@login_required
def kraj(request, dogadjaj_kraj_id):
    user = request.user
    clan = Clanovi.objects.get(user=user)

    dogadjaj = Dogadjaji.objects.get(id=dogadjaj_kraj_id)
    prijave_za_dogadjaj = Prijava.objects.filter(primljen="Primljen", prijava_za_dogadjaj=dogadjaj)
    if dogadjaj.organizator != clan:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Vi niste organizator ovog dogadjaja"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")
    else:
        if dogadjaj.datum_odrzavanja > timezone.now().date():
            print("Datum odrzavanja dogadjaja jos nije prosao")
            return render(request, "dogadjaji/zavrsen.html", context={"datum": dogadjaj.datum_odrzavanja})

        else:
            if dogadjaj.ima_igraca == 0:
                return HttpResponse(
                    "<title>MAXO</title>"
                    "
Nije moguce zavrsiti dogadjaj sa 0 "
                    "clanova
"
                    "
Stranica ce se zatvoriti za 5 sekundi"
                    "")
            else:
                dogadjaj.odrzano = True
                dogadjaj.save()
                for igrac in prijave_za_dogadjaj:
                    nov_glas = Glasao(igrac=igrac.prijavu_poslao.user, koji_dogadjaj=dogadjaj)
                    nov_glas.save()
                prijavljeni = Prijava.objects.filter(primljen="Primljen", prijava_za_dogadjaj=dogadjaj)
                for ocenjuje in prijavljeni:
                    for ocenjivan in prijavljeni:
                        if ocenjuje != ocenjivan:
                            nova_ocena = Ocenjivanje(ocenio=ocenjuje.prijavu_poslao.user,
                                                     koga_ocenio=ocenjivan.prijavu_poslao, koji_dogadjaj=dogadjaj)
                            nova_ocena.save()
                        else:
                            pass

                return HttpResponse(
                    "<title>MAXO</title>"
                    "
Dogadjaj je uspesno zavrsen
"
                    "

Obavestenje za glasanje je poslato ucesnicima
"
                    "
Stranica ce se zatvoriti za 5 sekundi"
                    "")

@login_required
def otkaz(request, dogadjaj_za_otkaz):
    user = request.user
    clan = Clanovi.objects.get(user=user)

    dogadjaj = Dogadjaji.objects.get(id=dogadjaj_za_otkaz)
    if dogadjaj.organizator != clan:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Vi niste organizator ovog dogadjaja"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")
    else:
        dogadjaj.delete()
        return HttpResponse(
            "<title>MAXO</title>"
            "
Uspesno ste obrisali svoj dogadjaj
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

@login_required
def ocenjuj(request, id_dog):
    user = request.user
    clan = Clanovi.objects.get(user=user)
    koji_dogadjaj = Dogadjaji.objects.get(id=id_dog)
    try:
        moja_prijava = Prijava.objects.get(prijavu_poslao=clan, prijava_za_dogadjaj=koji_dogadjaj)
        if moja_prijava.primljen != "Primljen":
            return HttpResponse(
                "<title>MAXO</title>"
                "
Ne mozete da glasate za ovaj"
                " dogadjaj posto niste primljeni
"
                "
Stranica ce se zatvoriti za 5 sekundi"
                "")
    except:
        pass

    if koji_dogadjaj.odrzano == False:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Ovaj dogadjaj jos nije zavrsen
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")
    try:
        if Glasao.objects.get(igrac=user, koji_dogadjaj=koji_dogadjaj).zavrsio:
            return HttpResponse(
                "<title>MAXO</title>"
                "
Zavrsili ste sa glasanjem za ovaj dogadjaj
"
                "
Stranica ce se zatvoriti za 5 sekundi"
                "")
    except:
        pass
    igraci_za_glasanje = Ocenjivanje.objects.filter(ocenio=user, koji_dogadjaj=koji_dogadjaj, ocena__exact=0)
    try:
        igrac = igraci_za_glasanje[0]

        # Staviti kada se na stranici posalje glas da ode na url koji cu da napravim i da se tu glas obradi i
        # posle izmeniti ovo za filter nekako da ako je vec glasano za tog igraca da vise ne glasa
    except:

        return HttpResponse(
            "<title>MAXO</title>"
            "
Doslo je do greske
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

    return render(request, 'dogadjaji/ocenjivanje.html', context={'igrac': igrac})

@login_required
def ocena(request, id_dog, usid):
    # print(usid)
    # print(id_dog)
    user = request.user
    clan = Clanovi.objects.get(user=user)
    koji_dogadjaj = Dogadjaji.objects.get(id=id_dog)
    try:
        dal_moze = Prijava.objects.get(prijavu_poslao=clan, prijava_za_dogadjaj=koji_dogadjaj, primljen="Primljen")
        print("\n\n\n", dal_moze)
        if dal_moze:
            print(dal_moze)
        else:
            print("GRESKA")
            return HttpResponse(
                "<title>MAXO</title>"
                "
Doslo je do greske
"
                "
Stranica ce se zatvoriti za 5 sekundi"
                "")
    except Exception as e:
        print("NE MOZETE GLASATI\n\n\n\n", e)
        return HttpResponse(
            "<title>MAXO</title>"
            "
Vi ne mozete glasati
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

    ocenjuje_igraca = User.objects.get(id=usid)
    print(ocenjuje_igraca)
    clan_ocenjen = Clanovi.objects.get(user=ocenjuje_igraca)
    provera = Ocenjivanje.objects.get(ocenio=user, koga_ocenio=clan_ocenjen, koji_dogadjaj=koji_dogadjaj)
    if provera.ocena > 0:
        print("Vec ste ocenili ovog igraca")
        return HttpResponse(
            "<title>MAXO</title>"
            "
Vec ste glasali za ovog igraca
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")
    try:
        ocena = float(request.POST['rating'][:-1])
    except:
        ocena = 0
    try:
        komentar = str(request.POST['komentar']).strip()
    except:
        komentar = ""
    nova_ocena = Ocenjivanje.objects.get(ocenio=user, koga_ocenio=clan_ocenjen, koji_dogadjaj=koji_dogadjaj)
    nova_ocena.ocena = ocena
    nova_ocena.komentar = komentar
    nova_ocena.save()
    igraci_za_glasanje = Ocenjivanje.objects.filter(ocenio=user, koji_dogadjaj=koji_dogadjaj, ocena__exact=0)
    if igraci_za_glasanje:
        print("\n\n\n")
        print(igraci_za_glasanje)
        ocene_igraca = Ocenjivanje.objects.filter(koga_ocenio=clan_ocenjen)
        zbir = 0
        ocene = 0
        for jedna in ocene_igraca:
            if jedna.ocena <= 0.1 or jedna.ocena > 5:
                continue
            zbir += jedna.ocena
            ocene += 1
        prosek = zbir / ocene
        clan_ocenjen.prosecna_ocena = prosek
        clan_ocenjen.save()
        url = reverse('dogadjaji:ocenjivanje', kwargs={'id_dog': koji_dogadjaj.id})
        return HttpResponseRedirect(url)
    else:
        glas = Glasao.objects.get(igrac=user, koji_dogadjaj=koji_dogadjaj)
        glas.zavrsio = True
        glas.save()
        ocene_igraca = Ocenjivanje.objects.filter(koga_ocenio=clan_ocenjen)
        zbir = 0
        ocene = 0
        for jedna in ocene_igraca:
            if jedna.ocena <= 0.1 or jedna.ocena > 5:
                continue
            zbir += jedna.ocena
            ocene += 1
        prosek = zbir / ocene
        clan_ocenjen.prosecna_ocena = prosek
        clan_ocenjen.save()
        return HttpResponseRedirect(reverse('korisnici:clanInfo'))

@login_required
def pregled(request, id_dog):
    user = request.user
    clan = Clanovi.objects.get(user=user)

    dogadjaj = Dogadjaji.objects.get(id=id_dog)

    organizator = dogadjaj.organizator
    prijavljeni = Prijava.objects.filter(prijava_za_dogadjaj=dogadjaj, primljen="Primljen")
    if organizator == clan:
        editor = True
        prijavio = True
    else:
        editor = False
        svi_prijavljeni = Prijava.objects.filter(prijava_za_dogadjaj=dogadjaj)
        prijavljeni_clanovi = []

        for jedan in svi_prijavljeni:
            prijavljeni_clanovi.append(jedan.prijavu_poslao)
        if clan in prijavljeni_clanovi:
            prijavio = True
        else:
            prijavio = False

        print(prijavio)
    # ZAVRSITI PRIKAZ DOGADJAJA I URADITI IZBACIVANJE IGRACA AKO JE USER ORGANIZATOR
    print(editor)
    return render(request, 'dogadjaji/dogadjaj.html',
                  {"editor": editor, "dogadjaj": dogadjaj, "prijavljeni": prijavljeni, "prijavio": prijavio})

@login_required
def izbaci(request, id_dog, usid):
    user = request.user
    clan = Clanovi.objects.get(user=user)
    try:
        user_za_izbacivanje = User.objects.get(id=usid)
    except:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Korisnik kojeg zelite da izbacite ne postoji
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")
    try:

        dogadjaj = Dogadjaji.objects.get(id=id_dog)

    except:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Dogadjaj ne postoji
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

    clan_za_izbacivanje = Clanovi.objects.get(user=user_za_izbacivanje)
    prijavljeni = Prijava.objects.get(prijava_za_dogadjaj=dogadjaj, prijavu_poslao=clan_za_izbacivanje)

    if user_za_izbacivanje == user:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Ne mozete izbaciti samog sebe
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

    if prijavljeni.primljen != "Primljen":
        return HttpResponse(
            "<title>MAXO</title>"
            "
Igrac nije primljen na ovaj dogadjaj
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

    if dogadjaj.odrzano == True:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Ovaj dogadjaj je vec zavrsen
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")
    prijavljeni.primljen = "Odbijen"
    prijavljeni.save()
    dogadjaj.ima_igraca -= 1
    dogadjaj.save()
    return HttpResponse(
        "<title>MAXO</title>"
        "
Igrac je uspesno uklonjen sa dogadjaja
"
        "
Stranica ce se zatvoriti za 5 sekundi"
        "")

@login_required
def pozovi(request, id_dog):
    if request.method != "POST":
        return HttpResponse(
            "<title>MAXO</title>"
            "
Doslo je do greske
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

    usid = str(request.POST['username']).strip()

    user = request.user
    clan = Clanovi.objects.get(user=user)

    try:
        user_za_poziv = User.objects.get(username=usid)
        clan_za_poziv = Clanovi.objects.get(user=user_za_poziv)
    except:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Ovaj korisnik ne postoji
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

    if user == user_za_poziv:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Ne mozete pozvati samog sebe
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

    try:
        dogadjaj = Dogadjaji.objects.get(id=id_dog)
    except:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Dogadjaj ne postoji
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

    if dogadjaj.odrzano == True:
        return HttpResponse(
            "<title>MAXO</title>"
            "
Dogadjaj je vec odrzan
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")

    try:
        pozivi = Poziv.objects.get(pozvao=user, ko_je_pozvan=clan_za_poziv, koji_dogadjaj=dogadjaj)
        return HttpResponse(
            "<title>MAXO</title>"
            "
Vec ste pozvali ovog igraca na ovaj dogadjaj
"
            "
Stranica ce se zatvoriti za 5 sekundi"
            "")
    # ZAVRSITI POZIVANJE
    # SMISLITI KAKO DA AKO VISE LJUDI POZOVE NA JEDAN DOGADJAJ DA TO BUDE PRIKAZANO NEKAKO DRUGACIJE
    except:
        try:
            prijava = Prijava.objects.get(prijava_za_dogadjaj=dogadjaj, prijavu_poslao=clan_za_poziv)
            return HttpResponse(
                "<title>MAXO</title>"
                "
Igrac je vec poslao prijavu za ovaj dogadjaj
"
                "
Stranica ce se zatvoriti za 5 sekundi"
                "")
        except:
            pozivi = Poziv(pozvao=user, ko_je_pozvan=clan_za_poziv, koji_dogadjaj=dogadjaj)
            pozivi.save()
            return HttpResponse(
                "<title>MAXO</title>"
                "
Poziv za ucesce je poslat
"
                "
Stranica ce se zatvoriti za 5 sekundi"
                "")

@login_required
def pozivi(request):
    user = request.user
    clan = Clanovi.objects.get(user=user)
    pozivi = Poziv.objects.filter(ko_je_pozvan=clan).order_by('-id')
    for poziv in pozivi:
        if poziv.pogledano == "Jeste pogledano":
            continue
        poziv.pogledano = "Jeste pogledano"
        poziv.save()
    print(pozivi)

    return render(request, 'dogadjaji/pozivi.html', {"pozivi": pozivi})


from Estimator.geo_estimator import GeoEstimator
import numpy as np
from numpy.linalg import inv
import matplotlib.pyplot as plt

class Circle2D(GeoEstimator):
    def __init__(self, x_data, y_data, n):
        super().__init__(x_data, y_data, n)
        self.num_points_per_model = 3

    def find_model(self, sample):
        pt1 = sample[0]
        pt2 = sample[1]
        pt3 = sample[2]
        A = np.array([[pt2[0] - pt1[0], pt2[1] - pt1[1]], [pt3[0] - pt2[0], pt3[1] - pt2[1]]])
        B = np.array([[pt2[0] ** 2 - pt1[0] ** 2 + pt2[1] ** 2 - pt1[1] ** 2],
                      [pt3[0] ** 2 - pt2[0] ** 2 + pt3[1] ** 2 - pt2[1] ** 2]])
        inv_A = inv(A)
        c_x, c_y = np.dot(inv_A, B) / 2
        c_x, c_y = c_x[0], c_y[0]
        r = np.sqrt((c_x - pt1[0]) ** 2 + (c_y - pt1[1]) ** 2)
        return c_x, c_y, r

    def eval_model(self, model):
        d = 0
        c_x, c_y, r = model
        for i in range(len(self.x_data)):
            dis = np.sqrt((self.x_data[i] - c_x) ** 2 + (self.y_data[i] - c_y) ** 2)
            if dis >= r:
                d += dis - r
            else:
                d += r - dis
        return d

    def get_plt_geo(self):
        return plt.Circle((self.best_model[0], self.best_model[1]), radius=self.best_model[2], color='r', fc='y', fill=False)


#! /usr/bin/env python

"""
Module with fake companion injection functions.
"""

__author__ = 'Carlos Alberto Gomez Gonzalez, Valentin Christiaens'
__all__ = ['collapse_psf_cube',
           'normalize_psf',
           'cube_inject_companions',
           'generate_cube_copies_with_injections',
           'frame_inject_companion']

from multiprocessing import cpu_count
import numpy as np
from scipy import stats
from scipy.interpolate import interp1d
from packaging import version
import photutils
try:
    from photutils.aperture import aperture_photometry, CircularAperture
except:
    from photutils import aperture_photometry, CircularAperture
if version.parse(photutils.__version__) >= version.parse('0.3'):
    # for photutils version >= '0.3' use photutils.centroids.centroid_com
    from photutils.centroids import centroid_com as cen_com
else:
    # for photutils version < '0.3' use photutils.centroid_com
    import photutils.centroid_com as cen_com
from ..preproc import (cube_crop_frames, frame_shift, frame_crop, cube_shift,
                       frame_rotate)
from ..var import (frame_center, fit_2dgaussian, fit_2dairydisk, fit_2dmoffat,
                   get_circle, get_annulus_segments, dist_matrix)
from ..config.utils_conf import print_precision, check_array, pool_map, iterable

def cube_inject_companions(array, psf_template, angle_list, flevel, rad_dists,
                           plsc=None, n_branches=1, theta=0, imlib='vip-fft',
                           interpolation='lanczos4', transmission=None,
                           radial_gradient=False, full_output=False,
                           verbose=False, nproc=1):
    """ Injects fake companions in branches, at given radial distances.

    Parameters
    ----------
    array : 3d/4d numpy ndarray
        Input cube. This is copied before the injections take place, so
        ``array`` is never modified.
    psf_template : 2d/3d numpy ndarray
        [for a 3D input array] 2d array with the normalized PSF template, with
        an odd or even shape. The PSF image must be centered wrt to the array.
        Therefore, it is recommended to run the function ``normalize_psf`` to
        generate a centered and flux-normalized PSF template.
        It can also be a 3D array, but length should match that of ADI cube.
        [for a 4D input array] In the ADI+mSDI case, it must be a 3d array
        (matching spectral dimensions).
    angle_list : 1d numpy ndarray
        List of parallactic angles, in degrees.
    flevel : float or 1d array or 2d array
        Factor for controlling the brightness of the fake companions. If a float,
        the same flux is used for all injections.
        [3D input cube]: if a list/1d array is provided, it should have same
        length as number of frames in the 3D cube (can be used to take into
        account varying observing conditions or airmass).
        [4D (ADI+mSDI) input cube]: if a list/1d array should have the same
        length as the number of spectral channels (i.e. provide a spectrum). If
        a 2d array, it should be n_wavelength x n_frames (can e.g. be used to
        inject a spectrum in varying conditions).
    plsc : float or None
        Value of the plsc in arcsec/px. Only used for printing debug output when
        ``verbose=True``.
    rad_dists : float, list or array 1d
        Vector of radial distances of fake companions in pixels.
    n_branches : int, optional
        Number of azimutal branches.
    theta : float, optional
        Angle in degrees for rotating the position of the first branch that by
        default is located at zero degrees. Theta counts counterclockwise from
        the positive x axis.
    imlib : str, optional
        See the documentation of the ``vip_hci.preproc.frame_shift`` function.
    interpolation : str, optional
        See the documentation of the ``vip_hci.preproc.frame_shift`` function.
    transmission: numpy array, optional
        Radial transmission of the coronagraph, if any. Array with either
        2 x n_rad, 1+n_ch x n_rad columns. The first column should contain the
        radial separation in pixels, while the other column(s) are the
        corresponding off-axis transmission (between 0 and 1), for either all,
        or each spectral channel (only relevant for a 4D input cube).
    radial_gradient: bool, optional
        Whether to apply a radial gradient to the psf image at the moment of
        injection. By default False, i.e. the flux of the psf image is scaled
        only considering the value of tramnsmission at the exact radius the
        companion is injected. Setting it to False may better represent the
        transmission at the very edge of a physical mask though.
    full_output : bool, optional
        Returns the ``x`` and ``y`` coordinates of the injections, additionally
        to the new array.
    verbose : bool, optional
        If True prints out additional information.
    nproc: int or None, optional
        Number of CPUs to use for multiprocessing. If None, will be
        automatically set to half the number of available CPUs.

    Returns
    -------
    array_out : numpy ndarray
        Output array with the injected fake companions.
    positions : list of tuple(y, x)
        [full_output] Coordinates of the injections in the first frame (and
        first wavelength for 4D cubes).
    psf_trans: numpy ndarray
        [full_output & transmission != None] Array with injected psf affected
        by transmission (serves to check radial transmission)

    """
    if nproc is None:
        nproc = cpu_count()//2

    def _cube_inject_adi(array, psf_template, angle_list, flevel, plsc,
                         rad_dists, n_branches=1, theta=0, imlib='vip-fft',
                         interpolation='lanczos4', transmission=None,
                         radial_gradient=False, verbose=False):
        if np.isscalar(flevel):
            flevel = np.ones_like(angle_list)*flevel

        if transmission is not None:
            # last radial separation should be beyond the edge of frame
            interp_trans = interp1d(transmission[0], transmission[1])

        ceny, cenx = frame_center(array[0])
        nframes = array.shape[-3]
        size_fc = psf_template.shape[-1]

        positions = []
        # fake companion cube
        fc_fr = np.zeros([nframes, size_fc, size_fc])
        if psf_template.ndim == 2:
            for fr in range(nframes):
                fc_fr[fr] = psf_template
        else:
            for fr in range(nframes):
                fc_fr[fr] = psf_template[fr]

        psf_trans = None
        array_out = array.copy()

        for branch in range(n_branches):
            ang = (branch * 2 * np.pi / n_branches) + np.deg2rad(theta)

            if verbose:
                print('Branch {}:'.format(branch+1))

            for rad in rad_dists:
                fc_fr_rad = fc_fr.copy()
                if transmission is not None:
                    if radial_gradient:
                        y_star = pceny
                        x_star = pcenx - rad
                        d = dist_matrix(size_fc, x_star, y_star)
                        for i in range(d.shape[0]):
                            fc_fr_rad[:, i] = interp_trans(d[i])*fc_fr[:, i]

                        # check the effect of transmission on a single PSF tmp
                        psf_trans = frame_rotate(fc_fr_rad[0],
                                                 -(ang*180/np.pi-angle_list[0]),
                                                 imlib=imlib_rot,
                                                 interpolation=interpolation)

                        # shift_y = rad * np.sin(ang - np.deg2rad(angle_list[0]))
                        # shift_x = rad * np.cos(ang - np.deg2rad(angle_list[0]))
                        # dsy = shift_y-int(shift_y)
                        # dsx = shift_x-int(shift_x)
                        # fc_fr_ang = frame_shift(psf_trans, dsy, dsx, imlib_sh,
                        #                         interpolation,
                        #                         border_mode='constant')
                    else:
                        fc_fr_rad = interp_trans(rad)*fc_fr
                if nproc == 1:
                    for fr in range(nframes):
                        array_out[fr] += _frame_shift_fcp(fc_fr_rad[fr],
                                                          array[fr], rad, ang,
                                                          angle_list[fr],
                                                          flevel[fr], size_fc,
                                                          imlib_sh, imlib_rot,
                                                          interpolation,
                                                          transmission,
                                                          radial_gradient)
                else:
                    res = pool_map(nproc, _frame_shift_fcp, iterable(fc_fr_rad),
                                   iterable(array), rad, ang,
                                   iterable(angle_list), iterable(flevel),
                                   size_fc, imlib_sh, imlib_rot, interpolation,
                                   transmission, radial_gradient)
                    array_out += np.array(res)

                pos_y = rad * np.sin(ang) + ceny
                pos_x = rad * np.cos(ang) + cenx

                positions.append((pos_y, pos_x))

                if verbose:
                    rad_arcs = rad * plsc
                    print('\t(X,Y)=({:.2f}, {:.2f}) at {:.2f} arcsec '
                          '({:.2f} pxs from center)'.format(pos_x, pos_y,
                                                            rad_arcs, rad))

        return array_out, positions, psf_trans

    check_array(array, dim=(3, 4), msg="array")
    check_array(psf_template, dim=(2, 3), msg="psf_template")

    nframes = array.shape[-3]

    pceny, pcenx = frame_center(psf_template)

    if array.ndim == 4 and psf_template.ndim != 3:
        raise ValueError('`psf_template` must be a 3d array')

    if verbose and not np.isscalar(plsc):
        raise TypeError("`plsc` must be a scalar")
    if not np.isscalar(flevel):
        if len(flevel) != array.shape[0]:
            msg = "if not scalar `flevel` must have same length as array"
            raise TypeError(msg)

    # set imlib for rotation & shift (rotation used if transmission!=None)
    if imlib == 'opencv':
        imlib_sh = imlib
        imlib_rot = imlib
    elif imlib == 'skimage' or imlib == 'ndimage-interp':
        imlib_sh = 'ndimage-interp'
        imlib_rot = 'skimage'
    elif imlib == 'vip-fft' or imlib == 'ndimage-fourier':
        imlib_sh = imlib
        imlib_rot = 'vip-fft'
    else:
        raise TypeError("Interpolation not recognized.")

    rad_dists = np.asarray(rad_dists).reshape(-1)  # forces ndim=1

    if not rad_dists[-1] < array.shape[-1] / 2:
        raise ValueError('rad_dists last location is at the border (or '
                         'outside) of the field')

    if transmission is not None:
        t_nz = transmission.shape[0]
        if transmission.ndim != 2:
            raise ValueError("transmission should be a 2D ndarray")
        elif t_nz != 2 and t_nz != 1+array.shape[0]:
            msg = "transmission dimensions should be either (2,N) or (n_wave+1, N)"
            raise ValueError(msg)
        # if transmission doesn't have right format for interpolation, adapt it
        diag = np.sqrt(2)*array.shape[-1]
        if transmission[0, 0] != 0 or transmission[0, -1] < diag:
            trans_rad_list = transmission[0].tolist()
            for j in range(t_nz-1):
                trans_list = transmission[j+1].tolist()
                # should have a zero point
                if transmission[0, 0] != 0:
                    if j == 0:
                        trans_rad_list = [0]+trans_rad_list
                    trans_list = [0]+trans_list
                # last point should be max possible distance between fc and star
                if transmission[0, -1] < np.sqrt(2)*array.shape[-1]/2:
                    if j == 0:
                        trans_rad_list = trans_rad_list+[diag]
                    trans_list = trans_list+[1]
                if j == 0:
                    ntransmission = np.zeros([t_nz, len(trans_rad_list)])
                    ntransmission[0] = trans_rad_list
                ntransmission[j+1] = trans_list
            transmission = ntransmission.copy()

    # ADI case
    if array.ndim == 3:
        res = _cube_inject_adi(array, psf_template, angle_list, flevel, plsc,
                               rad_dists, n_branches, theta, imlib,
                               interpolation, transmission, radial_gradient,
                               verbose)
        array_out, positions, psf_trans = res

    # ADI+mSDI (IFS) case
    else:
        nframes_wav = array.shape[0]
        array_out = array.copy()
        if np.isscalar(flevel):
            flevel_all = np.ones([nframes_wav, nframes])*flevel
        elif flevel.ndim == 1:
            flevel_all = np.zeros([nframes_wav, nframes])
            for i in range(nframes_wav):
                flevel_all[i, :] = flevel[i]
        else:
            flevel_all = flevel
        for i in range(nframes_wav):
            if verbose:
                msg = "*** Processing spectral channel {}/{} ***"
                print(msg.format(i+1, nframes_wav))
            if transmission is None:
                trans = None
            elif transmission.shape[0] == 2:
                trans = transmission
            elif transmission.shape[0] == nframes_wav+1:
                trans = np.array([transmission[0], transmission[i+1]])
            else:
                msg = "transmission shape ({}, {}) is not valid"
                raise TypeError(msg.format(transmission.shape[0],
                                           transmission.shape[1]))
            res = _cube_inject_adi(array[i], psf_template[i], angle_list,
                                   flevel_all[i], plsc, rad_dists, n_branches,
                                   theta, imlib, interpolation, trans,
                                   radial_gradient,
                                   verbose=(i == 0 & verbose is True))
            array_out[i], positions, psf_trans = res

    if full_output:
        if transmission is not None:
            return array_out, positions, psf_trans
        else:
            return array_out, positions
    else:
        return array_out

def _frame_shift_fcp(fc_fr_rad, array, rad, ang, derot_ang, flevel, size_fc,
                     imlib_sh, imlib_rot, interpolation, transmission,
                     radial_gradient):
    """
    Specific cube shift algorithm for injection of fake companions
    """

    ceny, cenx = frame_center(array)
    sizey = array.shape[-2]
    sizex = array.shape[-1]

    array_sh = np.zeros_like(array)

    w = int(np.ceil(size_fc/2))
    if size_fc % 2:  # new convention
        w -= 1
    sty = int(ceny) - w
    stx = int(cenx) - w

    shift_y = rad * np.sin(ang - np.deg2rad(derot_ang))
    shift_x = rad * np.cos(ang - np.deg2rad(derot_ang))
    if transmission is not None and radial_gradient:
        fc_fr_ang = frame_rotate(fc_fr_rad, -(ang*180/np.pi - derot_ang),
                                 imlib=imlib_rot, interpolation=interpolation)
    else:
        fc_fr_ang = fc_fr_rad.copy()

    # sub-px shift (within PSF template frame)
    dsy = shift_y-int(shift_y)
    dsx = shift_x-int(shift_x)
    fc_fr_ang = frame_shift(fc_fr_ang, dsy, dsx, imlib_sh, interpolation,
                            border_mode='constant')
    # integer shift (in final cube)
    y0 = sty+int(shift_y)
    x0 = stx+int(shift_x)
    yN = y0+size_fc
    xN = x0+size_fc
    p_y0 = 0
    p_x0 = 0
    p_yN = size_fc
    p_xN = size_fc
    if y0 < 0:
        p_y0 = -y0
        y0 = 0
    if x0 < 0:
        p_x0 = -x0
        x0 = 0
    if yN > sizey:
        p_yN -= yN-sizey
        yN = sizey
    if xN > sizex:
        p_xN -= xN-sizex
        xN = sizex

    array_sh[y0:yN, x0:xN] = flevel*fc_fr_ang[p_y0:p_yN, p_x0:p_xN]

    return array_sh

def generate_cube_copies_with_injections(array, psf_template, angle_list, plsc,
                                         n_copies=100, inrad=8, outrad=12,
                                         dist_flux=("uniform", 2, 500)):
    """
    Create multiple copies of ``array`` with different random injections.

    This is a wrapper around ``metrics.cube_inject_companions``, which deals
    with multiple copies of the original data cube and generates random
    parameters.

    Parameters
    ----------
    array : 3d/4d numpy ndarray
        Original input cube.
    psf_template : 2d/3d numpy ndarray
        Array with the normalized psf template. It should have an odd shape.
        It's recommended to run the function ``normalize_psf`` to get a proper
        PSF template. In the ADI+mSDI case it must be a 3d array.
    angle_list : 1d numpy ndarray
        List of parallactic angles, in degrees.
    plsc : float
        Value of the plsc in arcsec/px. Only used for printing debug output when
        ``verbose=True``.
    n_copies : int
        This is the number of 'cube copies' returned.
    inrad,outrad : float
        Inner and outer radius of the injections. The actual injection position
        is chosen randomly.
    dist_flux : tuple('method', params)
        Tuple describing the flux selection. Method can be a function, the
        ``*params`` are passed to it. Method can also be a string, for a
        pre-defined random function:

            ``('skewnormal', skew, mean, var)``
                uses scipy.stats.skewnorm.rvs
            ``('uniform', low, high)``
                uses np.random.uniform
            ``('normal', loc, scale)``
                uses np.random.normal

    Returns
    -------
    fake_data : dict
        Represents a copy of the original ``array``, with fake injections. The
        dictionary keys are:

            ``cube``
                Array shaped like the input ``array``, with the fake injections.
            ``position`` : list of tuples(y,x)
                List containing the positions of the injected companions, as
                (y,x) tuples.
            ``dist`` : float
                The distance of the injected companions, which was passed to
                ``cube_inject_companions``.
            ``theta`` : float, degrees
                The initial angle, as passed to ``cube_inject_companions``.
            ``flux`` : float
                The flux passed to ``cube_inject_companions``.

    """
    # TODO: 'mask' parameter for known companions?

    width = outrad - inrad
    yy, xx = get_annulus_segments(array[0], inrad, width)[0]
    num_patches = yy.shape[0]

    # Defining Fluxes according to chosen distribution
    dist_fkt = dict(skewnormal=stats.skewnorm.rvs,
                    normal=np.random.normal,
                    uniform=np.random.uniform).get(dist_flux[0],
                                                   dist_flux[0])
    fluxes = sorted(dist_fkt(*dist_flux[1:], size=n_copies))

    inds_inj = np.random.randint(0, num_patches, size=n_copies)

    # Injections
    for n in range(n_copies):

        injx = xx[inds_inj[n]] - frame_center(array[0])[1]
        injy = yy[inds_inj[n]] - frame_center(array[0])[0]
        dist = np.sqrt(injx**2 + injy**2)
        theta = np.mod(np.arctan2(injy, injx) / np.pi * 180, 360)

        fake_cube, positions = cube_inject_companions(
            array, psf_template, angle_list, plsc=plsc,
            flevel=fluxes[n], theta=theta,
            rad_dists=dist, n_branches=1,  # TODO: multiple injections?
            full_output=True, verbose=False
        )

        yield dict(
            positions=positions,
            dist=dist, theta=theta, flux=fluxes[n],
            cube=fake_cube
        )

def frame_inject_companion(array, array_fc, pos_y, pos_x, flux,
                           imlib='vip-fft', interpolation='lanczos4'):
    """
    Injects a fake companion in a single frame (it could be a single
    multi-wavelength frame) at given coordinates, or in a cube (at the same
    coordinates, flux and with same fake companion image throughout the cube).

    Parameters
    ----------
    array : numpy ndarray, 2d or 3d
        Input frame or cube.
    array_fc : numpy ndarray, 2d
        Fake companion image to be injected. If even-dimensions, the center
        should be placed at coordinates [dim//2, dim//2] (0-based indexing),
        as per VIP's convention.
    pos_y, pos_x: float
         Y and X coordinates where the companion should be injected
    flux : int
        Flux at which the fake companion should be injected (i.e. scaling
        factor for the injected image)
    imlib : str, optional
        See documentation of the ``vip_hci.preproc.frame_shift`` function.
    interpolation : str, optional
        See documentation of the ``vip_hci.preproc.frame_shift`` function.

    Returns
    -------
    array_out : numpy ndarray
        Frame or cube with the companion injected
    """
    if not (array.ndim == 2 or array.ndim == 3):
        raise TypeError('Array is not a 2d or 3d array.')
    if array.ndim == 2:
        size_fc = array_fc.shape[0]
        ceny, cenx = frame_center(array)
        ceny = int(ceny)
        cenx = int(cenx)
        fc_fr = np.zeros_like(array)
        w = int(np.floor(size_fc/2.))
        odd = size_fc % 2
        # fake companion in the center of a zeros frame
        fc_fr[ceny-w:ceny+w+odd, cenx-w:cenx+w+odd] = array_fc
        array_out = array + frame_shift(fc_fr, pos_y-ceny, pos_x-cenx, imlib,
                                        interpolation) * flux

    if array.ndim == 3:
        size_fc = array_fc.shape[1]
        ceny, cenx = frame_center(array[0])
        ceny = int(ceny)
        cenx = int(cenx)
        fc_fr = np.zeros_like(array)
        w = int(np.floor(size_fc/2.))
        odd = size_fc % 2
        # fake companion in the center of a zeros frame
        fc_fr[:, ceny-w:ceny+w+odd, cenx-w:cenx+w+odd] = array_fc
        array_out = array + cube_shift(fc_fr, pos_y - ceny, pos_x - cenx,
                                       imlib, interpolation) * flux

    return array_out

def collapse_psf_cube(array, size, fwhm=4, verbose=True, collapse='mean'):
    """ Creates a 2d PSF template from a cube of non-saturated off-axis frames
    of the star by taking the mean and normalizing the PSF flux.

    Parameters
    ----------
    array : numpy ndarray, 3d
        Input cube.
    size : int
        Size of the squared subimage.
    fwhm: float, optional
        The size of the Full Width Half Maximum in pixel.
    verbose : {True,False}, bool optional
        Whether to print to stdout information about file opening, cropping and
        completion of the psf template.
    collapse : {'mean','median'}, string optional
        Defines the way the frames are collapsed.

    Returns
    -------
    psf_normd : numpy ndarray
        Normalized PSF.
    """
    if array.ndim != 3 and array.ndim != 4:
        raise TypeError('Array is not a cube, 3d or 4d array.')

    n = array.shape[0]
    psf = cube_crop_frames(array, size=size, verbose=verbose)
    if collapse == 'mean':
        psf = np.mean(psf, axis=0)
    elif collapse == 'median':
        psf = np.median(psf, axis=0)
    else:
        raise TypeError('Collapse mode not recognized.')

    psf_normd = normalize_psf(psf, size=size, fwhm=fwhm)

    if verbose:
        print("Done scaled PSF template from the average of", n, "frames.")
    return psf_normd

def normalize_psf(array, fwhm='fit', size=None, threshold=None, mask_core=None,
                  model='gauss', imlib='vip-fft', interpolation='lanczos4',
                  force_odd=True, correct_outliers=True, full_output=False,
                  verbose=True, debug=False):
    """ Normalizes a PSF (2d or 3d array), to have the flux in a 1xFWHM
    aperture equal to one. It also allows to crop the array and center the PSF
    at the center of the array(s).

    Parameters
    ----------
    array: numpy ndarray
        The PSF, 2d (ADI data) or 3d array (IFS data).
    fwhm: int, float, 1d array or str, optional
        The Full Width Half Maximum in pixels. It can handle a different
        FWHM value for different wavelengths (IFS data). If set to 'fit' then
        a ``model`` (assuming the PSF is centered in the array) is fitted to
        estimate the FWHM in 2D or 3D PSF arrays.
    size : int or None, optional
        If int it will correspond to the size of the centered sub-image to be
        cropped form the PSF array. The PSF is assumed to be roughly centered wrt
        the array.
    threshold : None or float, optional
        Sets to zero values smaller than threshold (in the normalized image).
        This can be used to only leave the core of the PSF.
    mask_core : None or float, optional
        Sets the radius of a circular aperture for the core of the PSF,
        everything else will be set to zero.
    model : {'gauss', 'moff', 'airy'}, str optional
        The assumed model used to fit the PSF: either a Gaussian, a Moffat
        or an Airy 2d distribution.
    imlib : str, optional
        See the documentation of the ``vip_hci.preproc.frame_shift`` function.
    interpolation : str, optional
        See the documentation of the ``vip_hci.preproc.frame_shift`` function.
    force_odd : bool, optional
        If True the resulting array will have odd size (and the PSF will be
        placed at its center). If False, and the frame size is even, then the
        PSF will be put at the center of an even-sized frame.
    correct_outliers: bool, optional
        For an input 3D cube (IFS) of PSFs, if the 2D fit fails for one of the
        channels, whether to interpolate FWHM value from surrounding channels,
        and recalculate flux and normalization.
    full_output : bool, optional
        If True the flux in a FWHM aperture is returned along with the
        normalized PSF.
    verbose : bool, optional
        If True intermediate results are printed out.
    debug : bool, optional
        If True the fitting will output additional information and a diagnostic
        plot will be shown (this might cause a long output if ``array`` is 3d
        and has many slices).

    Returns
    -------
    psf_norm : numpy ndarray
        The normalized PSF (2d or 3d array).
    fwhm_flux : numpy ndarray
        [full_output=True] The flux in a FWHM aperture (it can be a single
        value or a vector).
    fwhm : numpy ndarray
        [full_output=True] The FWHM size. If ``fwhm`` is set to 'fit' then it
        is the fitted FWHM value according to the assumed ``model`` (the mean in
        X and Y is returned when ``model`` is set to 'gauss').

    """
    def psf_norm_2d(psf, fwhm, threshold, mask_core, full_output, verbose):
        """ 2d case """
        # we check if the psf is centered and fix it if needed
        cy, cx = frame_center(psf, verbose=False)
        xcom, ycom = cen_com(psf)
        if not (np.allclose(cy, ycom, atol=1e-2) or
                np.allclose(cx, xcom, atol=1e-2)):
            # first we find the centroid and put it in the center of the array
            centry, centrx = fit_2d(psf, full_output=False, debug=False)
            if not np.isnan(centry) and not np.isnan(centrx):
                shiftx, shifty = centrx - cx, centry - cy
                psf = frame_shift(psf, -shifty, -shiftx, imlib=imlib,
                                  interpolation=interpolation)

                for _ in range(2):
                    centry, centrx = fit_2d(psf, full_output=False, debug=False)
                    if np.isnan(centry) or np.isnan(centrx):
                        break
                    cy, cx = frame_center(psf, verbose=False)
                    shiftx, shifty = centrx - cx, centry - cy
                    psf = frame_shift(psf, -shifty, -shiftx, imlib=imlib,
                                      interpolation=interpolation)

        # we check whether the flux is normalized and fix it if needed
        fwhm_aper = CircularAperture((cx, cy), fwhm/2)
        fwhm_aper_phot = aperture_photometry(psf, fwhm_aper,
                                             method='exact')
        fwhm_flux = np.array(fwhm_aper_phot['aperture_sum'])

        if fwhm_flux > 1.1 or fwhm_flux < 0.9:
            psf_norm_array = psf / np.array(fwhm_aper_phot['aperture_sum'])
        else:
            psf_norm_array = psf

        if threshold is not None:
            psf_norm_array[np.where(psf_norm_array < threshold)] = 0

        if mask_core is not None:
            psf_norm_array = get_circle(psf_norm_array, radius=mask_core)

        if verbose:
            print("Flux in 1xFWHM aperture: {:.3f}".format(fwhm_flux[0]))

        if full_output:
            return psf_norm_array, fwhm_flux, fwhm
        else:
            return psf_norm_array
    ###########################################################################
    if model == 'gauss':
        fit_2d = fit_2dgaussian
    elif model == 'moff':
        fit_2d = fit_2dmoffat
    elif model == 'airy':
        fit_2d = fit_2dairydisk
    else:
        raise ValueError('`Model` not recognized')

    if array.ndim == 2:
        y, x = array.shape
        if size is not None:
            if force_odd and size % 2 == 0:
                size += 1
                msg = "`Force_odd` is True therefore `size` was set to {}"
                print(msg.format(size))
        else:
            if force_odd and y % 2 == 0:
                size = y - 1
                msg = "`Force_odd` is True and frame size is even, therefore "
                msg += "new frame size was set to {}"
                print(msg.format(size))

        if size is not None:
            if size < array.shape[0]:
                array = frame_crop(array, size, force=True, verbose=False)
            else:
                array = array.copy()
        else:
            array = array.copy()

        if not np.isscalar(fwhm):
            msg = "For a 2d input array, fwhm should be a scalar or string."
            raise ValueError(msg)
        elif fwhm == 'fit':
            fit = fit_2d(array, full_output=True, debug=debug)
            if model == 'gauss':
                fwhm = np.mean((fit['fwhm_x'], fit['fwhm_y']))
                if verbose:
                    print("\nMean FWHM: {:.3f}".format(fwhm))
            elif model == 'moff' or model == 'airy':
                fwhm = fit.fwhm.at[0]
                if verbose:
                    print("FWHM: {:.3f}".format(fwhm))

        res = psf_norm_2d(array, fwhm, threshold, mask_core, full_output,
                          verbose)
        return res

    elif array.ndim == 3:
        n, y, x = array.shape
        if size is not None:
            if force_odd and size % 2 == 0:
                size += 1
                msg = "`Force_odd` is True therefore `size` was set to {}"
                print(msg.format(size))
        else:
            if force_odd and y % 2 == 0:
                size = y - 1
                msg = "`Force_odd` is True and frame size is even, therefore "
                msg += "new frame size was set to {}"
                print(msg.format(size))

        if size is not None:
            if size < array.shape[1]:
                array = cube_crop_frames(array, size, force=True, verbose=False)
            else:
                array = array.copy()

        if np.isscalar(fwhm):
            if fwhm != 'fit':
                fwhm = [fwhm] * array.shape[0]
            else:
                fits_vect = [fit_2d(array[i], full_output=True, debug=debug) for i
                             in range(n)]
                if model == 'gauss':
                    fwhmx = [fits_vect[i]['fwhm_x'] for i in range(n)]
                    fwhmy = [fits_vect[i]['fwhm_y'] for i in range(n)]
                    fwhm_vect = [np.mean((fwhmx[i], fwhmy[i]))
                                 for i in range(n)]
                    fwhm = np.array(fwhm_vect)
                    if verbose:
                        print("Mean FWHM per channel: ")
                        print_precision(fwhm)
                elif model == 'moff' or model == 'airy':
                    fwhm_vect = [fits_vect[i]['fwhm'] for i in range(n)]
                    fwhm = np.array(fwhm_vect)
                    fwhm = fwhm.flatten()
                    if verbose:
                        print("FWHM per channel:")
                        print_precision(fwhm)
                # Replace outliers if needed
                if correct_outliers:
                    if np.sum(np.isnan(fwhm)) > 0:
                        for f in range(n):
                            if np.isnan(fwhm[f]) and f != 0 and f != n-1:
                                fwhm[f] = np.nanmean(np.array([fwhm[f-1],
                                                               fwhm[f+1]]))
                            elif np.isnan(fwhm[f]):
                                msg = "2D fit failed for first or last channel. "
                                msg += "Try other parameters?"
                                raise ValueError(msg)
        elif len(fwhm) != array.shape[0]:
            msg = "If fwhm is a list/1darray it should have a length of {}"
            raise ValueError(msg.format(array.shape[0]))

        array_out = []
        fwhm_flux = np.zeros(n)

        for fr in range(array.shape[0]):
            restemp = psf_norm_2d(array[fr], fwhm[fr], threshold, mask_core,
                                  True, False)
            array_out.append(restemp[0])
            fwhm_flux[fr] = restemp[1]

        array_out = np.array(array_out)
        if verbose:
            print("Flux in 1xFWHM aperture: ")
            print_precision(fwhm_flux)

        if full_output:
            return array_out, fwhm_flux, fwhm
        else:
            return array_out


import sqlite3

con = sqlite3.connect("sample.db")
cursor = con.cursor()
create_history_table_query = """
CREATE TABLE IF NOT EXISTS History(
    Name TXET,
    Age INTEGER
)
"""
cursor.execute(create_history_table_query)
target_name = input("whose 'age' do you want to update?")
new_age = input("Tell me new age:")
update_user_query = 'UPDATE User SET Age = ? WHERE Name = ?'
insert_history_query = 'INSERT INTO History VALUES (?, ?)'

try:
    cursor.execute(insert_history_query, (target_name, new_age))
    cursor.execute(update_user_query, (new_age, target_name))
except sqlite3.Error:
    print("sqlite3 error occurred")
    con.rollback()
else:
    con.commit()

# else: con.commit() があるならば、 con.rollback()はいらないじゃないか？となるが…
# rollback がないと、 error の時点では commite されず pending(ペンディング)の状態：保留という意味
# error がなくなって commite できる状態になった場合に、pending(保留)されていたものも commite されてしまう
# 必ず rollback を付ける事


import math
class Solution(object):
    def multiply(self, num1, num2):
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """
        # a leetcode submittion
        s = [0] * (len(num1) + len(num2))

        for i in reversed(range(len(num1))):
            for j in reversed(range(len(num2))):
                mult = int(num1[i]) * int(num2[j])
                summ = mult + s[i + j + 1]
                s[i + j] += summ // 10
                s[i + j + 1] = summ % 10

        # removes leading 0s by getting the first index of a non 0 which is stored in i
        for i, c in enumerate(s):
            if c != 0:
                break
        return ''.join(map(str, s[i:]))

        """ my solution
        if num1 == '0' or num2 == '0':
            return '0'

        table = {}

        ret = []
        i = 0
        for n in reversed(num1):
            if (n == '0'):
                i += 1
                continue
            val = table[n] if n in table else self.multiplySingle(n, num2)
            table[n] = val
            val = val.ljust(len(val) + i, '0')
            ret.append(val)
            i += 1
        return self.addStringArray(ret)

    def multiplySingle(self, digit, num):
        ret = []
        i = 0
        for n in reversed(num):
            val = str(int(n) * int(digit))
            val = val.ljust(i + len(val), '0')
            ret.append(val)
            i += 1
        return self.addStringArray(ret)

    def addStringArray(self, arr):
        sum = arr[0]
        for i in range(1, len(arr)):
            sum = self.addString(sum, arr[i])
        return sum

    def addString(self, num1, num2):
        ret = ''
        num1 = num1[::-1]
        num2 = num2[::-1]
        carryover = 0
        for i in range(max(len(num1), len(num2)) + 1):
            d1 = '0' if i >= len(num1) else num1[i]
            d2 = '0' if i >= len(num2) else num2[i]
            val = int(d1) + int(d2) + carryover
            carryover = math.floor(val / 10)
            val = int(val % 10)
            ret += str(val)
        ret = ret.rstrip('0')[::-1]
        return ret
    """

"""
https://leetcode.com/problems/multiply-strings/

Runtime: 2897 ms, faster than 5.03% of Python online submissions for Multiply Strings.
Memory Usage: 13.5 MB, less than 51.83% of Python online submissions for Multiply Strings.
"""


# Practice Python: Exercise 05
# http://www.practicepython.org/exercise/2014/03/05/05-list-overlap.html

import random

def solution():
    var_list_a = []
    var_list_b = []

    var_limit = random.randint(10, 20)
    for _r in range(1, var_limit):
        var_list_a.append(random.randrange(50, 59, 1))

    var_limit = random.randint(10, 20)
    for _r in range(1, var_limit):
        var_list_b.append(random.randrange(50, 59, 1))

    var_list_common = list(set(filter(lambda x: x in var_list_b, var_list_a)))

    print(sorted(var_list_a), sorted(var_list_b), sorted(var_list_common), sep="\n")


#
# @lc app=leetcode.cn id=547 lang=python3
#
# [547] 朋友圈
#

# @lc code=start
class Solution:
    def findCircleNum(self, M: List[List[int]]) -> int:
        #   2.并查集
        if not M:
            return 0
        n = len(M)
        p = [i for i in range(n)]  # 并查集初始化

        for i in range(n):
            for j in range(n):
                if M[i][j] == 1:
                    self.union(p, i, j)  # 遍历矩阵M，如果有1就进行合并
        return len(set([self.parent(p, i) for i in range(n)]))  # 遍历所有结点，看所有结点里 不同parent有多少个

    def union(self, p, i, j):
        p1 = self.parent(p, i)
        p2 = self.parent(p, j)
        p[p2] = p1
        # p[p1] = p2

    def parent(self, p, i):
        root = i
        while p[root] != root:
            root = p[root]
        while p[i] != i:  # i 压缩路径
            x = i; i = p[i]; p[x] = root
        return root

        '''
        #  2.BFS  O(n^2) O(n)
        visited = [0] * len(M)
        count = 0
        queue = []
        for i in range(len(M)):
            if visited[i] == 0:
                queue.append(i)
                while queue:
                    s = queue.pop()
                    visited[s] = 1
                    for j in range(len(M)):
                        if M[s][j] == 1 and visited[j] == 0:
                            queue.append(j)
                count += 1
        return count
        '''

        '''
        # 1.dfs  类似 岛屿问题 O(n^2) O(n)
        visited = [0] * len(M)
        count = 0
        for i in range(len(M)):
            if visited[i] == 0:
                self.dfs(M, visited, i)
                count += 1
        return count

    def dfs(self, M, visited, i):
        for j in range(len(M)):
            if M[i][j] == 1 and visited[j] == 0:
                visited[j] = 1  # ！！！
                self.dfs(M, visited, j)
    '''
# @lc code=end